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 along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 #include "bgpd/bgpd.h"
31 #include "bgpd/bgp_aspath.h"
32 #include "bgpd/bgp_regex.h"
33 #include "bgpd/bgp_filter.h"
35 /* List of AS filter list. */
41 /* AS path filter master. */
42 struct as_list_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
)(char *);
52 /* Hook function which is executed when access_list is deleted. */
53 void (*delete_hook
)(const char *);
56 /* Element of AS path filter. */
58 struct as_filter
*next
;
59 struct as_filter
*prev
;
61 enum as_filter_type type
;
67 /* AS path filter list. */
71 enum access_type type
;
76 struct as_filter
*head
;
77 struct as_filter
*tail
;
80 /* ip as-path access-list 10 permit AS1. */
82 static struct as_list_master as_list_master
= {{NULL
, NULL
},
87 /* Allocate new AS filter. */
88 static struct as_filter
*as_filter_new(void)
90 return XCALLOC(MTYPE_AS_FILTER
, sizeof(struct as_filter
));
93 /* Free allocated AS filter. */
94 static void as_filter_free(struct as_filter
*asfilter
)
97 bgp_regex_free(asfilter
->reg
);
98 if (asfilter
->reg_str
)
99 XFREE(MTYPE_AS_FILTER_STR
, asfilter
->reg_str
);
100 XFREE(MTYPE_AS_FILTER
, asfilter
);
103 /* Make new AS filter. */
104 static struct as_filter
*as_filter_make(regex_t
*reg
, const char *reg_str
,
105 enum as_filter_type type
)
107 struct as_filter
*asfilter
;
109 asfilter
= as_filter_new();
111 asfilter
->type
= type
;
112 asfilter
->reg_str
= XSTRDUP(MTYPE_AS_FILTER_STR
, reg_str
);
117 static struct as_filter
*as_filter_lookup(struct as_list
*aslist
,
119 enum as_filter_type type
)
121 struct as_filter
*asfilter
;
123 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
124 if (strcmp(reg_str
, asfilter
->reg_str
) == 0)
129 static void as_list_filter_add(struct as_list
*aslist
,
130 struct as_filter
*asfilter
)
132 asfilter
->next
= NULL
;
133 asfilter
->prev
= aslist
->tail
;
136 aslist
->tail
->next
= asfilter
;
138 aslist
->head
= asfilter
;
139 aslist
->tail
= asfilter
;
141 /* Run hook function. */
142 if (as_list_master
.add_hook
)
143 (*as_list_master
.add_hook
)(aslist
->name
);
146 /* Lookup as_list from list of as_list by name. */
147 struct as_list
*as_list_lookup(const char *name
)
149 struct as_list
*aslist
;
154 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= aslist
->next
)
155 if (strcmp(aslist
->name
, name
) == 0)
158 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= aslist
->next
)
159 if (strcmp(aslist
->name
, name
) == 0)
165 static struct as_list
*as_list_new(void)
167 return XCALLOC(MTYPE_AS_LIST
, sizeof(struct as_list
));
170 static void as_list_free(struct as_list
*aslist
)
173 XFREE(MTYPE_AS_STR
, aslist
->name
);
176 XFREE(MTYPE_AS_LIST
, aslist
);
179 /* Insert new AS list to list of as_list. Each as_list is sorted by
181 static struct as_list
*as_list_insert(const char *name
)
185 struct as_list
*aslist
;
186 struct as_list
*point
;
187 struct as_list_list
*list
;
189 /* Allocate new access_list and copy given name. */
190 aslist
= as_list_new();
191 aslist
->name
= XSTRDUP(MTYPE_AS_STR
, name
);
192 assert(aslist
->name
);
194 /* If name is made by all digit character. We treat it as
196 for (number
= 0, i
= 0; i
< strlen(name
); i
++) {
197 if (isdigit((int)name
[i
]))
198 number
= (number
* 10) + (name
[i
] - '0');
203 /* In case of name is all digit character */
204 if (i
== strlen(name
)) {
205 aslist
->type
= ACCESS_TYPE_NUMBER
;
207 /* Set access_list to number list. */
208 list
= &as_list_master
.num
;
210 for (point
= list
->head
; point
; point
= point
->next
)
211 if (atol(point
->name
) >= number
)
214 aslist
->type
= ACCESS_TYPE_STRING
;
216 /* Set access_list to string list. */
217 list
= &as_list_master
.str
;
219 /* Set point to insertion point. */
220 for (point
= list
->head
; point
; point
= point
->next
)
221 if (strcmp(point
->name
, name
) >= 0)
225 /* In case of this is the first element of master. */
226 if (list
->head
== NULL
) {
227 list
->head
= list
->tail
= aslist
;
231 /* In case of insertion is made at the tail of access_list. */
233 aslist
->prev
= list
->tail
;
234 list
->tail
->next
= aslist
;
239 /* In case of insertion is made at the head of access_list. */
240 if (point
== list
->head
) {
241 aslist
->next
= list
->head
;
242 list
->head
->prev
= aslist
;
247 /* Insertion is made at middle of the access_list. */
248 aslist
->next
= point
;
249 aslist
->prev
= point
->prev
;
252 point
->prev
->next
= aslist
;
253 point
->prev
= aslist
;
258 static struct as_list
*as_list_get(const char *name
)
260 struct as_list
*aslist
;
262 aslist
= as_list_lookup(name
);
264 aslist
= as_list_insert(name
);
269 static const char *filter_type_str(enum as_filter_type type
)
272 case AS_FILTER_PERMIT
:
281 static void as_list_delete(struct as_list
*aslist
)
283 struct as_list_list
*list
;
284 struct as_filter
*filter
, *next
;
286 for (filter
= aslist
->head
; filter
; filter
= next
) {
288 as_filter_free(filter
);
291 if (aslist
->type
== ACCESS_TYPE_NUMBER
)
292 list
= &as_list_master
.num
;
294 list
= &as_list_master
.str
;
297 aslist
->next
->prev
= aslist
->prev
;
299 list
->tail
= aslist
->prev
;
302 aslist
->prev
->next
= aslist
->next
;
304 list
->head
= aslist
->next
;
306 as_list_free(aslist
);
309 static int as_list_empty(struct as_list
*aslist
)
311 if (aslist
->head
== NULL
&& aslist
->tail
== NULL
)
317 static void as_list_filter_delete(struct as_list
*aslist
,
318 struct as_filter
*asfilter
)
320 char *name
= XSTRDUP(MTYPE_AS_STR
, aslist
->name
);
323 asfilter
->next
->prev
= asfilter
->prev
;
325 aslist
->tail
= asfilter
->prev
;
328 asfilter
->prev
->next
= asfilter
->next
;
330 aslist
->head
= asfilter
->next
;
332 as_filter_free(asfilter
);
334 /* If access_list becomes empty delete it from access_master. */
335 if (as_list_empty(aslist
))
336 as_list_delete(aslist
);
338 /* Run hook function. */
339 if (as_list_master
.delete_hook
)
340 (*as_list_master
.delete_hook
)(name
);
342 XFREE(MTYPE_AS_STR
, name
);
345 static int as_filter_match(struct as_filter
*asfilter
, struct aspath
*aspath
)
347 if (bgp_regexec(asfilter
->reg
, aspath
) != REG_NOMATCH
)
352 /* Apply AS path filter to AS. */
353 enum as_filter_type
as_list_apply(struct as_list
*aslist
, void *object
)
355 struct as_filter
*asfilter
;
356 struct aspath
*aspath
;
358 aspath
= (struct aspath
*)object
;
361 return AS_FILTER_DENY
;
363 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
) {
364 if (as_filter_match(asfilter
, aspath
))
365 return asfilter
->type
;
367 return AS_FILTER_DENY
;
370 /* Add hook function. */
371 void as_list_add_hook(void (*func
)(char *))
373 as_list_master
.add_hook
= func
;
376 /* Delete hook function. */
377 void as_list_delete_hook(void (*func
)(const char *))
379 as_list_master
.delete_hook
= func
;
382 static int as_list_dup_check(struct as_list
*aslist
, struct as_filter
*new)
384 struct as_filter
*asfilter
;
386 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
) {
387 if (asfilter
->type
== new->type
388 && strcmp(asfilter
->reg_str
, new->reg_str
) == 0)
394 static int config_bgp_aspath_validate(const char *regstr
)
396 char valid_chars
[] = "1234567890_^|[,{}() ]$*+.?-";
398 if (strspn(regstr
, valid_chars
) == strlen(regstr
))
404 DEFUN(ip_as_path
, ip_as_path_cmd
,
405 "ip as-path access-list WORD <deny|permit> LINE...",
407 "BGP autonomous system path filter\n"
408 "Specify an access list name\n"
409 "Regular expression access list name\n"
410 "Specify packets to reject\n"
411 "Specify packets to forward\n"
412 "A regular-expression (1234567890_(^|[,{}() ]|$)) to match the BGP AS paths\n")
415 enum as_filter_type type
;
416 struct as_filter
*asfilter
;
417 struct as_list
*aslist
;
421 /* Retrieve access list name */
422 argv_find(argv
, argc
, "WORD", &idx
);
423 char *alname
= argv
[idx
]->arg
;
425 /* Check the filter type. */
426 type
= argv_find(argv
, argc
, "deny", &idx
) ? AS_FILTER_DENY
429 /* Check AS path regex. */
430 argv_find(argv
, argc
, "LINE", &idx
);
431 regstr
= argv_concat(argv
, argc
, idx
);
433 regex
= bgp_regcomp(regstr
);
435 vty_out(vty
, "can't compile regexp %s\n", regstr
);
436 XFREE(MTYPE_TMP
, regstr
);
437 return CMD_WARNING_CONFIG_FAILED
;
440 if (!config_bgp_aspath_validate(regstr
)) {
441 vty_out(vty
, "Invalid character in as-path access-list %s\n",
443 return CMD_WARNING_CONFIG_FAILED
;
446 asfilter
= as_filter_make(regex
, regstr
, type
);
448 XFREE(MTYPE_TMP
, regstr
);
450 /* Install new filter to the access_list. */
451 aslist
= as_list_get(alname
);
453 /* Duplicate insertion check. */;
454 if (as_list_dup_check(aslist
, asfilter
))
455 as_filter_free(asfilter
);
457 as_list_filter_add(aslist
, asfilter
);
462 DEFUN(no_ip_as_path
, no_ip_as_path_cmd
,
463 "no ip as-path access-list WORD <deny|permit> LINE...",
465 "BGP autonomous system path filter\n"
466 "Specify an access list name\n"
467 "Regular expression access list name\n"
468 "Specify packets to reject\n"
469 "Specify packets to forward\n"
470 "A regular-expression (1234567890_(^|[,{}() ]|$)) to match the BGP AS paths\n")
473 enum as_filter_type type
;
474 struct as_filter
*asfilter
;
475 struct as_list
*aslist
;
480 argv_find(argv
, argc
, "WORD", &idx
) ? argv
[idx
]->arg
: NULL
;
482 /* Lookup AS list from AS path list. */
483 aslist
= as_list_lookup(aslistname
);
484 if (aslist
== NULL
) {
485 vty_out(vty
, "ip as-path access-list %s doesn't exist\n",
487 return CMD_WARNING_CONFIG_FAILED
;
490 /* Check the filter type. */
491 if (argv_find(argv
, argc
, "permit", &idx
))
492 type
= AS_FILTER_PERMIT
;
493 else if (argv_find(argv
, argc
, "deny", &idx
))
494 type
= AS_FILTER_DENY
;
496 vty_out(vty
, "filter type must be [permit|deny]\n");
497 return CMD_WARNING_CONFIG_FAILED
;
500 /* Compile AS path. */
501 argv_find(argv
, argc
, "LINE", &idx
);
502 regstr
= argv_concat(argv
, argc
, idx
);
504 if (!config_bgp_aspath_validate(regstr
)) {
505 vty_out(vty
, "Invalid character in as-path access-list %s\n",
507 return CMD_WARNING_CONFIG_FAILED
;
510 regex
= bgp_regcomp(regstr
);
512 vty_out(vty
, "can't compile regexp %s\n", regstr
);
513 XFREE(MTYPE_TMP
, regstr
);
514 return CMD_WARNING_CONFIG_FAILED
;
517 /* Lookup asfilter. */
518 asfilter
= as_filter_lookup(aslist
, regstr
, type
);
520 XFREE(MTYPE_TMP
, regstr
);
521 bgp_regex_free(regex
);
523 if (asfilter
== NULL
) {
525 return CMD_WARNING_CONFIG_FAILED
;
528 as_list_filter_delete(aslist
, asfilter
);
533 DEFUN (no_ip_as_path_all
,
534 no_ip_as_path_all_cmd
,
535 "no ip as-path access-list WORD",
538 "BGP autonomous system path filter\n"
539 "Specify an access list name\n"
540 "Regular expression access list name\n")
543 struct as_list
*aslist
;
545 aslist
= as_list_lookup(argv
[idx_word
]->arg
);
546 if (aslist
== NULL
) {
547 vty_out(vty
, "ip as-path access-list %s doesn't exist\n",
548 argv
[idx_word
]->arg
);
549 return CMD_WARNING_CONFIG_FAILED
;
552 as_list_delete(aslist
);
554 /* Run hook function. */
555 if (as_list_master
.delete_hook
)
556 (*as_list_master
.delete_hook
)(argv
[idx_word
]->arg
);
561 static void as_list_show(struct vty
*vty
, struct as_list
*aslist
)
563 struct as_filter
*asfilter
;
565 vty_out(vty
, "AS path access list %s\n", aslist
->name
);
567 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
) {
568 vty_out(vty
, " %s %s\n", filter_type_str(asfilter
->type
),
573 static void as_list_show_all(struct vty
*vty
)
575 struct as_list
*aslist
;
576 struct as_filter
*asfilter
;
578 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= aslist
->next
) {
579 vty_out(vty
, "AS path access list %s\n", aslist
->name
);
581 for (asfilter
= aslist
->head
; asfilter
;
582 asfilter
= asfilter
->next
) {
583 vty_out(vty
, " %s %s\n",
584 filter_type_str(asfilter
->type
),
589 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= aslist
->next
) {
590 vty_out(vty
, "AS path access list %s\n", aslist
->name
);
592 for (asfilter
= aslist
->head
; asfilter
;
593 asfilter
= asfilter
->next
) {
594 vty_out(vty
, " %s %s\n",
595 filter_type_str(asfilter
->type
),
601 DEFUN (show_ip_as_path_access_list
,
602 show_ip_as_path_access_list_cmd
,
603 "show ip as-path-access-list WORD",
606 "List AS path access lists\n"
607 "AS path access list name\n")
610 struct as_list
*aslist
;
612 aslist
= as_list_lookup(argv
[idx_word
]->arg
);
614 as_list_show(vty
, aslist
);
619 DEFUN (show_ip_as_path_access_list_all
,
620 show_ip_as_path_access_list_all_cmd
,
621 "show ip as-path-access-list",
624 "List AS path access lists\n")
626 as_list_show_all(vty
);
630 static int config_write_as_list(struct vty
*vty
)
632 struct as_list
*aslist
;
633 struct as_filter
*asfilter
;
636 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= aslist
->next
)
637 for (asfilter
= aslist
->head
; asfilter
;
638 asfilter
= asfilter
->next
) {
639 vty_out(vty
, "ip as-path access-list %s %s %s\n",
640 aslist
->name
, filter_type_str(asfilter
->type
),
645 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= aslist
->next
)
646 for (asfilter
= aslist
->head
; asfilter
;
647 asfilter
= asfilter
->next
) {
648 vty_out(vty
, "ip as-path access-list %s %s %s\n",
649 aslist
->name
, filter_type_str(asfilter
->type
),
656 static struct cmd_node as_list_node
= {AS_LIST_NODE
, "", 1};
658 /* Register functions. */
659 void bgp_filter_init(void)
661 install_node(&as_list_node
, config_write_as_list
);
663 install_element(CONFIG_NODE
, &ip_as_path_cmd
);
664 install_element(CONFIG_NODE
, &no_ip_as_path_cmd
);
665 install_element(CONFIG_NODE
, &no_ip_as_path_all_cmd
);
667 install_element(VIEW_NODE
, &show_ip_as_path_access_list_cmd
);
668 install_element(VIEW_NODE
, &show_ip_as_path_access_list_all_cmd
);
671 void bgp_filter_reset(void)
673 struct as_list
*aslist
;
674 struct as_list
*next
;
676 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= next
) {
678 as_list_delete(aslist
);
681 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= next
) {
683 as_list_delete(aslist
);
686 assert(as_list_master
.num
.head
== NULL
);
687 assert(as_list_master
.num
.tail
== NULL
);
689 assert(as_list_master
.str
.head
== NULL
);
690 assert(as_list_master
.str
.tail
== NULL
);