summaryrefslogtreecommitdiff
path: root/lib/filter.c
diff options
context:
space:
mode:
authorpaul <paul>2002-12-13 20:15:29 +0000
committerpaul <paul>2002-12-13 20:15:29 +0000
commit718e3744195351130f4ce7dbe0613f4b3e23df93 (patch)
treebac2ad39971cd43f31241ef123bd4e470f695ac9 /lib/filter.c
Initial revision
Diffstat (limited to 'lib/filter.c')
-rw-r--r--lib/filter.c2058
1 files changed, 2058 insertions, 0 deletions
diff --git a/lib/filter.c b/lib/filter.c
new file mode 100644
index 00000000..a483ce23
--- /dev/null
+++ b/lib/filter.c
@@ -0,0 +1,2058 @@
+/* Route filtering function.
+ * Copyright (C) 1998, 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 "prefix.h"
+#include "filter.h"
+#include "memory.h"
+#include "command.h"
+#include "sockunion.h"
+#include "buffer.h"
+
+struct filter_cisco
+{
+ /* Cisco access-list */
+ int extended;
+ struct in_addr addr;
+ struct in_addr addr_mask;
+ struct in_addr mask;
+ struct in_addr mask_mask;
+};
+
+struct filter_zebra
+{
+ /* If this filter is "exact" match then this flag is set. */
+ int exact;
+
+ /* Prefix information. */
+ struct prefix prefix;
+};
+
+/* Filter element of access list */
+struct filter
+{
+ /* For doubly linked list. */
+ struct filter *next;
+ struct filter *prev;
+
+ /* Filter type information. */
+ enum filter_type type;
+
+ /* Cisco access-list */
+ int cisco;
+
+ union
+ {
+ struct filter_cisco cfilter;
+ struct filter_zebra zfilter;
+ } u;
+};
+
+/* List of access_list. */
+struct access_list_list
+{
+ struct access_list *head;
+ struct access_list *tail;
+};
+
+/* Master structure of access_list. */
+struct access_master
+{
+ /* List of access_list which name is number. */
+ struct access_list_list num;
+
+ /* List of access_list which name is string. */
+ struct access_list_list str;
+
+ /* Hook function which is executed when new access_list is added. */
+ void (*add_hook) ();
+
+ /* Hook function which is executed when access_list is deleted. */
+ void (*delete_hook) ();
+};
+
+/* Static structure for IPv4 access_list's master. */
+static struct access_master access_master_ipv4 =
+{
+ {NULL, NULL},
+ {NULL, NULL},
+ NULL,
+ NULL,
+};
+
+#ifdef HAVE_IPV6
+/* Static structure for IPv6 access_list's master. */
+static struct access_master access_master_ipv6 =
+{
+ {NULL, NULL},
+ {NULL, NULL},
+ NULL,
+ NULL,
+};
+#endif /* HAVE_IPV6 */
+
+struct access_master *
+access_master_get (afi_t afi)
+{
+ if (afi == AFI_IP)
+ return &access_master_ipv4;
+#ifdef HAVE_IPV6
+ else if (afi == AFI_IP6)
+ return &access_master_ipv6;
+#endif /* HAVE_IPV6 */
+ return NULL;
+}
+
+/* Allocate new filter structure. */
+struct filter *
+filter_new ()
+{
+ return (struct filter *) XCALLOC (MTYPE_ACCESS_FILTER,
+ sizeof (struct filter));
+}
+
+void
+filter_free (struct filter *filter)
+{
+ XFREE (MTYPE_ACCESS_FILTER, filter);
+}
+
+/* Return string of filter_type. */
+static char *
+filter_type_str (struct filter *filter)
+{
+ switch (filter->type)
+ {
+ case FILTER_PERMIT:
+ return "permit";
+ break;
+ case FILTER_DENY:
+ return "deny";
+ break;
+ case FILTER_DYNAMIC:
+ return "dynamic";
+ break;
+ default:
+ return "";
+ break;
+ }
+}
+
+/* If filter match to the prefix then return 1. */
+static int
+filter_match_cisco (struct filter *mfilter, struct prefix *p)
+{
+ struct filter_cisco *filter;
+ struct in_addr mask;
+ u_int32_t check_addr;
+ u_int32_t check_mask;
+
+ filter = &mfilter->u.cfilter;
+ check_addr = p->u.prefix4.s_addr & ~filter->addr_mask.s_addr;
+
+ if (filter->extended)
+ {
+ masklen2ip (p->prefixlen, &mask);
+ check_mask = mask.s_addr & ~filter->mask_mask.s_addr;
+
+ if (memcmp (&check_addr, &filter->addr.s_addr, 4) == 0
+ && memcmp (&check_mask, &filter->mask.s_addr, 4) == 0)
+ return 1;
+ }
+ else if (memcmp (&check_addr, &filter->addr.s_addr, 4) == 0)
+ return 1;
+
+ return 0;
+}
+
+/* If filter match to the prefix then return 1. */
+static int
+filter_match_zebra (struct filter *mfilter, struct prefix *p)
+{
+ struct filter_zebra *filter;
+
+ filter = &mfilter->u.zfilter;
+
+ if (filter->prefix.family == p->family)
+ {
+ if (filter->exact)
+ {
+ if (filter->prefix.prefixlen == p->prefixlen)
+ return prefix_match (&filter->prefix, p);
+ else
+ return 0;
+ }
+ else
+ return prefix_match (&filter->prefix, p);
+ }
+ else
+ return 0;
+}
+
+/* Allocate new access list structure. */
+struct access_list *
+access_list_new ()
+{
+ return (struct access_list *) XCALLOC (MTYPE_ACCESS_LIST,
+ sizeof (struct access_list));
+}
+
+/* Free allocated access_list. */
+void
+access_list_free (struct access_list *access)
+{
+ XFREE (MTYPE_ACCESS_LIST, access);
+}
+
+/* Delete access_list from access_master and free it. */
+void
+access_list_delete (struct access_list *access)
+{
+ struct filter *filter;
+ struct filter *next;
+ struct access_list_list *list;
+ struct access_master *master;
+
+ for (filter = access->head; filter; filter = next)
+ {
+ next = filter->next;
+ filter_free (filter);
+ }
+
+ master = access->master;
+
+ if (access->type == ACCESS_TYPE_NUMBER)
+ list = &master->num;
+ else
+ list = &master->str;
+
+ if (access->next)
+ access->next->prev = access->prev;
+ else
+ list->tail = access->prev;
+
+ if (access->prev)
+ access->prev->next = access->next;
+ else
+ list->head = access->next;
+
+ if (access->name)
+ XFREE (MTYPE_ACCESS_LIST_STR, access->name);
+
+ if (access->remark)
+ XFREE (MTYPE_TMP, access->remark);
+
+ access_list_free (access);
+}
+
+/* Insert new access list to list of access_list. Each acceess_list
+ is sorted by the name. */
+struct access_list *
+access_list_insert (afi_t afi, char *name)
+{
+ int i;
+ long number;
+ struct access_list *access;
+ struct access_list *point;
+ struct access_list_list *alist;
+ struct access_master *master;
+
+ master = access_master_get (afi);
+ if (master == NULL)
+ return NULL;
+
+ /* Allocate new access_list and copy given name. */
+ access = access_list_new ();
+ access->name = XSTRDUP (MTYPE_ACCESS_LIST_STR, name);
+ access->master = master;
+
+ /* If name is made by all digit character. We treat it as
+ number. */
+ for (number = 0, i = 0; i < strlen (name); i++)
+ {
+ if (isdigit ((int) name[i]))
+ number = (number * 10) + (name[i] - '0');
+ else
+ break;
+ }
+
+ /* In case of name is all digit character */
+ if (i == strlen (name))
+ {
+ access->type = ACCESS_TYPE_NUMBER;
+
+ /* Set access_list to number list. */
+ alist = &master->num;
+
+ for (point = alist->head; point; point = point->next)
+ if (atol (point->name) >= number)
+ break;
+ }
+ else
+ {
+ access->type = ACCESS_TYPE_STRING;
+
+ /* Set access_list to string list. */
+ alist = &master->str;
+
+ /* Set point to insertion point. */
+ for (point = alist->head; point; point = point->next)
+ if (strcmp (point->name, name) >= 0)
+ break;
+ }
+
+ /* In case of this is the first element of master. */
+ if (alist->head == NULL)
+ {
+ alist->head = alist->tail = access;
+ return access;
+ }
+
+ /* In case of insertion is made at the tail of access_list. */
+ if (point == NULL)
+ {
+ access->prev = alist->tail;
+ alist->tail->next = access;
+ alist->tail = access;
+ return access;
+ }
+
+ /* In case of insertion is made at the head of access_list. */
+ if (point == alist->head)
+ {
+ access->next = alist->head;
+ alist->head->prev = access;
+ alist->head = access;
+ return access;
+ }
+
+ /* Insertion is made at middle of the access_list. */
+ access->next = point;
+ access->prev = point->prev;
+
+ if (point->prev)
+ point->prev->next = access;
+ point->prev = access;
+
+ return access;
+}
+
+/* Lookup access_list from list of access_list by name. */
+struct access_list *
+access_list_lookup (afi_t afi, char *name)
+{
+ struct access_list *access;
+ struct access_master *master;
+
+ if (name == NULL)
+ return NULL;
+
+ master = access_master_get (afi);
+ if (master == NULL)
+ return NULL;
+
+ for (access = master->num.head; access; access = access->next)
+ if (strcmp (access->name, name) == 0)
+ return access;
+
+ for (access = master->str.head; access; access = access->next)
+ if (strcmp (access->name, name) == 0)
+ return access;
+
+ return NULL;
+}
+
+/* Get access list from list of access_list. If there isn't matched
+ access_list create new one and return it. */
+struct access_list *
+access_list_get (afi_t afi, char *name)
+{
+ struct access_list *access;
+
+ access = access_list_lookup (afi, name);
+ if (access == NULL)
+ access = access_list_insert (afi, name);
+ return access;
+}
+
+/* Apply access list to object (which should be struct prefix *). */
+enum filter_type
+access_list_apply (struct access_list *access, void *object)
+{
+ struct filter *filter;
+ struct prefix *p;
+
+ p = (struct prefix *) object;
+
+ if (access == NULL)
+ return FILTER_DENY;
+
+ for (filter = access->head; filter; filter = filter->next)
+ {
+ if (filter->cisco)
+ {
+ if (filter_match_cisco (filter, p))
+ return filter->type;
+ }
+ else
+ {
+ if (filter_match_zebra (filter, p))
+ return filter->type;
+ }
+ }
+
+ return FILTER_DENY;
+}
+
+/* Add hook function. */
+void
+access_list_add_hook (void (*func) (struct access_list *access))
+{
+ access_master_ipv4.add_hook = func;
+#ifdef HAVE_IPV6
+ access_master_ipv6.add_hook = func;
+#endif /* HAVE_IPV6 */
+}
+
+/* Delete hook function. */
+void
+access_list_delete_hook (void (*func) (struct access_list *access))
+{
+ access_master_ipv4.delete_hook = func;
+#ifdef HAVE_IPV6
+ access_master_ipv6.delete_hook = func;
+#endif /* HAVE_IPV6 */
+}
+
+/* Add new filter to the end of specified access_list. */
+void
+access_list_filter_add (struct access_list *access, struct filter *filter)
+{
+ filter->next = NULL;
+ filter->prev = access->tail;
+
+ if (access->tail)
+ access->tail->next = filter;
+ else
+ access->head = filter;
+ access->tail = filter;
+
+ /* Run hook function. */
+ if (access->master->add_hook)
+ (*access->master->add_hook) (access);
+}
+
+/* If access_list has no filter then return 1. */
+static int
+access_list_empty (struct access_list *access)
+{
+ if (access->head == NULL && access->tail == NULL)
+ return 1;
+ else
+ return 0;
+}
+
+/* Delete filter from specified access_list. If there is hook
+ function execute it. */
+void
+access_list_filter_delete (struct access_list *access, struct filter *filter)
+{
+ struct access_master *master;
+
+ master = access->master;
+
+ if (filter->next)
+ filter->next->prev = filter->prev;
+ else
+ access->tail = filter->prev;
+
+ if (filter->prev)
+ filter->prev->next = filter->next;
+ else
+ access->head = filter->next;
+
+ filter_free (filter);
+
+ /* If access_list becomes empty delete it from access_master. */
+ if (access_list_empty (access))
+ access_list_delete (access);
+
+ /* Run hook function. */
+ if (master->delete_hook)
+ (*master->delete_hook) (access);
+}
+
+/*
+ deny Specify packets to reject
+ permit Specify packets to forward
+ dynamic ?
+*/
+
+/*
+ Hostname or A.B.C.D Address to match
+ any Any source host
+ host A single host address
+*/
+
+struct filter *
+filter_lookup_cisco (struct access_list *access, struct filter *mnew)
+{
+ struct filter *mfilter;
+ struct filter_cisco *filter;
+ struct filter_cisco *new;
+
+ new = &mnew->u.cfilter;
+
+ for (mfilter = access->head; mfilter; mfilter = mfilter->next)
+ {
+ filter = &mfilter->u.cfilter;
+
+ if (filter->extended)
+ {
+ if (mfilter->type == mnew->type
+ && filter->addr.s_addr == new->addr.s_addr
+ && filter->addr_mask.s_addr == new->addr_mask.s_addr
+ && filter->mask.s_addr == new->mask.s_addr
+ && filter->mask_mask.s_addr == new->mask_mask.s_addr)
+ return mfilter;
+ }
+ else
+ {
+ if (mfilter->type == mnew->type
+ && filter->addr.s_addr == new->addr.s_addr
+ && filter->addr_mask.s_addr == new->addr_mask.s_addr)
+ return mfilter;
+ }
+ }
+
+ return NULL;
+}
+
+struct filter *
+filter_lookup_zebra (struct access_list *access, struct filter *mnew)
+{
+ struct filter *mfilter;
+ struct filter_zebra *filter;
+ struct filter_zebra *new;
+
+ new = &mnew->u.zfilter;
+
+ for (mfilter = access->head; mfilter; mfilter = mfilter->next)
+ {
+ filter = &mfilter->u.zfilter;
+
+ if (filter->exact == new->exact
+ && mfilter->type == mnew->type
+ && prefix_same (&filter->prefix, &new->prefix))
+ return mfilter;
+ }
+ return NULL;
+}
+
+int
+vty_access_list_remark_unset (struct vty *vty, afi_t afi, char *name)
+{
+ struct access_list *access;
+
+ access = access_list_lookup (afi, name);
+ if (! access)
+ {
+ vty_out (vty, "%% access-list %s doesn't exist%s", name,
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (access->remark)
+ {
+ XFREE (MTYPE_TMP, access->remark);
+ access->remark = NULL;
+ }
+
+ if (access->head == NULL && access->tail == NULL && access->remark == NULL)
+ access_list_delete (access);
+
+ return CMD_SUCCESS;
+}
+
+int
+filter_set_cisco (struct vty *vty, char *name_str, char *type_str,
+ char *addr_str, char *addr_mask_str,
+ char *mask_str, char *mask_mask_str,
+ int extended, int set)
+{
+ int ret;
+ enum filter_type type;
+ struct filter *mfilter;
+ struct filter_cisco *filter;
+ struct access_list *access;
+ struct in_addr addr;
+ struct in_addr addr_mask;
+ struct in_addr mask;
+ struct in_addr mask_mask;
+
+ /* Check of filter type. */
+ if (strncmp (type_str, "p", 1) == 0)
+ type = FILTER_PERMIT;
+ else if (strncmp (type_str, "d", 1) == 0)
+ type = FILTER_DENY;
+ else
+ {
+ vty_out (vty, "%% filter type must be permit or deny%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ret = inet_aton (addr_str, &addr);
+ if (ret <= 0)
+ {
+ vty_out (vty, "%%Inconsistent address and mask%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ret = inet_aton (addr_mask_str, &addr_mask);
+ if (ret <= 0)
+ {
+ vty_out (vty, "%%Inconsistent address and mask%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (extended)
+ {
+ ret = inet_aton (mask_str, &mask);
+ if (ret <= 0)
+ {
+ vty_out (vty, "%%Inconsistent address and mask%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ret = inet_aton (mask_mask_str, &mask_mask);
+ if (ret <= 0)
+ {
+ vty_out (vty, "%%Inconsistent address and mask%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+
+ mfilter = filter_new();
+ mfilter->type = type;
+ mfilter->cisco = 1;
+ filter = &mfilter->u.cfilter;
+ filter->extended = extended;
+ filter->addr.s_addr = addr.s_addr & ~addr_mask.s_addr;
+ filter->addr_mask.s_addr = addr_mask.s_addr;
+
+ if (extended)
+ {
+ filter->mask.s_addr = mask.s_addr & ~mask_mask.s_addr;
+ filter->mask_mask.s_addr = mask_mask.s_addr;
+ }
+
+ /* Install new filter to the access_list. */
+ access = access_list_get (AFI_IP, name_str);
+
+ if (set)
+ {
+ if (filter_lookup_cisco (access, mfilter))
+ filter_free (mfilter);
+ else
+ access_list_filter_add (access, mfilter);
+ }
+ else
+ {
+ struct filter *delete_filter;
+
+ delete_filter = filter_lookup_cisco (access, mfilter);
+ if (delete_filter)
+ access_list_filter_delete (access, delete_filter);
+
+ filter_free (mfilter);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/* Standard access-list */
+DEFUN (access_list_standard,
+ access_list_standard_cmd,
+ "access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D A.B.C.D",
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP standard access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Address to match\n"
+ "Wildcard bits\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], argv[2], argv[3],
+ NULL, NULL, 0, 1);
+}
+
+DEFUN (access_list_standard_nomask,
+ access_list_standard_nomask_cmd,
+ "access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D",
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP standard access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Address to match\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], argv[2], "0.0.0.0",
+ NULL, NULL, 0, 1);
+}
+
+DEFUN (access_list_standard_host,
+ access_list_standard_host_cmd,
+ "access-list (<1-99>|<1300-1999>) (deny|permit) host A.B.C.D",
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP standard access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "A single host address\n"
+ "Address to match\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], argv[2], "0.0.0.0",
+ NULL, NULL, 0, 1);
+}
+
+DEFUN (access_list_standard_any,
+ access_list_standard_any_cmd,
+ "access-list (<1-99>|<1300-1999>) (deny|permit) any",
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP standard access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any source host\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+ "255.255.255.255", NULL, NULL, 0, 1);
+}
+
+DEFUN (no_access_list_standard,
+ no_access_list_standard_cmd,
+ "no access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D A.B.C.D",
+ NO_STR
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP standard access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Address to match\n"
+ "Wildcard bits\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], argv[2], argv[3],
+ NULL, NULL, 0, 0);
+}
+
+DEFUN (no_access_list_standard_nomask,
+ no_access_list_standard_nomask_cmd,
+ "no access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D",
+ NO_STR
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP standard access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Address to match\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], argv[2], "0.0.0.0",
+ NULL, NULL, 0, 0);
+}
+
+DEFUN (no_access_list_standard_host,
+ no_access_list_standard_host_cmd,
+ "no access-list (<1-99>|<1300-1999>) (deny|permit) host A.B.C.D",
+ NO_STR
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP standard access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "A single host address\n"
+ "Address to match\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], argv[2], "0.0.0.0",
+ NULL, NULL, 0, 0);
+}
+
+DEFUN (no_access_list_standard_any,
+ no_access_list_standard_any_cmd,
+ "no access-list (<1-99>|<1300-1999>) (deny|permit) any",
+ NO_STR
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP standard access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any source host\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+ "255.255.255.255", NULL, NULL, 0, 0);
+}
+
+/* Extended access-list */
+DEFUN (access_list_extended,
+ access_list_extended_cmd,
+ "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D",
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Source address\n"
+ "Source wildcard bits\n"
+ "Destination address\n"
+ "Destination Wildcard bits\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+ argv[3], argv[4], argv[5], 1 ,1);
+}
+
+DEFUN (access_list_extended_mask_any,
+ access_list_extended_mask_any_cmd,
+ "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D any",
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Source address\n"
+ "Source wildcard bits\n"
+ "Any destination host\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+ argv[3], "0.0.0.0",
+ "255.255.255.255", 1, 1);
+}
+
+DEFUN (access_list_extended_any_mask,
+ access_list_extended_any_mask_cmd,
+ "access-list (<100-199>|<2000-2699>) (deny|permit) ip any A.B.C.D A.B.C.D",
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Any source host\n"
+ "Destination address\n"
+ "Destination Wildcard bits\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+ "255.255.255.255", argv[2],
+ argv[3], 1, 1);
+}
+
+DEFUN (access_list_extended_any_any,
+ access_list_extended_any_any_cmd,
+ "access-list (<100-199>|<2000-2699>) (deny|permit) ip any any",
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Any source host\n"
+ "Any destination host\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+ "255.255.255.255", "0.0.0.0",
+ "255.255.255.255", 1, 1);
+}
+
+DEFUN (access_list_extended_mask_host,
+ access_list_extended_mask_host_cmd,
+ "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D host A.B.C.D",
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Source address\n"
+ "Source wildcard bits\n"
+ "A single destination host\n"
+ "Destination address\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+ argv[3], argv[4],
+ "0.0.0.0", 1, 1);
+}
+
+DEFUN (access_list_extended_host_mask,
+ access_list_extended_host_mask_cmd,
+ "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D A.B.C.D A.B.C.D",
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "A single source host\n"
+ "Source address\n"
+ "Destination address\n"
+ "Destination Wildcard bits\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+ "0.0.0.0", argv[3],
+ argv[4], 1, 1);
+}
+
+DEFUN (access_list_extended_host_host,
+ access_list_extended_host_host_cmd,
+ "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D host A.B.C.D",
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "A single source host\n"
+ "Source address\n"
+ "A single destination host\n"
+ "Destination address\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+ "0.0.0.0", argv[3],
+ "0.0.0.0", 1, 1);
+}
+
+DEFUN (access_list_extended_any_host,
+ access_list_extended_any_host_cmd,
+ "access-list (<100-199>|<2000-2699>) (deny|permit) ip any host A.B.C.D",
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Any source host\n"
+ "A single destination host\n"
+ "Destination address\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+ "255.255.255.255", argv[2],
+ "0.0.0.0", 1, 1);
+}
+
+DEFUN (access_list_extended_host_any,
+ access_list_extended_host_any_cmd,
+ "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D any",
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "A single source host\n"
+ "Source address\n"
+ "Any destination host\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+ "0.0.0.0", "0.0.0.0",
+ "255.255.255.255", 1, 1);
+}
+
+DEFUN (no_access_list_extended,
+ no_access_list_extended_cmd,
+ "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D",
+ NO_STR
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Source address\n"
+ "Source wildcard bits\n"
+ "Destination address\n"
+ "Destination Wildcard bits\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+ argv[3], argv[4], argv[5], 1, 0);
+}
+
+DEFUN (no_access_list_extended_mask_any,
+ no_access_list_extended_mask_any_cmd,
+ "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D any",
+ NO_STR
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Source address\n"
+ "Source wildcard bits\n"
+ "Any destination host\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+ argv[3], "0.0.0.0",
+ "255.255.255.255", 1, 0);
+}
+
+DEFUN (no_access_list_extended_any_mask,
+ no_access_list_extended_any_mask_cmd,
+ "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any A.B.C.D A.B.C.D",
+ NO_STR
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Any source host\n"
+ "Destination address\n"
+ "Destination Wildcard bits\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+ "255.255.255.255", argv[2],
+ argv[3], 1, 0);
+}
+
+DEFUN (no_access_list_extended_any_any,
+ no_access_list_extended_any_any_cmd,
+ "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any any",
+ NO_STR
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Any source host\n"
+ "Any destination host\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+ "255.255.255.255", "0.0.0.0",
+ "255.255.255.255", 1, 0);
+}
+
+DEFUN (no_access_list_extended_mask_host,
+ no_access_list_extended_mask_host_cmd,
+ "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D host A.B.C.D",
+ NO_STR
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Source address\n"
+ "Source wildcard bits\n"
+ "A single destination host\n"
+ "Destination address\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+ argv[3], argv[4],
+ "0.0.0.0", 1, 0);
+}
+
+DEFUN (no_access_list_extended_host_mask,
+ no_access_list_extended_host_mask_cmd,
+ "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D A.B.C.D A.B.C.D",
+ NO_STR
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "A single source host\n"
+ "Source address\n"
+ "Destination address\n"
+ "Destination Wildcard bits\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+ "0.0.0.0", argv[3],
+ argv[4], 1, 0);
+}
+
+DEFUN (no_access_list_extended_host_host,
+ no_access_list_extended_host_host_cmd,
+ "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D host A.B.C.D",
+ NO_STR
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "A single source host\n"
+ "Source address\n"
+ "A single destination host\n"
+ "Destination address\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+ "0.0.0.0", argv[3],
+ "0.0.0.0", 1, 0);
+}
+
+DEFUN (no_access_list_extended_any_host,
+ no_access_list_extended_any_host_cmd,
+ "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any host A.B.C.D",
+ NO_STR
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "Any source host\n"
+ "A single destination host\n"
+ "Destination address\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+ "255.255.255.255", argv[2],
+ "0.0.0.0", 1, 0);
+}
+
+DEFUN (no_access_list_extended_host_any,
+ no_access_list_extended_host_any_cmd,
+ "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D any",
+ NO_STR
+ "Add an access list entry\n"
+ "IP extended access list\n"
+ "IP extended access list (expanded range)\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any Internet Protocol\n"
+ "A single source host\n"
+ "Source address\n"
+ "Any destination host\n")
+{
+ return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+ "0.0.0.0", "0.0.0.0",
+ "255.255.255.255", 1, 0);
+}
+
+int
+filter_set_zebra (struct vty *vty, char *name_str, char *type_str,
+ afi_t afi, char *prefix_str, int exact, int set)
+{
+ int ret;
+ enum filter_type type;
+ struct filter *mfilter;
+ struct filter_zebra *filter;
+ struct access_list *access;
+ struct prefix p;
+
+ /* Check of filter type. */
+ if (strncmp (type_str, "p", 1) == 0)
+ type = FILTER_PERMIT;
+ else if (strncmp (type_str, "d", 1) == 0)
+ type = FILTER_DENY;
+ else
+ {
+ vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Check string format of prefix and prefixlen. */
+ if (afi == AFI_IP)
+ {
+ ret = str2prefix_ipv4 (prefix_str, (struct prefix_ipv4 *)&p);
+ if (ret <= 0)
+ {
+ vty_out (vty, "IP address prefix/prefixlen is malformed%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+#ifdef HAVE_IPV6
+ else if (afi == AFI_IP6)
+ {
+ ret = str2prefix_ipv6 (prefix_str, (struct prefix_ipv6 *) &p);
+ if (ret <= 0)
+ {
+ vty_out (vty, "IPv6 address prefix/prefixlen is malformed%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ }
+#endif /* HAVE_IPV6 */
+ else
+ return CMD_WARNING;
+
+ mfilter = filter_new ();
+ mfilter->type = type;
+ filter = &mfilter->u.zfilter;
+ prefix_copy (&filter->prefix, &p);
+
+ /* "exact-match" */
+ if (exact)
+ filter->exact = 1;
+
+ /* Install new filter to the access_list. */
+ access = access_list_get (afi, name_str);
+
+ if (set)
+ {
+ if (filter_lookup_zebra (access, mfilter))
+ filter_free (mfilter);
+ else
+ access_list_filter_add (access, mfilter);
+ }
+ else
+ {
+ struct filter *delete_filter;
+
+ delete_filter = filter_lookup_zebra (access, mfilter);
+ if (delete_filter)
+ access_list_filter_delete (access, delete_filter);
+
+ filter_free (mfilter);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/* Zebra access-list */
+DEFUN (access_list,
+ access_list_cmd,
+ "access-list WORD (deny|permit) A.B.C.D/M",
+ "Add an access list entry\n"
+ "IP zebra access-list name\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Prefix to match. e.g. 10.0.0.0/8\n")
+{
+ return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, argv[2], 0, 1);
+}
+
+DEFUN (access_list_exact,
+ access_list_exact_cmd,
+ "access-list WORD (deny|permit) A.B.C.D/M exact-match",
+ "Add an access list entry\n"
+ "IP zebra access-list name\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Prefix to match. e.g. 10.0.0.0/8\n"
+ "Exact match of the prefixes\n")
+{
+ return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, argv[2], 1, 1);
+}
+
+DEFUN (access_list_any,
+ access_list_any_cmd,
+ "access-list WORD (deny|permit) any",
+ "Add an access list entry\n"
+ "IP zebra access-list name\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Prefix to match. e.g. 10.0.0.0/8\n")
+{
+ return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, "0.0.0.0/0", 0, 1);
+}
+
+DEFUN (no_access_list,
+ no_access_list_cmd,
+ "no access-list WORD (deny|permit) A.B.C.D/M",
+ NO_STR
+ "Add an access list entry\n"
+ "IP zebra access-list name\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Prefix to match. e.g. 10.0.0.0/8\n")
+{
+ return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, argv[2], 0, 0);
+}
+
+DEFUN (no_access_list_exact,
+ no_access_list_exact_cmd,
+ "no access-list WORD (deny|permit) A.B.C.D/M exact-match",
+ NO_STR
+ "Add an access list entry\n"
+ "IP zebra access-list name\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Prefix to match. e.g. 10.0.0.0/8\n"
+ "Exact match of the prefixes\n")
+{
+ return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, argv[2], 1, 0);
+}
+
+DEFUN (no_access_list_any,
+ no_access_list_any_cmd,
+ "no access-list WORD (deny|permit) any",
+ NO_STR
+ "Add an access list entry\n"
+ "IP zebra access-list name\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Prefix to match. e.g. 10.0.0.0/8\n")
+{
+ return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, "0.0.0.0/0", 0, 0);
+}
+
+DEFUN (no_access_list_all,
+ no_access_list_all_cmd,
+ "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD)",
+ NO_STR
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP extended access list\n"
+ "IP standard access list (expanded range)\n"
+ "IP extended access list (expanded range)\n"
+ "IP zebra access-list name\n")
+{
+ struct access_list *access;
+ struct access_master *master;
+
+ /* Looking up access_list. */
+ access = access_list_lookup (AFI_IP, argv[0]);
+ if (access == NULL)
+ {
+ vty_out (vty, "%% access-list %s doesn't exist%s", argv[0],
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ master = access->master;
+
+ /* Delete all filter from access-list. */
+ access_list_delete (access);
+
+ /* Run hook function. */
+ if (master->delete_hook)
+ (*master->delete_hook) (access);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (access_list_remark,
+ access_list_remark_cmd,
+ "access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark .LINE",
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP extended access list\n"
+ "IP standard access list (expanded range)\n"
+ "IP extended access list (expanded range)\n"
+ "IP zebra access-list\n"
+ "Access list entry comment\n"
+ "Comment up to 100 characters\n")
+{
+ struct access_list *access;
+ struct buffer *b;
+ int i;
+
+ access = access_list_get (AFI_IP, argv[0]);
+
+ if (access->remark)
+ {
+ XFREE (MTYPE_TMP, access->remark);
+ access->remark = NULL;
+ }
+
+ /* Below is remark get codes. */
+ b = buffer_new (1024);
+ for (i = 1; i < argc; i++)
+ {
+ buffer_putstr (b, (u_char *)argv[i]);
+ buffer_putc (b, ' ');
+ }
+ buffer_putc (b, '\0');
+
+ access->remark = buffer_getstr (b);
+
+ buffer_free (b);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_access_list_remark,
+ no_access_list_remark_cmd,
+ "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark",
+ NO_STR
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP extended access list\n"
+ "IP standard access list (expanded range)\n"
+ "IP extended access list (expanded range)\n"
+ "IP zebra access-list\n"
+ "Access list entry comment\n")
+{
+ return vty_access_list_remark_unset (vty, AFI_IP, argv[0]);
+}
+
+ALIAS (no_access_list_remark,
+ no_access_list_remark_arg_cmd,
+ "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark .LINE",
+ NO_STR
+ "Add an access list entry\n"
+ "IP standard access list\n"
+ "IP extended access list\n"
+ "IP standard access list (expanded range)\n"
+ "IP extended access list (expanded range)\n"
+ "IP zebra access-list\n"
+ "Access list entry comment\n"
+ "Comment up to 100 characters\n")
+
+#ifdef HAVE_IPV6
+DEFUN (ipv6_access_list,
+ ipv6_access_list_cmd,
+ "ipv6 access-list WORD (deny|permit) X:X::X:X/M",
+ IPV6_STR
+ "Add an access list entry\n"
+ "IPv6 zebra access-list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Prefix to match. e.g. 3ffe:506::/32\n")
+{
+ return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, argv[2], 0, 1);
+}
+
+DEFUN (ipv6_access_list_exact,
+ ipv6_access_list_exact_cmd,
+ "ipv6 access-list WORD (deny|permit) X:X::X:X/M exact-match",
+ IPV6_STR
+ "Add an access list entry\n"
+ "IPv6 zebra access-list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Prefix to match. e.g. 3ffe:506::/32\n"
+ "Exact match of the prefixes\n")
+{
+ return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, argv[2], 1, 1);
+}
+
+DEFUN (ipv6_access_list_any,
+ ipv6_access_list_any_cmd,
+ "ipv6 access-list WORD (deny|permit) any",
+ IPV6_STR
+ "Add an access list entry\n"
+ "IPv6 zebra access-list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any prefixi to match\n")
+{
+ return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, "::/0", 0, 1);
+}
+
+DEFUN (no_ipv6_access_list,
+ no_ipv6_access_list_cmd,
+ "no ipv6 access-list WORD (deny|permit) X:X::X:X/M",
+ NO_STR
+ IPV6_STR
+ "Add an access list entry\n"
+ "IPv6 zebra access-list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Prefix to match. e.g. 3ffe:506::/32\n")
+{
+ return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, argv[2], 0, 0);
+}
+
+DEFUN (no_ipv6_access_list_exact,
+ no_ipv6_access_list_exact_cmd,
+ "no ipv6 access-list WORD (deny|permit) X:X::X:X/M exact-match",
+ NO_STR
+ IPV6_STR
+ "Add an access list entry\n"
+ "IPv6 zebra access-list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Prefix to match. e.g. 3ffe:506::/32\n"
+ "Exact match of the prefixes\n")
+{
+ return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, argv[2], 1, 0);
+}
+
+DEFUN (no_ipv6_access_list_any,
+ no_ipv6_access_list_any_cmd,
+ "no ipv6 access-list WORD (deny|permit) any",
+ NO_STR
+ IPV6_STR
+ "Add an access list entry\n"
+ "IPv6 zebra access-list\n"
+ "Specify packets to reject\n"
+ "Specify packets to forward\n"
+ "Any prefixi to match\n")
+{
+ return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, "::/0", 0, 0);
+}
+
+
+DEFUN (no_ipv6_access_list_all,
+ no_ipv6_access_list_all_cmd,
+ "no ipv6 access-list WORD",
+ NO_STR
+ IPV6_STR
+ "Add an access list entry\n"
+ "IPv6 zebra access-list\n")
+{
+ struct access_list *access;
+ struct access_master *master;
+
+ /* Looking up access_list. */
+ access = access_list_lookup (AFI_IP6, argv[0]);
+ if (access == NULL)
+ {
+ vty_out (vty, "%% access-list %s doesn't exist%s", argv[0],
+ VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ master = access->master;
+
+ /* Delete all filter from access-list. */
+ access_list_delete (access);
+
+ /* Run hook function. */
+ if (master->delete_hook)
+ (*master->delete_hook) (access);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_access_list_remark,
+ ipv6_access_list_remark_cmd,
+ "ipv6 access-list WORD remark .LINE",
+ IPV6_STR
+ "Add an access list entry\n"
+ "IPv6 zebra access-list\n"
+ "Access list entry comment\n"
+ "Comment up to 100 characters\n")
+{
+ struct access_list *access;
+ struct buffer *b;
+ int i;
+
+ access = access_list_get (AFI_IP6, argv[0]);
+
+ if (access->remark)
+ {
+ XFREE (MTYPE_TMP, access->remark);
+ access->remark = NULL;
+ }
+
+ /* Below is remark get codes. */
+ b = buffer_new (1024);
+ for (i = 1; i < argc; i++)
+ {
+ buffer_putstr (b, (u_char *)argv[i]);
+ buffer_putc (b, ' ');
+ }
+ buffer_putc (b, '\0');
+
+ access->remark = buffer_getstr (b);
+
+ buffer_free (b);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_access_list_remark,
+ no_ipv6_access_list_remark_cmd,
+ "no ipv6 access-list WORD remark",
+ NO_STR
+ IPV6_STR
+ "Add an access list entry\n"
+ "IPv6 zebra access-list\n"
+ "Access list entry comment\n")
+{
+ return vty_access_list_remark_unset (vty, AFI_IP6, argv[0]);
+}
+
+ALIAS (no_ipv6_access_list_remark,
+ no_ipv6_access_list_remark_arg_cmd,
+ "no ipv6 access-list WORD remark .LINE",
+ NO_STR
+ IPV6_STR
+ "Add an access list entry\n"
+ "IPv6 zebra access-list\n"
+ "Access list entry comment\n"
+ "Comment up to 100 characters\n")
+#endif /* HAVE_IPV6 */
+
+void config_write_access_zebra (struct vty *, struct filter *);
+void config_write_access_cisco (struct vty *, struct filter *);
+
+/* show access-list command. */
+int
+filter_show (struct vty *vty, char *name, afi_t afi)
+{
+ struct access_list *access;
+ struct access_master *master;
+ struct filter *mfilter;
+ struct filter_cisco *filter;
+ int write = 0;
+
+ master = access_master_get (afi);
+ if (master == NULL)
+ return 0;
+
+ for (access = master->num.head; access; access = access->next)
+ {
+ if (name && strcmp (access->name, name) != 0)
+ continue;
+
+ write = 1;
+
+ for (mfilter = access->head; mfilter; mfilter = mfilter->next)
+ {
+ filter = &mfilter->u.cfilter;
+
+ if (write)
+ {
+ vty_out (vty, "%s IP%s access list %s%s",
+ mfilter->cisco ?
+ (filter->extended ? "Extended" : "Standard") : "Zebra",
+ afi == AFI_IP6 ? "v6" : "",
+ access->name, VTY_NEWLINE);
+ write = 0;
+ }
+
+ vty_out (vty, " %s%s", filter_type_str (mfilter),
+ mfilter->type == FILTER_DENY ? " " : "");
+
+ if (! mfilter->cisco)
+ config_write_access_zebra (vty, mfilter);
+ else if (filter->extended)
+ config_write_access_cisco (vty, mfilter);
+ else
+ {
+ if (filter->addr_mask.s_addr == 0xffffffff)
+ vty_out (vty, " any%s", VTY_NEWLINE);
+ else
+ {
+ vty_out (vty, " %s", inet_ntoa (filter->addr));
+ if (filter->addr_mask.s_addr != 0)
+ vty_out (vty, ", wildcard bits %s", inet_ntoa (filter->addr_mask));
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ }
+ }
+ }
+
+ for (access = master->str.head; access; access = access->next)
+ {
+ if (name && strcmp (access->name, name) != 0)
+ continue;
+
+ write = 1;
+
+ for (mfilter = access->head; mfilter; mfilter = mfilter->next)
+ {
+ filter = &mfilter->u.cfilter;
+
+ if (write)
+ {
+ vty_out (vty, "%s IP%s access list %s%s",
+ mfilter->cisco ?
+ (filter->extended ? "Extended" : "Standard") : "Zebra",
+ afi == AFI_IP6 ? "v6" : "",
+ access->name, VTY_NEWLINE);
+ write = 0;
+ }
+
+ vty_out (vty, " %s%s", filter_type_str (mfilter),
+ mfilter->type == FILTER_DENY ? " " : "");
+
+ if (! mfilter->cisco)
+ config_write_access_zebra (vty, mfilter);
+ else if (filter->extended)
+ config_write_access_cisco (vty, mfilter);
+ else
+ {
+ if (filter->addr_mask.s_addr == 0xffffffff)
+ vty_out (vty, " any%s", VTY_NEWLINE);
+ else
+ {
+ vty_out (vty, " %s", inet_ntoa (filter->addr));
+ if (filter->addr_mask.s_addr != 0)
+ vty_out (vty, ", wildcard bits %s", inet_ntoa (filter->addr_mask));
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ }
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_access_list,
+ show_ip_access_list_cmd,
+ "show ip access-list",
+ SHOW_STR
+ IP_STR
+ "List IP access lists\n")
+{
+ return filter_show (vty, NULL, AFI_IP);
+}
+
+DEFUN (show_ip_access_list_name,
+ show_ip_access_list_name_cmd,
+ "show ip access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD)",
+ SHOW_STR
+ IP_STR
+ "List IP access lists\n"
+ "IP standard access list\n"
+ "IP extended access list\n"
+ "IP standard access list (expanded range)\n"
+ "IP extended access list (expanded range)\n"
+ "IP zebra access-list\n")
+{
+ return filter_show (vty, argv[0], AFI_IP);
+}
+
+#ifdef HAVE_IPV6
+DEFUN (show_ipv6_access_list,
+ show_ipv6_access_list_cmd,
+ "show ipv6 access-list",
+ SHOW_STR
+ IPV6_STR
+ "List IPv6 access lists\n")
+{
+ return filter_show (vty, NULL, AFI_IP6);
+}
+
+DEFUN (show_ipv6_access_list_name,
+ show_ipv6_access_list_name_cmd,
+ "show ipv6 access-list WORD",
+ SHOW_STR
+ IPV6_STR
+ "List IPv6 access lists\n"
+ "IPv6 zebra access-list\n")
+{
+ return filter_show (vty, argv[0], AFI_IP6);
+}
+#endif /* HAVE_IPV6 */
+
+void
+config_write_access_cisco (struct vty *vty, struct filter *mfilter)
+{
+ struct filter_cisco *filter;
+
+ filter = &mfilter->u.cfilter;
+
+ if (filter->extended)
+ {
+ vty_out (vty, " ip");
+ if (filter->addr_mask.s_addr == 0xffffffff)
+ vty_out (vty, " any");
+ else if (filter->addr_mask.s_addr == 0)
+ vty_out (vty, " host %s", inet_ntoa (filter->addr));
+ else
+ {
+ vty_out (vty, " %s", inet_ntoa (filter->addr));
+ vty_out (vty, " %s", inet_ntoa (filter->addr_mask));
+ }
+
+ if (filter->mask_mask.s_addr == 0xffffffff)
+ vty_out (vty, " any");
+ else if (filter->mask_mask.s_addr == 0)
+ vty_out (vty, " host %s", inet_ntoa (filter->mask));
+ else
+ {
+ vty_out (vty, " %s", inet_ntoa (filter->mask));
+ vty_out (vty, " %s", inet_ntoa (filter->mask_mask));
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ else
+ {
+ if (filter->addr_mask.s_addr == 0xffffffff)
+ vty_out (vty, " any%s", VTY_NEWLINE);
+ else
+ {
+ vty_out (vty, " %s", inet_ntoa (filter->addr));
+ if (filter->addr_mask.s_addr != 0)
+ vty_out (vty, " %s", inet_ntoa (filter->addr_mask));
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ }
+}
+
+void
+config_write_access_zebra (struct vty *vty, struct filter *mfilter)
+{
+ struct filter_zebra *filter;
+ struct prefix *p;
+ char buf[BUFSIZ];
+
+ filter = &mfilter->u.zfilter;
+ p = &filter->prefix;
+
+ if (p->prefixlen == 0 && ! filter->exact)
+ vty_out (vty, " any");
+ else
+ vty_out (vty, " %s/%d%s",
+ inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+ p->prefixlen,
+ filter->exact ? " exact-match" : "");
+
+ vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+int
+config_write_access (struct vty *vty, afi_t afi)
+{
+ struct access_list *access;
+ struct access_master *master;
+ struct filter *mfilter;
+ int write = 0;
+
+ master = access_master_get (afi);
+ if (master == NULL)
+ return 0;
+
+ for (access = master->num.head; access; access = access->next)
+ {
+ if (access->remark)
+ {
+ vty_out (vty, "%saccess-list %s remark %s%s",
+ afi == AFI_IP ? "" : "ipv6 ",
+ access->name, access->remark,
+ VTY_NEWLINE);
+ write++;
+ }
+
+ for (mfilter = access->head; mfilter; mfilter = mfilter->next)
+ {
+ vty_out (vty, "%saccess-list %s %s",
+ afi == AFI_IP ? "" : "ipv6 ",
+ access->name,
+ filter_type_str (mfilter));
+
+ if (mfilter->cisco)
+ config_write_access_cisco (vty, mfilter);
+ else
+ config_write_access_zebra (vty, mfilter);
+
+ write++;
+ }
+ }
+
+ for (access = master->str.head; access; access = access->next)
+ {
+ if (access->remark)
+ {
+ vty_out (vty, "%saccess-list %s remark %s%s",
+ afi == AFI_IP ? "" : "ipv6 ",
+ access->name, access->remark,
+ VTY_NEWLINE);
+ write++;
+ }
+
+ for (mfilter = access->head; mfilter; mfilter = mfilter->next)
+ {
+ vty_out (vty, "%saccess-list %s %s",
+ afi == AFI_IP ? "" : "ipv6 ",
+ access->name,
+ filter_type_str (mfilter));
+
+ if (mfilter->cisco)
+ config_write_access_cisco (vty, mfilter);
+ else
+ config_write_access_zebra (vty, mfilter);
+
+ write++;
+ }
+ }
+ return write;
+}
+
+/* Access-list node. */
+struct cmd_node access_node =
+{
+ ACCESS_NODE,
+ "", /* Access list has no interface. */
+ 1
+};
+
+int
+config_write_access_ipv4 (struct vty *vty)
+{
+ return config_write_access (vty, AFI_IP);
+}
+
+void
+access_list_reset_ipv4 ()
+{
+ struct access_list *access;
+ struct access_list *next;
+ struct access_master *master;
+
+ master = access_master_get (AFI_IP);
+ if (master == NULL)
+ return;
+
+ for (access = master->num.head; access; access = next)
+ {
+ next = access->next;
+ access_list_delete (access);
+ }
+ for (access = master->str.head; access; access = next)
+ {
+ next = access->next;
+ access_list_delete (access);
+ }
+
+ assert (master->num.head == NULL);
+ assert (master->num.tail == NULL);
+
+ assert (master->str.head == NULL);
+ assert (master->str.tail == NULL);
+}
+
+/* Install vty related command. */
+void
+access_list_init_ipv4 ()
+{
+ install_node (&access_node, config_write_access_ipv4);
+
+ install_element (ENABLE_NODE, &show_ip_access_list_cmd);
+ install_element (ENABLE_NODE, &show_ip_access_list_name_cmd);
+
+ /* Zebra access-list */
+ install_element (CONFIG_NODE, &access_list_cmd);
+ install_element (CONFIG_NODE, &access_list_exact_cmd);
+ install_element (CONFIG_NODE, &access_list_any_cmd);
+ install_element (CONFIG_NODE, &no_access_list_cmd);
+ install_element (CONFIG_NODE, &no_access_list_exact_cmd);
+ install_element (CONFIG_NODE, &no_access_list_any_cmd);
+
+ /* Standard access-list */
+ install_element (CONFIG_NODE, &access_list_standard_cmd);
+ install_element (CONFIG_NODE, &access_list_standard_nomask_cmd);
+ install_element (CONFIG_NODE, &access_list_standard_host_cmd);
+ install_element (CONFIG_NODE, &access_list_standard_any_cmd);
+ install_element (CONFIG_NODE, &no_access_list_standard_cmd);
+ install_element (CONFIG_NODE, &no_access_list_standard_nomask_cmd);
+ install_element (CONFIG_NODE, &no_access_list_standard_host_cmd);
+ install_element (CONFIG_NODE, &no_access_list_standard_any_cmd);
+
+ /* Extended access-list */
+ install_element (CONFIG_NODE, &access_list_extended_cmd);
+ install_element (CONFIG_NODE, &access_list_extended_any_mask_cmd);
+ install_element (CONFIG_NODE, &access_list_extended_mask_any_cmd);
+ install_element (CONFIG_NODE, &access_list_extended_any_any_cmd);
+ install_element (CONFIG_NODE, &access_list_extended_host_mask_cmd);
+ install_element (CONFIG_NODE, &access_list_extended_mask_host_cmd);
+ install_element (CONFIG_NODE, &access_list_extended_host_host_cmd);
+ install_element (CONFIG_NODE, &access_list_extended_any_host_cmd);
+ install_element (CONFIG_NODE, &access_list_extended_host_any_cmd);
+ install_element (CONFIG_NODE, &no_access_list_extended_cmd);
+ install_element (CONFIG_NODE, &no_access_list_extended_any_mask_cmd);
+ install_element (CONFIG_NODE, &no_access_list_extended_mask_any_cmd);
+ install_element (CONFIG_NODE, &no_access_list_extended_any_any_cmd);
+ install_element (CONFIG_NODE, &no_access_list_extended_host_mask_cmd);
+ install_element (CONFIG_NODE, &no_access_list_extended_mask_host_cmd);
+ install_element (CONFIG_NODE, &no_access_list_extended_host_host_cmd);
+ install_element (CONFIG_NODE, &no_access_list_extended_any_host_cmd);
+ install_element (CONFIG_NODE, &no_access_list_extended_host_any_cmd);
+
+ install_element (CONFIG_NODE, &access_list_remark_cmd);
+ install_element (CONFIG_NODE, &no_access_list_all_cmd);
+ install_element (CONFIG_NODE, &no_access_list_remark_cmd);
+ install_element (CONFIG_NODE, &no_access_list_remark_arg_cmd);
+}
+
+#ifdef HAVE_IPV6
+struct cmd_node access_ipv6_node =
+{
+ ACCESS_IPV6_NODE,
+ "",
+ 1
+};
+
+int
+config_write_access_ipv6 (struct vty *vty)
+{
+ return config_write_access (vty, AFI_IP6);
+}
+
+void
+access_list_reset_ipv6 ()
+{
+ struct access_list *access;
+ struct access_list *next;
+ struct access_master *master;
+
+ master = access_master_get (AFI_IP6);
+ if (master == NULL)
+ return;
+
+ for (access = master->num.head; access; access = next)
+ {
+ next = access->next;
+ access_list_delete (access);
+ }
+ for (access = master->str.head; access; access = next)
+ {
+ next = access->next;
+ access_list_delete (access);
+ }
+
+ assert (master->num.head == NULL);
+ assert (master->num.tail == NULL);
+
+ assert (master->str.head == NULL);
+ assert (master->str.tail == NULL);
+}
+
+void
+access_list_init_ipv6 ()
+{
+ install_node (&access_ipv6_node, config_write_access_ipv6);
+
+ install_element (ENABLE_NODE, &show_ipv6_access_list_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_access_list_name_cmd);
+
+ install_element (CONFIG_NODE, &ipv6_access_list_cmd);
+ install_element (CONFIG_NODE, &ipv6_access_list_exact_cmd);
+ install_element (CONFIG_NODE, &ipv6_access_list_any_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_access_list_exact_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_access_list_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_access_list_any_cmd);
+
+ install_element (CONFIG_NODE, &no_ipv6_access_list_all_cmd);
+ install_element (CONFIG_NODE, &ipv6_access_list_remark_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_access_list_remark_cmd);
+ install_element (CONFIG_NODE, &no_ipv6_access_list_remark_arg_cmd);
+}
+#endif /* HAVE_IPV6 */
+
+void
+access_list_init ()
+{
+ access_list_init_ipv4 ();
+#ifdef HAVE_IPV6
+ access_list_init_ipv6();
+#endif /* HAVE_IPV6 */
+}
+
+void
+access_list_reset ()
+{
+ access_list_reset_ipv4 ();
+#ifdef HAVE_IPV6
+ access_list_reset_ipv6();
+#endif /* HAVE_IPV6 */
+}