dynamic-string: Document a few functions.
[openvswitch] / lib / netdev-linux.c
index 19a80fbe14e1f4587c7aa615bd167a37b2b1faa2..6ad08520050307f64aabf784e2dbaf86e862091d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -368,7 +368,7 @@ struct netdev_dev_linux {
     struct in_addr address, netmask;
     struct in6_addr in6;
     int mtu;
-    bool carrier;
+    unsigned int ifi_flags;
     long long int carrier_resets;
     uint32_t kbits_rate;        /* Policing data. */
     uint32_t kbits_burst;
@@ -403,8 +403,8 @@ static int netdev_linux_do_ioctl(const char *name, struct ifreq *, int cmd,
                                  const char *cmd_name);
 static int netdev_linux_get_ipv4(const struct netdev *, struct in_addr *,
                                  int cmd, const char *cmd_name);
-static int get_flags(const struct netdev *, int *flagsp);
-static int set_flags(struct netdev *, int flags);
+static int get_flags(const struct netdev_dev *, unsigned int *flags);
+static int set_flags(struct netdev *, unsigned int flags);
 static int do_get_ifindex(const char *netdev_name);
 static int get_ifindex(const struct netdev *, int *ifindexp);
 static int do_set_addr(struct netdev *netdev,
@@ -415,7 +415,6 @@ static int set_etheraddr(const char *netdev_name, int hwaddr_family,
                          const uint8_t[ETH_ADDR_LEN]);
 static int get_stats_via_netlink(int ifindex, struct netdev_stats *stats);
 static int get_stats_via_proc(const char *netdev_name, struct netdev_stats *stats);
-static int get_carrier_via_sysfs(const char *name, bool *carrier);
 static int af_packet_sock(void);
 static void netdev_linux_miimon_run(void);
 static void netdev_linux_miimon_wait(void);
@@ -484,12 +483,18 @@ netdev_linux_wait(void)
 }
 
 static void
-netdev_dev_linux_changed(struct netdev_dev_linux *dev)
+netdev_dev_linux_changed(struct netdev_dev_linux *dev, unsigned int ifi_flags)
 {
     dev->change_seq++;
     if (!dev->change_seq) {
         dev->change_seq++;
     }
+
+    if ((dev->ifi_flags ^ ifi_flags) & IFF_RUNNING) {
+        dev->carrier_resets++;
+    }
+    dev->ifi_flags = ifi_flags;
+
     dev->cache_valid = 0;
 }
 
@@ -506,13 +511,7 @@ netdev_linux_cache_cb(const struct rtnetlink_link_change *change,
 
             if (is_netdev_linux_class(netdev_class)) {
                 dev = netdev_dev_linux_cast(base_dev);
-
-                if (dev->carrier != change->running) {
-                    dev->carrier = change->running;
-                    dev->carrier_resets++;
-                }
-
-                netdev_dev_linux_changed(dev);
+                netdev_dev_linux_changed(dev, change->ifi_flags);
             }
         }
     } else {
@@ -522,17 +521,12 @@ netdev_linux_cache_cb(const struct rtnetlink_link_change *change,
         shash_init(&device_shash);
         netdev_dev_get_devices(&netdev_linux_class, &device_shash);
         SHASH_FOR_EACH (node, &device_shash) {
-            bool carrier;
+            unsigned int flags;
 
             dev = node->data;
 
-            get_carrier_via_sysfs(node->name, &carrier);
-            if (dev->carrier != carrier) {
-                dev->carrier = carrier;
-                dev->carrier_resets++;
-            }
-
-            netdev_dev_linux_changed(dev);
+            get_flags(&dev->netdev_dev, &flags);
+            netdev_dev_linux_changed(dev, flags);
         }
         shash_destroy(&device_shash);
     }
@@ -583,7 +577,7 @@ netdev_linux_create(const struct netdev_class *class, const char *name,
     netdev_dev = xzalloc(sizeof *netdev_dev);
     netdev_dev->change_seq = 1;
     netdev_dev_init(&netdev_dev->netdev_dev, name, class);
-    get_carrier_via_sysfs(name, &netdev_dev->carrier);
+    get_flags(&netdev_dev->netdev_dev, &netdev_dev->ifi_flags);
 
     *netdev_devp = &netdev_dev->netdev_dev;
     return 0;
@@ -1030,6 +1024,10 @@ netdev_linux_set_mtu(const struct netdev *netdev_, int mtu)
     struct ifreq ifr;
     int error;
 
+    if (netdev_dev->cache_valid & VALID_MTU &&
+        netdev_dev->mtu == mtu) {
+        return 0;
+    }
     ifr.ifr_mtu = mtu;
     error = netdev_linux_do_ioctl(netdev_get_name(netdev_), &ifr,
                                   SIOCSIFMTU, "SIOCSIFMTU");
@@ -1062,7 +1060,7 @@ netdev_linux_get_carrier(const struct netdev *netdev_, bool *carrier)
     if (netdev_dev->miimon_interval > 0) {
         *carrier = netdev_dev->miimon;
     } else {
-        *carrier = netdev_dev->carrier;
+        *carrier = (netdev_dev->ifi_flags & IFF_RUNNING) != 0;
     }
 
     return 0;
@@ -1168,7 +1166,7 @@ netdev_linux_miimon_run(void)
         netdev_linux_get_miimon(dev->netdev_dev.name, &miimon);
         if (miimon != dev->miimon) {
             dev->miimon = miimon;
-            netdev_dev_linux_changed(dev);
+            netdev_dev_linux_changed(dev, dev->ifi_flags);
         }
 
         timer_set_duration(&dev->miimon_timer, dev->miimon_interval);
@@ -2209,16 +2207,17 @@ static int
 netdev_linux_update_flags(struct netdev *netdev, enum netdev_flags off,
                           enum netdev_flags on, enum netdev_flags *old_flagsp)
 {
+    struct netdev_dev_linux *netdev_dev;
     int old_flags, new_flags;
-    int error;
+    int error = 0;
 
-    error = get_flags(netdev, &old_flags);
-    if (!error) {
-        *old_flagsp = iff_to_nd_flags(old_flags);
-        new_flags = (old_flags & ~nd_to_iff_flags(off)) | nd_to_iff_flags(on);
-        if (new_flags != old_flags) {
-            error = set_flags(netdev, new_flags);
-        }
+    netdev_dev = netdev_dev_linux_cast(netdev_get_dev(netdev));
+    old_flags = netdev_dev->ifi_flags;
+    *old_flagsp = iff_to_nd_flags(old_flags);
+    new_flags = (old_flags & ~nd_to_iff_flags(off)) | nd_to_iff_flags(on);
+    if (new_flags != old_flags) {
+        error = set_flags(netdev, new_flags);
+        get_flags(&netdev_dev->netdev_dev, &netdev_dev->ifi_flags);
     }
     return error;
 }
@@ -4214,71 +4213,22 @@ get_stats_via_proc(const char *netdev_name, struct netdev_stats *stats)
 }
 
 static int
-get_carrier_via_sysfs(const char *name, bool *carrier)
-{
-    char line[8];
-    int retval;
-
-    int error = 0;
-    char *fn = NULL;
-    int fd = -1;
-
-    *carrier = false;
-
-    fn = xasprintf("/sys/class/net/%s/carrier", name);
-    fd = open(fn, O_RDONLY);
-    if (fd < 0) {
-        error = errno;
-        VLOG_WARN_RL(&rl, "%s: open failed: %s", fn, strerror(error));
-        goto exit;
-    }
-
-    retval = read(fd, line, sizeof line);
-    if (retval < 0) {
-        error = errno;
-        if (error == EINVAL) {
-            /* This is the normal return value when we try to check carrier if
-             * the network device is not up. */
-        } else {
-            VLOG_WARN_RL(&rl, "%s: read failed: %s", fn, strerror(error));
-        }
-        goto exit;
-    } else if (retval == 0) {
-        error = EPROTO;
-        VLOG_WARN_RL(&rl, "%s: unexpected end of file", fn);
-        goto exit;
-    }
-
-    if (line[0] != '0' && line[0] != '1') {
-        error = EPROTO;
-        VLOG_WARN_RL(&rl, "%s: value is %c (expected 0 or 1)", fn, line[0]);
-        goto exit;
-    }
-    *carrier = line[0] != '0';
-    error = 0;
-
-exit:
-    if (fd >= 0) {
-        close(fd);
-    }
-    free(fn);
-    return error;
-}
-
-static int
-get_flags(const struct netdev *netdev, int *flags)
+get_flags(const struct netdev_dev *dev, unsigned int *flags)
 {
     struct ifreq ifr;
     int error;
 
-    error = netdev_linux_do_ioctl(netdev_get_name(netdev), &ifr, SIOCGIFFLAGS,
+    *flags = 0;
+    error = netdev_linux_do_ioctl(dev->name, &ifr, SIOCGIFFLAGS,
                                   "SIOCGIFFLAGS");
-    *flags = ifr.ifr_flags;
+    if (!error) {
+        *flags = ifr.ifr_flags;
+    }
     return error;
 }
 
 static int
-set_flags(struct netdev *netdev, int flags)
+set_flags(struct netdev *netdev, unsigned int flags)
 {
     struct ifreq ifr;