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)
396 "ip as-path access-list WORD <deny|permit> LINE...",
398 "BGP autonomous system path filter\n"
399 "Specify an access list name\n"
400 "Regular expression access list name\n"
401 "Specify packets to reject\n"
402 "Specify packets to forward\n"
403 "A regular-expression to match the BGP AS paths\n")
406 enum as_filter_type type
;
407 struct as_filter
*asfilter
;
408 struct as_list
*aslist
;
412 /* Retrieve access list name */
413 argv_find(argv
, argc
, "WORD", &idx
);
414 char *alname
= argv
[idx
]->arg
;
416 /* Check the filter type. */
417 type
= argv_find(argv
, argc
, "deny", &idx
) ? AS_FILTER_DENY
420 /* Check AS path regex. */
421 argv_find(argv
, argc
, "LINE", &idx
);
422 regstr
= argv_concat(argv
, argc
, idx
);
424 regex
= bgp_regcomp(regstr
);
426 vty_out(vty
, "can't compile regexp %s\n", regstr
);
427 XFREE(MTYPE_TMP
, regstr
);
428 return CMD_WARNING_CONFIG_FAILED
;
431 asfilter
= as_filter_make(regex
, regstr
, type
);
433 XFREE(MTYPE_TMP
, regstr
);
435 /* Install new filter to the access_list. */
436 aslist
= as_list_get(alname
);
438 /* Duplicate insertion check. */;
439 if (as_list_dup_check(aslist
, asfilter
))
440 as_filter_free(asfilter
);
442 as_list_filter_add(aslist
, asfilter
);
447 DEFUN (no_ip_as_path
,
449 "no ip as-path access-list WORD <deny|permit> LINE...",
452 "BGP autonomous system path filter\n"
453 "Specify an access list name\n"
454 "Regular expression access list name\n"
455 "Specify packets to reject\n"
456 "Specify packets to forward\n"
457 "A regular-expression to match the BGP AS paths\n")
460 enum as_filter_type type
;
461 struct as_filter
*asfilter
;
462 struct as_list
*aslist
;
467 argv_find(argv
, argc
, "WORD", &idx
) ? argv
[idx
]->arg
: NULL
;
469 /* Lookup AS list from AS path list. */
470 aslist
= as_list_lookup(aslistname
);
471 if (aslist
== NULL
) {
472 vty_out(vty
, "ip as-path access-list %s doesn't exist\n",
474 return CMD_WARNING_CONFIG_FAILED
;
477 /* Check the filter type. */
478 if (argv_find(argv
, argc
, "permit", &idx
))
479 type
= AS_FILTER_PERMIT
;
480 else if (argv_find(argv
, argc
, "deny", &idx
))
481 type
= AS_FILTER_DENY
;
483 vty_out(vty
, "filter type must be [permit|deny]\n");
484 return CMD_WARNING_CONFIG_FAILED
;
487 /* Compile AS path. */
488 argv_find(argv
, argc
, "LINE", &idx
);
489 regstr
= argv_concat(argv
, argc
, idx
);
491 regex
= bgp_regcomp(regstr
);
493 vty_out(vty
, "can't compile regexp %s\n", regstr
);
494 XFREE(MTYPE_TMP
, regstr
);
495 return CMD_WARNING_CONFIG_FAILED
;
498 /* Lookup asfilter. */
499 asfilter
= as_filter_lookup(aslist
, regstr
, type
);
501 XFREE(MTYPE_TMP
, regstr
);
502 bgp_regex_free(regex
);
504 if (asfilter
== NULL
) {
506 return CMD_WARNING_CONFIG_FAILED
;
509 as_list_filter_delete(aslist
, asfilter
);
514 DEFUN (no_ip_as_path_all
,
515 no_ip_as_path_all_cmd
,
516 "no ip as-path access-list WORD",
519 "BGP autonomous system path filter\n"
520 "Specify an access list name\n"
521 "Regular expression access list name\n")
524 struct as_list
*aslist
;
526 aslist
= as_list_lookup(argv
[idx_word
]->arg
);
527 if (aslist
== NULL
) {
528 vty_out(vty
, "ip as-path access-list %s doesn't exist\n",
529 argv
[idx_word
]->arg
);
530 return CMD_WARNING_CONFIG_FAILED
;
533 as_list_delete(aslist
);
535 /* Run hook function. */
536 if (as_list_master
.delete_hook
)
537 (*as_list_master
.delete_hook
)(argv
[idx_word
]->arg
);
542 static void as_list_show(struct vty
*vty
, struct as_list
*aslist
)
544 struct as_filter
*asfilter
;
546 vty_out(vty
, "AS path access list %s\n", aslist
->name
);
548 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
) {
549 vty_out(vty
, " %s %s\n", filter_type_str(asfilter
->type
),
554 static void as_list_show_all(struct vty
*vty
)
556 struct as_list
*aslist
;
557 struct as_filter
*asfilter
;
559 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= aslist
->next
) {
560 vty_out(vty
, "AS path access list %s\n", aslist
->name
);
562 for (asfilter
= aslist
->head
; asfilter
;
563 asfilter
= asfilter
->next
) {
564 vty_out(vty
, " %s %s\n",
565 filter_type_str(asfilter
->type
),
570 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= aslist
->next
) {
571 vty_out(vty
, "AS path access list %s\n", aslist
->name
);
573 for (asfilter
= aslist
->head
; asfilter
;
574 asfilter
= asfilter
->next
) {
575 vty_out(vty
, " %s %s\n",
576 filter_type_str(asfilter
->type
),
582 DEFUN (show_ip_as_path_access_list
,
583 show_ip_as_path_access_list_cmd
,
584 "show ip as-path-access-list WORD",
587 "List AS path access lists\n"
588 "AS path access list name\n")
591 struct as_list
*aslist
;
593 aslist
= as_list_lookup(argv
[idx_word
]->arg
);
595 as_list_show(vty
, aslist
);
600 DEFUN (show_ip_as_path_access_list_all
,
601 show_ip_as_path_access_list_all_cmd
,
602 "show ip as-path-access-list",
605 "List AS path access lists\n")
607 as_list_show_all(vty
);
611 static int config_write_as_list(struct vty
*vty
)
613 struct as_list
*aslist
;
614 struct as_filter
*asfilter
;
617 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= aslist
->next
)
618 for (asfilter
= aslist
->head
; asfilter
;
619 asfilter
= asfilter
->next
) {
620 vty_out(vty
, "ip as-path access-list %s %s %s\n",
621 aslist
->name
, filter_type_str(asfilter
->type
),
626 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= aslist
->next
)
627 for (asfilter
= aslist
->head
; asfilter
;
628 asfilter
= asfilter
->next
) {
629 vty_out(vty
, "ip as-path access-list %s %s %s\n",
630 aslist
->name
, filter_type_str(asfilter
->type
),
637 static struct cmd_node as_list_node
= {AS_LIST_NODE
, "", 1};
639 /* Register functions. */
640 void bgp_filter_init(void)
642 install_node(&as_list_node
, config_write_as_list
);
644 install_element(CONFIG_NODE
, &ip_as_path_cmd
);
645 install_element(CONFIG_NODE
, &no_ip_as_path_cmd
);
646 install_element(CONFIG_NODE
, &no_ip_as_path_all_cmd
);
648 install_element(VIEW_NODE
, &show_ip_as_path_access_list_cmd
);
649 install_element(VIEW_NODE
, &show_ip_as_path_access_list_all_cmd
);
652 void bgp_filter_reset(void)
654 struct as_list
*aslist
;
655 struct as_list
*next
;
657 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= next
) {
659 as_list_delete(aslist
);
662 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= next
) {
664 as_list_delete(aslist
);
667 assert(as_list_master
.num
.head
== NULL
);
668 assert(as_list_master
.num
.tail
== NULL
);
670 assert(as_list_master
.str
.head
== NULL
);
671 assert(as_list_master
.str
.tail
== NULL
);