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