Skip to content

Commit

Permalink
lkl: Support json configuration and multiple interfaces
Browse files Browse the repository at this point in the history
This change allows user to configure lkl with json file.
This change still supports configuration using environment variable.
Also allows lkl to have multiple interfaces.

Reviewed-by: Hajime Tazaki <thehajime@gmail.com>
Signed-off-by: Motomu Utsumi <motomuman@gmail.com>
Motomu Utsumi committed Oct 24, 2017
1 parent bfb315c commit 842d02f
Showing 7 changed files with 1,388 additions and 368 deletions.
336 changes: 257 additions & 79 deletions Documentation/lkl.txt
Original file line number Diff line number Diff line change
@@ -134,129 +134,309 @@ LKL hijack library

LKL hijack library (liblkl-hijack.so) is used to replace system calls used by an
application on the fly so that the application can use LKL instead of the kernel
of host operating system. LD_PRELOAD is used to dynamically override system calls
with this library when you execute a program.
of host operating system. LD_PRELOAD is used to dynamically override system
calls with this library when you execute a program.

You can usually use this library via a wrapper script.

$ cd tools/lkl
$ ./bin/lkl-hijack.sh ip address show

There are environmental variables to configure the behavior of LKL. The followings
are the list of those variable for your environment.
In order to configure the behavior of LKL, a json file can be used. You can
specify json file with environmental variables (LKL_HIJACK_CONFIG_FILE). If
there is nothing specified, LKL tries to find with the name 'lkl-hijack.json'
for the configuration file. You can also use the old-style configuration with
environmental variables (e.g., LKL_HIJACK_NET_IFTYPE) but those are overridden
if a json file is specified.

* LKL_HIJACK_NET_IFTYPE

The interface type in host operating system to connect to LKL.
The following example specifies a tap interface.
```
$ LKL_HIJACK_NET_IFTYPE=tap LKL_HIJACK_NET_IFPARAMS=tap0 lkl-hijack.sh ip address show
$ cat conf.json
{
"gateway":"192.168.0.1",
"gateway6":"2001:db8:0:f101::1",
"debug":"1",
"singlecpu":"1",
"sysctl":"net.ipv4.tcp_wmem=4096 87380 2147483647",
"boot_cmdline":"ip=dhcp",
"interfaces":[
{
"mac":"12:34:56:78:9a:bc",
"type":"tap",
"param":"tap7",
"ip":"192.168.0.2",
"masklen":"24",
"ifgateway":"192.168.0.1",
"ipv6":"2001:db8:0:f101::2",
"masklen6":"64",
"ifgateway6":"2001:db8:0:f101::1",
"offload":"0xc803"
},
{
"mac":"12:34:56:78:9a:bd",
"type":"tap",
"param":"tap77",
"ip":"192.168.1.2",
"masklen":"24",
"ifgateway":"192.168.1.1",
"ipv6":"2001:db8:0:f102::2",
"masklen6":"64",
"ifgateway6":"2001:db8:0:f102::1",
"offload":"0xc803"
}
]
}
$ LKL_HIJACK_CONFIG_FILE="conf.json" lkl-hijack.sh ip addr s
```
* LKL_HIJACK_NET_IFPARAMS

Additional configuration parameters for the interface specified by LKL_HIJACK_NET_IFTYPE.
The parameters depend on the interface type (LKL_HIJACK_NET_IFTYPE).
```
$ LKL_HIJACK_NET_IFTYPE=tap LKL_HIJACK_NET_IFPARAMS=tap0 lkl-hijack.sh ip address show
```
* LKL_HIJACK_NET_IP

the IP address of the interface specified by LKL_HIJACK_NET_TAP.
```
$ LKL_HIJACK_NET_IP=198.51.100.5 lkl-hijack.sh ip address show
```
The following are the list of keys to describe a JSON file.

If you want to use DHCP for the IP address assignment, use
LKL_HIJACK_BOOT_CMDLINE with "ip=dhcp" option.
```
$ LKL_HIJACK_BOOT_CMDLINE="ip=dhcp" LKL_HIJACK_NET_IFTYPE=tap \
LKL_HIJACK_NET_IFPARAMS=tap0 lkl-hijack.sh ip address
```
* IPv4 gateway address

* LKL_HIJACK_NET_NETMASK_LEN
key: "gateway"
value type: string

the network mask length of the interface specified by LKL_HIJACK_NET_TAP.
the gateway IPv4 address of LKL network stack.
```
$ LKL_HIJACK_NET_IP=198.51.100.5 LKL_HIJACK_NET_NETMASK_LEN=24 lkl-hijack.sh ip address show
"gateway":"192.168.0.1"
```
* LKL_HIJACK_NET_MAC

the MAC address of the interface specified by LKL_HIJACK_NET_TAP.
```
$ LKL_HIJACK_NET_MAC="aa:bb:cc:dd:ee:ff" lkl-hijack.sh ip address show
```
* LKL_HIJACK_NET_GATEWAY
* IPv6 gateway address

the gateway IP address of LKL network stack.
```
$ LKL_HIJACK_NET_GATEWAY=198.51.100.5 lkl-hijack.sh ip address show
```
* LKL_HIJACK_NET_MTU
key: "gateway6"
value type: string

the MTU size of the interface specified by LKL_HIJACK_NET_TAP.
the gateway IPv6 address of LKL network stack.
```
$ LKL_HIJACK_NET_MTU=1280 lkl-hijack.sh ip address show
"gateway6":"2001:db8:0:f101::1"
```
* LKL_HIJACK_NET_NEIGHBOR

Add a list of permanent neighbor entries in the form of "ip|mac;ip|mac;...". ipv6 are supported
```
$ LKL_HIJACK_NET_NEIGHBOR="192.168.13.100|12:34:56:78:9a:bc;2001:db8:0:f101::3|12:34:56:78:9a:be"
lkl-hijack.sh ip neighbor show
```
* LKL_HIJACK_NET_QDISC
* Debug

Add a qdisc entry in the form of "root|type;root|type;...".
```
$ LKL_HIJACK_NET_QDISC="root|fq" lkl-hijack.sh tc qdisc
```
* LKL_HIJACK_DEBUG
key: "debug"
value type: string

Setting it causes some debug information (both from the kernel and the
LKL library) to be enabled.
It is also used as a bit mask to turn on specific debugging facilities.
E.g., setting it to 0x100 ("export LKL_HIJACK_DEBUG=0x100") will cause
the LKL kernel to pause after the hijack'ed app exits. This allows one
to debug or collect info from the LKL kernel before it quits.
E.g., setting it to "0x100" will cause the LKL kernel to pause after
the hijack'ed app exits. This allows one to debug or collect info from
the LKL kernel before it quits.
```
$ LKL_HIJACK_DEBUG=1 lkl-hijack.sh ip address show
"debug":"1"
```
* LKL_HIJACK_SINGLE_CPU

Pin LKL kernel threads on to a single host cpu. LKL_HIJACK_SINGLE_CPU=1 pins
only LKL kernel threads while LKL_HIJACK_SINGLE_CPU=2 also pins polling
* Single CPU pinning

key: "singlecpu"
value type: string

Pin LKL kernel threads on to a single host cpu. value "1" pins
only LKL kernel threads while value "2" also pins polling
threads.
```
$ LKL_HIJACK_SINGLE_CPU=1 lkl-hijack.sh ip address show
"singlecpu":"1"
```
* LKL_HIJACK_OFFLOAD

Work as a bit mask to enable selective device offload features. E.g.,
to enable "mergeable RX buffer" (LKL_VIRTIO_NET_F_MRG_RXBUF) +
"guest csum" (LKL_VIRTIO_NET_F_GUEST_CSUM) device features, simply set
it to 0x8002.
* SYSCTL

See virtio_net.h for a list of offload features and their bit masks.
```
$ LKL_HIJACK_OFFLOAD=0x8002 lkl-hijack.sh ./netserver -D -f
```
* LKL_HIJACK_SYSCTL
key: "sysctl"
value type: string

Configure sysctl values of the booted kernel via the hijack library. Multiple
entries can be specified.
```
$ LKL_HIJACK_SYSCTL="net.ipv4.tcp_wmem=4096 87380 2147483647"
./bin/lkl-hijack.sh ip address show
"sysctl":"net.ipv4.tcp_wmem=4096 87380 2147483647"
```
* LKL_HIJACK_BOOT_CMDLINE

* Boot command line

key: "boot_cmdline"
value type: string

Specify the command line to the kernel boot so that change the configuration
on a kernel instance. For instance, you can change the memory size with
below.
```
$ LKL_HIJACK_BOOT_CMDLINE="mem=1G" LKL_HIJACK_DEBUG=1 lkl-hijack.sh ip add
"boot_cmdline": "mem=1G"
```

* Mount

key: "mount"
value type: string

```
"mount": "proc,sysfs"
```

* Network Interface Configuration

key: "interfaces"
value type: array of objects

This key takes a set of sub-keys to configure a single interface. Each key is defined as follows.
```
"interfaces":[{....},{....}]
```


* Interface type

key: "type"
value type: string

The interface type in host operating system to connect to LKL.
The following example specifies a tap interface.
```
"type":"tap"
```

* Interface parameter

key: "param"
value type: string

Additional configuration parameters for the interface specified by Interface type (type).
The parameters depend on the interface type.
```
"type":"tap",
"param":"tap0"
```

* Interface MTU size

key: "mtu"
value type: string

the MTU size of the interface.
```
"mtu":"1280"
```

* Interface IPv4 address

key: "ip"
value type: string

the IPv4 address of the interface.
If you want to use DHCP for the IP address assignment,
use "boot_cmdline" with "ip=dhcp" option.
```
"ip":"192.168.0.2"
```
```
"boot_cmdline":"ip=dhcp"
```

* Interface IPv4 netmask length

key: "masklen"
value type: string

the network mask length of the interface.
```
"ip":"192.168.0.2",
"masklen":"24"
```

* Interface IPv4 gateway on routing policy table

key: "ifgateway"
value type: string

If you specify this parameter, LKL adds routing policy table.
And then LKL creates link local and gateway route on this table.
Table SELECTOR is "from" and PREFIX is address you assigned to this interface.
Table id is 2 * (interface index).
This parameter could be used to configure LKL for mptcp, for example.

```
"ip":"192.168.0.2",
"masklen":"24",
"ifgateway":"192.168.0.1"
```

* Interface IPv6 address

key: "ipv6"
value type: string

the IPv6 address of the interface.
```
"ipv6":"2001:db8:0:f101::2"
```

* Interface IPv6 netmask length

key: "masklen6"
value type: string

the network mask length of the interface.
```
"ipv6":"2001:db8:0:f101::2",
"masklen":"64"
```

* Interface IPv6 gateway on routing policy table

key: "ifgateway6"
value type: string

If you specify this parameter, LKL adds routing policy table.
And then LKL creates link local and gateway route on this table.
Table SELECTOR is "from" and PREFIX is address you assigned to this interface.
Table id is 2 * (interface index) + 1.
This parameter could be used to configure LKL for mptcp, for example.
```
"ipv6":"2001:db8:0:f101::2",
"masklen":"64"
"ifgateway6":"2001:db8:0:f101::1",
```

* Interface MAC address

key: "mac"
value type: string

the MAC address of the interface.
```
"mac":"12:34:56:78:9a:bc"
```

* Interfac neighbor entries

key: "neigh"
value type: string

Add a list of permanent neighbor entries in the form of "ip|mac;ip|mac;...". ipv6 are supported
```
"neigh":"192.168.0.1|12:34:56:78:9a:bc;2001:db8:0:f101::1|12:34:56:78:9a:be"
```

* Interface qdisc entries

key: "qdisc"
value type: string

Add a qdisc entry in the form of "root|type;root|type;...".
```
"qdisc":"root|fq"
```

* Interface offload

key: "offload"
value type: string

Work as a bit mask to enable selective device offload features. E.g.,
to enable "mergeable RX buffer" (LKL_VIRTIO_NET_F_MRG_RXBUF) +
"guest csum" (LKL_VIRTIO_NET_F_GUEST_CSUM) device features, simply set
it to 0x8002.
See virtio_net.h for a list of offload features and their bit masks.
```
"offload":"0x8002"
```

FAQ
===

@@ -276,5 +456,3 @@ A: LibOS re-implements high-level kernel APIs for timers, softirqs, scheduling,
sysctl, SLAB/SLUB, etc. LKL behaves like any arch port, implementing the arch
level operations requested by the Linux kernel. LKL also offers a host interface
so that support for multiple hosts can be implemented.


2 changes: 2 additions & 0 deletions tools/lkl/lib/Build
Original file line number Diff line number Diff line change
@@ -21,3 +21,5 @@ lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net_macvtap.o
lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net_dpdk.o
lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net_vde.o
lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net_pipe.o
lkl-y += ../../perf/pmu-events/jsmn.o
lkl-y += config.o
390 changes: 390 additions & 0 deletions tools/lkl/lib/config.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,390 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <lkl_host.h>

#include "config.h"
#include "../../perf/pmu-events/jsmn.h"

static int jsoneq(const char *json, jsmntok_t *tok, const char *s)
{
if (tok->type == JSMN_STRING &&
(int) strlen(s) == tok->end - tok->start &&
strncmp(json + tok->start, s, tok->end - tok->start) == 0) {
return 0;
}
return -1;
}

static int cfgcpy(char **to, char *from)
{
if (!from)
return 0;
if (*to)
free(*to);
*to = (char *)malloc((strlen(from) + 1) * sizeof(char));
if (*to == NULL) {
lkl_printf("malloc failed\n");
return -1;
}
strcpy(*to, from);
return 0;
}

static int cfgncpy(char **to, char *from, int len)
{
if (!from)
return 0;
if (*to)
free(*to);
*to = (char *)malloc((len + 1) * sizeof(char));
if (*to == NULL) {
lkl_printf("malloc failed\n");
return -1;
}
strncpy(*to, from, len + 1);
(*to)[len] = '\0';
return 0;
}

static int parse_ifarr(struct lkl_config *cfg,
jsmntok_t *toks, char *jstr, int startpos)
{
int ifidx, pos, posend, ret;
char **cfgptr;

if (!cfg || !toks || !jstr)
return -1;
pos = startpos;
pos++;
if (toks[pos].type != JSMN_ARRAY) {
lkl_printf("unexpected json type, json array expected\n");
return -1;
}
cfg->ifnum = toks[pos].size;
if (cfg->ifnum >= LKL_IF_MAX) {
lkl_printf("exceeded max number of interface (%d)\n",
LKL_IF_MAX);
return -1;
}
pos++;
for (ifidx = 0; ifidx < cfg->ifnum; ifidx++) {
if (toks[pos].type != JSMN_OBJECT) {
lkl_printf("object json type expected\n");
return -1;
}
posend = pos + toks[pos].size;
pos++;
for (; pos < posend; pos += 2) {
if (toks[pos].type != JSMN_STRING) {
lkl_printf("object json type expected\n");
return -1;
}
if (jsoneq(jstr, &toks[pos], "type") == 0) {
cfgptr = &cfg->iftype[ifidx];
} else if (jsoneq(jstr, &toks[pos], "param") == 0) {
cfgptr = &cfg->ifparams[ifidx];
} else if (jsoneq(jstr, &toks[pos], "mtu") == 0) {
cfgptr = &cfg->ifmtu_str[ifidx];
} else if (jsoneq(jstr, &toks[pos], "ip") == 0) {
cfgptr = &cfg->ifip[ifidx];
} else if (jsoneq(jstr, &toks[pos], "ipv6") == 0) {
cfgptr = &cfg->ifipv6[ifidx];
} else if (jsoneq(jstr, &toks[pos], "ifgateway") == 0) {
cfgptr = &cfg->ifgateway[ifidx];
} else if (jsoneq(jstr, &toks[pos],
"ifgateway6") == 0) {
cfgptr = &cfg->ifgateway6[ifidx];
} else if (jsoneq(jstr, &toks[pos], "mac") == 0) {
cfgptr = &cfg->ifmac_str[ifidx];
} else if (jsoneq(jstr, &toks[pos], "masklen") == 0) {
cfgptr = &cfg->ifnetmask_len[ifidx];
} else if (jsoneq(jstr, &toks[pos], "masklen6") == 0) {
cfgptr = &cfg->ifnetmask6_len[ifidx];
} else if (jsoneq(jstr, &toks[pos], "neigh") == 0) {
cfgptr = &cfg->ifneigh_entries[ifidx];
} else if (jsoneq(jstr, &toks[pos], "qdisc") == 0) {
cfgptr = &cfg->ifqdisc_entries[ifidx];
} else if (jsoneq(jstr, &toks[pos], "offload") == 0) {
cfgptr = &cfg->ifoffload_str[ifidx];
} else {
lkl_printf("unexpected key: %.*s\n",
toks[pos].end-toks[pos].start,
jstr + toks[pos].start);
return -1;
}
ret = cfgncpy(cfgptr, jstr + toks[pos+1].start,
toks[pos+1].end-toks[pos+1].start);
if (ret < 0)
return ret;
}
}
return pos - startpos;
}

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

int load_config_json(struct lkl_config *cfg, char *jstr)
{
int pos, ret;
char **cfgptr;
jsmn_parser jp;
jsmntok_t toks[LKL_CONFIG_JSON_TOKEN_MAX];

if (!cfg || !jstr)
return -1;
jsmn_init(&jp);
ret = jsmn_parse(&jp, jstr, strlen(jstr), toks, ARRAY_SIZE(toks));
if (ret != JSMN_SUCCESS) {
lkl_printf("failed to parse json\n");
return -1;
}
if (toks[0].type != JSMN_OBJECT) {
lkl_printf("object json type expected\n");
return -1;
}
for (pos = 1; pos < jp.toknext; pos++) {
if (toks[pos].type != JSMN_STRING) {
lkl_printf("string json type expected\n");
return -1;
}
if (jsoneq(jstr, &toks[pos], "interfaces") == 0) {
ret = parse_ifarr(cfg, toks, jstr, pos);
if (ret < 0)
return ret;
pos += ret;
pos--;
continue;
}
if (jsoneq(jstr, &toks[pos], "gateway") == 0) {
cfgptr = &cfg->gateway;
} else if (jsoneq(jstr, &toks[pos], "gateway6") == 0) {
cfgptr = &cfg->gateway6;
} else if (jsoneq(jstr, &toks[pos], "debug") == 0) {
cfgptr = &cfg->debug;
} else if (jsoneq(jstr, &toks[pos], "mount") == 0) {
cfgptr = &cfg->mount;
} else if (jsoneq(jstr, &toks[pos], "singlecpu") == 0) {
cfgptr = &cfg->single_cpu;
} else if (jsoneq(jstr, &toks[pos], "sysctl") == 0) {
cfgptr = &cfg->sysctls;
} else if (jsoneq(jstr, &toks[pos], "boot_cmdline") == 0) {
cfgptr = &cfg->boot_cmdline;
} else if (jsoneq(jstr, &toks[pos], "dump") == 0) {
cfgptr = &cfg->dump;
} else {
lkl_printf("unexpected key in json %.*s\n",
toks[pos].end-toks[pos].start,
jstr + toks[pos].start);
return -1;
}
pos++;
ret = cfgncpy(cfgptr, jstr + toks[pos].start,
toks[pos].end-toks[pos].start);
if (ret < 0)
return ret;
}
return 0;
}

void show_config(struct lkl_config *cfg)
{
int i;

if (!cfg)
return;
lkl_printf("gateway: %s\n", cfg->gateway);
lkl_printf("gateway6: %s\n", cfg->gateway6);
lkl_printf("debug: %s\n", cfg->debug);
lkl_printf("mount: %s\n", cfg->mount);
lkl_printf("singlecpu: %s\n", cfg->single_cpu);
lkl_printf("sysctl: %s\n", cfg->sysctls);
lkl_printf("cmdlien: %s\n", cfg->boot_cmdline);
lkl_printf("dump: %s\n", cfg->dump);
for (i = 0; i < cfg->ifnum; i++) {
lkl_printf("ifmac[%d] = %s\n", i, cfg->ifmac_str[i]);
lkl_printf("ifmtu[%d] = %s\n", i, cfg->ifmtu_str[i]);
lkl_printf("iftype[%d] = %s\n", i, cfg->iftype[i]);
lkl_printf("ifparam[%d] = %s\n", i, cfg->ifparams[i]);
lkl_printf("ifip[%d] = %s\n", i, cfg->ifip[i]);
lkl_printf("ifmasklen[%d] = %s\n", i, cfg->ifnetmask_len[i]);
lkl_printf("ifgateway[%d] = %s\n", i, cfg->ifgateway[i]);
lkl_printf("ifip6[%d] = %s\n", i, cfg->ifipv6[i]);
lkl_printf("ifmasklen6[%d] = %s\n", i, cfg->ifnetmask6_len[i]);
lkl_printf("ifgateway6[%d] = %s\n", i, cfg->ifgateway6[i]);
lkl_printf("ifoffload[%d] = %s\n", i, cfg->ifoffload_str[i]);
lkl_printf("ifneigh[%d] = %s\n", i, cfg->ifneigh_entries[i]);
lkl_printf("ifqdisk[%d] = %s\n", i, cfg->ifqdisc_entries[i]);
}
}

int load_config_env(struct lkl_config *cfg)
{
int ret;
char *envtap = getenv("LKL_HIJACK_NET_TAP");
char *enviftype = getenv("LKL_HIJACK_NET_IFTYPE");
char *envifparams = getenv("LKL_HIJACK_NET_IFPARAMS");
char *envmtu_str = getenv("LKL_HIJACK_NET_MTU");
char *envip = getenv("LKL_HIJACK_NET_IP");
char *envipv6 = getenv("LKL_HIJACK_NET_IPV6");
char *envifgateway = getenv("LKL_HIJACK_NET_IFGATEWAY");
char *envifgateway6 = getenv("LKL_HIJACK_NET_IFGATEWAY6");
char *envmac_str = getenv("LKL_HIJACK_NET_MAC");
char *envnetmask_len = getenv("LKL_HIJACK_NET_NETMASK_LEN");
char *envnetmask6_len = getenv("LKL_HIJACK_NET_NETMASK6_LEN");
char *envgateway = getenv("LKL_HIJACK_NET_GATEWAY");
char *envgateway6 = getenv("LKL_HIJACK_NET_GATEWAY6");
char *envdebug = getenv("LKL_HIJACK_DEBUG");
char *envmount = getenv("LKL_HIJACK_MOUNT");
char *envneigh_entries = getenv("LKL_HIJACK_NET_NEIGHBOR");
char *envqdisc_entries = getenv("LKL_HIJACK_NET_QDISC");
char *envsingle_cpu = getenv("LKL_HIJACK_SINGLE_CPU");
char *envoffload_str = getenv("LKL_HIJACK_OFFLOAD");
char *envsysctls = getenv("LKL_HIJACK_SYSCTL");
char *envboot_cmdline = getenv("LKL_HIJACK_BOOT_CMDLINE") ? : "";
char *envdump = getenv("LKL_HIJACK_DUMP");

if (!cfg)
return -1;
if (envtap || enviftype)
cfg->ifnum = 1;
ret = cfgcpy(&cfg->iftap[0], envtap);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->iftype[0], enviftype);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->ifparams[0], envifparams);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->ifmtu_str[0], envmtu_str);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->ifip[0], envip);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->ifipv6[0], envipv6);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->ifgateway[0], envifgateway);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->ifgateway6[0], envifgateway6);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->ifmac_str[0], envmac_str);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->ifnetmask_len[0], envnetmask_len);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->ifnetmask6_len[0], envnetmask6_len);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->ifoffload_str[0], envoffload_str);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->ifneigh_entries[0], envneigh_entries);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->ifqdisc_entries[0], envqdisc_entries);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->gateway, envgateway);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->gateway6, envgateway6);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->debug, envdebug);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->mount, envmount);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->single_cpu, envsingle_cpu);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->sysctls, envsysctls);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->boot_cmdline, envboot_cmdline);
if (ret < 0)
return ret;
ret = cfgcpy(&cfg->dump, envdump);
if (ret < 0)
return ret;
return 0;
}

int init_config(struct lkl_config *cfg)
{
int i;

if (!cfg)
return -1;
for (i = 0; i < LKL_IF_MAX; i++) {
cfg->iftap[i] = NULL;
cfg->iftype[i] = NULL;
cfg->ifparams[i] = NULL;
cfg->ifmtu_str[i] = NULL;
cfg->ifip[i] = NULL;
cfg->ifipv6[i] = NULL;
cfg->ifgateway[i] = NULL;
cfg->ifgateway6[i] = NULL;
cfg->ifmac_str[i] = NULL;
cfg->ifnetmask_len[i] = NULL;
cfg->ifnetmask6_len[i] = NULL;
cfg->ifoffload_str[i] = NULL;
cfg->ifneigh_entries[i] = NULL;
cfg->ifqdisc_entries[i] = NULL;
}
cfg->gateway = NULL;
cfg->gateway6 = NULL;
cfg->debug = NULL;
cfg->mount = NULL;
cfg->single_cpu = NULL;
cfg->sysctls = NULL;
cfg->boot_cmdline = NULL;
cfg->dump = NULL;
return 0;
}

static void free_cfgparam(char *cfgparam)
{
if (cfgparam)
free(cfgparam);
}

int clean_config(struct lkl_config *cfg)
{
int i;

if (!cfg)
return -1;
for (i = 0; i < LKL_IF_MAX; i++) {
free_cfgparam(cfg->iftap[i]);
free_cfgparam(cfg->iftype[i]);
free_cfgparam(cfg->ifparams[i]);
free_cfgparam(cfg->ifmtu_str[i]);
free_cfgparam(cfg->ifip[i]);
free_cfgparam(cfg->ifipv6[i]);
free_cfgparam(cfg->ifgateway[i]);
free_cfgparam(cfg->ifgateway6[i]);
free_cfgparam(cfg->ifmac_str[i]);
free_cfgparam(cfg->ifnetmask_len[i]);
free_cfgparam(cfg->ifnetmask6_len[i]);
free_cfgparam(cfg->ifoffload_str[i]);
free_cfgparam(cfg->ifneigh_entries[i]);
free_cfgparam(cfg->ifqdisc_entries[i]);
}
free_cfgparam(cfg->gateway);
free_cfgparam(cfg->gateway6);
free_cfgparam(cfg->debug);
free_cfgparam(cfg->mount);
free_cfgparam(cfg->single_cpu);
free_cfgparam(cfg->sysctls);
free_cfgparam(cfg->boot_cmdline);
free_cfgparam(cfg->dump);
return 0;
}
53 changes: 53 additions & 0 deletions tools/lkl/lib/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#ifndef _LKL_LIB_CONFIG_H
#define _LKL_LIB_CONFIG_H

#define LKL_CONFIG_JSON_TOKEN_MAX 300
/* TODO dynamically allocate interface info arr */
#define LKL_IF_MAX 16

struct lkl_config {
int ifnum;
/* OBSOLETE: should use IFTYPE and IFPARAMS */
char *iftap[LKL_IF_MAX];
char *iftype[LKL_IF_MAX];
char *ifparams[LKL_IF_MAX];
char *ifmtu_str[LKL_IF_MAX];
char *ifip[LKL_IF_MAX];
char *ifipv6[LKL_IF_MAX];
char *ifgateway[LKL_IF_MAX];
char *ifgateway6[LKL_IF_MAX];
char *ifmac_str[LKL_IF_MAX];
char *ifnetmask_len[LKL_IF_MAX];
char *ifnetmask6_len[LKL_IF_MAX];
char *ifoffload_str[LKL_IF_MAX];
char *ifneigh_entries[LKL_IF_MAX];
char *ifqdisc_entries[LKL_IF_MAX];

char *gateway;
char *gateway6;
char *debug;
char *mount;
/* single_cpu mode:
* 0: Don't pin to single CPU (default).
* 1: Pin only LKL kernel threads to single CPU.
* 2: Pin all LKL threads to single CPU including all LKL kernel threads
* and device polling threads. Avoid this mode if having busy polling
* threads.
*
* mode 2 can achieve better TCP_RR but worse TCP_STREAM than mode 1.
* You should choose the best for your application and virtio device
* type.
*/
char *single_cpu;
char *sysctls;
char *boot_cmdline;
char *dump;
};

int init_config(struct lkl_config *cfg);
int load_config_json(struct lkl_config *cfg, char *jstr);
int load_config_env(struct lkl_config *cfg);
int clean_config(struct lkl_config *cfg);
void show_config(struct lkl_config *cfg);

#endif /* _LKL_LIB_CONFIG_H */
475 changes: 275 additions & 200 deletions tools/lkl/lib/hijack/init.c

Large diffs are not rendered by default.

472 changes: 391 additions & 81 deletions tools/lkl/tests/hijack-test.sh

Large diffs are not rendered by default.

28 changes: 20 additions & 8 deletions tools/lkl/tests/run_netperf.sh
Original file line number Diff line number Diff line change
@@ -61,24 +61,36 @@ clean() {
}

clean_with_tap() {
rm -rf ${work_dir}
sudo ip link set dev $LKL_HIJACK_NET_IFPARAMS down &> /dev/null || true
sudo ip tuntap del dev $LKL_HIJACK_NET_IFPARAMS mode tap &> /dev/null || true
clean
}

trap clean EXIT

# LKL_HIJACK_NET_IFTYPE is not set, which means it's not called from
# LKL_HIJACK_CONFIG_FILE is not set, which means it's not called from
# hijack-test.sh. Needs to set up things first.
if [ -z ${LKL_HIJACK_NET_IFTYPE+x} ]
if [ -z ${LKL_HIJACK_CONFIG_FILE+x} ]
then
# Setting up environmental vars and TAP
export LKL_HIJACK_NET_IFTYPE=tap
export LKL_HIJACK_NET_IFPARAMS=lkl_ptt0
export LKL_HIJACK_NET_IP=192.168.13.2
export LKL_HIJACK_NET_NETMASK_LEN=24
export LKL_HIJACK_NET_IPV6=fc03::2
export LKL_HIJACK_NET_NETMASK6_LEN=64
work_dir=$(mktemp -d)
cfgjson=${work_dir}/hijack-test.conf
echo \
"{" \
"\"gateway\":\"192.168.13.1\"," \
"\"gateway6\":\"fc03::1\"," \
"\"interfaces\":[" \
"{" \
"\"type\":\"tap\"" \
"\"param\":\"lkl_ptt0\"" \
"\"ip\":\"192.168.13.2\"" \
"\"masklen\":\"24\"" \
"\"ipv6\":\"fc03::2\"" \
"\"masklen6\":\"64\"" \
"}" \
"]" \
"}" > ${cfgjson}

sudo ip tuntap del dev $LKL_HIJACK_NET_IFPARAMS mode tap || true
sudo ip tuntap add dev $LKL_HIJACK_NET_IFPARAMS mode tap user $USER

0 comments on commit 842d02f

Please sign in to comment.