1/* zebra routemap. 2 * Copyright (C) 2006 IBM Corporation 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 22#include <zebra.h> 23 24#include "memory.h" 25#include "prefix.h" 26#include "rib.h" 27#include "routemap.h" 28#include "command.h" 29#include "filter.h" 30#include "plist.h" 31 32#include "zebra/zserv.h" 33 34/* Add zebra route map rule */ 35static int 36zebra_route_match_add(struct vty *vty, struct route_map_index *index, 37 const char *command, const char *arg) 38{ 39 int ret; 40 41 ret = route_map_add_match (index, command, arg); 42 if (ret) 43 { 44 switch (ret) 45 { 46 case RMAP_RULE_MISSING: 47 vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); 48 return CMD_WARNING; 49 case RMAP_COMPILE_ERROR: 50 vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); 51 return CMD_WARNING; 52 } 53 } 54 return CMD_SUCCESS; 55} 56 57/* Delete zebra route map rule. */ 58static int 59zebra_route_match_delete (struct vty *vty, struct route_map_index *index, 60 const char *command, const char *arg) 61{ 62 int ret; 63 64 ret = route_map_delete_match (index, command, arg); 65 if (ret) 66 { 67 switch (ret) 68 { 69 case RMAP_RULE_MISSING: 70 vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); 71 return CMD_WARNING; 72 case RMAP_COMPILE_ERROR: 73 vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); 74 return CMD_WARNING; 75 } 76 } 77 return CMD_SUCCESS; 78} 79 80/* Add zebra route map rule. */ 81static int 82zebra_route_set_add (struct vty *vty, struct route_map_index *index, 83 const char *command, const char *arg) 84{ 85 int ret; 86 87 ret = route_map_add_set (index, command, arg); 88 if (ret) 89 { 90 switch (ret) 91 { 92 case RMAP_RULE_MISSING: 93 vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); 94 return CMD_WARNING; 95 case RMAP_COMPILE_ERROR: 96 vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); 97 return CMD_WARNING; 98 } 99 } 100 return CMD_SUCCESS; 101} 102 103/* Delete zebra route map rule. */ 104static int 105zebra_route_set_delete (struct vty *vty, struct route_map_index *index, 106 const char *command, const char *arg) 107{ 108 int ret; 109 110 ret = route_map_delete_set (index, command, arg); 111 if (ret) 112 { 113 switch (ret) 114 { 115 case RMAP_RULE_MISSING: 116 vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); 117 return CMD_WARNING; 118 case RMAP_COMPILE_ERROR: 119 vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); 120 return CMD_WARNING; 121 } 122 } 123 return CMD_SUCCESS; 124} 125 126 127/* `match interface IFNAME' */ 128/* Match function return 1 if match is success else return zero. */ 129static route_map_result_t 130route_match_interface (void *rule, struct prefix *prefix, 131 route_map_object_t type, void *object) 132{ 133 struct nexthop *nexthop; 134 char *ifname = rule; 135 unsigned int ifindex; 136 137 if (type == RMAP_ZEBRA) 138 { 139 if (strcasecmp(ifname, "any") == 0) 140 return RMAP_MATCH; 141 ifindex = ifname2ifindex(ifname); 142 if (ifindex == 0) 143 return RMAP_NOMATCH; 144 nexthop = object; 145 if (!nexthop) 146 return RMAP_NOMATCH; 147 if (nexthop->ifindex == ifindex) 148 return RMAP_MATCH; 149 } 150 return RMAP_NOMATCH; 151} 152 153/* Route map `match interface' match statement. `arg' is IFNAME value */ 154static void * 155route_match_interface_compile (const char *arg) 156{ 157 return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); 158} 159 160/* Free route map's compiled `match interface' value. */ 161static void 162route_match_interface_free (void *rule) 163{ 164 XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); 165} 166 167/* Route map commands for interface matching */ 168struct route_map_rule_cmd route_match_interface_cmd = 169{ 170 "interface", 171 route_match_interface, 172 route_match_interface_compile, 173 route_match_interface_free 174}; 175 176DEFUN (match_interface, 177 match_interface_cmd, 178 "match interface WORD", 179 MATCH_STR 180 "match first hop interface of route\n" 181 "Interface name\n") 182{ 183 return zebra_route_match_add (vty, vty->index, "interface", argv[0]); 184} 185 186DEFUN (no_match_interface, 187 no_match_interface_cmd, 188 "no match interface", 189 NO_STR 190 MATCH_STR 191 "Match first hop interface of route\n") 192{ 193 if (argc == 0) 194 return zebra_route_match_delete (vty, vty->index, "interface", NULL); 195 196 return zebra_route_match_delete (vty, vty->index, "interface", argv[0]); 197} 198 199ALIAS (no_match_interface, 200 no_match_interface_val_cmd, 201 "no match interface WORD", 202 NO_STR 203 MATCH_STR 204 "Match first hop interface of route\n" 205 "Interface name\n") 206 207DEFUN (match_ip_next_hop, 208 match_ip_next_hop_cmd, 209 "match ip next-hop (<1-199>|<1300-2699>|WORD)", 210 MATCH_STR 211 IP_STR 212 "Match next-hop address of route\n" 213 "IP access-list number\n" 214 "IP access-list number (expanded range)\n" 215 "IP Access-list name\n") 216{ 217 return zebra_route_match_add (vty, vty->index, "ip next-hop", argv[0]); 218} 219 220DEFUN (no_match_ip_next_hop, 221 no_match_ip_next_hop_cmd, 222 "no match ip next-hop", 223 NO_STR 224 MATCH_STR 225 IP_STR 226 "Match next-hop address of route\n") 227{ 228 if (argc == 0) 229 return zebra_route_match_delete (vty, vty->index, "ip next-hop", NULL); 230 231 return zebra_route_match_delete (vty, vty->index, "ip next-hop", argv[0]); 232} 233 234ALIAS (no_match_ip_next_hop, 235 no_match_ip_next_hop_val_cmd, 236 "no match ip next-hop (<1-199>|<1300-2699>|WORD)", 237 NO_STR 238 MATCH_STR 239 IP_STR 240 "Match next-hop address of route\n" 241 "IP access-list number\n" 242 "IP access-list number (expanded range)\n" 243 "IP Access-list name\n") 244 245DEFUN (match_ip_next_hop_prefix_list, 246 match_ip_next_hop_prefix_list_cmd, 247 "match ip next-hop prefix-list WORD", 248 MATCH_STR 249 IP_STR 250 "Match next-hop address of route\n" 251 "Match entries of prefix-lists\n" 252 "IP prefix-list name\n") 253{ 254 return zebra_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]); 255} 256 257DEFUN (no_match_ip_next_hop_prefix_list, 258 no_match_ip_next_hop_prefix_list_cmd, 259 "no match ip next-hop prefix-list", 260 NO_STR 261 MATCH_STR 262 IP_STR 263 "Match next-hop address of route\n" 264 "Match entries of prefix-lists\n") 265{ 266 if (argc == 0) 267 return zebra_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL); 268 269 return zebra_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]); 270} 271 272ALIAS (no_match_ip_next_hop_prefix_list, 273 no_match_ip_next_hop_prefix_list_val_cmd, 274 "no match ip next-hop prefix-list WORD", 275 NO_STR 276 MATCH_STR 277 IP_STR 278 "Match next-hop address of route\n" 279 "Match entries of prefix-lists\n" 280 "IP prefix-list name\n") 281 282DEFUN (match_ip_address, 283 match_ip_address_cmd, 284 "match ip address (<1-199>|<1300-2699>|WORD)", 285 MATCH_STR 286 IP_STR 287 "Match address of route\n" 288 "IP access-list number\n" 289 "IP access-list number (expanded range)\n" 290 "IP Access-list name\n") 291 292{ 293 return zebra_route_match_add (vty, vty->index, "ip address", argv[0]); 294} 295 296DEFUN (no_match_ip_address, 297 no_match_ip_address_cmd, 298 "no match ip address", 299 NO_STR 300 MATCH_STR 301 IP_STR 302 "Match address of route\n") 303{ 304 if (argc == 0) 305 return zebra_route_match_delete (vty, vty->index, "ip address", NULL); 306 307 return zebra_route_match_delete (vty, vty->index, "ip address", argv[0]); 308} 309 310ALIAS (no_match_ip_address, 311 no_match_ip_address_val_cmd, 312 "no match ip address (<1-199>|<1300-2699>|WORD)", 313 NO_STR 314 MATCH_STR 315 IP_STR 316 "Match address of route\n" 317 "IP access-list number\n" 318 "IP access-list number (expanded range)\n" 319 "IP Access-list name\n") 320 321DEFUN (match_ip_address_prefix_list, 322 match_ip_address_prefix_list_cmd, 323 "match ip address prefix-list WORD", 324 MATCH_STR 325 IP_STR 326 "Match address of route\n" 327 "Match entries of prefix-lists\n" 328 "IP prefix-list name\n") 329{ 330 return zebra_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]); 331} 332 333DEFUN (no_match_ip_address_prefix_list, 334 no_match_ip_address_prefix_list_cmd, 335 "no match ip address prefix-list", 336 NO_STR 337 MATCH_STR 338 IP_STR 339 "Match address of route\n" 340 "Match entries of prefix-lists\n") 341{ 342 if (argc == 0) 343 return zebra_route_match_delete (vty, vty->index, "ip address prefix-list", NULL); 344 345 return zebra_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]); 346} 347 348ALIAS (no_match_ip_address_prefix_list, 349 no_match_ip_address_prefix_list_val_cmd, 350 "no match ip address prefix-list WORD", 351 NO_STR 352 MATCH_STR 353 IP_STR 354 "Match address of route\n" 355 "Match entries of prefix-lists\n" 356 "IP prefix-list name\n") 357 358/* set functions */ 359 360DEFUN (set_src, 361 set_src_cmd, 362 "set src A.B.C.D", 363 SET_STR 364 "src address for route\n" 365 "src address\n") 366{ 367 struct in_addr src; 368 struct interface *pif; 369 370 if (inet_pton(AF_INET, argv[0], &src) <= 0) 371 { 372 vty_out (vty, "%% not a local address%s", VTY_NEWLINE); 373 return CMD_WARNING; 374 } 375 376 pif = if_lookup_exact_address (src); 377 if (!pif) 378 { 379 vty_out (vty, "%% not a local address%s", VTY_NEWLINE); 380 return CMD_WARNING; 381 } 382 return zebra_route_set_add (vty, vty->index, "src", argv[0]); 383} 384 385DEFUN (no_set_src, 386 no_set_src_cmd, 387 "no set src", 388 NO_STR 389 SET_STR 390 "Source address for route\n") 391{ 392 if (argc == 0) 393 return zebra_route_set_delete (vty, vty->index, "src", NULL); 394 395 return zebra_route_set_delete (vty, vty->index, "src", argv[0]); 396} 397 398ALIAS (no_set_src, 399 no_set_src_val_cmd, 400 "no set src (A.B.C.D)", 401 NO_STR 402 SET_STR 403 "src address for route\n" 404 "src address\n") 405 406/*XXXXXXXXXXXXXXXXXXXXXXXXXXXX*/ 407 408/* `match ip next-hop IP_ACCESS_LIST' */ 409 410/* Match function return 1 if match is success else return zero. */ 411static route_map_result_t 412route_match_ip_next_hop (void *rule, struct prefix *prefix, 413 route_map_object_t type, void *object) 414{ 415 struct access_list *alist; 416 struct nexthop *nexthop; 417 struct prefix_ipv4 p; 418 419 if (type == RMAP_ZEBRA) 420 { 421 nexthop = object; 422 switch (nexthop->type) { 423 case NEXTHOP_TYPE_IFINDEX: 424 case NEXTHOP_TYPE_IFNAME: 425 /* Interface routes can't match ip next-hop */ 426 return RMAP_NOMATCH; 427 case NEXTHOP_TYPE_IPV4_IFINDEX: 428 case NEXTHOP_TYPE_IPV4_IFNAME: 429 case NEXTHOP_TYPE_IPV4: 430 p.family = AF_INET; 431 p.prefix = nexthop->gate.ipv4; 432 p.prefixlen = IPV4_MAX_BITLEN; 433 break; 434 default: 435 return RMAP_NOMATCH; 436 } 437 alist = access_list_lookup (AFI_IP, (char *) rule); 438 if (alist == NULL) 439 return RMAP_NOMATCH; 440 441 return (access_list_apply (alist, &p) == FILTER_DENY ? 442 RMAP_NOMATCH : RMAP_MATCH); 443 } 444 return RMAP_NOMATCH; 445} 446 447/* Route map `ip next-hop' match statement. `arg' should be 448 access-list name. */ 449static void * 450route_match_ip_next_hop_compile (const char *arg) 451{ 452 return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); 453} 454 455/* Free route map's compiled `. */ 456static void 457route_match_ip_next_hop_free (void *rule) 458{ 459 XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); 460} 461 462/* Route map commands for ip next-hop matching. */ 463static struct route_map_rule_cmd route_match_ip_next_hop_cmd = 464{ 465 "ip next-hop", 466 route_match_ip_next_hop, 467 route_match_ip_next_hop_compile, 468 route_match_ip_next_hop_free 469}; 470 471/* `match ip next-hop prefix-list PREFIX_LIST' */ 472 473static route_map_result_t 474route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix, 475 route_map_object_t type, void *object) 476{ 477 struct prefix_list *plist; 478 struct nexthop *nexthop; 479 struct prefix_ipv4 p; 480 481 if (type == RMAP_ZEBRA) 482 { 483 nexthop = object; 484 switch (nexthop->type) { 485 case NEXTHOP_TYPE_IFINDEX: 486 case NEXTHOP_TYPE_IFNAME: 487 /* Interface routes can't match ip next-hop */ 488 return RMAP_NOMATCH; 489 case NEXTHOP_TYPE_IPV4_IFINDEX: 490 case NEXTHOP_TYPE_IPV4_IFNAME: 491 case NEXTHOP_TYPE_IPV4: 492 p.family = AF_INET; 493 p.prefix = nexthop->gate.ipv4; 494 p.prefixlen = IPV4_MAX_BITLEN; 495 break; 496 default: 497 return RMAP_NOMATCH; 498 } 499 plist = prefix_list_lookup (AFI_IP, (char *) rule); 500 if (plist == NULL) 501 return RMAP_NOMATCH; 502 503 return (prefix_list_apply (plist, &p) == PREFIX_DENY ? 504 RMAP_NOMATCH : RMAP_MATCH); 505 } 506 return RMAP_NOMATCH; 507} 508 509static void * 510route_match_ip_next_hop_prefix_list_compile (const char *arg) 511{ 512 return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); 513} 514 515static void 516route_match_ip_next_hop_prefix_list_free (void *rule) 517{ 518 XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); 519} 520 521static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = 522{ 523 "ip next-hop prefix-list", 524 route_match_ip_next_hop_prefix_list, 525 route_match_ip_next_hop_prefix_list_compile, 526 route_match_ip_next_hop_prefix_list_free 527}; 528 529/* `match ip address IP_ACCESS_LIST' */ 530 531/* Match function should return 1 if match is success else return 532 zero. */ 533static route_map_result_t 534route_match_ip_address (void *rule, struct prefix *prefix, 535 route_map_object_t type, void *object) 536{ 537 struct access_list *alist; 538 539 if (type == RMAP_ZEBRA) 540 { 541 alist = access_list_lookup (AFI_IP, (char *) rule); 542 if (alist == NULL) 543 return RMAP_NOMATCH; 544 545 return (access_list_apply (alist, prefix) == FILTER_DENY ? 546 RMAP_NOMATCH : RMAP_MATCH); 547 } 548 return RMAP_NOMATCH; 549} 550 551/* Route map `ip address' match statement. `arg' should be 552 access-list name. */ 553static void * 554route_match_ip_address_compile (const char *arg) 555{ 556 return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); 557} 558 559/* Free route map's compiled `ip address' value. */ 560static void 561route_match_ip_address_free (void *rule) 562{ 563 XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); 564} 565 566/* Route map commands for ip address matching. */ 567static struct route_map_rule_cmd route_match_ip_address_cmd = 568{ 569 "ip address", 570 route_match_ip_address, 571 route_match_ip_address_compile, 572 route_match_ip_address_free 573}; 574 575/* `match ip address prefix-list PREFIX_LIST' */ 576 577static route_map_result_t 578route_match_ip_address_prefix_list (void *rule, struct prefix *prefix, 579 route_map_object_t type, void *object) 580{ 581 struct prefix_list *plist; 582 583 if (type == RMAP_ZEBRA) 584 { 585 plist = prefix_list_lookup (AFI_IP, (char *) rule); 586 if (plist == NULL) 587 return RMAP_NOMATCH; 588 589 return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? 590 RMAP_NOMATCH : RMAP_MATCH); 591 } 592 return RMAP_NOMATCH; 593} 594 595static void * 596route_match_ip_address_prefix_list_compile (const char *arg) 597{ 598 return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); 599} 600 601static void 602route_match_ip_address_prefix_list_free (void *rule) 603{ 604 XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); 605} 606 607static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = 608{ 609 "ip address prefix-list", 610 route_match_ip_address_prefix_list, 611 route_match_ip_address_prefix_list_compile, 612 route_match_ip_address_prefix_list_free 613}; 614 615 616/* `set src A.B.C.D' */ 617 618/* Set src. */ 619static route_map_result_t 620route_set_src (void *rule, struct prefix *prefix, 621 route_map_object_t type, void *object) 622{ 623 if (type == RMAP_ZEBRA) 624 { 625 struct nexthop *nexthop; 626 627 nexthop = object; 628 nexthop->src = *(union g_addr *)rule; 629 } 630 return RMAP_OKAY; 631} 632 633/* set src compilation. */ 634static void * 635route_set_src_compile (const char *arg) 636{ 637 union g_addr src, *psrc; 638 639 if (inet_pton(AF_INET, arg, &src.ipv4) != 1 640#ifdef HAVE_IPV6 641 && inet_pton(AF_INET6, arg, &src.ipv6) != 1 642#endif /* HAVE_IPV6 */ 643 ) 644 return NULL; 645 646 psrc = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (union g_addr)); 647 *psrc = src; 648 649 return psrc; 650} 651 652/* Free route map's compiled `set src' value. */ 653static void 654route_set_src_free (void *rule) 655{ 656 XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); 657} 658 659/* Set src rule structure. */ 660static struct route_map_rule_cmd route_set_src_cmd = 661{ 662 "src", 663 route_set_src, 664 route_set_src_compile, 665 route_set_src_free, 666}; 667 668void 669zebra_route_map_init () 670{ 671 route_map_init (); 672 route_map_init_vty (); 673 674 route_map_install_match (&route_match_interface_cmd); 675 route_map_install_match (&route_match_ip_next_hop_cmd); 676 route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd); 677 route_map_install_match (&route_match_ip_address_cmd); 678 route_map_install_match (&route_match_ip_address_prefix_list_cmd); 679/* */ 680 route_map_install_set (&route_set_src_cmd); 681/* */ 682 install_element (RMAP_NODE, &match_interface_cmd); 683 install_element (RMAP_NODE, &no_match_interface_cmd); 684 install_element (RMAP_NODE, &no_match_interface_val_cmd); 685 install_element (RMAP_NODE, &match_ip_next_hop_cmd); 686 install_element (RMAP_NODE, &no_match_ip_next_hop_cmd); 687 install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd); 688 install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd); 689 install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd); 690 install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd); 691 install_element (RMAP_NODE, &match_ip_address_cmd); 692 install_element (RMAP_NODE, &no_match_ip_address_cmd); 693 install_element (RMAP_NODE, &no_match_ip_address_val_cmd); 694 install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd); 695 install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd); 696 install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd); 697/* */ 698 install_element (RMAP_NODE, &set_src_cmd); 699 install_element (RMAP_NODE, &no_set_src_cmd); 700} 701