]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/ioctl.c
Merge pull request #296 from opensourcerouting/ldpd-sighup
[mirror_frr.git] / zebra / ioctl.c
index 06be5bec9987ca46ee919010834104ea27dd1f1c..dfd69300f9c3c85645ca860cb7424d72a7123a05 100644 (file)
 #include "log.h"
 #include "privs.h"
 
+#include "vty.h"
 #include "zebra/rib.h"
 #include "zebra/rt.h"
 #include "zebra/interface.h"
 
+#ifdef HAVE_BSD_LINK_DETECT
+#include <net/if_media.h>
+#endif /* HAVE_BSD_LINK_DETECT*/
+
 extern struct zebra_privs_t zserv_privs;
 
 /* clear and set interface name string */
@@ -48,23 +53,23 @@ if_ioctl (u_long request, caddr_t buffer)
 {
   int sock;
   int ret;
-  int err;
+  int err = 0;
 
   if (zserv_privs.change(ZPRIVS_RAISE))
-    zlog (NULL, LOG_ERR, "Can't raise privileges");
+    zlog_err("Can't raise privileges");
   sock = socket (AF_INET, SOCK_DGRAM, 0);
   if (sock < 0)
     {
       int save_errno = errno;
       if (zserv_privs.change(ZPRIVS_LOWER))
-        zlog (NULL, LOG_ERR, "Can't lower privileges");
+        zlog_err("Can't lower privileges");
       zlog_err("Cannot create UDP socket: %s", safe_strerror(save_errno));
       exit (1);
     }
   if ((ret = ioctl (sock, request, buffer)) < 0)
     err = errno;
   if (zserv_privs.change(ZPRIVS_LOWER))
-    zlog (NULL, LOG_ERR, "Can't lower privileges");
+    zlog_err("Can't lower privileges");
   close (sock);
   
   if (ret < 0) 
@@ -75,22 +80,21 @@ if_ioctl (u_long request, caddr_t buffer)
   return 0;
 }
 
-#ifdef HAVE_IPV6
 static int
 if_ioctl_ipv6 (u_long request, caddr_t buffer)
 {
   int sock;
   int ret;
-  int err;
+  int err = 0;
 
   if (zserv_privs.change(ZPRIVS_RAISE))
-    zlog (NULL, LOG_ERR, "Can't raise privileges");
+    zlog_err("Can't raise privileges");
   sock = socket (AF_INET6, SOCK_DGRAM, 0);
   if (sock < 0)
     {
       int save_errno = errno;
       if (zserv_privs.change(ZPRIVS_LOWER))
-        zlog (NULL, LOG_ERR, "Can't lower privileges");
+        zlog_err("Can't lower privileges");
       zlog_err("Cannot create IPv6 datagram socket: %s",
               safe_strerror(save_errno));
       exit (1);
@@ -99,7 +103,7 @@ if_ioctl_ipv6 (u_long request, caddr_t buffer)
   if ((ret = ioctl (sock, request, buffer)) < 0)
     err = errno;
   if (zserv_privs.change(ZPRIVS_LOWER))
-    zlog (NULL, LOG_ERR, "Can't lower privileges");
+    zlog_err("Can't lower privileges");
   close (sock);
   
   if (ret < 0) 
@@ -109,7 +113,6 @@ if_ioctl_ipv6 (u_long request, caddr_t buffer)
     }
   return 0;
 }
-#endif /* HAVE_IPV6 */
 
 /*
  * get interface metric
@@ -155,8 +158,11 @@ if_get_mtu (struct interface *ifp)
   ifp->mtu6 = ifp->mtu = ifreq.ifr_mtu;
 #endif /* SUNOS_5 */
 
+  /* propogate */
+  zebra_interface_up_update(ifp);
+
 #else
-  zlog (NULL, LOG_INFO, "Can't lookup mtu on this system");
+  zlog_info("Can't lookup mtu on this system");
   ifp->mtu6 = ifp->mtu = -1;
 #endif
 }
@@ -176,7 +182,7 @@ if_unset_prefix (struct interface *ifp, struct connected *ifc)
   return kernel_address_delete_ipv4 (ifp, ifc);
 }
 #else /* ! HAVE_NETLINK */
-#ifdef HAVE_IFALIASREQ
+#ifdef HAVE_STRUCT_IFALIASREQ
 /* Set up interface's IP address, netmask (and broadcas? ).  *BSD may
    has ifaliasreq structure.  */
 int
@@ -189,6 +195,7 @@ if_set_prefix (struct interface *ifp, struct connected *ifc)
   struct prefix_ipv4 *p;
 
   p = (struct prefix_ipv4 *) ifc->address;
+  rib_lookup_and_pushup (p, ifp->vrf_id);
 
   memset (&addreq, 0, sizeof addreq);
   strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
@@ -196,7 +203,7 @@ if_set_prefix (struct interface *ifp, struct connected *ifc)
   memset (&addr, 0, sizeof (struct sockaddr_in));
   addr.sin_addr = p->prefix;
   addr.sin_family = p->family;
-#ifdef HAVE_SIN_LEN
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
   addr.sin_len = sizeof (struct sockaddr_in);
 #endif
   memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in));
@@ -204,7 +211,7 @@ if_set_prefix (struct interface *ifp, struct connected *ifc)
   memset (&mask, 0, sizeof (struct sockaddr_in));
   masklen2ip (p->prefixlen, &mask.sin_addr);
   mask.sin_family = p->family;
-#ifdef HAVE_SIN_LEN
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
   mask.sin_len = sizeof (struct sockaddr_in);
 #endif
   memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in));
@@ -234,7 +241,7 @@ if_unset_prefix (struct interface *ifp, struct connected *ifc)
   memset (&addr, 0, sizeof (struct sockaddr_in));
   addr.sin_addr = p->prefix;
   addr.sin_family = p->family;
-#ifdef HAVE_SIN_LEN
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
   addr.sin_len = sizeof (struct sockaddr_in);
 #endif
   memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in));
@@ -242,7 +249,7 @@ if_unset_prefix (struct interface *ifp, struct connected *ifc)
   memset (&mask, 0, sizeof (struct sockaddr_in));
   masklen2ip (p->prefixlen, &mask.sin_addr);
   mask.sin_family = p->family;
-#ifdef HAVE_SIN_LEN
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
   mask.sin_len = sizeof (struct sockaddr_in);
 #endif
   memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in));
@@ -332,7 +339,7 @@ if_unset_prefix (struct interface *ifp, struct connected *ifc)
 
   return 0;
 }
-#endif /* HAVE_IFALIASREQ */
+#endif /* HAVE_STRUCT_IFALIASREQ */
 #endif /* HAVE_NETLINK */
 
 /* get interface flags */
@@ -341,6 +348,9 @@ if_get_flags (struct interface *ifp)
 {
   int ret;
   struct ifreq ifreq;
+#ifdef HAVE_BSD_LINK_DETECT
+  struct ifmediareq ifmr;
+#endif /* HAVE_BSD_LINK_DETECT */
 
   ifreq_set_name (&ifreq, ifp);
 
@@ -350,6 +360,31 @@ if_get_flags (struct interface *ifp)
       zlog_err("if_ioctl(SIOCGIFFLAGS) failed: %s", safe_strerror(errno));
       return;
     }
+#ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */
+
+  /* Per-default, IFF_RUNNING is held high, unless link-detect says
+   * otherwise - we abuse IFF_RUNNING inside zebra as a link-state flag,
+   * following practice on Linux and Solaris kernels
+   */
+  SET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
+  
+  if (CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_LINKDETECTION))
+    {
+      (void) memset(&ifmr, 0, sizeof(ifmr));
+      strncpy (ifmr.ifm_name, ifp->name, IFNAMSIZ);
+      
+      /* Seems not all interfaces implement this ioctl */
+      if (if_ioctl(SIOCGIFMEDIA, (caddr_t) &ifmr) < 0)
+        zlog_err("if_ioctl(SIOCGIFMEDIA) failed: %s", safe_strerror(errno));
+      else if (ifmr.ifm_status & IFM_AVALID) /* Link state is valid */
+        {
+          if (ifmr.ifm_status & IFM_ACTIVE)
+            SET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
+          else
+            UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
+        }
+  }
+#endif /* HAVE_BSD_LINK_DETECT */
 
   if_flags_update (ifp, (ifreq.ifr_flags & 0x0000ffff));
 }
@@ -400,8 +435,6 @@ if_unset_flags (struct interface *ifp, uint64_t flags)
   return 0;
 }
 
-#ifdef HAVE_IPV6
-
 #ifdef LINUX_IPV6
 #ifndef _LINUX_IN6_H
 /* linux/include/net/ipv6.h */
@@ -454,7 +487,7 @@ if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
   return ret;
 }
 #else /* LINUX_IPV6 */
-#ifdef HAVE_IN6_ALIASREQ
+#ifdef HAVE_STRUCT_IN6_ALIASREQ
 #ifndef ND6_INFINITE_LIFETIME
 #define ND6_INFINITE_LIFETIME 0xffffffffL
 #endif /* ND6_INFINITE_LIFETIME */
@@ -475,7 +508,7 @@ if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
   memset (&addr, 0, sizeof (struct sockaddr_in6));
   addr.sin6_addr = p->prefix;
   addr.sin6_family = p->family;
-#ifdef HAVE_SIN_LEN
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
   addr.sin6_len = sizeof (struct sockaddr_in6);
 #endif
   memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6));
@@ -483,7 +516,7 @@ if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
   memset (&mask, 0, sizeof (struct sockaddr_in6));
   masklen2ip6 (p->prefixlen, &mask.sin6_addr);
   mask.sin6_family = p->family;
-#ifdef HAVE_SIN_LEN
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
   mask.sin6_len = sizeof (struct sockaddr_in6);
 #endif
   memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6));
@@ -491,7 +524,7 @@ if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
   addreq.ifra_lifetime.ia6t_vltime = 0xffffffff;
   addreq.ifra_lifetime.ia6t_pltime = 0xffffffff;
   
-#ifdef HAVE_IFRA_LIFETIME 
+#ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME 
   addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 
   addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 
 #endif
@@ -519,7 +552,7 @@ if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
   memset (&addr, 0, sizeof (struct sockaddr_in6));
   addr.sin6_addr = p->prefix;
   addr.sin6_family = p->family;
-#ifdef HAVE_SIN_LEN
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
   addr.sin6_len = sizeof (struct sockaddr_in6);
 #endif
   memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6));
@@ -527,12 +560,12 @@ if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
   memset (&mask, 0, sizeof (struct sockaddr_in6));
   masklen2ip6 (p->prefixlen, &mask.sin6_addr);
   mask.sin6_family = p->family;
-#ifdef HAVE_SIN_LEN
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
   mask.sin6_len = sizeof (struct sockaddr_in6);
 #endif
   memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6));
 
-#ifdef HAVE_IFRA_LIFETIME
+#ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
   addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 
   addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 
 #endif
@@ -554,8 +587,6 @@ if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
 {
   return 0;
 }
-#endif /* HAVE_IN6_ALIASREQ */
+#endif /* HAVE_STRUCT_IN6_ALIASREQ */
 
 #endif /* LINUX_IPV6 */
-
-#endif /* HAVE_IPV6 */