File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / ripngd / ripng_interface.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:26:11 2012 UTC (12 years, 4 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_22p0, v0_99_22, v0_99_21, v0_99_20_1, v0_99_20, HEAD
quagga

    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: 
   50: extern struct zebra_privs_t ripngd_privs;
   51: 
   52: /* Static utility function. */
   53: static void ripng_enable_apply (struct interface *);
   54: static void ripng_passive_interface_apply (struct interface *);
   55: static int ripng_enable_if_lookup (const char *);
   56: static int ripng_enable_network_lookup2 (struct connected *);
   57: static void ripng_enable_apply_all (void);
   58: 
   59: /* Join to the all rip routers multicast group. */
   60: static int
   61: ripng_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. */
  112: static int
  113: ripng_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 ? */
  140: static int
  141: ripng_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: 
  160: static int
  161: ripng_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. */
  216: int
  217: ripng_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. */
  247: int
  248: ripng_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. */
  272: int
  273: ripng_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: 
  296: int
  297: ripng_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: 
  325: void
  326: ripng_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: 
  348: void
  349: ripng_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: 
  382: static void
  383: ripng_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: 
  410: int
  411: ripng_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: 
  454: static void
  455: ripng_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: 
  477: int
  478: ripng_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. */
  510: vector ripng_enable_if;
  511: 
  512: /* RIPng enable network table. */
  513: struct 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. */
  518: static int
  519: ripng_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. */
  551: static int
  552: ripng_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. */
  580: static int
  581: ripng_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. */
  602: static int
  603: ripng_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. */
  624: static int
  625: ripng_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. */
  638: static int
  639: ripng_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. */
  655: static int
  656: ripng_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. */
  675: static int
  676: ripng_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: 
  702: static void
  703: ripng_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. */
  739: void
  740: ripng_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. */
  806: static void
  807: ripng_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 */
  817: void
  818: ripng_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. */
  840: vector Vripng_passive_interface;
  841: 
  842: /* Utility function for looking up passive interface settings. */
  843: static int
  844: ripng_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: 
  856: void
  857: ripng_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: 
  871: static void
  872: ripng_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. */
  882: static int
  883: ripng_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: 
  895: static int
  896: ripng_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. */
  915: void
  916: ripng_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. */
  931: int
  932: ripng_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. */
  970: DEFUN (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. */
  998: DEFUN (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: 
 1026: DEFUN (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: 
 1043: DEFUN (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: 
 1061: DEFUN (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: 
 1079: ALIAS (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: 
 1088: DEFUN (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: 
 1097: DEFUN (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: 
 1107: static struct ripng_interface *
 1108: ri_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: 
 1123: static int
 1124: ripng_if_new_hook (struct interface *ifp)
 1125: {
 1126:   ifp->info = ri_new ();
 1127:   return 0;
 1128: }
 1129: 
 1130: /* Called when interface structure deleted. */
 1131: static int
 1132: ripng_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. */
 1140: static int
 1141: interface_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. */
 1191: static struct cmd_node interface_node =
 1192: {
 1193:   INTERFACE_NODE,
 1194:   "%s(config-if)# ",
 1195:   1 /* VTYSH */
 1196: };
 1197: 
 1198: /* Initialization of interface. */
 1199: void
 1200: ripng_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: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>