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. */
42 /* AS path filter master. */
45 /* List of access_list which name is number. */
46 struct as_list_list num
;
48 /* List of access_list which name is string. */
49 struct as_list_list str
;
51 /* Hook function which is executed when new access_list is added. */
52 void (*add_hook
) (char *);
54 /* Hook function which is executed when access_list is deleted. */
55 void (*delete_hook
) (const char *);
58 /* Element of AS path filter. */
61 struct as_filter
*next
;
62 struct as_filter
*prev
;
64 enum as_filter_type type
;
70 /* AS path filter list. */
75 enum access_type type
;
80 struct as_filter
*head
;
81 struct as_filter
*tail
;
84 /* ip as-path access-list 10 permit AS1. */
86 static struct as_list_master as_list_master
=
94 /* Allocate new AS filter. */
95 static struct as_filter
*
98 return XCALLOC (MTYPE_AS_FILTER
, sizeof (struct as_filter
));
101 /* Free allocated AS filter. */
103 as_filter_free (struct as_filter
*asfilter
)
106 bgp_regex_free (asfilter
->reg
);
107 if (asfilter
->reg_str
)
108 XFREE (MTYPE_AS_FILTER_STR
, asfilter
->reg_str
);
109 XFREE (MTYPE_AS_FILTER
, asfilter
);
112 /* Make new AS filter. */
113 static struct as_filter
*
114 as_filter_make (regex_t
*reg
, const char *reg_str
, enum as_filter_type type
)
116 struct as_filter
*asfilter
;
118 asfilter
= as_filter_new ();
120 asfilter
->type
= type
;
121 asfilter
->reg_str
= XSTRDUP (MTYPE_AS_FILTER_STR
, reg_str
);
126 static struct as_filter
*
127 as_filter_lookup (struct as_list
*aslist
, const char *reg_str
,
128 enum as_filter_type type
)
130 struct as_filter
*asfilter
;
132 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
133 if (strcmp (reg_str
, asfilter
->reg_str
) == 0)
139 as_list_filter_add (struct as_list
*aslist
, struct as_filter
*asfilter
)
141 asfilter
->next
= NULL
;
142 asfilter
->prev
= aslist
->tail
;
145 aslist
->tail
->next
= asfilter
;
147 aslist
->head
= asfilter
;
148 aslist
->tail
= asfilter
;
150 /* Run hook function. */
151 if (as_list_master
.add_hook
)
152 (*as_list_master
.add_hook
) (aslist
->name
);
156 /* Lookup as_list from list of as_list by name. */
158 as_list_lookup (const char *name
)
160 struct as_list
*aslist
;
165 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= aslist
->next
)
166 if (strcmp (aslist
->name
, name
) == 0)
169 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= aslist
->next
)
170 if (strcmp (aslist
->name
, name
) == 0)
176 static struct as_list
*
179 return XCALLOC (MTYPE_AS_LIST
, sizeof (struct as_list
));
183 as_list_free (struct as_list
*aslist
)
187 XFREE(MTYPE_AS_STR
, aslist
->name
);
190 XFREE (MTYPE_AS_LIST
, aslist
);
193 /* Insert new AS list to list of as_list. Each as_list is sorted by
195 static struct as_list
*
196 as_list_insert (const char *name
)
200 struct as_list
*aslist
;
201 struct as_list
*point
;
202 struct as_list_list
*list
;
204 /* Allocate new access_list and copy given name. */
205 aslist
= as_list_new ();
206 aslist
->name
= XSTRDUP(MTYPE_AS_STR
, name
);
207 assert (aslist
->name
);
209 /* If name is made by all digit character. We treat it as
211 for (number
= 0, i
= 0; i
< strlen (name
); i
++)
213 if (isdigit ((int) name
[i
]))
214 number
= (number
* 10) + (name
[i
] - '0');
219 /* In case of name is all digit character */
220 if (i
== strlen (name
))
222 aslist
->type
= ACCESS_TYPE_NUMBER
;
224 /* Set access_list to number list. */
225 list
= &as_list_master
.num
;
227 for (point
= list
->head
; point
; point
= point
->next
)
228 if (atol (point
->name
) >= number
)
233 aslist
->type
= ACCESS_TYPE_STRING
;
235 /* Set access_list to string list. */
236 list
= &as_list_master
.str
;
238 /* Set point to insertion point. */
239 for (point
= list
->head
; point
; point
= point
->next
)
240 if (strcmp (point
->name
, name
) >= 0)
244 /* In case of this is the first element of master. */
245 if (list
->head
== NULL
)
247 list
->head
= list
->tail
= aslist
;
251 /* In case of insertion is made at the tail of access_list. */
254 aslist
->prev
= list
->tail
;
255 list
->tail
->next
= aslist
;
260 /* In case of insertion is made at the head of access_list. */
261 if (point
== list
->head
)
263 aslist
->next
= list
->head
;
264 list
->head
->prev
= aslist
;
269 /* Insertion is made at middle of the access_list. */
270 aslist
->next
= point
;
271 aslist
->prev
= point
->prev
;
274 point
->prev
->next
= aslist
;
275 point
->prev
= aslist
;
280 static struct as_list
*
281 as_list_get (const char *name
)
283 struct as_list
*aslist
;
285 aslist
= as_list_lookup (name
);
287 aslist
= as_list_insert (name
);
293 filter_type_str (enum as_filter_type type
)
297 case AS_FILTER_PERMIT
:
307 as_list_delete (struct as_list
*aslist
)
309 struct as_list_list
*list
;
310 struct as_filter
*filter
, *next
;
312 for (filter
= aslist
->head
; filter
; filter
= next
)
315 as_filter_free (filter
);
318 if (aslist
->type
== ACCESS_TYPE_NUMBER
)
319 list
= &as_list_master
.num
;
321 list
= &as_list_master
.str
;
324 aslist
->next
->prev
= aslist
->prev
;
326 list
->tail
= aslist
->prev
;
329 aslist
->prev
->next
= aslist
->next
;
331 list
->head
= aslist
->next
;
333 as_list_free (aslist
);
337 as_list_empty (struct as_list
*aslist
)
339 if (aslist
->head
== NULL
&& aslist
->tail
== NULL
)
346 as_list_filter_delete (struct as_list
*aslist
, struct as_filter
*asfilter
)
348 char *name
= XSTRDUP(MTYPE_AS_STR
, aslist
->name
);
351 asfilter
->next
->prev
= asfilter
->prev
;
353 aslist
->tail
= asfilter
->prev
;
356 asfilter
->prev
->next
= asfilter
->next
;
358 aslist
->head
= asfilter
->next
;
360 as_filter_free (asfilter
);
362 /* If access_list becomes empty delete it from access_master. */
363 if (as_list_empty (aslist
))
364 as_list_delete (aslist
);
366 /* Run hook function. */
367 if (as_list_master
.delete_hook
)
368 (*as_list_master
.delete_hook
) (name
);
370 XFREE(MTYPE_AS_STR
, name
);
374 as_filter_match (struct as_filter
*asfilter
, struct aspath
*aspath
)
376 if (bgp_regexec (asfilter
->reg
, aspath
) != REG_NOMATCH
)
381 /* Apply AS path filter to AS. */
383 as_list_apply (struct as_list
*aslist
, void *object
)
385 struct as_filter
*asfilter
;
386 struct aspath
*aspath
;
388 aspath
= (struct aspath
*) object
;
391 return AS_FILTER_DENY
;
393 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
395 if (as_filter_match (asfilter
, aspath
))
396 return asfilter
->type
;
398 return AS_FILTER_DENY
;
401 /* Add hook function. */
403 as_list_add_hook (void (*func
) (char *))
405 as_list_master
.add_hook
= func
;
408 /* Delete hook function. */
410 as_list_delete_hook (void (*func
) (const char *))
412 as_list_master
.delete_hook
= func
;
416 as_list_dup_check (struct as_list
*aslist
, struct as_filter
*new)
418 struct as_filter
*asfilter
;
420 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
422 if (asfilter
->type
== new->type
423 && strcmp (asfilter
->reg_str
, new->reg_str
) == 0)
431 "ip as-path access-list WORD <deny|permit> LINE...",
433 "BGP autonomous system path filter\n"
434 "Specify an access list name\n"
435 "Regular expression access list name\n"
436 "Specify packets to reject\n"
437 "Specify packets to forward\n"
438 "A regular-expression to match the BGP AS paths\n")
441 enum as_filter_type type
;
442 struct as_filter
*asfilter
;
443 struct as_list
*aslist
;
447 /* Retrieve access list name */
448 char *alname
= argv_find (argv
, argc
, "WORD", &idx
) ? argv
[idx
]->arg
: NULL
;
450 /* Check the filter type. */
451 type
= argv_find (argv
, argc
, "deny", &idx
) ? AS_FILTER_DENY
: AS_FILTER_PERMIT
;
453 /* Check AS path regex. */
454 argv_find (argv
, argc
, "LINE", &idx
);
455 regstr
= argv_concat(argv
, argc
, idx
);
457 regex
= bgp_regcomp (regstr
);
460 vty_out (vty
, "can't compile regexp %s%s", regstr
, VTY_NEWLINE
);
461 XFREE (MTYPE_TMP
, regstr
);
465 asfilter
= as_filter_make (regex
, regstr
, type
);
467 XFREE (MTYPE_TMP
, regstr
);
469 /* Install new filter to the access_list. */
470 aslist
= as_list_get (alname
);
472 /* Duplicate insertion check. */;
473 if (as_list_dup_check (aslist
, asfilter
))
474 as_filter_free (asfilter
);
476 as_list_filter_add (aslist
, asfilter
);
481 DEFUN (no_ip_as_path
,
483 "no ip as-path access-list WORD <deny|permit> LINE...",
486 "BGP autonomous system path filter\n"
487 "Specify an access list name\n"
488 "Regular expression access list name\n"
489 "Specify packets to reject\n"
490 "Specify packets to forward\n"
491 "A regular-expression to match the BGP AS paths\n")
494 enum as_filter_type type
;
495 struct as_filter
*asfilter
;
496 struct as_list
*aslist
;
500 char *aslistname
= argv_find (argv
, argc
, "WORD", &idx
) ? argv
[idx
]->arg
: NULL
;
502 /* Lookup AS list from AS path list. */
503 aslist
= as_list_lookup (aslistname
);
506 vty_out (vty
, "ip as-path access-list %s doesn't exist%s", aslistname
,
511 /* Check the filter type. */
512 if (argv_find (argv
, argc
, "permit", &idx
))
513 type
= AS_FILTER_PERMIT
;
514 else if (argv_find (argv
, argc
, "deny", &idx
))
515 type
= AS_FILTER_DENY
;
518 vty_out (vty
, "filter type must be [permit|deny]%s", VTY_NEWLINE
);
522 /* Compile AS path. */
523 argv_find (argv
, argc
, "LINE", &idx
);
524 regstr
= argv_concat(argv
, argc
, idx
);
526 regex
= bgp_regcomp (regstr
);
529 vty_out (vty
, "can't compile regexp %s%s", regstr
, VTY_NEWLINE
);
530 XFREE (MTYPE_TMP
, regstr
);
534 /* Lookup asfilter. */
535 asfilter
= as_filter_lookup (aslist
, regstr
, type
);
537 XFREE (MTYPE_TMP
, regstr
);
538 bgp_regex_free (regex
);
540 if (asfilter
== NULL
)
542 vty_out (vty
, "%s", VTY_NEWLINE
);
546 as_list_filter_delete (aslist
, asfilter
);
551 DEFUN (no_ip_as_path_all
,
552 no_ip_as_path_all_cmd
,
553 "no ip as-path access-list WORD",
556 "BGP autonomous system path filter\n"
557 "Specify an access list name\n"
558 "Regular expression access list name\n")
561 struct as_list
*aslist
;
563 aslist
= as_list_lookup (argv
[idx_word
]->arg
);
566 vty_out (vty
, "ip as-path access-list %s doesn't exist%s", argv
[idx_word
]->arg
,
571 as_list_delete (aslist
);
573 /* Run hook function. */
574 if (as_list_master
.delete_hook
)
575 (*as_list_master
.delete_hook
) (argv
[idx_word
]->arg
);
581 as_list_show (struct vty
*vty
, struct as_list
*aslist
)
583 struct as_filter
*asfilter
;
585 vty_out (vty
, "AS path access list %s%s", aslist
->name
, VTY_NEWLINE
);
587 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
589 vty_out (vty
, " %s %s%s", filter_type_str (asfilter
->type
),
590 asfilter
->reg_str
, VTY_NEWLINE
);
595 as_list_show_all (struct vty
*vty
)
597 struct as_list
*aslist
;
598 struct as_filter
*asfilter
;
600 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= aslist
->next
)
602 vty_out (vty
, "AS path access list %s%s", aslist
->name
, VTY_NEWLINE
);
604 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
606 vty_out (vty
, " %s %s%s", filter_type_str (asfilter
->type
),
607 asfilter
->reg_str
, VTY_NEWLINE
);
611 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= aslist
->next
)
613 vty_out (vty
, "AS path access list %s%s", aslist
->name
, VTY_NEWLINE
);
615 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
617 vty_out (vty
, " %s %s%s", filter_type_str (asfilter
->type
),
618 asfilter
->reg_str
, VTY_NEWLINE
);
623 DEFUN (show_ip_as_path_access_list
,
624 show_ip_as_path_access_list_cmd
,
625 "show ip as-path-access-list WORD",
628 "List AS path access lists\n"
629 "AS path access list name\n")
632 struct as_list
*aslist
;
634 aslist
= as_list_lookup (argv
[idx_word
]->arg
);
636 as_list_show (vty
, aslist
);
641 DEFUN (show_ip_as_path_access_list_all
,
642 show_ip_as_path_access_list_all_cmd
,
643 "show ip as-path-access-list",
646 "List AS path access lists\n")
648 as_list_show_all (vty
);
653 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
; asfilter
= asfilter
->next
)
662 vty_out (vty
, "ip as-path access-list %s %s %s%s",
663 aslist
->name
, filter_type_str (asfilter
->type
),
669 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= aslist
->next
)
670 for (asfilter
= aslist
->head
; asfilter
; asfilter
= asfilter
->next
)
672 vty_out (vty
, "ip as-path access-list %s %s %s%s",
673 aslist
->name
, filter_type_str (asfilter
->type
),
681 static struct cmd_node as_list_node
=
688 /* Register functions. */
690 bgp_filter_init (void)
692 install_node (&as_list_node
, config_write_as_list
);
694 install_element (CONFIG_NODE
, &ip_as_path_cmd
);
695 install_element (CONFIG_NODE
, &no_ip_as_path_cmd
);
696 install_element (CONFIG_NODE
, &no_ip_as_path_all_cmd
);
698 install_element (VIEW_NODE
, &show_ip_as_path_access_list_cmd
);
699 install_element (VIEW_NODE
, &show_ip_as_path_access_list_all_cmd
);
703 bgp_filter_reset (void)
705 struct as_list
*aslist
;
706 struct as_list
*next
;
708 for (aslist
= as_list_master
.num
.head
; aslist
; aslist
= next
)
711 as_list_delete (aslist
);
714 for (aslist
= as_list_master
.str
.head
; aslist
; aslist
= next
)
717 as_list_delete (aslist
);
720 assert (as_list_master
.num
.head
== NULL
);
721 assert (as_list_master
.num
.tail
== NULL
);
723 assert (as_list_master
.str
.head
== NULL
);
724 assert (as_list_master
.str
.tail
== NULL
);