Annotation of embedaddon/quagga/zebra/connected.c, revision 1.1

1.1     ! misho       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>