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 /* 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 XFREE(MTYPE_AS_FILTER_STR
, asfilter
->reg_str
);
99 XFREE(MTYPE_AS_FILTER
, asfilter
);
102 /* Make new AS filter. */
103 static struct as_filter
*as_filter_make(regex_t
*reg
, const char *reg_str
,
104 enum as_filter_type type
)
106 struct as_filter
*asfilter
;
108 asfilter
= as_filter_new();
110 asfilter
->type
= type
;
111 asfilter
->reg_str
= XSTRDUP(MTYPE_AS_FILTER_STR
, reg_str
);
116 static struct as_filter
*as_filter_lookup(struct as_list
*aslist
,
118 enum as_filter_type type
)
120 struct as_filter
*asfilter
;
122 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
123 if (strcmp(reg_str
, asfilter
->reg_str
) == 0)
128 static void as_list_filter_add(struct as_list
*aslist
,
129 struct as_filter
*asfilter
)
131 asfilter
->next
= NULL
;
132 asfilter
->prev
= aslist
->tail
;
135 aslist
->tail
->next
= asfilter
;
137 aslist
->head
= asfilter
;
138 aslist
->tail
= asfilter
;
140 /* Run hook function. */
141 if (as_list_master
.add_hook
)
142 (*as_list_master
.add_hook
)(aslist
->name
);
145 /* Lookup as_list from list of as_list by name. */
146 struct as_list
*as_list_lookup(const char *name
)
148 struct as_list
*aslist
;
153 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= aslist
->next
)
154 if (strcmp(aslist
->name
, name
) == 0)
157 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= aslist
->next
)
158 if (strcmp(aslist
->name
, name
) == 0)
164 static struct as_list
*as_list_new(void)
166 return XCALLOC(MTYPE_AS_LIST
, sizeof(struct as_list
));
169 static void as_list_free(struct as_list
*aslist
)
172 XFREE(MTYPE_AS_STR
, aslist
->name
);
175 XFREE(MTYPE_AS_LIST
, aslist
);
178 /* Insert new AS list to list of as_list. Each as_list is sorted by
180 static struct as_list
*as_list_insert(const char *name
)
184 struct as_list
*aslist
;
185 struct as_list
*point
;
186 struct as_list_list
*list
;
188 /* Allocate new access_list and copy given name. */
189 aslist
= as_list_new();
190 aslist
->name
= XSTRDUP(MTYPE_AS_STR
, name
);
191 assert(aslist
->name
);
193 /* If name is made by all digit character. We treat it as
195 for (number
= 0, i
= 0; i
< strlen(name
); i
++) {
196 if (isdigit((unsigned char)name
[i
]))
197 number
= (number
* 10) + (name
[i
] - '0');
202 /* In case of name is all digit character */
203 if (i
== strlen(name
)) {
204 aslist
->type
= ACCESS_TYPE_NUMBER
;
206 /* Set access_list to number list. */
207 list
= &as_list_master
.num
;
209 for (point
= list
->head
; point
; point
= point
->next
)
210 if (atol(point
->name
) >= number
)
213 aslist
->type
= ACCESS_TYPE_STRING
;
215 /* Set access_list to string list. */
216 list
= &as_list_master
.str
;
218 /* Set point to insertion point. */
219 for (point
= list
->head
; point
; point
= point
->next
)
220 if (strcmp(point
->name
, name
) >= 0)
224 /* In case of this is the first element of master. */
225 if (list
->head
== NULL
) {
226 list
->head
= list
->tail
= aslist
;
230 /* In case of insertion is made at the tail of access_list. */
232 aslist
->prev
= list
->tail
;
233 list
->tail
->next
= aslist
;
238 /* In case of insertion is made at the head of access_list. */
239 if (point
== list
->head
) {
240 aslist
->next
= list
->head
;
241 list
->head
->prev
= aslist
;
246 /* Insertion is made at middle of the access_list. */
247 aslist
->next
= point
;
248 aslist
->prev
= point
->prev
;
251 point
->prev
->next
= aslist
;
252 point
->prev
= aslist
;
257 static struct as_list
*as_list_get(const char *name
)
259 struct as_list
*aslist
;
261 aslist
= as_list_lookup(name
);
263 aslist
= as_list_insert(name
);
268 static const char *filter_type_str(enum as_filter_type type
)
271 case AS_FILTER_PERMIT
:
280 static void as_list_delete(struct as_list
*aslist
)
282 struct as_list_list
*list
;
283 struct as_filter
*filter
, *next
;
285 for (filter
= aslist
->head
; filter
; filter
= next
) {
287 as_filter_free(filter
);
290 if (aslist
->type
== ACCESS_TYPE_NUMBER
)
291 list
= &as_list_master
.num
;
293 list
= &as_list_master
.str
;
296 aslist
->next
->prev
= aslist
->prev
;
298 list
->tail
= aslist
->prev
;
301 aslist
->prev
->next
= aslist
->next
;
303 list
->head
= aslist
->next
;
305 as_list_free(aslist
);
308 static int as_list_empty(struct as_list
*aslist
)
310 if (aslist
->head
== NULL
&& aslist
->tail
== NULL
)
316 static void as_list_filter_delete(struct as_list
*aslist
,
317 struct as_filter
*asfilter
)
319 char *name
= XSTRDUP(MTYPE_AS_STR
, aslist
->name
);
322 asfilter
->next
->prev
= asfilter
->prev
;
324 aslist
->tail
= asfilter
->prev
;
327 asfilter
->prev
->next
= asfilter
->next
;
329 aslist
->head
= asfilter
->next
;
331 as_filter_free(asfilter
);
333 /* If access_list becomes empty delete it from access_master. */
334 if (as_list_empty(aslist
))
335 as_list_delete(aslist
);
337 /* Run hook function. */
338 if (as_list_master
.delete_hook
)
339 (*as_list_master
.delete_hook
)(name
);
340 XFREE(MTYPE_AS_STR
, name
);
343 static int as_filter_match(struct as_filter
*asfilter
, struct aspath
*aspath
)
345 if (bgp_regexec(asfilter
->reg
, aspath
) != REG_NOMATCH
)
350 /* Apply AS path filter to AS. */
351 enum as_filter_type
as_list_apply(struct as_list
*aslist
, void *object
)
353 struct as_filter
*asfilter
;
354 struct aspath
*aspath
;
356 aspath
= (struct aspath
*)object
;
359 return AS_FILTER_DENY
;
361 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
) {
362 if (as_filter_match(asfilter
, aspath
))
363 return asfilter
->type
;
365 return AS_FILTER_DENY
;
368 /* Add hook function. */
369 void as_list_add_hook(void (*func
)(char *))
371 as_list_master
.add_hook
= func
;
374 /* Delete hook function. */
375 void as_list_delete_hook(void (*func
)(const char *))
377 as_list_master
.delete_hook
= func
;
380 static int as_list_dup_check(struct as_list
*aslist
, struct as_filter
*new)
382 struct as_filter
*asfilter
;
384 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
) {
385 if (asfilter
->type
== new->type
386 && strcmp(asfilter
->reg_str
, new->reg_str
) == 0)
392 int config_bgp_aspath_validate(const char *regstr
)
394 char valid_chars
[] = "1234567890_^|[,{}() ]$*+.?-\\";
396 if (strspn(regstr
, valid_chars
) == strlen(regstr
))
402 DEFUN(as_path
, bgp_as_path_cmd
,
403 "bgp as-path access-list WORD <deny|permit> LINE...",
405 "BGP autonomous system path filter\n"
406 "Specify an access list name\n"
407 "Regular expression access list name\n"
408 "Specify packets to reject\n"
409 "Specify packets to forward\n"
410 "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n")
413 enum as_filter_type type
;
414 struct as_filter
*asfilter
;
415 struct as_list
*aslist
;
419 /* Retrieve access list name */
420 argv_find(argv
, argc
, "WORD", &idx
);
421 char *alname
= argv
[idx
]->arg
;
423 /* Check the filter type. */
424 type
= argv_find(argv
, argc
, "deny", &idx
) ? AS_FILTER_DENY
427 /* Check AS path regex. */
428 argv_find(argv
, argc
, "LINE", &idx
);
429 regstr
= argv_concat(argv
, argc
, idx
);
431 regex
= bgp_regcomp(regstr
);
433 vty_out(vty
, "can't compile regexp %s\n", regstr
);
434 XFREE(MTYPE_TMP
, regstr
);
435 return CMD_WARNING_CONFIG_FAILED
;
438 if (!config_bgp_aspath_validate(regstr
)) {
439 vty_out(vty
, "Invalid character in as-path access-list %s\n",
441 return CMD_WARNING_CONFIG_FAILED
;
444 asfilter
= as_filter_make(regex
, regstr
, type
);
446 XFREE(MTYPE_TMP
, regstr
);
448 /* Install new filter to the access_list. */
449 aslist
= as_list_get(alname
);
451 /* Duplicate insertion check. */;
452 if (as_list_dup_check(aslist
, asfilter
))
453 as_filter_free(asfilter
);
455 as_list_filter_add(aslist
, asfilter
);
460 DEFUN(no_as_path
, no_bgp_as_path_cmd
,
461 "no bgp as-path access-list WORD <deny|permit> LINE...",
464 "BGP autonomous system path filter\n"
465 "Specify an access list name\n"
466 "Regular expression access list name\n"
467 "Specify packets to reject\n"
468 "Specify packets to forward\n"
469 "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n")
472 enum as_filter_type type
;
473 struct as_filter
*asfilter
;
474 struct as_list
*aslist
;
479 argv_find(argv
, argc
, "WORD", &idx
) ? argv
[idx
]->arg
: NULL
;
481 /* Lookup AS list from AS path list. */
482 aslist
= as_list_lookup(aslistname
);
483 if (aslist
== NULL
) {
484 vty_out(vty
, "bgp as-path access-list %s doesn't exist\n",
486 return CMD_WARNING_CONFIG_FAILED
;
489 /* Check the filter type. */
490 if (argv_find(argv
, argc
, "permit", &idx
))
491 type
= AS_FILTER_PERMIT
;
492 else if (argv_find(argv
, argc
, "deny", &idx
))
493 type
= AS_FILTER_DENY
;
495 vty_out(vty
, "filter type must be [permit|deny]\n");
496 return CMD_WARNING_CONFIG_FAILED
;
499 /* Compile AS path. */
500 argv_find(argv
, argc
, "LINE", &idx
);
501 regstr
= argv_concat(argv
, argc
, idx
);
503 if (!config_bgp_aspath_validate(regstr
)) {
504 vty_out(vty
, "Invalid character in as-path access-list %s\n",
506 return CMD_WARNING_CONFIG_FAILED
;
509 regex
= bgp_regcomp(regstr
);
511 vty_out(vty
, "can't compile regexp %s\n", regstr
);
512 XFREE(MTYPE_TMP
, regstr
);
513 return CMD_WARNING_CONFIG_FAILED
;
516 /* Lookup asfilter. */
517 asfilter
= as_filter_lookup(aslist
, regstr
, type
);
519 XFREE(MTYPE_TMP
, regstr
);
520 bgp_regex_free(regex
);
522 if (asfilter
== NULL
) {
524 return CMD_WARNING_CONFIG_FAILED
;
527 as_list_filter_delete(aslist
, asfilter
);
532 DEFUN (no_as_path_all
,
533 no_bgp_as_path_all_cmd
,
534 "no bgp as-path access-list WORD",
537 "BGP autonomous system path filter\n"
538 "Specify an access list name\n"
539 "Regular expression access list name\n")
542 struct as_list
*aslist
;
544 aslist
= as_list_lookup(argv
[idx_word
]->arg
);
545 if (aslist
== NULL
) {
546 vty_out(vty
, "bgp as-path access-list %s doesn't exist\n",
547 argv
[idx_word
]->arg
);
548 return CMD_WARNING_CONFIG_FAILED
;
551 as_list_delete(aslist
);
553 /* Run hook function. */
554 if (as_list_master
.delete_hook
)
555 (*as_list_master
.delete_hook
)(argv
[idx_word
]->arg
);
560 ALIAS (no_as_path_all
,
561 no_ip_as_path_all_cmd
,
562 "no ip as-path access-list WORD",
565 "BGP autonomous system path filter\n"
566 "Specify an access list name\n"
567 "Regular expression access list name\n")
569 static void as_list_show(struct vty
*vty
, struct as_list
*aslist
)
571 struct as_filter
*asfilter
;
573 vty_out(vty
, "AS path access list %s\n", aslist
->name
);
575 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
) {
576 vty_out(vty
, " %s %s\n", filter_type_str(asfilter
->type
),
581 static void as_list_show_all(struct vty
*vty
)
583 struct as_list
*aslist
;
584 struct as_filter
*asfilter
;
586 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= aslist
->next
) {
587 vty_out(vty
, "AS path access list %s\n", aslist
->name
);
589 for (asfilter
= aslist
->head
; asfilter
;
590 asfilter
= asfilter
->next
) {
591 vty_out(vty
, " %s %s\n",
592 filter_type_str(asfilter
->type
),
597 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= aslist
->next
) {
598 vty_out(vty
, "AS path access list %s\n", aslist
->name
);
600 for (asfilter
= aslist
->head
; asfilter
;
601 asfilter
= asfilter
->next
) {
602 vty_out(vty
, " %s %s\n",
603 filter_type_str(asfilter
->type
),
609 DEFUN (show_as_path_access_list
,
610 show_bgp_as_path_access_list_cmd
,
611 "show bgp as-path-access-list WORD",
614 "List AS path access lists\n"
615 "AS path access list name\n")
618 struct as_list
*aslist
;
620 aslist
= as_list_lookup(argv
[idx_word
]->arg
);
622 as_list_show(vty
, aslist
);
627 ALIAS (show_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 DEFUN (show_as_path_access_list_all
,
636 show_bgp_as_path_access_list_all_cmd
,
637 "show bgp as-path-access-list",
640 "List AS path access lists\n")
642 as_list_show_all(vty
);
646 ALIAS (show_as_path_access_list_all
,
647 show_ip_as_path_access_list_all_cmd
,
648 "show ip as-path-access-list",
651 "List AS path access lists\n")
653 static int config_write_as_list(struct vty
*vty
)
655 struct as_list
*aslist
;
656 struct as_filter
*asfilter
;
659 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= aslist
->next
)
660 for (asfilter
= aslist
->head
; asfilter
;
661 asfilter
= asfilter
->next
) {
662 vty_out(vty
, "bgp as-path access-list %s %s %s\n",
663 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
;
670 asfilter
= asfilter
->next
) {
671 vty_out(vty
, "bgp as-path access-list %s %s %s\n",
672 aslist
->name
, filter_type_str(asfilter
->type
),
679 static struct cmd_node as_list_node
= {AS_LIST_NODE
, "", 1};
681 /* Register functions. */
682 void bgp_filter_init(void)
684 install_node(&as_list_node
, config_write_as_list
);
686 install_element(CONFIG_NODE
, &bgp_as_path_cmd
);
687 install_element(CONFIG_NODE
, &no_bgp_as_path_cmd
);
688 install_element(CONFIG_NODE
, &no_bgp_as_path_all_cmd
);
689 install_element(CONFIG_NODE
, &no_ip_as_path_all_cmd
);
691 install_element(VIEW_NODE
, &show_bgp_as_path_access_list_cmd
);
692 install_element(VIEW_NODE
, &show_ip_as_path_access_list_cmd
);
693 install_element(VIEW_NODE
, &show_bgp_as_path_access_list_all_cmd
);
694 install_element(VIEW_NODE
, &show_ip_as_path_access_list_all_cmd
);
697 void 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
) {
704 as_list_delete(aslist
);
707 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= next
) {
709 as_list_delete(aslist
);
712 assert(as_list_master
.num
.head
== NULL
);
713 assert(as_list_master
.num
.tail
== NULL
);
715 assert(as_list_master
.str
.head
== NULL
);
716 assert(as_list_master
.str
.tail
== NULL
);