[ospfd] Restructure opsf_if_update() and ospf_network_run()
[jleu-quagga.git] / bgpd / bgp_filter.c
blobab7f07037fce61af852f9c6f5c4a35632337736f
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
9 later version.
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
17 along with GNU Zebra; see the file COPYING. If not, write to the Free
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA. */
21 #include <zebra.h>
23 #include "command.h"
24 #include "log.h"
25 #include "memory.h"
26 #include "buffer.h"
28 #include "bgpd/bgpd.h"
29 #include "bgpd/bgp_aspath.h"
30 #include "bgpd/bgp_regex.h"
31 #include "bgpd/bgp_filter.h"
33 /* List of AS filter list. */
34 struct as_list_list
36 struct as_list *head;
37 struct as_list *tail;
40 /* AS path filter master. */
41 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) ();
52 /* Hook function which is executed when access_list is deleted. */
53 void (*delete_hook) ();
56 /* Element of AS path filter. */
57 struct as_filter
59 struct as_filter *next;
60 struct as_filter *prev;
62 enum as_filter_type type;
64 regex_t *reg;
65 char *reg_str;
68 enum as_list_type
70 ACCESS_TYPE_STRING,
71 ACCESS_TYPE_NUMBER
74 /* AS path filter list. */
75 struct as_list
77 char *name;
79 enum as_list_type type;
81 struct as_list *next;
82 struct as_list *prev;
84 struct as_filter *head;
85 struct as_filter *tail;
88 /* ip as-path access-list 10 permit AS1. */
90 static struct as_list_master as_list_master =
92 {NULL, NULL},
93 {NULL, NULL},
94 NULL,
95 NULL
98 /* Allocate new AS filter. */
99 static struct as_filter *
100 as_filter_new ()
102 struct as_filter *new;
104 new = XMALLOC (MTYPE_AS_FILTER, sizeof (struct as_filter));
105 memset (new, 0, sizeof (struct as_filter));
106 return new;
109 /* Free allocated AS filter. */
110 static void
111 as_filter_free (struct as_filter *asfilter)
113 if (asfilter->reg)
114 bgp_regex_free (asfilter->reg);
115 if (asfilter->reg_str)
116 XFREE (MTYPE_AS_FILTER_STR, asfilter->reg_str);
117 XFREE (MTYPE_AS_FILTER, asfilter);
120 /* Make new AS filter. */
121 static struct as_filter *
122 as_filter_make (regex_t *reg, const char *reg_str, enum as_filter_type type)
124 struct as_filter *asfilter;
126 asfilter = as_filter_new ();
127 asfilter->reg = reg;
128 asfilter->type = type;
129 asfilter->reg_str = XSTRDUP (MTYPE_AS_FILTER_STR, reg_str);
131 return asfilter;
134 static struct as_filter *
135 as_filter_lookup (struct as_list *aslist, const char *reg_str,
136 enum as_filter_type type)
138 struct as_filter *asfilter;
140 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
141 if (strcmp (reg_str, asfilter->reg_str) == 0)
142 return asfilter;
143 return NULL;
146 static void
147 as_list_filter_add (struct as_list *aslist, struct as_filter *asfilter)
149 asfilter->next = NULL;
150 asfilter->prev = aslist->tail;
152 if (aslist->tail)
153 aslist->tail->next = asfilter;
154 else
155 aslist->head = asfilter;
156 aslist->tail = asfilter;
159 /* Lookup as_list from list of as_list by name. */
160 struct as_list *
161 as_list_lookup (const char *name)
163 struct as_list *aslist;
165 if (name == NULL)
166 return NULL;
168 for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
169 if (strcmp (aslist->name, name) == 0)
170 return aslist;
172 for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
173 if (strcmp (aslist->name, name) == 0)
174 return aslist;
176 return NULL;
179 static struct as_list *
180 as_list_new ()
182 struct as_list *new;
184 new = XMALLOC (MTYPE_AS_LIST, sizeof (struct as_list));
185 memset (new, 0, sizeof (struct as_list));
186 return new;
189 static void
190 as_list_free (struct as_list *aslist)
192 XFREE (MTYPE_AS_LIST, aslist);
195 /* Insert new AS list to list of as_list. Each as_list is sorted by
196 the name. */
197 static struct as_list *
198 as_list_insert (const char *name)
200 size_t i;
201 long number;
202 struct as_list *aslist;
203 struct as_list *point;
204 struct as_list_list *list;
206 /* Allocate new access_list and copy given name. */
207 aslist = as_list_new ();
208 aslist->name = strdup (name);
210 /* If name is made by all digit character. We treat it as
211 number. */
212 for (number = 0, i = 0; i < strlen (name); i++)
214 if (isdigit ((int) name[i]))
215 number = (number * 10) + (name[i] - '0');
216 else
217 break;
220 /* In case of name is all digit character */
221 if (i == strlen (name))
223 aslist->type = ACCESS_TYPE_NUMBER;
225 /* Set access_list to number list. */
226 list = &as_list_master.num;
228 for (point = list->head; point; point = point->next)
229 if (atol (point->name) >= number)
230 break;
232 else
234 aslist->type = ACCESS_TYPE_STRING;
236 /* Set access_list to string list. */
237 list = &as_list_master.str;
239 /* Set point to insertion point. */
240 for (point = list->head; point; point = point->next)
241 if (strcmp (point->name, name) >= 0)
242 break;
245 /* In case of this is the first element of master. */
246 if (list->head == NULL)
248 list->head = list->tail = aslist;
249 return aslist;
252 /* In case of insertion is made at the tail of access_list. */
253 if (point == NULL)
255 aslist->prev = list->tail;
256 list->tail->next = aslist;
257 list->tail = aslist;
258 return aslist;
261 /* In case of insertion is made at the head of access_list. */
262 if (point == list->head)
264 aslist->next = list->head;
265 list->head->prev = aslist;
266 list->head = aslist;
267 return aslist;
270 /* Insertion is made at middle of the access_list. */
271 aslist->next = point;
272 aslist->prev = point->prev;
274 if (point->prev)
275 point->prev->next = aslist;
276 point->prev = aslist;
278 return aslist;
281 static struct as_list *
282 as_list_get (const char *name)
284 struct as_list *aslist;
286 aslist = as_list_lookup (name);
287 if (aslist == NULL)
289 aslist = as_list_insert (name);
291 /* Run hook function. */
292 if (as_list_master.add_hook)
293 (*as_list_master.add_hook) ();
296 return aslist;
299 static const char *
300 filter_type_str (enum as_filter_type type)
302 switch (type)
304 case AS_FILTER_PERMIT:
305 return "permit";
306 case AS_FILTER_DENY:
307 return "deny";
308 default:
309 return "";
313 static void
314 as_list_delete (struct as_list *aslist)
316 struct as_list_list *list;
317 struct as_filter *filter, *next;
319 for (filter = aslist->head; filter; filter = next)
321 next = filter->next;
322 as_filter_free (filter);
325 if (aslist->type == ACCESS_TYPE_NUMBER)
326 list = &as_list_master.num;
327 else
328 list = &as_list_master.str;
330 if (aslist->next)
331 aslist->next->prev = aslist->prev;
332 else
333 list->tail = aslist->prev;
335 if (aslist->prev)
336 aslist->prev->next = aslist->next;
337 else
338 list->head = aslist->next;
340 as_list_free (aslist);
343 static int
344 as_list_empty (struct as_list *aslist)
346 if (aslist->head == NULL && aslist->tail == NULL)
347 return 1;
348 else
349 return 0;
352 static void
353 as_list_filter_delete (struct as_list *aslist, struct as_filter *asfilter)
355 if (asfilter->next)
356 asfilter->next->prev = asfilter->prev;
357 else
358 aslist->tail = asfilter->prev;
360 if (asfilter->prev)
361 asfilter->prev->next = asfilter->next;
362 else
363 aslist->head = asfilter->next;
365 as_filter_free (asfilter);
367 /* If access_list becomes empty delete it from access_master. */
368 if (as_list_empty (aslist))
369 as_list_delete (aslist);
371 /* Run hook function. */
372 if (as_list_master.delete_hook)
373 (*as_list_master.delete_hook) ();
376 static int
377 as_filter_match (struct as_filter *asfilter, struct aspath *aspath)
379 if (bgp_regexec (asfilter->reg, aspath) != REG_NOMATCH)
380 return 1;
381 return 0;
384 /* Apply AS path filter to AS. */
385 enum as_filter_type
386 as_list_apply (struct as_list *aslist, void *object)
388 struct as_filter *asfilter;
389 struct aspath *aspath;
391 aspath = (struct aspath *) object;
393 if (aslist == NULL)
394 return AS_FILTER_DENY;
396 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
398 if (as_filter_match (asfilter, aspath))
399 return asfilter->type;
401 return AS_FILTER_DENY;
404 /* Add hook function. */
405 void
406 as_list_add_hook (void (*func) ())
408 as_list_master.add_hook = func;
411 /* Delete hook function. */
412 void
413 as_list_delete_hook (void (*func) ())
415 as_list_master.delete_hook = func;
418 static int
419 as_list_dup_check (struct as_list *aslist, struct as_filter *new)
421 struct as_filter *asfilter;
423 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
425 if (asfilter->type == new->type
426 && strcmp (asfilter->reg_str, new->reg_str) == 0)
427 return 1;
429 return 0;
432 DEFUN (ip_as_path, ip_as_path_cmd,
433 "ip as-path access-list WORD (deny|permit) .LINE",
434 IP_STR
435 "BGP autonomous system path filter\n"
436 "Specify an access list name\n"
437 "Regular expression access list name\n"
438 "Specify packets to reject\n"
439 "Specify packets to forward\n"
440 "A regular-expression to match the BGP AS paths\n")
442 enum as_filter_type type;
443 struct as_filter *asfilter;
444 struct as_list *aslist;
445 regex_t *regex;
446 char *regstr;
448 /* Check the filter type. */
449 if (strncmp (argv[1], "p", 1) == 0)
450 type = AS_FILTER_PERMIT;
451 else if (strncmp (argv[1], "d", 1) == 0)
452 type = AS_FILTER_DENY;
453 else
455 vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE);
456 return CMD_WARNING;
459 /* Check AS path regex. */
460 regstr = argv_concat(argv, argc, 2);
462 regex = bgp_regcomp (regstr);
463 if (!regex)
465 XFREE (MTYPE_TMP, regstr);
466 vty_out (vty, "can't compile regexp %s%s", argv[0],
467 VTY_NEWLINE);
468 return CMD_WARNING;
471 asfilter = as_filter_make (regex, regstr, type);
473 XFREE (MTYPE_TMP, regstr);
475 /* Install new filter to the access_list. */
476 aslist = as_list_get (argv[0]);
478 /* Duplicate insertion check. */;
479 if (as_list_dup_check (aslist, asfilter))
480 as_filter_free (asfilter);
481 else
482 as_list_filter_add (aslist, asfilter);
484 return CMD_SUCCESS;
487 DEFUN (no_ip_as_path,
488 no_ip_as_path_cmd,
489 "no ip as-path access-list WORD (deny|permit) .LINE",
490 NO_STR
491 IP_STR
492 "BGP autonomous system path filter\n"
493 "Specify an access list name\n"
494 "Regular expression access list name\n"
495 "Specify packets to reject\n"
496 "Specify packets to forward\n"
497 "A regular-expression to match the BGP AS paths\n")
499 enum as_filter_type type;
500 struct as_filter *asfilter;
501 struct as_list *aslist;
502 char *regstr;
503 regex_t *regex;
505 /* Lookup AS list from AS path list. */
506 aslist = as_list_lookup (argv[0]);
507 if (aslist == NULL)
509 vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0],
510 VTY_NEWLINE);
511 return CMD_WARNING;
514 /* Check the filter type. */
515 if (strncmp (argv[1], "p", 1) == 0)
516 type = AS_FILTER_PERMIT;
517 else if (strncmp (argv[1], "d", 1) == 0)
518 type = AS_FILTER_DENY;
519 else
521 vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE);
522 return CMD_WARNING;
525 /* Compile AS path. */
526 regstr = argv_concat(argv, argc, 2);
528 regex = bgp_regcomp (regstr);
529 if (!regex)
531 XFREE (MTYPE_TMP, regstr);
532 vty_out (vty, "can't compile regexp %s%s", argv[0],
533 VTY_NEWLINE);
534 return CMD_WARNING;
537 /* Lookup asfilter. */
538 asfilter = as_filter_lookup (aslist, regstr, type);
540 XFREE (MTYPE_TMP, regstr);
541 bgp_regex_free (regex);
543 if (asfilter == NULL)
545 vty_out (vty, "%s", VTY_NEWLINE);
546 return CMD_WARNING;
549 as_list_filter_delete (aslist, asfilter);
551 return CMD_SUCCESS;
554 DEFUN (no_ip_as_path_all,
555 no_ip_as_path_all_cmd,
556 "no ip as-path access-list WORD",
557 NO_STR
558 IP_STR
559 "BGP autonomous system path filter\n"
560 "Specify an access list name\n"
561 "Regular expression access list name\n")
563 struct as_list *aslist;
565 aslist = as_list_lookup (argv[0]);
566 if (aslist == NULL)
568 vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0],
569 VTY_NEWLINE);
570 return CMD_WARNING;
573 as_list_delete (aslist);
575 /* Run hook function. */
576 if (as_list_master.delete_hook)
577 (*as_list_master.delete_hook) ();
579 return CMD_SUCCESS;
582 static void
583 as_list_show (struct vty *vty, struct as_list *aslist)
585 struct as_filter *asfilter;
587 vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE);
589 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
591 vty_out (vty, " %s %s%s", filter_type_str (asfilter->type),
592 asfilter->reg_str, VTY_NEWLINE);
596 static void
597 as_list_show_all (struct vty *vty)
599 struct as_list *aslist;
600 struct as_filter *asfilter;
602 for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
604 vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE);
606 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
608 vty_out (vty, " %s %s%s", filter_type_str (asfilter->type),
609 asfilter->reg_str, VTY_NEWLINE);
613 for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
615 vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE);
617 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
619 vty_out (vty, " %s %s%s", filter_type_str (asfilter->type),
620 asfilter->reg_str, VTY_NEWLINE);
625 DEFUN (show_ip_as_path_access_list,
626 show_ip_as_path_access_list_cmd,
627 "show ip as-path-access-list WORD",
628 SHOW_STR
629 IP_STR
630 "List AS path access lists\n"
631 "AS path access list name\n")
633 struct as_list *aslist;
635 aslist = as_list_lookup (argv[0]);
636 if (aslist)
637 as_list_show (vty, aslist);
639 return CMD_SUCCESS;
642 DEFUN (show_ip_as_path_access_list_all,
643 show_ip_as_path_access_list_all_cmd,
644 "show ip as-path-access-list",
645 SHOW_STR
646 IP_STR
647 "List AS path access lists\n")
649 as_list_show_all (vty);
650 return CMD_SUCCESS;
653 static int
654 config_write_as_list (struct vty *vty)
656 struct as_list *aslist;
657 struct as_filter *asfilter;
658 int write = 0;
660 for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
661 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
663 vty_out (vty, "ip as-path access-list %s %s %s%s",
664 aslist->name, filter_type_str (asfilter->type),
665 asfilter->reg_str,
666 VTY_NEWLINE);
667 write++;
670 for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
671 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
673 vty_out (vty, "ip as-path access-list %s %s %s%s",
674 aslist->name, filter_type_str (asfilter->type),
675 asfilter->reg_str,
676 VTY_NEWLINE);
677 write++;
679 return write;
682 struct cmd_node as_list_node =
684 AS_LIST_NODE,
689 /* Register functions. */
690 void
691 bgp_filter_init (void)
693 install_node (&as_list_node, config_write_as_list);
695 install_element (CONFIG_NODE, &ip_as_path_cmd);
696 install_element (CONFIG_NODE, &no_ip_as_path_cmd);
697 install_element (CONFIG_NODE, &no_ip_as_path_all_cmd);
699 install_element (VIEW_NODE, &show_ip_as_path_access_list_cmd);
700 install_element (VIEW_NODE, &show_ip_as_path_access_list_all_cmd);
701 install_element (ENABLE_NODE, &show_ip_as_path_access_list_cmd);
702 install_element (ENABLE_NODE, &show_ip_as_path_access_list_all_cmd);