File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / bgpd / bgp_filter.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:10 2016 UTC (7 years, 8 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    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 "filter.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) (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: 
   74:   enum access_type type;
   75: 
   76:   struct as_list *next;
   77:   struct as_list *prev;
   78: 
   79:   struct as_filter *head;
   80:   struct as_filter *tail;
   81: };
   82: 
   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: }
  368: 
  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: }
  410: 
  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>