1 /* AS path filter list.
2 Copyright (C) 1999 Kunihiro Ishiguro
4 This file is part of GNU Zebra.
6 GNU Zebra is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 GNU Zebra is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Zebra; see the file COPYING. If not, write to the Free
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
29 #include "bgpd/bgpd.h"
30 #include "bgpd/bgp_aspath.h"
31 #include "bgpd/bgp_regex.h"
32 #include "bgpd/bgp_filter.h"
34 /* List of AS filter list. */
41 /* AS path filter master. */
44 /* List of access_list which name is number. */
45 struct as_list_list num;
47 /* List of access_list which name is string. */
48 struct as_list_list str;
50 /* Hook function which is executed when new access_list is added. */
51 void (*add_hook) (void);
53 /* Hook function which is executed when access_list is deleted. */
54 void (*delete_hook) (void);
57 /* Element of AS path filter. */
60 struct as_filter *next;
61 struct as_filter *prev;
63 enum as_filter_type type;
69 /* AS path filter list. */
74 enum access_type type;
79 struct as_filter *head;
80 struct as_filter *tail;
83 /* ip as-path access-list 10 permit AS1. */
85 static struct as_list_master as_list_master =
93 /* Allocate new AS filter. */
94 static struct as_filter *
97 return XCALLOC (MTYPE_AS_FILTER, sizeof (struct as_filter));
100 /* Free allocated AS filter. */
102 as_filter_free (struct as_filter *asfilter)
105 bgp_regex_free (asfilter->reg);
106 if (asfilter->reg_str)
107 XFREE (MTYPE_AS_FILTER_STR, asfilter->reg_str);
108 XFREE (MTYPE_AS_FILTER, asfilter);
111 /* Make new AS filter. */
112 static struct as_filter *
113 as_filter_make (regex_t *reg, const char *reg_str, enum as_filter_type type)
115 struct as_filter *asfilter;
117 asfilter = as_filter_new ();
119 asfilter->type = type;
120 asfilter->reg_str = XSTRDUP (MTYPE_AS_FILTER_STR, reg_str);
125 static struct as_filter *
126 as_filter_lookup (struct as_list *aslist, const char *reg_str,
127 enum as_filter_type type)
129 struct as_filter *asfilter;
131 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
132 if (strcmp (reg_str, asfilter->reg_str) == 0)
138 as_list_filter_add (struct as_list *aslist, struct as_filter *asfilter)
140 asfilter->next = NULL;
141 asfilter->prev = aslist->tail;
144 aslist->tail->next = asfilter;
146 aslist->head = asfilter;
147 aslist->tail = asfilter;
150 /* Lookup as_list from list of as_list by name. */
152 as_list_lookup (const char *name)
154 struct as_list *aslist;
159 for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
160 if (strcmp (aslist->name, name) == 0)
163 for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
164 if (strcmp (aslist->name, name) == 0)
170 static struct as_list *
173 return XCALLOC (MTYPE_AS_LIST, sizeof (struct as_list));
177 as_list_free (struct as_list *aslist)
184 XFREE (MTYPE_AS_LIST, aslist);
187 /* Insert new AS list to list of as_list. Each as_list is sorted by
189 static struct as_list *
190 as_list_insert (const char *name)
194 struct as_list *aslist;
195 struct as_list *point;
196 struct as_list_list *list;
198 /* Allocate new access_list and copy given name. */
199 aslist = as_list_new ();
200 aslist->name = strdup (name);
201 assert (aslist->name);
203 /* If name is made by all digit character. We treat it as
205 for (number = 0, i = 0; i < strlen (name); i++)
207 if (isdigit ((int) name[i]))
208 number = (number * 10) + (name[i] - '0');
213 /* In case of name is all digit character */
214 if (i == strlen (name))
216 aslist->type = ACCESS_TYPE_NUMBER;
218 /* Set access_list to number list. */
219 list = &as_list_master.num;
221 for (point = list->head; point; point = point->next)
222 if (atol (point->name) >= number)
227 aslist->type = ACCESS_TYPE_STRING;
229 /* Set access_list to string list. */
230 list = &as_list_master.str;
232 /* Set point to insertion point. */
233 for (point = list->head; point; point = point->next)
234 if (strcmp (point->name, name) >= 0)
238 /* In case of this is the first element of master. */
239 if (list->head == NULL)
241 list->head = list->tail = aslist;
245 /* In case of insertion is made at the tail of access_list. */
248 aslist->prev = list->tail;
249 list->tail->next = aslist;
254 /* In case of insertion is made at the head of access_list. */
255 if (point == list->head)
257 aslist->next = list->head;
258 list->head->prev = aslist;
263 /* Insertion is made at middle of the access_list. */
264 aslist->next = point;
265 aslist->prev = point->prev;
268 point->prev->next = aslist;
269 point->prev = aslist;
274 static struct as_list *
275 as_list_get (const char *name)
277 struct as_list *aslist;
279 aslist = as_list_lookup (name);
282 aslist = as_list_insert (name);
284 /* Run hook function. */
285 if (as_list_master.add_hook)
286 (*as_list_master.add_hook) ();
293 filter_type_str (enum as_filter_type type)
297 case AS_FILTER_PERMIT:
307 as_list_delete (struct as_list *aslist)
309 struct as_list_list *list;
310 struct as_filter *filter, *next;
312 for (filter = aslist->head; filter; filter = next)
315 as_filter_free (filter);
318 if (aslist->type == ACCESS_TYPE_NUMBER)
319 list = &as_list_master.num;
321 list = &as_list_master.str;
324 aslist->next->prev = aslist->prev;
326 list->tail = aslist->prev;
329 aslist->prev->next = aslist->next;
331 list->head = aslist->next;
333 as_list_free (aslist);
337 as_list_empty (struct as_list *aslist)
339 if (aslist->head == NULL && aslist->tail == NULL)
346 as_list_filter_delete (struct as_list *aslist, struct as_filter *asfilter)
349 asfilter->next->prev = asfilter->prev;
351 aslist->tail = asfilter->prev;
354 asfilter->prev->next = asfilter->next;
356 aslist->head = asfilter->next;
358 as_filter_free (asfilter);
360 /* If access_list becomes empty delete it from access_master. */
361 if (as_list_empty (aslist))
362 as_list_delete (aslist);
364 /* Run hook function. */
365 if (as_list_master.delete_hook)
366 (*as_list_master.delete_hook) ();
370 as_filter_match (struct as_filter *asfilter, struct aspath *aspath)
372 if (bgp_regexec (asfilter->reg, aspath) != REG_NOMATCH)
377 /* Apply AS path filter to AS. */
379 as_list_apply (struct as_list *aslist, void *object)
381 struct as_filter *asfilter;
382 struct aspath *aspath;
384 aspath = (struct aspath *) object;
387 return AS_FILTER_DENY;
389 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
391 if (as_filter_match (asfilter, aspath))
392 return asfilter->type;
394 return AS_FILTER_DENY;
397 /* Add hook function. */
399 as_list_add_hook (void (*func) (void))
401 as_list_master.add_hook = func;
404 /* Delete hook function. */
406 as_list_delete_hook (void (*func) (void))
408 as_list_master.delete_hook = func;
412 as_list_dup_check (struct as_list *aslist, struct as_filter *new)
414 struct as_filter *asfilter;
416 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
418 if (asfilter->type == new->type
419 && strcmp (asfilter->reg_str, new->reg_str) == 0)
425 DEFUN (ip_as_path, ip_as_path_cmd,
426 "ip as-path access-list WORD (deny|permit) .LINE",
428 "BGP autonomous system path filter\n"
429 "Specify an access list name\n"
430 "Regular expression access list name\n"
431 "Specify packets to reject\n"
432 "Specify packets to forward\n"
433 "A regular-expression to match the BGP AS paths\n")
435 enum as_filter_type type;
436 struct as_filter *asfilter;
437 struct as_list *aslist;
441 /* Check the filter type. */
442 if (strncmp (argv[1], "p", 1) == 0)
443 type = AS_FILTER_PERMIT;
444 else if (strncmp (argv[1], "d", 1) == 0)
445 type = AS_FILTER_DENY;
448 vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE);
452 /* Check AS path regex. */
453 regstr = argv_concat(argv, argc, 2);
455 regex = bgp_regcomp (regstr);
458 XFREE (MTYPE_TMP, regstr);
459 vty_out (vty, "can't compile regexp %s%s", argv[0],
464 asfilter = as_filter_make (regex, regstr, type);
466 XFREE (MTYPE_TMP, regstr);
468 /* Install new filter to the access_list. */
469 aslist = as_list_get (argv[0]);
471 /* Duplicate insertion check. */;
472 if (as_list_dup_check (aslist, asfilter))
473 as_filter_free (asfilter);
475 as_list_filter_add (aslist, asfilter);
480 DEFUN (no_ip_as_path,
482 "no ip as-path access-list WORD (deny|permit) .LINE",
485 "BGP autonomous system path filter\n"
486 "Specify an access list name\n"
487 "Regular expression access list name\n"
488 "Specify packets to reject\n"
489 "Specify packets to forward\n"
490 "A regular-expression to match the BGP AS paths\n")
492 enum as_filter_type type;
493 struct as_filter *asfilter;
494 struct as_list *aslist;
498 /* Lookup AS list from AS path list. */
499 aslist = as_list_lookup (argv[0]);
502 vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0],
507 /* Check the filter type. */
508 if (strncmp (argv[1], "p", 1) == 0)
509 type = AS_FILTER_PERMIT;
510 else if (strncmp (argv[1], "d", 1) == 0)
511 type = AS_FILTER_DENY;
514 vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE);
518 /* Compile AS path. */
519 regstr = argv_concat(argv, argc, 2);
521 regex = bgp_regcomp (regstr);
524 XFREE (MTYPE_TMP, regstr);
525 vty_out (vty, "can't compile regexp %s%s", argv[0],
530 /* Lookup asfilter. */
531 asfilter = as_filter_lookup (aslist, regstr, type);
533 XFREE (MTYPE_TMP, regstr);
534 bgp_regex_free (regex);
536 if (asfilter == NULL)
538 vty_out (vty, "%s", VTY_NEWLINE);
542 as_list_filter_delete (aslist, asfilter);
547 DEFUN (no_ip_as_path_all,
548 no_ip_as_path_all_cmd,
549 "no ip as-path access-list WORD",
552 "BGP autonomous system path filter\n"
553 "Specify an access list name\n"
554 "Regular expression access list name\n")
556 struct as_list *aslist;
558 aslist = as_list_lookup (argv[0]);
561 vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0],
566 as_list_delete (aslist);
568 /* Run hook function. */
569 if (as_list_master.delete_hook)
570 (*as_list_master.delete_hook) ();
576 as_list_show (struct vty *vty, struct as_list *aslist)
578 struct as_filter *asfilter;
580 vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE);
582 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
584 vty_out (vty, " %s %s%s", filter_type_str (asfilter->type),
585 asfilter->reg_str, VTY_NEWLINE);
590 as_list_show_all (struct vty *vty)
592 struct as_list *aslist;
593 struct as_filter *asfilter;
595 for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
597 vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE);
599 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
601 vty_out (vty, " %s %s%s", filter_type_str (asfilter->type),
602 asfilter->reg_str, VTY_NEWLINE);
606 for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
608 vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE);
610 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
612 vty_out (vty, " %s %s%s", filter_type_str (asfilter->type),
613 asfilter->reg_str, VTY_NEWLINE);
618 DEFUN (show_ip_as_path_access_list,
619 show_ip_as_path_access_list_cmd,
620 "show ip as-path-access-list WORD",
623 "List AS path access lists\n"
624 "AS path access list name\n")
626 struct as_list *aslist;
628 aslist = as_list_lookup (argv[0]);
630 as_list_show (vty, aslist);
635 DEFUN (show_ip_as_path_access_list_all,
636 show_ip_as_path_access_list_all_cmd,
637 "show ip as-path-access-list",
640 "List AS path access lists\n")
642 as_list_show_all (vty);
647 config_write_as_list (struct vty *vty)
649 struct as_list *aslist;
650 struct as_filter *asfilter;
653 for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
654 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
656 vty_out (vty, "ip as-path access-list %s %s %s%s",
657 aslist->name, filter_type_str (asfilter->type),
663 for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
664 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
666 vty_out (vty, "ip as-path access-list %s %s %s%s",
667 aslist->name, filter_type_str (asfilter->type),
675 static struct cmd_node as_list_node =
682 /* Register functions. */
684 bgp_filter_init (void)
686 install_node (&as_list_node, config_write_as_list);
688 install_element (CONFIG_NODE, &ip_as_path_cmd);
689 install_element (CONFIG_NODE, &no_ip_as_path_cmd);
690 install_element (CONFIG_NODE, &no_ip_as_path_all_cmd);
692 install_element (VIEW_NODE, &show_ip_as_path_access_list_cmd);
693 install_element (VIEW_NODE, &show_ip_as_path_access_list_all_cmd);
697 bgp_filter_reset (void)
699 struct as_list *aslist;
700 struct as_list *next;
702 for (aslist = as_list_master.num.head; aslist; aslist = next)
705 as_list_delete (aslist);
708 for (aslist = as_list_master.str.head; aslist; aslist = next)
711 as_list_delete (aslist);
714 assert (as_list_master.num.head == NULL);
715 assert (as_list_master.num.tail == NULL);
717 assert (as_list_master.str.head == NULL);
718 assert (as_list_master.str.tail == NULL);