diff --git a/docs/formatnode.html.in b/docs/formatnode.html.in index b820a34a16..ba9a0f8672 100644 --- a/docs/formatnode.html.in +++ b/docs/formatnode.html.in @@ -183,6 +183,24 @@ link. So far, the whole element is just for output, not setting. +
feature
+
If present, the hw offloads supported by this network + interface. Possible features are: +
+
rx
rx-checksumming
+
tx
tx-checksumming
+
sg
scatter-gather
+
tso
tcp-segmentation-offload
+
ufo
udp-fragmentation-offload
+
gso
generic-segmentation-offload
+
gro
generic-receive-offload
+
lro
large-receive-offload
+
rxvlan
rx-vlan-offload
+
txvlan
tx-vlan-offload
+
ntuple
ntuple-filters
+
rxhash
receive-hashing
+
+
capability
A network protocol exposed by the device, where the attribute type can be "80203" for IEEE diff --git a/docs/schemas/nodedev.rng b/docs/schemas/nodedev.rng index 13c5402213..744dccdf5f 100644 --- a/docs/schemas/nodedev.rng +++ b/docs/schemas/nodedev.rng @@ -274,11 +274,25 @@ + + + + + + + + + + + [a-zA-Z\-_]+ + + + diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c index 5ffe159b79..98808e2079 100644 --- a/src/conf/device_conf.c +++ b/src/conf/device_conf.c @@ -39,6 +39,20 @@ VIR_ENUM_IMPL(virInterfaceState, "down", "lowerlayerdown", "testing", "dormant", "up") +VIR_ENUM_IMPL(virNetDevFeature, + VIR_NET_DEV_FEAT_LAST, + "rx", + "tx", + "sg", + "tso", + "gso", + "gro", + "lro", + "rxvlan", + "txvlan", + "ntuple", + "rxhash") + int virDevicePCIAddressIsValid(virDevicePCIAddressPtr addr) { /* PCI bus has 32 slots and 8 functions per slot */ diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index 7256cdcf53..7ea90f6738 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -62,6 +62,23 @@ struct _virInterfaceLink { unsigned int speed; /* link speed in Mbits per second */ }; +typedef enum { + VIR_NET_DEV_FEAT_GRXCSUM, + VIR_NET_DEV_FEAT_GTXCSUM, + VIR_NET_DEV_FEAT_GSG, + VIR_NET_DEV_FEAT_GTSO, + VIR_NET_DEV_FEAT_GGSO, + VIR_NET_DEV_FEAT_GGRO, + VIR_NET_DEV_FEAT_LRO, + VIR_NET_DEV_FEAT_RXVLAN, + VIR_NET_DEV_FEAT_TXVLAN, + VIR_NET_DEV_FEAT_NTUPLE, + VIR_NET_DEV_FEAT_RXHASH, + VIR_NET_DEV_FEAT_LAST +} virNetDevFeature; + +VIR_ENUM_DECL(virNetDevFeature) + int virDevicePCIAddressIsValid(virDevicePCIAddressPtr addr); int virDevicePCIAddressParseXML(xmlNodePtr node, diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index a728a0081a..f9c9b6fa7a 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -437,6 +437,16 @@ char *virNodeDeviceDefFormat(const virNodeDeviceDef *def) virBufferEscapeString(&buf, "
%s
\n", data->net.address); virInterfaceLinkFormat(&buf, &data->net.lnk); + if (data->net.features) { + for (i = 0; i < VIR_NET_DEV_FEAT_LAST; i++) { + bool b; + ignore_value(virBitmapGetBit(data->net.features, i, &b)); + if (b) { + virBufferAsprintf(&buf, "\n", + virNetDevFeatureTypeToString(i)); + } + } + } if (data->net.subtype != VIR_NODE_DEV_CAP_NET_LAST) { const char *subtyp = virNodeDevNetCapTypeToString(data->net.subtype); @@ -927,8 +937,10 @@ virNodeDevCapNetParseXML(xmlXPathContextPtr ctxt, union _virNodeDevCapData *data) { xmlNodePtr orignode, lnk; - int ret = -1; + size_t i = -1; + int ret = -1, n = -1; char *tmp; + xmlNodePtr *nodes = NULL; orignode = ctxt->node; ctxt->node = node; @@ -943,6 +955,31 @@ virNodeDevCapNetParseXML(xmlXPathContextPtr ctxt, data->net.address = virXPathString("string(./address[1])", ctxt); + if ((n = virXPathNodeSet("./feature", ctxt, &nodes)) < 0) + goto out; + + if (n > 0) { + if (!(data->net.features = virBitmapNew(VIR_NET_DEV_FEAT_LAST))) + goto out; + } + + for (i = 0; i < n; i++) { + int val; + if (!(tmp = virXMLPropString(nodes[i], "name"))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing network device feature name")); + goto out; + } + + if ((val = virNetDevFeatureTypeFromString(tmp)) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("unknown network device feature '%s'"), + tmp); + goto out; + } + ignore_value(virBitmapSetBit(data->net.features, val)); + } + data->net.subtype = VIR_NODE_DEV_CAP_NET_LAST; tmp = virXPathString("string(./capability/@type)", ctxt); @@ -1679,6 +1716,8 @@ void virNodeDevCapsDefFree(virNodeDevCapsDefPtr caps) case VIR_NODE_DEV_CAP_NET: VIR_FREE(data->net.ifname); VIR_FREE(data->net.address); + virBitmapFree(data->net.features); + data->net.features = NULL; break; case VIR_NODE_DEV_CAP_SCSI_HOST: VIR_FREE(data->scsi_host.wwnn); diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index fd5d1799a2..38c6d45788 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -26,6 +26,7 @@ # define __VIR_NODE_DEVICE_CONF_H__ # include "internal.h" +# include "virbitmap.h" # include "virutil.h" # include "virthread.h" # include "virpci.h" @@ -141,6 +142,7 @@ struct _virNodeDevCapsDef { char *ifname; virInterfaceLink lnk; virNodeDevNetCapType subtype; /* LAST -> no subtype */ + virBitmapPtr features; /* enum virNetDevFeature */ } net; struct { unsigned int host; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 13e0931570..c810cf70d1 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1669,6 +1669,7 @@ virNetDevAddRoute; virNetDevClearIPAddress; virNetDevDelMulti; virNetDevExists; +virNetDevGetFeatures; virNetDevGetIndex; virNetDevGetIPv4Address; virNetDevGetLinkInfo; diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index 03c7a0b7b1..8c39e5f0f4 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -719,6 +719,9 @@ static int udevProcessNetworkInterface(struct udev_device *device, if (virNetDevGetLinkInfo(data->net.ifname, &data->net.lnk) < 0) goto out; + if (virNetDevGetFeatures(data->net.ifname, &data->net.features) < 0) + goto out; + ret = 0; out: diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index 2a0eb43b79..36e69a3688 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -2728,3 +2728,131 @@ int virNetDevGetRxFilter(const char *ifname, *filter = fil; return ret; } + +#if defined(SIOCETHTOOL) && defined(HAVE_STRUCT_IFREQ) + +/** + * virNetDevFeatureAvailable + * This function checks for the availability of a network device feature + * + * @ifname: name of the interface + * @cmd: reference to an ethtool command structure + * + * Returns 0 on success, -1 on failure. + */ +static int +virNetDevFeatureAvailable(const char *ifname, struct ethtool_value *cmd) +{ + int ret = -1; + int sock = -1; + virIfreq ifr; + + sock = socket(AF_LOCAL, SOCK_DGRAM, 0); + if (sock < 0) { + virReportSystemError(errno, "%s", _("Cannot open control socket")); + goto cleanup; + } + + strcpy(ifr.ifr_name, ifname); + ifr.ifr_data = (void*) cmd; + + if (ioctl(sock, SIOCETHTOOL, &ifr) != 0) { + switch (errno) { + case EPERM: + VIR_DEBUG("ethtool ioctl: permission denied"); + break; + case EINVAL: + VIR_DEBUG("ethtool ioctl: invalid request"); + break; + case EOPNOTSUPP: + VIR_DEBUG("ethtool ioctl: request not supported"); + break; + default: + virReportSystemError(errno, "%s", _("ethtool ioctl error")); + goto cleanup; + } + } + + ret = cmd->data > 0 ? 1: 0; + cleanup: + if (sock) + VIR_FORCE_CLOSE(sock); + + return ret; +} + + +/** + * virNetDevGetFeatures: + * This function gets the nic offloads features available for ifname + * + * @ifname: name of the interface + * @features: network device feature structures + * @nfeatures: number of features available + * + * Returns 0 on success, -1 on failure. + */ +int +virNetDevGetFeatures(const char *ifname, + virBitmapPtr *out) +{ + int ret = -1; + size_t i = -1; + size_t j = -1; + struct ethtool_value cmd = { 0 }; + + struct elem{ + const int cmd; + const virNetDevFeature feat; + }; + /* legacy ethtool getters */ + struct elem cmds[] = { + {ETHTOOL_GRXCSUM, VIR_NET_DEV_FEAT_GRXCSUM}, + {ETHTOOL_GTXCSUM, VIR_NET_DEV_FEAT_GTXCSUM}, + {ETHTOOL_GSG, VIR_NET_DEV_FEAT_GSG}, + {ETHTOOL_GTSO, VIR_NET_DEV_FEAT_GTSO}, + {ETHTOOL_GGSO, VIR_NET_DEV_FEAT_GGSO}, + {ETHTOOL_GGRO, VIR_NET_DEV_FEAT_GGRO}, + }; + /* ethtool masks */ + struct elem flags[] = { + {ETH_FLAG_LRO, VIR_NET_DEV_FEAT_LRO}, + {ETH_FLAG_RXVLAN, VIR_NET_DEV_FEAT_RXVLAN}, + {ETH_FLAG_TXVLAN, VIR_NET_DEV_FEAT_TXVLAN}, + {ETH_FLAG_NTUPLE, VIR_NET_DEV_FEAT_NTUPLE}, + {ETH_FLAG_RXHASH, VIR_NET_DEV_FEAT_RXHASH}, + }; + + if (!(*out = virBitmapNew(VIR_NET_DEV_FEAT_LAST))) + goto cleanup; + + for (i = 0; i < ARRAY_CARDINALITY(cmds); i++) { + cmd.cmd = cmds[i].cmd; + if (virNetDevFeatureAvailable(ifname, &cmd)) + ignore_value(virBitmapSetBit(*out, cmds[i].feat)); + } + + cmd.cmd = ETHTOOL_GFLAGS; + if (virNetDevFeatureAvailable(ifname, &cmd)) { + for (j = 0; j < ARRAY_CARDINALITY(flags); j++) { + if (cmd.data & flags[j].cmd) + ignore_value(virBitmapSetBit(*out, flags[j].feat)); + } + } + + ret = 0; + cleanup: + + return ret; + +} +#else +int +virNetDevGetFeatures(const char *ifname ATTRIBUTE_UNUSED, + virBitmapPtr *out ATTRIBUTE_UNUSED) +{ + VIR_DEBUG("Getting network device features on %s is not implemented on this platform", + ifname); + return 0; +} +#endif diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h index de8b48014f..643479d8f6 100644 --- a/src/util/virnetdev.h +++ b/src/util/virnetdev.h @@ -25,12 +25,14 @@ # include +# include "virbitmap.h" # include "virsocketaddr.h" # include "virnetlink.h" # include "virmacaddr.h" # include "virpci.h" # include "device_conf.h" +# include # ifdef HAVE_STRUCT_IFREQ typedef struct ifreq virIfreq; # else @@ -182,6 +184,10 @@ int virNetDevGetVirtualFunctionInfo(const char *vfname, char **pfname, int *vf) ATTRIBUTE_NONNULL(1); +int virNetDevGetFeatures(const char *ifname, + virBitmapPtr *out) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + int virNetDevGetLinkInfo(const char *ifname, virInterfaceLinkPtr lnk) ATTRIBUTE_NONNULL(1); diff --git a/tests/nodedevschemadata/net_00_13_02_b9_f9_d3.xml b/tests/nodedevschemadata/net_00_13_02_b9_f9_d3.xml index 970ccca366..2a34fed371 100644 --- a/tests/nodedevschemadata/net_00_13_02_b9_f9_d3.xml +++ b/tests/nodedevschemadata/net_00_13_02_b9_f9_d3.xml @@ -4,6 +4,15 @@ eth0
00:13:02:b9:f9:d3
+ + + + + + + + + diff --git a/tests/nodedevschemadata/net_00_15_58_2f_e9_55.xml b/tests/nodedevschemadata/net_00_15_58_2f_e9_55.xml index 741c959137..81d398cc7c 100644 --- a/tests/nodedevschemadata/net_00_15_58_2f_e9_55.xml +++ b/tests/nodedevschemadata/net_00_15_58_2f_e9_55.xml @@ -4,6 +4,15 @@ eth1
00:15:58:2f:e9:55
+ + + + + + + + +