New functions for getting and setting network device flags.
authorBen Pfaff <blp@nicira.com>
Wed, 21 May 2008 21:11:59 +0000 (14:11 -0700)
committerBen Pfaff <blp@nicira.com>
Wed, 28 May 2008 17:46:54 +0000 (10:46 -0700)
This allows us to open network devices without bringing them up
and setting them for promiscuous mode, which will be useful in the
secchan for in-band communication.

include/netdev.h
lib/netdev.c
switch/datapath.c

index 990d499..3dfd5db 100644 (file)
@@ -47,6 +47,11 @@ struct buffer;
 struct in_addr;
 struct in6_addr;
 
+enum netdev_flags {
+    NETDEV_UP = 0x0001,         /* Device enabled? */
+    NETDEV_PROMISC = 0x0002     /* Promiscuous mode? */
+};
+
 struct netdev;
 int netdev_open(const char *name, struct netdev **);
 void netdev_close(struct netdev *);
@@ -60,5 +65,7 @@ int netdev_get_speed(const struct netdev *);
 uint32_t netdev_get_features(const struct netdev *);
 bool netdev_get_in4(const struct netdev *, struct in_addr *);
 bool netdev_get_in6(const struct netdev *, struct in6_addr *);
+int netdev_get_flags(const struct netdev *, enum netdev_flags *);
+int netdev_set_flags(struct netdev *, enum netdev_flags);
 
 #endif /* netdev.h */
index df96792..d29848d 100644 (file)
@@ -80,6 +80,8 @@ static struct list netdev_list = LIST_INITIALIZER(&netdev_list);
 
 static void init_netdev(void);
 static int restore_flags(struct netdev *netdev);
+static int get_flags(const struct netdev *, int *flagsp);
+static int set_flags(struct netdev *, int flags);
 
 /* Obtains the IPv4 address for 'name' into 'in4'.  Returns true if
  * successful. */
@@ -321,32 +323,21 @@ netdev_open(const char *name, struct netdev **netdev_)
     do_ethtool(netdev);
 
     /* Save flags to restore at close or exit. */
-    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
-        VLOG_ERR("ioctl(SIOCGIFFLAGS) on %s device failed: %s",
-                 name, strerror(errno));
-        goto error;
+    error = get_flags(netdev, &netdev->save_flags);
+    if (error) {
+        goto preset_error;
     }
-    netdev->save_flags = ifr.ifr_flags;
     fatal_signal_block();
     list_push_back(&netdev_list, &netdev->node);
     fatal_signal_unblock();
 
-    /* Bring up interface and set promiscuous mode. */
-    ifr.ifr_flags |= IFF_PROMISC | IFF_UP;
-    if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
-        error = errno;
-        VLOG_ERR("failed to set promiscuous mode on %s device: %s",
-                 name, strerror(errno));
-        netdev_close(netdev);
-        return error;
-    }
-
     /* Success! */
     *netdev_ = netdev;
     return 0;
 
 error:
     error = errno;
+preset_error:
     close(fd);
     return error;
 }
@@ -561,6 +552,54 @@ netdev_get_in6(const struct netdev *netdev, struct in6_addr *in6)
     *in6 = netdev->in6;
     return memcmp(in6, &in6addr_any, sizeof *in6) != 0;
 }
+
+/* Obtains the current flags for 'netdev' and stores them into '*flagsp'.
+ * Returns 0 if successful, otherwise a positive errno value. */
+int
+netdev_get_flags(const struct netdev *netdev, enum netdev_flags *flagsp)
+{
+    int error, flags;
+
+    error = get_flags(netdev, &flags);
+    if (error) {
+        return error;
+    }
+
+    *flagsp = 0;
+    if (flags & IFF_UP) {
+        *flagsp |= NETDEV_UP;
+    }
+    if (flags & IFF_PROMISC) {
+        *flagsp |= NETDEV_PROMISC;
+    }
+    return 0;
+}
+
+/* Sets the flags for 'netdev' to 'nd_flags'.
+ * Returns 0 if successful, otherwise a positive errno value. */
+int
+netdev_set_flags(struct netdev *netdev, enum netdev_flags nd_flags)
+{
+    int old_flags, new_flags;
+    int error;
+
+    error = get_flags(netdev, &old_flags);
+    if (error) {
+        return error;
+    }
+
+    new_flags = old_flags & ~(IFF_UP | IFF_PROMISC);
+    if (nd_flags & NETDEV_UP) {
+        new_flags |= IFF_UP;
+    }
+    if (nd_flags & NETDEV_PROMISC) {
+        new_flags |= IFF_PROMISC;
+    }
+    if (new_flags != old_flags) {
+        error = set_flags(netdev, new_flags);
+    }
+    return error;
+}
 \f
 static void restore_all_flags(void *aux);
 
@@ -614,3 +653,31 @@ restore_all_flags(void *aux UNUSED)
         restore_flags(netdev);
     }
 }
+
+static int
+get_flags(const struct netdev *netdev, int *flags)
+{
+    struct ifreq ifr;
+    strncpy(ifr.ifr_name, netdev->name, sizeof ifr.ifr_name);
+    if (ioctl(netdev->fd, SIOCGIFFLAGS, &ifr) < 0) {
+        VLOG_ERR("ioctl(SIOCGIFFLAGS) on %s device failed: %s",
+                 netdev->name, strerror(errno));
+        return errno;
+    }
+    *flags = ifr.ifr_flags;
+    return 0;
+}
+
+static int
+set_flags(struct netdev *netdev, int flags)
+{
+    struct ifreq ifr;
+    strncpy(ifr.ifr_name, netdev->name, sizeof ifr.ifr_name);
+    ifr.ifr_flags = flags;
+    if (ioctl(netdev->fd, SIOCSIFFLAGS, &ifr) < 0) {
+        VLOG_ERR("ioctl(SIOCSIFFLAGS) on %s device failed: %s",
+                 netdev->name, strerror(errno));
+        return errno;
+    }
+    return 0;
+}
index b83ac48..5a0e14c 100644 (file)
@@ -226,6 +226,12 @@ dp_add_port(struct datapath *dp, const char *name)
     if (error) {
         return error;
     }
+    error = netdev_set_flags(netdev, NETDEV_UP | NETDEV_PROMISC);
+    if (error) {
+        VLOG_ERR("Couldn't set promiscuous mode on %s device", name);
+        netdev_close(netdev);
+        return error;
+    }
     if (netdev_get_in4(netdev, &in4)) {
         VLOG_ERR("%s device has assigned IP address %s", name, inet_ntoa(in4));
     }