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
) (char *);
53 /* Hook function which is executed when access_list is deleted. */
54 void (*delete_hook
) (const char *);
57 /* Element of AS path filter. */
60 struct as_filter
*next
;
61 struct as_filter
*prev
;
63 enum as_filter_type type
;
75 /* AS path filter list. */
80 enum as_list_type type
;
85 struct as_filter
*head
;
86 struct as_filter
*tail
;
89 /* ip as-path access-list 10 permit AS1. */
91 static struct as_list_master as_list_master
=
99 /* Allocate new AS filter. */
100 static struct as_filter
*
103 return XCALLOC (MTYPE_AS_FILTER
, sizeof (struct as_filter
));
106 /* Free allocated AS filter. */
108 as_filter_free (struct as_filter
*asfilter
)
111 bgp_regex_free (asfilter
->reg
);
112 if (asfilter
->reg_str
)
113 XFREE (MTYPE_AS_FILTER_STR
, asfilter
->reg_str
);
114 XFREE (MTYPE_AS_FILTER
, asfilter
);
117 /* Make new AS filter. */
118 static struct as_filter
*
119 as_filter_make (regex_t
*reg
, const char *reg_str
, enum as_filter_type type
)
121 struct as_filter
*asfilter
;
123 asfilter
= as_filter_new ();
125 asfilter
->type
= type
;
126 asfilter
->reg_str
= XSTRDUP (MTYPE_AS_FILTER_STR
, reg_str
);
131 static struct as_filter
*
132 as_filter_lookup (struct as_list
*aslist
, const char *reg_str
,
133 enum as_filter_type type
)
135 struct as_filter
*asfilter
;
137 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
138 if (strcmp (reg_str
, asfilter
->reg_str
) == 0)
144 as_list_filter_add (struct as_list
*aslist
, struct as_filter
*asfilter
)
146 asfilter
->next
= NULL
;
147 asfilter
->prev
= aslist
->tail
;
150 aslist
->tail
->next
= asfilter
;
152 aslist
->head
= asfilter
;
153 aslist
->tail
= asfilter
;
155 /* Run hook function. */
156 if (as_list_master
.add_hook
)
157 (*as_list_master
.add_hook
) (aslist
->name
);
161 /* Lookup as_list from list of as_list by name. */
163 as_list_lookup (const char *name
)
165 struct as_list
*aslist
;
170 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= aslist
->next
)
171 if (strcmp (aslist
->name
, name
) == 0)
174 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= aslist
->next
)
175 if (strcmp (aslist
->name
, name
) == 0)
181 static struct as_list
*
184 return XCALLOC (MTYPE_AS_LIST
, sizeof (struct as_list
));
188 as_list_free (struct as_list
*aslist
)
192 XFREE(MTYPE_AS_STR
, aslist
->name
);
195 XFREE (MTYPE_AS_LIST
, aslist
);
198 /* Insert new AS list to list of as_list. Each as_list is sorted by
200 static struct as_list
*
201 as_list_insert (const char *name
)
205 struct as_list
*aslist
;
206 struct as_list
*point
;
207 struct as_list_list
*list
;
209 /* Allocate new access_list and copy given name. */
210 aslist
= as_list_new ();
211 aslist
->name
= XSTRDUP(MTYPE_AS_STR
, name
);
212 assert (aslist
->name
);
214 /* If name is made by all digit character. We treat it as
216 for (number
= 0, i
= 0; i
< strlen (name
); i
++)
218 if (isdigit ((int) name
[i
]))
219 number
= (number
* 10) + (name
[i
] - '0');
224 /* In case of name is all digit character */
225 if (i
== strlen (name
))
227 aslist
->type
= ACCESS_TYPE_NUMBER
;
229 /* Set access_list to number list. */
230 list
= &as_list_master
.num
;
232 for (point
= list
->head
; point
; point
= point
->next
)
233 if (atol (point
->name
) >= number
)
238 aslist
->type
= ACCESS_TYPE_STRING
;
240 /* Set access_list to string list. */
241 list
= &as_list_master
.str
;
243 /* Set point to insertion point. */
244 for (point
= list
->head
; point
; point
= point
->next
)
245 if (strcmp (point
->name
, name
) >= 0)
249 /* In case of this is the first element of master. */
250 if (list
->head
== NULL
)
252 list
->head
= list
->tail
= aslist
;
256 /* In case of insertion is made at the tail of access_list. */
259 aslist
->prev
= list
->tail
;
260 list
->tail
->next
= aslist
;
265 /* In case of insertion is made at the head of access_list. */
266 if (point
== list
->head
)
268 aslist
->next
= list
->head
;
269 list
->head
->prev
= aslist
;
274 /* Insertion is made at middle of the access_list. */
275 aslist
->next
= point
;
276 aslist
->prev
= point
->prev
;
279 point
->prev
->next
= aslist
;
280 point
->prev
= aslist
;
285 static struct as_list
*
286 as_list_get (const char *name
)
288 struct as_list
*aslist
;
290 aslist
= as_list_lookup (name
);
292 aslist
= as_list_insert (name
);
298 filter_type_str (enum as_filter_type type
)
302 case AS_FILTER_PERMIT
:
312 as_list_delete (struct as_list
*aslist
)
314 struct as_list_list
*list
;
315 struct as_filter
*filter
, *next
;
317 for (filter
= aslist
->head
; filter
; filter
= next
)
320 as_filter_free (filter
);
323 if (aslist
->type
== ACCESS_TYPE_NUMBER
)
324 list
= &as_list_master
.num
;
326 list
= &as_list_master
.str
;
329 aslist
->next
->prev
= aslist
->prev
;
331 list
->tail
= aslist
->prev
;
334 aslist
->prev
->next
= aslist
->next
;
336 list
->head
= aslist
->next
;
338 as_list_free (aslist
);
342 as_list_empty (struct as_list
*aslist
)
344 if (aslist
->head
== NULL
&& aslist
->tail
== NULL
)
351 as_list_filter_delete (struct as_list
*aslist
, struct as_filter
*asfilter
)
353 char *name
= XSTRDUP(MTYPE_AS_STR
, aslist
->name
);
356 asfilter
->next
->prev
= asfilter
->prev
;
358 aslist
->tail
= asfilter
->prev
;
361 asfilter
->prev
->next
= asfilter
->next
;
363 aslist
->head
= asfilter
->next
;
365 as_filter_free (asfilter
);
367 /* If access_list becomes empty delete it from access_master. */
368 if (as_list_empty (aslist
))
369 as_list_delete (aslist
);
371 /* Run hook function. */
372 if (as_list_master
.delete_hook
)
373 (*as_list_master
.delete_hook
) (name
);
375 XFREE(MTYPE_AS_STR
, name
);
379 as_filter_match (struct as_filter
*asfilter
, struct aspath
*aspath
)
381 if (bgp_regexec (asfilter
->reg
, aspath
) != REG_NOMATCH
)
386 /* Apply AS path filter to AS. */
388 as_list_apply (struct as_list
*aslist
, void *object
)
390 struct as_filter
*asfilter
;
391 struct aspath
*aspath
;
393 aspath
= (struct aspath
*) object
;
396 return AS_FILTER_DENY
;
398 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
400 if (as_filter_match (asfilter
, aspath
))
401 return asfilter
->type
;
403 return AS_FILTER_DENY
;
406 /* Add hook function. */
408 as_list_add_hook (void (*func
) (char *))
410 as_list_master
.add_hook
= func
;
413 /* Delete hook function. */
415 as_list_delete_hook (void (*func
) (const char *))
417 as_list_master
.delete_hook
= func
;
421 as_list_dup_check (struct as_list
*aslist
, struct as_filter
*new)
423 struct as_filter
*asfilter
;
425 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
427 if (asfilter
->type
== new->type
428 && strcmp (asfilter
->reg_str
, new->reg_str
) == 0)
434 DEFUN (ip_as_path
, ip_as_path_cmd
,
435 "ip as-path access-list WORD (deny|permit) .LINE",
437 "BGP autonomous system path filter\n"
438 "Specify an access list name\n"
439 "Regular expression access list name\n"
440 "Specify packets to reject\n"
441 "Specify packets to forward\n"
442 "A regular-expression to match the BGP AS paths\n")
444 enum as_filter_type type
;
445 struct as_filter
*asfilter
;
446 struct as_list
*aslist
;
450 /* Check the filter type. */
451 if (strncmp (argv
[1], "p", 1) == 0)
452 type
= AS_FILTER_PERMIT
;
453 else if (strncmp (argv
[1], "d", 1) == 0)
454 type
= AS_FILTER_DENY
;
457 vty_out (vty
, "filter type must be [permit|deny]%s", VTY_NEWLINE
);
461 /* Check AS path regex. */
462 regstr
= argv_concat(argv
, argc
, 2);
464 regex
= bgp_regcomp (regstr
);
467 XFREE (MTYPE_TMP
, regstr
);
468 vty_out (vty
, "can't compile regexp %s%s", argv
[0],
473 asfilter
= as_filter_make (regex
, regstr
, type
);
475 XFREE (MTYPE_TMP
, regstr
);
477 /* Install new filter to the access_list. */
478 aslist
= as_list_get (argv
[0]);
480 /* Duplicate insertion check. */;
481 if (as_list_dup_check (aslist
, asfilter
))
482 as_filter_free (asfilter
);
484 as_list_filter_add (aslist
, asfilter
);
489 DEFUN (no_ip_as_path
,
491 "no ip as-path access-list WORD (deny|permit) .LINE",
494 "BGP autonomous system path filter\n"
495 "Specify an access list name\n"
496 "Regular expression access list name\n"
497 "Specify packets to reject\n"
498 "Specify packets to forward\n"
499 "A regular-expression to match the BGP AS paths\n")
501 enum as_filter_type type
;
502 struct as_filter
*asfilter
;
503 struct as_list
*aslist
;
507 /* Lookup AS list from AS path list. */
508 aslist
= as_list_lookup (argv
[0]);
511 vty_out (vty
, "ip as-path access-list %s doesn't exist%s", argv
[0],
516 /* Check the filter type. */
517 if (strncmp (argv
[1], "p", 1) == 0)
518 type
= AS_FILTER_PERMIT
;
519 else if (strncmp (argv
[1], "d", 1) == 0)
520 type
= AS_FILTER_DENY
;
523 vty_out (vty
, "filter type must be [permit|deny]%s", VTY_NEWLINE
);
527 /* Compile AS path. */
528 regstr
= argv_concat(argv
, argc
, 2);
530 regex
= bgp_regcomp (regstr
);
533 XFREE (MTYPE_TMP
, regstr
);
534 vty_out (vty
, "can't compile regexp %s%s", argv
[0],
539 /* Lookup asfilter. */
540 asfilter
= as_filter_lookup (aslist
, regstr
, type
);
542 XFREE (MTYPE_TMP
, regstr
);
543 bgp_regex_free (regex
);
545 if (asfilter
== NULL
)
547 vty_out (vty
, "%s", VTY_NEWLINE
);
551 as_list_filter_delete (aslist
, asfilter
);
556 DEFUN (no_ip_as_path_all
,
557 no_ip_as_path_all_cmd
,
558 "no ip as-path access-list WORD",
561 "BGP autonomous system path filter\n"
562 "Specify an access list name\n"
563 "Regular expression access list name\n")
565 struct as_list
*aslist
;
567 aslist
= as_list_lookup (argv
[0]);
570 vty_out (vty
, "ip as-path access-list %s doesn't exist%s", argv
[0],
575 as_list_delete (aslist
);
577 /* Run hook function. */
578 if (as_list_master
.delete_hook
)
579 (*as_list_master
.delete_hook
) (argv
[0]);
585 as_list_show (struct vty
*vty
, struct as_list
*aslist
)
587 struct as_filter
*asfilter
;
589 vty_out (vty
, "AS path access list %s%s", aslist
->name
, VTY_NEWLINE
);
591 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
593 vty_out (vty
, " %s %s%s", filter_type_str (asfilter
->type
),
594 asfilter
->reg_str
, VTY_NEWLINE
);
599 as_list_show_all (struct vty
*vty
)
601 struct as_list
*aslist
;
602 struct as_filter
*asfilter
;
604 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= aslist
->next
)
606 vty_out (vty
, "AS path access list %s%s", aslist
->name
, VTY_NEWLINE
);
608 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
610 vty_out (vty
, " %s %s%s", filter_type_str (asfilter
->type
),
611 asfilter
->reg_str
, VTY_NEWLINE
);
615 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= aslist
->next
)
617 vty_out (vty
, "AS path access list %s%s", aslist
->name
, VTY_NEWLINE
);
619 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
621 vty_out (vty
, " %s %s%s", filter_type_str (asfilter
->type
),
622 asfilter
->reg_str
, VTY_NEWLINE
);
627 DEFUN (show_ip_as_path_access_list
,
628 show_ip_as_path_access_list_cmd
,
629 "show ip as-path-access-list WORD",
632 "List AS path access lists\n"
633 "AS path access list name\n")
635 struct as_list
*aslist
;
637 aslist
= as_list_lookup (argv
[0]);
639 as_list_show (vty
, aslist
);
644 DEFUN (show_ip_as_path_access_list_all
,
645 show_ip_as_path_access_list_all_cmd
,
646 "show ip as-path-access-list",
649 "List AS path access lists\n")
651 as_list_show_all (vty
);
656 config_write_as_list (struct vty
*vty
)
658 struct as_list
*aslist
;
659 struct as_filter
*asfilter
;
662 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= aslist
->next
)
663 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
665 vty_out (vty
, "ip as-path access-list %s %s %s%s",
666 aslist
->name
, filter_type_str (asfilter
->type
),
672 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= aslist
->next
)
673 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
675 vty_out (vty
, "ip as-path access-list %s %s %s%s",
676 aslist
->name
, filter_type_str (asfilter
->type
),
684 static struct cmd_node as_list_node
=
691 /* Register functions. */
693 bgp_filter_init (void)
695 install_node (&as_list_node
, config_write_as_list
);
697 install_element (CONFIG_NODE
, &ip_as_path_cmd
);
698 install_element (CONFIG_NODE
, &no_ip_as_path_cmd
);
699 install_element (CONFIG_NODE
, &no_ip_as_path_all_cmd
);
701 install_element (VIEW_NODE
, &show_ip_as_path_access_list_cmd
);
702 install_element (VIEW_NODE
, &show_ip_as_path_access_list_all_cmd
);
703 install_element (ENABLE_NODE
, &show_ip_as_path_access_list_cmd
);
704 install_element (ENABLE_NODE
, &show_ip_as_path_access_list_all_cmd
);
708 bgp_filter_reset (void)
710 struct as_list
*aslist
;
711 struct as_list
*next
;
713 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= next
)
716 as_list_delete (aslist
);
719 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= next
)
722 as_list_delete (aslist
);
725 assert (as_list_master
.num
.head
== NULL
);
726 assert (as_list_master
.num
.tail
== NULL
);
728 assert (as_list_master
.str
.head
== NULL
);
729 assert (as_list_master
.str
.tail
== NULL
);