checkpoint

1.) add a simple configuration file to the runtime (see sample.config for example)
2.) bug fixes to ARP worker thread
3.) bug fix to DPDK so completions aren't held too long (still WIP)
4.) print more useful startup messages in runtime
5.) remove shm delete hack, it didn't work as intended
This commit is contained in:
Adam Belay 2018-01-02 15:29:10 -05:00
parent 5e4c8254fe
commit 9efe8bddb1
21 changed files with 309 additions and 64 deletions

View File

@ -182,12 +182,6 @@ void *mem_map_shm(mem_key_t key, void *base, size_t len, size_t pgsize,
if (addr == MAP_FAILED)
return MAP_FAILED;
/* mark the shm segment for destruction after the process dies */
if (exclusive) {
if (shmctl(shmid, IPC_RMID, NULL) == 1)
return MAP_FAILED;
}
touch_mapping(addr, len, pgsize);
return addr;
}

View File

@ -49,7 +49,7 @@
#define IP_ADDR_STR_LEN 16
extern void ip_addr_to_str(uint32_t addr, char *str);
extern char *ip_addr_to_str(uint32_t addr, char *str);
/*
* Structure of an internet header, naked of options.

View File

@ -42,4 +42,4 @@ extern int thread_spawn(thread_fn_t fn, void *arg);
extern void thread_exit(void) __noreturn;
/* main initialization */
extern int runtime_init(thread_fn_t main_fn, void *arg, unsigned int cores);
extern int runtime_init(const char *cfgpath, thread_fn_t main_fn, void *arg);

View File

@ -201,7 +201,7 @@ static struct rte_mempool *dpdk_pktmbuf_completion_pool_create(const char *name,
mbp_priv.mbuf_data_room_size = 0;
mbp_priv.mbuf_priv_size = priv_size;
mp = rte_mempool_create_empty(name, n, elt_size, cache_size,
mp = rte_mempool_create_empty(name, n, elt_size, 0,
sizeof(struct rte_pktmbuf_pool_private), socket_id, 0);
if (mp == NULL)
return NULL;

View File

@ -116,11 +116,12 @@ void dump_udp_pkt(int loglvl, uint32_t saddr, struct udp_hdr *udp_hdr,
*
* The buffer must be IP_ADDR_STR_LEN in size.
*/
void ip_addr_to_str(uint32_t addr, char *str)
char *ip_addr_to_str(uint32_t addr, char *str)
{
snprintf(str, IP_ADDR_STR_LEN, "%d.%d.%d.%d",
((addr >> 24) & 0xff),
((addr >> 16) & 0xff),
((addr >> 8) & 0xff),
(addr & 0xff));
return str;
}

179
runtime/cfg.c Normal file
View File

@ -0,0 +1,179 @@
/*
* cfg.c - configuration file support
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <base/stddef.h>
#include <base/bitmap.h>
#include <base/log.h>
#include <base/cpu.h>
#include "defs.h"
/*
* Configuration Options
*/
static int str_to_ip(const char *str, uint32_t *addr)
{
uint8_t a, b, c, d;
if(sscanf(str, "%hhu.%hhu.%hhu.%hhu", &a, &b, &c, &d) != 4) {
return -EINVAL;
}
*addr = MAKE_IP_ADDR(a, b, c, d);
return 0;
}
static int str_to_long(const char *str, long *val)
{
char *endptr;
*val = strtol(str, &endptr, 10);
if (endptr == str || (*endptr != '\0' && *endptr != '\n') ||
((*val == LONG_MIN || *val == LONG_MAX) && errno == ERANGE))
return -EINVAL;
return 0;
}
static int parse_host_ip(const char *name, const char *val)
{
uint32_t *addr;
int ret;
if (!strcmp(name, "host_addr"))
addr = &netcfg.addr;
else if (!strcmp(name, "host_netmask"))
addr = &netcfg.netmask;
else if (!strcmp(name, "host_gateway"))
addr = &netcfg.gateway;
else
return -EINVAL;
if (!val)
return -EINVAL;
ret = str_to_ip(val, addr);
if (ret)
return ret;
if (!strcmp(name, "host_netmask") &&
(!*addr || ((~*addr + 1) & ~*addr))) {
log_err("invalid netmask");
return -EINVAL;
}
if (*addr >> 24 == 127) {
log_err("IP address can't be local subnet");
return -EINVAL;
}
return 0;
}
static int parse_runtime_kthreads(const char *name, const char *val)
{
long tmp;
int ret;
ret = str_to_long(val, &tmp);
if (ret)
return ret;
if (tmp < 1 || tmp > cpu_count - 1) {
log_err("invalid number of kthreads requested, '%ld'", tmp);
log_err("must be > 0 and < %d (number of CPUs)", cpu_count);
return -EINVAL;
}
maxks = tmp;
return 0;
}
/*
* Parsing Infrastructure
*/
typedef int (*cfg_fn_t)(const char *name, const char *val);
struct cfg_handler {
const char *name;
cfg_fn_t fn;
bool required;
};
static const struct cfg_handler cfg_handlers[] = {
{ "host_addr", parse_host_ip, true },
{ "host_netmask", parse_host_ip, true },
{ "host_gateway", parse_host_ip, true },
{ "runtime_kthreads", parse_runtime_kthreads, true },
};
/**
* cfg_load - loads the configuration file
* @path: a path to the configuration file
*
* Returns 0 if successful, otherwise fail.
*/
int cfg_load(const char *path)
{
FILE *f;
char buf[BUFSIZ];
DEFINE_BITMAP(parsed, ARRAY_SIZE(cfg_handlers));
const char *name, *val;
int i, ret = 0, line = 0;
bitmap_init(parsed, ARRAY_SIZE(cfg_handlers), 0);
log_info("loading configuration from '%s'", path);
f = fopen(path, "r");
if (!f)
return -errno;
while (fgets(buf, sizeof(buf), f)) {
if (buf[0] == '#' || buf[0] == '\n') {
line++;
continue;
}
name = strtok(buf, " ");
if (!name)
break;
val = strtok(NULL, " ");
for (i = 0; i < ARRAY_SIZE(cfg_handlers); i++) {
const struct cfg_handler *h = &cfg_handlers[i];
if (!strncmp(name, h->name, BUFSIZ)) {
ret = h->fn(name, val);
if (ret) {
log_err("bad config option on line %d",
line);
goto out;
}
bitmap_set(parsed, i);
break;
}
}
line++;
}
for (i = 0; i < ARRAY_SIZE(cfg_handlers); i++) {
const struct cfg_handler *h = &cfg_handlers[i];
if (h->required && !bitmap_test(parsed, i)) {
log_err("missing required config option '%s'", h->name);
ret = -EINVAL;
goto out;
}
}
out:
fclose(f);
return ret;
}

View File

@ -274,6 +274,7 @@ static inline struct kthread *myk(void)
}
DECLARE_SPINLOCK(klock);
extern unsigned int maxks;
extern unsigned int nrks;
extern struct kthread *ks[NCPU];
@ -315,12 +316,12 @@ struct net_cfg {
uint32_t addr;
uint32_t netmask;
uint32_t gateway;
uint32_t broadcast;
uint32_t network;
struct eth_addr mac;
uint8_t pad[6];
uint8_t pad[14];
} __packed;
BUILD_ASSERT(sizeof(struct net_cfg) == CACHE_LINE_SIZE);
extern struct net_cfg netcfg;
extern thread_t *net_run(struct kthread *k, unsigned int budget);
@ -371,6 +372,9 @@ extern int usocket_init(void);
/* late initialization */
extern int arp_init_late(void);
/* configuration loading */
extern int cfg_load(const char *path);
/* runtime entry helpers */
extern void sched_start(void) __noreturn;
extern int thread_spawn_main(thread_fn_t fn, void *arg);

View File

@ -64,7 +64,7 @@ static int run_init_handlers(const char *phase,
log_debug("entering '%s' init phase", phase);
for (i = 0; i < nr; i++) {
log_debug("init -> %s", h[0].name);
log_debug("init -> %s", h[i].name);
ret = h[i].init();
if (ret) {
log_debug("failed, ret = %d", ret);
@ -106,13 +106,13 @@ static void *pthread_entry(void *data)
/**
* runtime_init - starts the runtime
* @cfgpath: the path to the configuration file
* @main_fn: the first function to run as a thread
* @arg: an argument to @main_fn
* @threads: the number of threads to use
*
* Does not return if successful, otherwise return < 0 if an error.
*/
int runtime_init(thread_fn_t main_fn, void *arg, unsigned int threads)
int runtime_init(const char *cfgpath, thread_fn_t main_fn, void *arg)
{
pthread_t tid[NCPU];
int ret, i;
@ -123,13 +123,11 @@ int runtime_init(thread_fn_t main_fn, void *arg, unsigned int threads)
return ret;
}
if (threads < 1 || threads > cpu_count - 1) {
log_err("invalid number of kthreads, requested %d, detected %d",
threads, cpu_count);
return -EINVAL;
}
ret = cfg_load(cfgpath);
if (ret)
return ret;
ret = ioqueues_init(threads);
ret = ioqueues_init(maxks);
if (ret) {
log_err("couldn't connect to iokernel, ret = %d", ret);
return ret;
@ -142,7 +140,8 @@ int runtime_init(thread_fn_t main_fn, void *arg, unsigned int threads)
/* point of no return starts here */
for (i = 1; i < threads; i++) {
log_info("spawning %d kthreads", maxks);
for (i = 1; i < maxks; i++) {
ret = pthread_create(&tid[i], NULL, pthread_entry, NULL);
BUG_ON(ret);
}

View File

@ -13,6 +13,8 @@
/* protects @ks and @nrks below */
DEFINE_SPINLOCK(klock);
/* the maximum number of kthreads */
unsigned int maxks;
/* the total number of kthreads (i.e. the size of @ks) */
unsigned int nrks;
/* an array of all the kthreads (for work-stealing) */
@ -59,7 +61,7 @@ int kthread_init_thread(void)
void kthread_attach(void)
{
spin_lock(&klock);
assert(nrks < cpu_count - 1);
assert(nrks < maxks);
ks[nrks++] = mykthread;
rcu_tlgen = rcu_gen;
spin_unlock(&klock);

View File

@ -17,7 +17,7 @@
#define ARP_TABLE_CAPACITY 1024
#define ARP_RETRIES 3
#define ARP_RETRY_TIME ONE_SECOND
#define ARP_REPROBE_TIME (5 * ONE_SECOND)
#define ARP_REPROBE_TIME (10 * ONE_SECOND)
enum {
/* the MAC address is being probed */
@ -130,8 +130,8 @@ static void arp_send(uint16_t op, struct eth_addr dhost, uint32_t daddr)
static void arp_age_entry(uint64_t now_us, struct arp_entry *e)
{
/* check if this entry has timed out */
if (now_us - e->ts < (e->state == ARP_STATE_VALID) ?
ARP_REPROBE_TIME : ARP_RETRY_TIME)
if (now_us - e->ts < ((e->state == ARP_STATE_VALID) ?
ARP_REPROBE_TIME : ARP_RETRY_TIME))
return;
switch (e->state) {
@ -162,11 +162,13 @@ static void arp_worker(void *arg)
{
struct arp_entry *e;
struct rcu_hlist_node *node;
uint64_t now_us = microtime();
uint64_t now_us;
int i;
/* wake up each second and update the ARP table */
while (true) {
now_us = microtime();
spin_lock(&arp_lock);
for (i = 0; i < ARP_TABLE_CAPACITY; i++) {
rcu_hlist_for_each(&arp_tbl[i], node, true) {

View File

@ -15,10 +15,6 @@
/* the maximum number of packets to process per scheduler invocation */
#define MAX_BUDGET 512
#define TEMP_IP_ADDR 3232235781 // 192.168.1.5
#define TEMP_NETMASK 0xffffff00 // 255.255.255.0
#define TEMP_GATEWAY 0
/* important global state */
struct net_cfg netcfg __aligned(CACHE_LINE_SIZE);
@ -390,7 +386,7 @@ int net_tx_ip(struct mbuf *m, uint8_t proto, uint32_t daddr)
m->txflags |= OLFLAG_IP_CHKSUM | OLFLAG_IPV4;
/* simple IP routing */
if ((daddr & netcfg.netmask) != netcfg.network)
if ((daddr & netcfg.netmask) != (netcfg.addr & netcfg.netmask))
daddr = netcfg.gateway;
/* need to use ARP to resolve dhost */
@ -423,6 +419,20 @@ int net_init_thread(void)
return 0;
}
static void net_dump_config(void)
{
char buf[IP_ADDR_STR_LEN];
log_info("net: using the following configuration:");
log_info(" addr:\t%s", ip_addr_to_str(netcfg.addr, buf));
log_info(" netmask:\t%s", ip_addr_to_str(netcfg.netmask, buf));
log_info(" gateway:\t%s", ip_addr_to_str(netcfg.gateway, buf));
log_info(" mac:\t%02X:%02X:%02X:%02X:%02X:%02X",
netcfg.mac.addr[0], netcfg.mac.addr[1], netcfg.mac.addr[2],
netcfg.mac.addr[3], netcfg.mac.addr[4], netcfg.mac.addr[5]);
}
/**
* net_init - initializes the network stack
*
@ -452,12 +462,7 @@ int net_init(void)
if (!net_tx_buf_tcache)
return -ENOMEM;
netcfg.addr = TEMP_IP_ADDR;
netcfg.netmask = TEMP_NETMASK;
netcfg.gateway = TEMP_GATEWAY;
netcfg.network = netcfg.addr & netcfg.netmask;
netcfg.broadcast = netcfg.network | ~netcfg.netmask;
BUILD_ASSERT(sizeof(struct net_cfg) == CACHE_LINE_SIZE);
log_info("net: started network stack");
net_dump_config();
return 0;
}

5
sample.config Normal file
View File

@ -0,0 +1,5 @@
# an example runtime config file
host_addr 192.168.1.5
host_netmask 255.255.255.0
host_gateway 192.168.1.1
runtime_kthreads 3

View File

@ -1,3 +1,4 @@
#include <stdio.h>
#include <base/stddef.h>
#include <base/log.h>
@ -43,9 +44,14 @@ int main(int argc, char *argv[])
{
int ret;
ret = runtime_init(main_handler, NULL, NCORES);
if (argc < 2) {
printf("arg must be config file\n");
return -EINVAL;
}
ret = runtime_init(argv[1], main_handler, NULL);
if (ret) {
log_err("failed to start runtime");
printf("failed to start runtime");
return ret;
}

View File

@ -2,6 +2,7 @@
* test_multiple_runtimes.c - tests initialization of multiple runtimes
*/
#include <stdio.h>
#include <unistd.h>
#include <base/log.h>
@ -19,12 +20,17 @@ int main(int argc, char *argv[])
{
int i, pid, ret;
if (argc < 2) {
printf("arg must be config file\n");
return -EINVAL;
}
for (i = 0; i < N_RUNTIMES; i++) {
pid = fork();
BUG_ON(pid == -1);
if (pid == 0) {
ret = runtime_init(main_handler, NULL, 1);
ret = runtime_init(argv[1], main_handler, NULL);
BUG_ON(ret < 0);
}

View File

@ -3,6 +3,7 @@
*/
#include <unistd.h>
#include <stdio.h>
#include <base/log.h>
#include <base/time.h>
@ -38,9 +39,14 @@ int main(int argc, char *argv[])
{
int ret;
ret = runtime_init(main_handler, NULL, 1);
if (argc < 2) {
printf("arg must be config file\n");
return -EINVAL;
}
ret = runtime_init(argv[1], main_handler, NULL);
if (ret) {
log_err("failed to start runtime");
printf("failed to start runtime\n");
return ret;
}

View File

@ -1,3 +1,4 @@
#include <stdio.h>
#include <base/stddef.h>
#include <base/log.h>
@ -6,8 +7,8 @@
#include <runtime/thread.h>
#include <runtime/sync.h>
#define N 1000000
#define NCORES 4
#define N 1000000
struct test_args {
chan_t *chan;
@ -304,9 +305,14 @@ int main(int argc, char *argv[])
{
int ret;
ret = runtime_init(main_handler, NULL, NCORES);
if (argc < 2) {
printf("arg must be config file\n");
return -EINVAL;
}
ret = runtime_init(argv[1], main_handler, NULL);
if (ret) {
log_err("failed to start runtime");
printf("failed to start runtime\n");
return ret;
}

View File

@ -1,3 +1,4 @@
#include <stdio.h>
#include <base/stddef.h>
#include <base/log.h>
@ -139,9 +140,14 @@ int main(int argc, char *argv[])
{
int ret;
ret = runtime_init(main_handler, NULL, NCORES);
if (argc < 2) {
printf("arg must be config file\n");
return -EINVAL;
}
ret = runtime_init(argv[1], main_handler, NULL);
if (ret) {
log_err("failed to start runtime");
printf("failed to start runtime\n");
return ret;
}

View File

@ -3,6 +3,7 @@
*/
#include <stdlib.h>
#include <stdio.h>
#include <base/stddef.h>
#include <base/log.h>
@ -90,9 +91,14 @@ int main(int argc, char *argv[])
{
int ret;
ret = runtime_init(main_handler, NULL, NCORES);
if (argc < 2) {
printf("arg must be config file\n");
return -EINVAL;
}
ret = runtime_init(argv[1], main_handler, NULL);
if (ret) {
log_err("failed to start runtime");
printf("failed to start runtime\n");
return ret;
}

View File

@ -2,6 +2,8 @@
* test_runtime_thread.c - tests basic thread spawning
*/
#include <stdio.h>
#include <base/stddef.h>
#include <base/log.h>
#include <base/time.h>
@ -13,8 +15,8 @@
static void leaf_handler(void *arg)
{
delay_us(1);
waitgroup_t *wg_parent = (waitgroup_t *)arg;
delay_us(1);
waitgroup_done(wg_parent);
}
@ -58,16 +60,21 @@ static void main_handler(void *arg)
threads_per_second = (double)(NCORES * N) /
((microtime() - start_us) * 0.000001);
log_info("spawned %f threads / second, efficiency %f",
threads_per_second, threads_per_second / (NCORES * 1000000));
threads_per_second, threads_per_second / 1000000);
}
int main(int argc, char *argv[])
{
int ret;
ret = runtime_init(main_handler, NULL, NCORES);
if (argc < 2) {
printf("arg must be config file\n");
return -EINVAL;
}
ret = runtime_init(argv[1], main_handler, NULL);
if (ret) {
log_err("failed to start runtime");
printf("failed to start runtime\n");
return ret;
}

View File

@ -2,6 +2,8 @@
* test_runtime_thread.c - tests basic thread spawning
*/
#include <stdio.h>
#include <base/stddef.h>
#include <base/log.h>
#include <base/time.h>
@ -11,7 +13,6 @@
#define WORKERS 1000
#define N 100000
#define NCORES 4
static void work_handler(void *arg)
{
@ -44,17 +45,21 @@ static void main_handler(void *arg)
waitgroup_wait(&wg);
timeouts_per_second = (double)(WORKERS * N) /
((microtime() - start_us) * 0.000001);
log_info("handled %f timeouts / second / core",
timeouts_per_second / NCORES);
log_info("handled %f timeouts / second", timeouts_per_second);
}
int main(int argc, char *argv[])
{
int ret;
ret = runtime_init(main_handler, NULL, NCORES);
if (argc < 2) {
printf("arg must be config file\n");
return -EINVAL;
}
ret = runtime_init(argv[1], main_handler, NULL);
if (ret) {
log_err("failed to start runtime");
printf("failed to start runtime\n");
return ret;
}

View File

@ -1,8 +1,9 @@
/*
* test_runtime_thread.c - tests basic thread spawning
* test_udp_echo.c - echoes UDP packets
*/
#include <string.h>
#include <stdio.h>
#include <base/stddef.h>
#include <base/log.h>
@ -54,9 +55,14 @@ int main(int argc, char *argv[])
{
int ret;
ret = runtime_init(main_handler, NULL, NCORES);
if (argc < 2) {
printf("arg must be config file\n");
return -EINVAL;
}
ret = runtime_init(argv[1], main_handler, NULL);
if (ret) {
log_err("failed to start runtime");
printf("failed to start runtime\n");
return ret;
}