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 <pshelar@nicira.com>
COVERAGE_DEFINE(netdev_get_hwaddr);
COVERAGE_DEFINE(netdev_set_hwaddr);
COVERAGE_DEFINE(netdev_ethtool);
COVERAGE_DEFINE(netdev_get_hwaddr);
COVERAGE_DEFINE(netdev_set_hwaddr);
COVERAGE_DEFINE(netdev_ethtool);
\f
/* These were introduced in Linux 2.6.14, so they might be missing if we have
* old headers. */
\f
/* These were introduced in Linux 2.6.14, so they might be missing if we have
* old headers. */
VALID_IN6 = 1 << 3,
VALID_MTU = 1 << 4,
VALID_POLICING = 1 << 5,
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,
uint32_t kbits_burst;
int vport_stats_error; /* Cached error code from vport_get_stats().
0 or an errno value. */
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. */
netdev_linux_miimon_wait();
}
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;
+}
+
-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) {
{
dev->change_seq++;
if (!dev->change_seq) {
}
dev->ifi_flags = ifi_flags;
}
dev->ifi_flags = ifi_flags;
+ 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);
+ }
if (is_netdev_linux_class(netdev_class)) {
dev = netdev_dev_linux_cast(base_dev);
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);
dev = node->data;
get_flags(&dev->netdev_dev, &flags);
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);
}
}
shash_destroy(&device_shash);
}
netdev_linux_get_miimon(dev->netdev_dev.name, &miimon);
if (miimon != dev->miimon) {
dev->miimon = miimon;
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);
}
timer_set_duration(&dev->miimon_timer, dev->miimon_interval);
static int
netdev_linux_get_status(const struct netdev *netdev, struct shash *sh)
{
static int
netdev_linux_get_status(const struct netdev *netdev, struct shash *sh)
{
- struct ethtool_drvinfo drvinfo;
+ 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);
- 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));
+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,
/* 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,
return netdev_dev_linux_cast(netdev_get_dev(netdev))->change_seq;
}
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) \
netdev_linux_get_in6, \
netdev_linux_add_router, \
netdev_linux_get_next_hop, \
netdev_linux_get_in6, \
netdev_linux_add_router, \
netdev_linux_get_next_hop, \
- netdev_linux_get_status, \
netdev_linux_arp_lookup, \
\
netdev_linux_update_flags, \
netdev_linux_arp_lookup, \
\
netdev_linux_update_flags, \
"system",
netdev_linux_create,
netdev_linux_get_stats,
"system",
netdev_linux_create,
netdev_linux_get_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,
const struct netdev_class netdev_tap_class =
NETDEV_LINUX_CLASS(
"tap",
netdev_linux_create_tap,
netdev_tap_get_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,
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);
\f
/* HTB traffic control class. */
\f
/* HTB traffic control class. */