Signed-off-by: Pravin B Shelar <pshe...@nicira.com>
---
 lib/netdev-linux.c |  123 ++++++++++++++++++++++++++++++++-------------------
 1 files changed, 77 insertions(+), 46 deletions(-)

diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index cfa66f5..2619509 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -118,6 +118,7 @@ enum {
     VALID_POLICING          = 1 << 5,
     VALID_VPORT_STAT_ERROR  = 1 << 6,
     VALID_DRVINFO           = 1 << 7,
+    VALID_FEATURES          = 1 << 8,
 };
 
 struct tap_state {
@@ -380,8 +381,14 @@ struct netdev_dev_linux {
     int netdev_mtu_error;       /* Cached error code from SIOCGIFMTU or 
SIOCSIFMTU. */
     int ether_addr_error;       /* Cached error code from set/get etheraddr. */
     int netdev_policy_error;    /* Cached error code from set policy. */
+    int get_features_error;     /* Cached error code from ETHTOOL_GSET. */
 
     struct ethtool_drvinfo drvinfo;  /* Cached from ETHTOOL_GDRVINFO. */
+    uint32_t current;           /* Cached from ETHTOOL_GSET. */
+    uint32_t advertised;        /* Cached from ETHTOOL_GSET. */
+    uint32_t supported;         /* Cached from ETHTOOL_GSET. */
+    uint32_t peer;              /* Cached from ETHTOOL_GSET. */
+
     struct tc *tc;
 
     union {
@@ -1482,130 +1489,154 @@ netdev_internal_get_stats(const struct netdev 
*netdev_,
     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. */
-static int
-netdev_linux_get_features(const struct netdev *netdev,
-                          uint32_t *current, uint32_t *advertised,
-                          uint32_t *supported, uint32_t *peer)
+static void
+netdev_linux_read_features(struct netdev_dev_linux *netdev_dev)
 {
     struct ethtool_cmd ecmd;
     int error;
 
     memset(&ecmd, 0, sizeof ecmd);
-    error = netdev_linux_do_ethtool(netdev_get_name(netdev), &ecmd,
+    error = netdev_linux_do_ethtool(netdev_dev->netdev_dev.name, &ecmd,
                                     ETHTOOL_GSET, "ETHTOOL_GSET");
     if (error) {
-        return error;
+        goto out;
     }
 
     /* Supported features. */
-    *supported = 0;
+    netdev_dev->supported = 0;
     if (ecmd.supported & SUPPORTED_10baseT_Half) {
-        *supported |= OFPPF_10MB_HD;
+        netdev_dev->supported |= OFPPF_10MB_HD;
     }
     if (ecmd.supported & SUPPORTED_10baseT_Full) {
-        *supported |= OFPPF_10MB_FD;
+        netdev_dev->supported |= OFPPF_10MB_FD;
     }
     if (ecmd.supported & SUPPORTED_100baseT_Half)  {
-        *supported |= OFPPF_100MB_HD;
+        netdev_dev->supported |= OFPPF_100MB_HD;
     }
     if (ecmd.supported & SUPPORTED_100baseT_Full) {
-        *supported |= OFPPF_100MB_FD;
+        netdev_dev->supported |= OFPPF_100MB_FD;
     }
     if (ecmd.supported & SUPPORTED_1000baseT_Half) {
-        *supported |= OFPPF_1GB_HD;
+        netdev_dev->supported |= OFPPF_1GB_HD;
     }
     if (ecmd.supported & SUPPORTED_1000baseT_Full) {
-        *supported |= OFPPF_1GB_FD;
+        netdev_dev->supported |= OFPPF_1GB_FD;
     }
     if (ecmd.supported & SUPPORTED_10000baseT_Full) {
-        *supported |= OFPPF_10GB_FD;
+        netdev_dev->supported |= OFPPF_10GB_FD;
     }
     if (ecmd.supported & SUPPORTED_TP) {
-        *supported |= OFPPF_COPPER;
+        netdev_dev->supported |= OFPPF_COPPER;
     }
     if (ecmd.supported & SUPPORTED_FIBRE) {
-        *supported |= OFPPF_FIBER;
+        netdev_dev->supported |= OFPPF_FIBER;
     }
     if (ecmd.supported & SUPPORTED_Autoneg) {
-        *supported |= OFPPF_AUTONEG;
+        netdev_dev->supported |= OFPPF_AUTONEG;
     }
     if (ecmd.supported & SUPPORTED_Pause) {
-        *supported |= OFPPF_PAUSE;
+        netdev_dev->supported |= OFPPF_PAUSE;
     }
     if (ecmd.supported & SUPPORTED_Asym_Pause) {
-        *supported |= OFPPF_PAUSE_ASYM;
+        netdev_dev->supported |= OFPPF_PAUSE_ASYM;
     }
 
     /* Advertised features. */
-    *advertised = 0;
+    netdev_dev->advertised = 0;
     if (ecmd.advertising & ADVERTISED_10baseT_Half) {
-        *advertised |= OFPPF_10MB_HD;
+        netdev_dev->advertised |= OFPPF_10MB_HD;
     }
     if (ecmd.advertising & ADVERTISED_10baseT_Full) {
-        *advertised |= OFPPF_10MB_FD;
+        netdev_dev->advertised |= OFPPF_10MB_FD;
     }
     if (ecmd.advertising & ADVERTISED_100baseT_Half) {
-        *advertised |= OFPPF_100MB_HD;
+        netdev_dev->advertised |= OFPPF_100MB_HD;
     }
     if (ecmd.advertising & ADVERTISED_100baseT_Full) {
-        *advertised |= OFPPF_100MB_FD;
+        netdev_dev->advertised |= OFPPF_100MB_FD;
     }
     if (ecmd.advertising & ADVERTISED_1000baseT_Half) {
-        *advertised |= OFPPF_1GB_HD;
+        netdev_dev->advertised |= OFPPF_1GB_HD;
     }
     if (ecmd.advertising & ADVERTISED_1000baseT_Full) {
-        *advertised |= OFPPF_1GB_FD;
+        netdev_dev->advertised |= OFPPF_1GB_FD;
     }
     if (ecmd.advertising & ADVERTISED_10000baseT_Full) {
-        *advertised |= OFPPF_10GB_FD;
+        netdev_dev->advertised |= OFPPF_10GB_FD;
     }
     if (ecmd.advertising & ADVERTISED_TP) {
-        *advertised |= OFPPF_COPPER;
+        netdev_dev->advertised |= OFPPF_COPPER;
     }
     if (ecmd.advertising & ADVERTISED_FIBRE) {
-        *advertised |= OFPPF_FIBER;
+        netdev_dev->advertised |= OFPPF_FIBER;
     }
     if (ecmd.advertising & ADVERTISED_Autoneg) {
-        *advertised |= OFPPF_AUTONEG;
+        netdev_dev->advertised |= OFPPF_AUTONEG;
     }
     if (ecmd.advertising & ADVERTISED_Pause) {
-        *advertised |= OFPPF_PAUSE;
+        netdev_dev->advertised |= OFPPF_PAUSE;
     }
     if (ecmd.advertising & ADVERTISED_Asym_Pause) {
-        *advertised |= OFPPF_PAUSE_ASYM;
+        netdev_dev->advertised |= OFPPF_PAUSE_ASYM;
     }
 
     /* Current settings. */
     if (ecmd.speed == SPEED_10) {
-        *current = ecmd.duplex ? OFPPF_10MB_FD : OFPPF_10MB_HD;
+        netdev_dev->current = ecmd.duplex ? OFPPF_10MB_FD : OFPPF_10MB_HD;
     } else if (ecmd.speed == SPEED_100) {
-        *current = ecmd.duplex ? OFPPF_100MB_FD : OFPPF_100MB_HD;
+        netdev_dev->current = ecmd.duplex ? OFPPF_100MB_FD : OFPPF_100MB_HD;
     } else if (ecmd.speed == SPEED_1000) {
-        *current = ecmd.duplex ? OFPPF_1GB_FD : OFPPF_1GB_HD;
+        netdev_dev->current = ecmd.duplex ? OFPPF_1GB_FD : OFPPF_1GB_HD;
     } else if (ecmd.speed == SPEED_10000) {
-        *current = OFPPF_10GB_FD;
+        netdev_dev->current = OFPPF_10GB_FD;
     } else {
-        *current = 0;
+        netdev_dev->current = 0;
     }
 
     if (ecmd.port == PORT_TP) {
-        *current |= OFPPF_COPPER;
+        netdev_dev->current |= OFPPF_COPPER;
     } else if (ecmd.port == PORT_FIBRE) {
-        *current |= OFPPF_FIBER;
+        netdev_dev->current |= OFPPF_FIBER;
     }
 
     if (ecmd.autoneg) {
-        *current |= OFPPF_AUTONEG;
+        netdev_dev->current |= OFPPF_AUTONEG;
     }
 
     /* Peer advertisements. */
-    *peer = 0;                  /* XXX */
+    netdev_dev->peer = 0;                  /* XXX */
 
-    return 0;
+out:
+    netdev_dev->cache_valid |= VALID_FEATURES;
+    netdev_dev->get_features_error = 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. */
+static int
+netdev_linux_get_features(const struct netdev *netdev_,
+                          uint32_t *current, uint32_t *advertised,
+                          uint32_t *supported, uint32_t *peer)
+{
+    struct netdev_dev_linux *netdev_dev =
+                                netdev_dev_linux_cast(netdev_get_dev(netdev_));
+
+    if (netdev_dev->cache_valid & VALID_FEATURES) {
+        goto out;
+    }
+
+    netdev_linux_read_features(netdev_dev);
+
+out:
+    if (!netdev_dev->get_features_error) {
+        *current = netdev_dev->current;
+        *advertised = netdev_dev->advertised;
+        *supported = netdev_dev->supported;
+        *peer = netdev_dev->peer;
+    }
+    return netdev_dev->get_features_error;
 }
 
 /* Set the features advertised by 'netdev' to 'advertise'. */
-- 
1.7.1

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to