]> 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 8a00833915025edd5ad59038a6b31e22820eb7c7..01c338f1773a6b8ee8687de3dd972d3485643190 100644 (file)
@@ -49,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])
-    XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[DISTRIBUTE_IN]);
-  if (dist->list[DISTRIBUTE_OUT])
-    XFREE(MTYPE_DISTRIBUTE_NAME, 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])
-    XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[DISTRIBUTE_IN]);
-  if (dist->prefix[DISTRIBUTE_OUT])
-    XFREE(MTYPE_DISTRIBUTE_NAME, 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)
@@ -156,18 +169,9 @@ distribute_list_set (const char *ifname, enum distribute_type type,
 
   dist = distribute_get (ifname);
 
-  if (type == DISTRIBUTE_IN)
-    {
-      if (dist->list[DISTRIBUTE_IN])
-       XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[DISTRIBUTE_IN]);
-      dist->list[DISTRIBUTE_IN] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, alist_name);
-    }
-  if (type == DISTRIBUTE_OUT)
-    {
-      if (dist->list[DISTRIBUTE_OUT])
-       XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[DISTRIBUTE_OUT]);
-      dist->list[DISTRIBUTE_OUT] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, 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);
@@ -185,41 +189,19 @@ distribute_list_unset (const char *ifname, enum distribute_type type,
   if (!dist)
     return 0;
 
-  if (type == DISTRIBUTE_IN)
-    {
-      if (!dist->list[DISTRIBUTE_IN])
+  if (!dist->list[type])
        return 0;
-      if (strcmp (dist->list[DISTRIBUTE_IN], alist_name) != 0)
+  if (strcmp (dist->list[type], alist_name) != 0)
        return 0;
 
-      XFREE(MTYPE_DISTRIBUTE_NAME, dist->list[DISTRIBUTE_IN]);
-      dist->list[DISTRIBUTE_IN] = NULL;      
-    }
-
-  if (type == DISTRIBUTE_OUT)
-    {
-      if (!dist->list[DISTRIBUTE_OUT])
-       return 0;
-      if (strcmp (dist->list[DISTRIBUTE_OUT], alist_name) != 0)
-       return 0;
-
-      XFREE(MTYPE_DISTRIBUTE_NAME, 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;
 }
 
@@ -232,18 +214,9 @@ distribute_list_prefix_set (const char *ifname, enum distribute_type type,
 
   dist = distribute_get (ifname);
 
-  if (type == DISTRIBUTE_IN)
-    {
-      if (dist->prefix[DISTRIBUTE_IN])
-       XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[DISTRIBUTE_IN]);
-      dist->prefix[DISTRIBUTE_IN] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, plist_name);
-    }
-  if (type == DISTRIBUTE_OUT)
-    {
-      if (dist->prefix[DISTRIBUTE_OUT])
-       XFREE(MTYPE_DISTRIBUTE_NAME, dist->prefix[DISTRIBUTE_OUT]);
-      dist->prefix[DISTRIBUTE_OUT] = XSTRDUP(MTYPE_DISTRIBUTE_NAME, 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);
@@ -261,41 +234,19 @@ 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;
-
-      XFREE(MTYPE_DISTRIBUTE_NAME, 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;
 
-      XFREE(MTYPE_DISTRIBUTE_NAME, 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;
 }
 
@@ -312,7 +263,7 @@ DEFUN (distribute_list,
 
   /* Check of distribute list type. */
   enum distribute_type type = argv[2 + prefix]->arg[0] == 'i' ?
-    DISTRIBUTE_IN : DISTRIBUTE_OUT;
+    DISTRIBUTE_V4_IN : DISTRIBUTE_V4_OUT;
 
   /* Set appropriate function call */
   void (*distfn)(const char *, enum distribute_type, const char *) = prefix ? 
@@ -329,9 +280,41 @@ DEFUN (distribute_list,
   return CMD_SUCCESS;
 }
 
+DEFUN (ipv6_distribute_list,
+       ipv6_distribute_list_cmd,
+       "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 prefix = (argv[2]->type == WORD_TKN) ? 1 : 0;
+
+  /* Check of distribute list type. */
+  enum distribute_type type = argv[3 + prefix]->arg[0] == 'i' ?
+    DISTRIBUTE_V6_IN : DISTRIBUTE_V6_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. */
+  distfn (ifname, type, argv[1 + prefix]->arg);
+
+  return CMD_SUCCESS;
+}
+       
 DEFUN (no_distribute_list,
        no_distribute_list_cmd,
-       "no distribute-list [prefix] WORD <in|out> [WORD]",
+       "no [ipv6] distribute-list [prefix] WORD <in|out> [WORD]",
        NO_STR
        "Filter networks in routing updates\n"
        "Access-list name\n"
@@ -339,11 +322,17 @@ DEFUN (no_distribute_list,
        "Filter outgoing routing updates\n"
        "Interface name\n")
 {
-  int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0;
+  int ipv6 = strmatch(argv[1]->text, "ipv6");
+  int prefix = (argv[2 + ipv6]->type == WORD_TKN) ? 1 : 0;
+
+  int idx_alname = 2 + ipv6 + prefix;
+  int idx_disttype = idx_alname + 1;
 
   /* Check of distribute list type. */
-  enum distribute_type type = argv[3 + prefix]->arg[0] == 'i' ?
-    DISTRIBUTE_IN : DISTRIBUTE_OUT;
+  enum distribute_type distin = (ipv6) ? DISTRIBUTE_V6_IN : DISTRIBUTE_V4_IN;
+  enum distribute_type distout = (ipv6) ? DISTRIBUTE_V6_OUT : DISTRIBUTE_V4_OUT;
+
+  enum distribute_type type = argv[idx_disttype]->arg[0] == 'i' ? distin : distout;
 
   /* Set appropriate function call */
   int (*distfn)(const char *, enum distribute_type, const char *) = prefix ? 
@@ -353,7 +342,6 @@ DEFUN (no_distribute_list,
   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);
 
@@ -365,79 +353,112 @@ DEFUN (no_distribute_list,
   return CMD_SUCCESS;
 }
 
+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;
@@ -448,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;
 
@@ -458,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],
-                    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],
+       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->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++;
@@ -512,6 +524,29 @@ distribute_list_init (int node)
   disthash = hash_create (distribute_hash_make,
                           (int (*) (const void *, const void *)) distribute_cmp);
 
-  install_element (node, &distribute_list_cmd);
-  install_element (node, &no_distribute_list_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);
+  } 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);
+  }
+
+  /* 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);
+    }*/
 }