1/* Route map function. 2 Copyright (C) 1998, 1999 Kunihiro Ishiguro 3 4This file is part of GNU Zebra. 5 6GNU Zebra is free software; you can redistribute it and/or modify it 7under the terms of the GNU General Public License as published by the 8Free Software Foundation; either version 2, or (at your option) any 9later version. 10 11GNU Zebra is distributed in the hope that it will be useful, but 12WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14General Public License for more details. 15 16You should have received a copy of the GNU General Public License 17along with GNU Zebra; see the file COPYING. If not, write to the Free 18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 1902111-1307, USA. */ 20 21#ifdef FOX_LIST_SUPPORT 22 23#include <zebra.h> 24 25#include "linklist.h" 26#include "memory.h" 27#include "vector.h" 28#include "prefix.h" 29#include "routemap.h" 30#include "command.h" 31 32/* Vector for route match rules. */ 33static vector route_match_vec; 34 35/* Vector for route set rules. */ 36static vector route_set_vec; 37 38/* Route map rule. This rule has both `match' rule and `set' rule. */ 39struct 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. */ 56struct route_map_list 57{ 58 struct route_map *head; 59 struct route_map *tail; 60 61 void (*add_hook) (char *); 62 void (*delete_hook) (char *); 63 void (*event_hook) (route_map_event_t, char *); 64}; 65 66/* Master list of route map. */ 67static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL }; 68 69static void 70route_map_rule_delete (struct route_map_rule_list *, 71 struct route_map_rule *); 72 73static void 74route_map_index_delete (struct route_map_index *, int); 75 76/* New route map allocation. Please note route map's name must be 77 specified. */ 78static struct route_map * 79route_map_new (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. */ 89static struct route_map * 90route_map_add (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. */ 114static void 115route_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. */ 150struct route_map * 151route_map_lookup_by_name (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. */ 163struct route_map * 164route_map_get (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. */ 175static char * 176route_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 192int 193route_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/* For debug. */ 202void 203route_map_print () 204{ 205 struct route_map *map; 206 struct route_map_index *index; 207 struct route_map_rule *rule; 208 209 for (map = route_map_master.head; map; map = map->next) 210 for (index = map->head; index; index = index->next) 211 { 212 printf ("route-map %s %s %d\n", 213 map->name, 214 route_map_type_str (index->type), 215 index->pref); 216 for (rule = index->match_list.head; rule; rule = rule->next) 217 printf (" match %s %s\n", rule->cmd->str, rule->rule_str); 218 for (rule = index->set_list.head; rule; rule = rule->next) 219 printf (" set %s %s\n", rule->cmd->str, rule->rule_str); 220 if (index->exitpolicy == RMAP_GOTO) 221 printf (" on-match goto %d\n", index->nextpref); 222 if (index->exitpolicy == RMAP_NEXT) 223 printf (" on-match next\n"); 224 } 225} 226 227/* New route map allocation. Please note route map's name must be 228 specified. */ 229struct route_map_index * 230route_map_index_new () 231{ 232 struct route_map_index *new; 233 234 new = XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index)); 235 new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */ 236 return new; 237} 238 239/* Free route map index. */ 240static void 241route_map_index_delete (struct route_map_index *index, int notify) 242{ 243 struct route_map_rule *rule; 244 245 /* Free route match. */ 246 while ((rule = index->match_list.head) != NULL) 247 route_map_rule_delete (&index->match_list, rule); 248 249 /* Free route set. */ 250 while ((rule = index->set_list.head) != NULL) 251 route_map_rule_delete (&index->set_list, rule); 252 253 /* Remove index from route map list. */ 254 if (index->next) 255 index->next->prev = index->prev; 256 else 257 index->map->tail = index->prev; 258 259 if (index->prev) 260 index->prev->next = index->next; 261 else 262 index->map->head = index->next; 263 264 /* Execute event hook. */ 265 if (route_map_master.event_hook && notify) 266 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED, 267 index->map->name); 268 269 XFREE (MTYPE_ROUTE_MAP_INDEX, index); 270} 271 272/* Lookup index from route map. */ 273struct route_map_index * 274route_map_index_lookup (struct route_map *map, enum route_map_type type, 275 int pref) 276{ 277 struct route_map_index *index; 278 279 for (index = map->head; index; index = index->next) 280 if ((index->type == type || type == RMAP_ANY) 281 && index->pref == pref) 282 return index; 283 return NULL; 284} 285 286/* Add new index to route map. */ 287struct route_map_index * 288route_map_index_add (struct route_map *map, enum route_map_type type, 289 int pref) 290{ 291 struct route_map_index *index; 292 struct route_map_index *point; 293 294 /* Allocate new route map inex. */ 295 index = route_map_index_new (); 296 index->map = map; 297 index->type = type; 298 index->pref = pref; 299 300 /* Compare preference. */ 301 for (point = map->head; point; point = point->next) 302 if (point->pref >= pref) 303 break; 304 305 if (map->head == NULL) 306 { 307 map->head = map->tail = index; 308 } 309 else if (point == NULL) 310 { 311 index->prev = map->tail; 312 map->tail->next = index; 313 map->tail = index; 314 } 315 else if (point == map->head) 316 { 317 index->next = map->head; 318 map->head->prev = index; 319 map->head = index; 320 } 321 else 322 { 323 index->next = point; 324 index->prev = point->prev; 325 if (point->prev) 326 point->prev->next = index; 327 point->prev = index; 328 } 329 330 /* Execute event hook. */ 331 if (route_map_master.event_hook) 332 (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED, 333 map->name); 334 335 return index; 336} 337 338/* Get route map index. */ 339struct route_map_index * 340route_map_index_get (struct route_map *map, enum route_map_type type, 341 int pref) 342{ 343 struct route_map_index *index; 344 345 index = route_map_index_lookup (map, RMAP_ANY, pref); 346 if (index && index->type != type) 347 { 348 /* Delete index from route map. */ 349 route_map_index_delete (index, 1); 350 index = NULL; 351 } 352 if (index == NULL) 353 index = route_map_index_add (map, type, pref); 354 return index; 355} 356 357/* New route map rule */ 358struct route_map_rule * 359route_map_rule_new () 360{ 361 struct route_map_rule *new; 362 363 new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule)); 364 return new; 365} 366 367/* Install rule command to the match list. */ 368void 369route_map_install_match (struct route_map_rule_cmd *cmd) 370{ 371 vector_set (route_match_vec, cmd); 372} 373 374/* Install rule command to the set list. */ 375void 376route_map_install_set (struct route_map_rule_cmd *cmd) 377{ 378 vector_set (route_set_vec, cmd); 379} 380 381/* Lookup rule command from match list. */ 382struct route_map_rule_cmd * 383route_map_lookup_match (char *name) 384{ 385 int i; 386 struct route_map_rule_cmd *rule; 387 388 for (i = 0; i < vector_max (route_match_vec); i++) 389 if ((rule = vector_slot (route_match_vec, i)) != NULL) 390 if (strcmp (rule->str, name) == 0) 391 return rule; 392 return NULL; 393} 394 395/* Lookup rule command from set list. */ 396struct route_map_rule_cmd * 397route_map_lookup_set (char *name) 398{ 399 int i; 400 struct route_map_rule_cmd *rule; 401 402 for (i = 0; i < vector_max (route_set_vec); i++) 403 if ((rule = vector_slot (route_set_vec, i)) != NULL) 404 if (strcmp (rule->str, name) == 0) 405 return rule; 406 return NULL; 407} 408 409/* Add match and set rule to rule list. */ 410static void 411route_map_rule_add (struct route_map_rule_list *list, 412 struct route_map_rule *rule) 413{ 414 rule->next = NULL; 415 rule->prev = list->tail; 416 if (list->tail) 417 list->tail->next = rule; 418 else 419 list->head = rule; 420 list->tail = rule; 421} 422 423/* Delete rule from rule list. */ 424static void 425route_map_rule_delete (struct route_map_rule_list *list, 426 struct route_map_rule *rule) 427{ 428 if (rule->cmd->func_free) 429 (*rule->cmd->func_free) (rule->value); 430 431 if (rule->rule_str) 432 XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str); 433 434 if (rule->next) 435 rule->next->prev = rule->prev; 436 else 437 list->tail = rule->prev; 438 if (rule->prev) 439 rule->prev->next = rule->next; 440 else 441 list->head = rule->next; 442 443 XFREE (MTYPE_ROUTE_MAP_RULE, rule); 444} 445 446/* strcmp wrapper function which don't crush even argument is NULL. */ 447int 448rulecmp (char *dst, char *src) 449{ 450 if (dst == NULL) 451 { 452 if (src == NULL) 453 return 0; 454 else 455 return 1; 456 } 457 else 458 { 459 if (src == NULL) 460 return 1; 461 else 462 return strcmp (dst, src); 463 } 464 return 1; 465} 466 467/* Add match statement to route map. */ 468int 469route_map_add_match (struct route_map_index *index, char *match_name, 470 char *match_arg) 471{ 472 struct route_map_rule *rule; 473 struct route_map_rule *next; 474 struct route_map_rule_cmd *cmd; 475 void *compile; 476 int replaced = 0; 477 478 /* First lookup rule for add match statement. */ 479 cmd = route_map_lookup_match (match_name); 480 if (cmd == NULL) 481 return RMAP_RULE_MISSING; 482 483 /* Next call compile function for this match statement. */ 484 if (cmd->func_compile) 485 { 486 compile= (*cmd->func_compile)(match_arg); 487 if (compile == NULL) 488 return RMAP_COMPILE_ERROR; 489 } 490 else 491 compile = NULL; 492 493 /* If argument is completely same ignore it. */ 494 for (rule = index->match_list.head; rule; rule = next) 495 { 496 next = rule->next; 497 if (rule->cmd == cmd) 498 { 499 route_map_rule_delete (&index->match_list, rule); 500 replaced = 1; 501 } 502 } 503 504 /* Add new route map match rule. */ 505 rule = route_map_rule_new (); 506 rule->cmd = cmd; 507 rule->value = compile; 508 if (match_arg) 509 rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg); 510 else 511 rule->rule_str = NULL; 512 513 /* Add new route match rule to linked list. */ 514 route_map_rule_add (&index->match_list, rule); 515 516 /* Execute event hook. */ 517 if (route_map_master.event_hook) 518 (*route_map_master.event_hook) (replaced ? 519 RMAP_EVENT_MATCH_REPLACED: 520 RMAP_EVENT_MATCH_ADDED, 521 index->map->name); 522 523 return 0; 524} 525 526/* Delete specified route match rule. */ 527int 528route_map_delete_match (struct route_map_index *index, char *match_name, 529 char *match_arg) 530{ 531 struct route_map_rule *rule; 532 struct route_map_rule_cmd *cmd; 533 534 cmd = route_map_lookup_match (match_name); 535 if (cmd == NULL) 536 return 1; 537 538 for (rule = index->match_list.head; rule; rule = rule->next) 539 if (rule->cmd == cmd && 540 (rulecmp (rule->rule_str, match_arg) == 0 || match_arg == NULL)) 541 { 542 route_map_rule_delete (&index->match_list, rule); 543 /* Execute event hook. */ 544 if (route_map_master.event_hook) 545 (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED, 546 index->map->name); 547 return 0; 548 } 549 /* Can't find matched rule. */ 550 return 1; 551} 552 553/* Add route-map set statement to the route map. */ 554int 555route_map_add_set (struct route_map_index *index, char *set_name, 556 char *set_arg) 557{ 558 struct route_map_rule *rule; 559 struct route_map_rule *next; 560 struct route_map_rule_cmd *cmd; 561 void *compile; 562 int replaced = 0; 563 564 cmd = route_map_lookup_set (set_name); 565 if (cmd == NULL) 566 return RMAP_RULE_MISSING; 567 568 /* Next call compile function for this match statement. */ 569 if (cmd->func_compile) 570 { 571 compile= (*cmd->func_compile)(set_arg); 572 if (compile == NULL) 573 return RMAP_COMPILE_ERROR; 574 } 575 else 576 compile = NULL; 577 578 /* Add by WJL. if old set command of same kind exist, delete it first 579 to ensure only one set command of same kind exist under a 580 route_map_index. */ 581 for (rule = index->set_list.head; rule; rule = next) 582 { 583 next = rule->next; 584 if (rule->cmd == cmd) 585 { 586 route_map_rule_delete (&index->set_list, rule); 587 replaced = 1; 588 } 589 } 590 591 /* Add new route map match rule. */ 592 rule = route_map_rule_new (); 593 rule->cmd = cmd; 594 rule->value = compile; 595 if (set_arg) 596 rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg); 597 else 598 rule->rule_str = NULL; 599 600 /* Add new route match rule to linked list. */ 601 route_map_rule_add (&index->set_list, rule); 602 603 /* Execute event hook. */ 604 if (route_map_master.event_hook) 605 (*route_map_master.event_hook) (replaced ? 606 RMAP_EVENT_SET_REPLACED: 607 RMAP_EVENT_SET_ADDED, 608 index->map->name); 609 return 0; 610} 611 612/* Delete route map set rule. */ 613int 614route_map_delete_set (struct route_map_index *index, char *set_name, 615 char *set_arg) 616{ 617 struct route_map_rule *rule; 618 struct route_map_rule_cmd *cmd; 619 620 cmd = route_map_lookup_set (set_name); 621 if (cmd == NULL) 622 return 1; 623 624 for (rule = index->set_list.head; rule; rule = rule->next) 625 if ((rule->cmd == cmd) && 626 (rulecmp (rule->rule_str, set_arg) == 0 || set_arg == NULL)) 627 { 628 route_map_rule_delete (&index->set_list, rule); 629 /* Execute event hook. */ 630 if (route_map_master.event_hook) 631 (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED, 632 index->map->name); 633 return 0; 634 } 635 /* Can't find matched rule. */ 636 return 1; 637} 638 639/* Apply route map's each index to the object. */ 640/* 641** The matrix for a route-map looks like this: 642** (note, this includes the description for the "NEXT" 643** and "GOTO" frobs now 644** 645** Match | No Match 646** | 647** permit a | c 648** | 649** ------------------+--------------- 650** | 651** deny b | d 652** | 653** 654** a) Apply Set statements, accept route 655** If NEXT is specified, goto NEXT statement 656** If GOTO is specified, goto the first clause where pref > nextpref 657** If nothing is specified, do as Cisco and finish 658** b) Finish route-map processing, and deny route 659** c) & d) Goto Next index 660** 661** If we get no matches after we've processed all updates, then the route 662** is dropped too. 663** 664** Some notes on the new "NEXT" and "GOTO" 665** on-match next - If this clause is matched, then the set statements 666** are executed and then we drop through to the next clause 667** on-match goto n - If this clause is matched, then the set statments 668** are executed and then we goto the nth clause, or the 669** first clause greater than this. In order to ensure 670** route-maps *always* exit, you cannot jump backwards. 671** Sorry ;) 672** 673** We need to make sure our route-map processing matches the above 674*/ 675route_map_result_t 676route_map_apply_index (struct route_map_index *index, struct prefix *prefix, 677 route_map_object_t type, void *object) 678{ 679 int ret; 680 struct route_map_rule *match; 681 struct route_map_rule *set; 682 683 /* Check all match rule and if there is no match rule return 0. */ 684 for (match = index->match_list.head; match; match = match->next) 685 { 686 /* Try each match statement in turn. If any return something 687 other than RM_MATCH then we don't need to check anymore and can 688 return */ 689 ret = (*match->cmd->func_apply)(match->value, prefix, type, object); 690 if (ret != RMAP_MATCH) 691 return ret; 692 } 693 694 /* We get here if all match statements matched From the matrix 695 above, if this is PERMIT we go on and apply the SET functions. If 696 we're deny, we return indicating we matched a deny */ 697 698 /* Apply set statement to the object. */ 699 if (index->type == RMAP_PERMIT) 700 { 701 for (set = index->set_list.head; set; set = set->next) 702 { 703 ret = (*set->cmd->func_apply)(set->value, prefix, type, object); 704 } 705 return RMAP_MATCH; 706 } 707 else 708 { 709 return RMAP_DENYMATCH; 710 } 711 /* Should not get here! */ 712 return RMAP_MATCH; 713} 714 715/* Apply route map to the object. */ 716route_map_result_t 717route_map_apply (struct route_map *map, struct prefix *prefix, 718 route_map_object_t type, void *object) 719{ 720 int ret = 0; 721 struct route_map_index *index; 722 723 if (map == NULL) 724 return RMAP_DENYMATCH; 725 726 for (index = map->head; index; index = index->next) 727 { 728 /* Apply this index. End here if we get a RM_NOMATCH */ 729 ret = route_map_apply_index (index, prefix, type, object); 730 731 if (ret != RMAP_NOMATCH) 732 { 733 /* We now have to handle the NEXT and GOTO clauses */ 734 if(index->exitpolicy == RMAP_EXIT) 735 return ret; 736 if(index->exitpolicy == RMAP_GOTO) 737 { 738 /* Find the next clause to jump to */ 739 struct route_map_index *next; 740 741 next = index->next; 742 while (next && next->pref < index->nextpref) 743 { 744 index = next; 745 next = next->next; 746 } 747 if (next == NULL) 748 { 749 /* No clauses match! */ 750 return ret; 751 } 752 } 753 /* Otherwise, we fall through as it was a NEXT */ 754 } 755 } 756 /* Finally route-map does not match at all. */ 757 return RMAP_DENYMATCH; 758} 759 760void 761route_map_add_hook (void (*func) (char *)) 762{ 763 route_map_master.add_hook = func; 764} 765 766void 767route_map_delete_hook (void (*func) (char *)) 768{ 769 route_map_master.delete_hook = func; 770} 771 772void 773route_map_event_hook (void (*func) (route_map_event_t, char *)) 774{ 775 route_map_master.event_hook = func; 776} 777 778void 779route_map_init () 780{ 781 /* Make vector for match and set. */ 782 route_match_vec = vector_init (1); 783 route_set_vec = vector_init (1); 784} 785 786/* VTY related functions. */ 787DEFUN (route_map, 788 route_map_cmd, 789 "route-map WORD (deny|permit) <1-65535>", 790 "Create route-map or enter route-map command mode\n" 791 "Route map tag\n" 792 "Route map denies set operations\n" 793 "Route map permits set operations\n" 794 "Sequence to insert to/delete from existing route-map entry\n") 795{ 796 int permit; 797 unsigned long pref; 798 struct route_map *map; 799 struct route_map_index *index; 800 char *endptr = NULL; 801 802 /* Permit check. */ 803 if (strncmp (argv[1], "permit", strlen (argv[1])) == 0) 804 permit = RMAP_PERMIT; 805 else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0) 806 permit = RMAP_DENY; 807 else 808 { 809 vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE); 810 return CMD_WARNING; 811 } 812 813 /* Preference check. */ 814 pref = strtoul (argv[2], &endptr, 10); 815 if (pref == ULONG_MAX || *endptr != '\0') 816 { 817 vty_out (vty, "the fourth field must be positive integer%s", 818 VTY_NEWLINE); 819 return CMD_WARNING; 820 } 821 if (pref == 0 || pref > 65535) 822 { 823 vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE); 824 return CMD_WARNING; 825 } 826 827 /* Get route map. */ 828 map = route_map_get (argv[0]); 829 index = route_map_index_get (map, permit, pref); 830 831 vty->index = index; 832 vty->node = RMAP_NODE; 833 return CMD_SUCCESS; 834} 835 836DEFUN (no_route_map_all, 837 no_route_map_all_cmd, 838 "no route-map WORD", 839 NO_STR 840 "Create route-map or enter route-map command mode\n" 841 "Route map tag\n") 842{ 843 struct route_map *map; 844 845 map = route_map_lookup_by_name (argv[0]); 846 if (map == NULL) 847 { 848 vty_out (vty, "%% Could not find route-map %s%s", 849 argv[0], VTY_NEWLINE); 850 return CMD_WARNING; 851 } 852 853 route_map_delete (map); 854 855 return CMD_SUCCESS; 856} 857 858DEFUN (no_route_map, 859 no_route_map_cmd, 860 "no route-map WORD (deny|permit) <1-65535>", 861 NO_STR 862 "Create route-map or enter route-map command mode\n" 863 "Route map tag\n" 864 "Route map denies set operations\n" 865 "Route map permits set operations\n" 866 "Sequence to insert to/delete from existing route-map entry\n") 867{ 868 int permit; 869 unsigned long pref; 870 struct route_map *map; 871 struct route_map_index *index; 872 char *endptr = NULL; 873 874 /* Permit check. */ 875 if (strncmp (argv[1], "permit", strlen (argv[1])) == 0) 876 permit = RMAP_PERMIT; 877 else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0) 878 permit = RMAP_DENY; 879 else 880 { 881 vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE); 882 return CMD_WARNING; 883 } 884 885 /* Preference. */ 886 pref = strtoul (argv[2], &endptr, 10); 887 if (pref == ULONG_MAX || *endptr != '\0') 888 { 889 vty_out (vty, "the fourth field must be positive integer%s", 890 VTY_NEWLINE); 891 return CMD_WARNING; 892 } 893 if (pref == 0 || pref > 65535) 894 { 895 vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE); 896 return CMD_WARNING; 897 } 898 899 /* Existence check. */ 900 map = route_map_lookup_by_name (argv[0]); 901 if (map == NULL) 902 { 903 vty_out (vty, "%% Could not find route-map %s%s", 904 argv[0], VTY_NEWLINE); 905 return CMD_WARNING; 906 } 907 908 /* Lookup route map index. */ 909 index = route_map_index_lookup (map, permit, pref); 910 if (index == NULL) 911 { 912 vty_out (vty, "%% Could not find route-map entry %s %s%s", 913 argv[0], argv[2], VTY_NEWLINE); 914 return CMD_WARNING; 915 } 916 917 /* Delete index from route map. */ 918 route_map_index_delete (index, 1); 919 920 /* If this route rule is the last one, delete route map itself. */ 921 if (route_map_empty (map)) 922 route_map_delete (map); 923 924 return CMD_SUCCESS; 925} 926 927DEFUN (rmap_onmatch_next, 928 rmap_onmatch_next_cmd, 929 "on-match next", 930 "Exit policy on matches\n" 931 "Next clause\n") 932{ 933 struct route_map_index *index; 934 935 index = vty->index; 936 937 if (index) 938 index->exitpolicy = RMAP_NEXT; 939 940 return CMD_SUCCESS; 941} 942 943DEFUN (no_rmap_onmatch_next, 944 no_rmap_onmatch_next_cmd, 945 "no on-match next", 946 NO_STR 947 "Exit policy on matches\n" 948 "Next clause\n") 949{ 950 struct route_map_index *index; 951 952 index = vty->index; 953 954 if (index) 955 index->exitpolicy = RMAP_EXIT; 956 957 return CMD_SUCCESS; 958} 959 960DEFUN (rmap_onmatch_goto, 961 rmap_onmatch_goto_cmd, 962 "on-match goto <1-65535>", 963 "Exit policy on matches\n" 964 "Goto Clause number\n" 965 "Number\n") 966{ 967 struct route_map_index *index; 968 int d = 0; 969 970 if (argv[0]) 971 d = atoi(argv[0]); 972 973 index = vty->index; 974 if (index) 975 { 976 if (d <= index->pref) 977 { 978 /* Can't allow you to do that, Dave */ 979 vty_out (vty, "can't jump backwards in route-maps%s", 980 VTY_NEWLINE); 981 return CMD_WARNING; 982 } 983 else 984 { 985 index->exitpolicy = RMAP_GOTO; 986 index->nextpref = d; 987 } 988 } 989 return CMD_SUCCESS; 990} 991 992DEFUN (no_rmap_onmatch_goto, 993 no_rmap_onmatch_goto_cmd, 994 "no on-match goto", 995 NO_STR 996 "Exit policy on matches\n" 997 "Next clause\n") 998{ 999 struct route_map_index *index; 1000 1001 index = vty->index; 1002 1003 if (index) 1004 index->exitpolicy = RMAP_EXIT; 1005 1006 return CMD_SUCCESS; 1007} 1008 1009/* Configuration write function. */ 1010int 1011route_map_config_write (struct vty *vty) 1012{ 1013 struct route_map *map; 1014 struct route_map_index *index; 1015 struct route_map_rule *rule; 1016 int first = 1; 1017 int write = 0; 1018 1019 for (map = route_map_master.head; map; map = map->next) 1020 for (index = map->head; index; index = index->next) 1021 { 1022 if (!first) 1023 vty_out (vty, "!%s", VTY_NEWLINE); 1024 else 1025 first = 0; 1026 1027 vty_out (vty, "route-map %s %s %d%s", 1028 map->name, 1029 route_map_type_str (index->type), 1030 index->pref, VTY_NEWLINE); 1031 1032 for (rule = index->match_list.head; rule; rule = rule->next) 1033 vty_out (vty, " match %s %s%s", rule->cmd->str, 1034 rule->rule_str ? rule->rule_str : "", 1035 VTY_NEWLINE); 1036 1037 for (rule = index->set_list.head; rule; rule = rule->next) 1038 vty_out (vty, " set %s %s%s", rule->cmd->str, 1039 rule->rule_str ? rule->rule_str : "", 1040 VTY_NEWLINE); 1041 if (index->exitpolicy == RMAP_GOTO) 1042 vty_out (vty, " on-match goto %d%s", index->nextpref, 1043 VTY_NEWLINE); 1044 if (index->exitpolicy == RMAP_NEXT) 1045 vty_out (vty," on-match next%s", VTY_NEWLINE); 1046 1047 write++; 1048 } 1049 return write; 1050} 1051 1052/* Route map node structure. */ 1053struct cmd_node rmap_node = 1054{ 1055 RMAP_NODE, 1056 "%s(config-route-map)# ", 1057 1 1058}; 1059 1060/* Initialization of route map vector. */ 1061void 1062route_map_init_vty () 1063{ 1064 /* Install route map top node. */ 1065 install_node (&rmap_node, route_map_config_write); 1066 1067 /* Install route map commands. */ 1068 install_default (RMAP_NODE); 1069 install_element (CONFIG_NODE, &route_map_cmd); 1070 install_element (CONFIG_NODE, &no_route_map_cmd); 1071 install_element (CONFIG_NODE, &no_route_map_all_cmd); 1072 1073 /* Install the on-match stuff */ 1074 install_element (RMAP_NODE, &route_map_cmd); 1075 install_element (RMAP_NODE, &rmap_onmatch_next_cmd); 1076 install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd); 1077 install_element (RMAP_NODE, &rmap_onmatch_goto_cmd); 1078 install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd); 1079} 1080#endif /* FOX_LIST_SUPPORT */ 1081