Annotation of embedaddon/quagga/bgpd/bgp_filter.c, revision 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>