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

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;
1.1.1.4 ! misho      39: 
        !            40: /* communicate the withdrawal of a connected address */
1.1       misho      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: 
1.1.1.4 ! misho      52:       if (ifc->address->family == AF_INET)
        !            53:         if_subnet_delete (ifc->ifp, ifc);
        !            54: 
1.1       misho      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: 
1.1.1.4 ! misho      65:   /* The address is not in the kernel anymore, so clear the flag */
        !            66:   UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
        !            67: 
1.1       misho      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. */
1.1.1.4 ! misho      84:   if (ifc->address->family == AF_INET)
        !            85:     if_subnet_add (ifp, ifc);
1.1       misho      86: 
1.1.1.4 ! misho      87:   zebra_interface_address_add_update (ifp, ifc);
1.1       misho      88: 
1.1.1.4 ! misho      89:   if (if_is_operative(ifp))
        !            90:     {
        !            91:       if (ifc->address->family == AF_INET)
        !            92:         connected_up_ipv4 (ifp, ifc);
1.1       misho      93: #ifdef HAVE_IPV6
1.1.1.4 ! misho      94:       else
        !            95:         connected_up_ipv6 (ifp, ifc);
1.1       misho      96: #endif
                     97:     }
                     98: }
1.1.1.4 ! misho      99: 
1.1       misho     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: 
1.1.1.4 ! misho     114: /* Check if two ifc's describe the same address in the same state */
1.1       misho     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;
1.1.1.4 ! misho     134: 
        !           135:   if (ifc1->conf != ifc2->conf)
        !           136:     return 0;
1.1       misho     137:   
                    138:   return 1;
                    139: }
                    140: 
1.1.1.4 ! misho     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)
1.1       misho     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:        */
1.1.1.4 ! misho     157:       if (connected_same (current, ifc))
1.1       misho     158:         {
                    159:           /* nothing to do */
                    160:           connected_free (ifc);
1.1.1.4 ! misho     161:           return;
1.1       misho     162:         }
1.1.1.4 ! misho     163: 
        !           164:       /* Clear the configured flag on the old ifc, so it will be freed by
        !           165:        * connected withdraw. */
1.1       misho     166:       UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED);
                    167:       connected_withdraw (current); /* implicit withdraw - freebsd does this */
                    168:     }
1.1.1.4 ! misho     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);
1.1       misho     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,
1.1.1.4 ! misho     195:        ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, 0, SAFI_UNICAST);
1.1       misho     196: 
1.1.1.3   misho     197:   rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex,
1.1.1.4 ! misho     198:        ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, 0, SAFI_MULTICAST);
1.1.1.3   misho     199: 
1.1.1.4 ! misho     200:   rib_update (ifp->vrf_id);
1.1       misho     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;
1.1.1.4 ! misho     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);
1.1       misho     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: 
1.1.1.4 ! misho     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);
1.1       misho     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. */
1.1.1.4 ! misho     307:   rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id,
        !           308:                    SAFI_UNICAST);
1.1       misho     309: 
1.1.1.4 ! misho     310:   rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id,
        !           311:                    SAFI_MULTICAST);
1.1.1.3   misho     312: 
1.1.1.4 ! misho     313:   rib_update (ifp->vrf_id);
1.1       misho     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: 
1.1.1.4 ! misho     335:   rib_update (ifp->vrf_id);
1.1       misho     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: 
1.1.1.4 ! misho     352: #ifndef LINUX
1.1       misho     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: 
1.1.1.4 ! misho     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);
1.1       misho     360: 
1.1.1.4 ! misho     361:   rib_update (ifp->vrf_id);
1.1       misho     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;
1.1.1.4 ! misho     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);
1.1       misho     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);
1.1.1.4 ! misho     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);
1.1       misho     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: 
1.1.1.4 ! misho     441:   rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id,
        !           442:                    SAFI_UNICAST);
1.1       misho     443: 
1.1.1.4 ! misho     444:   rib_update (ifp->vrf_id);
1.1       misho     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: 
1.1.1.4 ! misho     465:   rib_update (ifp->vrf_id);
1.1       misho     466: }
                    467: #endif /* HAVE_IPV6 */

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