Annotation of embedaddon/quagga/lib/routemap.c, revision 1.1
1.1 ! misho 1: /* Route map function.
! 2: Copyright (C) 1998, 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 "linklist.h"
! 24: #include "memory.h"
! 25: #include "vector.h"
! 26: #include "prefix.h"
! 27: #include "routemap.h"
! 28: #include "command.h"
! 29: #include "vty.h"
! 30: #include "log.h"
! 31:
! 32: /* Vector for route match rules. */
! 33: static vector route_match_vec;
! 34:
! 35: /* Vector for route set rules. */
! 36: static vector route_set_vec;
! 37:
! 38: /* Route map rule. This rule has both `match' rule and `set' rule. */
! 39: struct route_map_rule
! 40: {
! 41: /* Rule type. */
! 42: struct route_map_rule_cmd *cmd;
! 43:
! 44: /* For pretty printing. */
! 45: char *rule_str;
! 46:
! 47: /* Pre-compiled match rule. */
! 48: void *value;
! 49:
! 50: /* Linked list. */
! 51: struct route_map_rule *next;
! 52: struct route_map_rule *prev;
! 53: };
! 54:
! 55: /* Making route map list. */
! 56: struct route_map_list
! 57: {
! 58: struct route_map *head;
! 59: struct route_map *tail;
! 60:
! 61: void (*add_hook) (const char *);
! 62: void (*delete_hook) (const char *);
! 63: void (*event_hook) (route_map_event_t, const char *);
! 64: };
! 65:
! 66: /* Master list of route map. */
! 67: static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL };
! 68:
! 69: static void
! 70: route_map_rule_delete (struct route_map_rule_list *,
! 71: struct route_map_rule *);
! 72:
! 73: static void
! 74: route_map_index_delete (struct route_map_index *, int);
! 75:
! 76: /* New route map allocation. Please note route map's name must be
! 77: specified. */
! 78: static struct route_map *
! 79: route_map_new (const char *name)
! 80: {
! 81: struct route_map *new;
! 82:
! 83: new = XCALLOC (MTYPE_ROUTE_MAP, sizeof (struct route_map));
! 84: new->name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, name);
! 85: return new;
! 86: }
! 87:
! 88: /* Add new name to route_map. */
! 89: static struct route_map *
! 90: route_map_add (const char *name)
! 91: {
! 92: struct route_map *map;
! 93: struct route_map_list *list;
! 94:
! 95: map = route_map_new (name);
! 96: list = &route_map_master;
! 97:
! 98: map->next = NULL;
! 99: map->prev = list->tail;
! 100: if (list->tail)
! 101: list->tail->next = map;
! 102: else
! 103: list->head = map;
! 104: list->tail = map;
! 105:
! 106: /* Execute hook. */
! 107: if (route_map_master.add_hook)
! 108: (*route_map_master.add_hook) (name);
! 109:
! 110: return map;
! 111: }
! 112:
! 113: /* Route map delete from list. */
! 114: static void
! 115: route_map_delete (struct route_map *map)
! 116: {
! 117: struct route_map_list *list;
! 118: struct route_map_index *index;
! 119: char *name;
! 120:
! 121: while ((index = map->head) != NULL)
! 122: route_map_index_delete (index, 0);
! 123:
! 124: name = map->name;
! 125:
! 126: list = &route_map_master;
! 127:
! 128: if (map->next)
! 129: map->next->prev = map->prev;
! 130: else
! 131: list->tail = map->prev;
! 132:
! 133: if (map->prev)
! 134: map->prev->next = map->next;
! 135: else
! 136: list->head = map->next;
! 137:
! 138: XFREE (MTYPE_ROUTE_MAP, map);
! 139:
! 140: /* Execute deletion hook. */
! 141: if (route_map_master.delete_hook)
! 142: (*route_map_master.delete_hook) (name);
! 143:
! 144: if (name)
! 145: XFREE (MTYPE_ROUTE_MAP_NAME, name);
! 146:
! 147: }
! 148:
! 149: /* Lookup route map by route map name string. */
! 150: struct route_map *
! 151: route_map_lookup_by_name (const char *name)
! 152: {
! 153: struct route_map *map;
! 154:
! 155: for (map = route_map_master.head; map; map = map->next)
! 156: if (strcmp (map->name, name) == 0)
! 157: return map;
! 158: return NULL;
! 159: }
! 160:
! 161: /* Lookup route map. If there isn't route map create one and return
! 162: it. */
! 163: static struct route_map *
! 164: route_map_get (const char *name)
! 165: {
! 166: struct route_map *map;
! 167:
! 168: map = route_map_lookup_by_name (name);
! 169: if (map == NULL)
! 170: map = route_map_add (name);
! 171: return map;
! 172: }
! 173:
! 174: /* Return route map's type string. */
! 175: static const char *
! 176: route_map_type_str (enum route_map_type type)
! 177: {
! 178: switch (type)
! 179: {
! 180: case RMAP_PERMIT:
! 181: return "permit";
! 182: break;
! 183: case RMAP_DENY:
! 184: return "deny";
! 185: break;
! 186: default:
! 187: return "";
! 188: break;
! 189: }
! 190: }
! 191:
! 192: static int
! 193: route_map_empty (struct route_map *map)
! 194: {
! 195: if (map->head == NULL && map->tail == NULL)
! 196: return 1;
! 197: else
! 198: return 0;
! 199: }
! 200:
! 201: /* show route-map */
! 202: static void
! 203: vty_show_route_map_entry (struct vty *vty, struct route_map *map)
! 204: {
! 205: struct route_map_index *index;
! 206: struct route_map_rule *rule;
! 207:
! 208: /* Print the name of the protocol */
! 209: if (zlog_default)
! 210: vty_out (vty, "%s:%s", zlog_proto_names[zlog_default->protocol],
! 211: VTY_NEWLINE);
! 212:
! 213: for (index = map->head; index; index = index->next)
! 214: {
! 215: vty_out (vty, "route-map %s, %s, sequence %d%s",
! 216: map->name, route_map_type_str (index->type),
! 217: index->pref, VTY_NEWLINE);
! 218:
! 219: /* Description */
! 220: if (index->description)
! 221: vty_out (vty, " Description:%s %s%s", VTY_NEWLINE,
! 222: index->description, VTY_NEWLINE);
! 223:
! 224: /* Match clauses */
! 225: vty_out (vty, " Match clauses:%s", VTY_NEWLINE);
! 226: for (rule = index->match_list.head; rule; rule = rule->next)
! 227: vty_out (vty, " %s %s%s",
! 228: rule->cmd->str, rule->rule_str, VTY_NEWLINE);
! 229:
! 230: vty_out (vty, " Set clauses:%s", VTY_NEWLINE);
! 231: for (rule = index->set_list.head; rule; rule = rule->next)
! 232: vty_out (vty, " %s %s%s",
! 233: rule->cmd->str, rule->rule_str, VTY_NEWLINE);
! 234:
! 235: /* Call clause */
! 236: vty_out (vty, " Call clause:%s", VTY_NEWLINE);
! 237: if (index->nextrm)
! 238: vty_out (vty, " Call %s%s", index->nextrm, VTY_NEWLINE);
! 239:
! 240: /* Exit Policy */
! 241: vty_out (vty, " Action:%s", VTY_NEWLINE);
! 242: if (index->exitpolicy == RMAP_GOTO)
! 243: vty_out (vty, " Goto %d%s", index->nextpref, VTY_NEWLINE);
! 244: else if (index->exitpolicy == RMAP_NEXT)
! 245: vty_out (vty, " Continue to next entry%s", VTY_NEWLINE);
! 246: else if (index->exitpolicy == RMAP_EXIT)
! 247: vty_out (vty, " Exit routemap%s", VTY_NEWLINE);
! 248: }
! 249: }
! 250:
! 251: static int
! 252: vty_show_route_map (struct vty *vty, const char *name)
! 253: {
! 254: struct route_map *map;
! 255:
! 256: if (name)
! 257: {
! 258: map = route_map_lookup_by_name (name);
! 259:
! 260: if (map)
! 261: {
! 262: vty_show_route_map_entry (vty, map);
! 263: return CMD_SUCCESS;
! 264: }
! 265: else
! 266: {
! 267: vty_out (vty, "%%route-map %s not found%s", name, VTY_NEWLINE);
! 268: return CMD_WARNING;
! 269: }
! 270: }
! 271: else
! 272: {
! 273: for (map = route_map_master.head; map; map = map->next)
! 274: vty_show_route_map_entry (vty, map);
! 275: }
! 276: return CMD_SUCCESS;
! 277: }
! 278:
! 279:
! 280: /* New route map allocation. Please note route map's name must be
! 281: specified. */
! 282: static struct route_map_index *
! 283: route_map_index_new (void)
! 284: {
! 285: struct route_map_index *new;
! 286:
! 287: new = XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index));
! 288: new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
! 289: return new;
! 290: }
! 291:
! 292: /* Free route map index. */
! 293: static void
! 294: route_map_index_delete (struct route_map_index *index, int notify)
! 295: {
! 296: struct route_map_rule *rule;
! 297:
! 298: /* Free route match. */
! 299: while ((rule = index->match_list.head) != NULL)
! 300: route_map_rule_delete (&index->match_list, rule);
! 301:
! 302: /* Free route set. */
! 303: while ((rule = index->set_list.head) != NULL)
! 304: route_map_rule_delete (&index->set_list, rule);
! 305:
! 306: /* Remove index from route map list. */
! 307: if (index->next)
! 308: index->next->prev = index->prev;
! 309: else
! 310: index->map->tail = index->prev;
! 311:
! 312: if (index->prev)
! 313: index->prev->next = index->next;
! 314: else
! 315: index->map->head = index->next;
! 316:
! 317: /* Free 'char *nextrm' if not NULL */
! 318: if (index->nextrm)
! 319: XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
! 320:
! 321: /* Execute event hook. */
! 322: if (route_map_master.event_hook && notify)
! 323: (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
! 324: index->map->name);
! 325:
! 326: XFREE (MTYPE_ROUTE_MAP_INDEX, index);
! 327: }
! 328:
! 329: /* Lookup index from route map. */
! 330: static struct route_map_index *
! 331: route_map_index_lookup (struct route_map *map, enum route_map_type type,
! 332: int pref)
! 333: {
! 334: struct route_map_index *index;
! 335:
! 336: for (index = map->head; index; index = index->next)
! 337: if ((index->type == type || type == RMAP_ANY)
! 338: && index->pref == pref)
! 339: return index;
! 340: return NULL;
! 341: }
! 342:
! 343: /* Add new index to route map. */
! 344: static struct route_map_index *
! 345: route_map_index_add (struct route_map *map, enum route_map_type type,
! 346: int pref)
! 347: {
! 348: struct route_map_index *index;
! 349: struct route_map_index *point;
! 350:
! 351: /* Allocate new route map inex. */
! 352: index = route_map_index_new ();
! 353: index->map = map;
! 354: index->type = type;
! 355: index->pref = pref;
! 356:
! 357: /* Compare preference. */
! 358: for (point = map->head; point; point = point->next)
! 359: if (point->pref >= pref)
! 360: break;
! 361:
! 362: if (map->head == NULL)
! 363: {
! 364: map->head = map->tail = index;
! 365: }
! 366: else if (point == NULL)
! 367: {
! 368: index->prev = map->tail;
! 369: map->tail->next = index;
! 370: map->tail = index;
! 371: }
! 372: else if (point == map->head)
! 373: {
! 374: index->next = map->head;
! 375: map->head->prev = index;
! 376: map->head = index;
! 377: }
! 378: else
! 379: {
! 380: index->next = point;
! 381: index->prev = point->prev;
! 382: if (point->prev)
! 383: point->prev->next = index;
! 384: point->prev = index;
! 385: }
! 386:
! 387: /* Execute event hook. */
! 388: if (route_map_master.event_hook)
! 389: (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
! 390: map->name);
! 391:
! 392: return index;
! 393: }
! 394:
! 395: /* Get route map index. */
! 396: static struct route_map_index *
! 397: route_map_index_get (struct route_map *map, enum route_map_type type,
! 398: int pref)
! 399: {
! 400: struct route_map_index *index;
! 401:
! 402: index = route_map_index_lookup (map, RMAP_ANY, pref);
! 403: if (index && index->type != type)
! 404: {
! 405: /* Delete index from route map. */
! 406: route_map_index_delete (index, 1);
! 407: index = NULL;
! 408: }
! 409: if (index == NULL)
! 410: index = route_map_index_add (map, type, pref);
! 411: return index;
! 412: }
! 413:
! 414: /* New route map rule */
! 415: static struct route_map_rule *
! 416: route_map_rule_new (void)
! 417: {
! 418: struct route_map_rule *new;
! 419:
! 420: new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule));
! 421: return new;
! 422: }
! 423:
! 424: /* Install rule command to the match list. */
! 425: void
! 426: route_map_install_match (struct route_map_rule_cmd *cmd)
! 427: {
! 428: vector_set (route_match_vec, cmd);
! 429: }
! 430:
! 431: /* Install rule command to the set list. */
! 432: void
! 433: route_map_install_set (struct route_map_rule_cmd *cmd)
! 434: {
! 435: vector_set (route_set_vec, cmd);
! 436: }
! 437:
! 438: /* Lookup rule command from match list. */
! 439: static struct route_map_rule_cmd *
! 440: route_map_lookup_match (const char *name)
! 441: {
! 442: unsigned int i;
! 443: struct route_map_rule_cmd *rule;
! 444:
! 445: for (i = 0; i < vector_active (route_match_vec); i++)
! 446: if ((rule = vector_slot (route_match_vec, i)) != NULL)
! 447: if (strcmp (rule->str, name) == 0)
! 448: return rule;
! 449: return NULL;
! 450: }
! 451:
! 452: /* Lookup rule command from set list. */
! 453: static struct route_map_rule_cmd *
! 454: route_map_lookup_set (const char *name)
! 455: {
! 456: unsigned int i;
! 457: struct route_map_rule_cmd *rule;
! 458:
! 459: for (i = 0; i < vector_active (route_set_vec); i++)
! 460: if ((rule = vector_slot (route_set_vec, i)) != NULL)
! 461: if (strcmp (rule->str, name) == 0)
! 462: return rule;
! 463: return NULL;
! 464: }
! 465:
! 466: /* Add match and set rule to rule list. */
! 467: static void
! 468: route_map_rule_add (struct route_map_rule_list *list,
! 469: struct route_map_rule *rule)
! 470: {
! 471: rule->next = NULL;
! 472: rule->prev = list->tail;
! 473: if (list->tail)
! 474: list->tail->next = rule;
! 475: else
! 476: list->head = rule;
! 477: list->tail = rule;
! 478: }
! 479:
! 480: /* Delete rule from rule list. */
! 481: static void
! 482: route_map_rule_delete (struct route_map_rule_list *list,
! 483: struct route_map_rule *rule)
! 484: {
! 485: if (rule->cmd->func_free)
! 486: (*rule->cmd->func_free) (rule->value);
! 487:
! 488: if (rule->rule_str)
! 489: XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
! 490:
! 491: if (rule->next)
! 492: rule->next->prev = rule->prev;
! 493: else
! 494: list->tail = rule->prev;
! 495: if (rule->prev)
! 496: rule->prev->next = rule->next;
! 497: else
! 498: list->head = rule->next;
! 499:
! 500: XFREE (MTYPE_ROUTE_MAP_RULE, rule);
! 501: }
! 502:
! 503: /* strcmp wrapper function which don't crush even argument is NULL. */
! 504: static int
! 505: rulecmp (const char *dst, const char *src)
! 506: {
! 507: if (dst == NULL)
! 508: {
! 509: if (src == NULL)
! 510: return 0;
! 511: else
! 512: return 1;
! 513: }
! 514: else
! 515: {
! 516: if (src == NULL)
! 517: return 1;
! 518: else
! 519: return strcmp (dst, src);
! 520: }
! 521: return 1;
! 522: }
! 523:
! 524: /* Add match statement to route map. */
! 525: int
! 526: route_map_add_match (struct route_map_index *index, const char *match_name,
! 527: const char *match_arg)
! 528: {
! 529: struct route_map_rule *rule;
! 530: struct route_map_rule *next;
! 531: struct route_map_rule_cmd *cmd;
! 532: void *compile;
! 533: int replaced = 0;
! 534:
! 535: /* First lookup rule for add match statement. */
! 536: cmd = route_map_lookup_match (match_name);
! 537: if (cmd == NULL)
! 538: return RMAP_RULE_MISSING;
! 539:
! 540: /* Next call compile function for this match statement. */
! 541: if (cmd->func_compile)
! 542: {
! 543: compile= (*cmd->func_compile)(match_arg);
! 544: if (compile == NULL)
! 545: return RMAP_COMPILE_ERROR;
! 546: }
! 547: else
! 548: compile = NULL;
! 549:
! 550: /* If argument is completely same ignore it. */
! 551: for (rule = index->match_list.head; rule; rule = next)
! 552: {
! 553: next = rule->next;
! 554: if (rule->cmd == cmd)
! 555: {
! 556: route_map_rule_delete (&index->match_list, rule);
! 557: replaced = 1;
! 558: }
! 559: }
! 560:
! 561: /* Add new route map match rule. */
! 562: rule = route_map_rule_new ();
! 563: rule->cmd = cmd;
! 564: rule->value = compile;
! 565: if (match_arg)
! 566: rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg);
! 567: else
! 568: rule->rule_str = NULL;
! 569:
! 570: /* Add new route match rule to linked list. */
! 571: route_map_rule_add (&index->match_list, rule);
! 572:
! 573: /* Execute event hook. */
! 574: if (route_map_master.event_hook)
! 575: (*route_map_master.event_hook) (replaced ?
! 576: RMAP_EVENT_MATCH_REPLACED:
! 577: RMAP_EVENT_MATCH_ADDED,
! 578: index->map->name);
! 579:
! 580: return 0;
! 581: }
! 582:
! 583: /* Delete specified route match rule. */
! 584: int
! 585: route_map_delete_match (struct route_map_index *index, const char *match_name,
! 586: const char *match_arg)
! 587: {
! 588: struct route_map_rule *rule;
! 589: struct route_map_rule_cmd *cmd;
! 590:
! 591: cmd = route_map_lookup_match (match_name);
! 592: if (cmd == NULL)
! 593: return 1;
! 594:
! 595: for (rule = index->match_list.head; rule; rule = rule->next)
! 596: if (rule->cmd == cmd &&
! 597: (rulecmp (rule->rule_str, match_arg) == 0 || match_arg == NULL))
! 598: {
! 599: route_map_rule_delete (&index->match_list, rule);
! 600: /* Execute event hook. */
! 601: if (route_map_master.event_hook)
! 602: (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
! 603: index->map->name);
! 604: return 0;
! 605: }
! 606: /* Can't find matched rule. */
! 607: return 1;
! 608: }
! 609:
! 610: /* Add route-map set statement to the route map. */
! 611: int
! 612: route_map_add_set (struct route_map_index *index, const char *set_name,
! 613: const char *set_arg)
! 614: {
! 615: struct route_map_rule *rule;
! 616: struct route_map_rule *next;
! 617: struct route_map_rule_cmd *cmd;
! 618: void *compile;
! 619: int replaced = 0;
! 620:
! 621: cmd = route_map_lookup_set (set_name);
! 622: if (cmd == NULL)
! 623: return RMAP_RULE_MISSING;
! 624:
! 625: /* Next call compile function for this match statement. */
! 626: if (cmd->func_compile)
! 627: {
! 628: compile= (*cmd->func_compile)(set_arg);
! 629: if (compile == NULL)
! 630: return RMAP_COMPILE_ERROR;
! 631: }
! 632: else
! 633: compile = NULL;
! 634:
! 635: /* Add by WJL. if old set command of same kind exist, delete it first
! 636: to ensure only one set command of same kind exist under a
! 637: route_map_index. */
! 638: for (rule = index->set_list.head; rule; rule = next)
! 639: {
! 640: next = rule->next;
! 641: if (rule->cmd == cmd)
! 642: {
! 643: route_map_rule_delete (&index->set_list, rule);
! 644: replaced = 1;
! 645: }
! 646: }
! 647:
! 648: /* Add new route map match rule. */
! 649: rule = route_map_rule_new ();
! 650: rule->cmd = cmd;
! 651: rule->value = compile;
! 652: if (set_arg)
! 653: rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg);
! 654: else
! 655: rule->rule_str = NULL;
! 656:
! 657: /* Add new route match rule to linked list. */
! 658: route_map_rule_add (&index->set_list, rule);
! 659:
! 660: /* Execute event hook. */
! 661: if (route_map_master.event_hook)
! 662: (*route_map_master.event_hook) (replaced ?
! 663: RMAP_EVENT_SET_REPLACED:
! 664: RMAP_EVENT_SET_ADDED,
! 665: index->map->name);
! 666: return 0;
! 667: }
! 668:
! 669: /* Delete route map set rule. */
! 670: int
! 671: route_map_delete_set (struct route_map_index *index, const char *set_name,
! 672: const char *set_arg)
! 673: {
! 674: struct route_map_rule *rule;
! 675: struct route_map_rule_cmd *cmd;
! 676:
! 677: cmd = route_map_lookup_set (set_name);
! 678: if (cmd == NULL)
! 679: return 1;
! 680:
! 681: for (rule = index->set_list.head; rule; rule = rule->next)
! 682: if ((rule->cmd == cmd) &&
! 683: (rulecmp (rule->rule_str, set_arg) == 0 || set_arg == NULL))
! 684: {
! 685: route_map_rule_delete (&index->set_list, rule);
! 686: /* Execute event hook. */
! 687: if (route_map_master.event_hook)
! 688: (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
! 689: index->map->name);
! 690: return 0;
! 691: }
! 692: /* Can't find matched rule. */
! 693: return 1;
! 694: }
! 695:
! 696: /* Apply route map's each index to the object.
! 697:
! 698: The matrix for a route-map looks like this:
! 699: (note, this includes the description for the "NEXT"
! 700: and "GOTO" frobs now
! 701:
! 702: Match | No Match
! 703: |
! 704: permit action | cont
! 705: |
! 706: ------------------+---------------
! 707: |
! 708: deny deny | cont
! 709: |
! 710:
! 711: action)
! 712: -Apply Set statements, accept route
! 713: -If Call statement is present jump to the specified route-map, if it
! 714: denies the route we finish.
! 715: -If NEXT is specified, goto NEXT statement
! 716: -If GOTO is specified, goto the first clause where pref > nextpref
! 717: -If nothing is specified, do as Cisco and finish
! 718: deny)
! 719: -Route is denied by route-map.
! 720: cont)
! 721: -Goto Next index
! 722:
! 723: If we get no matches after we've processed all updates, then the route
! 724: is dropped too.
! 725:
! 726: Some notes on the new "CALL", "NEXT" and "GOTO"
! 727: call WORD - If this clause is matched, then the set statements
! 728: are executed and then we jump to route-map 'WORD'. If
! 729: this route-map denies the route, we finish, in other case we
! 730: do whatever the exit policy (EXIT, NEXT or GOTO) tells.
! 731: on-match next - If this clause is matched, then the set statements
! 732: are executed and then we drop through to the next clause
! 733: on-match goto n - If this clause is matched, then the set statments
! 734: are executed and then we goto the nth clause, or the
! 735: first clause greater than this. In order to ensure
! 736: route-maps *always* exit, you cannot jump backwards.
! 737: Sorry ;)
! 738:
! 739: We need to make sure our route-map processing matches the above
! 740: */
! 741:
! 742: static route_map_result_t
! 743: route_map_apply_match (struct route_map_rule_list *match_list,
! 744: struct prefix *prefix, route_map_object_t type,
! 745: void *object)
! 746: {
! 747: route_map_result_t ret = RMAP_NOMATCH;
! 748: struct route_map_rule *match;
! 749:
! 750:
! 751: /* Check all match rule and if there is no match rule, go to the
! 752: set statement. */
! 753: if (!match_list->head)
! 754: ret = RMAP_MATCH;
! 755: else
! 756: {
! 757: for (match = match_list->head; match; match = match->next)
! 758: {
! 759: /* Try each match statement in turn, If any do not return
! 760: RMAP_MATCH, return, otherwise continue on to next match
! 761: statement. All match statements must match for end-result
! 762: to be a match. */
! 763: ret = (*match->cmd->func_apply) (match->value, prefix,
! 764: type, object);
! 765: if (ret != RMAP_MATCH)
! 766: return ret;
! 767: }
! 768: }
! 769: return ret;
! 770: }
! 771:
! 772: /* Apply route map to the object. */
! 773: route_map_result_t
! 774: route_map_apply (struct route_map *map, struct prefix *prefix,
! 775: route_map_object_t type, void *object)
! 776: {
! 777: static int recursion = 0;
! 778: int ret = 0;
! 779: struct route_map_index *index;
! 780: struct route_map_rule *set;
! 781:
! 782: if (recursion > RMAP_RECURSION_LIMIT)
! 783: {
! 784: zlog (NULL, LOG_WARNING,
! 785: "route-map recursion limit (%d) reached, discarding route",
! 786: RMAP_RECURSION_LIMIT);
! 787: recursion = 0;
! 788: return RMAP_DENYMATCH;
! 789: }
! 790:
! 791: if (map == NULL)
! 792: return RMAP_DENYMATCH;
! 793:
! 794: for (index = map->head; index; index = index->next)
! 795: {
! 796: /* Apply this index. */
! 797: ret = route_map_apply_match (&index->match_list, prefix, type, object);
! 798:
! 799: /* Now we apply the matrix from above */
! 800: if (ret == RMAP_NOMATCH)
! 801: /* 'cont' from matrix - continue to next route-map sequence */
! 802: continue;
! 803: else if (ret == RMAP_MATCH)
! 804: {
! 805: if (index->type == RMAP_PERMIT)
! 806: /* 'action' */
! 807: {
! 808: /* permit+match must execute sets */
! 809: for (set = index->set_list.head; set; set = set->next)
! 810: ret = (*set->cmd->func_apply) (set->value, prefix,
! 811: type, object);
! 812:
! 813: /* Call another route-map if available */
! 814: if (index->nextrm)
! 815: {
! 816: struct route_map *nextrm =
! 817: route_map_lookup_by_name (index->nextrm);
! 818:
! 819: if (nextrm) /* Target route-map found, jump to it */
! 820: {
! 821: recursion++;
! 822: ret = route_map_apply (nextrm, prefix, type, object);
! 823: recursion--;
! 824: }
! 825:
! 826: /* If nextrm returned 'deny', finish. */
! 827: if (ret == RMAP_DENYMATCH)
! 828: return ret;
! 829: }
! 830:
! 831: switch (index->exitpolicy)
! 832: {
! 833: case RMAP_EXIT:
! 834: return ret;
! 835: case RMAP_NEXT:
! 836: continue;
! 837: case RMAP_GOTO:
! 838: {
! 839: /* Find the next clause to jump to */
! 840: struct route_map_index *next = index->next;
! 841: int nextpref = index->nextpref;
! 842:
! 843: while (next && next->pref < nextpref)
! 844: {
! 845: index = next;
! 846: next = next->next;
! 847: }
! 848: if (next == NULL)
! 849: {
! 850: /* No clauses match! */
! 851: return ret;
! 852: }
! 853: }
! 854: }
! 855: }
! 856: else if (index->type == RMAP_DENY)
! 857: /* 'deny' */
! 858: {
! 859: return RMAP_DENYMATCH;
! 860: }
! 861: }
! 862: }
! 863: /* Finally route-map does not match at all. */
! 864: return RMAP_DENYMATCH;
! 865: }
! 866:
! 867: void
! 868: route_map_add_hook (void (*func) (const char *))
! 869: {
! 870: route_map_master.add_hook = func;
! 871: }
! 872:
! 873: void
! 874: route_map_delete_hook (void (*func) (const char *))
! 875: {
! 876: route_map_master.delete_hook = func;
! 877: }
! 878:
! 879: void
! 880: route_map_event_hook (void (*func) (route_map_event_t, const char *))
! 881: {
! 882: route_map_master.event_hook = func;
! 883: }
! 884:
! 885: void
! 886: route_map_init (void)
! 887: {
! 888: /* Make vector for match and set. */
! 889: route_match_vec = vector_init (1);
! 890: route_set_vec = vector_init (1);
! 891: }
! 892:
! 893: void
! 894: route_map_finish (void)
! 895: {
! 896: vector_free (route_match_vec);
! 897: route_match_vec = NULL;
! 898: vector_free (route_set_vec);
! 899: route_set_vec = NULL;
! 900: }
! 901:
! 902: /* VTY related functions. */
! 903: DEFUN (route_map,
! 904: route_map_cmd,
! 905: "route-map WORD (deny|permit) <1-65535>",
! 906: "Create route-map or enter route-map command mode\n"
! 907: "Route map tag\n"
! 908: "Route map denies set operations\n"
! 909: "Route map permits set operations\n"
! 910: "Sequence to insert to/delete from existing route-map entry\n")
! 911: {
! 912: int permit;
! 913: unsigned long pref;
! 914: struct route_map *map;
! 915: struct route_map_index *index;
! 916: char *endptr = NULL;
! 917:
! 918: /* Permit check. */
! 919: if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
! 920: permit = RMAP_PERMIT;
! 921: else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
! 922: permit = RMAP_DENY;
! 923: else
! 924: {
! 925: vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
! 926: return CMD_WARNING;
! 927: }
! 928:
! 929: /* Preference check. */
! 930: pref = strtoul (argv[2], &endptr, 10);
! 931: if (pref == ULONG_MAX || *endptr != '\0')
! 932: {
! 933: vty_out (vty, "the fourth field must be positive integer%s",
! 934: VTY_NEWLINE);
! 935: return CMD_WARNING;
! 936: }
! 937: if (pref == 0 || pref > 65535)
! 938: {
! 939: vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
! 940: return CMD_WARNING;
! 941: }
! 942:
! 943: /* Get route map. */
! 944: map = route_map_get (argv[0]);
! 945: index = route_map_index_get (map, permit, pref);
! 946:
! 947: vty->index = index;
! 948: vty->node = RMAP_NODE;
! 949: return CMD_SUCCESS;
! 950: }
! 951:
! 952: DEFUN (no_route_map_all,
! 953: no_route_map_all_cmd,
! 954: "no route-map WORD",
! 955: NO_STR
! 956: "Create route-map or enter route-map command mode\n"
! 957: "Route map tag\n")
! 958: {
! 959: struct route_map *map;
! 960:
! 961: map = route_map_lookup_by_name (argv[0]);
! 962: if (map == NULL)
! 963: {
! 964: vty_out (vty, "%% Could not find route-map %s%s",
! 965: argv[0], VTY_NEWLINE);
! 966: return CMD_WARNING;
! 967: }
! 968:
! 969: route_map_delete (map);
! 970:
! 971: return CMD_SUCCESS;
! 972: }
! 973:
! 974: DEFUN (no_route_map,
! 975: no_route_map_cmd,
! 976: "no route-map WORD (deny|permit) <1-65535>",
! 977: NO_STR
! 978: "Create route-map or enter route-map command mode\n"
! 979: "Route map tag\n"
! 980: "Route map denies set operations\n"
! 981: "Route map permits set operations\n"
! 982: "Sequence to insert to/delete from existing route-map entry\n")
! 983: {
! 984: int permit;
! 985: unsigned long pref;
! 986: struct route_map *map;
! 987: struct route_map_index *index;
! 988: char *endptr = NULL;
! 989:
! 990: /* Permit check. */
! 991: if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
! 992: permit = RMAP_PERMIT;
! 993: else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
! 994: permit = RMAP_DENY;
! 995: else
! 996: {
! 997: vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
! 998: return CMD_WARNING;
! 999: }
! 1000:
! 1001: /* Preference. */
! 1002: pref = strtoul (argv[2], &endptr, 10);
! 1003: if (pref == ULONG_MAX || *endptr != '\0')
! 1004: {
! 1005: vty_out (vty, "the fourth field must be positive integer%s",
! 1006: VTY_NEWLINE);
! 1007: return CMD_WARNING;
! 1008: }
! 1009: if (pref == 0 || pref > 65535)
! 1010: {
! 1011: vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
! 1012: return CMD_WARNING;
! 1013: }
! 1014:
! 1015: /* Existence check. */
! 1016: map = route_map_lookup_by_name (argv[0]);
! 1017: if (map == NULL)
! 1018: {
! 1019: vty_out (vty, "%% Could not find route-map %s%s",
! 1020: argv[0], VTY_NEWLINE);
! 1021: return CMD_WARNING;
! 1022: }
! 1023:
! 1024: /* Lookup route map index. */
! 1025: index = route_map_index_lookup (map, permit, pref);
! 1026: if (index == NULL)
! 1027: {
! 1028: vty_out (vty, "%% Could not find route-map entry %s %s%s",
! 1029: argv[0], argv[2], VTY_NEWLINE);
! 1030: return CMD_WARNING;
! 1031: }
! 1032:
! 1033: /* Delete index from route map. */
! 1034: route_map_index_delete (index, 1);
! 1035:
! 1036: /* If this route rule is the last one, delete route map itself. */
! 1037: if (route_map_empty (map))
! 1038: route_map_delete (map);
! 1039:
! 1040: return CMD_SUCCESS;
! 1041: }
! 1042:
! 1043: DEFUN (rmap_onmatch_next,
! 1044: rmap_onmatch_next_cmd,
! 1045: "on-match next",
! 1046: "Exit policy on matches\n"
! 1047: "Next clause\n")
! 1048: {
! 1049: struct route_map_index *index;
! 1050:
! 1051: index = vty->index;
! 1052:
! 1053: if (index)
! 1054: index->exitpolicy = RMAP_NEXT;
! 1055:
! 1056: return CMD_SUCCESS;
! 1057: }
! 1058:
! 1059: DEFUN (no_rmap_onmatch_next,
! 1060: no_rmap_onmatch_next_cmd,
! 1061: "no on-match next",
! 1062: NO_STR
! 1063: "Exit policy on matches\n"
! 1064: "Next clause\n")
! 1065: {
! 1066: struct route_map_index *index;
! 1067:
! 1068: index = vty->index;
! 1069:
! 1070: if (index)
! 1071: index->exitpolicy = RMAP_EXIT;
! 1072:
! 1073: return CMD_SUCCESS;
! 1074: }
! 1075:
! 1076: DEFUN (rmap_onmatch_goto,
! 1077: rmap_onmatch_goto_cmd,
! 1078: "on-match goto <1-65535>",
! 1079: "Exit policy on matches\n"
! 1080: "Goto Clause number\n"
! 1081: "Number\n")
! 1082: {
! 1083: struct route_map_index *index = vty->index;
! 1084: int d = 0;
! 1085:
! 1086: if (index)
! 1087: {
! 1088: if (argc == 1 && argv[0])
! 1089: VTY_GET_INTEGER_RANGE("route-map index", d, argv[0], 1, 65536);
! 1090: else
! 1091: d = index->pref + 1;
! 1092:
! 1093: if (d <= index->pref)
! 1094: {
! 1095: /* Can't allow you to do that, Dave */
! 1096: vty_out (vty, "can't jump backwards in route-maps%s",
! 1097: VTY_NEWLINE);
! 1098: return CMD_WARNING;
! 1099: }
! 1100: else
! 1101: {
! 1102: index->exitpolicy = RMAP_GOTO;
! 1103: index->nextpref = d;
! 1104: }
! 1105: }
! 1106: return CMD_SUCCESS;
! 1107: }
! 1108:
! 1109: DEFUN (no_rmap_onmatch_goto,
! 1110: no_rmap_onmatch_goto_cmd,
! 1111: "no on-match goto",
! 1112: NO_STR
! 1113: "Exit policy on matches\n"
! 1114: "Goto Clause number\n")
! 1115: {
! 1116: struct route_map_index *index;
! 1117:
! 1118: index = vty->index;
! 1119:
! 1120: if (index)
! 1121: index->exitpolicy = RMAP_EXIT;
! 1122:
! 1123: return CMD_SUCCESS;
! 1124: }
! 1125:
! 1126: /* Cisco/GNU Zebra compatible ALIASes for on-match next */
! 1127: ALIAS (rmap_onmatch_goto,
! 1128: rmap_continue_cmd,
! 1129: "continue",
! 1130: "Continue on a different entry within the route-map\n")
! 1131:
! 1132: ALIAS (no_rmap_onmatch_goto,
! 1133: no_rmap_continue_cmd,
! 1134: "no continue",
! 1135: NO_STR
! 1136: "Continue on a different entry within the route-map\n")
! 1137:
! 1138: /* GNU Zebra compatible */
! 1139: ALIAS (rmap_onmatch_goto,
! 1140: rmap_continue_seq_cmd,
! 1141: "continue <1-65535>",
! 1142: "Continue on a different entry within the route-map\n"
! 1143: "Route-map entry sequence number\n")
! 1144:
! 1145: ALIAS (no_rmap_onmatch_goto,
! 1146: no_rmap_continue_seq,
! 1147: "no continue <1-65535>",
! 1148: NO_STR
! 1149: "Continue on a different entry within the route-map\n"
! 1150: "Route-map entry sequence number\n")
! 1151:
! 1152: DEFUN (rmap_show_name,
! 1153: rmap_show_name_cmd,
! 1154: "show route-map [WORD]",
! 1155: SHOW_STR
! 1156: "route-map information\n"
! 1157: "route-map name\n")
! 1158: {
! 1159: const char *name = NULL;
! 1160: if (argc)
! 1161: name = argv[0];
! 1162: return vty_show_route_map (vty, name);
! 1163: }
! 1164:
! 1165: ALIAS (rmap_onmatch_goto,
! 1166: rmap_continue_index_cmd,
! 1167: "continue <1-65536>",
! 1168: "Exit policy on matches\n"
! 1169: "Goto Clause number\n")
! 1170:
! 1171: DEFUN (rmap_call,
! 1172: rmap_call_cmd,
! 1173: "call WORD",
! 1174: "Jump to another Route-Map after match+set\n"
! 1175: "Target route-map name\n")
! 1176: {
! 1177: struct route_map_index *index;
! 1178:
! 1179: index = vty->index;
! 1180: if (index)
! 1181: {
! 1182: if (index->nextrm)
! 1183: XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
! 1184: index->nextrm = XSTRDUP (MTYPE_ROUTE_MAP_NAME, argv[0]);
! 1185: }
! 1186: return CMD_SUCCESS;
! 1187: }
! 1188:
! 1189: DEFUN (no_rmap_call,
! 1190: no_rmap_call_cmd,
! 1191: "no call",
! 1192: NO_STR
! 1193: "Jump to another Route-Map after match+set\n")
! 1194: {
! 1195: struct route_map_index *index;
! 1196:
! 1197: index = vty->index;
! 1198:
! 1199: if (index->nextrm)
! 1200: {
! 1201: XFREE (MTYPE_ROUTE_MAP_NAME, index->nextrm);
! 1202: index->nextrm = NULL;
! 1203: }
! 1204:
! 1205: return CMD_SUCCESS;
! 1206: }
! 1207:
! 1208: DEFUN (rmap_description,
! 1209: rmap_description_cmd,
! 1210: "description .LINE",
! 1211: "Route-map comment\n"
! 1212: "Comment describing this route-map rule\n")
! 1213: {
! 1214: struct route_map_index *index;
! 1215:
! 1216: index = vty->index;
! 1217: if (index)
! 1218: {
! 1219: if (index->description)
! 1220: XFREE (MTYPE_TMP, index->description);
! 1221: index->description = argv_concat (argv, argc, 0);
! 1222: }
! 1223: return CMD_SUCCESS;
! 1224: }
! 1225:
! 1226: DEFUN (no_rmap_description,
! 1227: no_rmap_description_cmd,
! 1228: "no description",
! 1229: NO_STR
! 1230: "Route-map comment\n")
! 1231: {
! 1232: struct route_map_index *index;
! 1233:
! 1234: index = vty->index;
! 1235: if (index)
! 1236: {
! 1237: if (index->description)
! 1238: XFREE (MTYPE_TMP, index->description);
! 1239: index->description = NULL;
! 1240: }
! 1241: return CMD_SUCCESS;
! 1242: }
! 1243:
! 1244: /* Configuration write function. */
! 1245: static int
! 1246: route_map_config_write (struct vty *vty)
! 1247: {
! 1248: struct route_map *map;
! 1249: struct route_map_index *index;
! 1250: struct route_map_rule *rule;
! 1251: int first = 1;
! 1252: int write = 0;
! 1253:
! 1254: for (map = route_map_master.head; map; map = map->next)
! 1255: for (index = map->head; index; index = index->next)
! 1256: {
! 1257: if (!first)
! 1258: vty_out (vty, "!%s", VTY_NEWLINE);
! 1259: else
! 1260: first = 0;
! 1261:
! 1262: vty_out (vty, "route-map %s %s %d%s",
! 1263: map->name,
! 1264: route_map_type_str (index->type),
! 1265: index->pref, VTY_NEWLINE);
! 1266:
! 1267: if (index->description)
! 1268: vty_out (vty, " description %s%s", index->description, VTY_NEWLINE);
! 1269:
! 1270: for (rule = index->match_list.head; rule; rule = rule->next)
! 1271: vty_out (vty, " match %s %s%s", rule->cmd->str,
! 1272: rule->rule_str ? rule->rule_str : "",
! 1273: VTY_NEWLINE);
! 1274:
! 1275: for (rule = index->set_list.head; rule; rule = rule->next)
! 1276: vty_out (vty, " set %s %s%s", rule->cmd->str,
! 1277: rule->rule_str ? rule->rule_str : "",
! 1278: VTY_NEWLINE);
! 1279: if (index->nextrm)
! 1280: vty_out (vty, " call %s%s", index->nextrm, VTY_NEWLINE);
! 1281: if (index->exitpolicy == RMAP_GOTO)
! 1282: vty_out (vty, " on-match goto %d%s", index->nextpref, VTY_NEWLINE);
! 1283: if (index->exitpolicy == RMAP_NEXT)
! 1284: vty_out (vty," on-match next%s", VTY_NEWLINE);
! 1285:
! 1286: write++;
! 1287: }
! 1288: return write;
! 1289: }
! 1290:
! 1291: /* Route map node structure. */
! 1292: static struct cmd_node rmap_node =
! 1293: {
! 1294: RMAP_NODE,
! 1295: "%s(config-route-map)# ",
! 1296: 1
! 1297: };
! 1298:
! 1299: /* Initialization of route map vector. */
! 1300: void
! 1301: route_map_init_vty (void)
! 1302: {
! 1303: /* Install route map top node. */
! 1304: install_node (&rmap_node, route_map_config_write);
! 1305:
! 1306: /* Install route map commands. */
! 1307: install_default (RMAP_NODE);
! 1308: install_element (CONFIG_NODE, &route_map_cmd);
! 1309: install_element (CONFIG_NODE, &no_route_map_cmd);
! 1310: install_element (CONFIG_NODE, &no_route_map_all_cmd);
! 1311:
! 1312: /* Install the on-match stuff */
! 1313: install_element (RMAP_NODE, &route_map_cmd);
! 1314: install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
! 1315: install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
! 1316: install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
! 1317: install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
! 1318:
! 1319: /* Install the continue stuff (ALIAS of on-match). */
! 1320: install_element (RMAP_NODE, &rmap_continue_cmd);
! 1321: install_element (RMAP_NODE, &no_rmap_continue_cmd);
! 1322: install_element (RMAP_NODE, &rmap_continue_index_cmd);
! 1323:
! 1324: /* Install the call stuff. */
! 1325: install_element (RMAP_NODE, &rmap_call_cmd);
! 1326: install_element (RMAP_NODE, &no_rmap_call_cmd);
! 1327:
! 1328: /* Install description commands. */
! 1329: install_element (RMAP_NODE, &rmap_description_cmd);
! 1330: install_element (RMAP_NODE, &no_rmap_description_cmd);
! 1331:
! 1332: /* Install show command */
! 1333: install_element (ENABLE_NODE, &rmap_show_name_cmd);
! 1334: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>