Line data Source code
1 : /* AS path filter list.
2 : Copyright (C) 1999 Kunihiro Ishiguro
3 :
4 : This file is part of GNU Zebra.
5 :
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.
10 :
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.
15 :
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. */
20 :
21 : #include <zebra.h>
22 :
23 : #include "command.h"
24 : #include "log.h"
25 : #include "memory.h"
26 : #include "buffer.h"
27 :
28 : #include "bgpd/bgpd.h"
29 : #include "bgpd/bgp_aspath.h"
30 : #include "bgpd/bgp_regex.h"
31 : #include "bgpd/bgp_filter.h"
32 :
33 : /* List of AS filter list. */
34 : struct as_list_list
35 : {
36 : struct as_list *head;
37 : struct as_list *tail;
38 : };
39 :
40 : /* AS path filter master. */
41 : struct as_list_master
42 : {
43 : /* List of access_list which name is number. */
44 : struct as_list_list num;
45 :
46 : /* List of access_list which name is string. */
47 : struct as_list_list str;
48 :
49 : /* Hook function which is executed when new access_list is added. */
50 : void (*add_hook) (void);
51 :
52 : /* Hook function which is executed when access_list is deleted. */
53 : void (*delete_hook) (void);
54 : };
55 :
56 : /* Element of AS path filter. */
57 : struct as_filter
58 : {
59 : struct as_filter *next;
60 : struct as_filter *prev;
61 :
62 : enum as_filter_type type;
63 :
64 : regex_t *reg;
65 : char *reg_str;
66 : };
67 :
68 : enum as_list_type
69 : {
70 : ACCESS_TYPE_STRING,
71 : ACCESS_TYPE_NUMBER
72 : };
73 :
74 : /* AS path filter list. */
75 : struct as_list
76 : {
77 : char *name;
78 :
79 : enum as_list_type type;
80 :
81 : struct as_list *next;
82 : struct as_list *prev;
83 :
84 : struct as_filter *head;
85 : struct as_filter *tail;
86 : };
87 :
88 : /* ip as-path access-list 10 permit AS1. */
89 :
90 : static struct as_list_master as_list_master =
91 : {
92 : {NULL, NULL},
93 : {NULL, NULL},
94 : NULL,
95 : NULL
96 : };
97 :
98 : /* Allocate new AS filter. */
99 : static struct as_filter *
100 0 : as_filter_new (void)
101 : {
102 0 : return XCALLOC (MTYPE_AS_FILTER, sizeof (struct as_filter));
103 : }
104 :
105 : /* Free allocated AS filter. */
106 : static void
107 0 : as_filter_free (struct as_filter *asfilter)
108 : {
109 0 : if (asfilter->reg)
110 0 : bgp_regex_free (asfilter->reg);
111 0 : if (asfilter->reg_str)
112 0 : XFREE (MTYPE_AS_FILTER_STR, asfilter->reg_str);
113 0 : XFREE (MTYPE_AS_FILTER, asfilter);
114 0 : }
115 :
116 : /* Make new AS filter. */
117 : static struct as_filter *
118 0 : as_filter_make (regex_t *reg, const char *reg_str, enum as_filter_type type)
119 : {
120 : struct as_filter *asfilter;
121 :
122 0 : asfilter = as_filter_new ();
123 0 : asfilter->reg = reg;
124 0 : asfilter->type = type;
125 0 : asfilter->reg_str = XSTRDUP (MTYPE_AS_FILTER_STR, reg_str);
126 :
127 0 : return asfilter;
128 : }
129 :
130 : static struct as_filter *
131 0 : as_filter_lookup (struct as_list *aslist, const char *reg_str,
132 : enum as_filter_type type)
133 : {
134 : struct as_filter *asfilter;
135 :
136 0 : for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
137 0 : if (strcmp (reg_str, asfilter->reg_str) == 0)
138 0 : return asfilter;
139 0 : return NULL;
140 : }
141 :
142 : static void
143 0 : as_list_filter_add (struct as_list *aslist, struct as_filter *asfilter)
144 : {
145 0 : asfilter->next = NULL;
146 0 : asfilter->prev = aslist->tail;
147 :
148 0 : if (aslist->tail)
149 0 : aslist->tail->next = asfilter;
150 : else
151 0 : aslist->head = asfilter;
152 0 : aslist->tail = asfilter;
153 0 : }
154 :
155 : /* Lookup as_list from list of as_list by name. */
156 : struct as_list *
157 0 : as_list_lookup (const char *name)
158 : {
159 : struct as_list *aslist;
160 :
161 0 : if (name == NULL)
162 0 : return NULL;
163 :
164 0 : for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
165 0 : if (strcmp (aslist->name, name) == 0)
166 0 : return aslist;
167 :
168 0 : for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
169 0 : if (strcmp (aslist->name, name) == 0)
170 0 : return aslist;
171 :
172 0 : return NULL;
173 : }
174 :
175 : static struct as_list *
176 0 : as_list_new (void)
177 : {
178 0 : return XCALLOC (MTYPE_AS_LIST, sizeof (struct as_list));
179 : }
180 :
181 : static void
182 0 : as_list_free (struct as_list *aslist)
183 : {
184 0 : if (aslist->name)
185 : {
186 0 : free (aslist->name);
187 0 : aslist->name = NULL;
188 : }
189 0 : XFREE (MTYPE_AS_LIST, aslist);
190 0 : }
191 :
192 : /* Insert new AS list to list of as_list. Each as_list is sorted by
193 : the name. */
194 : static struct as_list *
195 0 : as_list_insert (const char *name)
196 : {
197 : size_t i;
198 : long number;
199 : struct as_list *aslist;
200 : struct as_list *point;
201 : struct as_list_list *list;
202 :
203 : /* Allocate new access_list and copy given name. */
204 0 : aslist = as_list_new ();
205 0 : aslist->name = strdup (name);
206 0 : assert (aslist->name);
207 :
208 : /* If name is made by all digit character. We treat it as
209 : number. */
210 0 : for (number = 0, i = 0; i < strlen (name); i++)
211 : {
212 0 : if (isdigit ((int) name[i]))
213 0 : number = (number * 10) + (name[i] - '0');
214 : else
215 0 : break;
216 : }
217 :
218 : /* In case of name is all digit character */
219 0 : if (i == strlen (name))
220 : {
221 0 : aslist->type = ACCESS_TYPE_NUMBER;
222 :
223 : /* Set access_list to number list. */
224 0 : list = &as_list_master.num;
225 :
226 0 : for (point = list->head; point; point = point->next)
227 0 : if (atol (point->name) >= number)
228 0 : break;
229 : }
230 : else
231 : {
232 0 : aslist->type = ACCESS_TYPE_STRING;
233 :
234 : /* Set access_list to string list. */
235 0 : list = &as_list_master.str;
236 :
237 : /* Set point to insertion point. */
238 0 : for (point = list->head; point; point = point->next)
239 0 : if (strcmp (point->name, name) >= 0)
240 0 : break;
241 : }
242 :
243 : /* In case of this is the first element of master. */
244 0 : if (list->head == NULL)
245 : {
246 0 : list->head = list->tail = aslist;
247 0 : return aslist;
248 : }
249 :
250 : /* In case of insertion is made at the tail of access_list. */
251 0 : if (point == NULL)
252 : {
253 0 : aslist->prev = list->tail;
254 0 : list->tail->next = aslist;
255 0 : list->tail = aslist;
256 0 : return aslist;
257 : }
258 :
259 : /* In case of insertion is made at the head of access_list. */
260 0 : if (point == list->head)
261 : {
262 0 : aslist->next = list->head;
263 0 : list->head->prev = aslist;
264 0 : list->head = aslist;
265 0 : return aslist;
266 : }
267 :
268 : /* Insertion is made at middle of the access_list. */
269 0 : aslist->next = point;
270 0 : aslist->prev = point->prev;
271 :
272 0 : if (point->prev)
273 0 : point->prev->next = aslist;
274 0 : point->prev = aslist;
275 :
276 0 : return aslist;
277 : }
278 :
279 : static struct as_list *
280 0 : as_list_get (const char *name)
281 : {
282 : struct as_list *aslist;
283 :
284 0 : aslist = as_list_lookup (name);
285 0 : if (aslist == NULL)
286 : {
287 0 : aslist = as_list_insert (name);
288 :
289 : /* Run hook function. */
290 0 : if (as_list_master.add_hook)
291 0 : (*as_list_master.add_hook) ();
292 : }
293 :
294 0 : return aslist;
295 : }
296 :
297 : static const char *
298 0 : filter_type_str (enum as_filter_type type)
299 : {
300 0 : switch (type)
301 : {
302 : case AS_FILTER_PERMIT:
303 0 : return "permit";
304 : case AS_FILTER_DENY:
305 0 : return "deny";
306 : default:
307 0 : return "";
308 : }
309 : }
310 :
311 : static void
312 0 : as_list_delete (struct as_list *aslist)
313 : {
314 : struct as_list_list *list;
315 : struct as_filter *filter, *next;
316 :
317 0 : for (filter = aslist->head; filter; filter = next)
318 : {
319 0 : next = filter->next;
320 0 : as_filter_free (filter);
321 : }
322 :
323 0 : if (aslist->type == ACCESS_TYPE_NUMBER)
324 0 : list = &as_list_master.num;
325 : else
326 0 : list = &as_list_master.str;
327 :
328 0 : if (aslist->next)
329 0 : aslist->next->prev = aslist->prev;
330 : else
331 0 : list->tail = aslist->prev;
332 :
333 0 : if (aslist->prev)
334 0 : aslist->prev->next = aslist->next;
335 : else
336 0 : list->head = aslist->next;
337 :
338 0 : as_list_free (aslist);
339 0 : }
340 :
341 : static int
342 0 : as_list_empty (struct as_list *aslist)
343 : {
344 0 : if (aslist->head == NULL && aslist->tail == NULL)
345 0 : return 1;
346 : else
347 0 : return 0;
348 : }
349 :
350 : static void
351 0 : as_list_filter_delete (struct as_list *aslist, struct as_filter *asfilter)
352 : {
353 0 : if (asfilter->next)
354 0 : asfilter->next->prev = asfilter->prev;
355 : else
356 0 : aslist->tail = asfilter->prev;
357 :
358 0 : if (asfilter->prev)
359 0 : asfilter->prev->next = asfilter->next;
360 : else
361 0 : aslist->head = asfilter->next;
362 :
363 0 : as_filter_free (asfilter);
364 :
365 : /* If access_list becomes empty delete it from access_master. */
366 0 : if (as_list_empty (aslist))
367 0 : as_list_delete (aslist);
368 :
369 : /* Run hook function. */
370 0 : if (as_list_master.delete_hook)
371 0 : (*as_list_master.delete_hook) ();
372 0 : }
373 :
374 : static int
375 0 : as_filter_match (struct as_filter *asfilter, struct aspath *aspath)
376 : {
377 0 : if (bgp_regexec (asfilter->reg, aspath) != REG_NOMATCH)
378 0 : return 1;
379 0 : return 0;
380 : }
381 :
382 : /* Apply AS path filter to AS. */
383 : enum as_filter_type
384 0 : as_list_apply (struct as_list *aslist, void *object)
385 : {
386 : struct as_filter *asfilter;
387 : struct aspath *aspath;
388 :
389 0 : aspath = (struct aspath *) object;
390 :
391 0 : if (aslist == NULL)
392 0 : return AS_FILTER_DENY;
393 :
394 0 : for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
395 : {
396 0 : if (as_filter_match (asfilter, aspath))
397 0 : return asfilter->type;
398 : }
399 0 : return AS_FILTER_DENY;
400 : }
401 :
402 : /* Add hook function. */
403 : void
404 0 : as_list_add_hook (void (*func) (void))
405 : {
406 0 : as_list_master.add_hook = func;
407 0 : }
408 :
409 : /* Delete hook function. */
410 : void
411 0 : as_list_delete_hook (void (*func) (void))
412 : {
413 0 : as_list_master.delete_hook = func;
414 0 : }
415 :
416 : static int
417 0 : as_list_dup_check (struct as_list *aslist, struct as_filter *new)
418 : {
419 : struct as_filter *asfilter;
420 :
421 0 : for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
422 : {
423 0 : if (asfilter->type == new->type
424 0 : && strcmp (asfilter->reg_str, new->reg_str) == 0)
425 0 : return 1;
426 : }
427 0 : return 0;
428 : }
429 :
430 0 : DEFUN (ip_as_path, ip_as_path_cmd,
431 : "ip as-path access-list WORD (deny|permit) .LINE",
432 : IP_STR
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")
439 : {
440 : enum as_filter_type type;
441 : struct as_filter *asfilter;
442 : struct as_list *aslist;
443 : regex_t *regex;
444 : char *regstr;
445 :
446 : /* Check the filter type. */
447 0 : if (strncmp (argv[1], "p", 1) == 0)
448 0 : type = AS_FILTER_PERMIT;
449 0 : else if (strncmp (argv[1], "d", 1) == 0)
450 0 : type = AS_FILTER_DENY;
451 : else
452 : {
453 0 : vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE);
454 0 : return CMD_WARNING;
455 : }
456 :
457 : /* Check AS path regex. */
458 0 : regstr = argv_concat(argv, argc, 2);
459 :
460 0 : regex = bgp_regcomp (regstr);
461 0 : if (!regex)
462 : {
463 0 : XFREE (MTYPE_TMP, regstr);
464 0 : vty_out (vty, "can't compile regexp %s%s", argv[0],
465 0 : VTY_NEWLINE);
466 0 : return CMD_WARNING;
467 : }
468 :
469 0 : asfilter = as_filter_make (regex, regstr, type);
470 :
471 0 : XFREE (MTYPE_TMP, regstr);
472 :
473 : /* Install new filter to the access_list. */
474 0 : aslist = as_list_get (argv[0]);
475 :
476 : /* Duplicate insertion check. */;
477 0 : if (as_list_dup_check (aslist, asfilter))
478 0 : as_filter_free (asfilter);
479 : else
480 0 : as_list_filter_add (aslist, asfilter);
481 :
482 0 : return CMD_SUCCESS;
483 : }
484 :
485 0 : DEFUN (no_ip_as_path,
486 : no_ip_as_path_cmd,
487 : "no ip as-path access-list WORD (deny|permit) .LINE",
488 : NO_STR
489 : IP_STR
490 : "BGP autonomous system path filter\n"
491 : "Specify an access list name\n"
492 : "Regular expression access list name\n"
493 : "Specify packets to reject\n"
494 : "Specify packets to forward\n"
495 : "A regular-expression to match the BGP AS paths\n")
496 : {
497 : enum as_filter_type type;
498 : struct as_filter *asfilter;
499 : struct as_list *aslist;
500 : char *regstr;
501 : regex_t *regex;
502 :
503 : /* Lookup AS list from AS path list. */
504 0 : aslist = as_list_lookup (argv[0]);
505 0 : if (aslist == NULL)
506 : {
507 0 : vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0],
508 0 : VTY_NEWLINE);
509 0 : return CMD_WARNING;
510 : }
511 :
512 : /* Check the filter type. */
513 0 : if (strncmp (argv[1], "p", 1) == 0)
514 0 : type = AS_FILTER_PERMIT;
515 0 : else if (strncmp (argv[1], "d", 1) == 0)
516 0 : type = AS_FILTER_DENY;
517 : else
518 : {
519 0 : vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE);
520 0 : return CMD_WARNING;
521 : }
522 :
523 : /* Compile AS path. */
524 0 : regstr = argv_concat(argv, argc, 2);
525 :
526 0 : regex = bgp_regcomp (regstr);
527 0 : if (!regex)
528 : {
529 0 : XFREE (MTYPE_TMP, regstr);
530 0 : vty_out (vty, "can't compile regexp %s%s", argv[0],
531 0 : VTY_NEWLINE);
532 0 : return CMD_WARNING;
533 : }
534 :
535 : /* Lookup asfilter. */
536 0 : asfilter = as_filter_lookup (aslist, regstr, type);
537 :
538 0 : XFREE (MTYPE_TMP, regstr);
539 0 : bgp_regex_free (regex);
540 :
541 0 : if (asfilter == NULL)
542 : {
543 0 : vty_out (vty, "%s", VTY_NEWLINE);
544 0 : return CMD_WARNING;
545 : }
546 :
547 0 : as_list_filter_delete (aslist, asfilter);
548 :
549 0 : return CMD_SUCCESS;
550 : }
551 :
552 0 : DEFUN (no_ip_as_path_all,
553 : no_ip_as_path_all_cmd,
554 : "no ip as-path access-list WORD",
555 : NO_STR
556 : IP_STR
557 : "BGP autonomous system path filter\n"
558 : "Specify an access list name\n"
559 : "Regular expression access list name\n")
560 : {
561 : struct as_list *aslist;
562 :
563 0 : aslist = as_list_lookup (argv[0]);
564 0 : if (aslist == NULL)
565 : {
566 0 : vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0],
567 0 : VTY_NEWLINE);
568 0 : return CMD_WARNING;
569 : }
570 :
571 0 : as_list_delete (aslist);
572 :
573 : /* Run hook function. */
574 0 : if (as_list_master.delete_hook)
575 0 : (*as_list_master.delete_hook) ();
576 :
577 0 : return CMD_SUCCESS;
578 : }
579 :
580 : static void
581 0 : as_list_show (struct vty *vty, struct as_list *aslist)
582 : {
583 : struct as_filter *asfilter;
584 :
585 0 : vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE);
586 :
587 0 : for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
588 : {
589 0 : vty_out (vty, " %s %s%s", filter_type_str (asfilter->type),
590 0 : asfilter->reg_str, VTY_NEWLINE);
591 : }
592 0 : }
593 :
594 : static void
595 0 : as_list_show_all (struct vty *vty)
596 : {
597 : struct as_list *aslist;
598 : struct as_filter *asfilter;
599 :
600 0 : for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
601 : {
602 0 : vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE);
603 :
604 0 : for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
605 : {
606 0 : vty_out (vty, " %s %s%s", filter_type_str (asfilter->type),
607 0 : asfilter->reg_str, VTY_NEWLINE);
608 : }
609 : }
610 :
611 0 : for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
612 : {
613 0 : vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE);
614 :
615 0 : for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
616 : {
617 0 : vty_out (vty, " %s %s%s", filter_type_str (asfilter->type),
618 0 : asfilter->reg_str, VTY_NEWLINE);
619 : }
620 : }
621 0 : }
622 :
623 0 : DEFUN (show_ip_as_path_access_list,
624 : show_ip_as_path_access_list_cmd,
625 : "show ip as-path-access-list WORD",
626 : SHOW_STR
627 : IP_STR
628 : "List AS path access lists\n"
629 : "AS path access list name\n")
630 : {
631 : struct as_list *aslist;
632 :
633 0 : aslist = as_list_lookup (argv[0]);
634 0 : if (aslist)
635 0 : as_list_show (vty, aslist);
636 :
637 0 : return CMD_SUCCESS;
638 : }
639 :
640 0 : DEFUN (show_ip_as_path_access_list_all,
641 : show_ip_as_path_access_list_all_cmd,
642 : "show ip as-path-access-list",
643 : SHOW_STR
644 : IP_STR
645 : "List AS path access lists\n")
646 : {
647 0 : as_list_show_all (vty);
648 0 : return CMD_SUCCESS;
649 : }
650 :
651 : static int
652 0 : config_write_as_list (struct vty *vty)
653 : {
654 : struct as_list *aslist;
655 : struct as_filter *asfilter;
656 0 : int write = 0;
657 :
658 0 : for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
659 0 : for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
660 : {
661 0 : vty_out (vty, "ip as-path access-list %s %s %s%s",
662 : aslist->name, filter_type_str (asfilter->type),
663 : asfilter->reg_str,
664 0 : VTY_NEWLINE);
665 0 : write++;
666 : }
667 :
668 0 : for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
669 0 : for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
670 : {
671 0 : vty_out (vty, "ip as-path access-list %s %s %s%s",
672 : aslist->name, filter_type_str (asfilter->type),
673 : asfilter->reg_str,
674 0 : VTY_NEWLINE);
675 0 : write++;
676 : }
677 0 : return write;
678 : }
679 :
680 : static struct cmd_node as_list_node =
681 : {
682 : AS_LIST_NODE,
683 : "",
684 : 1
685 : };
686 :
687 : /* Register functions. */
688 : void
689 0 : bgp_filter_init (void)
690 : {
691 0 : install_node (&as_list_node, config_write_as_list);
692 :
693 0 : install_element (CONFIG_NODE, &ip_as_path_cmd);
694 0 : install_element (CONFIG_NODE, &no_ip_as_path_cmd);
695 0 : install_element (CONFIG_NODE, &no_ip_as_path_all_cmd);
696 :
697 0 : install_element (VIEW_NODE, &show_ip_as_path_access_list_cmd);
698 0 : install_element (VIEW_NODE, &show_ip_as_path_access_list_all_cmd);
699 0 : install_element (ENABLE_NODE, &show_ip_as_path_access_list_cmd);
700 0 : install_element (ENABLE_NODE, &show_ip_as_path_access_list_all_cmd);
701 0 : }
702 :
703 : void
704 0 : bgp_filter_reset (void)
705 : {
706 : struct as_list *aslist;
707 : struct as_list *next;
708 :
709 0 : for (aslist = as_list_master.num.head; aslist; aslist = next)
710 : {
711 0 : next = aslist->next;
712 0 : as_list_delete (aslist);
713 : }
714 :
715 0 : for (aslist = as_list_master.str.head; aslist; aslist = next)
716 : {
717 0 : next = aslist->next;
718 0 : as_list_delete (aslist);
719 : }
720 :
721 0 : assert (as_list_master.num.head == NULL);
722 0 : assert (as_list_master.num.tail == NULL);
723 :
724 0 : assert (as_list_master.str.head == NULL);
725 0 : assert (as_list_master.str.tail == NULL);
726 0 : }
|