link. So far, the whole element is just for output,
not setting.
</dd>
+ <dt><code>feature</code></dt>
+ <dd>If present, the hw offloads supported by this network
+ interface. Possible features are:
+ <dl>
+ <dt><code>rx</code></dt><dd>rx-checksumming</dd>
+ <dt><code>tx</code></dt><dd>tx-checksumming</dd>
+ <dt><code>sg</code></dt><dd>scatter-gather</dd>
+ <dt><code>tso</code></dt><dd>tcp-segmentation-offload</dd>
+ <dt><code>ufo</code></dt><dd>udp-fragmentation-offload</dd>
+ <dt><code>gso</code></dt><dd>generic-segmentation-offload</dd>
+ <dt><code>gro</code></dt><dd>generic-receive-offload</dd>
+ <dt><code>lro</code></dt><dd>large-receive-offload</dd>
+ <dt><code>rxvlan</code></dt><dd>rx-vlan-offload</dd>
+ <dt><code>txvlan</code></dt><dd>tx-vlan-offload</dd>
+ <dt><code>ntuple</code></dt><dd>ntuple-filters</dd>
+ <dt><code>rxhash</code></dt><dd>receive-hashing</dd>
+ </dl>
+ </dd>
<dt><code>capability</code></dt>
<dd>A network protocol exposed by the device, where the
attribute <code>type</code> can be "80203" for IEEE
</optional>
<ref name="link-speed-state"/>
+ <zeroOrMore>
+ <element name='feature'>
+ <attribute name='name'>
+ <ref name='netfeaturename'/>
+ </attribute>
+ </element>
+ </zeroOrMore>
+
<zeroOrMore>
<ref name='subcapnet'/>
</zeroOrMore>
</define>
+ <define name='netfeaturename'>
+ <data type='string'>
+ <param name='pattern'>[a-zA-Z\-_]+</param>
+ </data>
+ </define>
+
<define name='subcapnet'>
<element name='capability'>
<choice>
"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 */
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,
virBufferEscapeString(&buf, "<address>%s</address>\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, "<feature name='%s'/>\n",
+ virNetDevFeatureTypeToString(i));
+ }
+ }
+ }
if (data->net.subtype != VIR_NODE_DEV_CAP_NET_LAST) {
const char *subtyp =
virNodeDevNetCapTypeToString(data->net.subtype);
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;
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);
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);
# define __VIR_NODE_DEVICE_CONF_H__
# include "internal.h"
+# include "virbitmap.h"
# include "virutil.h"
# include "virthread.h"
# include "virpci.h"
char *ifname;
virInterfaceLink lnk;
virNodeDevNetCapType subtype; /* LAST -> no subtype */
+ virBitmapPtr features; /* enum virNetDevFeature */
} net;
struct {
unsigned int host;
virNetDevClearIPAddress;
virNetDevDelMulti;
virNetDevExists;
+virNetDevGetFeatures;
virNetDevGetIndex;
virNetDevGetIPv4Address;
virNetDevGetLinkInfo;
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:
*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
# include <net/if.h>
+# include "virbitmap.h"
# include "virsocketaddr.h"
# include "virnetlink.h"
# include "virmacaddr.h"
# include "virpci.h"
# include "device_conf.h"
+# include <linux/ethtool.h>
# ifdef HAVE_STRUCT_IFREQ
typedef struct ifreq virIfreq;
# else
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);
<capability type='net'>
<interface>eth0</interface>
<address>00:13:02:b9:f9:d3</address>
+ <feature name='rx'/>
+ <feature name='tx'/>
+ <feature name='sg'/>
+ <feature name='tso'/>
+ <feature name='gso'/>
+ <feature name='gro'/>
+ <feature name='rxvlan'/>
+ <feature name='txvlan'/>
+ <feature name='rxhash'/>
<capability type='80211'/>
</capability>
</device>
<capability type='net'>
<interface>eth1</interface>
<address>00:15:58:2f:e9:55</address>
+ <feature name='rx'/>
+ <feature name='tx'/>
+ <feature name='sg'/>
+ <feature name='tso'/>
+ <feature name='gso'/>
+ <feature name='gro'/>
+ <feature name='rxvlan'/>
+ <feature name='txvlan'/>
+ <feature name='rxhash'/>
<capability type='80203'/>
</capability>
</device>