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
)
171 XFREE(MTYPE_AS_STR
, aslist
->name
);
172 XFREE(MTYPE_AS_LIST
, aslist
);
175 /* Insert new AS list to list of as_list. Each as_list is sorted by
177 static struct as_list
*as_list_insert(const char *name
)
181 struct as_list
*aslist
;
182 struct as_list
*point
;
183 struct as_list_list
*list
;
185 /* Allocate new access_list and copy given name. */
186 aslist
= as_list_new();
187 aslist
->name
= XSTRDUP(MTYPE_AS_STR
, name
);
188 assert(aslist
->name
);
190 /* If name is made by all digit character. We treat it as
192 for (number
= 0, i
= 0; i
< strlen(name
); i
++) {
193 if (isdigit((unsigned char)name
[i
]))
194 number
= (number
* 10) + (name
[i
] - '0');
199 /* In case of name is all digit character */
200 if (i
== strlen(name
)) {
201 aslist
->type
= ACCESS_TYPE_NUMBER
;
203 /* Set access_list to number list. */
204 list
= &as_list_master
.num
;
206 for (point
= list
->head
; point
; point
= point
->next
)
207 if (atol(point
->name
) >= number
)
210 aslist
->type
= ACCESS_TYPE_STRING
;
212 /* Set access_list to string list. */
213 list
= &as_list_master
.str
;
215 /* Set point to insertion point. */
216 for (point
= list
->head
; point
; point
= point
->next
)
217 if (strcmp(point
->name
, name
) >= 0)
221 /* In case of this is the first element of master. */
222 if (list
->head
== NULL
) {
223 list
->head
= list
->tail
= aslist
;
227 /* In case of insertion is made at the tail of access_list. */
229 aslist
->prev
= list
->tail
;
230 list
->tail
->next
= aslist
;
235 /* In case of insertion is made at the head of access_list. */
236 if (point
== list
->head
) {
237 aslist
->next
= list
->head
;
238 list
->head
->prev
= aslist
;
243 /* Insertion is made at middle of the access_list. */
244 aslist
->next
= point
;
245 aslist
->prev
= point
->prev
;
248 point
->prev
->next
= aslist
;
249 point
->prev
= aslist
;
254 static struct as_list
*as_list_get(const char *name
)
256 struct as_list
*aslist
;
258 aslist
= as_list_lookup(name
);
260 aslist
= as_list_insert(name
);
265 static const char *filter_type_str(enum as_filter_type type
)
268 case AS_FILTER_PERMIT
:
277 static void as_list_delete(struct as_list
*aslist
)
279 struct as_list_list
*list
;
280 struct as_filter
*filter
, *next
;
282 for (filter
= aslist
->head
; filter
; filter
= next
) {
284 as_filter_free(filter
);
287 if (aslist
->type
== ACCESS_TYPE_NUMBER
)
288 list
= &as_list_master
.num
;
290 list
= &as_list_master
.str
;
293 aslist
->next
->prev
= aslist
->prev
;
295 list
->tail
= aslist
->prev
;
298 aslist
->prev
->next
= aslist
->next
;
300 list
->head
= aslist
->next
;
302 as_list_free(aslist
);
305 static int as_list_empty(struct as_list
*aslist
)
307 if (aslist
->head
== NULL
&& aslist
->tail
== NULL
)
313 static void as_list_filter_delete(struct as_list
*aslist
,
314 struct as_filter
*asfilter
)
316 char *name
= XSTRDUP(MTYPE_AS_STR
, aslist
->name
);
319 asfilter
->next
->prev
= asfilter
->prev
;
321 aslist
->tail
= asfilter
->prev
;
324 asfilter
->prev
->next
= asfilter
->next
;
326 aslist
->head
= asfilter
->next
;
328 as_filter_free(asfilter
);
330 /* If access_list becomes empty delete it from access_master. */
331 if (as_list_empty(aslist
))
332 as_list_delete(aslist
);
334 /* Run hook function. */
335 if (as_list_master
.delete_hook
)
336 (*as_list_master
.delete_hook
)(name
);
337 XFREE(MTYPE_AS_STR
, name
);
340 static int as_filter_match(struct as_filter
*asfilter
, struct aspath
*aspath
)
342 if (bgp_regexec(asfilter
->reg
, aspath
) != REG_NOMATCH
)
347 /* Apply AS path filter to AS. */
348 enum as_filter_type
as_list_apply(struct as_list
*aslist
, void *object
)
350 struct as_filter
*asfilter
;
351 struct aspath
*aspath
;
353 aspath
= (struct aspath
*)object
;
356 return AS_FILTER_DENY
;
358 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
) {
359 if (as_filter_match(asfilter
, aspath
))
360 return asfilter
->type
;
362 return AS_FILTER_DENY
;
365 /* Add hook function. */
366 void as_list_add_hook(void (*func
)(char *))
368 as_list_master
.add_hook
= func
;
371 /* Delete hook function. */
372 void as_list_delete_hook(void (*func
)(const char *))
374 as_list_master
.delete_hook
= func
;
377 static int as_list_dup_check(struct as_list
*aslist
, struct as_filter
*new)
379 struct as_filter
*asfilter
;
381 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
) {
382 if (asfilter
->type
== new->type
383 && strcmp(asfilter
->reg_str
, new->reg_str
) == 0)
389 int config_bgp_aspath_validate(const char *regstr
)
391 char valid_chars
[] = "1234567890_^|[,{}() ]$*+.?-\\";
393 if (strspn(regstr
, valid_chars
) == strlen(regstr
))
399 DEFUN(as_path
, bgp_as_path_cmd
,
400 "bgp as-path access-list WORD <deny|permit> LINE...",
402 "BGP autonomous system path filter\n"
403 "Specify an access list name\n"
404 "Regular expression access list name\n"
405 "Specify packets to reject\n"
406 "Specify packets to forward\n"
407 "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n")
410 enum as_filter_type type
;
411 struct as_filter
*asfilter
;
412 struct as_list
*aslist
;
416 /* Retrieve access list name */
417 argv_find(argv
, argc
, "WORD", &idx
);
418 char *alname
= argv
[idx
]->arg
;
420 /* Check the filter type. */
421 type
= argv_find(argv
, argc
, "deny", &idx
) ? AS_FILTER_DENY
424 /* Check AS path regex. */
425 argv_find(argv
, argc
, "LINE", &idx
);
426 regstr
= argv_concat(argv
, argc
, idx
);
428 regex
= bgp_regcomp(regstr
);
430 vty_out(vty
, "can't compile regexp %s\n", regstr
);
431 XFREE(MTYPE_TMP
, regstr
);
432 return CMD_WARNING_CONFIG_FAILED
;
435 if (!config_bgp_aspath_validate(regstr
)) {
436 vty_out(vty
, "Invalid character in as-path access-list %s\n",
438 return CMD_WARNING_CONFIG_FAILED
;
441 asfilter
= as_filter_make(regex
, regstr
, type
);
443 XFREE(MTYPE_TMP
, regstr
);
445 /* Install new filter to the access_list. */
446 aslist
= as_list_get(alname
);
448 /* Duplicate insertion check. */;
449 if (as_list_dup_check(aslist
, asfilter
))
450 as_filter_free(asfilter
);
452 as_list_filter_add(aslist
, asfilter
);
457 DEFUN(no_as_path
, no_bgp_as_path_cmd
,
458 "no bgp as-path access-list WORD <deny|permit> LINE...",
461 "BGP autonomous system path filter\n"
462 "Specify an access list name\n"
463 "Regular expression access list name\n"
464 "Specify packets to reject\n"
465 "Specify packets to forward\n"
466 "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n")
469 enum as_filter_type type
;
470 struct as_filter
*asfilter
;
471 struct as_list
*aslist
;
476 argv_find(argv
, argc
, "WORD", &idx
) ? argv
[idx
]->arg
: NULL
;
478 /* Lookup AS list from AS path list. */
479 aslist
= as_list_lookup(aslistname
);
480 if (aslist
== NULL
) {
481 vty_out(vty
, "bgp as-path access-list %s doesn't exist\n",
483 return CMD_WARNING_CONFIG_FAILED
;
486 /* Check the filter type. */
487 if (argv_find(argv
, argc
, "permit", &idx
))
488 type
= AS_FILTER_PERMIT
;
489 else if (argv_find(argv
, argc
, "deny", &idx
))
490 type
= AS_FILTER_DENY
;
492 vty_out(vty
, "filter type must be [permit|deny]\n");
493 return CMD_WARNING_CONFIG_FAILED
;
496 /* Compile AS path. */
497 argv_find(argv
, argc
, "LINE", &idx
);
498 regstr
= argv_concat(argv
, argc
, idx
);
500 if (!config_bgp_aspath_validate(regstr
)) {
501 vty_out(vty
, "Invalid character in as-path access-list %s\n",
503 return CMD_WARNING_CONFIG_FAILED
;
506 regex
= bgp_regcomp(regstr
);
508 vty_out(vty
, "can't compile regexp %s\n", regstr
);
509 XFREE(MTYPE_TMP
, regstr
);
510 return CMD_WARNING_CONFIG_FAILED
;
513 /* Lookup asfilter. */
514 asfilter
= as_filter_lookup(aslist
, regstr
, type
);
516 XFREE(MTYPE_TMP
, regstr
);
517 bgp_regex_free(regex
);
519 if (asfilter
== NULL
) {
521 return CMD_WARNING_CONFIG_FAILED
;
524 as_list_filter_delete(aslist
, asfilter
);
529 DEFUN (no_as_path_all
,
530 no_bgp_as_path_all_cmd
,
531 "no bgp as-path access-list WORD",
534 "BGP autonomous system path filter\n"
535 "Specify an access list name\n"
536 "Regular expression access list name\n")
539 struct as_list
*aslist
;
541 aslist
= as_list_lookup(argv
[idx_word
]->arg
);
542 if (aslist
== NULL
) {
543 vty_out(vty
, "bgp as-path access-list %s doesn't exist\n",
544 argv
[idx_word
]->arg
);
545 return CMD_WARNING_CONFIG_FAILED
;
548 as_list_delete(aslist
);
550 /* Run hook function. */
551 if (as_list_master
.delete_hook
)
552 (*as_list_master
.delete_hook
)(argv
[idx_word
]->arg
);
557 ALIAS (no_as_path_all
,
558 no_ip_as_path_all_cmd
,
559 "no ip as-path access-list WORD",
562 "BGP autonomous system path filter\n"
563 "Specify an access list name\n"
564 "Regular expression access list name\n")
566 static void as_list_show(struct vty
*vty
, struct as_list
*aslist
)
568 struct as_filter
*asfilter
;
570 vty_out(vty
, "AS path access list %s\n", aslist
->name
);
572 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
) {
573 vty_out(vty
, " %s %s\n", filter_type_str(asfilter
->type
),
578 static void as_list_show_all(struct vty
*vty
)
580 struct as_list
*aslist
;
581 struct as_filter
*asfilter
;
583 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= aslist
->next
) {
584 vty_out(vty
, "AS path access list %s\n", aslist
->name
);
586 for (asfilter
= aslist
->head
; asfilter
;
587 asfilter
= asfilter
->next
) {
588 vty_out(vty
, " %s %s\n",
589 filter_type_str(asfilter
->type
),
594 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= aslist
->next
) {
595 vty_out(vty
, "AS path access list %s\n", aslist
->name
);
597 for (asfilter
= aslist
->head
; asfilter
;
598 asfilter
= asfilter
->next
) {
599 vty_out(vty
, " %s %s\n",
600 filter_type_str(asfilter
->type
),
606 DEFUN (show_as_path_access_list
,
607 show_bgp_as_path_access_list_cmd
,
608 "show bgp as-path-access-list WORD",
611 "List AS path access lists\n"
612 "AS path access list name\n")
615 struct as_list
*aslist
;
617 aslist
= as_list_lookup(argv
[idx_word
]->arg
);
619 as_list_show(vty
, aslist
);
624 ALIAS (show_as_path_access_list
,
625 show_ip_as_path_access_list_cmd
,
626 "show ip as-path-access-list WORD",
629 "List AS path access lists\n"
630 "AS path access list name\n")
632 DEFUN (show_as_path_access_list_all
,
633 show_bgp_as_path_access_list_all_cmd
,
634 "show bgp as-path-access-list",
637 "List AS path access lists\n")
639 as_list_show_all(vty
);
643 ALIAS (show_as_path_access_list_all
,
644 show_ip_as_path_access_list_all_cmd
,
645 "show ip as-path-access-list",
648 "List AS path access lists\n")
650 static int config_write_as_list(struct vty
*vty
)
652 struct as_list
*aslist
;
653 struct as_filter
*asfilter
;
656 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= aslist
->next
)
657 for (asfilter
= aslist
->head
; asfilter
;
658 asfilter
= asfilter
->next
) {
659 vty_out(vty
, "bgp as-path access-list %s %s %s\n",
660 aslist
->name
, filter_type_str(asfilter
->type
),
665 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= aslist
->next
)
666 for (asfilter
= aslist
->head
; asfilter
;
667 asfilter
= asfilter
->next
) {
668 vty_out(vty
, "bgp as-path access-list %s %s %s\n",
669 aslist
->name
, filter_type_str(asfilter
->type
),
676 static struct cmd_node as_list_node
= {AS_LIST_NODE
, "", 1};
678 /* Register functions. */
679 void bgp_filter_init(void)
681 install_node(&as_list_node
, config_write_as_list
);
683 install_element(CONFIG_NODE
, &bgp_as_path_cmd
);
684 install_element(CONFIG_NODE
, &no_bgp_as_path_cmd
);
685 install_element(CONFIG_NODE
, &no_bgp_as_path_all_cmd
);
686 install_element(CONFIG_NODE
, &no_ip_as_path_all_cmd
);
688 install_element(VIEW_NODE
, &show_bgp_as_path_access_list_cmd
);
689 install_element(VIEW_NODE
, &show_ip_as_path_access_list_cmd
);
690 install_element(VIEW_NODE
, &show_bgp_as_path_access_list_all_cmd
);
691 install_element(VIEW_NODE
, &show_ip_as_path_access_list_all_cmd
);
694 void bgp_filter_reset(void)
696 struct as_list
*aslist
;
697 struct as_list
*next
;
699 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= next
) {
701 as_list_delete(aslist
);
704 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= next
) {
706 as_list_delete(aslist
);
709 assert(as_list_master
.num
.head
== NULL
);
710 assert(as_list_master
.num
.tail
== NULL
);
712 assert(as_list_master
.str
.head
== NULL
);
713 assert(as_list_master
.str
.tail
== NULL
);