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