aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWei Chen <Wei.Chen@arm.com>2017-08-25 10:18:23 +0800
committerWill Deacon <will.deacon@arm.com>2017-08-30 09:44:00 +0100
commit59ee54eb10d78c2411795f89ad44459ee7a11425 (patch)
tree8e91b20987a69a19b91f2de8e427acc92799837b
parent1cc05b24bfe0211bb408f3264af8e0c42dcdde9c (diff)
downloadkvmtool-59ee54eb10d78c2411795f89ad44459ee7a11425.tar.gz
net: Check UFO offloading support for tap driver
In Linux commit fb652fdfe83710da0ca13448a41b7ed027d0a984: https://www.spinics.net/lists/netdev/msg443562.html The UFO support had been removed. If we use tap mode for network (--network mode=tap,tapif=...), we will get following error: "Warning: Config tap device TUNSETOFFLOAD error You have requested a TAP device, but creation of one has failed because: Invalid argument" So, if we're running with latest kernel, we'd better to remove TUN_F_UFO from TAP init. But if we're running with older kernels without above commit. We'll miss the UFO feature. In this case, we'd better to check the kernel UFO support status for tap driver. The tap UFO state will used in get_host_features to return correct VIRTIO_NET features. If we defer the tap UFO support check in virtio_net__tap_init, it will be too later. So we separate the tap create code from tap_init to a standalone function. This new function will be used in virtio_net_init to create tap device and check the tap UFO support status at the very beginning. Signed-off-by: Wei Chen <Wei.Chen@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--virtio/net.c114
1 files changed, 80 insertions, 34 deletions
diff --git a/virtio/net.c b/virtio/net.c
index 9fb9f1ee..419a5e30 100644
--- a/virtio/net.c
+++ b/virtio/net.c
@@ -52,6 +52,7 @@ struct net_dev {
int vhost_fd;
int tap_fd;
char tap_name[IFNAMSIZ];
+ bool tap_ufo;
int mode;
@@ -315,34 +316,11 @@ static int virtio_net_exec_script(const char* script, const char *tap_name)
static bool virtio_net__tap_init(struct net_dev *ndev)
{
int sock = socket(AF_INET, SOCK_STREAM, 0);
- int offload, hdr_len;
+ int hdr_len;
struct sockaddr_in sin = {0};
struct ifreq ifr;
const struct virtio_net_params *params = ndev->params;
bool skipconf = !!params->tapif;
- bool macvtap = skipconf && (params->tapif[0] == '/');
- const char *tap_file = "/dev/net/tun";
-
- /* Did the user already gave us the FD? */
- if (params->fd) {
- ndev->tap_fd = params->fd;
- return 1;
- }
-
- if (macvtap)
- tap_file = params->tapif;
-
- ndev->tap_fd = open(tap_file, O_RDWR);
- if (ndev->tap_fd < 0) {
- pr_warning("Unable to open %s", tap_file);
- goto fail;
- }
-
- if (!macvtap &&
- virtio_net_request_tap(ndev, &ifr, params->tapif) < 0) {
- pr_warning("Config tap device error. Are you root?");
- goto fail;
- }
hdr_len = has_virtio_feature(ndev, VIRTIO_NET_F_MRG_RXBUF) ?
sizeof(struct virtio_net_hdr_mrg_rxbuf) :
@@ -350,12 +328,6 @@ static bool virtio_net__tap_init(struct net_dev *ndev)
if (ioctl(ndev->tap_fd, TUNSETVNETHDRSZ, &hdr_len) < 0)
pr_warning("Config tap device TUNSETVNETHDRSZ error");
- offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | TUN_F_UFO;
- if (ioctl(ndev->tap_fd, TUNSETOFFLOAD, offload) < 0) {
- pr_warning("Config tap device TUNSETOFFLOAD error");
- goto fail;
- }
-
if (strcmp(params->script, "none")) {
if (virtio_net_exec_script(params->script, ndev->tap_name) < 0)
goto fail;
@@ -393,6 +365,68 @@ fail:
return 0;
}
+static bool virtio_net__tap_create(struct net_dev *ndev)
+{
+ int offload;
+ struct ifreq ifr;
+ const struct virtio_net_params *params = ndev->params;
+ bool macvtap = (!!params->tapif) && (params->tapif[0] == '/');
+
+ /* Did the user already gave us the FD? */
+ if (params->fd)
+ ndev->tap_fd = params->fd;
+ else {
+ const char *tap_file = "/dev/net/tun";
+
+ /* Did the user ask us to use macvtap? */
+ if (macvtap)
+ tap_file = params->tapif;
+
+ ndev->tap_fd = open(tap_file, O_RDWR);
+ if (ndev->tap_fd < 0) {
+ pr_warning("Unable to open %s", tap_file);
+ return 0;
+ }
+ }
+
+ if (!macvtap &&
+ virtio_net_request_tap(ndev, &ifr, params->tapif) < 0) {
+ pr_warning("Config tap device error. Are you root?");
+ goto fail;
+ }
+
+ /*
+ * The UFO support had been removed from kernel in commit:
+ * ID: fb652fdfe83710da0ca13448a41b7ed027d0a984
+ * https://www.spinics.net/lists/netdev/msg443562.html
+ * In oder to support the older kernels without this commit,
+ * we set the TUN_F_UFO to offload by default to test the status of
+ * UFO kernel support.
+ */
+ ndev->tap_ufo = true;
+ offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | TUN_F_UFO;
+ if (ioctl(ndev->tap_fd, TUNSETOFFLOAD, offload) < 0) {
+ /*
+ * Is this failure caused by kernel remove the UFO support?
+ * Try TUNSETOFFLOAD without TUN_F_UFO.
+ */
+ offload &= ~TUN_F_UFO;
+ if (ioctl(ndev->tap_fd, TUNSETOFFLOAD, offload) < 0) {
+ pr_warning("Config tap device TUNSETOFFLOAD error");
+ goto fail;
+ }
+ ndev->tap_ufo = false;
+ }
+
+ return 1;
+
+fail:
+ if ((ndev->tap_fd >= 0) || (!params->fd) )
+ close(ndev->tap_fd);
+
+ return 0;
+}
+
static inline int tap_ops_tx(struct iovec *iov, u16 out, struct net_dev *ndev)
{
return writev(ndev->tap_fd, iov, out);
@@ -432,14 +466,13 @@ static u8 *get_config(struct kvm *kvm, void *dev)
static u32 get_host_features(struct kvm *kvm, void *dev)
{
+ u32 features;
struct net_dev *ndev = dev;
- return 1UL << VIRTIO_NET_F_MAC
+ features = 1UL << VIRTIO_NET_F_MAC
| 1UL << VIRTIO_NET_F_CSUM
- | 1UL << VIRTIO_NET_F_HOST_UFO
| 1UL << VIRTIO_NET_F_HOST_TSO4
| 1UL << VIRTIO_NET_F_HOST_TSO6
- | 1UL << VIRTIO_NET_F_GUEST_UFO
| 1UL << VIRTIO_NET_F_GUEST_TSO4
| 1UL << VIRTIO_NET_F_GUEST_TSO6
| 1UL << VIRTIO_RING_F_EVENT_IDX
@@ -447,6 +480,16 @@ static u32 get_host_features(struct kvm *kvm, void *dev)
| 1UL << VIRTIO_NET_F_CTRL_VQ
| 1UL << VIRTIO_NET_F_MRG_RXBUF
| 1UL << (ndev->queue_pairs > 1 ? VIRTIO_NET_F_MQ : 0);
+
+ /*
+ * The UFO feature for host and guest only can be enabled when the
+ * kernel has TAP UFO support.
+ */
+ if (ndev->tap_ufo)
+ features |= (1UL << VIRTIO_NET_F_HOST_UFO
+ | 1UL << VIRTIO_NET_F_GUEST_UFO);
+
+ return features;
}
static int virtio_net__vhost_set_features(struct net_dev *ndev)
@@ -478,7 +521,8 @@ static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
if (ndev->mode == NET_MODE_TAP) {
if (!virtio_net__tap_init(ndev))
- die_perror("You have requested a TAP device, but creation of one has failed because");
+ die_perror("TAP device initialized failed because");
+
if (ndev->vhost_fd &&
virtio_net__vhost_set_features(ndev) != 0)
die_perror("VHOST_SET_FEATURES failed");
@@ -820,6 +864,8 @@ static int virtio_net__init_one(struct virtio_net_params *params)
ndev->mode = params->mode;
if (ndev->mode == NET_MODE_TAP) {
ndev->ops = &tap_ops;
+ if (!virtio_net__tap_create(ndev))
+ die_perror("You have requested a TAP device, but creation of one has failed because");
} else {
ndev->info.host_ip = ntohl(inet_addr(params->host_ip));
ndev->info.guest_ip = ntohl(inet_addr(params->guest_ip));