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

    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: /* communicate the withdrawal of 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 (ifc->address->family == AF_INET)
   53:         if_subnet_delete (ifc->ifp, ifc);
   54: 
   55:       if (ifc->address->family == AF_INET)
   56:         connected_down_ipv4 (ifc->ifp, ifc);
   57: #ifdef HAVE_IPV6
   58:       else
   59:         connected_down_ipv6 (ifc->ifp, ifc);
   60: #endif
   61: 
   62:       UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
   63:     }
   64: 
   65:   /* The address is not in the kernel anymore, so clear the flag */
   66:   UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
   67: 
   68:   if (!CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
   69:     {
   70:       listnode_delete (ifc->ifp->connected, ifc);
   71:       connected_free (ifc);
   72:     }
   73: }
   74: 
   75: static void
   76: connected_announce (struct interface *ifp, struct connected *ifc)
   77: {
   78:   if (!ifc)
   79:     return;
   80:   
   81:   listnode_add (ifp->connected, ifc);
   82: 
   83:   /* Update interface address information to protocol daemon. */
   84:   if (ifc->address->family == AF_INET)
   85:     if_subnet_add (ifp, ifc);
   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: /* If same interface address is already exist... */
  101: struct connected *
  102: connected_check (struct interface *ifp, struct prefix *p)
  103: {
  104:   struct connected *ifc;
  105:   struct listnode *node;
  106: 
  107:   for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc))
  108:     if (prefix_same (ifc->address, p))
  109:       return ifc;
  110: 
  111:   return NULL;
  112: }
  113: 
  114: /* Check if two ifc's describe the same address in the same state */
  115: static int
  116: connected_same (struct connected *ifc1, struct connected *ifc2)
  117: {
  118:   if (ifc1->ifp != ifc2->ifp)
  119:     return 0;
  120:   
  121:   if (ifc1->destination)
  122:     if (!ifc2->destination)
  123:       return 0;
  124:   if (ifc2->destination)
  125:     if (!ifc1->destination)
  126:       return 0;
  127:   
  128:   if (ifc1->destination && ifc2->destination)
  129:     if (!prefix_same (ifc1->destination, ifc2->destination))
  130:       return 0;
  131: 
  132:   if (ifc1->flags != ifc2->flags)
  133:     return 0;
  134: 
  135:   if (ifc1->conf != ifc2->conf)
  136:     return 0;
  137:   
  138:   return 1;
  139: }
  140: 
  141: /* Handle changes to addresses and send the neccesary announcements
  142:  * to clients. */
  143: static void
  144: connected_update(struct interface *ifp, struct connected *ifc)
  145: {
  146:   struct connected *current;
  147:   
  148:   /* Check same connected route. */
  149:   if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
  150:     {
  151:       if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
  152:         SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
  153: 	
  154:       /* Avoid spurious withdraws, this might be just the kernel 'reflecting'
  155:        * back an address we have already added.
  156:        */
  157:       if (connected_same (current, ifc))
  158:         {
  159:           /* nothing to do */
  160:           connected_free (ifc);
  161:           return;
  162:         }
  163: 
  164:       /* Clear the configured flag on the old ifc, so it will be freed by
  165:        * connected withdraw. */
  166:       UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED);
  167:       connected_withdraw (current); /* implicit withdraw - freebsd does this */
  168:     }
  169: 
  170:   /* If the connected is new or has changed, announce it, if it is usable */
  171:   if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
  172:     connected_announce(ifp, ifc);
  173: }
  174: 
  175: /* Called from if_up(). */
  176: void
  177: connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
  178: {
  179:   struct prefix_ipv4 p;
  180: 
  181:   if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
  182:     return;
  183: 
  184:   PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
  185: 
  186:   /* Apply mask to the network. */
  187:   apply_mask_ipv4 (&p);
  188: 
  189:   /* In case of connected address is 0.0.0.0/0 we treat it tunnel
  190:      address. */
  191:   if (prefix_ipv4_any (&p))
  192:     return;
  193: 
  194:   rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex,
  195:        ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, 0, SAFI_UNICAST);
  196: 
  197:   rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex,
  198:        ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, 0, SAFI_MULTICAST);
  199: 
  200:   rib_update (ifp->vrf_id);
  201: }
  202: 
  203: /* Add connected IPv4 route to the interface. */
  204: void
  205: connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, 
  206: 		    u_char prefixlen, struct in_addr *broad, 
  207: 		    const char *label)
  208: {
  209:   struct prefix_ipv4 *p;
  210:   struct connected *ifc;
  211: 
  212:   /* Make connected structure. */
  213:   ifc = connected_new ();
  214:   ifc->ifp = ifp;
  215:   ifc->flags = flags;
  216:   /* If we get a notification from the kernel,
  217:    * we can safely assume the address is known to the kernel */
  218:   SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
  219: 
  220:   /* Allocate new connected address. */
  221:   p = prefix_ipv4_new ();
  222:   p->family = AF_INET;
  223:   p->prefix = *addr;
  224:   p->prefixlen = prefixlen;
  225:   ifc->address = (struct prefix *) p;
  226:   
  227:   /* If there is broadcast or peer address. */
  228:   if (broad)
  229:     {
  230:       p = prefix_ipv4_new ();
  231:       p->family = AF_INET;
  232:       p->prefix = *broad;
  233:       p->prefixlen = prefixlen;
  234:       ifc->destination = (struct prefix *) p;
  235: 
  236:       /* validate the destination address */
  237:       if (CONNECTED_PEER(ifc))
  238:         {
  239: 	  if (IPV4_ADDR_SAME(addr,broad))
  240: 	    zlog_warn("warning: interface %s has same local and peer "
  241: 		      "address %s, routing protocols may malfunction",
  242: 		      ifp->name,inet_ntoa(*addr));
  243:         }
  244:       else
  245:         {
  246: 	  if (broad->s_addr != ipv4_broadcast_addr(addr->s_addr,prefixlen))
  247: 	    {
  248: 	      char buf[2][INET_ADDRSTRLEN];
  249: 	      struct in_addr bcalc;
  250: 	      bcalc.s_addr = ipv4_broadcast_addr(addr->s_addr,prefixlen);
  251: 	      zlog_warn("warning: interface %s broadcast addr %s/%d != "
  252: 	       		"calculated %s, routing protocols may malfunction",
  253: 	    		ifp->name,
  254: 			inet_ntop (AF_INET, broad, buf[0], sizeof(buf[0])),
  255: 			prefixlen,
  256: 			inet_ntop (AF_INET, &bcalc, buf[1], sizeof(buf[1])));
  257: 	    }
  258:         }
  259: 
  260:     }
  261:   else
  262:     {
  263:       if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER))
  264:         {
  265: 	  zlog_warn("warning: %s called for interface %s "
  266: 		    "with peer flag set, but no peer address supplied",
  267: 		    __func__, ifp->name);
  268: 	  UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
  269: 	}
  270: 
  271:       /* no broadcast or destination address was supplied */
  272:       if ((prefixlen == IPV4_MAX_PREFIXLEN) && if_is_pointopoint(ifp))
  273: 	zlog_warn("warning: PtP interface %s with addr %s/%d needs a "
  274: 		  "peer address",ifp->name,inet_ntoa(*addr),prefixlen);
  275:     }
  276: 
  277:   /* Label of this address. */
  278:   if (label)
  279:     ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
  280: 
  281:   /* For all that I know an IPv4 address is always ready when we receive
  282:    * the notification. So it should be safe to set the REAL flag here. */
  283:   SET_FLAG(ifc->conf, ZEBRA_IFC_REAL);
  284: 
  285:   connected_update(ifp, ifc);
  286: }
  287: 
  288: void
  289: connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
  290: {
  291:   struct prefix_ipv4 p;
  292: 
  293:   if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
  294:     return;
  295: 
  296:   PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
  297: 
  298:   /* Apply mask to the network. */
  299:   apply_mask_ipv4 (&p);
  300: 
  301:   /* In case of connected address is 0.0.0.0/0 we treat it tunnel
  302:      address. */
  303:   if (prefix_ipv4_any (&p))
  304:     return;
  305: 
  306:   /* Same logic as for connected_up_ipv4(): push the changes into the head. */
  307:   rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id,
  308:                    SAFI_UNICAST);
  309: 
  310:   rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id,
  311:                    SAFI_MULTICAST);
  312: 
  313:   rib_update (ifp->vrf_id);
  314: }
  315: 
  316: /* Delete connected IPv4 route to the interface. */
  317: void
  318: connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
  319: 		       u_char prefixlen, struct in_addr *broad)
  320: {
  321:   struct prefix_ipv4 p;
  322:   struct connected *ifc;
  323: 
  324:   memset (&p, 0, sizeof (struct prefix_ipv4));
  325:   p.family = AF_INET;
  326:   p.prefix = *addr;
  327:   p.prefixlen = prefixlen;
  328: 
  329:   ifc = connected_check (ifp, (struct prefix *) &p);
  330:   if (! ifc)
  331:     return;
  332:     
  333:   connected_withdraw (ifc);
  334: 
  335:   rib_update (ifp->vrf_id);
  336: }
  337: 
  338: #ifdef HAVE_IPV6
  339: void
  340: connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
  341: {
  342:   struct prefix_ipv6 p;
  343: 
  344:   if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
  345:     return;
  346: 
  347:   PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc));
  348: 
  349:   /* Apply mask to the network. */
  350:   apply_mask_ipv6 (&p);
  351: 
  352: #ifndef LINUX
  353:   /* XXX: It is already done by rib_bogus_ipv6 within rib_add_ipv6 */
  354:   if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
  355:     return;
  356: #endif
  357: 
  358:   rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id,
  359:                 RT_TABLE_MAIN, ifp->metric, 0, 0, SAFI_UNICAST);
  360: 
  361:   rib_update (ifp->vrf_id);
  362: }
  363: 
  364: /* Add connected IPv6 route to the interface. */
  365: void
  366: connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr,
  367: 		    u_char prefixlen, struct in6_addr *broad,
  368: 		    const char *label)
  369: {
  370:   struct prefix_ipv6 *p;
  371:   struct connected *ifc;
  372: 
  373:   /* Make connected structure. */
  374:   ifc = connected_new ();
  375:   ifc->ifp = ifp;
  376:   ifc->flags = flags;
  377:   /* If we get a notification from the kernel,
  378:    * we can safely assume the address is known to the kernel */
  379:   SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
  380: 
  381:   /* Allocate new connected address. */
  382:   p = prefix_ipv6_new ();
  383:   p->family = AF_INET6;
  384:   IPV6_ADDR_COPY (&p->prefix, addr);
  385:   p->prefixlen = prefixlen;
  386:   ifc->address = (struct prefix *) p;
  387: 
  388:   /* If there is broadcast or peer address. */
  389:   if (broad)
  390:     {
  391:       if (IN6_IS_ADDR_UNSPECIFIED(broad))
  392: 	zlog_warn("warning: %s called for interface %s with unspecified "
  393: 		  "destination address; ignoring!", __func__, ifp->name);
  394:       else
  395: 	{
  396: 	  p = prefix_ipv6_new ();
  397: 	  p->family = AF_INET6;
  398: 	  IPV6_ADDR_COPY (&p->prefix, broad);
  399: 	  p->prefixlen = prefixlen;
  400: 	  ifc->destination = (struct prefix *) p;
  401: 	}
  402:     }
  403:   if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER) && !ifc->destination)
  404:     {
  405:       zlog_warn("warning: %s called for interface %s "
  406: 		"with peer flag set, but no peer address supplied",
  407: 		__func__, ifp->name);
  408:       UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
  409:     }
  410: 
  411:   /* Label of this address. */
  412:   if (label)
  413:     ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
  414: 
  415:   /* On Linux, we only get here when DAD is complete, therefore we can set
  416:    * ZEBRA_IFC_REAL.
  417:    *
  418:    * On BSD, there currently doesn't seem to be a way to check for completion of
  419:    * DAD, so we replicate the old behaviour and set ZEBRA_IFC_REAL, although DAD
  420:    * might still be running.
  421:    */
  422:   SET_FLAG(ifc->conf, ZEBRA_IFC_REAL);
  423:   connected_update(ifp, ifc);
  424: }
  425: 
  426: void
  427: connected_down_ipv6 (struct interface *ifp, struct connected *ifc)
  428: {
  429:   struct prefix_ipv6 p;
  430: 
  431:   if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
  432:     return;
  433: 
  434:   PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc));
  435: 
  436:   apply_mask_ipv6 (&p);
  437: 
  438:   if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
  439:     return;
  440: 
  441:   rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id,
  442:                    SAFI_UNICAST);
  443: 
  444:   rib_update (ifp->vrf_id);
  445: }
  446: 
  447: void
  448: connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
  449: 		       u_char prefixlen, struct in6_addr *broad)
  450: {
  451:   struct prefix_ipv6 p;
  452:   struct connected *ifc;
  453:   
  454:   memset (&p, 0, sizeof (struct prefix_ipv6));
  455:   p.family = AF_INET6;
  456:   memcpy (&p.prefix, address, sizeof (struct in6_addr));
  457:   p.prefixlen = prefixlen;
  458: 
  459:   ifc = connected_check (ifp, (struct prefix *) &p);
  460:   if (! ifc)
  461:     return;
  462: 
  463:   connected_withdraw (ifc);
  464: 
  465:   rib_update (ifp->vrf_id);
  466: }
  467: #endif /* HAVE_IPV6 */

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