1/* Distribute list functions 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 7 * it under the terms of the GNU General Public License as published 8 * by the Free Software Foundation; either version 2, or (at your 9 * option) any 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 18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 * Boston, MA 02111-1307, USA. 20 */ 21 22#include <zebra.h> 23 24#include "hash.h" 25#include "if.h" 26#include "filter.h" 27#include "command.h" 28#include "distribute.h" 29#include "memory.h" 30 31/* Hash of distribute list. */ 32struct hash *disthash; 33 34/* Hook functions. */ 35void (*distribute_add_hook) (struct distribute *); 36void (*distribute_delete_hook) (struct distribute *); 37 38struct distribute * 39distribute_new () 40{ 41 struct distribute *new; 42 43 new = XMALLOC (MTYPE_DISTRIBUTE, sizeof (struct distribute)); 44 memset (new, 0, sizeof (struct distribute)); 45 46 return new; 47} 48 49/* Free distribute object. */ 50void 51distribute_free (struct distribute *dist) 52{ 53 if (dist->ifname) 54 free (dist->ifname); 55 56 if (dist->list[DISTRIBUTE_IN]) 57 free (dist->list[DISTRIBUTE_IN]); 58 if (dist->list[DISTRIBUTE_OUT]) 59 free (dist->list[DISTRIBUTE_OUT]); 60 61 if (dist->prefix[DISTRIBUTE_IN]) 62 free (dist->prefix[DISTRIBUTE_IN]); 63 if (dist->prefix[DISTRIBUTE_OUT]) 64 free (dist->prefix[DISTRIBUTE_OUT]); 65 66 XFREE (MTYPE_DISTRIBUTE, dist); 67} 68 69/* Lookup interface's distribute list. */ 70struct distribute * 71distribute_lookup (char *ifname) 72{ 73 struct distribute key; 74 struct distribute *dist; 75 76 key.ifname = ifname; 77 78 dist = hash_lookup (disthash, &key); 79 80 return dist; 81} 82 83void 84distribute_list_add_hook (void (*func) (struct distribute *)) 85{ 86 distribute_add_hook = func; 87} 88 89void 90distribute_list_delete_hook (void (*func) (struct distribute *)) 91{ 92 distribute_delete_hook = func; 93} 94 95void * 96distribute_hash_alloc (struct distribute *arg) 97{ 98 struct distribute *dist; 99 100 dist = distribute_new (); 101 if (arg->ifname) 102 dist->ifname = strdup (arg->ifname); 103 else 104 dist->ifname = NULL; 105 return dist; 106} 107 108/* Make new distribute list and push into hash. */ 109struct distribute * 110distribute_get (char *ifname) 111{ 112 struct distribute key; 113 114 key.ifname = ifname; 115 116 return hash_get (disthash, &key, distribute_hash_alloc); 117} 118 119unsigned int 120distribute_hash_make (struct distribute *dist) 121{ 122 unsigned int key; 123 int i; 124 125 key = 0; 126 if (dist->ifname) 127 for (i = 0; i < strlen (dist->ifname); i++) 128 key += dist->ifname[i]; 129 130 return key; 131} 132 133/* If two distribute-list have same value then return 1 else return 134 0. This function is used by hash package. */ 135int 136distribute_cmp (struct distribute *dist1, struct distribute *dist2) 137{ 138 if (dist1->ifname && dist2->ifname) 139 if (strcmp (dist1->ifname, dist2->ifname) == 0) 140 return 1; 141 if (! dist1->ifname && ! dist2->ifname) 142 return 1; 143 return 0; 144} 145 146/* Set access-list name to the distribute list. */ 147struct distribute * 148distribute_list_set (char *ifname, enum distribute_type type, char *alist_name) 149{ 150 struct distribute *dist; 151 152 dist = distribute_get (ifname); 153 154 if (type == DISTRIBUTE_IN) 155 { 156 if (dist->list[DISTRIBUTE_IN]) 157 free (dist->list[DISTRIBUTE_IN]); 158 dist->list[DISTRIBUTE_IN] = strdup (alist_name); 159 } 160 if (type == DISTRIBUTE_OUT) 161 { 162 if (dist->list[DISTRIBUTE_OUT]) 163 free (dist->list[DISTRIBUTE_OUT]); 164 dist->list[DISTRIBUTE_OUT] = strdup (alist_name); 165 } 166 167 /* Apply this distribute-list to the interface. */ 168 (*distribute_add_hook) (dist); 169 170 return dist; 171} 172 173/* Unset distribute-list. If matched distribute-list exist then 174 return 1. */ 175int 176distribute_list_unset (char *ifname, enum distribute_type type, 177 char *alist_name) 178{ 179 struct distribute *dist; 180 181 dist = distribute_lookup (ifname); 182 if (!dist) 183 return 0; 184 185 if (type == DISTRIBUTE_IN) 186 { 187 if (!dist->list[DISTRIBUTE_IN]) 188 return 0; 189 if (strcmp (dist->list[DISTRIBUTE_IN], alist_name) != 0) 190 return 0; 191 192 free (dist->list[DISTRIBUTE_IN]); 193 dist->list[DISTRIBUTE_IN] = NULL; 194 } 195 196 if (type == DISTRIBUTE_OUT) 197 { 198 if (!dist->list[DISTRIBUTE_OUT]) 199 return 0; 200 if (strcmp (dist->list[DISTRIBUTE_OUT], alist_name) != 0) 201 return 0; 202 203 free (dist->list[DISTRIBUTE_OUT]); 204 dist->list[DISTRIBUTE_OUT] = NULL; 205 } 206 207 /* Apply this distribute-list to the interface. */ 208 (*distribute_delete_hook) (dist); 209 210 /* If both out and in is NULL then free distribute list. */ 211 if (dist->list[DISTRIBUTE_IN] == NULL && 212 dist->list[DISTRIBUTE_OUT] == NULL && 213 dist->prefix[DISTRIBUTE_IN] == NULL && 214 dist->prefix[DISTRIBUTE_OUT] == NULL) 215 { 216 hash_release (disthash, dist); 217 distribute_free (dist); 218 } 219 220 return 1; 221} 222 223#ifdef FOX_CMD_SUPPORT 224/* Set access-list name to the distribute list. */ 225struct distribute * 226distribute_list_prefix_set (char *ifname, enum distribute_type type, 227 char *plist_name) 228{ 229 struct distribute *dist; 230 231 dist = distribute_get (ifname); 232 233 if (type == DISTRIBUTE_IN) 234 { 235 if (dist->prefix[DISTRIBUTE_IN]) 236 free (dist->prefix[DISTRIBUTE_IN]); 237 dist->prefix[DISTRIBUTE_IN] = strdup (plist_name); 238 } 239 if (type == DISTRIBUTE_OUT) 240 { 241 if (dist->prefix[DISTRIBUTE_OUT]) 242 free (dist->prefix[DISTRIBUTE_OUT]); 243 dist->prefix[DISTRIBUTE_OUT] = strdup (plist_name); 244 } 245 246 /* Apply this distribute-list to the interface. */ 247 (*distribute_add_hook) (dist); 248 249 return dist; 250} 251 252/* Unset distribute-list. If matched distribute-list exist then 253 return 1. */ 254int 255distribute_list_prefix_unset (char *ifname, enum distribute_type type, 256 char *plist_name) 257{ 258 struct distribute *dist; 259 260 dist = distribute_lookup (ifname); 261 if (!dist) 262 return 0; 263 264 if (type == DISTRIBUTE_IN) 265 { 266 if (!dist->prefix[DISTRIBUTE_IN]) 267 return 0; 268 if (strcmp (dist->prefix[DISTRIBUTE_IN], plist_name) != 0) 269 return 0; 270 271 free (dist->prefix[DISTRIBUTE_IN]); 272 dist->prefix[DISTRIBUTE_IN] = NULL; 273 } 274 275 if (type == DISTRIBUTE_OUT) 276 { 277 if (!dist->prefix[DISTRIBUTE_OUT]) 278 return 0; 279 if (strcmp (dist->prefix[DISTRIBUTE_OUT], plist_name) != 0) 280 return 0; 281 282 free (dist->prefix[DISTRIBUTE_OUT]); 283 dist->prefix[DISTRIBUTE_OUT] = NULL; 284 } 285 286 /* Apply this distribute-list to the interface. */ 287 (*distribute_delete_hook) (dist); 288 289 /* If both out and in is NULL then free distribute list. */ 290 if (dist->list[DISTRIBUTE_IN] == NULL && 291 dist->list[DISTRIBUTE_OUT] == NULL && 292 dist->prefix[DISTRIBUTE_IN] == NULL && 293 dist->prefix[DISTRIBUTE_OUT] == NULL) 294 { 295 hash_release (disthash, dist); 296 distribute_free (dist); 297 } 298 299 return 1; 300} 301 302DEFUN (distribute_list_all, 303 distribute_list_all_cmd, 304 "distribute-list WORD (in|out)", 305 "Filter networks in routing updates\n" 306 "Access-list name\n" 307 "Filter incoming routing updates\n" 308 "Filter outgoing routing updates\n") 309{ 310 enum distribute_type type; 311 struct distribute *dist; 312 313 /* Check of distribute list type. */ 314 if (strncmp (argv[1], "i", 1) == 0) 315 type = DISTRIBUTE_IN; 316 else if (strncmp (argv[1], "o", 1) == 0) 317 type = DISTRIBUTE_OUT; 318 else 319 { 320 vty_out (vty, "distribute list direction must be [in|out]%s", 321 VTY_NEWLINE); 322 return CMD_WARNING; 323 } 324 325 /* Get interface name corresponding distribute list. */ 326 dist = distribute_list_set (NULL, type, argv[0]); 327 328 return CMD_SUCCESS; 329} 330 331DEFUN (no_distribute_list_all, 332 no_distribute_list_all_cmd, 333 "no distribute-list WORD (in|out)", 334 NO_STR 335 "Filter networks in routing updates\n" 336 "Access-list name\n" 337 "Filter incoming routing updates\n" 338 "Filter outgoing routing updates\n") 339{ 340 int ret; 341 enum distribute_type type; 342 343 /* Check of distribute list type. */ 344 if (strncmp (argv[1], "i", 1) == 0) 345 type = DISTRIBUTE_IN; 346 else if (strncmp (argv[1], "o", 1) == 0) 347 type = DISTRIBUTE_OUT; 348 else 349 { 350 vty_out (vty, "distribute list direction must be [in|out]%s", 351 VTY_NEWLINE); 352 return CMD_WARNING; 353 } 354 355 ret = distribute_list_unset (NULL, type, argv[0]); 356 if (! ret) 357 { 358 vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE); 359 return CMD_WARNING; 360 } 361 return CMD_SUCCESS; 362} 363#endif /* FOX_CMD_SUPPORT */ 364 365DEFUN (distribute_list, 366 distribute_list_cmd, 367 "distribute-list WORD (in|out) WORD", 368 "Filter networks in routing updates\n" 369 "Access-list name\n" 370 "Filter incoming routing updates\n" 371 "Filter outgoing routing updates\n" 372 "Interface name\n") 373{ 374 enum distribute_type type; 375 struct distribute *dist; 376 377 /* Check of distribute list type. */ 378 if (strncmp (argv[1], "i", 1) == 0) 379 type = DISTRIBUTE_IN; 380 else if (strncmp (argv[1], "o", 1) == 0) 381 type = DISTRIBUTE_OUT; 382 else 383 { 384 vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); 385 return CMD_WARNING; 386 } 387 388 /* Get interface name corresponding distribute list. */ 389 dist = distribute_list_set (argv[2], type, argv[0]); 390 391 return CMD_SUCCESS; 392} 393 394DEFUN (no_districute_list, no_distribute_list_cmd, 395 "no distribute-list WORD (in|out) WORD", 396 NO_STR 397 "Filter networks in routing updates\n" 398 "Access-list name\n" 399 "Filter incoming routing updates\n" 400 "Filter outgoing routing updates\n" 401 "Interface name\n") 402{ 403 int ret; 404 enum distribute_type type; 405 406 /* Check of distribute list type. */ 407 if (strncmp (argv[1], "i", 1) == 0) 408 type = DISTRIBUTE_IN; 409 else if (strncmp (argv[1], "o", 1) == 0) 410 type = DISTRIBUTE_OUT; 411 else 412 { 413 vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE); 414 return CMD_WARNING; 415 } 416 417 ret = distribute_list_unset (argv[2], type, argv[0]); 418 if (! ret) 419 { 420 vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE); 421 return CMD_WARNING; 422 } 423 return CMD_SUCCESS; 424} 425 426#ifdef FOX_CMD_SUPPORT 427DEFUN (districute_list_prefix_all, 428 distribute_list_prefix_all_cmd, 429 "distribute-list prefix WORD (in|out)", 430 "Filter networks in routing updates\n" 431 "Filter prefixes in routing updates\n" 432 "Name of an IP prefix-list\n" 433 "Filter incoming routing updates\n" 434 "Filter outgoing routing updates\n") 435{ 436 enum distribute_type type; 437 struct distribute *dist; 438 439 /* Check of distribute list type. */ 440 if (strncmp (argv[1], "i", 1) == 0) 441 type = DISTRIBUTE_IN; 442 else if (strncmp (argv[1], "o", 1) == 0) 443 type = DISTRIBUTE_OUT; 444 else 445 { 446 vty_out (vty, "distribute list direction must be [in|out]%s", 447 VTY_NEWLINE); 448 return CMD_WARNING; 449 } 450 451 /* Get interface name corresponding distribute list. */ 452 dist = distribute_list_prefix_set (NULL, type, argv[0]); 453 454 return CMD_SUCCESS; 455} 456 457DEFUN (no_districute_list_prefix_all, 458 no_distribute_list_prefix_all_cmd, 459 "no distribute-list prefix WORD (in|out)", 460 NO_STR 461 "Filter networks in routing updates\n" 462 "Filter prefixes in routing updates\n" 463 "Name of an IP prefix-list\n" 464 "Filter incoming routing updates\n" 465 "Filter outgoing routing updates\n") 466{ 467 int ret; 468 enum distribute_type type; 469 470 /* Check of distribute list type. */ 471 if (strncmp (argv[1], "i", 1) == 0) 472 type = DISTRIBUTE_IN; 473 else if (strncmp (argv[1], "o", 1) == 0) 474 type = DISTRIBUTE_OUT; 475 else 476 { 477 vty_out (vty, "distribute list direction must be [in|out]%s", 478 VTY_NEWLINE); 479 return CMD_WARNING; 480 } 481 482 ret = distribute_list_prefix_unset (NULL, type, argv[0]); 483 if (! ret) 484 { 485 vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE); 486 return CMD_WARNING; 487 } 488 return CMD_SUCCESS; 489} 490 491DEFUN (districute_list_prefix, distribute_list_prefix_cmd, 492 "distribute-list prefix WORD (in|out) WORD", 493 "Filter networks in routing updates\n" 494 "Filter prefixes in routing updates\n" 495 "Name of an IP prefix-list\n" 496 "Filter incoming routing updates\n" 497 "Filter outgoing routing updates\n" 498 "Interface name\n") 499{ 500 enum distribute_type type; 501 struct distribute *dist; 502 503 /* Check of distribute list type. */ 504 if (strncmp (argv[1], "i", 1) == 0) 505 type = DISTRIBUTE_IN; 506 else if (strncmp (argv[1], "o", 1) == 0) 507 type = DISTRIBUTE_OUT; 508 else 509 { 510 vty_out (vty, "distribute list direction must be [in|out]%s", 511 VTY_NEWLINE); 512 return CMD_WARNING; 513 } 514 515 /* Get interface name corresponding distribute list. */ 516 dist = distribute_list_prefix_set (argv[2], type, argv[0]); 517 518 return CMD_SUCCESS; 519} 520 521DEFUN (no_districute_list_prefix, no_distribute_list_prefix_cmd, 522 "no distribute-list prefix WORD (in|out) WORD", 523 NO_STR 524 "Filter networks in routing updates\n" 525 "Filter prefixes in routing updates\n" 526 "Name of an IP prefix-list\n" 527 "Filter incoming routing updates\n" 528 "Filter outgoing routing updates\n" 529 "Interface name\n") 530{ 531 int ret; 532 enum distribute_type type; 533 534 /* Check of distribute list type. */ 535 if (strncmp (argv[1], "i", 1) == 0) 536 type = DISTRIBUTE_IN; 537 else if (strncmp (argv[1], "o", 1) == 0) 538 type = DISTRIBUTE_OUT; 539 else 540 { 541 vty_out (vty, "distribute list direction must be [in|out]%s", 542 VTY_NEWLINE); 543 return CMD_WARNING; 544 } 545 546 ret = distribute_list_prefix_unset (argv[2], type, argv[0]); 547 if (! ret) 548 { 549 vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE); 550 return CMD_WARNING; 551 } 552 return CMD_SUCCESS; 553} 554#endif /* FOX_CMD_SUPPORT */ 555 556int 557config_show_distribute (struct vty *vty) 558{ 559 int i; 560 struct hash_backet *mp; 561 struct distribute *dist; 562 563 /* Output filter configuration. */ 564 dist = distribute_lookup (NULL); 565 if (dist && (dist->list[DISTRIBUTE_OUT] || dist->prefix[DISTRIBUTE_OUT])) 566 { 567 vty_out (vty, " Outgoing update filter list for all interface is"); 568 if (dist->list[DISTRIBUTE_OUT]) 569 vty_out (vty, " %s", dist->list[DISTRIBUTE_OUT]); 570 if (dist->prefix[DISTRIBUTE_OUT]) 571 vty_out (vty, "%s (prefix-list) %s", 572 dist->list[DISTRIBUTE_OUT] ? "," : "", 573 dist->prefix[DISTRIBUTE_OUT]); 574 vty_out (vty, "%s", VTY_NEWLINE); 575 } 576 else 577 vty_out (vty, " Outgoing update filter list for all interface is not set%s", VTY_NEWLINE); 578 579 for (i = 0; i < disthash->size; i++) 580 for (mp = disthash->index[i]; mp; mp = mp->next) 581 { 582 dist = mp->data; 583 if (dist->ifname) 584 if (dist->list[DISTRIBUTE_OUT] || dist->prefix[DISTRIBUTE_OUT]) 585 { 586 vty_out (vty, " %s filtered by", dist->ifname); 587 if (dist->list[DISTRIBUTE_OUT]) 588 vty_out (vty, " %s", dist->list[DISTRIBUTE_OUT]); 589 if (dist->prefix[DISTRIBUTE_OUT]) 590 vty_out (vty, "%s (prefix-list) %s", 591 dist->list[DISTRIBUTE_OUT] ? "," : "", 592 dist->prefix[DISTRIBUTE_OUT]); 593 vty_out (vty, "%s", VTY_NEWLINE); 594 } 595 } 596 597 598 /* Input filter configuration. */ 599 dist = distribute_lookup (NULL); 600 if (dist && (dist->list[DISTRIBUTE_IN] || dist->prefix[DISTRIBUTE_IN])) 601 { 602 vty_out (vty, " Incoming update filter list for all interface is"); 603 if (dist->list[DISTRIBUTE_IN]) 604 vty_out (vty, " %s", dist->list[DISTRIBUTE_IN]); 605 if (dist->prefix[DISTRIBUTE_IN]) 606 vty_out (vty, "%s (prefix-list) %s", 607 dist->list[DISTRIBUTE_IN] ? "," : "", 608 dist->prefix[DISTRIBUTE_IN]); 609 vty_out (vty, "%s", VTY_NEWLINE); 610 } 611 else 612 vty_out (vty, " Incoming update filter list for all interface is not set%s", VTY_NEWLINE); 613 614 for (i = 0; i < disthash->size; i++) 615 for (mp = disthash->index[i]; mp; mp = mp->next) 616 { 617 dist = mp->data; 618 if (dist->ifname) 619 if (dist->list[DISTRIBUTE_IN] || dist->prefix[DISTRIBUTE_IN]) 620 { 621 vty_out (vty, " %s filtered by", dist->ifname); 622 if (dist->list[DISTRIBUTE_IN]) 623 vty_out (vty, " %s", dist->list[DISTRIBUTE_IN]); 624 if (dist->prefix[DISTRIBUTE_IN]) 625 vty_out (vty, "%s (prefix-list) %s", 626 dist->list[DISTRIBUTE_IN] ? "," : "", 627 dist->prefix[DISTRIBUTE_IN]); 628 vty_out (vty, "%s", VTY_NEWLINE); 629 } 630 } 631 return 0; 632} 633 634/* Configuration write function. */ 635int 636config_write_distribute (struct vty *vty) 637{ 638 int i; 639 struct hash_backet *mp; 640 int write = 0; 641 642 for (i = 0; i < disthash->size; i++) 643 for (mp = disthash->index[i]; mp; mp = mp->next) 644 { 645 struct distribute *dist; 646 647 dist = mp->data; 648 649 if (dist->list[DISTRIBUTE_IN]) 650 { 651 vty_out (vty, " distribute-list %s in %s%s", 652 dist->list[DISTRIBUTE_IN], 653 dist->ifname ? dist->ifname : "", 654 VTY_NEWLINE); 655 write++; 656 } 657 658 if (dist->list[DISTRIBUTE_OUT]) 659 { 660 vty_out (vty, " distribute-list %s out %s%s", 661 662 dist->list[DISTRIBUTE_OUT], 663 dist->ifname ? dist->ifname : "", 664 VTY_NEWLINE); 665 write++; 666 } 667 668 if (dist->prefix[DISTRIBUTE_IN]) 669 { 670 vty_out (vty, " distribute-list prefix %s in %s%s", 671 dist->prefix[DISTRIBUTE_IN], 672 dist->ifname ? dist->ifname : "", 673 VTY_NEWLINE); 674 write++; 675 } 676 677 if (dist->prefix[DISTRIBUTE_OUT]) 678 { 679 vty_out (vty, " distribute-list prefix %s out %s%s", 680 dist->prefix[DISTRIBUTE_OUT], 681 dist->ifname ? dist->ifname : "", 682 VTY_NEWLINE); 683 write++; 684 } 685 } 686 return write; 687} 688 689/* Clear all distribute list. */ 690void 691distribute_list_reset () 692{ 693 hash_clean (disthash, (void (*) (void *)) distribute_free); 694} 695 696/* Initialize distribute list related hash. */ 697void 698distribute_list_init (int node) 699{ 700 disthash = hash_create (distribute_hash_make, distribute_cmp); 701 702#ifdef FOX_CMD_SUPPORT 703 install_element (node, &distribute_list_all_cmd); 704 install_element (node, &no_distribute_list_all_cmd); 705#endif /* FOX_CMD_SUPPORT */ 706 707 install_element (node, &distribute_list_cmd); 708 install_element (node, &no_distribute_list_cmd); 709#ifdef FOX_CMD_SUPPORT 710 install_element (node, &distribute_list_prefix_all_cmd); 711 install_element (node, &no_distribute_list_prefix_all_cmd); 712 713 install_element (node, &distribute_list_prefix_cmd); 714 install_element (node, &no_distribute_list_prefix_cmd); 715#endif /* FOX_CMD_SUPPORT */ 716} 717