datapath: update linux/.gitignore
[sliver-openvswitch.git] / lib / netdev-linux.c
index 16e1c35..3c474e3 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.
@@ -114,7 +114,7 @@ enum {
     VALID_IN6               = 1 << 3,
     VALID_MTU               = 1 << 4,
     VALID_POLICING          = 1 << 5,
-    VALID_HAVE_VPORT_STATS  = 1 << 6
+    VALID_VPORT_STAT_ERROR  = 1 << 6
 };
 
 struct tap_state {
@@ -368,11 +368,12 @@ struct netdev_dev_linux {
     struct in_addr address, netmask;
     struct in6_addr in6;
     int mtu;
-    int ifi_flags;
+    unsigned int ifi_flags;
     long long int carrier_resets;
     uint32_t kbits_rate;        /* Policing data. */
     uint32_t kbits_burst;
-    bool have_vport_stats;
+    int vport_stats_error;      /* Cached error code from vport_get_stats().
+                                   0 or an errno value. */
     struct tc *tc;
 
     union {
@@ -403,8 +404,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_dev *, 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,
@@ -483,12 +484,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;
 }
 
@@ -505,13 +512,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->ifi_flags ^ change->ifi_flags) & IFF_RUNNING) {
-                    dev->carrier_resets++;
-                }
-                dev->ifi_flags = change->ifi_flags;
-
-                netdev_dev_linux_changed(dev);
+                netdev_dev_linux_changed(dev, change->ifi_flags);
             }
         }
     } else {
@@ -521,17 +522,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) {
-            int flags;
+            unsigned int flags;
 
             dev = node->data;
 
             get_flags(&dev->netdev_dev, &flags);
-            if ((dev->ifi_flags ^ flags) & IFF_RUNNING) {
-                dev->carrier_resets++;
-            }
-            dev->ifi_flags = flags;
-
-            netdev_dev_linux_changed(dev);
+            netdev_dev_linux_changed(dev, flags);
         }
         shash_destroy(&device_shash);
     }
@@ -1171,7 +1167,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);
@@ -1241,8 +1237,8 @@ get_stats_via_vport(const struct netdev *netdev_,
     struct netdev_dev_linux *netdev_dev =
                                 netdev_dev_linux_cast(netdev_get_dev(netdev_));
 
-    if (netdev_dev->have_vport_stats ||
-        !(netdev_dev->cache_valid & VALID_HAVE_VPORT_STATS)) {
+    if (!netdev_dev->vport_stats_error ||
+        !(netdev_dev->cache_valid & VALID_VPORT_STAT_ERROR)) {
         int error;
 
         error = netdev_vport_get_stats(netdev_, stats);
@@ -1250,8 +1246,8 @@ get_stats_via_vport(const struct netdev *netdev_,
             VLOG_WARN_RL(&rl, "%s: obtaining netdev stats via vport failed "
                          "(%s)", netdev_get_name(netdev_), strerror(error));
         }
-        netdev_dev->have_vport_stats = !error;
-        netdev_dev->cache_valid |= VALID_HAVE_VPORT_STATS;
+        netdev_dev->vport_stats_error = error;
+        netdev_dev->cache_valid |= VALID_VPORT_STAT_ERROR;
     }
 }
 
@@ -1300,14 +1296,14 @@ netdev_linux_get_stats(const struct netdev *netdev_,
     error = netdev_linux_sys_get_stats(netdev_, &dev_stats);
 
     if (error) {
-        if (!netdev_dev->have_vport_stats) {
+        if (netdev_dev->vport_stats_error) {
             return error;
         } else {
             return 0;
         }
     }
 
-    if (!netdev_dev->have_vport_stats) {
+    if (netdev_dev->vport_stats_error) {
         /* stats not available from OVS then use ioctl stats. */
         *stats = dev_stats;
     } else {
@@ -1335,7 +1331,7 @@ netdev_linux_get_stats(const struct netdev *netdev_,
 /* Retrieves current device stats for 'netdev-tap' netdev or
  * netdev-internal. */
 static int
-netdev_pseudo_get_stats(const struct netdev *netdev_,
+netdev_tap_get_stats(const struct netdev *netdev_,
                         struct netdev_stats *stats)
 {
     struct netdev_dev_linux *netdev_dev =
@@ -1347,7 +1343,7 @@ netdev_pseudo_get_stats(const struct netdev *netdev_,
 
     error = netdev_linux_sys_get_stats(netdev_, &dev_stats);
     if (error) {
-        if (!netdev_dev->have_vport_stats) {
+        if (netdev_dev->vport_stats_error) {
             return error;
         } else {
             return 0;
@@ -1360,7 +1356,7 @@ netdev_pseudo_get_stats(const struct netdev *netdev_,
      * them back here. This does not apply if we are getting stats from the
      * vport layer because it always tracks stats from the perspective of the
      * switch. */
-    if (!netdev_dev->have_vport_stats) {
+    if (netdev_dev->vport_stats_error) {
         *stats = dev_stats;
         swap_uint64(&stats->rx_packets, &stats->tx_packets);
         swap_uint64(&stats->rx_bytes, &stats->tx_bytes);
@@ -1390,16 +1386,30 @@ netdev_pseudo_get_stats(const struct netdev *netdev_,
     return 0;
 }
 
+static int
+netdev_internal_get_stats(const struct netdev *netdev_,
+                          struct netdev_stats *stats)
+{
+    struct netdev_dev_linux *netdev_dev =
+                                netdev_dev_linux_cast(netdev_get_dev(netdev_));
+
+    get_stats_via_vport(netdev_, stats);
+    return netdev_dev->vport_stats_error;
+}
+
 /* Stores the features supported by 'netdev' into each of '*current',
  * '*advertised', '*supported', and '*peer' that are non-null.  Each value is a
- * bitmap of "enum ofp_port_features" bits, in host byte order.  Returns 0 if
- * successful, otherwise a positive errno value. */
+ * bitmap of NETDEV_* bits.  Returns 0 if successful, otherwise a positive
+ * errno value. */
 static int
 netdev_linux_get_features(const struct netdev *netdev,
-                          uint32_t *current, uint32_t *advertised,
-                          uint32_t *supported, uint32_t *peer)
+                          enum netdev_features *current,
+                          enum netdev_features *advertised,
+                          enum netdev_features *supported,
+                          enum netdev_features *peer)
 {
     struct ethtool_cmd ecmd;
+    uint32_t speed;
     int error;
 
     memset(&ecmd, 0, sizeof ecmd);
@@ -1412,102 +1422,109 @@ netdev_linux_get_features(const struct netdev *netdev,
     /* Supported features. */
     *supported = 0;
     if (ecmd.supported & SUPPORTED_10baseT_Half) {
-        *supported |= OFPPF_10MB_HD;
+        *supported |= NETDEV_F_10MB_HD;
     }
     if (ecmd.supported & SUPPORTED_10baseT_Full) {
-        *supported |= OFPPF_10MB_FD;
+        *supported |= NETDEV_F_10MB_FD;
     }
     if (ecmd.supported & SUPPORTED_100baseT_Half)  {
-        *supported |= OFPPF_100MB_HD;
+        *supported |= NETDEV_F_100MB_HD;
     }
     if (ecmd.supported & SUPPORTED_100baseT_Full) {
-        *supported |= OFPPF_100MB_FD;
+        *supported |= NETDEV_F_100MB_FD;
     }
     if (ecmd.supported & SUPPORTED_1000baseT_Half) {
-        *supported |= OFPPF_1GB_HD;
+        *supported |= NETDEV_F_1GB_HD;
     }
     if (ecmd.supported & SUPPORTED_1000baseT_Full) {
-        *supported |= OFPPF_1GB_FD;
+        *supported |= NETDEV_F_1GB_FD;
     }
     if (ecmd.supported & SUPPORTED_10000baseT_Full) {
-        *supported |= OFPPF_10GB_FD;
+        *supported |= NETDEV_F_10GB_FD;
     }
     if (ecmd.supported & SUPPORTED_TP) {
-        *supported |= OFPPF_COPPER;
+        *supported |= NETDEV_F_COPPER;
     }
     if (ecmd.supported & SUPPORTED_FIBRE) {
-        *supported |= OFPPF_FIBER;
+        *supported |= NETDEV_F_FIBER;
     }
     if (ecmd.supported & SUPPORTED_Autoneg) {
-        *supported |= OFPPF_AUTONEG;
+        *supported |= NETDEV_F_AUTONEG;
     }
     if (ecmd.supported & SUPPORTED_Pause) {
-        *supported |= OFPPF_PAUSE;
+        *supported |= NETDEV_F_PAUSE;
     }
     if (ecmd.supported & SUPPORTED_Asym_Pause) {
-        *supported |= OFPPF_PAUSE_ASYM;
+        *supported |= NETDEV_F_PAUSE_ASYM;
     }
 
     /* Advertised features. */
     *advertised = 0;
     if (ecmd.advertising & ADVERTISED_10baseT_Half) {
-        *advertised |= OFPPF_10MB_HD;
+        *advertised |= NETDEV_F_10MB_HD;
     }
     if (ecmd.advertising & ADVERTISED_10baseT_Full) {
-        *advertised |= OFPPF_10MB_FD;
+        *advertised |= NETDEV_F_10MB_FD;
     }
     if (ecmd.advertising & ADVERTISED_100baseT_Half) {
-        *advertised |= OFPPF_100MB_HD;
+        *advertised |= NETDEV_F_100MB_HD;
     }
     if (ecmd.advertising & ADVERTISED_100baseT_Full) {
-        *advertised |= OFPPF_100MB_FD;
+        *advertised |= NETDEV_F_100MB_FD;
     }
     if (ecmd.advertising & ADVERTISED_1000baseT_Half) {
-        *advertised |= OFPPF_1GB_HD;
+        *advertised |= NETDEV_F_1GB_HD;
     }
     if (ecmd.advertising & ADVERTISED_1000baseT_Full) {
-        *advertised |= OFPPF_1GB_FD;
+        *advertised |= NETDEV_F_1GB_FD;
     }
     if (ecmd.advertising & ADVERTISED_10000baseT_Full) {
-        *advertised |= OFPPF_10GB_FD;
+        *advertised |= NETDEV_F_10GB_FD;
     }
     if (ecmd.advertising & ADVERTISED_TP) {
-        *advertised |= OFPPF_COPPER;
+        *advertised |= NETDEV_F_COPPER;
     }
     if (ecmd.advertising & ADVERTISED_FIBRE) {
-        *advertised |= OFPPF_FIBER;
+        *advertised |= NETDEV_F_FIBER;
     }
     if (ecmd.advertising & ADVERTISED_Autoneg) {
-        *advertised |= OFPPF_AUTONEG;
+        *advertised |= NETDEV_F_AUTONEG;
     }
     if (ecmd.advertising & ADVERTISED_Pause) {
-        *advertised |= OFPPF_PAUSE;
+        *advertised |= NETDEV_F_PAUSE;
     }
     if (ecmd.advertising & ADVERTISED_Asym_Pause) {
-        *advertised |= OFPPF_PAUSE_ASYM;
+        *advertised |= NETDEV_F_PAUSE_ASYM;
     }
 
     /* Current settings. */
-    if (ecmd.speed == SPEED_10) {
-        *current = ecmd.duplex ? OFPPF_10MB_FD : OFPPF_10MB_HD;
-    } else if (ecmd.speed == SPEED_100) {
-        *current = ecmd.duplex ? OFPPF_100MB_FD : OFPPF_100MB_HD;
-    } else if (ecmd.speed == SPEED_1000) {
-        *current = ecmd.duplex ? OFPPF_1GB_FD : OFPPF_1GB_HD;
-    } else if (ecmd.speed == SPEED_10000) {
-        *current = OFPPF_10GB_FD;
+    speed = ecmd.speed;
+    if (speed == SPEED_10) {
+        *current = ecmd.duplex ? NETDEV_F_10MB_FD : NETDEV_F_10MB_HD;
+    } else if (speed == SPEED_100) {
+        *current = ecmd.duplex ? NETDEV_F_100MB_FD : NETDEV_F_100MB_HD;
+    } else if (speed == SPEED_1000) {
+        *current = ecmd.duplex ? NETDEV_F_1GB_FD : NETDEV_F_1GB_HD;
+    } else if (speed == SPEED_10000) {
+        *current = NETDEV_F_10GB_FD;
+    } else if (speed == 40000) {
+        *current = NETDEV_F_40GB_FD;
+    } else if (speed == 100000) {
+        *current = NETDEV_F_100GB_FD;
+    } else if (speed == 1000000) {
+        *current = NETDEV_F_1TB_FD;
     } else {
         *current = 0;
     }
 
     if (ecmd.port == PORT_TP) {
-        *current |= OFPPF_COPPER;
+        *current |= NETDEV_F_COPPER;
     } else if (ecmd.port == PORT_FIBRE) {
-        *current |= OFPPF_FIBER;
+        *current |= NETDEV_F_FIBER;
     }
 
     if (ecmd.autoneg) {
-        *current |= OFPPF_AUTONEG;
+        *current |= NETDEV_F_AUTONEG;
     }
 
     /* Peer advertisements. */
@@ -1518,7 +1535,8 @@ netdev_linux_get_features(const struct netdev *netdev,
 
 /* Set the features advertised by 'netdev' to 'advertise'. */
 static int
-netdev_linux_set_advertisements(struct netdev *netdev, uint32_t advertise)
+netdev_linux_set_advertisements(struct netdev *netdev,
+                                enum netdev_features advertise)
 {
     struct ethtool_cmd ecmd;
     int error;
@@ -1531,40 +1549,40 @@ netdev_linux_set_advertisements(struct netdev *netdev, uint32_t advertise)
     }
 
     ecmd.advertising = 0;
-    if (advertise & OFPPF_10MB_HD) {
+    if (advertise & NETDEV_F_10MB_HD) {
         ecmd.advertising |= ADVERTISED_10baseT_Half;
     }
-    if (advertise & OFPPF_10MB_FD) {
+    if (advertise & NETDEV_F_10MB_FD) {
         ecmd.advertising |= ADVERTISED_10baseT_Full;
     }
-    if (advertise & OFPPF_100MB_HD) {
+    if (advertise & NETDEV_F_100MB_HD) {
         ecmd.advertising |= ADVERTISED_100baseT_Half;
     }
-    if (advertise & OFPPF_100MB_FD) {
+    if (advertise & NETDEV_F_100MB_FD) {
         ecmd.advertising |= ADVERTISED_100baseT_Full;
     }
-    if (advertise & OFPPF_1GB_HD) {
+    if (advertise & NETDEV_F_1GB_HD) {
         ecmd.advertising |= ADVERTISED_1000baseT_Half;
     }
-    if (advertise & OFPPF_1GB_FD) {
+    if (advertise & NETDEV_F_1GB_FD) {
         ecmd.advertising |= ADVERTISED_1000baseT_Full;
     }
-    if (advertise & OFPPF_10GB_FD) {
+    if (advertise & NETDEV_F_10GB_FD) {
         ecmd.advertising |= ADVERTISED_10000baseT_Full;
     }
-    if (advertise & OFPPF_COPPER) {
+    if (advertise & NETDEV_F_COPPER) {
         ecmd.advertising |= ADVERTISED_TP;
     }
-    if (advertise & OFPPF_FIBER) {
+    if (advertise & NETDEV_F_FIBER) {
         ecmd.advertising |= ADVERTISED_FIBRE;
     }
-    if (advertise & OFPPF_AUTONEG) {
+    if (advertise & NETDEV_F_AUTONEG) {
         ecmd.advertising |= ADVERTISED_Autoneg;
     }
-    if (advertise & OFPPF_PAUSE) {
+    if (advertise & NETDEV_F_PAUSE) {
         ecmd.advertising |= ADVERTISED_Pause;
     }
-    if (advertise & OFPPF_PAUSE_ASYM) {
+    if (advertise & NETDEV_F_PAUSE_ASYM) {
         ecmd.advertising |= ADVERTISED_Asym_Pause;
     }
     return netdev_linux_do_ethtool(netdev_get_name(netdev), &ecmd,
@@ -1582,7 +1600,6 @@ netdev_linux_set_policing(struct netdev *netdev,
     const char *netdev_name = netdev_get_name(netdev);
     int error;
 
-    COVERAGE_INC(netdev_set_policing);
 
     kbits_burst = (!kbits_rate ? 0       /* Force to 0 if no rate specified. */
                    : !kbits_burst ? 1000 /* Default to 1000 kbits if 0. */
@@ -1595,6 +1612,7 @@ netdev_linux_set_policing(struct netdev *netdev,
         return 0;
     }
 
+    COVERAGE_INC(netdev_set_policing);
     /* Remove any existing ingress qdisc. */
     error = tc_add_del_ingress_qdisc(netdev, false);
     if (error) {
@@ -2307,14 +2325,14 @@ const struct netdev_class netdev_tap_class =
     NETDEV_LINUX_CLASS(
         "tap",
         netdev_linux_create_tap,
-        netdev_pseudo_get_stats,
+        netdev_tap_get_stats,
         NULL);                  /* set_stats */
 
 const struct netdev_class netdev_internal_class =
     NETDEV_LINUX_CLASS(
         "internal",
         netdev_linux_create,
-        netdev_pseudo_get_stats,
+        netdev_internal_get_stats,
         netdev_vport_set_stats);
 \f
 /* HTB traffic control class. */
@@ -4218,7 +4236,7 @@ get_stats_via_proc(const char *netdev_name, struct netdev_stats *stats)
 }
 
 static int
-get_flags(const struct netdev_dev *dev, int *flags)
+get_flags(const struct netdev_dev *dev, unsigned int *flags)
 {
     struct ifreq ifr;
     int error;
@@ -4233,7 +4251,7 @@ get_flags(const struct netdev_dev *dev, int *flags)
 }
 
 static int
-set_flags(struct netdev *netdev, int flags)
+set_flags(struct netdev *netdev, unsigned int flags)
 {
     struct ifreq ifr;