1/* 2 * Interface related function for RIPng. 3 * Copyright (C) 1998 Kunihiro Ishiguro 4 * 5 * This file is part of GNU Zebra. 6 * 7 * GNU Zebra is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the 9 * Free Software Foundation; either version 2, or (at your option) any 10 * later version. 11 * 12 * GNU Zebra is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with GNU Zebra; see the file COPYING. If not, write to the Free 19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 20 * 02111-1307, USA. 21 */ 22 23#include <zebra.h> 24 25#include "linklist.h" 26#include "if.h" 27#include "prefix.h" 28#include "memory.h" 29#include "network.h" 30#include "filter.h" 31#include "log.h" 32#include "stream.h" 33#include "zclient.h" 34#include "command.h" 35#include "table.h" 36#include "thread.h" 37#include "privs.h" 38 39#include "ripngd/ripngd.h" 40#include "ripngd/ripng_debug.h" 41 42/* If RFC2133 definition is used. */ 43#ifndef IPV6_JOIN_GROUP 44#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP 45#endif 46#ifndef IPV6_LEAVE_GROUP 47#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP 48#endif 49 50extern struct zebra_privs_t ripngd_privs; 51 52/* Static utility function. */ 53static void ripng_enable_apply (struct interface *); 54static void ripng_passive_interface_apply (struct interface *); 55static int ripng_enable_if_lookup (const char *); 56static int ripng_enable_network_lookup2 (struct connected *); 57static void ripng_enable_apply_all (void); 58 59/* Join to the all rip routers multicast group. */ 60static int 61ripng_multicast_join (struct interface *ifp) 62{ 63 int ret; 64 struct ipv6_mreq mreq; 65 int save_errno; 66 67 if (if_is_up (ifp) && if_is_multicast (ifp)) { 68 memset (&mreq, 0, sizeof (mreq)); 69 inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr); 70 mreq.ipv6mr_interface = ifp->ifindex; 71 72 /* 73 * NetBSD 1.6.2 requires root to join groups on gif(4). 74 * While this is bogus, privs are available and easy to use 75 * for this call as a workaround. 76 */ 77 if (ripngd_privs.change (ZPRIVS_RAISE)) 78 zlog_err ("ripng_multicast_join: could not raise privs"); 79 80 ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, 81 (char *) &mreq, sizeof (mreq)); 82 save_errno = errno; 83 84 if (ripngd_privs.change (ZPRIVS_LOWER)) 85 zlog_err ("ripng_multicast_join: could not lower privs"); 86 87 if (ret < 0 && save_errno == EADDRINUSE) 88 { 89 /* 90 * Group is already joined. This occurs due to sloppy group 91 * management, in particular declining to leave the group on 92 * an interface that has just gone down. 93 */ 94 zlog_warn ("ripng join on %s EADDRINUSE (ignoring)\n", ifp->name); 95 return 0; /* not an error */ 96 } 97 98 if (ret < 0) 99 zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", 100 safe_strerror (save_errno)); 101 102 if (IS_RIPNG_DEBUG_EVENT) 103 zlog_debug ("RIPng %s join to all-rip-routers multicast group", ifp->name); 104 105 if (ret < 0) 106 return -1; 107 } 108 return 0; 109} 110 111/* Leave from the all rip routers multicast group. */ 112static int 113ripng_multicast_leave (struct interface *ifp) 114{ 115 int ret; 116 struct ipv6_mreq mreq; 117 118 if (if_is_up (ifp) && if_is_multicast (ifp)) { 119 memset (&mreq, 0, sizeof (mreq)); 120 inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr); 121 mreq.ipv6mr_interface = ifp->ifindex; 122 123 ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, 124 (char *) &mreq, sizeof (mreq)); 125 if (ret < 0) 126 zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s\n", safe_strerror (errno)); 127 128 if (IS_RIPNG_DEBUG_EVENT) 129 zlog_debug ("RIPng %s leave from all-rip-routers multicast group", 130 ifp->name); 131 132 if (ret < 0) 133 return -1; 134 } 135 136 return 0; 137} 138 139/* How many link local IPv6 address could be used on the interface ? */ 140static int 141ripng_if_ipv6_lladdress_check (struct interface *ifp) 142{ 143 struct listnode *nn; 144 struct connected *connected; 145 int count = 0; 146 147 for (ALL_LIST_ELEMENTS_RO (ifp->connected, nn, connected)) 148 { 149 struct prefix *p; 150 p = connected->address; 151 152 if ((p->family == AF_INET6) && 153 IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6)) 154 count++; 155 } 156 157 return count; 158} 159 160static int 161ripng_if_down (struct interface *ifp) 162{ 163 struct route_node *rp; 164 struct ripng_info *rinfo; 165 struct ripng_interface *ri; 166 167 if (ripng) 168 { 169 for (rp = route_top (ripng->table); rp; rp = route_next (rp)) 170 if ((rinfo = rp->info) != NULL) 171 { 172 /* Routes got through this interface. */ 173 if (rinfo->ifindex == ifp->ifindex 174 && rinfo->type == ZEBRA_ROUTE_RIPNG 175 && rinfo->sub_type == RIPNG_ROUTE_RTE) 176 { 177 ripng_zebra_ipv6_delete ((struct prefix_ipv6 *) &rp->p, 178 &rinfo->nexthop, 179 rinfo->ifindex); 180 181 ripng_redistribute_delete (rinfo->type, rinfo->sub_type, 182 (struct prefix_ipv6 *)&rp->p, 183 rinfo->ifindex); 184 } 185 else 186 { 187 /* All redistributed routes got through this interface, 188 * but the static and system ones are kept. */ 189 if ((rinfo->ifindex == ifp->ifindex) && 190 (rinfo->type != ZEBRA_ROUTE_STATIC) && 191 (rinfo->type != ZEBRA_ROUTE_SYSTEM)) 192 ripng_redistribute_delete (rinfo->type, rinfo->sub_type, 193 (struct prefix_ipv6 *) &rp->p, 194 rinfo->ifindex); 195 } 196 } 197 } 198 199 ri = ifp->info; 200 201 if (ri->running) 202 { 203 if (IS_RIPNG_DEBUG_EVENT) 204 zlog_debug ("turn off %s", ifp->name); 205 206 /* Leave from multicast group. */ 207 ripng_multicast_leave (ifp); 208 209 ri->running = 0; 210 } 211 212 return 0; 213} 214 215/* Inteface link up message processing. */ 216int 217ripng_interface_up (int command, struct zclient *zclient, zebra_size_t length) 218{ 219 struct stream *s; 220 struct interface *ifp; 221 222 /* zebra_interface_state_read() updates interface structure in iflist. */ 223 s = zclient->ibuf; 224 ifp = zebra_interface_state_read (s); 225 226 if (ifp == NULL) 227 return 0; 228 229 if (IS_RIPNG_DEBUG_ZEBRA) 230 zlog_debug ("interface up %s index %d flags %llx metric %d mtu %d", 231 ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, 232 ifp->metric, ifp->mtu6); 233 234 /* Check if this interface is RIPng enabled or not. */ 235 ripng_enable_apply (ifp); 236 237 /* Check for a passive interface. */ 238 ripng_passive_interface_apply (ifp); 239 240 /* Apply distribute list to the all interface. */ 241 ripng_distribute_update_interface (ifp); 242 243 return 0; 244} 245 246/* Inteface link down message processing. */ 247int 248ripng_interface_down (int command, struct zclient *zclient, 249 zebra_size_t length) 250{ 251 struct stream *s; 252 struct interface *ifp; 253 254 /* zebra_interface_state_read() updates interface structure in iflist. */ 255 s = zclient->ibuf; 256 ifp = zebra_interface_state_read (s); 257 258 if (ifp == NULL) 259 return 0; 260 261 ripng_if_down (ifp); 262 263 if (IS_RIPNG_DEBUG_ZEBRA) 264 zlog_debug ("interface down %s index %d flags %#llx metric %d mtu %d", 265 ifp->name, ifp->ifindex, 266 (unsigned long long) ifp->flags, ifp->metric, ifp->mtu6); 267 268 return 0; 269} 270 271/* Inteface addition message from zebra. */ 272int 273ripng_interface_add (int command, struct zclient *zclient, zebra_size_t length) 274{ 275 struct interface *ifp; 276 277 ifp = zebra_interface_add_read (zclient->ibuf); 278 279 if (IS_RIPNG_DEBUG_ZEBRA) 280 zlog_debug ("RIPng interface add %s index %d flags %#llx metric %d mtu %d", 281 ifp->name, ifp->ifindex, (unsigned long long) ifp->flags, 282 ifp->metric, ifp->mtu6); 283 284 /* Check is this interface is RIP enabled or not.*/ 285 ripng_enable_apply (ifp); 286 287 /* Apply distribute list to the interface. */ 288 ripng_distribute_update_interface (ifp); 289 290 /* Check interface routemap. */ 291 ripng_if_rmap_update_interface (ifp); 292 293 return 0; 294} 295 296int 297ripng_interface_delete (int command, struct zclient *zclient, 298 zebra_size_t length) 299{ 300 struct interface *ifp; 301 struct stream *s; 302 303 s = zclient->ibuf; 304 /* zebra_interface_state_read() updates interface structure in iflist */ 305 ifp = zebra_interface_state_read(s); 306 307 if (ifp == NULL) 308 return 0; 309 310 if (if_is_up (ifp)) { 311 ripng_if_down(ifp); 312 } 313 314 zlog_info("interface delete %s index %d flags %#llx metric %d mtu %d", 315 ifp->name, ifp->ifindex, (unsigned long long) ifp->flags, 316 ifp->metric, ifp->mtu6); 317 318 /* To support pseudo interface do not free interface structure. */ 319 /* if_delete(ifp); */ 320 ifp->ifindex = IFINDEX_INTERNAL; 321 322 return 0; 323} 324 325void 326ripng_interface_clean (void) 327{ 328 struct listnode *node, *nnode; 329 struct interface *ifp; 330 struct ripng_interface *ri; 331 332 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) 333 { 334 ri = ifp->info; 335 336 ri->enable_network = 0; 337 ri->enable_interface = 0; 338 ri->running = 0; 339 340 if (ri->t_wakeup) 341 { 342 thread_cancel (ri->t_wakeup); 343 ri->t_wakeup = NULL; 344 } 345 } 346} 347 348void 349ripng_interface_reset (void) 350{ 351 struct listnode *node; 352 struct interface *ifp; 353 struct ripng_interface *ri; 354 355 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) 356 { 357 ri = ifp->info; 358 359 ri->enable_network = 0; 360 ri->enable_interface = 0; 361 ri->running = 0; 362 363 ri->split_horizon = RIPNG_NO_SPLIT_HORIZON; 364 ri->split_horizon_default = RIPNG_NO_SPLIT_HORIZON; 365 366 ri->list[RIPNG_FILTER_IN] = NULL; 367 ri->list[RIPNG_FILTER_OUT] = NULL; 368 369 ri->prefix[RIPNG_FILTER_IN] = NULL; 370 ri->prefix[RIPNG_FILTER_OUT] = NULL; 371 372 if (ri->t_wakeup) 373 { 374 thread_cancel (ri->t_wakeup); 375 ri->t_wakeup = NULL; 376 } 377 378 ri->passive = 0; 379 } 380} 381 382static void 383ripng_apply_address_add (struct connected *ifc) { 384 struct prefix_ipv6 address; 385 struct prefix *p; 386 387 if (!ripng) 388 return; 389 390 if (! if_is_up(ifc->ifp)) 391 return; 392 393 p = ifc->address; 394 395 memset (&address, 0, sizeof (address)); 396 address.family = p->family; 397 address.prefix = p->u.prefix6; 398 address.prefixlen = p->prefixlen; 399 apply_mask_ipv6(&address); 400 401 /* Check if this interface is RIP enabled or not 402 or Check if this address's prefix is RIP enabled */ 403 if ((ripng_enable_if_lookup(ifc->ifp->name) >= 0) || 404 (ripng_enable_network_lookup2(ifc) >= 0)) 405 ripng_redistribute_add(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, 406 &address, ifc->ifp->ifindex, NULL); 407 408} 409 410int 411ripng_interface_address_add (int command, struct zclient *zclient, 412 zebra_size_t length) 413{ 414 struct connected *c; 415 struct prefix *p; 416 417 c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, 418 zclient->ibuf); 419 420 if (c == NULL) 421 return 0; 422 423 p = c->address; 424 425 if (p->family == AF_INET6) 426 { 427 struct ripng_interface *ri = c->ifp->info; 428 429 if (IS_RIPNG_DEBUG_ZEBRA) 430 zlog_debug ("RIPng connected address %s/%d add", 431 inet6_ntoa(p->u.prefix6), 432 p->prefixlen); 433 434 /* Check is this prefix needs to be redistributed. */ 435 ripng_apply_address_add(c); 436 437 /* Let's try once again whether the interface could be activated */ 438 if (!ri->running) { 439 /* Check if this interface is RIP enabled or not.*/ 440 ripng_enable_apply (c->ifp); 441 442 /* Apply distribute list to the interface. */ 443 ripng_distribute_update_interface (c->ifp); 444 445 /* Check interface routemap. */ 446 ripng_if_rmap_update_interface (c->ifp); 447 } 448 449 } 450 451 return 0; 452} 453 454static void 455ripng_apply_address_del (struct connected *ifc) { 456 struct prefix_ipv6 address; 457 struct prefix *p; 458 459 if (!ripng) 460 return; 461 462 if (! if_is_up(ifc->ifp)) 463 return; 464 465 p = ifc->address; 466 467 memset (&address, 0, sizeof (address)); 468 address.family = p->family; 469 address.prefix = p->u.prefix6; 470 address.prefixlen = p->prefixlen; 471 apply_mask_ipv6(&address); 472 473 ripng_redistribute_delete(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, 474 &address, ifc->ifp->ifindex); 475} 476 477int 478ripng_interface_address_delete (int command, struct zclient *zclient, 479 zebra_size_t length) 480{ 481 struct connected *ifc; 482 struct prefix *p; 483 char buf[INET6_ADDRSTRLEN]; 484 485 ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE, 486 zclient->ibuf); 487 488 if (ifc) 489 { 490 p = ifc->address; 491 492 if (p->family == AF_INET6) 493 { 494 if (IS_RIPNG_DEBUG_ZEBRA) 495 zlog_debug ("RIPng connected address %s/%d delete", 496 inet_ntop (AF_INET6, &p->u.prefix6, buf, 497 INET6_ADDRSTRLEN), 498 p->prefixlen); 499 500 /* Check wether this prefix needs to be removed. */ 501 ripng_apply_address_del(ifc); 502 } 503 connected_free (ifc); 504 } 505 506 return 0; 507} 508 509/* RIPng enable interface vector. */ 510vector ripng_enable_if; 511 512/* RIPng enable network table. */ 513struct route_table *ripng_enable_network; 514 515/* Lookup RIPng enable network. */ 516/* Check wether the interface has at least a connected prefix that 517 * is within the ripng_enable_network table. */ 518static int 519ripng_enable_network_lookup_if (struct interface *ifp) 520{ 521 struct listnode *node; 522 struct connected *connected; 523 struct prefix_ipv6 address; 524 525 for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected)) 526 { 527 struct prefix *p; 528 struct route_node *node; 529 530 p = connected->address; 531 532 if (p->family == AF_INET6) 533 { 534 address.family = AF_INET6; 535 address.prefix = p->u.prefix6; 536 address.prefixlen = IPV6_MAX_BITLEN; 537 538 node = route_node_match (ripng_enable_network, 539 (struct prefix *)&address); 540 if (node) 541 { 542 route_unlock_node (node); 543 return 1; 544 } 545 } 546 } 547 return -1; 548} 549 550/* Check wether connected is within the ripng_enable_network table. */ 551static int 552ripng_enable_network_lookup2 (struct connected *connected) 553{ 554 struct prefix_ipv6 address; 555 struct prefix *p; 556 557 p = connected->address; 558 559 if (p->family == AF_INET6) { 560 struct route_node *node; 561 562 address.family = p->family; 563 address.prefix = p->u.prefix6; 564 address.prefixlen = IPV6_MAX_BITLEN; 565 566 /* LPM on p->family, p->u.prefix6/IPV6_MAX_BITLEN within ripng_enable_network */ 567 node = route_node_match (ripng_enable_network, 568 (struct prefix *)&address); 569 570 if (node) { 571 route_unlock_node (node); 572 return 1; 573 } 574 } 575 576 return -1; 577} 578 579/* Add RIPng enable network. */ 580static int 581ripng_enable_network_add (struct prefix *p) 582{ 583 struct route_node *node; 584 585 node = route_node_get (ripng_enable_network, p); 586 587 if (node->info) 588 { 589 route_unlock_node (node); 590 return -1; 591 } 592 else 593 node->info = (char *) "enabled"; 594 595 /* XXX: One should find a better solution than a generic one */ 596 ripng_enable_apply_all(); 597 598 return 1; 599} 600 601/* Delete RIPng enable network. */ 602static int 603ripng_enable_network_delete (struct prefix *p) 604{ 605 struct route_node *node; 606 607 node = route_node_lookup (ripng_enable_network, p); 608 if (node) 609 { 610 node->info = NULL; 611 612 /* Unlock info lock. */ 613 route_unlock_node (node); 614 615 /* Unlock lookup lock. */ 616 route_unlock_node (node); 617 618 return 1; 619 } 620 return -1; 621} 622 623/* Lookup function. */ 624static int 625ripng_enable_if_lookup (const char *ifname) 626{ 627 unsigned int i; 628 char *str; 629 630 for (i = 0; i < vector_active (ripng_enable_if); i++) 631 if ((str = vector_slot (ripng_enable_if, i)) != NULL) 632 if (strcmp (str, ifname) == 0) 633 return i; 634 return -1; 635} 636 637/* Add interface to ripng_enable_if. */ 638static int 639ripng_enable_if_add (const char *ifname) 640{ 641 int ret; 642 643 ret = ripng_enable_if_lookup (ifname); 644 if (ret >= 0) 645 return -1; 646 647 vector_set (ripng_enable_if, strdup (ifname)); 648 649 ripng_enable_apply_all(); 650 651 return 1; 652} 653 654/* Delete interface from ripng_enable_if. */ 655static int 656ripng_enable_if_delete (const char *ifname) 657{ 658 int index; 659 char *str; 660 661 index = ripng_enable_if_lookup (ifname); 662 if (index < 0) 663 return -1; 664 665 str = vector_slot (ripng_enable_if, index); 666 free (str); 667 vector_unset (ripng_enable_if, index); 668 669 ripng_enable_apply_all(); 670 671 return 1; 672} 673 674/* Wake up interface. */ 675static int 676ripng_interface_wakeup (struct thread *t) 677{ 678 struct interface *ifp; 679 struct ripng_interface *ri; 680 681 /* Get interface. */ 682 ifp = THREAD_ARG (t); 683 684 ri = ifp->info; 685 ri->t_wakeup = NULL; 686 687 /* Join to multicast group. */ 688 if (ripng_multicast_join (ifp) < 0) { 689 zlog_err ("multicast join failed, interface %s not running", ifp->name); 690 return 0; 691 } 692 693 /* Set running flag. */ 694 ri->running = 1; 695 696 /* Send RIP request to the interface. */ 697 ripng_request (ifp); 698 699 return 0; 700} 701 702static void 703ripng_connect_set (struct interface *ifp, int set) 704{ 705 struct listnode *node, *nnode; 706 struct connected *connected; 707 struct prefix_ipv6 address; 708 709 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected)) 710 { 711 struct prefix *p; 712 p = connected->address; 713 714 if (p->family != AF_INET6) 715 continue; 716 717 address.family = AF_INET6; 718 address.prefix = p->u.prefix6; 719 address.prefixlen = p->prefixlen; 720 apply_mask_ipv6 (&address); 721 722 if (set) { 723 /* Check once more wether this prefix is within a "network IF_OR_PREF" one */ 724 if ((ripng_enable_if_lookup(connected->ifp->name) >= 0) || 725 (ripng_enable_network_lookup2(connected) >= 0)) 726 ripng_redistribute_add (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, 727 &address, connected->ifp->ifindex, NULL); 728 } else { 729 ripng_redistribute_delete (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, 730 &address, connected->ifp->ifindex); 731 if (ripng_redistribute_check (ZEBRA_ROUTE_CONNECT)) 732 ripng_redistribute_add (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_REDISTRIBUTE, 733 &address, connected->ifp->ifindex, NULL); 734 } 735 } 736} 737 738/* Check RIPng is enabed on this interface. */ 739void 740ripng_enable_apply (struct interface *ifp) 741{ 742 int ret; 743 struct ripng_interface *ri = NULL; 744 745 /* Check interface. */ 746 if (! if_is_up (ifp)) 747 return; 748 749 ri = ifp->info; 750 751 /* Is this interface a candidate for RIPng ? */ 752 ret = ripng_enable_network_lookup_if (ifp); 753 754 /* If the interface is matched. */ 755 if (ret > 0) 756 ri->enable_network = 1; 757 else 758 ri->enable_network = 0; 759 760 /* Check interface name configuration. */ 761 ret = ripng_enable_if_lookup (ifp->name); 762 if (ret >= 0) 763 ri->enable_interface = 1; 764 else 765 ri->enable_interface = 0; 766 767 /* any candidate interface MUST have a link-local IPv6 address */ 768 if ((! ripng_if_ipv6_lladdress_check (ifp)) && 769 (ri->enable_network || ri->enable_interface)) { 770 ri->enable_network = 0; 771 ri->enable_interface = 0; 772 zlog_warn("Interface %s does not have any link-local address", 773 ifp->name); 774 } 775 776 /* Update running status of the interface. */ 777 if (ri->enable_network || ri->enable_interface) 778 { 779 { 780 if (IS_RIPNG_DEBUG_EVENT) 781 zlog_debug ("RIPng turn on %s", ifp->name); 782 783 /* Add interface wake up thread. */ 784 if (! ri->t_wakeup) 785 ri->t_wakeup = thread_add_timer (master, ripng_interface_wakeup, 786 ifp, 1); 787 788 ripng_connect_set (ifp, 1); 789 } 790 } 791 else 792 { 793 if (ri->running) 794 { 795 /* Might as well clean up the route table as well 796 * ripng_if_down sets to 0 ri->running, and displays "turn off %s" 797 **/ 798 ripng_if_down(ifp); 799 800 ripng_connect_set (ifp, 0); 801 } 802 } 803} 804 805/* Set distribute list to all interfaces. */ 806static void 807ripng_enable_apply_all (void) 808{ 809 struct interface *ifp; 810 struct listnode *node; 811 812 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) 813 ripng_enable_apply (ifp); 814} 815 816/* Clear all network and neighbor configuration */ 817void 818ripng_clean_network () 819{ 820 unsigned int i; 821 char *str; 822 struct route_node *rn; 823 824 /* ripng_enable_network */ 825 for (rn = route_top (ripng_enable_network); rn; rn = route_next (rn)) 826 if (rn->info) { 827 rn->info = NULL; 828 route_unlock_node(rn); 829 } 830 831 /* ripng_enable_if */ 832 for (i = 0; i < vector_active (ripng_enable_if); i++) 833 if ((str = vector_slot (ripng_enable_if, i)) != NULL) { 834 free (str); 835 vector_slot (ripng_enable_if, i) = NULL; 836 } 837} 838 839/* Vector to store passive-interface name. */ 840vector Vripng_passive_interface; 841 842/* Utility function for looking up passive interface settings. */ 843static int 844ripng_passive_interface_lookup (const char *ifname) 845{ 846 unsigned int i; 847 char *str; 848 849 for (i = 0; i < vector_active (Vripng_passive_interface); i++) 850 if ((str = vector_slot (Vripng_passive_interface, i)) != NULL) 851 if (strcmp (str, ifname) == 0) 852 return i; 853 return -1; 854} 855 856void 857ripng_passive_interface_apply (struct interface *ifp) 858{ 859 int ret; 860 struct ripng_interface *ri; 861 862 ri = ifp->info; 863 864 ret = ripng_passive_interface_lookup (ifp->name); 865 if (ret < 0) 866 ri->passive = 0; 867 else 868 ri->passive = 1; 869} 870 871static void 872ripng_passive_interface_apply_all (void) 873{ 874 struct interface *ifp; 875 struct listnode *node; 876 877 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) 878 ripng_passive_interface_apply (ifp); 879} 880 881/* Passive interface. */ 882static int 883ripng_passive_interface_set (struct vty *vty, const char *ifname) 884{ 885 if (ripng_passive_interface_lookup (ifname) >= 0) 886 return CMD_WARNING; 887 888 vector_set (Vripng_passive_interface, strdup (ifname)); 889 890 ripng_passive_interface_apply_all (); 891 892 return CMD_SUCCESS; 893} 894 895static int 896ripng_passive_interface_unset (struct vty *vty, const char *ifname) 897{ 898 int i; 899 char *str; 900 901 i = ripng_passive_interface_lookup (ifname); 902 if (i < 0) 903 return CMD_WARNING; 904 905 str = vector_slot (Vripng_passive_interface, i); 906 free (str); 907 vector_unset (Vripng_passive_interface, i); 908 909 ripng_passive_interface_apply_all (); 910 911 return CMD_SUCCESS; 912} 913 914/* Free all configured RIP passive-interface settings. */ 915void 916ripng_passive_interface_clean (void) 917{ 918 unsigned int i; 919 char *str; 920 921 for (i = 0; i < vector_active (Vripng_passive_interface); i++) 922 if ((str = vector_slot (Vripng_passive_interface, i)) != NULL) 923 { 924 free (str); 925 vector_slot (Vripng_passive_interface, i) = NULL; 926 } 927 ripng_passive_interface_apply_all (); 928} 929 930/* Write RIPng enable network and interface to the vty. */ 931int 932ripng_network_write (struct vty *vty, int config_mode) 933{ 934 unsigned int i; 935 const char *ifname; 936 struct route_node *node; 937 char buf[BUFSIZ]; 938 939 /* Write enable network. */ 940 for (node = route_top (ripng_enable_network); node; node = route_next (node)) 941 if (node->info) 942 { 943 struct prefix *p = &node->p; 944 vty_out (vty, "%s%s/%d%s", 945 config_mode ? " network " : " ", 946 inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), 947 p->prefixlen, 948 VTY_NEWLINE); 949 950 } 951 952 /* Write enable interface. */ 953 for (i = 0; i < vector_active (ripng_enable_if); i++) 954 if ((ifname = vector_slot (ripng_enable_if, i)) != NULL) 955 vty_out (vty, "%s%s%s", 956 config_mode ? " network " : " ", 957 ifname, 958 VTY_NEWLINE); 959 960 /* Write passive interface. */ 961 if (config_mode) 962 for (i = 0; i < vector_active (Vripng_passive_interface); i++) 963 if ((ifname = vector_slot (Vripng_passive_interface, i)) != NULL) 964 vty_out (vty, " passive-interface %s%s", ifname, VTY_NEWLINE); 965 966 return 0; 967} 968 969/* RIPng enable on specified interface or matched network. */ 970DEFUN (ripng_network, 971 ripng_network_cmd, 972 "network IF_OR_ADDR", 973 "RIPng enable on specified interface or network.\n" 974 "Interface or address") 975{ 976 int ret; 977 struct prefix p; 978 979 ret = str2prefix (argv[0], &p); 980 981 /* Given string is IPv6 network or interface name. */ 982 if (ret) 983 ret = ripng_enable_network_add (&p); 984 else 985 ret = ripng_enable_if_add (argv[0]); 986 987 if (ret < 0) 988 { 989 vty_out (vty, "There is same network configuration %s%s", argv[0], 990 VTY_NEWLINE); 991 return CMD_WARNING; 992 } 993 994 return CMD_SUCCESS; 995} 996 997/* RIPng enable on specified interface or matched network. */ 998DEFUN (no_ripng_network, 999 no_ripng_network_cmd, 1000 "no network IF_OR_ADDR", 1001 NO_STR 1002 "RIPng enable on specified interface or network.\n" 1003 "Interface or address") 1004{ 1005 int ret; 1006 struct prefix p; 1007 1008 ret = str2prefix (argv[0], &p); 1009 1010 /* Given string is interface name. */ 1011 if (ret) 1012 ret = ripng_enable_network_delete (&p); 1013 else 1014 ret = ripng_enable_if_delete (argv[0]); 1015 1016 if (ret < 0) 1017 { 1018 vty_out (vty, "can't find network %s%s", argv[0], 1019 VTY_NEWLINE); 1020 return CMD_WARNING; 1021 } 1022 1023 return CMD_SUCCESS; 1024} 1025 1026DEFUN (ipv6_ripng_split_horizon, 1027 ipv6_ripng_split_horizon_cmd, 1028 "ipv6 ripng split-horizon", 1029 IPV6_STR 1030 "Routing Information Protocol\n" 1031 "Perform split horizon\n") 1032{ 1033 struct interface *ifp; 1034 struct ripng_interface *ri; 1035 1036 ifp = vty->index; 1037 ri = ifp->info; 1038 1039 ri->split_horizon = RIPNG_SPLIT_HORIZON; 1040 return CMD_SUCCESS; 1041} 1042 1043DEFUN (ipv6_ripng_split_horizon_poisoned_reverse, 1044 ipv6_ripng_split_horizon_poisoned_reverse_cmd, 1045 "ipv6 ripng split-horizon poisoned-reverse", 1046 IPV6_STR 1047 "Routing Information Protocol\n" 1048 "Perform split horizon\n" 1049 "With poisoned-reverse\n") 1050{ 1051 struct interface *ifp; 1052 struct ripng_interface *ri; 1053 1054 ifp = vty->index; 1055 ri = ifp->info; 1056 1057 ri->split_horizon = RIPNG_SPLIT_HORIZON_POISONED_REVERSE; 1058 return CMD_SUCCESS; 1059} 1060 1061DEFUN (no_ipv6_ripng_split_horizon, 1062 no_ipv6_ripng_split_horizon_cmd, 1063 "no ipv6 ripng split-horizon", 1064 NO_STR 1065 IPV6_STR 1066 "Routing Information Protocol\n" 1067 "Perform split horizon\n") 1068{ 1069 struct interface *ifp; 1070 struct ripng_interface *ri; 1071 1072 ifp = vty->index; 1073 ri = ifp->info; 1074 1075 ri->split_horizon = RIPNG_NO_SPLIT_HORIZON; 1076 return CMD_SUCCESS; 1077} 1078 1079ALIAS (no_ipv6_ripng_split_horizon, 1080 no_ipv6_ripng_split_horizon_poisoned_reverse_cmd, 1081 "no ipv6 ripng split-horizon poisoned-reverse", 1082 NO_STR 1083 IPV6_STR 1084 "Routing Information Protocol\n" 1085 "Perform split horizon\n" 1086 "With poisoned-reverse\n") 1087 1088DEFUN (ripng_passive_interface, 1089 ripng_passive_interface_cmd, 1090 "passive-interface IFNAME", 1091 "Suppress routing updates on an interface\n" 1092 "Interface name\n") 1093{ 1094 return ripng_passive_interface_set (vty, argv[0]); 1095} 1096 1097DEFUN (no_ripng_passive_interface, 1098 no_ripng_passive_interface_cmd, 1099 "no passive-interface IFNAME", 1100 NO_STR 1101 "Suppress routing updates on an interface\n" 1102 "Interface name\n") 1103{ 1104 return ripng_passive_interface_unset (vty, argv[0]); 1105} 1106 1107static struct ripng_interface * 1108ri_new (void) 1109{ 1110 struct ripng_interface *ri; 1111 ri = XCALLOC (MTYPE_IF, sizeof (struct ripng_interface)); 1112 1113 /* Set default split-horizon behavior. If the interface is Frame 1114 Relay or SMDS is enabled, the default value for split-horizon is 1115 off. But currently Zebra does detect Frame Relay or SMDS 1116 interface. So all interface is set to split horizon. */ 1117 ri->split_horizon_default = RIPNG_SPLIT_HORIZON; 1118 ri->split_horizon = ri->split_horizon_default; 1119 1120 return ri; 1121} 1122 1123static int 1124ripng_if_new_hook (struct interface *ifp) 1125{ 1126 ifp->info = ri_new (); 1127 return 0; 1128} 1129 1130/* Called when interface structure deleted. */ 1131static int 1132ripng_if_delete_hook (struct interface *ifp) 1133{ 1134 XFREE (MTYPE_IF, ifp->info); 1135 ifp->info = NULL; 1136 return 0; 1137} 1138 1139/* Configuration write function for ripngd. */ 1140static int 1141interface_config_write (struct vty *vty) 1142{ 1143 struct listnode *node; 1144 struct interface *ifp; 1145 struct ripng_interface *ri; 1146 int write = 0; 1147 1148 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) 1149 { 1150 ri = ifp->info; 1151 1152 /* Do not display the interface if there is no 1153 * configuration about it. 1154 **/ 1155 if ((!ifp->desc) && 1156 (ri->split_horizon == ri->split_horizon_default)) 1157 continue; 1158 1159 vty_out (vty, "interface %s%s", ifp->name, 1160 VTY_NEWLINE); 1161 if (ifp->desc) 1162 vty_out (vty, " description %s%s", ifp->desc, 1163 VTY_NEWLINE); 1164 1165 /* Split horizon. */ 1166 if (ri->split_horizon != ri->split_horizon_default) 1167 { 1168 switch (ri->split_horizon) { 1169 case RIPNG_SPLIT_HORIZON: 1170 vty_out (vty, " ipv6 ripng split-horizon%s", VTY_NEWLINE); 1171 break; 1172 case RIPNG_SPLIT_HORIZON_POISONED_REVERSE: 1173 vty_out (vty, " ipv6 ripng split-horizon poisoned-reverse%s", 1174 VTY_NEWLINE); 1175 break; 1176 case RIPNG_NO_SPLIT_HORIZON: 1177 default: 1178 vty_out (vty, " no ipv6 ripng split-horizon%s", VTY_NEWLINE); 1179 break; 1180 } 1181 } 1182 1183 vty_out (vty, "!%s", VTY_NEWLINE); 1184 1185 write++; 1186 } 1187 return write; 1188} 1189 1190/* ripngd's interface node. */ 1191static struct cmd_node interface_node = 1192{ 1193 INTERFACE_NODE, 1194 "%s(config-if)# ", 1195 1 /* VTYSH */ 1196}; 1197 1198/* Initialization of interface. */ 1199void 1200ripng_if_init () 1201{ 1202 /* Interface initialize. */ 1203 iflist = list_new (); 1204 if_add_hook (IF_NEW_HOOK, ripng_if_new_hook); 1205 if_add_hook (IF_DELETE_HOOK, ripng_if_delete_hook); 1206 1207 /* RIPng enable network init. */ 1208 ripng_enable_network = route_table_init (); 1209 1210 /* RIPng enable interface init. */ 1211 ripng_enable_if = vector_init (1); 1212 1213 /* RIPng passive interface. */ 1214 Vripng_passive_interface = vector_init (1); 1215 1216 /* Install interface node. */ 1217 install_node (&interface_node, interface_config_write); 1218 1219 /* Install commands. */ 1220 install_element (CONFIG_NODE, &interface_cmd); 1221 install_element (CONFIG_NODE, &no_interface_cmd); 1222 install_default (INTERFACE_NODE); 1223 install_element (INTERFACE_NODE, &interface_desc_cmd); 1224 install_element (INTERFACE_NODE, &no_interface_desc_cmd); 1225 1226 install_element (RIPNG_NODE, &ripng_network_cmd); 1227 install_element (RIPNG_NODE, &no_ripng_network_cmd); 1228 install_element (RIPNG_NODE, &ripng_passive_interface_cmd); 1229 install_element (RIPNG_NODE, &no_ripng_passive_interface_cmd); 1230 1231 install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_cmd); 1232 install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_poisoned_reverse_cmd); 1233 install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_cmd); 1234 install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_poisoned_reverse_cmd); 1235} 1236