Fixed according to comments from Ben.
v1-v2:
- Added comment for netdev_internal_open
- Removed get-stat call from status check.
--8<--------------------------cut here-------------------------->8--
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 <[email protected]>
---
lib/netdev-linux.c | 96 ++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 79 insertions(+), 17 deletions(-)
diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index 3c474e3..04a53b9 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,30 @@ 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)
{
dev->change_seq++;
if (!dev->change_seq) {
@@ -496,7 +521,19 @@ 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;
+}
+
+static void
+netdev_dev_linux_update(struct netdev_dev_linux *dev,
+ const struct rtnetlink_link_change *change)
+{
+ netdev_dev_linux_changed(dev, change->ifi_flags);
+ if (change->nlmsg_type == RTM_NEWLINK) {
+ /* Required for internal devices. */
+ netdev_linux_get_drvinfo(dev);
+ }
}
static void
@@ -512,7 +549,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 {
@@ -672,8 +709,11 @@ netdev_linux_destroy(struct netdev_dev *netdev_dev_)
cache_notifier_unref();
}
+/* Since internal devices are registered after netdev_open call. Driver-info
+ * for internal devices can not be retrieved in open call. Therefore It is
+ * read in RTM_NEWLINK notification for given device. */
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 +759,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_)
@@ -2151,20 +2214,16 @@ 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;
}
@@ -2251,7 +2310,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, \
\
@@ -2264,7 +2323,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, \
@@ -2318,6 +2377,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 */
@@ -2325,6 +2385,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 */
@@ -2332,6 +2393,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
[email protected]
http://openvswitch.org/mailman/listinfo/dev