LCOV - code coverage report
Current view: top level - zebra - connected.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 141 184 76.6 %
Date: 2015-11-19 Functions: 13 13 100.0 %

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

Generated by: LCOV version 1.10