File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / ripngd / ripng_interface.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:12 2016 UTC (7 years, 7 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

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

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