Skip to content
This repository has been archived by the owner on Sep 19, 2024. It is now read-only.

add common context to commands #38

Merged
merged 4 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ wasm-objs := third-party/wasm3/source/m3_api_libc.o \
worker_thread.o \
opa.o \
proxywasm.o \
socket.o
socket.o \
task_context.o \
commands.o

# Set the path to the Kernel build utils.
KBUILD=/lib/modules/$(shell uname -r)/build/
Expand Down Expand Up @@ -126,6 +128,6 @@ setup-dev-env:
test -f .vscode/c_cpp_properties.json || cp .vscode/c_cpp_properties.json.orig .vscode/c_cpp_properties.json
brew tap messense/macos-cross-toolchains
brew install $(shell lima uname -m)-unknown-linux-gnu
test -d linux || git clone --depth=1 --branch v6.2 git@github.com:torvalds/linux.git
test -d linux || git clone --depth=1 --branch v6.2 https://github.com/torvalds/linux.git
cd linux && lima make tinyconfig
cd linux && lima make -j
141 changes: 141 additions & 0 deletions commands.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* Copyright (c) 2023 Cisco and/or its affiliates. All rights reserved.
*
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*
* Licensed under the MIT license <LICENSE.MIT or https://opensource.org/licenses/MIT> or the GPLv2 license
* <LICENSE.GPL or https://opensource.org/license/gpl-2-0>, at your option. This file may not be copied,
* modified, or distributed except according to those terms.
*/
#include <linux/slab.h>
#include <linux/uuid.h>

#include "commands.h"
#include "json.h"

// create a function to add a command to the list (called from the VM), locked with a spinlock
command_answer *send_command(char *name, char *data, task_context *context)
{
struct command *cmd = kmalloc(sizeof(struct command), GFP_KERNEL);

uuid_gen(&cmd->uuid);
cmd->name = name;
cmd->data = data;
cmd->context = context;
init_waitqueue_head(&cmd->wait_queue);

spin_lock_irqsave(&command_list_lock, command_list_lock_flags);
list_add_tail(&cmd->list, &command_list);
spin_unlock_irqrestore(&command_list_lock, command_list_lock_flags);

DEFINE_WAIT(wait);

// wait until the command is processed
printk("wasm: waiting for command to be processed");

// wait for the command to be processed
prepare_to_wait(&cmd->wait_queue, &wait, TASK_INTERRUPTIBLE);
// Sleep until the condition is true or the timeout expires
unsigned long timeout = msecs_to_jiffies(COMMAND_TIMEOUT_SECONDS * 1000);
schedule_timeout(timeout);

finish_wait(&cmd->wait_queue, &wait);

if (cmd->answer == NULL)
{
printk(KERN_ERR "wasm: command answer timeout");

cmd->answer = kmalloc(sizeof(struct command_answer), GFP_KERNEL);
cmd->answer->error = kmalloc(strlen("timeout") + 1, GFP_KERNEL);
strcpy(cmd->answer->error, "timeout");
}

spin_lock_irqsave(&command_list_lock, command_list_lock_flags);
list_del(&cmd->list);
spin_unlock_irqrestore(&command_list_lock, command_list_lock_flags);

command_answer *cmd_answer = cmd->answer;
if (cmd->context)
{
free_task_context(cmd->context);
}
kfree(cmd);

return cmd_answer;
}

command_answer *send_accept_command(u16 port)
{
JSON_Value *root_value = json_value_init_object();
JSON_Object *root_object = json_value_get_object(root_value);

json_object_set_number(root_object, "port", port);

command_answer *answer = send_command("accept", json_serialize_to_string(root_value), get_task_context());

return answer;
}

command_answer *send_connect_command(u16 port)
{
JSON_Value *root_value = json_value_init_object();
JSON_Object *root_object = json_value_get_object(root_value);

json_object_set_number(root_object, "port", port);

command_answer *answer = send_command("connect", json_serialize_to_string(root_value), get_task_context());

return answer;
}

struct command *lookup_in_flight_command(char *id)
{
spin_lock_irqsave(&command_list_lock, command_list_lock_flags);

struct command *cmd = NULL;
struct command *tmp;
list_for_each_entry(tmp, &in_flight_command_list, list)
{
if (strncmp(tmp->uuid.b, id, UUID_SIZE) == 0)
{
cmd = tmp;
break;
}
}

spin_unlock_irqrestore(&command_list_lock, command_list_lock_flags);

return cmd;
}

// create a function to get a command from the list (called from the driver), locked with a mutex
struct command *get_command(void)
{
struct command *cmd = NULL;

spin_lock_irqsave(&command_list_lock, command_list_lock_flags);
if (!list_empty(&command_list))
{
cmd = list_first_entry(&command_list, struct command, list);
list_del(&cmd->list);
list_add_tail(&cmd->list, &in_flight_command_list);
}
spin_unlock_irqrestore(&command_list_lock, command_list_lock_flags);

return cmd;
}

void free_command_answer(struct command_answer *cmd_answer)
{
if (cmd_answer->error)
{
kfree(cmd_answer->error);
}

if (cmd_answer->answer)
{
kfree(cmd_answer->answer);
}

kfree(cmd_answer);
}
52 changes: 52 additions & 0 deletions commands.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2023 Cisco and/or its affiliates. All rights reserved.
*
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*
* Licensed under the MIT license <LICENSE.MIT or https://opensource.org/licenses/MIT> or the GPLv2 license
* <LICENSE.GPL or https://opensource.org/license/gpl-2-0>, at your option. This file may not be copied,
* modified, or distributed except according to those terms.
*/

#ifndef commands_h
#define commands_h

#include "task_context.h"

#define COMMAND_TIMEOUT_SECONDS 1

typedef struct command_answer
{
char *error;
char *answer;
} command_answer;

void free_command_answer(command_answer *cmd_answer);

command_answer *send_command(char *name, char *data, task_context *context);

command_answer *send_accept_command(u16 port);
command_answer *send_connect_command(u16 port);

// create a linked list for outgoing commands
typedef struct command
{
struct list_head list;
char *name;
char *data;
task_context *context;
uuid_t uuid;
struct command_answer *answer;
wait_queue_head_t wait_queue;
};

struct command *lookup_in_flight_command(char *id);
struct command *get_command(void);

// protect the command list with a mutex
static DEFINE_SPINLOCK(command_list_lock);
static unsigned long command_list_lock_flags;
static LIST_HEAD(command_list);
static LIST_HEAD(in_flight_command_list);

#endif
131 changes: 14 additions & 117 deletions device_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@
#include "proxywasm.h"
#include "csr.h"
#include "runtime.h"
#include "commands.h"

/* Global variables are declared as static, so are global within the file. */

#define DEFAULT_MODULE_ENTRYPOINT "main"
#define COMMAND_TIMEOUT_SECONDS 5

static int major; /* major number assigned to our device driver */

Expand All @@ -37,120 +37,6 @@ enum
/* Is device open? Used to prevent multiple access to device */
static atomic_t already_open = ATOMIC_INIT(CDEV_NOT_USED);

// create a linked list for outgoing commands
typedef struct command
{
struct list_head list;
char *name;
char *data;
uuid_t uuid;
struct command_answer *answer;
wait_queue_head_t wait_queue;
};

// protect the command list with a mutex
static DEFINE_SPINLOCK(command_list_lock);
static unsigned long command_list_lock_flags;
static LIST_HEAD(command_list);
static LIST_HEAD(in_flight_command_list);

static struct command *lookup_in_flight_command(char *id)
{
spin_lock_irqsave(&command_list_lock, command_list_lock_flags);

struct command *cmd = NULL;
struct command *tmp;
list_for_each_entry(tmp, &in_flight_command_list, list)
{
if (strncmp(tmp->uuid.b, id, UUID_SIZE) == 0)
{
cmd = tmp;
break;
}
}

spin_unlock_irqrestore(&command_list_lock, command_list_lock_flags);

return cmd;
}

void free_command_answer(struct command_answer *cmd_answer)
{
if (cmd_answer->error)
{
kfree(cmd_answer->error);
}

if (cmd_answer->answer)
{
kfree(cmd_answer->answer);
}

kfree(cmd_answer);
}

// create a function to add a command to the list (called from the VM), locked with a spinlock
command_answer *send_command(char *name, char *data)
{
struct command *cmd = kmalloc(sizeof(struct command), GFP_KERNEL);

uuid_gen(&cmd->uuid);
cmd->name = name;
cmd->data = data;
init_waitqueue_head(&cmd->wait_queue);

spin_lock_irqsave(&command_list_lock, command_list_lock_flags);
list_add_tail(&cmd->list, &command_list);
spin_unlock_irqrestore(&command_list_lock, command_list_lock_flags);

DEFINE_WAIT(wait);

// wait until the command is processed
printk("wasm: waiting for command to be processed");

// wait for the command to be processed
prepare_to_wait(&cmd->wait_queue, &wait, TASK_INTERRUPTIBLE);
// Sleep until the condition is true or the timeout expires
unsigned long timeout = msecs_to_jiffies(COMMAND_TIMEOUT_SECONDS * 1000);
schedule_timeout(timeout);

finish_wait(&cmd->wait_queue, &wait);

if (cmd->answer == NULL)
{
printk(KERN_ERR "wasm: command answer timeout");

cmd->answer = kmalloc(sizeof(struct command_answer), GFP_KERNEL);
cmd->answer->error = kmalloc(strlen("timeout") + 1, GFP_KERNEL);
strcpy(cmd->answer->error, "timeout");
}

spin_lock_irqsave(&command_list_lock, command_list_lock_flags);
list_del(&cmd->list);
spin_unlock_irqrestore(&command_list_lock, command_list_lock_flags);

command_answer *cmd_answer = cmd->answer;
kfree(cmd);
return cmd_answer;
}

// create a function to get a command from the list (called from the driver), locked with a mutex
static struct command *get_command(void)
{
struct command *cmd = NULL;

spin_lock_irqsave(&command_list_lock, command_list_lock_flags);
if (!list_empty(&command_list))
{
cmd = list_first_entry(&command_list, struct command, list);
list_del(&cmd->list);
list_add_tail(&cmd->list, &in_flight_command_list);
}
spin_unlock_irqrestore(&command_list_lock, command_list_lock_flags);

return cmd;
}

static int write_command_to_buffer(char *buffer, size_t buffer_size, struct command *cmd)
{
char uuid[UUID_SIZE * 2];
Expand All @@ -164,12 +50,23 @@ static int write_command_to_buffer(char *buffer, size_t buffer_size, struct comm
JSON_Value *root_value = json_value_init_object();
JSON_Object *root_object = json_value_get_object(root_value);

if (cmd->context)
{
JSON_Value *context_value = json_value_init_object();
JSON_Object *context_object = json_value_get_object(context_value);
json_object_set_number(context_object, "uid", cmd->context->uid.val);
json_object_set_number(context_object, "gid", cmd->context->gid.val);
json_object_set_string(context_object, "command_path", cmd->context->command_path);
json_object_set_string(context_object, "command_name", cmd->context->command_name);
json_object_set_value(root_object, "context", context_value);
}

json_object_set_string(root_object, "id", uuid);
json_object_set_string(root_object, "command", cmd->name);
json_object_set_string(root_object, "data", cmd->data);

char *serialized_string = json_serialize_to_string(root_value);

length = strlen(serialized_string);
if (length > buffer_size)
{
Expand Down Expand Up @@ -545,7 +442,7 @@ static ssize_t device_read(struct file *file, /* see include/linux/fs.h */

int json_length = write_command_to_buffer(device_out_buffer, sizeof device_out_buffer, c);
if (json_length < 0)
{
{
return -EFAULT;
}

Expand Down
9 changes: 0 additions & 9 deletions device_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,6 @@ static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char __user *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char __user *, size_t, loff_t *);

typedef struct command_answer
{
char *error;
char *answer;
} command_answer;

void free_command_answer(command_answer *cmd_answer);

command_answer *send_command(char *name, char *data);
wasm_vm_result load_module(char *name, char *code, unsigned length, char *entrypoint);

#define SUCCESS 0
Expand Down
Loading