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