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 bool as_list_empty(struct as_list
*aslist
)
307 return aslist
->head
== NULL
&& aslist
->tail
== NULL
;
310 static void as_list_filter_delete(struct as_list
*aslist
,
311 struct as_filter
*asfilter
)
313 char *name
= XSTRDUP(MTYPE_AS_STR
, aslist
->name
);
316 asfilter
->next
->prev
= asfilter
->prev
;
318 aslist
->tail
= asfilter
->prev
;
321 asfilter
->prev
->next
= asfilter
->next
;
323 aslist
->head
= asfilter
->next
;
325 as_filter_free(asfilter
);
327 /* If access_list becomes empty delete it from access_master. */
328 if (as_list_empty(aslist
))
329 as_list_delete(aslist
);
331 /* Run hook function. */
332 if (as_list_master
.delete_hook
)
333 (*as_list_master
.delete_hook
)(name
);
334 XFREE(MTYPE_AS_STR
, name
);
337 static bool as_filter_match(struct as_filter
*asfilter
, struct aspath
*aspath
)
339 return bgp_regexec(asfilter
->reg
, aspath
) != REG_NOMATCH
;
342 /* Apply AS path filter to AS. */
343 enum as_filter_type
as_list_apply(struct as_list
*aslist
, void *object
)
345 struct as_filter
*asfilter
;
346 struct aspath
*aspath
;
348 aspath
= (struct aspath
*)object
;
351 return AS_FILTER_DENY
;
353 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
) {
354 if (as_filter_match(asfilter
, aspath
))
355 return asfilter
->type
;
357 return AS_FILTER_DENY
;
360 /* Add hook function. */
361 void as_list_add_hook(void (*func
)(char *))
363 as_list_master
.add_hook
= func
;
366 /* Delete hook function. */
367 void as_list_delete_hook(void (*func
)(const char *))
369 as_list_master
.delete_hook
= func
;
372 static bool as_list_dup_check(struct as_list
*aslist
, struct as_filter
*new)
374 struct as_filter
*asfilter
;
376 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
) {
377 if (asfilter
->type
== new->type
378 && strcmp(asfilter
->reg_str
, new->reg_str
) == 0)
384 bool config_bgp_aspath_validate(const char *regstr
)
386 char valid_chars
[] = "1234567890_^|[,{}() ]$*+.?-\\";
388 if (strspn(regstr
, valid_chars
) == strlen(regstr
))
393 DEFUN(as_path
, bgp_as_path_cmd
,
394 "bgp as-path access-list WORD <deny|permit> LINE...",
396 "BGP autonomous system path filter\n"
397 "Specify an access list name\n"
398 "Regular expression access list name\n"
399 "Specify packets to reject\n"
400 "Specify packets to forward\n"
401 "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n")
404 enum as_filter_type type
;
405 struct as_filter
*asfilter
;
406 struct as_list
*aslist
;
410 /* Retrieve access list name */
411 argv_find(argv
, argc
, "WORD", &idx
);
412 char *alname
= argv
[idx
]->arg
;
414 /* Check the filter type. */
415 type
= argv_find(argv
, argc
, "deny", &idx
) ? AS_FILTER_DENY
418 /* Check AS path regex. */
419 argv_find(argv
, argc
, "LINE", &idx
);
420 regstr
= argv_concat(argv
, argc
, idx
);
422 regex
= bgp_regcomp(regstr
);
424 vty_out(vty
, "can't compile regexp %s\n", regstr
);
425 XFREE(MTYPE_TMP
, regstr
);
426 return CMD_WARNING_CONFIG_FAILED
;
429 if (!config_bgp_aspath_validate(regstr
)) {
430 vty_out(vty
, "Invalid character in as-path access-list %s\n",
432 return CMD_WARNING_CONFIG_FAILED
;
435 asfilter
= as_filter_make(regex
, regstr
, type
);
437 XFREE(MTYPE_TMP
, regstr
);
439 /* Install new filter to the access_list. */
440 aslist
= as_list_get(alname
);
442 /* Duplicate insertion check. */;
443 if (as_list_dup_check(aslist
, asfilter
))
444 as_filter_free(asfilter
);
446 as_list_filter_add(aslist
, asfilter
);
451 DEFUN(no_as_path
, no_bgp_as_path_cmd
,
452 "no bgp as-path access-list WORD <deny|permit> LINE...",
455 "BGP autonomous system path filter\n"
456 "Specify an access list name\n"
457 "Regular expression access list name\n"
458 "Specify packets to reject\n"
459 "Specify packets to forward\n"
460 "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n")
463 enum as_filter_type type
;
464 struct as_filter
*asfilter
;
465 struct as_list
*aslist
;
470 argv_find(argv
, argc
, "WORD", &idx
) ? argv
[idx
]->arg
: NULL
;
472 /* Lookup AS list from AS path list. */
473 aslist
= as_list_lookup(aslistname
);
474 if (aslist
== NULL
) {
475 vty_out(vty
, "bgp as-path access-list %s doesn't exist\n",
477 return CMD_WARNING_CONFIG_FAILED
;
480 /* Check the filter type. */
481 if (argv_find(argv
, argc
, "permit", &idx
))
482 type
= AS_FILTER_PERMIT
;
483 else if (argv_find(argv
, argc
, "deny", &idx
))
484 type
= AS_FILTER_DENY
;
486 vty_out(vty
, "filter type must be [permit|deny]\n");
487 return CMD_WARNING_CONFIG_FAILED
;
490 /* Compile AS path. */
491 argv_find(argv
, argc
, "LINE", &idx
);
492 regstr
= argv_concat(argv
, argc
, idx
);
494 if (!config_bgp_aspath_validate(regstr
)) {
495 vty_out(vty
, "Invalid character in as-path access-list %s\n",
497 return CMD_WARNING_CONFIG_FAILED
;
500 regex
= bgp_regcomp(regstr
);
502 vty_out(vty
, "can't compile regexp %s\n", regstr
);
503 XFREE(MTYPE_TMP
, regstr
);
504 return CMD_WARNING_CONFIG_FAILED
;
507 /* Lookup asfilter. */
508 asfilter
= as_filter_lookup(aslist
, regstr
, type
);
510 XFREE(MTYPE_TMP
, regstr
);
511 bgp_regex_free(regex
);
513 if (asfilter
== NULL
) {
515 return CMD_WARNING_CONFIG_FAILED
;
518 as_list_filter_delete(aslist
, asfilter
);
523 DEFUN (no_as_path_all
,
524 no_bgp_as_path_all_cmd
,
525 "no bgp as-path access-list WORD",
528 "BGP autonomous system path filter\n"
529 "Specify an access list name\n"
530 "Regular expression access list name\n")
533 struct as_list
*aslist
;
535 aslist
= as_list_lookup(argv
[idx_word
]->arg
);
536 if (aslist
== NULL
) {
537 vty_out(vty
, "bgp as-path access-list %s doesn't exist\n",
538 argv
[idx_word
]->arg
);
539 return CMD_WARNING_CONFIG_FAILED
;
542 as_list_delete(aslist
);
544 /* Run hook function. */
545 if (as_list_master
.delete_hook
)
546 (*as_list_master
.delete_hook
)(argv
[idx_word
]->arg
);
551 static void as_list_show(struct vty
*vty
, struct as_list
*aslist
)
553 struct as_filter
*asfilter
;
555 vty_out(vty
, "AS path access list %s\n", aslist
->name
);
557 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
) {
558 vty_out(vty
, " %s %s\n", filter_type_str(asfilter
->type
),
563 static void as_list_show_all(struct vty
*vty
)
565 struct as_list
*aslist
;
566 struct as_filter
*asfilter
;
568 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= aslist
->next
) {
569 vty_out(vty
, "AS path access list %s\n", aslist
->name
);
571 for (asfilter
= aslist
->head
; asfilter
;
572 asfilter
= asfilter
->next
) {
573 vty_out(vty
, " %s %s\n",
574 filter_type_str(asfilter
->type
),
579 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= aslist
->next
) {
580 vty_out(vty
, "AS path access list %s\n", aslist
->name
);
582 for (asfilter
= aslist
->head
; asfilter
;
583 asfilter
= asfilter
->next
) {
584 vty_out(vty
, " %s %s\n",
585 filter_type_str(asfilter
->type
),
591 DEFUN (show_as_path_access_list
,
592 show_bgp_as_path_access_list_cmd
,
593 "show bgp as-path-access-list WORD",
596 "List AS path access lists\n"
597 "AS path access list name\n")
600 struct as_list
*aslist
;
602 aslist
= as_list_lookup(argv
[idx_word
]->arg
);
604 as_list_show(vty
, aslist
);
609 ALIAS (show_as_path_access_list
,
610 show_ip_as_path_access_list_cmd
,
611 "show ip as-path-access-list WORD",
614 "List AS path access lists\n"
615 "AS path access list name\n")
617 DEFUN (show_as_path_access_list_all
,
618 show_bgp_as_path_access_list_all_cmd
,
619 "show bgp as-path-access-list",
622 "List AS path access lists\n")
624 as_list_show_all(vty
);
628 ALIAS (show_as_path_access_list_all
,
629 show_ip_as_path_access_list_all_cmd
,
630 "show ip as-path-access-list",
633 "List AS path access lists\n")
635 static int config_write_as_list(struct vty
*vty
)
637 struct as_list
*aslist
;
638 struct as_filter
*asfilter
;
641 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= aslist
->next
)
642 for (asfilter
= aslist
->head
; asfilter
;
643 asfilter
= asfilter
->next
) {
644 vty_out(vty
, "bgp as-path access-list %s %s %s\n",
645 aslist
->name
, filter_type_str(asfilter
->type
),
650 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= aslist
->next
)
651 for (asfilter
= aslist
->head
; asfilter
;
652 asfilter
= asfilter
->next
) {
653 vty_out(vty
, "bgp as-path access-list %s %s %s\n",
654 aslist
->name
, filter_type_str(asfilter
->type
),
661 static int config_write_as_list(struct vty
*vty
);
662 static struct cmd_node as_list_node
= {
664 .node
= AS_LIST_NODE
,
666 .config_write
= config_write_as_list
,
669 /* Register functions. */
670 void bgp_filter_init(void)
672 install_node(&as_list_node
);
674 install_element(CONFIG_NODE
, &bgp_as_path_cmd
);
675 install_element(CONFIG_NODE
, &no_bgp_as_path_cmd
);
676 install_element(CONFIG_NODE
, &no_bgp_as_path_all_cmd
);
678 install_element(VIEW_NODE
, &show_bgp_as_path_access_list_cmd
);
679 install_element(VIEW_NODE
, &show_ip_as_path_access_list_cmd
);
680 install_element(VIEW_NODE
, &show_bgp_as_path_access_list_all_cmd
);
681 install_element(VIEW_NODE
, &show_ip_as_path_access_list_all_cmd
);
684 void bgp_filter_reset(void)
686 struct as_list
*aslist
;
687 struct as_list
*next
;
689 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= next
) {
691 as_list_delete(aslist
);
694 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= next
) {
696 as_list_delete(aslist
);
699 assert(as_list_master
.num
.head
== NULL
);
700 assert(as_list_master
.num
.tail
== NULL
);
702 assert(as_list_master
.str
.head
== NULL
);
703 assert(as_list_master
.str
.tail
== NULL
);