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/lib/memtypes.c b/lib/memtypes.c
index 6df1448..3b9345d 100644
--- a/lib/memtypes.c
+++ b/lib/memtypes.c
@@ -234,6 +234,7 @@
   { MTYPE_OSPF6_NEXTHOP,      "OSPF6 nexthop"			},
   { MTYPE_OSPF6_EXTERNAL_INFO,"OSPF6 ext. info"			},
   { MTYPE_OSPF6_OTHER,        "OSPF6 other"			},
+  { MTYPE_OSPF6_DISTANCE,     "OSPF6 distance"			},
   { -1, NULL },
 };
 
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);
 }
 
 
diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h
index d6f4bf0..97fac0d 100644
--- a/ospf6d/ospf6_top.h
+++ b/ospf6d/ospf6_top.h
@@ -82,6 +82,14 @@
   struct thread *maxage_remover;
 
   u_int32_t ref_bandwidth;
+
+  /* Distance parameters */
+  u_char distance_all;
+  u_char distance_intra;
+  u_char distance_inter;
+  u_char distance_external;
+
+  struct route_table *distance_table;
 };
 
 #define OSPF6_DISABLED    0x01
@@ -97,5 +105,3 @@
 extern void ospf6_maxage_remove (struct ospf6 *o);
 
 #endif /* OSPF6_TOP_H */
-
-
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
index c8f20d8..1f0daa1 100644
--- a/ospf6d/ospf6_zebra.c
+++ b/ospf6d/ospf6_zebra.c
@@ -477,6 +477,8 @@
   SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
   api.metric = (request->path.metric_type == 2 ?
                 request->path.cost_e2 : request->path.cost);
+  SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE);
+  api.distance = ospf6_distance_apply (request, ospf6);
 
   dest = (struct prefix_ipv6 *) &request->prefix;
   if (type == REM)
@@ -579,6 +581,147 @@
   zclient_send_requests (zclient, VRF_DEFAULT);
 }
 
+static struct ospf6_distance *
+ospf6_distance_new (void)
+{
+  return XCALLOC (MTYPE_OSPF6_DISTANCE, sizeof (struct ospf6_distance));
+}
+
+static void
+ospf6_distance_free (struct ospf6_distance *odistance)
+{
+  XFREE (MTYPE_OSPF6_DISTANCE, odistance);
+}
+
+int
+ospf6_distance_set (struct vty *vty, struct ospf6 *o,
+                    const char *distance_str,
+                    const char *ip_str,
+                    const char *access_list_str)
+{
+  int ret;
+  struct prefix_ipv6 p;
+  u_char distance;
+  struct route_node *rn;
+  struct ospf6_distance *odistance;
+
+  ret = str2prefix_ipv6 (ip_str, &p);
+  if (ret == 0)
+    {
+      vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  distance = atoi (distance_str);
+
+  /* Get OSPF6 distance node. */
+  rn = route_node_get (o->distance_table, (struct prefix *) &p);
+  if (rn->info)
+    {
+      odistance = rn->info;
+      route_unlock_node (rn);
+    }
+  else
+    {
+      odistance = ospf6_distance_new ();
+      rn->info = odistance;
+    }
+
+  /* Set distance value. */
+  odistance->distance = distance;
+
+  /*Reset access-list configuration. */
+  if (odistance->access_list)
+    {
+      free (odistance->access_list);
+      odistance->access_list = NULL;
+    }
+  if (access_list_str)
+    odistance->access_list = strdup (access_list_str);
+
+  return CMD_SUCCESS;
+}
+
+int
+ospf6_distance_unset (struct vty *vty, struct ospf6 *o,
+                      const char *ip_str,
+                      const char *access_list_str)
+{
+  int ret;
+  struct prefix_ipv6 p;
+  struct route_node *rn;
+  struct ospf6_distance *odistance;
+
+  ret = str2prefix_ipv6 (ip_str, &p);
+  if (ret == 0)
+    {
+      vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  rn = route_node_lookup (o->distance_table, (struct prefix *) &p);
+  if (!rn)
+    {
+      vty_out (vty, "Cant't find specified prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  odistance = rn->info;
+
+  if (odistance->access_list)
+    free (odistance->access_list);
+  ospf6_distance_free (odistance);
+
+  rn->info = NULL;
+  route_unlock_node (rn);
+  route_unlock_node (rn);
+
+  return CMD_SUCCESS;
+}
+
+void
+ospf6_distance_reset (struct ospf6 *o)
+{
+  struct route_node *rn;
+  struct ospf6_distance *odistance;
+
+  for (rn = route_top (o->distance_table); rn; rn = route_next (rn))
+    if ((odistance = rn->info) != NULL)
+      {
+        if (odistance->access_list)
+          free (odistance->access_list);
+        ospf6_distance_free (odistance);
+        rn->info = NULL;
+        route_unlock_node (rn);
+      }
+}
+
+u_char
+ospf6_distance_apply (struct ospf6_route *or, struct ospf6 *o)
+{
+
+  if (o == NULL)
+    return 0;
+
+  if (o->distance_intra)
+    if (or->path.type == OSPF6_PATH_TYPE_INTRA)
+      return o->distance_intra;
+
+  if (o->distance_inter)
+    if (or->path.type == OSPF6_PATH_TYPE_INTER)
+      return o->distance_inter;
+
+  if (o->distance_external)
+    if(or->path.type == OSPF6_PATH_TYPE_EXTERNAL1
+       || or->path.type == OSPF6_PATH_TYPE_EXTERNAL2)
+      return o->distance_external;
+
+  if (o->distance_all)
+    return o->distance_all;
+
+  return 0;
+}
+
 void
 ospf6_zebra_init (struct thread_master *master)
 {
diff --git a/ospf6d/ospf6_zebra.h b/ospf6d/ospf6_zebra.h
index 05694d3..51eb9d7 100644
--- a/ospf6d/ospf6_zebra.h
+++ b/ospf6d/ospf6_zebra.h
@@ -23,6 +23,7 @@
 #define OSPF6_ZEBRA_H
 
 #include "zclient.h"
+#include "ospf6_top.h"
 
 /* Debug option */
 extern unsigned char conf_debug_ospf6_zebra;
@@ -35,6 +36,16 @@
 #define IS_OSPF6_DEBUG_ZEBRA(e) \
   (conf_debug_ospf6_zebra & OSPF6_DEBUG_ZEBRA_ ## e)
 
+/* OSPF6 distance */
+struct ospf6_distance
+{
+  /* Distance value for the IP source prefix */
+  u_char distance;
+
+  /* Name of the access-list to be matched */
+  char *access_list;
+};
+
 extern struct zclient *zclient;
 
 extern void ospf6_zebra_route_update_add (struct ospf6_route *request);
@@ -44,6 +55,15 @@
 extern void ospf6_zebra_no_redistribute (int);
 #define ospf6_zebra_is_redistribute(type) \
     vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT)
+
+extern void ospf6_distance_reset (struct ospf6 *);
+extern u_char ospf6_distance_apply (struct ospf6_route *,
+                                    struct ospf6 *);
+extern int ospf6_distance_set (struct vty *, struct ospf6 *, const char *,
+                               const char *, const char *);
+extern int ospf6_distance_unset (struct vty *, struct ospf6 *, const char *,
+                                 const char *);
+
 extern void ospf6_zebra_init(struct thread_master *);
 
 extern int config_write_ospf6_debug_zebra (struct vty *vty);