Reuse the socket in virNetDevGetFeatures

This speeds up node_device_udev driver startup 11x.
This commit is contained in:
Ján Tomko 2016-06-03 20:46:05 +02:00
parent d59ca0b05f
commit 0a9bbe748a

View File

@ -3200,26 +3200,17 @@ virNetDevRDMAFeature(const char *ifname,
* virNetDevSendEthtoolIoctl * virNetDevSendEthtoolIoctl
* This function sends ethtool ioctl request * This function sends ethtool ioctl request
* *
* @ifname: name of the interface * @fd: socket to operate on
* @cmd: reference to an ethtool command structure * @ifr: struct ifreq with the command
* *
* Returns 0 on success, -1 on failure. * Returns 0 on success, -1 on failure.
*/ */
static int static int
virNetDevSendEthtoolIoctl(const char *ifname, void *cmd) virNetDevSendEthtoolIoctl(int fd, struct ifreq *ifr)
{ {
int ret = -1; int ret = -1;
int fd = -1;
struct ifreq ifr;
/* Ultimately uses AF_PACKET for socket which requires privileged ret = ioctl(fd, SIOCETHTOOL, ifr);
* daemon support.
*/
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
return ret;
ifr.ifr_data = cmd;
ret = ioctl(fd, SIOCETHTOOL, &ifr);
if (ret != 0) { if (ret != 0) {
switch (errno) { switch (errno) {
case EINVAL: /* kernel doesn't support SIOCETHTOOL */ case EINVAL: /* kernel doesn't support SIOCETHTOOL */
@ -3230,12 +3221,10 @@ virNetDevSendEthtoolIoctl(const char *ifname, void *cmd)
break; break;
default: default:
virReportSystemError(errno, "%s", _("ethtool ioctl error")); virReportSystemError(errno, "%s", _("ethtool ioctl error"));
goto cleanup; break;
} }
} }
cleanup:
VIR_FORCE_CLOSE(fd);
return ret; return ret;
} }
@ -3249,16 +3238,17 @@ struct virNetDevEthtoolFeatureCmd {
* virNetDevFeatureAvailable * virNetDevFeatureAvailable
* This function checks for the availability of a network device feature * This function checks for the availability of a network device feature
* *
* @ifname: name of the interface * @fd: socket to operate on
* @ifr: struct ifreq with the command
* @cmd: reference to an ethtool command structure * @cmd: reference to an ethtool command structure
* *
* Returns true if the feature is available, false otherwise. * Returns true if the feature is available, false otherwise.
*/ */
static bool static bool
virNetDevFeatureAvailable(const char *ifname, struct ethtool_value *cmd) virNetDevFeatureAvailable(int fd, struct ifreq *ifr, struct ethtool_value *cmd)
{ {
cmd = (void*)cmd; ifr->ifr_data = (void*)cmd;
if (virNetDevSendEthtoolIoctl(ifname, cmd) == 0 && if (virNetDevSendEthtoolIoctl(fd, ifr) == 0 &&
cmd->data > 0) cmd->data > 0)
return true; return true;
return false; return false;
@ -3267,7 +3257,8 @@ virNetDevFeatureAvailable(const char *ifname, struct ethtool_value *cmd)
static void static void
virNetDevGetEthtoolFeatures(virBitmapPtr bitmap, virNetDevGetEthtoolFeatures(virBitmapPtr bitmap,
const char *ifname) int fd,
struct ifreq *ifr)
{ {
size_t i; size_t i;
struct ethtool_value cmd = { 0 }; struct ethtool_value cmd = { 0 };
@ -3307,13 +3298,13 @@ virNetDevGetEthtoolFeatures(virBitmapPtr bitmap,
for (i = 0; i < ARRAY_CARDINALITY(ethtool_cmds); i++) { for (i = 0; i < ARRAY_CARDINALITY(ethtool_cmds); i++) {
cmd.cmd = ethtool_cmds[i].cmd; cmd.cmd = ethtool_cmds[i].cmd;
if (virNetDevFeatureAvailable(ifname, &cmd)) if (virNetDevFeatureAvailable(fd, ifr, &cmd))
ignore_value(virBitmapSetBit(bitmap, ethtool_cmds[i].feat)); ignore_value(virBitmapSetBit(bitmap, ethtool_cmds[i].feat));
} }
# if HAVE_DECL_ETHTOOL_GFLAGS # if HAVE_DECL_ETHTOOL_GFLAGS
cmd.cmd = ETHTOOL_GFLAGS; cmd.cmd = ETHTOOL_GFLAGS;
if (virNetDevFeatureAvailable(ifname, &cmd)) { if (virNetDevFeatureAvailable(fd, ifr, &cmd)) {
for (i = 0; i < ARRAY_CARDINALITY(flags); i++) { for (i = 0; i < ARRAY_CARDINALITY(flags); i++) {
if (cmd.data & flags[i].cmd) if (cmd.data & flags[i].cmd)
ignore_value(virBitmapSetBit(bitmap, flags[i].feat)); ignore_value(virBitmapSetBit(bitmap, flags[i].feat));
@ -3328,16 +3319,19 @@ virNetDevGetEthtoolFeatures(virBitmapPtr bitmap,
* virNetDevGFeatureAvailable * virNetDevGFeatureAvailable
* This function checks for the availability of a network device gfeature * This function checks for the availability of a network device gfeature
* *
* @ifname: name of the interface * @fd: socket to operate on
* @cmd: reference to a gfeatures ethtool command structure * @ifr: struct ifreq with the command
* @cmd: reference to an ethtool command structure
* *
* Returns true if the feature is available, false otherwise. * Returns true if the feature is available, false otherwise.
*/ */
static bool static bool
virNetDevGFeatureAvailable(const char *ifname, struct ethtool_gfeatures *cmd) virNetDevGFeatureAvailable(int fd,
struct ifreq *ifr,
struct ethtool_gfeatures *cmd)
{ {
cmd = (void*)cmd; ifr->ifr_data = (void*)cmd;
if (virNetDevSendEthtoolIoctl(ifname, cmd) == 0) if (virNetDevSendEthtoolIoctl(fd, ifr) == 0)
return !!FEATURE_BIT_IS_SET(cmd->features, TX_UDP_TNL, active); return !!FEATURE_BIT_IS_SET(cmd->features, TX_UDP_TNL, active);
return false; return false;
} }
@ -3345,7 +3339,8 @@ virNetDevGFeatureAvailable(const char *ifname, struct ethtool_gfeatures *cmd)
static int static int
virNetDevGetEthtoolGFeatures(virBitmapPtr bitmap, virNetDevGetEthtoolGFeatures(virBitmapPtr bitmap,
const char *ifname) int fd,
struct ifreq *ifr)
{ {
struct ethtool_gfeatures *g_cmd; struct ethtool_gfeatures *g_cmd;
@ -3355,7 +3350,7 @@ virNetDevGetEthtoolGFeatures(virBitmapPtr bitmap,
g_cmd->cmd = ETHTOOL_GFEATURES; g_cmd->cmd = ETHTOOL_GFEATURES;
g_cmd->size = GFEATURES_SIZE; g_cmd->size = GFEATURES_SIZE;
if (virNetDevGFeatureAvailable(ifname, g_cmd)) if (virNetDevGFeatureAvailable(fd, ifr, g_cmd))
ignore_value(virBitmapSetBit(bitmap, VIR_NET_DEV_FEAT_TXUDPTNL)); ignore_value(virBitmapSetBit(bitmap, VIR_NET_DEV_FEAT_TXUDPTNL));
VIR_FREE(g_cmd); VIR_FREE(g_cmd);
return 0; return 0;
@ -3363,7 +3358,8 @@ virNetDevGetEthtoolGFeatures(virBitmapPtr bitmap,
# else # else
static int static int
virNetDevGetEthtoolGFeatures(virBitmapPtr bitmap ATTRIBUTE_UNUSED, virNetDevGetEthtoolGFeatures(virBitmapPtr bitmap ATTRIBUTE_UNUSED,
const char *ifname ATTRIBUTE_UNUSED) int fd ATTRIBUTE_UNUSED,
struct ifreq *ifr ATTRIBUGE_UNUSED)
{ {
return 0; return 0;
} }
@ -3384,6 +3380,10 @@ int
virNetDevGetFeatures(const char *ifname, virNetDevGetFeatures(const char *ifname,
virBitmapPtr *out) virBitmapPtr *out)
{ {
struct ifreq ifr;
int ret = -1;
int fd = -1;
if (!(*out = virBitmapNew(VIR_NET_DEV_FEAT_LAST))) if (!(*out = virBitmapNew(VIR_NET_DEV_FEAT_LAST)))
return -1; return -1;
@ -3393,14 +3393,24 @@ virNetDevGetFeatures(const char *ifname,
return 0; return 0;
} }
virNetDevGetEthtoolFeatures(*out, ifname); /* Ultimately uses AF_PACKET for socket which requires privileged
* daemon support.
*/
if ((fd = virNetDevSetupControl(ifname, &ifr)) < 0)
goto cleanup;
if (virNetDevGetEthtoolGFeatures(*out, ifname) < 0) virNetDevGetEthtoolFeatures(*out, fd, &ifr);
return -1;
if (virNetDevGetEthtoolGFeatures(*out, fd, &ifr) < 0)
goto cleanup;
if (virNetDevRDMAFeature(ifname, out) < 0) if (virNetDevRDMAFeature(ifname, out) < 0)
return -1; goto cleanup;
return 0;
ret = 0;
cleanup:
VIR_FORCE_CLOSE(fd);
return ret;
} }
#else #else
int int