]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_filter.c
*: make consistent & update GPLv2 file headers
[mirror_frr.git] / bgpd / bgp_filter.c
CommitLineData
718e3744 1/* AS path filter list.
896014f4
DL
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 */
718e3744 20
21#include <zebra.h>
22
23#include "command.h"
24#include "log.h"
25#include "memory.h"
26#include "buffer.h"
3f9c7369 27#include "queue.h"
039f3a34 28#include "filter.h"
718e3744 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. */
36struct as_list_list
37{
38 struct as_list *head;
39 struct as_list *tail;
40};
41
42/* AS path filter master. */
43struct 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. */
518f0eb1 52 void (*add_hook) (char *);
718e3744 53
54 /* Hook function which is executed when access_list is deleted. */
ffd0c037 55 void (*delete_hook) (const char *);
718e3744 56};
57
58/* Element of AS path filter. */
59struct 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
718e3744 70/* AS path filter list. */
71struct as_list
72{
73 char *name;
74
039f3a34 75 enum access_type type;
718e3744 76
77 struct as_list *next;
78 struct as_list *prev;
79
80 struct as_filter *head;
81 struct as_filter *tail;
82};
6b0655a2 83
718e3744 84/* ip as-path access-list 10 permit AS1. */
85
86static 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. */
94f2b392 95static struct as_filter *
66e5cd87 96as_filter_new (void)
718e3744 97{
393deb9b 98 return XCALLOC (MTYPE_AS_FILTER, sizeof (struct as_filter));
718e3744 99}
100
101/* Free allocated AS filter. */
94f2b392 102static void
718e3744 103as_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. */
94f2b392 113static struct as_filter *
fd79ac91 114as_filter_make (regex_t *reg, const char *reg_str, enum as_filter_type type)
718e3744 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
94f2b392 126static struct as_filter *
fd79ac91 127as_filter_lookup (struct as_list *aslist, const char *reg_str,
718e3744 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
94f2b392 138static void
718e3744 139as_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;
518f0eb1
DS
149
150 /* Run hook function. */
151 if (as_list_master.add_hook)
152 (*as_list_master.add_hook) (aslist->name);
153
718e3744 154}
155
156/* Lookup as_list from list of as_list by name. */
157struct as_list *
fd79ac91 158as_list_lookup (const char *name)
718e3744 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
94f2b392 176static struct as_list *
66e5cd87 177as_list_new (void)
718e3744 178{
393deb9b 179 return XCALLOC (MTYPE_AS_LIST, sizeof (struct as_list));
718e3744 180}
181
94f2b392 182static void
718e3744 183as_list_free (struct as_list *aslist)
184{
228da428
CC
185 if (aslist->name)
186 {
6e919709 187 XFREE(MTYPE_AS_STR, aslist->name);
228da428
CC
188 aslist->name = NULL;
189 }
718e3744 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. */
94f2b392 195static struct as_list *
fd79ac91 196as_list_insert (const char *name)
718e3744 197{
fd79ac91 198 size_t i;
718e3744 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 ();
6e919709 206 aslist->name = XSTRDUP(MTYPE_AS_STR, name);
228da428 207 assert (aslist->name);
718e3744 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
94f2b392 280static struct as_list *
fd79ac91 281as_list_get (const char *name)
718e3744 282{
283 struct as_list *aslist;
284
285 aslist = as_list_lookup (name);
286 if (aslist == NULL)
518f0eb1 287 aslist = as_list_insert (name);
718e3744 288
289 return aslist;
290}
291
fd79ac91 292static const char *
718e3744 293filter_type_str (enum as_filter_type type)
294{
295 switch (type)
296 {
297 case AS_FILTER_PERMIT:
298 return "permit";
718e3744 299 case AS_FILTER_DENY:
300 return "deny";
718e3744 301 default:
302 return "";
718e3744 303 }
304}
305
94f2b392 306static void
718e3744 307as_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
336static int
337as_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
94f2b392 345static void
718e3744 346as_list_filter_delete (struct as_list *aslist, struct as_filter *asfilter)
347{
6e919709 348 char *name = XSTRDUP(MTYPE_AS_STR, aslist->name);
518f0eb1 349
718e3744 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)
518f0eb1
DS
368 (*as_list_master.delete_hook) (name);
369 if (name)
6e919709 370 XFREE(MTYPE_AS_STR, name);
718e3744 371}
6b0655a2 372
718e3744 373static int
374as_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. */
382enum as_filter_type
383as_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. */
402void
518f0eb1 403as_list_add_hook (void (*func) (char *))
718e3744 404{
405 as_list_master.add_hook = func;
406}
407
408/* Delete hook function. */
409void
ffd0c037 410as_list_delete_hook (void (*func) (const char *))
718e3744 411{
412 as_list_master.delete_hook = func;
413}
6b0655a2 414
94f2b392 415static int
718e3744 416as_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
4dcadbef
DW
429DEFUN (ip_as_path,
430 ip_as_path_cmd,
e961923c 431 "ip as-path access-list WORD <deny|permit> LINE...",
718e3744 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{
332bafd8 440 int idx = 0;
718e3744 441 enum as_filter_type type;
442 struct as_filter *asfilter;
443 struct as_list *aslist;
444 regex_t *regex;
718e3744 445 char *regstr;
718e3744 446
332bafd8
QY
447 /* Retrieve access list name */
448 char *alname = argv_find (argv, argc, "WORD", &idx) ? argv[idx]->arg : NULL;
449
718e3744 450 /* Check the filter type. */
332bafd8 451 type = argv_find (argv, argc, "deny", &idx) ? AS_FILTER_DENY : AS_FILTER_PERMIT;
718e3744 452
453 /* Check AS path regex. */
332bafd8
QY
454 argv_find (argv, argc, "LINE", &idx);
455 regstr = argv_concat(argv, argc, idx);
718e3744 456
457 regex = bgp_regcomp (regstr);
458 if (!regex)
459 {
332bafd8 460 vty_out (vty, "can't compile regexp %s%s", regstr, VTY_NEWLINE);
46c699ab 461 XFREE (MTYPE_TMP, regstr);
718e3744 462 return CMD_WARNING;
463 }
464
465 asfilter = as_filter_make (regex, regstr, type);
466
3b8b1855 467 XFREE (MTYPE_TMP, regstr);
718e3744 468
469 /* Install new filter to the access_list. */
332bafd8 470 aslist = as_list_get (alname);
718e3744 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
481DEFUN (no_ip_as_path,
482 no_ip_as_path_cmd,
e961923c 483 "no ip as-path access-list WORD <deny|permit> LINE...",
718e3744 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{
46c699ab 493 int idx = 0;
718e3744 494 enum as_filter_type type;
495 struct as_filter *asfilter;
496 struct as_list *aslist;
718e3744 497 char *regstr;
498 regex_t *regex;
499
46c699ab
QY
500 char *aslistname = argv_find (argv, argc, "WORD", &idx) ? argv[idx]->arg : NULL;
501
718e3744 502 /* Lookup AS list from AS path list. */
46c699ab 503 aslist = as_list_lookup (aslistname);
718e3744 504 if (aslist == NULL)
505 {
46c699ab 506 vty_out (vty, "ip as-path access-list %s doesn't exist%s", aslistname,
718e3744 507 VTY_NEWLINE);
508 return CMD_WARNING;
509 }
510
511 /* Check the filter type. */
46c699ab 512 if (argv_find (argv, argc, "permit", &idx))
718e3744 513 type = AS_FILTER_PERMIT;
46c699ab 514 else if (argv_find (argv, argc, "deny", &idx))
718e3744 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. */
46c699ab
QY
523 argv_find (argv, argc, "LINE", &idx);
524 regstr = argv_concat(argv, argc, idx);
718e3744 525
526 regex = bgp_regcomp (regstr);
527 if (!regex)
528 {
46c699ab 529 vty_out (vty, "can't compile regexp %s%s", regstr, VTY_NEWLINE);
3b8b1855 530 XFREE (MTYPE_TMP, regstr);
718e3744 531 return CMD_WARNING;
532 }
533
534 /* Lookup asfilter. */
535 asfilter = as_filter_lookup (aslist, regstr, type);
536
3b8b1855 537 XFREE (MTYPE_TMP, regstr);
718e3744 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
551DEFUN (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{
c500ae40 560 int idx_word = 4;
718e3744 561 struct as_list *aslist;
562
c500ae40 563 aslist = as_list_lookup (argv[idx_word]->arg);
718e3744 564 if (aslist == NULL)
565 {
c500ae40 566 vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[idx_word]->arg,
718e3744 567 VTY_NEWLINE);
568 return CMD_WARNING;
569 }
570
571 as_list_delete (aslist);
572
e0701b79 573 /* Run hook function. */
574 if (as_list_master.delete_hook)
c500ae40 575 (*as_list_master.delete_hook) (argv[idx_word]->arg);
e0701b79 576
718e3744 577 return CMD_SUCCESS;
578}
579
94f2b392 580static void
4f991ef0 581as_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
94f2b392 594static void
4f991ef0 595as_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
623DEFUN (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{
c500ae40 631 int idx_word = 3;
4f991ef0 632 struct as_list *aslist;
633
c500ae40 634 aslist = as_list_lookup (argv[idx_word]->arg);
4f991ef0 635 if (aslist)
636 as_list_show (vty, aslist);
637
638 return CMD_SUCCESS;
639}
640
641DEFUN (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
94f2b392 652static int
718e3744 653config_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
7fc626de 681static struct cmd_node as_list_node =
718e3744 682{
683 AS_LIST_NODE,
684 "",
685 1
686};
687
688/* Register functions. */
689void
94f2b392 690bgp_filter_init (void)
718e3744 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);
4f991ef0 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);
718e3744 700}
228da428
CC
701
702void
703bgp_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}