From: Pravin B Shelar Date: Fri, 9 Mar 2012 20:57:13 +0000 (-0800) Subject: netdev-linux: Cache drv-info for net device. X-Git-Tag: v1.7.0~296 X-Git-Url: http://git.cascardo.eti.br/?a=commitdiff_plain;h=4f925bd39b21c9d189af2cbfce8cc6287419d538;p=cascardo%2Fovs.git netdev-linux: Cache drv-info for net device. Netdev-linux calls ETHTOOL_GDRVINFO on every netdev_linux_get_status() which is not optimal as drv-info does not change for given device. So following patch changes netdev_linux_get_status() to read drv-info at device initialization and cache it. Signed-off-by: Pravin B Shelar --- diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 7c2b901b3..87c8832d2 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -79,6 +79,7 @@ COVERAGE_DEFINE(netdev_get_ifindex); COVERAGE_DEFINE(netdev_get_hwaddr); COVERAGE_DEFINE(netdev_set_hwaddr); COVERAGE_DEFINE(netdev_ethtool); + /* These were introduced in Linux 2.6.14, so they might be missing if we have * old headers. */ @@ -114,7 +115,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 +376,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 +486,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, + unsigned int mask) { dev->change_seq++; if (!dev->change_seq) { @@ -496,7 +522,19 @@ netdev_dev_linux_changed(struct netdev_dev_linux *dev, unsigned int ifi_flags) } dev->ifi_flags = ifi_flags; - dev->cache_valid = 0; + dev->cache_valid &= mask; +} + +static void +netdev_dev_linux_update(struct netdev_dev_linux *dev, + const struct rtnetlink_link_change *change) +{ + if (change->nlmsg_type == RTM_NEWLINK) { + /* Keep drv-info */ + netdev_dev_linux_changed(dev, change->ifi_flags, VALID_DRVINFO); + } else { + netdev_dev_linux_changed(dev, change->ifi_flags, 0); + } } static void @@ -512,7 +550,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_update(dev, change); } } } else { @@ -527,7 +565,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); } @@ -1171,7 +1209,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); @@ -2155,23 +2193,26 @@ 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; 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"); + error = netdev_linux_get_drvinfo(netdev_dev); 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)); + 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 error; } +static int +netdev_internal_get_status(const struct netdev *netdev OVS_UNUSED, struct shash *sh) +{ + shash_add(sh, "driver_name", xstrdup("openvswitch")); + return 0; +} + /* Looks up the ARP table entry for 'ip' on 'netdev'. If one exists and can be * successfully retrieved, it stores the corresponding MAC address in 'mac' and * returns 0. Otherwise, it returns a positive errno value; in particular, @@ -2255,7 +2296,8 @@ 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, GET_STATS, SET_STATS, \ + GET_STATUS) \ { \ NAME, \ \ @@ -2310,7 +2352,7 @@ netdev_linux_change_seq(const struct netdev *netdev) netdev_linux_get_in6, \ netdev_linux_add_router, \ netdev_linux_get_next_hop, \ - netdev_linux_get_status, \ + GET_STATUS, \ netdev_linux_arp_lookup, \ \ netdev_linux_update_flags, \ @@ -2323,21 +2365,24 @@ const struct netdev_class netdev_linux_class = "system", netdev_linux_create, netdev_linux_get_stats, - NULL); /* set_stats */ + NULL, /* set_stats */ + netdev_linux_get_status); const struct netdev_class netdev_tap_class = NETDEV_LINUX_CLASS( "tap", netdev_linux_create_tap, netdev_tap_get_stats, - NULL); /* set_stats */ + NULL, /* set_stats */ + netdev_linux_get_status); const struct netdev_class netdev_internal_class = NETDEV_LINUX_CLASS( "internal", netdev_linux_create, netdev_internal_get_stats, - netdev_vport_set_stats); + netdev_vport_set_stats, + netdev_internal_get_status); /* HTB traffic control class. */