123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719 |
- /* AS path filter list.
- Copyright (C) 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 "command.h"
- #include "log.h"
- #include "memory.h"
- #include "buffer.h"
- #include "filter.h"
- #include "bgpd/bgpd.h"
- #include "bgpd/bgp_aspath.h"
- #include "bgpd/bgp_regex.h"
- #include "bgpd/bgp_filter.h"
- /* List of AS filter list. */
- struct as_list_list
- {
- struct as_list *head;
- struct as_list *tail;
- };
- /* AS path filter master. */
- struct as_list_master
- {
- /* List of access_list which name is number. */
- struct as_list_list num;
- /* List of access_list which name is string. */
- struct as_list_list str;
- /* Hook function which is executed when new access_list is added. */
- void (*add_hook) (void);
- /* Hook function which is executed when access_list is deleted. */
- void (*delete_hook) (void);
- };
- /* Element of AS path filter. */
- struct as_filter
- {
- struct as_filter *next;
- struct as_filter *prev;
- enum as_filter_type type;
- regex_t *reg;
- char *reg_str;
- };
- /* AS path filter list. */
- struct as_list
- {
- char *name;
- enum access_type type;
- struct as_list *next;
- struct as_list *prev;
- struct as_filter *head;
- struct as_filter *tail;
- };
- /* ip as-path access-list 10 permit AS1. */
- static struct as_list_master as_list_master =
- {
- {NULL, NULL},
- {NULL, NULL},
- NULL,
- NULL
- };
- /* Allocate new AS filter. */
- static struct as_filter *
- as_filter_new (void)
- {
- return XCALLOC (MTYPE_AS_FILTER, sizeof (struct as_filter));
- }
- /* Free allocated AS filter. */
- static void
- as_filter_free (struct as_filter *asfilter)
- {
- if (asfilter->reg)
- bgp_regex_free (asfilter->reg);
- if (asfilter->reg_str)
- XFREE (MTYPE_AS_FILTER_STR, asfilter->reg_str);
- XFREE (MTYPE_AS_FILTER, asfilter);
- }
- /* Make new AS filter. */
- static struct as_filter *
- as_filter_make (regex_t *reg, const char *reg_str, enum as_filter_type type)
- {
- struct as_filter *asfilter;
- asfilter = as_filter_new ();
- asfilter->reg = reg;
- asfilter->type = type;
- asfilter->reg_str = XSTRDUP (MTYPE_AS_FILTER_STR, reg_str);
- return asfilter;
- }
- static struct as_filter *
- as_filter_lookup (struct as_list *aslist, const char *reg_str,
- enum as_filter_type type)
- {
- struct as_filter *asfilter;
- for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
- if (strcmp (reg_str, asfilter->reg_str) == 0)
- return asfilter;
- return NULL;
- }
- static void
- as_list_filter_add (struct as_list *aslist, struct as_filter *asfilter)
- {
- asfilter->next = NULL;
- asfilter->prev = aslist->tail;
- if (aslist->tail)
- aslist->tail->next = asfilter;
- else
- aslist->head = asfilter;
- aslist->tail = asfilter;
- }
- /* Lookup as_list from list of as_list by name. */
- struct as_list *
- as_list_lookup (const char *name)
- {
- struct as_list *aslist;
- if (name == NULL)
- return NULL;
- for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
- if (strcmp (aslist->name, name) == 0)
- return aslist;
- for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
- if (strcmp (aslist->name, name) == 0)
- return aslist;
- return NULL;
- }
- static struct as_list *
- as_list_new (void)
- {
- return XCALLOC (MTYPE_AS_LIST, sizeof (struct as_list));
- }
- static void
- as_list_free (struct as_list *aslist)
- {
- if (aslist->name)
- {
- free (aslist->name);
- aslist->name = NULL;
- }
- XFREE (MTYPE_AS_LIST, aslist);
- }
- /* Insert new AS list to list of as_list. Each as_list is sorted by
- the name. */
- static struct as_list *
- as_list_insert (const char *name)
- {
- size_t i;
- long number;
- struct as_list *aslist;
- struct as_list *point;
- struct as_list_list *list;
- /* Allocate new access_list and copy given name. */
- aslist = as_list_new ();
- aslist->name = strdup (name);
- assert (aslist->name);
- /* 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))
- {
- aslist->type = ACCESS_TYPE_NUMBER;
- /* Set access_list to number list. */
- list = &as_list_master.num;
- for (point = list->head; point; point = point->next)
- if (atol (point->name) >= number)
- break;
- }
- else
- {
- aslist->type = ACCESS_TYPE_STRING;
- /* Set access_list to string list. */
- list = &as_list_master.str;
-
- /* Set point to insertion point. */
- for (point = list->head; point; point = point->next)
- if (strcmp (point->name, name) >= 0)
- break;
- }
- /* In case of this is the first element of master. */
- if (list->head == NULL)
- {
- list->head = list->tail = aslist;
- return aslist;
- }
- /* In case of insertion is made at the tail of access_list. */
- if (point == NULL)
- {
- aslist->prev = list->tail;
- list->tail->next = aslist;
- list->tail = aslist;
- return aslist;
- }
- /* In case of insertion is made at the head of access_list. */
- if (point == list->head)
- {
- aslist->next = list->head;
- list->head->prev = aslist;
- list->head = aslist;
- return aslist;
- }
- /* Insertion is made at middle of the access_list. */
- aslist->next = point;
- aslist->prev = point->prev;
- if (point->prev)
- point->prev->next = aslist;
- point->prev = aslist;
- return aslist;
- }
- static struct as_list *
- as_list_get (const char *name)
- {
- struct as_list *aslist;
- aslist = as_list_lookup (name);
- if (aslist == NULL)
- {
- aslist = as_list_insert (name);
- /* Run hook function. */
- if (as_list_master.add_hook)
- (*as_list_master.add_hook) ();
- }
- return aslist;
- }
- static const char *
- filter_type_str (enum as_filter_type type)
- {
- switch (type)
- {
- case AS_FILTER_PERMIT:
- return "permit";
- case AS_FILTER_DENY:
- return "deny";
- default:
- return "";
- }
- }
- static void
- as_list_delete (struct as_list *aslist)
- {
- struct as_list_list *list;
- struct as_filter *filter, *next;
- for (filter = aslist->head; filter; filter = next)
- {
- next = filter->next;
- as_filter_free (filter);
- }
- if (aslist->type == ACCESS_TYPE_NUMBER)
- list = &as_list_master.num;
- else
- list = &as_list_master.str;
- if (aslist->next)
- aslist->next->prev = aslist->prev;
- else
- list->tail = aslist->prev;
- if (aslist->prev)
- aslist->prev->next = aslist->next;
- else
- list->head = aslist->next;
- as_list_free (aslist);
- }
- static int
- as_list_empty (struct as_list *aslist)
- {
- if (aslist->head == NULL && aslist->tail == NULL)
- return 1;
- else
- return 0;
- }
- static void
- as_list_filter_delete (struct as_list *aslist, struct as_filter *asfilter)
- {
- if (asfilter->next)
- asfilter->next->prev = asfilter->prev;
- else
- aslist->tail = asfilter->prev;
- if (asfilter->prev)
- asfilter->prev->next = asfilter->next;
- else
- aslist->head = asfilter->next;
- as_filter_free (asfilter);
- /* If access_list becomes empty delete it from access_master. */
- if (as_list_empty (aslist))
- as_list_delete (aslist);
- /* Run hook function. */
- if (as_list_master.delete_hook)
- (*as_list_master.delete_hook) ();
- }
- static int
- as_filter_match (struct as_filter *asfilter, struct aspath *aspath)
- {
- if (bgp_regexec (asfilter->reg, aspath) != REG_NOMATCH)
- return 1;
- return 0;
- }
- /* Apply AS path filter to AS. */
- enum as_filter_type
- as_list_apply (struct as_list *aslist, void *object)
- {
- struct as_filter *asfilter;
- struct aspath *aspath;
- aspath = (struct aspath *) object;
- if (aslist == NULL)
- return AS_FILTER_DENY;
- for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
- {
- if (as_filter_match (asfilter, aspath))
- return asfilter->type;
- }
- return AS_FILTER_DENY;
- }
- /* Add hook function. */
- void
- as_list_add_hook (void (*func) (void))
- {
- as_list_master.add_hook = func;
- }
- /* Delete hook function. */
- void
- as_list_delete_hook (void (*func) (void))
- {
- as_list_master.delete_hook = func;
- }
- static int
- as_list_dup_check (struct as_list *aslist, struct as_filter *new)
- {
- struct as_filter *asfilter;
- for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
- {
- if (asfilter->type == new->type
- && strcmp (asfilter->reg_str, new->reg_str) == 0)
- return 1;
- }
- return 0;
- }
- DEFUN (ip_as_path, ip_as_path_cmd,
- "ip as-path access-list WORD (deny|permit) .LINE",
- IP_STR
- "BGP autonomous system path filter\n"
- "Specify an access list name\n"
- "Regular expression access list name\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "A regular-expression to match the BGP AS paths\n")
- {
- enum as_filter_type type;
- struct as_filter *asfilter;
- struct as_list *aslist;
- regex_t *regex;
- char *regstr;
- /* Check the filter type. */
- if (strncmp (argv[1], "p", 1) == 0)
- type = AS_FILTER_PERMIT;
- else if (strncmp (argv[1], "d", 1) == 0)
- type = AS_FILTER_DENY;
- else
- {
- vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- /* Check AS path regex. */
- regstr = argv_concat(argv, argc, 2);
- regex = bgp_regcomp (regstr);
- if (!regex)
- {
- XFREE (MTYPE_TMP, regstr);
- vty_out (vty, "can't compile regexp %s%s", argv[0],
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- asfilter = as_filter_make (regex, regstr, type);
-
- XFREE (MTYPE_TMP, regstr);
- /* Install new filter to the access_list. */
- aslist = as_list_get (argv[0]);
- /* Duplicate insertion check. */;
- if (as_list_dup_check (aslist, asfilter))
- as_filter_free (asfilter);
- else
- as_list_filter_add (aslist, asfilter);
- return CMD_SUCCESS;
- }
- DEFUN (no_ip_as_path,
- no_ip_as_path_cmd,
- "no ip as-path access-list WORD (deny|permit) .LINE",
- NO_STR
- IP_STR
- "BGP autonomous system path filter\n"
- "Specify an access list name\n"
- "Regular expression access list name\n"
- "Specify packets to reject\n"
- "Specify packets to forward\n"
- "A regular-expression to match the BGP AS paths\n")
- {
- enum as_filter_type type;
- struct as_filter *asfilter;
- struct as_list *aslist;
- char *regstr;
- regex_t *regex;
- /* Lookup AS list from AS path list. */
- aslist = as_list_lookup (argv[0]);
- if (aslist == NULL)
- {
- vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0],
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- /* Check the filter type. */
- if (strncmp (argv[1], "p", 1) == 0)
- type = AS_FILTER_PERMIT;
- else if (strncmp (argv[1], "d", 1) == 0)
- type = AS_FILTER_DENY;
- else
- {
- vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- /* Compile AS path. */
- regstr = argv_concat(argv, argc, 2);
- regex = bgp_regcomp (regstr);
- if (!regex)
- {
- XFREE (MTYPE_TMP, regstr);
- vty_out (vty, "can't compile regexp %s%s", argv[0],
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- /* Lookup asfilter. */
- asfilter = as_filter_lookup (aslist, regstr, type);
- XFREE (MTYPE_TMP, regstr);
- bgp_regex_free (regex);
- if (asfilter == NULL)
- {
- vty_out (vty, "%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- as_list_filter_delete (aslist, asfilter);
- return CMD_SUCCESS;
- }
- DEFUN (no_ip_as_path_all,
- no_ip_as_path_all_cmd,
- "no ip as-path access-list WORD",
- NO_STR
- IP_STR
- "BGP autonomous system path filter\n"
- "Specify an access list name\n"
- "Regular expression access list name\n")
- {
- struct as_list *aslist;
- aslist = as_list_lookup (argv[0]);
- if (aslist == NULL)
- {
- vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0],
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- as_list_delete (aslist);
- /* Run hook function. */
- if (as_list_master.delete_hook)
- (*as_list_master.delete_hook) ();
- return CMD_SUCCESS;
- }
- static void
- as_list_show (struct vty *vty, struct as_list *aslist)
- {
- struct as_filter *asfilter;
- vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE);
- for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
- {
- vty_out (vty, " %s %s%s", filter_type_str (asfilter->type),
- asfilter->reg_str, VTY_NEWLINE);
- }
- }
- static void
- as_list_show_all (struct vty *vty)
- {
- struct as_list *aslist;
- struct as_filter *asfilter;
- for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
- {
- vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE);
- for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
- {
- vty_out (vty, " %s %s%s", filter_type_str (asfilter->type),
- asfilter->reg_str, VTY_NEWLINE);
- }
- }
- for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
- {
- vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE);
- for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
- {
- vty_out (vty, " %s %s%s", filter_type_str (asfilter->type),
- asfilter->reg_str, VTY_NEWLINE);
- }
- }
- }
- DEFUN (show_ip_as_path_access_list,
- show_ip_as_path_access_list_cmd,
- "show ip as-path-access-list WORD",
- SHOW_STR
- IP_STR
- "List AS path access lists\n"
- "AS path access list name\n")
- {
- struct as_list *aslist;
- aslist = as_list_lookup (argv[0]);
- if (aslist)
- as_list_show (vty, aslist);
- return CMD_SUCCESS;
- }
- DEFUN (show_ip_as_path_access_list_all,
- show_ip_as_path_access_list_all_cmd,
- "show ip as-path-access-list",
- SHOW_STR
- IP_STR
- "List AS path access lists\n")
- {
- as_list_show_all (vty);
- return CMD_SUCCESS;
- }
- static int
- config_write_as_list (struct vty *vty)
- {
- struct as_list *aslist;
- struct as_filter *asfilter;
- int write = 0;
- for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
- for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
- {
- vty_out (vty, "ip as-path access-list %s %s %s%s",
- aslist->name, filter_type_str (asfilter->type),
- asfilter->reg_str,
- VTY_NEWLINE);
- write++;
- }
- for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
- for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
- {
- vty_out (vty, "ip as-path access-list %s %s %s%s",
- aslist->name, filter_type_str (asfilter->type),
- asfilter->reg_str,
- VTY_NEWLINE);
- write++;
- }
- return write;
- }
- static struct cmd_node as_list_node =
- {
- AS_LIST_NODE,
- "",
- 1
- };
- /* Register functions. */
- void
- bgp_filter_init (void)
- {
- install_node (&as_list_node, config_write_as_list);
- install_element (CONFIG_NODE, &ip_as_path_cmd);
- install_element (CONFIG_NODE, &no_ip_as_path_cmd);
- install_element (CONFIG_NODE, &no_ip_as_path_all_cmd);
- install_element (VIEW_NODE, &show_ip_as_path_access_list_cmd);
- install_element (VIEW_NODE, &show_ip_as_path_access_list_all_cmd);
- }
- void
- bgp_filter_reset (void)
- {
- struct as_list *aslist;
- struct as_list *next;
- for (aslist = as_list_master.num.head; aslist; aslist = next)
- {
- next = aslist->next;
- as_list_delete (aslist);
- }
- for (aslist = as_list_master.str.head; aslist; aslist = next)
- {
- next = aslist->next;
- as_list_delete (aslist);
- }
- assert (as_list_master.num.head == NULL);
- assert (as_list_master.num.tail == NULL);
- assert (as_list_master.str.head == NULL);
- assert (as_list_master.str.tail == NULL);
- }
|