Annotation of embedaddon/quagga/bgpd/bgp_filter.c, revision 1.1.1.1
1.1 misho 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: as_filter_new (void)
101: {
102: return XCALLOC (MTYPE_AS_FILTER, sizeof (struct as_filter));
103: }
104:
105: /* Free allocated AS filter. */
106: static void
107: as_filter_free (struct as_filter *asfilter)
108: {
109: if (asfilter->reg)
110: bgp_regex_free (asfilter->reg);
111: if (asfilter->reg_str)
112: XFREE (MTYPE_AS_FILTER_STR, asfilter->reg_str);
113: XFREE (MTYPE_AS_FILTER, asfilter);
114: }
115:
116: /* Make new AS filter. */
117: static struct as_filter *
118: as_filter_make (regex_t *reg, const char *reg_str, enum as_filter_type type)
119: {
120: struct as_filter *asfilter;
121:
122: asfilter = as_filter_new ();
123: asfilter->reg = reg;
124: asfilter->type = type;
125: asfilter->reg_str = XSTRDUP (MTYPE_AS_FILTER_STR, reg_str);
126:
127: return asfilter;
128: }
129:
130: static struct as_filter *
131: 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: for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
137: if (strcmp (reg_str, asfilter->reg_str) == 0)
138: return asfilter;
139: return NULL;
140: }
141:
142: static void
143: as_list_filter_add (struct as_list *aslist, struct as_filter *asfilter)
144: {
145: asfilter->next = NULL;
146: asfilter->prev = aslist->tail;
147:
148: if (aslist->tail)
149: aslist->tail->next = asfilter;
150: else
151: aslist->head = asfilter;
152: aslist->tail = asfilter;
153: }
154:
155: /* Lookup as_list from list of as_list by name. */
156: struct as_list *
157: as_list_lookup (const char *name)
158: {
159: struct as_list *aslist;
160:
161: if (name == NULL)
162: return NULL;
163:
164: for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
165: if (strcmp (aslist->name, name) == 0)
166: return aslist;
167:
168: for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
169: if (strcmp (aslist->name, name) == 0)
170: return aslist;
171:
172: return NULL;
173: }
174:
175: static struct as_list *
176: as_list_new (void)
177: {
178: return XCALLOC (MTYPE_AS_LIST, sizeof (struct as_list));
179: }
180:
181: static void
182: as_list_free (struct as_list *aslist)
183: {
184: if (aslist->name)
185: {
186: free (aslist->name);
187: aslist->name = NULL;
188: }
189: XFREE (MTYPE_AS_LIST, aslist);
190: }
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: 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: aslist = as_list_new ();
205: aslist->name = strdup (name);
206: assert (aslist->name);
207:
208: /* If name is made by all digit character. We treat it as
209: number. */
210: for (number = 0, i = 0; i < strlen (name); i++)
211: {
212: if (isdigit ((int) name[i]))
213: number = (number * 10) + (name[i] - '0');
214: else
215: break;
216: }
217:
218: /* In case of name is all digit character */
219: if (i == strlen (name))
220: {
221: aslist->type = ACCESS_TYPE_NUMBER;
222:
223: /* Set access_list to number list. */
224: list = &as_list_master.num;
225:
226: for (point = list->head; point; point = point->next)
227: if (atol (point->name) >= number)
228: break;
229: }
230: else
231: {
232: aslist->type = ACCESS_TYPE_STRING;
233:
234: /* Set access_list to string list. */
235: list = &as_list_master.str;
236:
237: /* Set point to insertion point. */
238: for (point = list->head; point; point = point->next)
239: if (strcmp (point->name, name) >= 0)
240: break;
241: }
242:
243: /* In case of this is the first element of master. */
244: if (list->head == NULL)
245: {
246: list->head = list->tail = aslist;
247: return aslist;
248: }
249:
250: /* In case of insertion is made at the tail of access_list. */
251: if (point == NULL)
252: {
253: aslist->prev = list->tail;
254: list->tail->next = aslist;
255: list->tail = aslist;
256: return aslist;
257: }
258:
259: /* In case of insertion is made at the head of access_list. */
260: if (point == list->head)
261: {
262: aslist->next = list->head;
263: list->head->prev = aslist;
264: list->head = aslist;
265: return aslist;
266: }
267:
268: /* Insertion is made at middle of the access_list. */
269: aslist->next = point;
270: aslist->prev = point->prev;
271:
272: if (point->prev)
273: point->prev->next = aslist;
274: point->prev = aslist;
275:
276: return aslist;
277: }
278:
279: static struct as_list *
280: as_list_get (const char *name)
281: {
282: struct as_list *aslist;
283:
284: aslist = as_list_lookup (name);
285: if (aslist == NULL)
286: {
287: aslist = as_list_insert (name);
288:
289: /* Run hook function. */
290: if (as_list_master.add_hook)
291: (*as_list_master.add_hook) ();
292: }
293:
294: return aslist;
295: }
296:
297: static const char *
298: filter_type_str (enum as_filter_type type)
299: {
300: switch (type)
301: {
302: case AS_FILTER_PERMIT:
303: return "permit";
304: case AS_FILTER_DENY:
305: return "deny";
306: default:
307: return "";
308: }
309: }
310:
311: static void
312: as_list_delete (struct as_list *aslist)
313: {
314: struct as_list_list *list;
315: struct as_filter *filter, *next;
316:
317: for (filter = aslist->head; filter; filter = next)
318: {
319: next = filter->next;
320: as_filter_free (filter);
321: }
322:
323: if (aslist->type == ACCESS_TYPE_NUMBER)
324: list = &as_list_master.num;
325: else
326: list = &as_list_master.str;
327:
328: if (aslist->next)
329: aslist->next->prev = aslist->prev;
330: else
331: list->tail = aslist->prev;
332:
333: if (aslist->prev)
334: aslist->prev->next = aslist->next;
335: else
336: list->head = aslist->next;
337:
338: as_list_free (aslist);
339: }
340:
341: static int
342: as_list_empty (struct as_list *aslist)
343: {
344: if (aslist->head == NULL && aslist->tail == NULL)
345: return 1;
346: else
347: return 0;
348: }
349:
350: static void
351: as_list_filter_delete (struct as_list *aslist, struct as_filter *asfilter)
352: {
353: if (asfilter->next)
354: asfilter->next->prev = asfilter->prev;
355: else
356: aslist->tail = asfilter->prev;
357:
358: if (asfilter->prev)
359: asfilter->prev->next = asfilter->next;
360: else
361: aslist->head = asfilter->next;
362:
363: as_filter_free (asfilter);
364:
365: /* If access_list becomes empty delete it from access_master. */
366: if (as_list_empty (aslist))
367: as_list_delete (aslist);
368:
369: /* Run hook function. */
370: if (as_list_master.delete_hook)
371: (*as_list_master.delete_hook) ();
372: }
373:
374: static int
375: as_filter_match (struct as_filter *asfilter, struct aspath *aspath)
376: {
377: if (bgp_regexec (asfilter->reg, aspath) != REG_NOMATCH)
378: return 1;
379: return 0;
380: }
381:
382: /* Apply AS path filter to AS. */
383: enum as_filter_type
384: as_list_apply (struct as_list *aslist, void *object)
385: {
386: struct as_filter *asfilter;
387: struct aspath *aspath;
388:
389: aspath = (struct aspath *) object;
390:
391: if (aslist == NULL)
392: return AS_FILTER_DENY;
393:
394: for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
395: {
396: if (as_filter_match (asfilter, aspath))
397: return asfilter->type;
398: }
399: return AS_FILTER_DENY;
400: }
401:
402: /* Add hook function. */
403: void
404: as_list_add_hook (void (*func) (void))
405: {
406: as_list_master.add_hook = func;
407: }
408:
409: /* Delete hook function. */
410: void
411: as_list_delete_hook (void (*func) (void))
412: {
413: as_list_master.delete_hook = func;
414: }
415:
416: static int
417: as_list_dup_check (struct as_list *aslist, struct as_filter *new)
418: {
419: struct as_filter *asfilter;
420:
421: for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
422: {
423: if (asfilter->type == new->type
424: && strcmp (asfilter->reg_str, new->reg_str) == 0)
425: return 1;
426: }
427: return 0;
428: }
429:
430: 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: if (strncmp (argv[1], "p", 1) == 0)
448: type = AS_FILTER_PERMIT;
449: else if (strncmp (argv[1], "d", 1) == 0)
450: type = AS_FILTER_DENY;
451: else
452: {
453: vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE);
454: return CMD_WARNING;
455: }
456:
457: /* Check AS path regex. */
458: regstr = argv_concat(argv, argc, 2);
459:
460: regex = bgp_regcomp (regstr);
461: if (!regex)
462: {
463: XFREE (MTYPE_TMP, regstr);
464: vty_out (vty, "can't compile regexp %s%s", argv[0],
465: VTY_NEWLINE);
466: return CMD_WARNING;
467: }
468:
469: asfilter = as_filter_make (regex, regstr, type);
470:
471: XFREE (MTYPE_TMP, regstr);
472:
473: /* Install new filter to the access_list. */
474: aslist = as_list_get (argv[0]);
475:
476: /* Duplicate insertion check. */;
477: if (as_list_dup_check (aslist, asfilter))
478: as_filter_free (asfilter);
479: else
480: as_list_filter_add (aslist, asfilter);
481:
482: return CMD_SUCCESS;
483: }
484:
485: 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: aslist = as_list_lookup (argv[0]);
505: if (aslist == NULL)
506: {
507: vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0],
508: VTY_NEWLINE);
509: return CMD_WARNING;
510: }
511:
512: /* Check the filter type. */
513: if (strncmp (argv[1], "p", 1) == 0)
514: type = AS_FILTER_PERMIT;
515: else if (strncmp (argv[1], "d", 1) == 0)
516: type = AS_FILTER_DENY;
517: else
518: {
519: vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE);
520: return CMD_WARNING;
521: }
522:
523: /* Compile AS path. */
524: regstr = argv_concat(argv, argc, 2);
525:
526: regex = bgp_regcomp (regstr);
527: if (!regex)
528: {
529: XFREE (MTYPE_TMP, regstr);
530: vty_out (vty, "can't compile regexp %s%s", argv[0],
531: VTY_NEWLINE);
532: return CMD_WARNING;
533: }
534:
535: /* Lookup asfilter. */
536: asfilter = as_filter_lookup (aslist, regstr, type);
537:
538: XFREE (MTYPE_TMP, regstr);
539: bgp_regex_free (regex);
540:
541: if (asfilter == NULL)
542: {
543: vty_out (vty, "%s", VTY_NEWLINE);
544: return CMD_WARNING;
545: }
546:
547: as_list_filter_delete (aslist, asfilter);
548:
549: return CMD_SUCCESS;
550: }
551:
552: 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: aslist = as_list_lookup (argv[0]);
564: if (aslist == NULL)
565: {
566: vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0],
567: VTY_NEWLINE);
568: return CMD_WARNING;
569: }
570:
571: as_list_delete (aslist);
572:
573: /* Run hook function. */
574: if (as_list_master.delete_hook)
575: (*as_list_master.delete_hook) ();
576:
577: return CMD_SUCCESS;
578: }
579:
580: static void
581: as_list_show (struct vty *vty, struct as_list *aslist)
582: {
583: struct as_filter *asfilter;
584:
585: vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE);
586:
587: for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
588: {
589: vty_out (vty, " %s %s%s", filter_type_str (asfilter->type),
590: asfilter->reg_str, VTY_NEWLINE);
591: }
592: }
593:
594: static void
595: as_list_show_all (struct vty *vty)
596: {
597: struct as_list *aslist;
598: struct as_filter *asfilter;
599:
600: for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
601: {
602: vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE);
603:
604: for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
605: {
606: vty_out (vty, " %s %s%s", filter_type_str (asfilter->type),
607: asfilter->reg_str, VTY_NEWLINE);
608: }
609: }
610:
611: for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
612: {
613: vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE);
614:
615: for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
616: {
617: vty_out (vty, " %s %s%s", filter_type_str (asfilter->type),
618: asfilter->reg_str, VTY_NEWLINE);
619: }
620: }
621: }
622:
623: 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: aslist = as_list_lookup (argv[0]);
634: if (aslist)
635: as_list_show (vty, aslist);
636:
637: return CMD_SUCCESS;
638: }
639:
640: 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: as_list_show_all (vty);
648: return CMD_SUCCESS;
649: }
650:
651: static int
652: config_write_as_list (struct vty *vty)
653: {
654: struct as_list *aslist;
655: struct as_filter *asfilter;
656: int write = 0;
657:
658: for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
659: for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
660: {
661: 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: VTY_NEWLINE);
665: write++;
666: }
667:
668: for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
669: for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
670: {
671: 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: VTY_NEWLINE);
675: write++;
676: }
677: 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: bgp_filter_init (void)
690: {
691: install_node (&as_list_node, config_write_as_list);
692:
693: install_element (CONFIG_NODE, &ip_as_path_cmd);
694: install_element (CONFIG_NODE, &no_ip_as_path_cmd);
695: install_element (CONFIG_NODE, &no_ip_as_path_all_cmd);
696:
697: install_element (VIEW_NODE, &show_ip_as_path_access_list_cmd);
698: install_element (VIEW_NODE, &show_ip_as_path_access_list_all_cmd);
699: install_element (ENABLE_NODE, &show_ip_as_path_access_list_cmd);
700: install_element (ENABLE_NODE, &show_ip_as_path_access_list_all_cmd);
701: }
702:
703: void
704: bgp_filter_reset (void)
705: {
706: struct as_list *aslist;
707: struct as_list *next;
708:
709: for (aslist = as_list_master.num.head; aslist; aslist = next)
710: {
711: next = aslist->next;
712: as_list_delete (aslist);
713: }
714:
715: for (aslist = as_list_master.str.head; aslist; aslist = next)
716: {
717: next = aslist->next;
718: as_list_delete (aslist);
719: }
720:
721: assert (as_list_master.num.head == NULL);
722: assert (as_list_master.num.tail == NULL);
723:
724: assert (as_list_master.str.head == NULL);
725: assert (as_list_master.str.tail == NULL);
726: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>