File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / zebra / connected.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, 5 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_20_1, v0_99_20, HEAD
quagga

    1: /*
    2:  * Address linked list routine.
    3:  * Copyright (C) 1997, 98 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 "prefix.h"
   26: #include "linklist.h"
   27: #include "if.h"
   28: #include "table.h"
   29: #include "rib.h"
   30: #include "table.h"
   31: #include "log.h"
   32: #include "memory.h"
   33: 
   34: #include "zebra/zserv.h"
   35: #include "zebra/redistribute.h"
   36: #include "zebra/interface.h"
   37: #include "zebra/connected.h"
   38: extern struct zebra_t zebrad;
   39: 
   40: /* withdraw a connected address */
   41: static void
   42: connected_withdraw (struct connected *ifc)
   43: {
   44:   if (! ifc)
   45:     return;
   46: 
   47:   /* Update interface address information to protocol daemon. */
   48:   if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
   49:     {
   50:       zebra_interface_address_delete_update (ifc->ifp, ifc);
   51: 
   52:       if_subnet_delete (ifc->ifp, ifc);
   53:       
   54:       if (ifc->address->family == AF_INET)
   55:         connected_down_ipv4 (ifc->ifp, ifc);
   56: #ifdef HAVE_IPV6
   57:       else
   58:         connected_down_ipv6 (ifc->ifp, ifc);
   59: #endif
   60: 
   61:       UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
   62:     }
   63: 
   64:   if (!CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
   65:     {
   66:       listnode_delete (ifc->ifp->connected, ifc);
   67:       connected_free (ifc);
   68:     }
   69: }
   70: 
   71: static void
   72: connected_announce (struct interface *ifp, struct connected *ifc)
   73: {
   74:   if (!ifc)
   75:     return;
   76:   
   77:   listnode_add (ifp->connected, ifc);
   78: 
   79:   /* Update interface address information to protocol daemon. */
   80:   if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
   81:     {
   82:       if (ifc->address->family == AF_INET)
   83:         if_subnet_add (ifp, ifc);
   84: 
   85:       SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
   86: 
   87:       zebra_interface_address_add_update (ifp, ifc);
   88: 
   89:       if (if_is_operative(ifp))
   90:         {
   91:           if (ifc->address->family == AF_INET)
   92: 	    connected_up_ipv4 (ifp, ifc);
   93: #ifdef HAVE_IPV6
   94:           else
   95:             connected_up_ipv6 (ifp, ifc);
   96: #endif
   97:         }
   98:     }
   99: }
  100: 
  101: /* If same interface address is already exist... */
  102: struct connected *
  103: connected_check (struct interface *ifp, struct prefix *p)
  104: {
  105:   struct connected *ifc;
  106:   struct listnode *node;
  107: 
  108:   for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc))
  109:     if (prefix_same (ifc->address, p))
  110:       return ifc;
  111: 
  112:   return NULL;
  113: }
  114: 
  115: /* Check if two ifc's describe the same address */
  116: static int
  117: connected_same (struct connected *ifc1, struct connected *ifc2)
  118: {
  119:   if (ifc1->ifp != ifc2->ifp)
  120:     return 0;
  121:   
  122:   if (ifc1->destination)
  123:     if (!ifc2->destination)
  124:       return 0;
  125:   if (ifc2->destination)
  126:     if (!ifc1->destination)
  127:       return 0;
  128:   
  129:   if (ifc1->destination && ifc2->destination)
  130:     if (!prefix_same (ifc1->destination, ifc2->destination))
  131:       return 0;
  132: 
  133:   if (ifc1->flags != ifc2->flags)
  134:     return 0;
  135:   
  136:   return 1;
  137: }
  138: 
  139: /* Handle implicit withdrawals of addresses, where a system ADDs an address
  140:  * to an interface which already has the same address configured.
  141:  *
  142:  * Returns the struct connected which must be announced to clients,
  143:  * or NULL if nothing to do.
  144:  */
  145: static struct connected *
  146: connected_implicit_withdraw (struct interface *ifp, struct connected *ifc)
  147: {
  148:   struct connected *current;
  149:   
  150:   /* Check same connected route. */
  151:   if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
  152:     {
  153:       if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
  154:         SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
  155: 	
  156:       /* Avoid spurious withdraws, this might be just the kernel 'reflecting'
  157:        * back an address we have already added.
  158:        */
  159:       if (connected_same (current, ifc) && CHECK_FLAG(current->conf, ZEBRA_IFC_REAL))
  160:         {
  161:           /* nothing to do */
  162:           connected_free (ifc);
  163:           return NULL;
  164:         }
  165:       
  166:       UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED);
  167:       connected_withdraw (current); /* implicit withdraw - freebsd does this */
  168:     }
  169:   return ifc;
  170: }
  171: 
  172: /* Called from if_up(). */
  173: void
  174: connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
  175: {
  176:   struct prefix_ipv4 p;
  177: 
  178:   if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
  179:     return;
  180: 
  181:   PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
  182: 
  183:   /* Apply mask to the network. */
  184:   apply_mask_ipv4 (&p);
  185: 
  186:   /* In case of connected address is 0.0.0.0/0 we treat it tunnel
  187:      address. */
  188:   if (prefix_ipv4_any (&p))
  189:     return;
  190: 
  191:   rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex,
  192: 	RT_TABLE_MAIN, ifp->metric, 0);
  193: 
  194:   rib_update ();
  195: }
  196: 
  197: /* Add connected IPv4 route to the interface. */
  198: void
  199: connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, 
  200: 		    u_char prefixlen, struct in_addr *broad, 
  201: 		    const char *label)
  202: {
  203:   struct prefix_ipv4 *p;
  204:   struct connected *ifc;
  205: 
  206:   /* Make connected structure. */
  207:   ifc = connected_new ();
  208:   ifc->ifp = ifp;
  209:   ifc->flags = flags;
  210: 
  211:   /* Allocate new connected address. */
  212:   p = prefix_ipv4_new ();
  213:   p->family = AF_INET;
  214:   p->prefix = *addr;
  215:   p->prefixlen = prefixlen;
  216:   ifc->address = (struct prefix *) p;
  217:   
  218:   /* If there is broadcast or peer address. */
  219:   if (broad)
  220:     {
  221:       p = prefix_ipv4_new ();
  222:       p->family = AF_INET;
  223:       p->prefix = *broad;
  224:       p->prefixlen = prefixlen;
  225:       ifc->destination = (struct prefix *) p;
  226: 
  227:       /* validate the destination address */
  228:       if (CONNECTED_PEER(ifc))
  229:         {
  230: 	  if (IPV4_ADDR_SAME(addr,broad))
  231: 	    zlog_warn("warning: interface %s has same local and peer "
  232: 		      "address %s, routing protocols may malfunction",
  233: 		      ifp->name,inet_ntoa(*addr));
  234:         }
  235:       else
  236:         {
  237: 	  if (broad->s_addr != ipv4_broadcast_addr(addr->s_addr,prefixlen))
  238: 	    {
  239: 	      char buf[2][INET_ADDRSTRLEN];
  240: 	      struct in_addr bcalc;
  241: 	      bcalc.s_addr = ipv4_broadcast_addr(addr->s_addr,prefixlen);
  242: 	      zlog_warn("warning: interface %s broadcast addr %s/%d != "
  243: 	       		"calculated %s, routing protocols may malfunction",
  244: 	    		ifp->name,
  245: 			inet_ntop (AF_INET, broad, buf[0], sizeof(buf[0])),
  246: 			prefixlen,
  247: 			inet_ntop (AF_INET, &bcalc, buf[1], sizeof(buf[1])));
  248: 	    }
  249:         }
  250: 
  251:     }
  252:   else
  253:     {
  254:       if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER))
  255:         {
  256: 	  zlog_warn("warning: %s called for interface %s "
  257: 		    "with peer flag set, but no peer address supplied",
  258: 		    __func__, ifp->name);
  259: 	  UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
  260: 	}
  261: 
  262:       /* no broadcast or destination address was supplied */
  263:       if ((prefixlen == IPV4_MAX_PREFIXLEN) && if_is_pointopoint(ifp))
  264: 	zlog_warn("warning: PtP interface %s with addr %s/%d needs a "
  265: 		  "peer address",ifp->name,inet_ntoa(*addr),prefixlen);
  266:     }
  267: 
  268:   /* Label of this address. */
  269:   if (label)
  270:     ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
  271: 
  272:   /* nothing to do? */
  273:   if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL)
  274:     return;
  275:   
  276:   connected_announce (ifp, ifc);
  277: }
  278: 
  279: void
  280: connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
  281: {
  282:   struct prefix_ipv4 p;
  283: 
  284:   if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
  285:     return;
  286: 
  287:   PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
  288: 
  289:   /* Apply mask to the network. */
  290:   apply_mask_ipv4 (&p);
  291: 
  292:   /* In case of connected address is 0.0.0.0/0 we treat it tunnel
  293:      address. */
  294:   if (prefix_ipv4_any (&p))
  295:     return;
  296: 
  297:   /* Same logic as for connected_up_ipv4(): push the changes into the head. */
  298:   rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
  299: 
  300:   rib_update ();
  301: }
  302: 
  303: /* Delete connected IPv4 route to the interface. */
  304: void
  305: connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
  306: 		       u_char prefixlen, struct in_addr *broad)
  307: {
  308:   struct prefix_ipv4 p;
  309:   struct connected *ifc;
  310: 
  311:   memset (&p, 0, sizeof (struct prefix_ipv4));
  312:   p.family = AF_INET;
  313:   p.prefix = *addr;
  314:   p.prefixlen = prefixlen;
  315: 
  316:   ifc = connected_check (ifp, (struct prefix *) &p);
  317:   if (! ifc)
  318:     return;
  319:     
  320:   connected_withdraw (ifc);
  321: 
  322:   rib_update();
  323: }
  324: 
  325: #ifdef HAVE_IPV6
  326: void
  327: connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
  328: {
  329:   struct prefix_ipv6 p;
  330: 
  331:   if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
  332:     return;
  333: 
  334:   PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc));
  335: 
  336:   /* Apply mask to the network. */
  337:   apply_mask_ipv6 (&p);
  338: 
  339: #if ! defined (MUSICA) && ! defined (LINUX)
  340:   /* XXX: It is already done by rib_bogus_ipv6 within rib_add_ipv6 */
  341:   if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
  342:     return;
  343: #endif
  344: 
  345:   rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, RT_TABLE_MAIN,
  346:                 ifp->metric, 0);
  347: 
  348:   rib_update ();
  349: }
  350: 
  351: /* Add connected IPv6 route to the interface. */
  352: void
  353: connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr,
  354: 		    u_char prefixlen, struct in6_addr *broad,
  355: 		    const char *label)
  356: {
  357:   struct prefix_ipv6 *p;
  358:   struct connected *ifc;
  359: 
  360:   /* Make connected structure. */
  361:   ifc = connected_new ();
  362:   ifc->ifp = ifp;
  363:   ifc->flags = flags;
  364: 
  365:   /* Allocate new connected address. */
  366:   p = prefix_ipv6_new ();
  367:   p->family = AF_INET6;
  368:   IPV6_ADDR_COPY (&p->prefix, addr);
  369:   p->prefixlen = prefixlen;
  370:   ifc->address = (struct prefix *) p;
  371: 
  372:   /* If there is broadcast or peer address. */
  373:   if (broad)
  374:     {
  375:       if (IN6_IS_ADDR_UNSPECIFIED(broad))
  376: 	zlog_warn("warning: %s called for interface %s with unspecified "
  377: 		  "destination address; ignoring!", __func__, ifp->name);
  378:       else
  379: 	{
  380: 	  p = prefix_ipv6_new ();
  381: 	  p->family = AF_INET6;
  382: 	  IPV6_ADDR_COPY (&p->prefix, broad);
  383: 	  p->prefixlen = prefixlen;
  384: 	  ifc->destination = (struct prefix *) p;
  385: 	}
  386:     }
  387:   if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER) && !ifc->destination)
  388:     {
  389:       zlog_warn("warning: %s called for interface %s "
  390: 		"with peer flag set, but no peer address supplied",
  391: 		__func__, ifp->name);
  392:       UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
  393:     }
  394: 
  395:   /* Label of this address. */
  396:   if (label)
  397:     ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
  398:   
  399:   if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL)
  400:     return;
  401:   
  402:   connected_announce (ifp, ifc);
  403: }
  404: 
  405: void
  406: connected_down_ipv6 (struct interface *ifp, struct connected *ifc)
  407: {
  408:   struct prefix_ipv6 p;
  409: 
  410:   if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
  411:     return;
  412: 
  413:   PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc));
  414: 
  415:   apply_mask_ipv6 (&p);
  416: 
  417:   if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
  418:     return;
  419: 
  420:   rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
  421: 
  422:   rib_update ();
  423: }
  424: 
  425: void
  426: connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
  427: 		       u_char prefixlen, struct in6_addr *broad)
  428: {
  429:   struct prefix_ipv6 p;
  430:   struct connected *ifc;
  431:   
  432:   memset (&p, 0, sizeof (struct prefix_ipv6));
  433:   p.family = AF_INET6;
  434:   memcpy (&p.prefix, address, sizeof (struct in6_addr));
  435:   p.prefixlen = prefixlen;
  436: 
  437:   ifc = connected_check (ifp, (struct prefix *) &p);
  438:   if (! ifc)
  439:     return;
  440: 
  441:   connected_withdraw (ifc);
  442: 
  443:   rib_update();
  444: }
  445: #endif /* HAVE_IPV6 */

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