Rather than using ETHTOOL_GDRVINFO to check netdev-status, use
ovs-get-stats since it is more consistent. Covergage counter is
added for status check.

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

diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index 8a8f912..f1f7beb 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -79,6 +79,8 @@ COVERAGE_DEFINE(netdev_get_ifindex);
 COVERAGE_DEFINE(netdev_get_hwaddr);
 COVERAGE_DEFINE(netdev_set_hwaddr);
 COVERAGE_DEFINE(netdev_ethtool);
+COVERAGE_DEFINE(netdev_get_status);
+
 
 /* These were introduced in Linux 2.6.14, so they might be missing if we have
  * old headers. */
@@ -114,7 +116,8 @@ enum {
     VALID_IN6               = 1 << 3,
     VALID_MTU               = 1 << 4,
     VALID_POLICING          = 1 << 5,
-    VALID_VPORT_STAT_ERROR  = 1 << 6
+    VALID_VPORT_STAT_ERROR  = 1 << 6,
+    VALID_DRVINFO           = 1 << 7,
 };
 
 struct tap_state {
@@ -374,6 +377,7 @@ struct netdev_dev_linux {
     uint32_t kbits_burst;
     int vport_stats_error;      /* Cached error code from vport_get_stats().
                                    0 or an errno value. */
+    struct ethtool_drvinfo drvinfo;  /* Cached from ETHTOOL_GDRVINFO. */
     struct tc *tc;
 
     union {
@@ -483,8 +487,31 @@ netdev_linux_wait(void)
     netdev_linux_miimon_wait();
 }
 
+static int
+netdev_linux_get_drvinfo(struct netdev_dev_linux *netdev_dev)
+{
+
+    int error;
+
+    if (netdev_dev->cache_valid & VALID_DRVINFO) {
+        return 0;
+    }
+
+    memset(&netdev_dev->drvinfo, 0, sizeof netdev_dev->drvinfo);
+    error = netdev_linux_do_ethtool(netdev_dev->netdev_dev.name,
+                                    (struct ethtool_cmd *)&netdev_dev->drvinfo,
+                                    ETHTOOL_GDRVINFO,
+                                    "ETHTOOL_GDRVINFO");
+    if (!error) {
+        netdev_dev->cache_valid |= VALID_DRVINFO;
+    }
+    return error;
+}
+
 static void
-netdev_dev_linux_changed(struct netdev_dev_linux *dev, unsigned int ifi_flags)
+netdev_dev_linux_changed(struct netdev_dev_linux *dev,
+                         unsigned int ifi_flags,
+                         uint16_t change)
 {
     dev->change_seq++;
     if (!dev->change_seq) {
@@ -496,7 +523,14 @@ netdev_dev_linux_changed(struct netdev_dev_linux *dev, 
unsigned int ifi_flags)
     }
     dev->ifi_flags = ifi_flags;
 
-    dev->cache_valid = 0;
+    /* Always cache driver-info. */
+    dev->cache_valid &= VALID_DRVINFO;
+
+    if (change == RTM_NEWLINK) {
+        /* Required for internal devices. */
+        netdev_linux_get_drvinfo(dev);
+    }
+
 }
 
 static void
@@ -512,7 +546,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);
-                netdev_dev_linux_changed(dev, change->ifi_flags);
+                netdev_dev_linux_changed(dev, change->ifi_flags, 
change->nlmsg_type);
             }
         }
     } else {
@@ -527,7 +561,7 @@ netdev_linux_cache_cb(const struct rtnetlink_link_change 
*change,
             dev = node->data;
 
             get_flags(&dev->netdev_dev, &flags);
-            netdev_dev_linux_changed(dev, flags);
+            netdev_dev_linux_changed(dev, flags, 0);
         }
         shash_destroy(&device_shash);
     }
@@ -673,7 +707,7 @@ netdev_linux_destroy(struct netdev_dev *netdev_dev_)
 }
 
 static int
-netdev_linux_open(struct netdev_dev *netdev_dev_, struct netdev **netdevp)
+netdev_internal_open(struct netdev_dev *netdev_dev_, struct netdev **netdevp)
 {
     struct netdev_dev_linux *netdev_dev = netdev_dev_linux_cast(netdev_dev_);
     struct netdev_linux *netdev;
@@ -719,6 +753,29 @@ error:
     return error;
 }
 
+static int
+netdev_linux_open(struct netdev_dev *netdev_dev_, struct netdev **netdevp)
+{
+    struct netdev_dev_linux *netdev_dev = netdev_dev_linux_cast(netdev_dev_);
+    int error;
+
+    error = netdev_internal_open(netdev_dev_, netdevp);
+    if (error) {
+       return error;
+    }
+
+    error = netdev_linux_get_drvinfo(netdev_dev);
+    if (error) {
+       goto error;
+    }
+
+    return 0;
+
+error:
+    netdev_uninit(*netdevp, true);
+    return error;
+}
+
 /* Closes and destroys 'netdev'. */
 static void
 netdev_linux_close(struct netdev *netdev_)
@@ -1167,7 +1224,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, dev->ifi_flags);
+            netdev_dev_linux_changed(dev, dev->ifi_flags, 0);
         }
 
         timer_set_duration(&dev->miimon_timer, dev->miimon_interval);
@@ -2140,21 +2197,25 @@ netdev_linux_get_next_hop(const struct in_addr *host, 
struct in_addr *next_hop,
 static int
 netdev_linux_get_status(const struct netdev *netdev, struct shash *sh)
 {
-    struct ethtool_drvinfo drvinfo;
+    struct netdev_stats stats;
     int error;
+    struct netdev_dev_linux *netdev_dev =
+                                netdev_dev_linux_cast(netdev_get_dev(netdev));
 
-    memset(&drvinfo, 0, sizeof drvinfo);
-    error = netdev_linux_do_ethtool(netdev_get_name(netdev),
-                                    (struct ethtool_cmd *)&drvinfo,
-                                    ETHTOOL_GDRVINFO,
-                                    "ETHTOOL_GDRVINFO");
-    if (!error) {
-        shash_add(sh, "driver_name", xstrdup(drvinfo.driver));
-        shash_add(sh, "driver_version", xstrdup(drvinfo.version));
-        shash_add(sh, "firmware_version", xstrdup(drvinfo.fw_version));
+    error = netdev_linux_get_drvinfo(netdev_dev);
+    if (error) {
+        return error;
     }
+    COVERAGE_INC(netdev_get_status);
+    /* Use vport-stats for checking status of device. */
+    get_stats_via_vport(netdev, &stats);
 
-    return error;
+    if (!netdev_dev->vport_stats_error) {
+        shash_add(sh, "driver_name", xstrdup(netdev_dev->drvinfo.driver));
+        shash_add(sh, "driver_version", xstrdup(netdev_dev->drvinfo.version));
+        shash_add(sh, "firmware_version", 
xstrdup(netdev_dev->drvinfo.fw_version));
+    }
+    return netdev_dev->vport_stats_error;
 }
 
 /* Looks up the ARP table entry for 'ip' on 'netdev'.  If one exists and can be
@@ -2240,7 +2301,7 @@ netdev_linux_change_seq(const struct netdev *netdev)
     return netdev_dev_linux_cast(netdev_get_dev(netdev))->change_seq;
 }
 
-#define NETDEV_LINUX_CLASS(NAME, CREATE, GET_STATS, SET_STATS)  \
+#define NETDEV_LINUX_CLASS(NAME, CREATE, OPEN, GET_STATS, SET_STATS)  \
 {                                                               \
     NAME,                                                       \
                                                                 \
@@ -2253,7 +2314,7 @@ netdev_linux_change_seq(const struct netdev *netdev)
     NULL,                       /* get_config */                \
     NULL,                       /* set_config */                \
                                                                 \
-    netdev_linux_open,                                          \
+    OPEN,                                                       \
     netdev_linux_close,                                         \
                                                                 \
     netdev_linux_listen,                                        \
@@ -2307,6 +2368,7 @@ const struct netdev_class netdev_linux_class =
     NETDEV_LINUX_CLASS(
         "system",
         netdev_linux_create,
+        netdev_linux_open,
         netdev_linux_get_stats,
         NULL);                  /* set_stats */
 
@@ -2314,6 +2376,7 @@ const struct netdev_class netdev_tap_class =
     NETDEV_LINUX_CLASS(
         "tap",
         netdev_linux_create_tap,
+        netdev_linux_open,
         netdev_tap_get_stats,
         NULL);                  /* set_stats */
 
@@ -2321,6 +2384,7 @@ const struct netdev_class netdev_internal_class =
     NETDEV_LINUX_CLASS(
         "internal",
         netdev_linux_create,
+        netdev_internal_open,
         netdev_internal_get_stats,
         netdev_vport_set_stats);
 
-- 
1.7.1

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

Reply via email to