]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_filter.c
*: make consistent & update GPLv2 file headers
[mirror_frr.git] / bgpd / bgp_filter.c
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 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
19 */
20
21 #include <zebra.h>
22
23 #include "command.h"
24 #include "log.h"
25 #include "memory.h"
26 #include "buffer.h"
27 #include "queue.h"
28 #include "filter.h"
29
30 #include "bgpd/bgpd.h"
31 #include "bgpd/bgp_aspath.h"
32 #include "bgpd/bgp_regex.h"
33 #include "bgpd/bgp_filter.h"
34
35 /* List of AS filter list. */
36 struct as_list_list
37 {
38 struct as_list *head;
39 struct as_list *tail;
40 };
41
42 /* AS path filter master. */
43 struct as_list_master
44 {
45 /* List of access_list which name is number. */
46 struct as_list_list num;
47
48 /* List of access_list which name is string. */
49 struct as_list_list str;
50
51 /* Hook function which is executed when new access_list is added. */
52 void (*add_hook) (char *);
53
54 /* Hook function which is executed when access_list is deleted. */
55 void (*delete_hook) (const char *);
56 };
57
58 /* Element of AS path filter. */
59 struct as_filter
60 {
61 struct as_filter *next;
62 struct as_filter *prev;
63
64 enum as_filter_type type;
65
66 regex_t *reg;
67 char *reg_str;
68 };
69
70 /* AS path filter list. */
71 struct as_list
72 {
73 char *name;
74
75 enum access_type type;
76
77 struct as_list *next;
78 struct as_list *prev;
79
80 struct as_filter *head;
81 struct as_filter *tail;
82 };
83
84 /* ip as-path access-list 10 permit AS1. */
85
86 static struct as_list_master as_list_master =
87 {
88 {NULL, NULL},
89 {NULL, NULL},
90 NULL,
91 NULL
92 };
93
94 /* Allocate new AS filter. */
95 static struct as_filter *
96 as_filter_new (void)
97 {
98 return XCALLOC (MTYPE_AS_FILTER, sizeof (struct as_filter));
99 }
100
101 /* Free allocated AS filter. */
102 static void
103 as_filter_free (struct as_filter *asfilter)
104 {
105 if (asfilter->reg)
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);
110 }
111
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)
115 {
116 struct as_filter *asfilter;
117
118 asfilter = as_filter_new ();
119 asfilter->reg = reg;
120 asfilter->type = type;
121 asfilter->reg_str = XSTRDUP (MTYPE_AS_FILTER_STR, reg_str);
122
123 return asfilter;
124 }
125
126 static struct as_filter *
127 as_filter_lookup (struct as_list *aslist, const char *reg_str,
128 enum as_filter_type type)
129 {
130 struct as_filter *asfilter;
131
132 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
133 if (strcmp (reg_str, asfilter->reg_str) == 0)
134 return asfilter;
135 return NULL;
136 }
137
138 static void
139 as_list_filter_add (struct as_list *aslist, struct as_filter *asfilter)
140 {
141 asfilter->next = NULL;
142 asfilter->prev = aslist->tail;
143
144 if (aslist->tail)
145 aslist->tail->next = asfilter;
146 else
147 aslist->head = asfilter;
148 aslist->tail = asfilter;
149
150 /* Run hook function. */
151 if (as_list_master.add_hook)
152 (*as_list_master.add_hook) (aslist->name);
153
154 }
155
156 /* Lookup as_list from list of as_list by name. */
157 struct as_list *
158 as_list_lookup (const char *name)
159 {
160 struct as_list *aslist;
161
162 if (name == NULL)
163 return NULL;
164
165 for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
166 if (strcmp (aslist->name, name) == 0)
167 return aslist;
168
169 for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
170 if (strcmp (aslist->name, name) == 0)
171 return aslist;
172
173 return NULL;
174 }
175
176 static struct as_list *
177 as_list_new (void)
178 {
179 return XCALLOC (MTYPE_AS_LIST, sizeof (struct as_list));
180 }
181
182 static void
183 as_list_free (struct as_list *aslist)
184 {
185 if (aslist->name)
186 {
187 XFREE(MTYPE_AS_STR, aslist->name);
188 aslist->name = NULL;
189 }
190 XFREE (MTYPE_AS_LIST, aslist);
191 }
192
193 /* Insert new AS list to list of as_list. Each as_list is sorted by
194 the name. */
195 static struct as_list *
196 as_list_insert (const char *name)
197 {
198 size_t i;
199 long number;
200 struct as_list *aslist;
201 struct as_list *point;
202 struct as_list_list *list;
203
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);
208
209 /* If name is made by all digit character. We treat it as
210 number. */
211 for (number = 0, i = 0; i < strlen (name); i++)
212 {
213 if (isdigit ((int) name[i]))
214 number = (number * 10) + (name[i] - '0');
215 else
216 break;
217 }
218
219 /* In case of name is all digit character */
220 if (i == strlen (name))
221 {
222 aslist->type = ACCESS_TYPE_NUMBER;
223
224 /* Set access_list to number list. */
225 list = &as_list_master.num;
226
227 for (point = list->head; point; point = point->next)
228 if (atol (point->name) >= number)
229 break;
230 }
231 else
232 {
233 aslist->type = ACCESS_TYPE_STRING;
234
235 /* Set access_list to string list. */
236 list = &as_list_master.str;
237
238 /* Set point to insertion point. */
239 for (point = list->head; point; point = point->next)
240 if (strcmp (point->name, name) >= 0)
241 break;
242 }
243
244 /* In case of this is the first element of master. */
245 if (list->head == NULL)
246 {
247 list->head = list->tail = aslist;
248 return aslist;
249 }
250
251 /* In case of insertion is made at the tail of access_list. */
252 if (point == NULL)
253 {
254 aslist->prev = list->tail;
255 list->tail->next = aslist;
256 list->tail = aslist;
257 return aslist;
258 }
259
260 /* In case of insertion is made at the head of access_list. */
261 if (point == list->head)
262 {
263 aslist->next = list->head;
264 list->head->prev = aslist;
265 list->head = aslist;
266 return aslist;
267 }
268
269 /* Insertion is made at middle of the access_list. */
270 aslist->next = point;
271 aslist->prev = point->prev;
272
273 if (point->prev)
274 point->prev->next = aslist;
275 point->prev = aslist;
276
277 return aslist;
278 }
279
280 static struct as_list *
281 as_list_get (const char *name)
282 {
283 struct as_list *aslist;
284
285 aslist = as_list_lookup (name);
286 if (aslist == NULL)
287 aslist = as_list_insert (name);
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 char *name = XSTRDUP(MTYPE_AS_STR, aslist->name);
349
350 if (asfilter->next)
351 asfilter->next->prev = asfilter->prev;
352 else
353 aslist->tail = asfilter->prev;
354
355 if (asfilter->prev)
356 asfilter->prev->next = asfilter->next;
357 else
358 aslist->head = asfilter->next;
359
360 as_filter_free (asfilter);
361
362 /* If access_list becomes empty delete it from access_master. */
363 if (as_list_empty (aslist))
364 as_list_delete (aslist);
365
366 /* Run hook function. */
367 if (as_list_master.delete_hook)
368 (*as_list_master.delete_hook) (name);
369 if (name)
370 XFREE(MTYPE_AS_STR, name);
371 }
372
373 static int
374 as_filter_match (struct as_filter *asfilter, struct aspath *aspath)
375 {
376 if (bgp_regexec (asfilter->reg, aspath) != REG_NOMATCH)
377 return 1;
378 return 0;
379 }
380
381 /* Apply AS path filter to AS. */
382 enum as_filter_type
383 as_list_apply (struct as_list *aslist, void *object)
384 {
385 struct as_filter *asfilter;
386 struct aspath *aspath;
387
388 aspath = (struct aspath *) object;
389
390 if (aslist == NULL)
391 return AS_FILTER_DENY;
392
393 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
394 {
395 if (as_filter_match (asfilter, aspath))
396 return asfilter->type;
397 }
398 return AS_FILTER_DENY;
399 }
400
401 /* Add hook function. */
402 void
403 as_list_add_hook (void (*func) (char *))
404 {
405 as_list_master.add_hook = func;
406 }
407
408 /* Delete hook function. */
409 void
410 as_list_delete_hook (void (*func) (const char *))
411 {
412 as_list_master.delete_hook = func;
413 }
414
415 static int
416 as_list_dup_check (struct as_list *aslist, struct as_filter *new)
417 {
418 struct as_filter *asfilter;
419
420 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
421 {
422 if (asfilter->type == new->type
423 && strcmp (asfilter->reg_str, new->reg_str) == 0)
424 return 1;
425 }
426 return 0;
427 }
428
429 DEFUN (ip_as_path,
430 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 int idx = 0;
441 enum as_filter_type type;
442 struct as_filter *asfilter;
443 struct as_list *aslist;
444 regex_t *regex;
445 char *regstr;
446
447 /* Retrieve access list name */
448 char *alname = argv_find (argv, argc, "WORD", &idx) ? argv[idx]->arg : NULL;
449
450 /* Check the filter type. */
451 type = argv_find (argv, argc, "deny", &idx) ? AS_FILTER_DENY : AS_FILTER_PERMIT;
452
453 /* Check AS path regex. */
454 argv_find (argv, argc, "LINE", &idx);
455 regstr = argv_concat(argv, argc, idx);
456
457 regex = bgp_regcomp (regstr);
458 if (!regex)
459 {
460 vty_out (vty, "can't compile regexp %s%s", regstr, VTY_NEWLINE);
461 XFREE (MTYPE_TMP, regstr);
462 return CMD_WARNING;
463 }
464
465 asfilter = as_filter_make (regex, regstr, type);
466
467 XFREE (MTYPE_TMP, regstr);
468
469 /* Install new filter to the access_list. */
470 aslist = as_list_get (alname);
471
472 /* Duplicate insertion check. */;
473 if (as_list_dup_check (aslist, asfilter))
474 as_filter_free (asfilter);
475 else
476 as_list_filter_add (aslist, asfilter);
477
478 return CMD_SUCCESS;
479 }
480
481 DEFUN (no_ip_as_path,
482 no_ip_as_path_cmd,
483 "no ip as-path access-list WORD <deny|permit> LINE...",
484 NO_STR
485 IP_STR
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")
492 {
493 int idx = 0;
494 enum as_filter_type type;
495 struct as_filter *asfilter;
496 struct as_list *aslist;
497 char *regstr;
498 regex_t *regex;
499
500 char *aslistname = argv_find (argv, argc, "WORD", &idx) ? argv[idx]->arg : NULL;
501
502 /* Lookup AS list from AS path list. */
503 aslist = as_list_lookup (aslistname);
504 if (aslist == NULL)
505 {
506 vty_out (vty, "ip as-path access-list %s doesn't exist%s", aslistname,
507 VTY_NEWLINE);
508 return CMD_WARNING;
509 }
510
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;
516 else
517 {
518 vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE);
519 return CMD_WARNING;
520 }
521
522 /* Compile AS path. */
523 argv_find (argv, argc, "LINE", &idx);
524 regstr = argv_concat(argv, argc, idx);
525
526 regex = bgp_regcomp (regstr);
527 if (!regex)
528 {
529 vty_out (vty, "can't compile regexp %s%s", regstr, VTY_NEWLINE);
530 XFREE (MTYPE_TMP, regstr);
531 return CMD_WARNING;
532 }
533
534 /* Lookup asfilter. */
535 asfilter = as_filter_lookup (aslist, regstr, type);
536
537 XFREE (MTYPE_TMP, regstr);
538 bgp_regex_free (regex);
539
540 if (asfilter == NULL)
541 {
542 vty_out (vty, "%s", VTY_NEWLINE);
543 return CMD_WARNING;
544 }
545
546 as_list_filter_delete (aslist, asfilter);
547
548 return CMD_SUCCESS;
549 }
550
551 DEFUN (no_ip_as_path_all,
552 no_ip_as_path_all_cmd,
553 "no ip as-path access-list WORD",
554 NO_STR
555 IP_STR
556 "BGP autonomous system path filter\n"
557 "Specify an access list name\n"
558 "Regular expression access list name\n")
559 {
560 int idx_word = 4;
561 struct as_list *aslist;
562
563 aslist = as_list_lookup (argv[idx_word]->arg);
564 if (aslist == NULL)
565 {
566 vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[idx_word]->arg,
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) (argv[idx_word]->arg);
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 int idx_word = 3;
632 struct as_list *aslist;
633
634 aslist = as_list_lookup (argv[idx_word]->arg);
635 if (aslist)
636 as_list_show (vty, aslist);
637
638 return CMD_SUCCESS;
639 }
640
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",
644 SHOW_STR
645 IP_STR
646 "List AS path access lists\n")
647 {
648 as_list_show_all (vty);
649 return CMD_SUCCESS;
650 }
651
652 static int
653 config_write_as_list (struct vty *vty)
654 {
655 struct as_list *aslist;
656 struct as_filter *asfilter;
657 int write = 0;
658
659 for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
660 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
661 {
662 vty_out (vty, "ip as-path access-list %s %s %s%s",
663 aslist->name, filter_type_str (asfilter->type),
664 asfilter->reg_str,
665 VTY_NEWLINE);
666 write++;
667 }
668
669 for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
670 for (asfilter = aslist->head; asfilter; asfilter = asfilter->next)
671 {
672 vty_out (vty, "ip as-path access-list %s %s %s%s",
673 aslist->name, filter_type_str (asfilter->type),
674 asfilter->reg_str,
675 VTY_NEWLINE);
676 write++;
677 }
678 return write;
679 }
680
681 static struct cmd_node as_list_node =
682 {
683 AS_LIST_NODE,
684 "",
685 1
686 };
687
688 /* Register functions. */
689 void
690 bgp_filter_init (void)
691 {
692 install_node (&as_list_node, config_write_as_list);
693
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);
697
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);
700 }
701
702 void
703 bgp_filter_reset (void)
704 {
705 struct as_list *aslist;
706 struct as_list *next;
707
708 for (aslist = as_list_master.num.head; aslist; aslist = next)
709 {
710 next = aslist->next;
711 as_list_delete (aslist);
712 }
713
714 for (aslist = as_list_master.str.head; aslist; aslist = next)
715 {
716 next = aslist->next;
717 as_list_delete (aslist);
718 }
719
720 assert (as_list_master.num.head == NULL);
721 assert (as_list_master.num.tail == NULL);
722
723 assert (as_list_master.str.head == NULL);
724 assert (as_list_master.str.tail == NULL);
725 }