@@ -22,9 +22,25 @@
#include <linux/vmalloc.h>
#include <linux/rtnetlink.h>
+#define REQUIRE_PATH_LEN (256)
+
+struct backend_features {
+ unsigned int max_queues;
+ unsigned int split_evtchn:1;
+ unsigned int ctrl_ring:1;
+ unsigned int can_sg:1;
+ unsigned int gso_v4:1;
+ unsigned int gso_v6:1;
+ unsigned int mcast_ctrl:1;
+ unsigned int dyn_mcast_ctrl:1;
+ unsigned int ip_no_csum:1;
+ unsigned int ipv6_csum:1;
+};
+
struct backend_info {
struct xenbus_device *dev;
struct xenvif *vif;
+ struct backend_features features;
/* This is the state that will be reflected in xenstore when any
* active hotplug script completes.
@@ -48,6 +64,17 @@ static void xen_unregister_watchers(struct xenvif *vif);
static void set_backend_state(struct backend_info *be,
enum xenbus_state state);
+static int xenbus_read_feature(const char *dir, const char *node,
+ unsigned int default_val)
+{
+ char reqnode[REQUIRE_PATH_LEN];
+ unsigned int val;
+
+ snprintf(reqnode, REQUIRE_PATH_LEN, "%s/require", dir);
+ val = xenbus_read_unsigned(reqnode, node, default_val);
+ return val;
+}
+
#ifdef CONFIG_DEBUG_FS
struct dentry *xen_netback_dbg_root = NULL;
@@ -280,6 +307,32 @@ static int netback_remove(struct xenbus_device *dev)
return 0;
}
+static void netback_probe_features(struct xenbus_device *dev,
+ struct backend_info *be)
+{
+ struct backend_features *ft = &be->features;
+
+ ft->can_sg = xenbus_read_feature(dev->nodename, "feature-sg", 1);
+ ft->gso_v4 = xenbus_read_feature(dev->nodename, "feature-gso-v4", 1);
+ ft->gso_v6 = xenbus_read_feature(dev->nodename, "feature-gso-v6", 1);
+ ft->gso_v6 = xenbus_read_feature(dev->nodename, "feature-gso-v6", 1);
+ ft->ipv6_csum = xenbus_read_feature(dev->nodename,
+ "feature-ipv6-csum-offload", 1);
+ ft->ip_no_csum = xenbus_read_feature(dev->nodename,
+ "feature-no-csum-offload", 0);
+ ft->mcast_ctrl = xenbus_read_feature(dev->nodename,
+ "feature-multicast-control", 1);
+ ft->dyn_mcast_ctrl = xenbus_read_feature(dev->nodename,
+ "feature-dynamic-multicast-control", 1);
+ ft->split_evtchn = xenbus_read_feature(dev->nodename,
+ "feature-split-event-channels",
+ separate_tx_rx_irq);
+ ft->max_queues = xenbus_read_feature(dev->nodename,
+ "multi-queue-max-queues",
+ xenvif_max_queues);
+ ft->ctrl_ring = xenbus_read_feature(dev->nodename, "feature-ctrl-ring",
+ 1);
+}
/**
* Entry point to this code when a new device is created. Allocate the basic
@@ -291,8 +344,8 @@ static int netback_probe(struct xenbus_device *dev,
const char *message;
struct xenbus_transaction xbt;
int err;
- int sg;
const char *script;
+ struct backend_features *ft;
struct backend_info *be = kzalloc(sizeof(struct backend_info),
GFP_KERNEL);
if (!be) {
@@ -309,7 +362,8 @@ static int netback_probe(struct xenbus_device *dev,
if (err)
goto fail;
- sg = 1;
+ netback_probe_features(dev, be);
+ ft = &be->features;
do {
err = xenbus_transaction_start(&xbt);
@@ -318,21 +372,22 @@ static int netback_probe(struct xenbus_device *dev,
goto fail;
}
- err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", sg);
+ err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d",
+ ft->can_sg);
if (err) {
message = "writing feature-sg";
goto abort_transaction;
}
err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4",
- "%d", sg);
+ "%d", ft->gso_v4);
if (err) {
message = "writing feature-gso-tcpv4";
goto abort_transaction;
}
err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv6",
- "%d", sg);
+ "%d", ft->gso_v6);
if (err) {
message = "writing feature-gso-tcpv6";
goto abort_transaction;
@@ -341,12 +396,21 @@ static int netback_probe(struct xenbus_device *dev,
/* We support partial checksum setup for IPv6 packets */
err = xenbus_printf(xbt, dev->nodename,
"feature-ipv6-csum-offload",
- "%d", 1);
+ "%d", ft->ipv6_csum);
if (err) {
message = "writing feature-ipv6-csum-offload";
goto abort_transaction;
}
+ /* We support partial checksum setup for IPv4 packets */
+ err = xenbus_printf(xbt, dev->nodename,
+ "feature-no-csum-offload",
+ "%d", ft->ip_no_csum);
+ if (err) {
+ message = "writing feature-no-csum-offload";
+ goto abort_transaction;
+ }
+
/* We support rx-copy path. */
err = xenbus_printf(xbt, dev->nodename,
"feature-rx-copy", "%d", 1);
@@ -368,7 +432,8 @@ static int netback_probe(struct xenbus_device *dev,
/* We support dynamic multicast-control. */
err = xenbus_printf(xbt, dev->nodename,
- "feature-multicast-control", "%d", 1);
+ "feature-multicast-control", "%d",
+ ft->mcast_ctrl);
if (err) {
message = "writing feature-multicast-control";
goto abort_transaction;
@@ -376,7 +441,7 @@ static int netback_probe(struct xenbus_device *dev,
err = xenbus_printf(xbt, dev->nodename,
"feature-dynamic-multicast-control",
- "%d", 1);
+ "%d", ft->dyn_mcast_ctrl);
if (err) {
message = "writing feature-dynamic-multicast-control";
goto abort_transaction;
@@ -396,19 +461,19 @@ static int netback_probe(struct xenbus_device *dev,
*/
err = xenbus_printf(XBT_NIL, dev->nodename,
"feature-split-event-channels",
- "%u", separate_tx_rx_irq);
+ "%u", ft->split_evtchn);
if (err)
pr_debug("Error writing feature-split-event-channels\n");
/* Multi-queue support: This is an optional feature. */
err = xenbus_printf(XBT_NIL, dev->nodename,
- "multi-queue-max-queues", "%u", xenvif_max_queues);
+ "multi-queue-max-queues", "%u", ft->max_queues);
if (err)
pr_debug("Error writing multi-queue-max-queues\n");
err = xenbus_printf(XBT_NIL, dev->nodename,
"feature-ctrl-ring",
- "%u", true);
+ "%u", ft->ctrl_ring);
if (err)
pr_debug("Error writing feature-ctrl-ring\n");
@@ -904,6 +969,9 @@ static int connect_ctrl_ring(struct backend_info *be)
unsigned int evtchn;
int err;
+ if (!be->features.ctrl_ring)
+ goto done;
+
err = xenbus_scanf(XBT_NIL, dev->otherend,
"ctrl-ring-ref", "%u", &val);
if (err < 0)
@@ -951,11 +1019,11 @@ static void connect(struct backend_info *be)
*/
requested_num_queues = xenbus_read_unsigned(dev->otherend,
"multi-queue-num-queues", 1);
- if (requested_num_queues > xenvif_max_queues) {
+ if (requested_num_queues > be->features.max_queues) {
/* buggy or malicious guest */
xenbus_dev_fatal(dev, -EINVAL,
"guest requested %u queues, exceeding the maximum of %u.",
- requested_num_queues, xenvif_max_queues);
+ requested_num_queues, be->features.max_queues);
return;
}
@@ -1110,10 +1178,13 @@ static int connect_data_rings(struct backend_info *be,
goto err;
}
+ err = -EOPNOTSUPP;
/* Try split event channels first, then single event channel. */
- err = xenbus_gather(XBT_NIL, xspath,
- "event-channel-tx", "%u", &tx_evtchn,
- "event-channel-rx", "%u", &rx_evtchn, NULL);
+ if (be->features.split_evtchn)
+ err = xenbus_gather(XBT_NIL, xspath,
+ "event-channel-tx", "%u", &tx_evtchn,
+ "event-channel-rx", "%u", &rx_evtchn, NULL);
+
if (err < 0) {
err = xenbus_scanf(XBT_NIL, xspath,
"event-channel", "%u", &tx_evtchn);
@@ -1173,21 +1244,26 @@ static int read_xenbus_vif_flags(struct backend_info *be)
be->vif->stall_timeout = 0;
}
- vif->can_sg = !!xenbus_read_unsigned(dev->otherend, "feature-sg", 0);
+ vif->can_sg = be->features.can_sg &&
+ !!xenbus_read_unsigned(dev->otherend, "feature-sg", 0);
vif->gso_mask = 0;
- if (xenbus_read_unsigned(dev->otherend, "feature-gso-tcpv4", 0))
+ if (be->features.gso_v4 &&
+ xenbus_read_unsigned(dev->otherend, "feature-gso-tcpv4", 0))
vif->gso_mask |= GSO_BIT(TCPV4);
- if (xenbus_read_unsigned(dev->otherend, "feature-gso-tcpv6", 0))
+ if (be->features.gso_v6 &&
+ xenbus_read_unsigned(dev->otherend, "feature-gso-tcpv6", 0))
vif->gso_mask |= GSO_BIT(TCPV6);
- vif->ip_csum = !xenbus_read_unsigned(dev->otherend,
- "feature-no-csum-offload", 0);
+ vif->ip_csum = !be->features.ip_no_csum &&
+ !xenbus_read_unsigned(dev->otherend,
+ "feature-no-csum-offload", 0);
- vif->ipv6_csum = !!xenbus_read_unsigned(dev->otherend,
- "feature-ipv6-csum-offload", 0);
+ vif->ipv6_csum = be->features.ipv6_csum &&
+ !!xenbus_read_unsigned(dev->otherend,
+ "feature-ipv6-csum-offload", 0);
return 0;
}
Toolstack may write values to the "require" subdirectory in the backend main xenstore directory (e.g. backend/vif/X/Y/). Read these values and use them when announcing those to the frontend. When backend scans frontend features the values set in the require directory take precedence, hence making no significant changes in feature parsing. This is achieved by using the newly introduced helper (xenbus_printf_feature()) which reads from require subdirectory and prints that value and otherwise printing a default_val in the entry. We then replace all instances of xenbus_printf by this new helper. A backend_features struct is introduced and all values set there are used in place of the module parameters being used. Note, however that feature-rx-copy, feature-rx-flip aren't probed because first two aren't implemented the full set of possibilities. Additionally probe to for 'feature-no-csum-offload' to allow toolstack to control per device checksum offloading. Signed-off-by: Joao Martins <joao.m.martins@oracle.com> --- drivers/net/xen-netback/xenbus.c | 122 +++++++++++++++++++++++++++++++-------- 1 file changed, 99 insertions(+), 23 deletions(-)