aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>2024-10-08 13:30:34 +0300
committerTimos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>2024-10-08 13:31:47 +0300
commit153ec0a4e0b9b426d3dbf68534c6dfa55b58ebae (patch)
treedcb02e1fd6b80862b11d14e95c434ad0bf0525f9
parent9941dec970111be9e02dcaf6819c037946bde160 (diff)
Update virtio-loopback-adapter
Updates [v1]: - Add missing source file: src/adapter/parser.c and src/adapter/adapter.c - Fix compilation error Bug-AGL: SPEC-4834 Change-Id: Ie3e4e493d09bfee4be49a3177e9fb0995cca614b Signed-off-by: Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>
-rw-r--r--linux/.fuse_hidden001086ab000006dabin16384 -> 0 bytes
-rw-r--r--src/adapter/adapter.c214
-rw-r--r--src/adapter/parser.c215
3 files changed, 429 insertions, 0 deletions
diff --git a/linux/.fuse_hidden001086ab000006da b/linux/.fuse_hidden001086ab000006da
deleted file mode 100644
index ce99873..0000000
--- a/linux/.fuse_hidden001086ab000006da
+++ /dev/null
Binary files differ
diff --git a/src/adapter/adapter.c b/src/adapter/adapter.c
new file mode 100644
index 0000000..8360ffb
--- /dev/null
+++ b/src/adapter/adapter.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2022-2023 Virtual Open Systems SAS
+ *
+ * Authors:
+ * Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>
+ * Stefanos Gerangelos <s.gerangelos@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/eventfd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <sys/param.h>
+#include <assert.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+/* For socket */
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+/* Project header files */
+#include "adapter.h"
+
+#ifdef DEBUG
+#define DBG(...) printf("adapter: " __VA_ARGS__)
+#else
+#define DBG(...)
+#endif /* DEBUG */
+
+/* Global variables */
+struct adapter_dev* adevs[MAX_DEVICES];
+Device devices[MAX_DEVICES];
+
+static int alloc_adapter_dev(struct adapter_dev **adevs_ptr, Device *device_params)
+{
+ struct adapter_dev *adev;
+
+ DBG("Setup adapter data structures\n");
+
+ /* Init adapter device */
+ adev = (struct adapter_dev *)malloc(sizeof(struct adapter_dev));
+ adev->device_params = device_params;
+
+ /* Add device to global structure */
+ *adevs_ptr = adev;
+
+ /* Interconnections */
+ adev->vbus.vdev = &adev->virtio_dev;
+ adev->virtio_dev.vbus = &adev->vbus;
+ adev->virtio_dev.vhdev = &adev->vdev;
+ adev->vdev.vdev = &adev->virtio_dev;
+ adev->vudev.dev = &adev->vdev;
+ adev->vdev.vhudev = &adev->vudev;
+
+ return 0;
+}
+
+static int init_adapter_data_structure(int active_devices)
+{
+ int i, err;
+
+ for (i = 0; i < active_devices; i++) {
+ err = alloc_adapter_dev(&adevs[i], &devices[i]);
+ if (err)
+ return -1;
+ }
+
+ return 0;
+}
+
+static void client(Device *device)
+{
+ int rc, len;
+ struct sockaddr_un client_sockaddr;
+ char *sock_path = device->socket;
+
+ DBG("Create shared socket with vhost-user-device\n");
+
+ /* Initialize the struct to zero */
+ memset(&client_sockaddr, 0, sizeof(struct sockaddr_un));
+
+ /*
+ * Create a UNIX socket
+ */
+ device->client_socket = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (device->client_socket == -1) {
+ DBG("SOCKET ERROR\n");
+ exit(1);
+ }
+
+ /*
+ * Set up the UNIX sockaddr structure
+ * by using AF_UNIX for the family and
+ * giving it a filepath to connect.
+ */
+ client_sockaddr.sun_family = AF_UNIX;
+ strcpy(client_sockaddr.sun_path, sock_path);
+ len = sizeof(client_sockaddr);
+ rc = connect(device->client_socket, (struct sockaddr *) &client_sockaddr, len);
+ if (rc == -1) {
+ printf("CONNECT ERROR: Check the \"-s\" parameter\n");
+ close(device->client_socket);
+ exit(1);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int device_count, i, ret;
+ pthread_t thread_ids[MAX_DEVICES];
+
+
+ /* Parse arguments */
+ device_count = parse_args(argc, argv);
+ if (device_count < 0)
+ goto error_args;
+
+ /* Initialize the adapter data structures */
+ init_adapter_data_structure(device_count);
+
+ for (i = 0; i < device_count; i++) {
+
+ /*
+ * Create the socket and connect to the backend.
+ * Enabled on vhost-user case
+ */
+ if (devices[i].requires_socket) {
+ client(&devices[i]);
+ }
+
+ /* Initialize the virtio/vhost-user device */
+ /* TODO: Switch numbers with name defs */
+ switch (devices[i].device_index) {
+ case 0:
+ virtio_rng_realize(adevs[i]);
+ break;
+ case 1:
+ vhost_user_rng_realize(adevs[i]);
+ break;
+ case 2:
+ vhost_user_blk_realize(adevs[i]);
+ break;
+ case 3:
+ virtio_input_device_realize(adevs[i]);
+ break;
+ case 4:
+ vus_device_realize(adevs[i]);
+ break;
+ case 5:
+ vu_gpio_device_realize(adevs[i]);
+ break;
+ case 6:
+ vhost_user_can_realize(adevs[i]);
+ break;
+ case 7:
+ vhost_user_console_realize(adevs[i]);
+ break;
+ default:
+ exit(1);
+ }
+
+ /*
+ * Start loopback trasnport layer and communiation with the loopback driver
+ */
+ DBG("Start loobpack[%i]\n", i);
+ ret = virtio_loopback_start(adevs[i], &thread_ids[i]);
+ if (ret != 0) {
+ DBG("Error starting device: %d\n", i);
+ goto error_driver;
+ }
+ }
+
+ for (i = 0; i < device_count; i++) {
+ ret = pthread_join(thread_ids[i], NULL);
+ if (ret != 0) {
+ DBG("Virtio thread: %d terminated with error\n", (int)thread_ids[i]);
+ exit(1);
+ }
+ /* Close open file descriptor */
+ virtio_loopback_stop(adevs[i]);
+ }
+
+ return 0;
+
+error_args:
+ help_args();
+error_driver:
+ return 1;
+}
diff --git a/src/adapter/parser.c b/src/adapter/parser.c
new file mode 100644
index 0000000..0300baa
--- /dev/null
+++ b/src/adapter/parser.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2022-2024 Virtual Open Systems SAS
+ *
+ * Authors:
+ * Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <sys/param.h>
+#include <ctype.h>
+#include <sys/stat.h>
+
+/* For socket */
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+/* Project header files */
+#include "parser.h"
+
+// Function to check if a string contains only digits
+static int is_number(const char *str) {
+ if (str == NULL || *str == '\0') return 0; // Empty string or NULL is invalid
+ for (int i = 0; str[i] != '\0'; i++) {
+ if (!isdigit(str[i])) return 0;
+ }
+ return 1;
+}
+
+// Function to check if queue_num is a valid positive integer
+static int check_queue_num(const char *queue_num_str) {
+ if (!is_number(queue_num_str)) {
+ return 0;
+ }
+ int queue_num = atoi(queue_num_str);
+ return queue_num > 0; // Check if the queue_num is positive
+}
+
+// Function to check if queue_size is a power of 2
+static int check_queue_size(const char *queue_size_str) {
+ if (!is_number(queue_size_str)) {
+ return 0;
+ }
+ int queue_size = atoi(queue_size_str);
+ // Check if the queue_size is a power of 2
+ return (queue_size > 0) && ((queue_size & (queue_size - 1)) == 0);
+}
+
+// Function to check if the socket path is valid
+static int check_socket(const char *socket_path) {
+ if (socket_path == NULL || strlen(socket_path) == 0) {
+ return 0; // Empty path is invalid
+ }
+ if (strlen(socket_path) >= MAX_SOCKET_LENGTH) {
+ return 0; // Path too long
+ }
+
+ struct stat path_stat;
+ if (stat(socket_path, &path_stat) != 0) {
+ return 0; // Path does not exist or cannot be accessed
+ }
+
+ if (!S_ISSOCK(path_stat.st_mode)) {
+ return 0; // Path is not a socket file
+ }
+
+ return 1;
+}
+
+// Function to check if the device name is valid and get its index
+static int check_device_name(const char *device_name, int *device_index, int *requires_socket) {
+ for (unsigned int i = 0; i < num_adapter_devices; i++) {
+ if (strcmp(device_name, adapter_devices[i]) == 0) {
+ *device_index = i;
+ *requires_socket = 0;
+ // Check if the device name is also in vhu_devices
+ for (unsigned int j = 0; j < num_vhu_devices; j++) {
+ if (strcmp(device_name, vhu_devices[j]) == 0) {
+ *requires_socket = 1;
+ break;
+ }
+ }
+ return 1; // Valid device name
+ }
+ }
+ return 0; // Invalid device name
+}
+
+static int parse_device_arg(const char *arg, Device *device) {
+
+ char *token;
+
+ // Initialize with default values
+ device->queue_num = DEFAULT_QUEUE_NUM;
+ device->queue_size = DEFAULT_QUEUE_SIZE;
+
+ // Extract device name
+ token = strtok((char *)arg, ",");
+ if (token == NULL) {
+ return -1;
+ }
+
+ // Check if the device name is valid and get the index and socket requirement
+ if (!check_device_name(token, &device->device_index, &device->requires_socket)) {
+ return -1; // Invalid device name
+ }
+ strncpy(device->device_name, token, MAX_NAME_LENGTH - 1);
+ device->device_name[MAX_NAME_LENGTH - 1] = '\0'; // Ensure null termination
+
+ // Extract other parameters
+ while ((token = strtok(NULL, ",")) != NULL) {
+ if (strncmp(token, "socket=", 7) == 0) {
+ const char *socket_path = token + 7; // Skip "socket="
+ if (device->requires_socket) {
+ if (!check_socket(socket_path)) {
+ return -1; // Invalid socket path
+ }
+ strncpy(device->socket, socket_path, MAX_SOCKET_LENGTH - 1);
+ device->socket[MAX_SOCKET_LENGTH - 1] = '\0'; // Ensure null termination
+ } else {
+ // If device does not allow socket, return an error
+ fprintf(stderr, "Error: Socket path is not allowed for device: %s\n", device->device_name);
+ return -1;
+ }
+ } else if (strncmp(token, "queue_num=", 10) == 0) {
+ const char *queue_num_str = token + 10; // Skip "queue_num="
+ if (!check_queue_num(queue_num_str)) {
+ return -1; // Invalid queue_num
+ }
+ device->queue_num = atoi(queue_num_str); // Skip "queue_num="
+ } else if (strncmp(token, "queue_size=", 11) == 0) {
+ const char *queue_size_str = token + 11; // Skip "queue_size="
+ if (!check_queue_size(queue_size_str)) {
+ return -1; // Invalid queue_size
+ }
+ device->queue_size = atoi(queue_size_str); // Skip "queue_size="
+ } else {
+ return -1; // Unknown parameter
+ }
+ }
+
+ return 0;
+}
+
+int parse_args(int argc, char *argv[]) {
+ int device_count = 0;
+
+ // Iterate over the command line arguments
+ for (int i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-device") == 0) {
+ if (i + 1 < argc && device_count < MAX_DEVICES) {
+ if (parse_device_arg(argv[i + 1], &devices[device_count]) == 0) {
+ device_count++;
+ } else {
+ fprintf(stderr, "Error: Failed to parse device argument: %s\n", argv[i + 1]);
+ return EXIT_FAILURE;
+ }
+ i++; // Skip next argument as it's already processed
+ } else {
+ fprintf(stderr, "Error: Missing or too many device arguments.\n");
+ return EXIT_FAILURE;
+ }
+ }
+ }
+
+ // Output parsed devices
+ printf("Parsed %d devices:\n", device_count);
+ for (int i = 0; i < device_count; i++) {
+ printf("Device %d:\n", i + 1);
+ printf(" Device index: %d\n", devices[i].device_index);
+ printf(" Name: %s\n", devices[i].device_name);
+ printf(" Socket: %s\n", devices[i].socket);
+ printf(" Queue Num: %d\n", devices[i].queue_num);
+ printf(" Queue Size: %d\n", devices[i].queue_size);
+ }
+
+ return device_count;
+}
+
+void help_args(void)
+{
+ printf("Run example:\n\t./adapter \\\n"
+ "\t\t -device device_name_1,socket=\"/path_to_socket/common.sock[,queue_num=<QUEUE_NUM>,queue_size<QUEUE_SIZE>]\"\n"
+ "\t\t -device device_name_2,socket=\"/path_to_socket/common.sock[,queue_num=<QUEUE_NUM>,queue_size<QUEUE_SIZE>]\"\n"
+ "\t\t ...\n"
+ "\t\t -device device_name,socket=\"/path_to_socket/common.sock[,queue_num=<QUEUE_NUM>,queue_size<QUEUE_SIZE>]\"\n"
+ "The 'device_name' can be one of the following:\n"
+ "\tvrng, vhurng, vhublk, vhuinput, vhusnd, vhugpio, vhucan, vhuconsole\n"
+ "\n"
+ "In case of 'vrng' device, the 'socket' argument is not used\n");
+}