]> git.proxmox.com Git - mirror_frr.git/blobdiff - lib/distribute.c
Merge pull request #337 from donaldsharp/more_spt_more
[mirror_frr.git] / lib / distribute.c
index 04889030f7e47881e200f2dc4008ee2f4dbca663..01c338f1773a6b8ee8687de3dd972d3485643190 100644 (file)
 #include "distribute.h"
 #include "memory.h"
 
+DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE,        "Distribute list")
+DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_IFNAME, "Dist-list ifname")
+DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_NAME,   "Dist-list name")
+
 /* Hash of distribute list. */
 struct hash *disthash;
 
 /* Hook functions. */
 void (*distribute_add_hook) (struct distribute *);
 void (*distribute_delete_hook) (struct distribute *);
-\f
+
 static struct distribute *
 distribute_new (void)
 {
@@ -45,22 +49,35 @@ distribute_new (void)
 static void
 distribute_free (struct distribute *dist)
 {
+  int i = 0;
+
   if (dist->ifname)
     XFREE (MTYPE_DISTRIBUTE_IFNAME, dist->ifname);
 
-  if (dist->list[DISTRIBUTE_IN])
-    free (dist->list[DISTRIBUTE_IN]);
-  if (dist->list[DISTRIBUTE_OUT])
-    free (dist->list[DISTRIBUTE_OUT]);
+  for (i = 0; i < DISTRIBUTE_MAX; i++)
+    if (dist->list[i])
+      XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[i]);
 
-  if (dist->prefix[DISTRIBUTE_IN])
-    free (dist->prefix[DISTRIBUTE_IN]);
-  if (dist->prefix[DISTRIBUTE_OUT])
-    free (dist->prefix[DISTRIBUTE_OUT]);
+  for (i = 0; i < DISTRIBUTE_MAX; i++)
+    if (dist->prefix[i])
+      XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[i]);
 
   XFREE (MTYPE_DISTRIBUTE, dist);
 }
 
+static void
+distribute_free_if_empty(struct distribute *dist)
+{
+  int i;
+
+  for (i = 0; i < DISTRIBUTE_MAX; i++)
+    if (dist->list[i] != NULL || dist->prefix[i] != NULL)
+      return;
+
+  hash_release (disthash, dist);
+  distribute_free (dist);
+}
+
 /* Lookup interface's distribute list. */
 struct distribute *
 distribute_lookup (const char *ifname)
@@ -69,10 +86,13 @@ distribute_lookup (const char *ifname)
   struct distribute *dist;
 
   /* temporary reference */
-  key.ifname = (char *)ifname;
+  key.ifname = (ifname) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME, ifname) : NULL;
 
   dist = hash_lookup (disthash, &key);
-  
+
+  if (key.ifname)
+    XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname);
+
   return dist;
 }
 
@@ -106,11 +126,17 @@ static struct distribute *
 distribute_get (const char *ifname)
 {
   struct distribute key;
+  struct distribute *ret;
 
   /* temporary reference */
-  key.ifname = (char *)ifname;
+  key.ifname = (ifname) ? XSTRDUP(MTYPE_DISTRIBUTE_IFNAME, ifname) : NULL;
   
-  return hash_get (disthash, &key, (void * (*) (void *))distribute_hash_alloc);
+  ret = hash_get (disthash, &key, (void * (*) (void *))distribute_hash_alloc);
+
+  if (key.ifname)
+    XFREE(MTYPE_DISTRIBUTE_IFNAME, key.ifname);
+
+  return ret;
 }
 
 static unsigned int
@@ -133,9 +159,9 @@ distribute_cmp (const struct distribute *dist1, const struct distribute *dist2)
     return 1;
   return 0;
 }
-\f
+
 /* Set access-list name to the distribute list. */
-static struct distribute *
+static void
 distribute_list_set (const char *ifname, enum distribute_type type, 
                      const char *alist_name)
 {
@@ -143,23 +169,12 @@ distribute_list_set (const char *ifname, enum distribute_type type,
 
   dist = distribute_get (ifname);
 
-  if (type == DISTRIBUTE_IN)
-    {
-      if (dist->list[DISTRIBUTE_IN])
-       free (dist->list[DISTRIBUTE_IN]);
-      dist->list[DISTRIBUTE_IN] = strdup (alist_name);
-    }
-  if (type == DISTRIBUTE_OUT)
-    {
-      if (dist->list[DISTRIBUTE_OUT])
-       free (dist->list[DISTRIBUTE_OUT]);
-      dist->list[DISTRIBUTE_OUT] = strdup (alist_name);
-    }
+  if (dist->list[type])
+    XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]);
+  dist->list[type] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, alist_name);
 
   /* Apply this distribute-list to the interface. */
   (*distribute_add_hook) (dist);
-  
-  return dist;
 }
 
 /* Unset distribute-list.  If matched distribute-list exist then
@@ -174,46 +189,24 @@ distribute_list_unset (const char *ifname, enum distribute_type type,
   if (!dist)
     return 0;
 
-  if (type == DISTRIBUTE_IN)
-    {
-      if (!dist->list[DISTRIBUTE_IN])
-       return 0;
-      if (strcmp (dist->list[DISTRIBUTE_IN], alist_name) != 0)
-       return 0;
-
-      free (dist->list[DISTRIBUTE_IN]);
-      dist->list[DISTRIBUTE_IN] = NULL;      
-    }
-
-  if (type == DISTRIBUTE_OUT)
-    {
-      if (!dist->list[DISTRIBUTE_OUT])
+  if (!dist->list[type])
        return 0;
-      if (strcmp (dist->list[DISTRIBUTE_OUT], alist_name) != 0)
+  if (strcmp (dist->list[type], alist_name) != 0)
        return 0;
 
-      free (dist->list[DISTRIBUTE_OUT]);
-      dist->list[DISTRIBUTE_OUT] = NULL;      
-    }
+  XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[type]);
+  dist->list[type] = NULL;
 
   /* Apply this distribute-list to the interface. */
   (*distribute_delete_hook) (dist);
 
-  /* If both out and in is NULL then free distribute list. */
-  if (dist->list[DISTRIBUTE_IN] == NULL &&
-      dist->list[DISTRIBUTE_OUT] == NULL &&
-      dist->prefix[DISTRIBUTE_IN] == NULL &&
-      dist->prefix[DISTRIBUTE_OUT] == NULL)
-    {
-      hash_release (disthash, dist);
-      distribute_free (dist);
-    }
-
+  /* If all dist are NULL, then free distribute list. */
+  distribute_free_if_empty(dist);
   return 1;
 }
 
 /* Set access-list name to the distribute list. */
-static struct distribute *
+static void
 distribute_list_prefix_set (const char *ifname, enum distribute_type type,
                            const char *plist_name)
 {
@@ -221,23 +214,12 @@ distribute_list_prefix_set (const char *ifname, enum distribute_type type,
 
   dist = distribute_get (ifname);
 
-  if (type == DISTRIBUTE_IN)
-    {
-      if (dist->prefix[DISTRIBUTE_IN])
-       free (dist->prefix[DISTRIBUTE_IN]);
-      dist->prefix[DISTRIBUTE_IN] = strdup (plist_name);
-    }
-  if (type == DISTRIBUTE_OUT)
-    {
-      if (dist->prefix[DISTRIBUTE_OUT])
-       free (dist->prefix[DISTRIBUTE_OUT]);
-      dist->prefix[DISTRIBUTE_OUT] = strdup (plist_name);
-    }
+  if (dist->prefix[type])
+    XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]);
+  dist->prefix[type] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, plist_name);
 
   /* Apply this distribute-list to the interface. */
   (*distribute_add_hook) (dist);
-  
-  return dist;
 }
 
 /* Unset distribute-list.  If matched distribute-list exist then
@@ -252,437 +234,231 @@ distribute_list_prefix_unset (const char *ifname, enum distribute_type type,
   if (!dist)
     return 0;
 
-  if (type == DISTRIBUTE_IN)
-    {
-      if (!dist->prefix[DISTRIBUTE_IN])
-       return 0;
-      if (strcmp (dist->prefix[DISTRIBUTE_IN], plist_name) != 0)
-       return 0;
-
-      free (dist->prefix[DISTRIBUTE_IN]);
-      dist->prefix[DISTRIBUTE_IN] = NULL;      
-    }
-
-  if (type == DISTRIBUTE_OUT)
-    {
-      if (!dist->prefix[DISTRIBUTE_OUT])
+  if (!dist->prefix[type])
        return 0;
-      if (strcmp (dist->prefix[DISTRIBUTE_OUT], plist_name) != 0)
+  if (strcmp (dist->prefix[type], plist_name) != 0)
        return 0;
 
-      free (dist->prefix[DISTRIBUTE_OUT]);
-      dist->prefix[DISTRIBUTE_OUT] = NULL;      
-    }
+  XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[type]);
+  dist->prefix[type] = NULL;
 
   /* Apply this distribute-list to the interface. */
   (*distribute_delete_hook) (dist);
 
-  /* If both out and in is NULL then free distribute list. */
-  if (dist->list[DISTRIBUTE_IN] == NULL &&
-      dist->list[DISTRIBUTE_OUT] == NULL &&
-      dist->prefix[DISTRIBUTE_IN] == NULL &&
-      dist->prefix[DISTRIBUTE_OUT] == NULL)
-    {
-      hash_release (disthash, dist);
-      distribute_free (dist);
-    }
-
+  /* If all dist are NULL, then free distribute list. */
+  distribute_free_if_empty(dist);
   return 1;
 }
 
-DEFUN (distribute_list_all,
-       distribute_list_all_cmd,
-       "distribute-list WORD (in|out)",
-       "Filter networks in routing updates\n"
-       "Access-list name\n"
-       "Filter incoming routing updates\n"
-       "Filter outgoing routing updates\n")
-{
-  enum distribute_type type;
-
-  /* Check of distribute list type. */
-  if (strncmp (argv[1], "i", 1) == 0)
-    type = DISTRIBUTE_IN;
-  else if (strncmp (argv[1], "o", 1) == 0)
-    type = DISTRIBUTE_OUT;
-  else
-    {
-      vty_out (vty, "distribute list direction must be [in|out]%s",
-              VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-
-  /* Get interface name corresponding distribute list. */
-  distribute_list_set (NULL, type, argv[0]);
-
-  return CMD_SUCCESS;
-}
-
-ALIAS (distribute_list_all,
-       ipv6_distribute_list_all_cmd,
-       "distribute-list WORD (in|out)",
-       "Filter networks in routing updates\n"
-       "Access-list name\n"
-       "Filter incoming routing updates\n"
-       "Filter outgoing routing updates\n")
-
-DEFUN (no_distribute_list_all,
-       no_distribute_list_all_cmd,
-       "no distribute-list WORD (in|out)",
-       NO_STR
-       "Filter networks in routing updates\n"
-       "Access-list name\n"
-       "Filter incoming routing updates\n"
-       "Filter outgoing routing updates\n")
-{
-  int ret;
-  enum distribute_type type;
-
-  /* Check of distribute list type. */
-  if (strncmp (argv[1], "i", 1) == 0)
-    type = DISTRIBUTE_IN;
-  else if (strncmp (argv[1], "o", 1) == 0)
-    type = DISTRIBUTE_OUT;
-  else
-    {
-      vty_out (vty, "distribute list direction must be [in|out]%s",
-              VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-
-  ret = distribute_list_unset (NULL, type, argv[0]);
-  if (! ret)
-    {
-      vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-  return CMD_SUCCESS;
-}
-
-ALIAS (no_distribute_list_all,
-       no_ipv6_distribute_list_all_cmd,
-       "no distribute-list WORD (in|out)",
-       NO_STR
-       "Filter networks in routing updates\n"
-       "Access-list name\n"
-       "Filter incoming routing updates\n"
-       "Filter outgoing routing updates\n")
-
 DEFUN (distribute_list,
        distribute_list_cmd,
-       "distribute-list WORD (in|out) WORD",
+       "distribute-list [prefix] WORD <in|out> [WORD]",
        "Filter networks in routing updates\n"
        "Access-list name\n"
        "Filter incoming routing updates\n"
        "Filter outgoing routing updates\n"
        "Interface name\n")
 {
-  enum distribute_type type;
+  int prefix = (argv[1]->type == WORD_TKN) ? 1 : 0;
 
   /* Check of distribute list type. */
-  if (strncmp (argv[1], "i", 1) == 0)
-    type = DISTRIBUTE_IN;
-  else if (strncmp (argv[1], "o", 1) == 0)
-    type = DISTRIBUTE_OUT;
-  else
-    {
-      vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE);
-      return CMD_WARNING;
-    }
+  enum distribute_type type = argv[2 + prefix]->arg[0] == 'i' ?
+    DISTRIBUTE_V4_IN : DISTRIBUTE_V4_OUT;
+
+  /* Set appropriate function call */
+  void (*distfn)(const char *, enum distribute_type, const char *) = prefix ? 
+    &distribute_list_prefix_set : &distribute_list_set;
+  
+  /* if interface is present, get name */
+  const char *ifname = NULL;
+  if (argv[argc - 1]->type == VARIABLE_TKN)
+    ifname = argv[argc - 1]->arg;
 
   /* Get interface name corresponding distribute list. */
-  distribute_list_set (argv[2], type, argv[0]);
+  distfn (ifname, type, argv[1 + prefix]->arg);
 
   return CMD_SUCCESS;
-}       
+}
 
-ALIAS (distribute_list,
+DEFUN (ipv6_distribute_list,
        ipv6_distribute_list_cmd,
-       "distribute-list WORD (in|out) WORD",
-       "Filter networks in routing updates\n"
-       "Access-list name\n"
-       "Filter incoming routing updates\n"
-       "Filter outgoing routing updates\n"
-       "Interface name\n")
-
-DEFUN (no_distribute_list, no_distribute_list_cmd,
-       "no distribute-list WORD (in|out) WORD",
-       NO_STR
+       "ipv6 distribute-list [prefix] WORD <in|out> [WORD]",
+       "IPv6\n"
        "Filter networks in routing updates\n"
+       "Specify a prefix\n"
        "Access-list name\n"
        "Filter incoming routing updates\n"
        "Filter outgoing routing updates\n"
        "Interface name\n")
 {
-  int ret;
-  enum distribute_type type;
+  int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0;
 
   /* Check of distribute list type. */
-  if (strncmp (argv[1], "i", 1) == 0)
-    type = DISTRIBUTE_IN;
-  else if (strncmp (argv[1], "o", 1) == 0)
-    type = DISTRIBUTE_OUT;
-  else
-    {
-      vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-
-  ret = distribute_list_unset (argv[2], type, argv[0]);
-  if (! ret)
-    {
-      vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-  return CMD_SUCCESS;
-}       
-
-ALIAS (no_distribute_list, no_ipv6_distribute_list_cmd,
-       "no distribute-list WORD (in|out) WORD",
-       NO_STR
-       "Filter networks in routing updates\n"
-       "Access-list name\n"
-       "Filter incoming routing updates\n"
-       "Filter outgoing routing updates\n"
-       "Interface name\n")
-
-DEFUN (distribute_list_prefix_all,
-       distribute_list_prefix_all_cmd,
-       "distribute-list prefix WORD (in|out)",
-       "Filter networks in routing updates\n"
-       "Filter prefixes in routing updates\n"
-       "Name of an IP prefix-list\n"
-       "Filter incoming routing updates\n"
-       "Filter outgoing routing updates\n")
-{
-  enum distribute_type type;
+  enum distribute_type type = argv[3 + prefix]->arg[0] == 'i' ?
+    DISTRIBUTE_V6_IN : DISTRIBUTE_V6_OUT;
 
-  /* Check of distribute list type. */
-  if (strncmp (argv[1], "i", 1) == 0)
-    type = DISTRIBUTE_IN;
-  else if (strncmp (argv[1], "o", 1) == 0)
-    type = DISTRIBUTE_OUT;
-  else
-    {
-      vty_out (vty, "distribute list direction must be [in|out]%s", 
-              VTY_NEWLINE);
-      return CMD_WARNING;
-    }
+  /* Set appropriate function call */
+  void (*distfn)(const char *, enum distribute_type, const char *) = prefix ? 
+    &distribute_list_prefix_set : &distribute_list_set;
+  
+  /* if interface is present, get name */
+  const char *ifname = NULL;
+  if (argv[argc - 1]->type == VARIABLE_TKN)
+    ifname = argv[argc - 1]->arg;
 
   /* Get interface name corresponding distribute list. */
-  distribute_list_prefix_set (NULL, type, argv[0]);
+  distfn (ifname, type, argv[1 + prefix]->arg);
 
   return CMD_SUCCESS;
-}       
-
-ALIAS (distribute_list_prefix_all,
-       ipv6_distribute_list_prefix_all_cmd,
-       "distribute-list prefix WORD (in|out)",
-       "Filter networks in routing updates\n"
-       "Filter prefixes in routing updates\n"
-       "Name of an IP prefix-list\n"
-       "Filter incoming routing updates\n"
-       "Filter outgoing routing updates\n")
-
-DEFUN (no_distribute_list_prefix_all,
-       no_distribute_list_prefix_all_cmd,
-       "no distribute-list prefix WORD (in|out)",
-       NO_STR
-       "Filter networks in routing updates\n"
-       "Filter prefixes in routing updates\n"
-       "Name of an IP prefix-list\n"
-       "Filter incoming routing updates\n"
-       "Filter outgoing routing updates\n")
-{
-  int ret;
-  enum distribute_type type;
-
-  /* Check of distribute list type. */
-  if (strncmp (argv[1], "i", 1) == 0)
-    type = DISTRIBUTE_IN;
-  else if (strncmp (argv[1], "o", 1) == 0)
-    type = DISTRIBUTE_OUT;
-  else
-    {
-      vty_out (vty, "distribute list direction must be [in|out]%s", 
-              VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-
-  ret = distribute_list_prefix_unset (NULL, type, argv[0]);
-  if (! ret)
-    {
-      vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-  return CMD_SUCCESS;
-}       
-
-ALIAS (no_distribute_list_prefix_all,
-       no_ipv6_distribute_list_prefix_all_cmd,
-       "no distribute-list prefix WORD (in|out)",
+}
+       
+DEFUN (no_distribute_list,
+       no_distribute_list_cmd,
+       "no [ipv6] distribute-list [prefix] WORD <in|out> [WORD]",
        NO_STR
        "Filter networks in routing updates\n"
-       "Filter prefixes in routing updates\n"
-       "Name of an IP prefix-list\n"
-       "Filter incoming routing updates\n"
-       "Filter outgoing routing updates\n")
-
-DEFUN (distribute_list_prefix, distribute_list_prefix_cmd,
-       "distribute-list prefix WORD (in|out) WORD",
-       "Filter networks in routing updates\n"
-       "Filter prefixes in routing updates\n"
-       "Name of an IP prefix-list\n"
+       "Access-list name\n"
        "Filter incoming routing updates\n"
        "Filter outgoing routing updates\n"
        "Interface name\n")
 {
-  enum distribute_type type;
+  int ipv6 = strmatch(argv[1]->text, "ipv6");
+  int prefix = (argv[2 + ipv6]->type == WORD_TKN) ? 1 : 0;
 
-  /* Check of distribute list type. */
-  if (strncmp (argv[1], "i", 1) == 0)
-    type = DISTRIBUTE_IN;
-  else if (strncmp (argv[1], "o", 1) == 0)
-    type = DISTRIBUTE_OUT;
-  else
-    {
-      vty_out (vty, "distribute list direction must be [in|out]%s", 
-              VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-
-  /* Get interface name corresponding distribute list. */
-  distribute_list_prefix_set (argv[2], type, argv[0]);
-
-  return CMD_SUCCESS;
-}       
+  int idx_alname = 2 + ipv6 + prefix;
+  int idx_disttype = idx_alname + 1;
 
-ALIAS (distribute_list_prefix, ipv6_distribute_list_prefix_cmd,
-       "distribute-list prefix WORD (in|out) WORD",
-       "Filter networks in routing updates\n"
-       "Filter prefixes in routing updates\n"
-       "Name of an IP prefix-list\n"
-       "Filter incoming routing updates\n"
-       "Filter outgoing routing updates\n"
-       "Interface name\n")
+  /* Check of distribute list type. */
+  enum distribute_type distin = (ipv6) ? DISTRIBUTE_V6_IN : DISTRIBUTE_V4_IN;
+  enum distribute_type distout = (ipv6) ? DISTRIBUTE_V6_OUT : DISTRIBUTE_V4_OUT;
 
-DEFUN (no_distribute_list_prefix, no_distribute_list_prefix_cmd,
-       "no distribute-list prefix WORD (in|out) WORD",
-       NO_STR
-       "Filter networks in routing updates\n"
-       "Filter prefixes in routing updates\n"
-       "Name of an IP prefix-list\n"
-       "Filter incoming routing updates\n"
-       "Filter outgoing routing updates\n"
-       "Interface name\n")
-{
-  int ret;
-  enum distribute_type type;
+  enum distribute_type type = argv[idx_disttype]->arg[0] == 'i' ? distin : distout;
 
-  /* Check of distribute list type. */
-  if (strncmp (argv[1], "i", 1) == 0)
-    type = DISTRIBUTE_IN;
-  else if (strncmp (argv[1], "o", 1) == 0)
-    type = DISTRIBUTE_OUT;
-  else
-    {
-      vty_out (vty, "distribute list direction must be [in|out]%s", 
-              VTY_NEWLINE);
-      return CMD_WARNING;
-    }
+  /* Set appropriate function call */
+  int (*distfn)(const char *, enum distribute_type, const char *) = prefix ? 
+    &distribute_list_prefix_unset : &distribute_list_unset;
+  
+  /* if interface is present, get name */
+  const char *ifname = NULL;
+  if (argv[argc - 1]->type == VARIABLE_TKN)
+    ifname = argv[argc - 1]->arg;
+  /* Get interface name corresponding distribute list. */
+  int ret = distfn (ifname, type, argv[2 + prefix]->arg);
 
-  ret = distribute_list_prefix_unset (argv[2], type, argv[0]);
   if (! ret)
     {
       vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
       return CMD_WARNING;
     }
   return CMD_SUCCESS;
-}       
+}
 
-ALIAS (no_distribute_list_prefix, no_ipv6_distribute_list_prefix_cmd,
-       "no distribute-list prefix WORD (in|out) WORD",
-       NO_STR
-       "Filter networks in routing updates\n"
-       "Filter prefixes in routing updates\n"
-       "Name of an IP prefix-list\n"
-       "Filter incoming routing updates\n"
-       "Filter outgoing routing updates\n"
-       "Interface name\n")
+static int
+distribute_print (struct vty *vty, char *tab[], int is_prefix,
+                  enum distribute_type type, int has_print)
+{
+  if (tab[type]) {
+    vty_out (vty, "%s %s%s",
+             has_print ? "," : "",
+             is_prefix ? "(prefix-list) " : "",
+             tab[type]);
+    return 1;
+  }
+  return has_print;
+}
 
 int
 config_show_distribute (struct vty *vty)
 {
   unsigned int i;
+  int has_print = 0;
   struct hash_backet *mp;
   struct distribute *dist;
 
   /* Output filter configuration. */
   dist = distribute_lookup (NULL);
-  if (dist && (dist->list[DISTRIBUTE_OUT] || dist->prefix[DISTRIBUTE_OUT]))
-    {
       vty_out (vty, "  Outgoing update filter list for all interface is");
-      if (dist->list[DISTRIBUTE_OUT])
-       vty_out (vty, " %s", dist->list[DISTRIBUTE_OUT]);
-      if (dist->prefix[DISTRIBUTE_OUT])
-       vty_out (vty, "%s (prefix-list) %s",
-                dist->list[DISTRIBUTE_OUT] ? "," : "",
-                dist->prefix[DISTRIBUTE_OUT]);
-      vty_out (vty, "%s", VTY_NEWLINE);
+  has_print = 0;
+  if (dist)
+    {
+      has_print = distribute_print(vty, dist->list,   0,
+                                   DISTRIBUTE_V4_OUT, has_print);
+      has_print = distribute_print(vty, dist->prefix, 1,
+                                   DISTRIBUTE_V4_OUT, has_print);
+      has_print = distribute_print(vty, dist->list,   0,
+                                   DISTRIBUTE_V6_OUT, has_print);
+      has_print = distribute_print(vty, dist->prefix, 1,
+                                   DISTRIBUTE_V6_OUT, has_print);
     }
+  if (has_print)
+    vty_out (vty, "%s", VTY_NEWLINE);
   else
-    vty_out (vty, "  Outgoing update filter list for all interface is not set%s", VTY_NEWLINE);
+    vty_out (vty, " not set%s", VTY_NEWLINE);
 
   for (i = 0; i < disthash->size; i++)
     for (mp = disthash->index[i]; mp; mp = mp->next)
       {
        dist = mp->data;
        if (dist->ifname)
-         if (dist->list[DISTRIBUTE_OUT] || dist->prefix[DISTRIBUTE_OUT])
            {
              vty_out (vty, "    %s filtered by", dist->ifname);
-             if (dist->list[DISTRIBUTE_OUT])
-               vty_out (vty, " %s", dist->list[DISTRIBUTE_OUT]);
-             if (dist->prefix[DISTRIBUTE_OUT])
-               vty_out (vty, "%s (prefix-list) %s",
-                        dist->list[DISTRIBUTE_OUT] ? "," : "",
-                        dist->prefix[DISTRIBUTE_OUT]);
+            has_print = 0;
+            has_print = distribute_print(vty, dist->list,   0,
+                                         DISTRIBUTE_V4_OUT, has_print);
+            has_print = distribute_print(vty, dist->prefix, 1,
+                                         DISTRIBUTE_V4_OUT, has_print);
+            has_print = distribute_print(vty, dist->list,   0,
+                                         DISTRIBUTE_V6_OUT, has_print);
+            has_print = distribute_print(vty, dist->prefix, 1,
+                                         DISTRIBUTE_V6_OUT, has_print);
+            if (has_print)
              vty_out (vty, "%s", VTY_NEWLINE);
+            else
+              vty_out(vty, " nothing%s", VTY_NEWLINE);
            }
       }
 
 
   /* Input filter configuration. */
   dist = distribute_lookup (NULL);
-  if (dist && (dist->list[DISTRIBUTE_IN] || dist->prefix[DISTRIBUTE_IN]))
-    {
       vty_out (vty, "  Incoming update filter list for all interface is");
-      if (dist->list[DISTRIBUTE_IN])
-       vty_out (vty, " %s", dist->list[DISTRIBUTE_IN]);
-      if (dist->prefix[DISTRIBUTE_IN])
-       vty_out (vty, "%s (prefix-list) %s",
-                dist->list[DISTRIBUTE_IN] ? "," : "",
-                dist->prefix[DISTRIBUTE_IN]);
-      vty_out (vty, "%s", VTY_NEWLINE);
+  has_print = 0;
+  if (dist)
+    {
+      has_print = distribute_print(vty, dist->list,   0,
+                                   DISTRIBUTE_V4_IN, has_print);
+      has_print = distribute_print(vty, dist->prefix, 1,
+                                   DISTRIBUTE_V4_IN, has_print);
+      has_print = distribute_print(vty, dist->list,   0,
+                                   DISTRIBUTE_V6_IN, has_print);
+      has_print = distribute_print(vty, dist->prefix, 1,
+                                   DISTRIBUTE_V6_IN, has_print);
     }
+  if (has_print)
+    vty_out (vty, "%s", VTY_NEWLINE);
   else
-    vty_out (vty, "  Incoming update filter list for all interface is not set%s", VTY_NEWLINE);
+    vty_out (vty, " not set%s", VTY_NEWLINE);
 
   for (i = 0; i < disthash->size; i++)
     for (mp = disthash->index[i]; mp; mp = mp->next)
       {
        dist = mp->data;
        if (dist->ifname)
-         if (dist->list[DISTRIBUTE_IN] || dist->prefix[DISTRIBUTE_IN])
            {
              vty_out (vty, "    %s filtered by", dist->ifname);
-             if (dist->list[DISTRIBUTE_IN])
-               vty_out (vty, " %s", dist->list[DISTRIBUTE_IN]);
-             if (dist->prefix[DISTRIBUTE_IN])
-               vty_out (vty, "%s (prefix-list) %s",
-                        dist->list[DISTRIBUTE_IN] ? "," : "",
-                        dist->prefix[DISTRIBUTE_IN]);
+            has_print = 0;
+            has_print = distribute_print(vty, dist->list,   0,
+                                         DISTRIBUTE_V4_IN, has_print);
+            has_print = distribute_print(vty, dist->prefix, 1,
+                                         DISTRIBUTE_V4_IN, has_print);
+            has_print = distribute_print(vty, dist->list,   0,
+                                         DISTRIBUTE_V6_IN, has_print);
+            has_print = distribute_print(vty, dist->prefix, 1,
+                                         DISTRIBUTE_V6_IN, has_print);
+            if (has_print)
              vty_out (vty, "%s", VTY_NEWLINE);
+            else
+              vty_out(vty, " nothing%s", VTY_NEWLINE);
            }
       }
   return 0;
@@ -693,6 +469,8 @@ int
 config_write_distribute (struct vty *vty)
 {
   unsigned int i;
+  int j;
+  int output, v6;
   struct hash_backet *mp;
   int write = 0;
 
@@ -703,38 +481,27 @@ config_write_distribute (struct vty *vty)
 
        dist = mp->data;
 
-       if (dist->list[DISTRIBUTE_IN])
-         {
-           vty_out (vty, " distribute-list %s in %s%s", 
-                    dist->list[DISTRIBUTE_IN],
+       for (j = 0; j < DISTRIBUTE_MAX; j++)
+         if (dist->list[j]) {
+           output = j == DISTRIBUTE_V4_OUT || j == DISTRIBUTE_V6_OUT;
+            v6 = j == DISTRIBUTE_V6_IN || j == DISTRIBUTE_V6_OUT;
+           vty_out (vty, " %sdistribute-list %s %s %s%s",
+                     v6 ? "ipv6 " : "",
+                    dist->list[j],
+                    output ? "out" : "in",
                     dist->ifname ? dist->ifname : "",
                     VTY_NEWLINE);
            write++;
          }
 
-       if (dist->list[DISTRIBUTE_OUT])
-         {
-           vty_out (vty, " distribute-list %s out %s%s", 
-
-                    dist->list[DISTRIBUTE_OUT],
-                    dist->ifname ? dist->ifname : "",
-                    VTY_NEWLINE);
-           write++;
-         }
-
-       if (dist->prefix[DISTRIBUTE_IN])
-         {
-           vty_out (vty, " distribute-list prefix %s in %s%s",
-                    dist->prefix[DISTRIBUTE_IN],
-                    dist->ifname ? dist->ifname : "",
-                    VTY_NEWLINE);
-           write++;
-         }
-
-       if (dist->prefix[DISTRIBUTE_OUT])
-         {
-           vty_out (vty, " distribute-list prefix %s out %s%s",
-                    dist->prefix[DISTRIBUTE_OUT],
+       for (j = 0; j < DISTRIBUTE_MAX; j++)
+         if (dist->prefix[j]) {
+           output = j == DISTRIBUTE_V4_OUT || j == DISTRIBUTE_V6_OUT;
+            v6 = j == DISTRIBUTE_V6_IN || j == DISTRIBUTE_V6_OUT;
+           vty_out (vty, " %sdistribute-list prefix %s %s %s%s",
+                     v6 ? "ipv6 " : "",
+                    dist->prefix[j],
+                    output ? "out" : "in",
                     dist->ifname ? dist->ifname : "",
                     VTY_NEWLINE);
            write++;
@@ -757,23 +524,29 @@ distribute_list_init (int node)
   disthash = hash_create (distribute_hash_make,
                           (int (*) (const void *, const void *)) distribute_cmp);
 
-  if(node==RIP_NODE) {
-    install_element (RIP_NODE, &distribute_list_all_cmd);
-    install_element (RIP_NODE, &no_distribute_list_all_cmd);
+  /* vtysh command-extraction doesn't grok install_element(node, ) */
+  if (node == RIP_NODE) {
     install_element (RIP_NODE, &distribute_list_cmd);
     install_element (RIP_NODE, &no_distribute_list_cmd);
-    install_element (RIP_NODE, &distribute_list_prefix_all_cmd);
-    install_element (RIP_NODE, &no_distribute_list_prefix_all_cmd);
-    install_element (RIP_NODE, &distribute_list_prefix_cmd);
-    install_element (RIP_NODE, &no_distribute_list_prefix_cmd);
-  } else {
-    install_element (RIPNG_NODE, &ipv6_distribute_list_all_cmd);
-    install_element (RIPNG_NODE, &no_ipv6_distribute_list_all_cmd);
+  } else if (node == RIPNG_NODE) {
+    install_element (RIPNG_NODE, &distribute_list_cmd);
+    install_element (RIPNG_NODE, &no_distribute_list_cmd);
+  }
+
+  /* install v6 */
+  if (node == RIPNG_NODE) {
     install_element (RIPNG_NODE, &ipv6_distribute_list_cmd);
-    install_element (RIPNG_NODE, &no_ipv6_distribute_list_cmd);
-    install_element (RIPNG_NODE, &ipv6_distribute_list_prefix_all_cmd);
-    install_element (RIPNG_NODE, &no_ipv6_distribute_list_prefix_all_cmd);
-    install_element (RIPNG_NODE, &ipv6_distribute_list_prefix_cmd);
-    install_element (RIPNG_NODE, &no_ipv6_distribute_list_prefix_cmd);
   }
+
+  /* TODO: install v4 syntax command for v6 only protocols. */
+ /* if (node == RIPNG_NODE) {
+  *   install_element (node, &ipv6_as_v4_distribute_list_all_cmd);
+  *   install_element (node, &no_ipv6_as_v4_distribute_list_all_cmd);
+  *   install_element (node, &ipv6_as_v4_distribute_list_cmd);
+  *   install_element (node, &no_ipv6_as_v4_distribute_list_cmd);
+  *   install_element (node, &ipv6_as_v4_distribute_list_prefix_all_cmd);
+  *   install_element (node, &no_ipv6_as_v4_distribute_list_prefix_all_cmd);
+  *   install_element (node, &ipv6_as_v4_distribute_list_prefix_cmd);
+  *   install_element (node, &no_ipv6_as_v4_distribute_list_prefix_cmd);
+    }*/
 }