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
28 #include "bgpd/bgpd.h"
29 #include "bgpd/bgp_aspath.h"
30 #include "bgpd/bgp_regex.h"
31 #include "bgpd/bgp_filter.h"
33 /* List of AS filter list. */
40 /* AS path filter master. */
43 /* List of access_list which name is number. */
44 struct as_list_list num
;
46 /* List of access_list which name is string. */
47 struct as_list_list str
;
49 /* Hook function which is executed when new access_list is added. */
50 void (*add_hook
) (void);
52 /* Hook function which is executed when access_list is deleted. */
53 void (*delete_hook
) (void);
56 /* Element of AS path filter. */
59 struct as_filter
*next
;
60 struct as_filter
*prev
;
62 enum as_filter_type type
;
74 /* AS path filter list. */
79 enum as_list_type type
;
84 struct as_filter
*head
;
85 struct as_filter
*tail
;
88 /* ip as-path access-list 10 permit AS1. */
90 static struct as_list_master as_list_master
=
98 /* Allocate new AS filter. */
99 static struct as_filter
*
102 return XCALLOC (MTYPE_AS_FILTER
, sizeof (struct as_filter
));
105 /* Free allocated AS filter. */
107 as_filter_free (struct as_filter
*asfilter
)
110 bgp_regex_free (asfilter
->reg
);
111 if (asfilter
->reg_str
)
112 XFREE (MTYPE_AS_FILTER_STR
, asfilter
->reg_str
);
113 XFREE (MTYPE_AS_FILTER
, asfilter
);
116 /* Make new AS filter. */
117 static struct as_filter
*
118 as_filter_make (regex_t
*reg
, const char *reg_str
, enum as_filter_type type
)
120 struct as_filter
*asfilter
;
122 asfilter
= as_filter_new ();
124 asfilter
->type
= type
;
125 asfilter
->reg_str
= XSTRDUP (MTYPE_AS_FILTER_STR
, reg_str
);
130 static struct as_filter
*
131 as_filter_lookup (struct as_list
*aslist
, const char *reg_str
,
132 enum as_filter_type type
)
134 struct as_filter
*asfilter
;
136 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
137 if (strcmp (reg_str
, asfilter
->reg_str
) == 0)
143 as_list_filter_add (struct as_list
*aslist
, struct as_filter
*asfilter
)
145 asfilter
->next
= NULL
;
146 asfilter
->prev
= aslist
->tail
;
149 aslist
->tail
->next
= asfilter
;
151 aslist
->head
= asfilter
;
152 aslist
->tail
= asfilter
;
155 /* Lookup as_list from list of as_list by name. */
157 as_list_lookup (const char *name
)
159 struct as_list
*aslist
;
164 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= aslist
->next
)
165 if (strcmp (aslist
->name
, name
) == 0)
168 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= aslist
->next
)
169 if (strcmp (aslist
->name
, name
) == 0)
175 static struct as_list
*
178 return XCALLOC (MTYPE_AS_LIST
, sizeof (struct as_list
));
182 as_list_free (struct as_list
*aslist
)
189 XFREE (MTYPE_AS_LIST
, aslist
);
192 /* Insert new AS list to list of as_list. Each as_list is sorted by
194 static struct as_list
*
195 as_list_insert (const char *name
)
199 struct as_list
*aslist
;
200 struct as_list
*point
;
201 struct as_list_list
*list
;
203 /* Allocate new access_list and copy given name. */
204 aslist
= as_list_new ();
205 aslist
->name
= strdup (name
);
206 assert (aslist
->name
);
208 /* If name is made by all digit character. We treat it as
210 for (number
= 0, i
= 0; i
< strlen (name
); i
++)
212 if (isdigit ((int) name
[i
]))
213 number
= (number
* 10) + (name
[i
] - '0');
218 /* In case of name is all digit character */
219 if (i
== strlen (name
))
221 aslist
->type
= ACCESS_TYPE_NUMBER
;
223 /* Set access_list to number list. */
224 list
= &as_list_master
.num
;
226 for (point
= list
->head
; point
; point
= point
->next
)
227 if (atol (point
->name
) >= number
)
232 aslist
->type
= ACCESS_TYPE_STRING
;
234 /* Set access_list to string list. */
235 list
= &as_list_master
.str
;
237 /* Set point to insertion point. */
238 for (point
= list
->head
; point
; point
= point
->next
)
239 if (strcmp (point
->name
, name
) >= 0)
243 /* In case of this is the first element of master. */
244 if (list
->head
== NULL
)
246 list
->head
= list
->tail
= aslist
;
250 /* In case of insertion is made at the tail of access_list. */
253 aslist
->prev
= list
->tail
;
254 list
->tail
->next
= aslist
;
259 /* In case of insertion is made at the head of access_list. */
260 if (point
== list
->head
)
262 aslist
->next
= list
->head
;
263 list
->head
->prev
= aslist
;
268 /* Insertion is made at middle of the access_list. */
269 aslist
->next
= point
;
270 aslist
->prev
= point
->prev
;
273 point
->prev
->next
= aslist
;
274 point
->prev
= aslist
;
279 static struct as_list
*
280 as_list_get (const char *name
)
282 struct as_list
*aslist
;
284 aslist
= as_list_lookup (name
);
287 aslist
= as_list_insert (name
);
289 /* Run hook function. */
290 if (as_list_master
.add_hook
)
291 (*as_list_master
.add_hook
) ();
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
)
354 asfilter
->next
->prev
= asfilter
->prev
;
356 aslist
->tail
= asfilter
->prev
;
359 asfilter
->prev
->next
= asfilter
->next
;
361 aslist
->head
= asfilter
->next
;
363 as_filter_free (asfilter
);
365 /* If access_list becomes empty delete it from access_master. */
366 if (as_list_empty (aslist
))
367 as_list_delete (aslist
);
369 /* Run hook function. */
370 if (as_list_master
.delete_hook
)
371 (*as_list_master
.delete_hook
) ();
375 as_filter_match (struct as_filter
*asfilter
, struct aspath
*aspath
)
377 if (bgp_regexec (asfilter
->reg
, aspath
) != REG_NOMATCH
)
382 /* Apply AS path filter to AS. */
384 as_list_apply (struct as_list
*aslist
, void *object
)
386 struct as_filter
*asfilter
;
387 struct aspath
*aspath
;
389 aspath
= (struct aspath
*) object
;
392 return AS_FILTER_DENY
;
394 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
396 if (as_filter_match (asfilter
, aspath
))
397 return asfilter
->type
;
399 return AS_FILTER_DENY
;
402 /* Add hook function. */
404 as_list_add_hook (void (*func
) (void))
406 as_list_master
.add_hook
= func
;
409 /* Delete hook function. */
411 as_list_delete_hook (void (*func
) (void))
413 as_list_master
.delete_hook
= func
;
417 as_list_dup_check (struct as_list
*aslist
, struct as_filter
*new)
419 struct as_filter
*asfilter
;
421 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
423 if (asfilter
->type
== new->type
424 && strcmp (asfilter
->reg_str
, new->reg_str
) == 0)
430 DEFUN (ip_as_path
, ip_as_path_cmd
,
431 "ip as-path access-list WORD (deny|permit) .LINE",
433 "BGP autonomous system path filter\n"
434 "Specify an access list name\n"
435 "Regular expression access list name\n"
436 "Specify packets to reject\n"
437 "Specify packets to forward\n"
438 "A regular-expression to match the BGP AS paths\n")
440 enum as_filter_type type
;
441 struct as_filter
*asfilter
;
442 struct as_list
*aslist
;
446 /* Check the filter type. */
447 if (strncmp (argv
[1], "p", 1) == 0)
448 type
= AS_FILTER_PERMIT
;
449 else if (strncmp (argv
[1], "d", 1) == 0)
450 type
= AS_FILTER_DENY
;
453 vty_out (vty
, "filter type must be [permit|deny]%s", VTY_NEWLINE
);
457 /* Check AS path regex. */
458 regstr
= argv_concat(argv
, argc
, 2);
460 regex
= bgp_regcomp (regstr
);
463 XFREE (MTYPE_TMP
, regstr
);
464 vty_out (vty
, "can't compile regexp %s%s", argv
[0],
469 asfilter
= as_filter_make (regex
, regstr
, type
);
471 XFREE (MTYPE_TMP
, regstr
);
473 /* Install new filter to the access_list. */
474 aslist
= as_list_get (argv
[0]);
476 /* Duplicate insertion check. */;
477 if (as_list_dup_check (aslist
, asfilter
))
478 as_filter_free (asfilter
);
480 as_list_filter_add (aslist
, asfilter
);
485 DEFUN (no_ip_as_path
,
487 "no ip as-path access-list WORD (deny|permit) .LINE",
490 "BGP autonomous system path filter\n"
491 "Specify an access list name\n"
492 "Regular expression access list name\n"
493 "Specify packets to reject\n"
494 "Specify packets to forward\n"
495 "A regular-expression to match the BGP AS paths\n")
497 enum as_filter_type type
;
498 struct as_filter
*asfilter
;
499 struct as_list
*aslist
;
503 /* Lookup AS list from AS path list. */
504 aslist
= as_list_lookup (argv
[0]);
507 vty_out (vty
, "ip as-path access-list %s doesn't exist%s", argv
[0],
512 /* Check the filter type. */
513 if (strncmp (argv
[1], "p", 1) == 0)
514 type
= AS_FILTER_PERMIT
;
515 else if (strncmp (argv
[1], "d", 1) == 0)
516 type
= AS_FILTER_DENY
;
519 vty_out (vty
, "filter type must be [permit|deny]%s", VTY_NEWLINE
);
523 /* Compile AS path. */
524 regstr
= argv_concat(argv
, argc
, 2);
526 regex
= bgp_regcomp (regstr
);
529 XFREE (MTYPE_TMP
, regstr
);
530 vty_out (vty
, "can't compile regexp %s%s", argv
[0],
535 /* Lookup asfilter. */
536 asfilter
= as_filter_lookup (aslist
, regstr
, type
);
538 XFREE (MTYPE_TMP
, regstr
);
539 bgp_regex_free (regex
);
541 if (asfilter
== NULL
)
543 vty_out (vty
, "%s", VTY_NEWLINE
);
547 as_list_filter_delete (aslist
, asfilter
);
552 DEFUN (no_ip_as_path_all
,
553 no_ip_as_path_all_cmd
,
554 "no ip as-path access-list WORD",
557 "BGP autonomous system path filter\n"
558 "Specify an access list name\n"
559 "Regular expression access list name\n")
561 struct as_list
*aslist
;
563 aslist
= as_list_lookup (argv
[0]);
566 vty_out (vty
, "ip as-path access-list %s doesn't exist%s", argv
[0],
571 as_list_delete (aslist
);
573 /* Run hook function. */
574 if (as_list_master
.delete_hook
)
575 (*as_list_master
.delete_hook
) ();
581 as_list_show (struct vty
*vty
, struct as_list
*aslist
)
583 struct as_filter
*asfilter
;
585 vty_out (vty
, "AS path access list %s%s", aslist
->name
, VTY_NEWLINE
);
587 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
589 vty_out (vty
, " %s %s%s", filter_type_str (asfilter
->type
),
590 asfilter
->reg_str
, VTY_NEWLINE
);
595 as_list_show_all (struct vty
*vty
)
597 struct as_list
*aslist
;
598 struct as_filter
*asfilter
;
600 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= aslist
->next
)
602 vty_out (vty
, "AS path access list %s%s", aslist
->name
, VTY_NEWLINE
);
604 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
606 vty_out (vty
, " %s %s%s", filter_type_str (asfilter
->type
),
607 asfilter
->reg_str
, VTY_NEWLINE
);
611 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= aslist
->next
)
613 vty_out (vty
, "AS path access list %s%s", aslist
->name
, VTY_NEWLINE
);
615 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
617 vty_out (vty
, " %s %s%s", filter_type_str (asfilter
->type
),
618 asfilter
->reg_str
, VTY_NEWLINE
);
623 DEFUN (show_ip_as_path_access_list
,
624 show_ip_as_path_access_list_cmd
,
625 "show ip as-path-access-list WORD",
628 "List AS path access lists\n"
629 "AS path access list name\n")
631 struct as_list
*aslist
;
633 aslist
= as_list_lookup (argv
[0]);
635 as_list_show (vty
, aslist
);
640 DEFUN (show_ip_as_path_access_list_all
,
641 show_ip_as_path_access_list_all_cmd
,
642 "show ip as-path-access-list",
645 "List AS path access lists\n")
647 as_list_show_all (vty
);
652 config_write_as_list (struct vty
*vty
)
654 struct as_list
*aslist
;
655 struct as_filter
*asfilter
;
658 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= aslist
->next
)
659 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
661 vty_out (vty
, "ip as-path access-list %s %s %s%s",
662 aslist
->name
, filter_type_str (asfilter
->type
),
668 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= aslist
->next
)
669 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
671 vty_out (vty
, "ip as-path access-list %s %s %s%s",
672 aslist
->name
, filter_type_str (asfilter
->type
),
680 static struct cmd_node as_list_node
=
687 /* Register functions. */
689 bgp_filter_init (void)
691 install_node (&as_list_node
, config_write_as_list
);
693 install_element (CONFIG_NODE
, &ip_as_path_cmd
);
694 install_element (CONFIG_NODE
, &no_ip_as_path_cmd
);
695 install_element (CONFIG_NODE
, &no_ip_as_path_all_cmd
);
697 install_element (VIEW_NODE
, &show_ip_as_path_access_list_cmd
);
698 install_element (VIEW_NODE
, &show_ip_as_path_access_list_all_cmd
);
699 install_element (ENABLE_NODE
, &show_ip_as_path_access_list_cmd
);
700 install_element (ENABLE_NODE
, &show_ip_as_path_access_list_all_cmd
);
704 bgp_filter_reset (void)
706 struct as_list
*aslist
;
707 struct as_list
*next
;
709 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= next
)
712 as_list_delete (aslist
);
715 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= next
)
718 as_list_delete (aslist
);
721 assert (as_list_master
.num
.head
== NULL
);
722 assert (as_list_master
.num
.tail
== NULL
);
724 assert (as_list_master
.str
.head
== NULL
);
725 assert (as_list_master
.str
.tail
== NULL
);