summaryrefslogtreecommitdiffstats
path: root/src/vnet/devices/virtio/virtio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vnet/devices/virtio/virtio.c')
-rw-r--r--src/vnet/devices/virtio/virtio.c159
1 files changed, 159 insertions, 0 deletions
diff --git a/src/vnet/devices/virtio/virtio.c b/src/vnet/devices/virtio/virtio.c
new file mode 100644
index 00000000000..63ca6011a9e
--- /dev/null
+++ b/src/vnet/devices/virtio/virtio.c
@@ -0,0 +1,159 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <linux/if_tun.h>
+#include <sys/ioctl.h>
+#include <linux/virtio_net.h>
+#include <linux/vhost.h>
+#include <sys/eventfd.h>
+
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+#include <vnet/ethernet/ethernet.h>
+#include <vnet/devices/virtio/virtio.h>
+
+virtio_main_t virtio_main;
+
+#define _IOCTL(fd,a,...) \
+ if (ioctl (fd, a, __VA_ARGS__) < 0) \
+ { \
+ err = clib_error_return_unix (0, "ioctl(" #a ")"); \
+ goto error; \
+ }
+
+static clib_error_t *
+call_read_ready (clib_file_t * uf)
+{
+ virtio_main_t *nm = &virtio_main;
+ vnet_main_t *vnm = vnet_get_main ();
+ u16 qid = uf->private_data & 0xFFFF;
+ virtio_if_t *vif =
+ vec_elt_at_index (nm->interfaces, uf->private_data >> 16);
+ u64 b;
+
+ CLIB_UNUSED (ssize_t size) = read (uf->file_descriptor, &b, sizeof (b));
+ if ((qid & 1) == 0)
+ vnet_device_input_set_interrupt_pending (vnm, vif->hw_if_index, qid);
+
+ return 0;
+}
+
+
+clib_error_t *
+virtio_vring_init (vlib_main_t * vm, virtio_if_t * vif, u16 idx, u16 sz)
+{
+ clib_error_t *err = 0;
+ virtio_vring_t *vring;
+ struct vhost_vring_state state;
+ struct vhost_vring_addr addr;
+ struct vhost_vring_file file;
+ clib_file_t t = { 0 };
+ int i;
+
+ if (!is_pow2 (sz))
+ return clib_error_return (0, "ring size must be power of 2");
+
+ if (sz > 32768)
+ return clib_error_return (0, "ring size must be 32768 or lower");
+
+ if (sz == 0)
+ sz = 256;
+
+ vec_validate_aligned (vif->vrings, idx, CLIB_CACHE_LINE_BYTES);
+ vring = vec_elt_at_index (vif->vrings, idx);
+
+ i = sizeof (struct vring_desc) * sz;
+ i = round_pow2 (i, CLIB_CACHE_LINE_BYTES);
+ vring->desc = clib_mem_alloc_aligned (i, CLIB_CACHE_LINE_BYTES);
+ memset (vring->desc, 0, i);
+
+ i = sizeof (struct vring_avail) + sz * sizeof (vring->avail->ring[0]);
+ i = round_pow2 (i, CLIB_CACHE_LINE_BYTES);
+ vring->avail = clib_mem_alloc_aligned (i, CLIB_CACHE_LINE_BYTES);
+ memset (vring->avail, 0, i);
+ // tell kernel that we don't need interrupt
+ vring->avail->flags = VIRTIO_RING_FLAG_MASK_INT;
+
+ i = sizeof (struct vring_used) + sz * sizeof (struct vring_used_elem);
+ i = round_pow2 (i, CLIB_CACHE_LINE_BYTES);
+ vring->used = clib_mem_alloc_aligned (i, CLIB_CACHE_LINE_BYTES);
+ memset (vring->used, 0, i);
+
+ ASSERT (vring->buffers == 0);
+ vec_validate_aligned (vring->buffers, sz * 2, CLIB_CACHE_LINE_BYTES);
+
+ vring->size = sz;
+ vring->call_fd = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC);
+ vring->kick_fd = eventfd (0, EFD_CLOEXEC);
+
+ t.read_function = call_read_ready;
+ t.file_descriptor = vring->call_fd;
+ t.private_data = vif->dev_instance << 16 | idx;
+ vring->call_file_index = clib_file_add (&file_main, &t);
+
+ state.index = idx;
+ state.num = sz;
+ _IOCTL (vif->fd, VHOST_SET_VRING_NUM, &state);
+
+ addr.index = idx;
+ addr.flags = 0;
+ addr.desc_user_addr = pointer_to_uword (vring->desc);
+ addr.avail_user_addr = pointer_to_uword (vring->avail);
+ addr.used_user_addr = pointer_to_uword (vring->used);
+ _IOCTL (vif->fd, VHOST_SET_VRING_ADDR, &addr);
+
+ file.index = idx;
+ file.fd = vring->kick_fd;
+ _IOCTL (vif->fd, VHOST_SET_VRING_KICK, &file);
+ file.fd = vring->call_fd;
+ _IOCTL (vif->fd, VHOST_SET_VRING_CALL, &file);
+ file.fd = vif->tap_fd;
+ _IOCTL (vif->fd, VHOST_NET_SET_BACKEND, &file);
+
+error:
+ return err;
+}
+
+clib_error_t *
+virtio_vring_free (virtio_if_t * vif, u32 idx)
+{
+ //TODO free buffers and indirect descriptor allocs
+ virtio_vring_t *vring = vec_elt_at_index (vif->vrings, idx);
+ if (vring->desc)
+ clib_mem_free (vring->desc);
+ if (vring->avail)
+ clib_mem_free (vring->avail);
+ if (vring->used)
+ clib_mem_free (vring->used);
+ clib_file_del_by_index (&file_main, vring->call_file_index);
+ close (vring->kick_fd);
+ close (vring->call_fd);
+ vec_free (vring->buffers);
+ return 0;
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */