- add netmap (FreeBSD header files need to be updated with this) - move prototype perl scripts to prototype/ folder - create basic structure for sipcap app (no code yet)
1084 lines
20 KiB
C
1084 lines
20 KiB
C
#define TEST_NETMAP
|
|
|
|
#include <inttypes.h>
|
|
#include <sys/param.h> /* ULONG_MAX */
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <sys/poll.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/mman.h> /* PROT_* */
|
|
#include <fcntl.h> /* O_RDWR */
|
|
#include <pthread.h>
|
|
#include <signal.h>
|
|
|
|
|
|
#define MAX_VARS 100
|
|
|
|
char *variables[MAX_VARS];
|
|
int curr_var;
|
|
|
|
#define VAR_FAILED ((void*)1)
|
|
|
|
char *firstarg(char *buf)
|
|
{
|
|
int v;
|
|
char *arg = strtok(buf, " \t\n");
|
|
char *ret;
|
|
if (!arg)
|
|
return NULL;
|
|
if (arg[0] != '$' && arg[0] != '?')
|
|
return arg;
|
|
v = atoi(arg+1);
|
|
if (v < 0 || v >= MAX_VARS)
|
|
return "";
|
|
ret = variables[v];
|
|
if (ret == NULL)
|
|
return "NULL";
|
|
if (ret == VAR_FAILED) {
|
|
printf("reading failed var, exit\n");
|
|
exit(1);
|
|
}
|
|
if (arg[0] == '?')
|
|
return ret;
|
|
ret = rindex(ret, '=') + 1;
|
|
return ret;
|
|
}
|
|
|
|
char *nextarg()
|
|
{
|
|
return firstarg(NULL);
|
|
}
|
|
|
|
char *restofline()
|
|
{
|
|
return strtok(NULL, "\n");
|
|
}
|
|
|
|
void resetvar(int v, char *b)
|
|
{
|
|
if (variables[v] != VAR_FAILED)
|
|
free(variables[v]);
|
|
variables[v] = b;
|
|
}
|
|
|
|
#define outecho(format, args...) \
|
|
do {\
|
|
printf("%u:%lu: " format "\n", getpid(), (unsigned long) pthread_self(), ##args);\
|
|
fflush(stdout);\
|
|
} while (0)
|
|
|
|
#define output(format, args...) \
|
|
do {\
|
|
resetvar(curr_var, (char*)malloc(1024));\
|
|
snprintf(variables[curr_var], 1024, format, ##args);\
|
|
outecho(format, ##args);\
|
|
} while (0)
|
|
|
|
#define output_err(ret, format, args...)\
|
|
do {\
|
|
if (ret < 0) {\
|
|
resetvar(curr_var, VAR_FAILED);\
|
|
outecho(format, ##args);\
|
|
outecho("error: %s", strerror(errno));\
|
|
} else {\
|
|
output(format, ##args);\
|
|
}\
|
|
} while (0)
|
|
|
|
struct chan {
|
|
FILE *out;
|
|
pid_t pid;
|
|
pthread_t tid;
|
|
};
|
|
|
|
int chan_search_free(struct chan* c[], int max)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < max && c[i]; i++)
|
|
;
|
|
|
|
return i;
|
|
}
|
|
|
|
void chan_clear_all(struct chan *c[], int max)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < max; i++) {
|
|
if (c[i]) {
|
|
fclose(c[i]->out);
|
|
free(c[i]);
|
|
c[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
int last_fd = -1;
|
|
size_t last_memsize = 0;
|
|
void* last_mmap_addr = NULL;
|
|
char* last_access_addr = NULL;
|
|
struct nmreq curr_nmr;
|
|
char nmr_name[64];
|
|
|
|
|
|
void do_open()
|
|
{
|
|
last_fd = open("/dev/netmap", O_RDWR);
|
|
output_err(last_fd, "open(\"/dev/netmap\", O_RDWR)=%d", last_fd);
|
|
}
|
|
|
|
void do_close()
|
|
{
|
|
int ret, fd;
|
|
char *arg = nextarg();
|
|
fd = arg ? atoi(arg) : last_fd;
|
|
ret = close(fd);
|
|
output_err(ret, "close(%d)=%d", fd, ret);
|
|
}
|
|
|
|
#ifdef TEST_NETMAP
|
|
#include <sys/ioctl.h>
|
|
#include <sys/socket.h>
|
|
#include <ifaddrs.h>
|
|
#include <net/netmap_user.h>
|
|
|
|
void parse_nmr_config(char* w, struct nmreq *nmr)
|
|
{
|
|
char *tok;
|
|
int i, v;
|
|
|
|
nmr->nr_tx_rings = nmr->nr_rx_rings = 0;
|
|
nmr->nr_tx_slots = nmr->nr_rx_slots = 0;
|
|
if (w == NULL || ! *w)
|
|
return;
|
|
for (i = 0, tok = strtok(w, ","); tok; i++, tok = strtok(NULL, ",")) {
|
|
v = atoi(tok);
|
|
switch (i) {
|
|
case 0:
|
|
nmr->nr_tx_slots = nmr->nr_rx_slots = v;
|
|
break;
|
|
case 1:
|
|
nmr->nr_rx_slots = v;
|
|
break;
|
|
case 2:
|
|
nmr->nr_tx_rings = nmr->nr_rx_rings = v;
|
|
break;
|
|
case 3:
|
|
nmr->nr_rx_rings = v;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void do_getinfo()
|
|
{
|
|
int ret;
|
|
char *arg, *name;
|
|
int fd;
|
|
|
|
bzero(&curr_nmr, sizeof(curr_nmr));
|
|
curr_nmr.nr_version = NETMAP_API;
|
|
|
|
name = nextarg();
|
|
if (name) {
|
|
strncpy(curr_nmr.nr_name, name, sizeof(curr_nmr.nr_name));
|
|
} else {
|
|
name = "any";
|
|
}
|
|
|
|
arg = nextarg();
|
|
if (!arg) {
|
|
fd = last_fd;
|
|
goto doit;
|
|
}
|
|
fd = atoi(arg);
|
|
|
|
arg = nextarg();
|
|
parse_nmr_config(arg, &curr_nmr);
|
|
|
|
doit:
|
|
ret = ioctl(fd, NIOCGINFO, &curr_nmr);
|
|
last_memsize = curr_nmr.nr_memsize;
|
|
output_err(ret, "ioctl(%d, NIOCGINFO) for %s: region %d memsize=%zu",
|
|
fd, name, curr_nmr.nr_arg2, last_memsize);
|
|
}
|
|
|
|
|
|
void do_regif()
|
|
{
|
|
int ret;
|
|
char *arg, *name;
|
|
int fd = last_fd;
|
|
|
|
name = nextarg();
|
|
if (!name) {
|
|
name = nmr_name;
|
|
goto doit;
|
|
}
|
|
|
|
bzero(&curr_nmr, sizeof(curr_nmr));
|
|
curr_nmr.nr_version = NETMAP_API;
|
|
strncpy(curr_nmr.nr_name, name, sizeof(curr_nmr.nr_name));
|
|
|
|
arg = nextarg();
|
|
if (!arg) {
|
|
goto doit;
|
|
}
|
|
fd = atoi(arg);
|
|
|
|
arg = nextarg();
|
|
parse_nmr_config(arg, &curr_nmr);
|
|
|
|
doit:
|
|
ret = ioctl(fd, NIOCREGIF, &curr_nmr);
|
|
last_memsize = curr_nmr.nr_memsize;
|
|
output_err(ret, "ioctl(%d, NIOCREGIF) for %s: region %d memsize=%zu",
|
|
fd, name, curr_nmr.nr_arg2, last_memsize);
|
|
}
|
|
|
|
|
|
void
|
|
do_txsync()
|
|
{
|
|
char *arg = nextarg();
|
|
int fd = arg ? atoi(arg) : last_fd;
|
|
int ret = ioctl(fd, NIOCTXSYNC, NULL);
|
|
output_err(ret, "ioctl(%d, NIOCTXSYNC)=%d", fd, ret);
|
|
}
|
|
|
|
void
|
|
do_rxsync()
|
|
{
|
|
char *arg = nextarg();
|
|
int fd = arg ? atoi(arg) : last_fd;
|
|
int ret = ioctl(fd, NIOCRXSYNC, NULL);
|
|
output_err(ret, "ioctl(%d, NIOCRXSYNC)=%d", fd, ret);
|
|
}
|
|
#endif /* TEST_NETMAP */
|
|
|
|
|
|
volatile char tmp1;
|
|
void do_access()
|
|
{
|
|
char *arg = nextarg();
|
|
char *p;
|
|
if (!arg) {
|
|
if (!last_access_addr) {
|
|
output("missing address");
|
|
return;
|
|
}
|
|
p = last_access_addr;
|
|
} else {
|
|
p = (char *)strtoul((void *)arg, NULL, 0);
|
|
}
|
|
last_access_addr = p + 4096;
|
|
tmp1 = *p;
|
|
}
|
|
|
|
void do_mmap()
|
|
{
|
|
size_t memsize;
|
|
off_t off = 0;
|
|
int fd;
|
|
char *arg;
|
|
|
|
arg = nextarg();
|
|
if (!arg) {
|
|
memsize = last_memsize;
|
|
fd = last_fd;
|
|
goto doit;
|
|
}
|
|
memsize = atoi(arg);
|
|
arg = nextarg();
|
|
if (!arg) {
|
|
fd = last_fd;
|
|
goto doit;
|
|
}
|
|
fd = atoi(arg);
|
|
arg = nextarg();
|
|
if (arg) {
|
|
off = (off_t)atol(arg);
|
|
}
|
|
doit:
|
|
last_mmap_addr = mmap(0, memsize,
|
|
PROT_WRITE | PROT_READ,
|
|
MAP_SHARED, fd, off);
|
|
if (last_access_addr == NULL)
|
|
last_access_addr = last_mmap_addr;
|
|
output_err(last_mmap_addr == MAP_FAILED ? -1 : 0,
|
|
"mmap(0, %zu, PROT_WRITE|PROT_READ, MAP_SHARED, %d, %jd)=%p",
|
|
memsize, fd, (intmax_t)off, last_mmap_addr);
|
|
|
|
}
|
|
|
|
void do_munmap()
|
|
{
|
|
void *mmap_addr;
|
|
size_t memsize;
|
|
char *arg;
|
|
int ret;
|
|
|
|
arg = nextarg();
|
|
if (!arg) {
|
|
mmap_addr = last_mmap_addr;
|
|
memsize = last_memsize;
|
|
goto doit;
|
|
}
|
|
mmap_addr = (void*)strtoul(arg, NULL, 0);
|
|
arg = nextarg();
|
|
if (!arg) {
|
|
memsize = last_memsize;
|
|
goto doit;
|
|
}
|
|
memsize = (size_t)strtoul(arg, NULL, 0);
|
|
doit:
|
|
ret = munmap(mmap_addr, memsize);
|
|
output_err(ret, "munmap(%p, %zu)=%d", mmap_addr, memsize, ret);
|
|
}
|
|
|
|
void do_poll()
|
|
{
|
|
/* timeout fd fd... */
|
|
nfds_t nfds = 0, allocated_fds = 10, i;
|
|
struct pollfd *fds;
|
|
int timeout = 500; /* 1/2 second */
|
|
char *arg;
|
|
int ret;
|
|
|
|
arg = nextarg();
|
|
if (arg)
|
|
timeout = atoi(arg);
|
|
fds = malloc(allocated_fds * sizeof(struct pollfd));
|
|
if (fds == NULL) {
|
|
output_err(-1, "out of memory");
|
|
return;
|
|
}
|
|
while ( (arg = nextarg()) ) {
|
|
if (nfds >= allocated_fds) {
|
|
allocated_fds *= 2;
|
|
fds = realloc(fds, allocated_fds * sizeof(struct pollfd));
|
|
if (fds == NULL) {
|
|
output_err(-1, "out of memory");
|
|
return;
|
|
}
|
|
}
|
|
fds[nfds].fd = atoi(arg);
|
|
fds[nfds].events = POLLIN;
|
|
nfds++;
|
|
}
|
|
ret = poll(fds, nfds, timeout);
|
|
for (i = 0; i < nfds; i++) {
|
|
output("poll(%d)=%s%s%s%s%s", fds[i].fd,
|
|
(fds[i].revents & POLLIN) ? "IN " : "- ",
|
|
(fds[i].revents & POLLOUT)? "OUT " : "- ",
|
|
(fds[i].revents & POLLERR)? "ERR " : "- ",
|
|
(fds[i].revents & POLLHUP)? "HUP " : "- ",
|
|
(fds[i].revents & POLLNVAL)?"NVAL" : "-");
|
|
|
|
}
|
|
output_err(ret, "poll(...)=%d", ret);
|
|
free(fds);
|
|
}
|
|
|
|
|
|
void
|
|
do_expr()
|
|
{
|
|
unsigned long stack[11];
|
|
int top = 10;
|
|
char *arg;
|
|
int err = 0;
|
|
|
|
stack[10] = ULONG_MAX;
|
|
while ( (arg = nextarg()) ) {
|
|
errno = 0;
|
|
char *rest;
|
|
unsigned long n = strtoul(arg, &rest, 0);
|
|
if (!errno && rest != arg) {
|
|
if (top <= 0) {
|
|
err = -1;
|
|
break;
|
|
}
|
|
stack[--top] = n;
|
|
continue;
|
|
}
|
|
if (top <= 8) {
|
|
unsigned long n1 = stack[top++];
|
|
unsigned long n2 = stack[top++];
|
|
unsigned long r = 0;
|
|
switch (arg[0]) {
|
|
case '+':
|
|
r = n1 + n2;
|
|
break;
|
|
case '-':
|
|
r = n1 - n2;
|
|
break;
|
|
case '*':
|
|
r = n1 * n2;
|
|
break;
|
|
case '/':
|
|
if (n2)
|
|
r = n1 / n2;
|
|
else {
|
|
errno = EDOM;
|
|
err = -1;
|
|
}
|
|
break;
|
|
default:
|
|
err = -1;
|
|
break;
|
|
}
|
|
stack[--top] = r;
|
|
continue;
|
|
}
|
|
err = -1;
|
|
break;
|
|
}
|
|
output_err(err, "expr=%lu", stack[top]);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
do_echo()
|
|
{
|
|
char *arg;
|
|
for (arg = nextarg(); arg; arg = nextarg()) {
|
|
printf("%s\n", arg);
|
|
}
|
|
}
|
|
|
|
void
|
|
do_vars()
|
|
{
|
|
int i;
|
|
for (i = 0; i < MAX_VARS; i++) {
|
|
const char *v = variables[i];
|
|
if (v == NULL)
|
|
continue;
|
|
printf("?%d\t%s\n", i, v == VAR_FAILED ? "FAILED" : v);
|
|
}
|
|
}
|
|
|
|
|
|
struct cmd_def {
|
|
const char *name;
|
|
void (*f)(void);
|
|
};
|
|
|
|
int _find_command(const struct cmd_def *cmds, int ncmds, const char* cmd)
|
|
{
|
|
int i;
|
|
for (i = 0; i < ncmds; i++) {
|
|
if (strcmp(cmds[i].name, cmd) == 0)
|
|
break;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
typedef void (*nmr_arg_interp_fun)();
|
|
|
|
#define nmr_arg_unexpected(n) \
|
|
printf("arg%d: %d%s\n", n, curr_nmr.nr_arg ## n, \
|
|
(curr_nmr.nr_arg ## n ? "???" : ""))
|
|
|
|
void
|
|
nmr_arg_bdg_attach()
|
|
{
|
|
uint16_t v = curr_nmr.nr_arg1;
|
|
printf("arg1: %d [", v);
|
|
if (v == 0) {
|
|
printf("no host rings");
|
|
} else if (v == NETMAP_BDG_HOST) {
|
|
printf("BDG_HOST");
|
|
} else {
|
|
printf("???");
|
|
}
|
|
printf("]\n");
|
|
nmr_arg_unexpected(2);
|
|
nmr_arg_unexpected(3);
|
|
}
|
|
|
|
void
|
|
nmr_arg_bdg_detach()
|
|
{
|
|
nmr_arg_unexpected(1);
|
|
nmr_arg_unexpected(2);
|
|
nmr_arg_unexpected(3);
|
|
}
|
|
|
|
void
|
|
nmr_arg_bdg_list()
|
|
{
|
|
}
|
|
|
|
void
|
|
nmr_arg_lookup_reg()
|
|
{
|
|
}
|
|
|
|
void
|
|
nmr_arg_vnet_hdr()
|
|
{
|
|
printf("arg1: %d [vnet hdr len]", curr_nmr.nr_arg1);
|
|
nmr_arg_unexpected(2);
|
|
nmr_arg_unexpected(3);
|
|
}
|
|
|
|
void
|
|
nmr_arg_error()
|
|
{
|
|
nmr_arg_unexpected(1);
|
|
nmr_arg_unexpected(2);
|
|
nmr_arg_unexpected(3);
|
|
}
|
|
|
|
void
|
|
nmr_arg_extra()
|
|
{
|
|
printf("arg1: %d [%sextra rings]\n", curr_nmr.nr_arg1,
|
|
(curr_nmr.nr_arg1 ? "" : "no "));
|
|
printf("arg2: %d [%s memory allocator]\n", curr_nmr.nr_arg2,
|
|
(curr_nmr.nr_arg2 == 0 ? "global" : "private"));
|
|
printf("arg3: %d [%sextra buffers]\n", curr_nmr.nr_arg3,
|
|
(curr_nmr.nr_arg3 ? "" : "no "));
|
|
}
|
|
|
|
void
|
|
do_nmr_dump()
|
|
{
|
|
u_int ringid = curr_nmr.nr_ringid & NETMAP_RING_MASK;
|
|
nmr_arg_interp_fun arg_interp;
|
|
|
|
snprintf(nmr_name, IFNAMSIZ + 1, "%s", curr_nmr.nr_name);
|
|
nmr_name[IFNAMSIZ] = '\0';
|
|
printf("name: %s\n", nmr_name);
|
|
printf("version: %d\n", curr_nmr.nr_version);
|
|
printf("offset: %d\n", curr_nmr.nr_offset);
|
|
printf("memsize: %d [", curr_nmr.nr_memsize);
|
|
if (curr_nmr.nr_memsize < (1<<20)) {
|
|
printf("%d KiB", curr_nmr.nr_memsize >> 10);
|
|
} else {
|
|
printf("%d MiB", curr_nmr.nr_memsize >> 20);
|
|
}
|
|
printf("]\n");
|
|
printf("tx_slots: %d\n", curr_nmr.nr_tx_slots);
|
|
printf("rx_slots: %d\n", curr_nmr.nr_rx_slots);
|
|
printf("tx_rings: %d\n", curr_nmr.nr_tx_rings);
|
|
printf("rx_rings: %d\n", curr_nmr.nr_rx_rings);
|
|
printf("ringid: %x [", curr_nmr.nr_ringid);
|
|
if (curr_nmr.nr_ringid & NETMAP_SW_RING) {
|
|
printf("host rings");
|
|
} else if (curr_nmr.nr_ringid & NETMAP_HW_RING) {
|
|
printf("hw ring %d", ringid);
|
|
} else {
|
|
printf("hw rings");
|
|
}
|
|
if (curr_nmr.nr_ringid & NETMAP_NO_TX_POLL) {
|
|
printf(", no tx poll");
|
|
}
|
|
printf(", region %d", curr_nmr.nr_arg2);
|
|
printf("]\n");
|
|
printf("cmd: %d", curr_nmr.nr_cmd);
|
|
if (curr_nmr.nr_cmd) {
|
|
printf("[");
|
|
switch (curr_nmr.nr_cmd) {
|
|
case NETMAP_BDG_ATTACH:
|
|
printf("BDG_ATTACH");
|
|
arg_interp = nmr_arg_bdg_attach;
|
|
break;
|
|
case NETMAP_BDG_DETACH:
|
|
printf("BDG_DETACH");
|
|
arg_interp = nmr_arg_bdg_detach;
|
|
break;
|
|
case NETMAP_BDG_LIST:
|
|
printf("BDG_LIST");
|
|
arg_interp = nmr_arg_bdg_list;
|
|
break;
|
|
case NETMAP_BDG_LOOKUP_REG:
|
|
printf("BDG_LOOKUP_REG");
|
|
arg_interp = nmr_arg_lookup_reg;
|
|
break;
|
|
case NETMAP_BDG_VNET_HDR:
|
|
printf("BDG_VNET_HDR");
|
|
arg_interp = nmr_arg_vnet_hdr;
|
|
break;
|
|
default:
|
|
printf("???");
|
|
arg_interp = nmr_arg_error;
|
|
break;
|
|
}
|
|
printf("]\n");
|
|
} else {
|
|
arg_interp = nmr_arg_extra;
|
|
}
|
|
printf("\n");
|
|
arg_interp();
|
|
printf("flags: %x [", curr_nmr.nr_flags);
|
|
switch (curr_nmr.nr_flags & NR_REG_MASK) {
|
|
case NR_REG_DEFAULT:
|
|
printf("obey ringid");
|
|
break;
|
|
case NR_REG_ALL_NIC:
|
|
printf("ALL_NIC");
|
|
break;
|
|
case NR_REG_SW:
|
|
printf("SW");
|
|
break;
|
|
case NR_REG_NIC_SW:
|
|
printf("NIC_SW");
|
|
break;
|
|
case NR_REG_ONE_NIC:
|
|
printf("ONE_NIC(%d)", ringid);
|
|
break;
|
|
case NR_REG_PIPE_MASTER:
|
|
printf("PIPE_MASTER(%d)", ringid);
|
|
break;
|
|
case NR_REG_PIPE_SLAVE:
|
|
printf("PIPE_SLAVE(%d)", ringid);
|
|
break;
|
|
default:
|
|
printf("???");
|
|
break;
|
|
}
|
|
if (curr_nmr.nr_flags & NR_MONITOR_TX) {
|
|
printf(", MONITOR_TX");
|
|
}
|
|
if (curr_nmr.nr_flags & NR_MONITOR_RX) {
|
|
printf(", MONITOR_RX");
|
|
}
|
|
printf("]\n");
|
|
printf("spare2[0]: %x\n", curr_nmr.spare2[0]);
|
|
}
|
|
|
|
void
|
|
do_nmr_reset()
|
|
{
|
|
bzero(&curr_nmr, sizeof(curr_nmr));
|
|
}
|
|
|
|
void
|
|
do_nmr_name()
|
|
{
|
|
char *name = nextarg();
|
|
if (name) {
|
|
strncpy(curr_nmr.nr_name, name, IFNAMSIZ);
|
|
}
|
|
strncpy(nmr_name, curr_nmr.nr_name, IFNAMSIZ);
|
|
nmr_name[IFNAMSIZ] = '\0';
|
|
output("name=%s", nmr_name);
|
|
}
|
|
|
|
void
|
|
do_nmr_ringid()
|
|
{
|
|
char *arg;
|
|
uint16_t ringid = curr_nmr.nr_ringid;
|
|
int n;
|
|
for (n = 0, arg = nextarg(); arg; arg = nextarg(), n++) {
|
|
if (strcmp(arg, "hw-ring") == 0) {
|
|
ringid |= NETMAP_HW_RING;
|
|
} else if (strcmp(arg, "sw-ring") == 0) {
|
|
ringid |= NETMAP_SW_RING;
|
|
} else if (strcmp(arg, "no-tx-poll") == 0) {
|
|
ringid |= NETMAP_NO_TX_POLL;
|
|
} else if (strcmp(arg, "default") == 0) {
|
|
ringid = 0;
|
|
} else {
|
|
ringid &= ~NETMAP_RING_MASK;
|
|
ringid |= (atoi(arg) & NETMAP_RING_MASK);
|
|
}
|
|
}
|
|
if (n)
|
|
curr_nmr.nr_ringid = ringid;
|
|
output("ringid=%x", curr_nmr.nr_ringid);
|
|
}
|
|
|
|
void
|
|
do_nmr_cmd()
|
|
{
|
|
}
|
|
|
|
void
|
|
do_nmr_flags()
|
|
{
|
|
char *arg;
|
|
uint32_t flags = curr_nmr.nr_flags;
|
|
int n;
|
|
for (n = 0, arg = nextarg(); arg; arg = nextarg(), n++) {
|
|
if (strcmp(arg, "all-nic") == 0) {
|
|
flags &= ~NR_REG_MASK;
|
|
flags |= NR_REG_ALL_NIC;
|
|
} else if (strcmp(arg, "sw") == 0) {
|
|
flags &= ~NR_REG_MASK;
|
|
flags |= NR_REG_SW;
|
|
} else if (strcmp(arg, "nic-sw") == 0) {
|
|
flags &= ~NR_REG_MASK;
|
|
flags |= NR_REG_NIC_SW;
|
|
} else if (strcmp(arg, "pipe-master") == 0) {
|
|
flags &= ~NR_REG_MASK;
|
|
flags |= NR_REG_PIPE_MASTER;
|
|
} else if (strcmp(arg, "pipe-slave") == 0) {
|
|
flags &= ~NR_REG_MASK;
|
|
flags |= NR_REG_PIPE_SLAVE;
|
|
} else if (strcmp(arg, "monitor-tx") == 0) {
|
|
flags |= NR_MONITOR_TX;
|
|
} else if (strcmp(arg, "monitor-rx") == 0) {
|
|
flags |= NR_MONITOR_RX;
|
|
} else if (strcmp(arg, "default") == 0) {
|
|
flags = 0;
|
|
}
|
|
}
|
|
if (n)
|
|
curr_nmr.nr_flags = flags;
|
|
output("flags=%x", curr_nmr.nr_flags);
|
|
}
|
|
|
|
struct cmd_def nmr_commands[] = {
|
|
{ "dump", do_nmr_dump },
|
|
{ "reset", do_nmr_reset },
|
|
{ "name", do_nmr_name },
|
|
{ "ringid", do_nmr_ringid },
|
|
{ "cmd", do_nmr_cmd },
|
|
{ "flags", do_nmr_flags },
|
|
};
|
|
|
|
const int N_NMR_CMDS = sizeof(nmr_commands) / sizeof(struct cmd_def);
|
|
|
|
int
|
|
find_nmr_command(const char *cmd)
|
|
{
|
|
return _find_command(nmr_commands, N_NMR_CMDS, cmd);
|
|
}
|
|
|
|
#define nmr_arg_update(f) \
|
|
({ \
|
|
int __ret = 0; \
|
|
if (strcmp(cmd, #f) == 0) { \
|
|
char *arg = nextarg(); \
|
|
if (arg) { \
|
|
curr_nmr.nr_##f = strtol(arg, NULL, 0); \
|
|
} \
|
|
output(#f "=%d", curr_nmr.nr_##f); \
|
|
__ret = 1; \
|
|
} \
|
|
__ret; \
|
|
})
|
|
|
|
/* prepare the curr_nmr */
|
|
void
|
|
do_nmr()
|
|
{
|
|
char *cmd = nextarg();
|
|
int i;
|
|
|
|
if (cmd == NULL) {
|
|
do_nmr_dump();
|
|
return;
|
|
}
|
|
if (cmd[0] == '.') {
|
|
cmd++;
|
|
} else {
|
|
i = find_nmr_command(cmd);
|
|
if (i < N_NMR_CMDS) {
|
|
nmr_commands[i].f();
|
|
return;
|
|
}
|
|
}
|
|
if (nmr_arg_update(version) ||
|
|
nmr_arg_update(offset) ||
|
|
nmr_arg_update(memsize) ||
|
|
nmr_arg_update(tx_slots) ||
|
|
nmr_arg_update(rx_slots) ||
|
|
nmr_arg_update(tx_rings) ||
|
|
nmr_arg_update(rx_rings) ||
|
|
nmr_arg_update(ringid) ||
|
|
nmr_arg_update(cmd) ||
|
|
nmr_arg_update(arg1) ||
|
|
nmr_arg_update(arg2) ||
|
|
nmr_arg_update(arg3) ||
|
|
nmr_arg_update(flags))
|
|
return;
|
|
output("unknown field: %s", cmd);
|
|
}
|
|
|
|
|
|
|
|
struct cmd_def commands[] = {
|
|
{ "open", do_open, },
|
|
{ "close", do_close, },
|
|
#ifdef TEST_NETMAP
|
|
{ "getinfo", do_getinfo, },
|
|
{ "regif", do_regif, },
|
|
{ "txsync", do_txsync, },
|
|
{ "rxsync", do_rxsync, },
|
|
#endif /* TEST_NETMAP */
|
|
{ "mmap", do_mmap, },
|
|
{ "access", do_access, },
|
|
{ "munmap", do_munmap, },
|
|
{ "poll", do_poll, },
|
|
{ "expr", do_expr, },
|
|
{ "echo", do_echo, },
|
|
{ "vars", do_vars, },
|
|
{ "nmr", do_nmr, }
|
|
};
|
|
|
|
const int N_CMDS = sizeof(commands) / sizeof(struct cmd_def);
|
|
|
|
int find_command(const char* cmd)
|
|
{
|
|
return _find_command(commands, N_CMDS, cmd);
|
|
}
|
|
|
|
#define MAX_CHAN 10
|
|
|
|
void prompt()
|
|
{
|
|
if (isatty(STDIN_FILENO)) {
|
|
printf("> ");
|
|
}
|
|
}
|
|
|
|
struct chan *channels[MAX_CHAN];
|
|
|
|
void*
|
|
thread_cmd_loop(void *arg)
|
|
{
|
|
char buf[1024];
|
|
FILE *in = (FILE*)arg;
|
|
|
|
while (fgets(buf, 1024, in)) {
|
|
char *cmd;
|
|
int i;
|
|
|
|
cmd = firstarg(buf);
|
|
i = find_command(cmd);
|
|
if (i < N_CMDS) {
|
|
commands[i].f();
|
|
continue;
|
|
}
|
|
output("unknown cmd %s", cmd);
|
|
}
|
|
fclose(in);
|
|
return NULL;
|
|
}
|
|
|
|
void do_exit()
|
|
{
|
|
output("quit");
|
|
}
|
|
|
|
void
|
|
cmd_loop()
|
|
{
|
|
char buf[1024];
|
|
int i;
|
|
struct chan *c;
|
|
|
|
bzero(channels, sizeof(*channels) * MAX_CHAN);
|
|
|
|
atexit(do_exit);
|
|
|
|
for (prompt(); fgets(buf, 1024, stdin); prompt()) {
|
|
char *cmd;
|
|
int slot;
|
|
|
|
cmd = firstarg(buf);
|
|
if (!cmd)
|
|
continue;
|
|
if (cmd[0] == '@') {
|
|
curr_var = atoi(cmd + 1);
|
|
if (curr_var < 0 || curr_var >= MAX_VARS)
|
|
curr_var = 0;
|
|
cmd = nextarg();
|
|
if (!cmd)
|
|
continue;
|
|
} else {
|
|
curr_var = 0;
|
|
}
|
|
|
|
if (strcmp(cmd, "fork") == 0) {
|
|
int slot = chan_search_free(channels, MAX_CHAN);
|
|
struct chan *c = NULL;
|
|
pid_t pid;
|
|
int p1[2] = { -1, -1};
|
|
|
|
if (slot == MAX_CHAN) {
|
|
output("too many channels");
|
|
continue;
|
|
}
|
|
c = channels[slot] = (struct chan*)malloc(sizeof(struct chan));
|
|
if (c == NULL) {
|
|
output_err(-1, "malloc");
|
|
continue;
|
|
}
|
|
bzero(c, sizeof(*c));
|
|
if (pipe(p1) < 0) {
|
|
output_err(-1, "pipe");
|
|
goto clean1;
|
|
}
|
|
c->out = fdopen(p1[1], "w");
|
|
if (c->out == NULL) {
|
|
output_err(-1, "fdopen");
|
|
goto clean1;
|
|
}
|
|
pid = fork();
|
|
switch (pid) {
|
|
case -1:
|
|
output_err(-1, "fork");
|
|
goto clean1;
|
|
case 0:
|
|
fclose(stdin);
|
|
if (dup(p1[0]) < 0) {
|
|
output_err(-1, "dup");
|
|
exit(1);
|
|
}
|
|
close(p1[1]);
|
|
stdin = fdopen(0, "r");
|
|
chan_clear_all(channels, MAX_CHAN);
|
|
goto out;
|
|
default:
|
|
break;
|
|
}
|
|
c->pid = pid;
|
|
close(p1[0]);
|
|
output("fork()=%d slot=%d", pid, slot);
|
|
continue;
|
|
clean1:
|
|
if (c) {
|
|
fclose(c->out);
|
|
}
|
|
close(p1[0]);
|
|
close(p1[1]);
|
|
free(c);
|
|
out:
|
|
continue;
|
|
}
|
|
if (strcmp(cmd, "kill") == 0) {
|
|
int ret;
|
|
|
|
cmd = nextarg();
|
|
if (!cmd) {
|
|
output("missing slot");
|
|
continue;
|
|
}
|
|
slot = atoi(cmd);
|
|
if (slot < 0 || slot >= MAX_CHAN || !channels[slot]) {
|
|
output("invalid slot: %s", cmd);
|
|
continue;
|
|
}
|
|
c = channels[slot];
|
|
ret = kill(c->pid, SIGTERM);
|
|
output_err(ret, "kill(%d, SIGTERM)=%d", c->pid, ret);
|
|
if (ret != -1) {
|
|
wait(NULL);
|
|
fclose(c->out);
|
|
free(c);
|
|
channels[slot] = NULL;
|
|
}
|
|
continue;
|
|
}
|
|
if (strcmp(cmd, "thread") == 0) {
|
|
int slot = chan_search_free(channels, MAX_CHAN);
|
|
struct chan *c = NULL;
|
|
pthread_t tid;
|
|
int p1[2] = { -1, -1};
|
|
int ret;
|
|
FILE *in = NULL;
|
|
|
|
if (slot == MAX_CHAN) {
|
|
output("too many channels");
|
|
continue;
|
|
}
|
|
c = channels[slot] = (struct chan*)malloc(sizeof(struct chan));
|
|
bzero(c, sizeof(*c));
|
|
if (pipe(p1) < 0) {
|
|
output_err(-1, "pipe");
|
|
goto clean2;
|
|
}
|
|
c->out = fdopen(p1[1], "w");
|
|
if (c->out == NULL) {
|
|
output_err(-1, "fdopen");
|
|
goto clean2;
|
|
}
|
|
in = fdopen(p1[0], "r");
|
|
if (in == NULL) {
|
|
output_err(-1, "fdopen");
|
|
goto clean2;
|
|
}
|
|
ret = pthread_create(&tid, NULL, thread_cmd_loop, in);
|
|
output_err(ret, "pthread_create() tid=%lu slot=%d",
|
|
(unsigned long) tid, slot);
|
|
if (ret < 0)
|
|
goto clean2;
|
|
c->pid = getpid();
|
|
c->tid = tid;
|
|
continue;
|
|
clean2:
|
|
fclose(in);
|
|
fclose(c->out);
|
|
close(p1[0]);
|
|
close(p1[1]);
|
|
free(c);
|
|
continue;
|
|
}
|
|
if (strcmp(cmd, "cancel") == 0) {
|
|
int ret;
|
|
|
|
cmd = nextarg();
|
|
if (!cmd) {
|
|
output("missing slot");
|
|
continue;
|
|
}
|
|
slot = atoi(cmd);
|
|
if (slot < 0 || slot >= MAX_CHAN || !channels[slot]) {
|
|
output("invalid slot: %s", cmd);
|
|
continue;
|
|
}
|
|
c = channels[slot];
|
|
fclose(c->out);
|
|
ret = pthread_join(c->tid, NULL);
|
|
output_err(ret, "pthread_join(%lu)=%d",
|
|
(unsigned long) c->tid, ret);
|
|
if (ret > 0) {
|
|
free(c);
|
|
channels[slot] = NULL;
|
|
}
|
|
continue;
|
|
}
|
|
i = find_command(cmd);
|
|
if (i < N_CMDS) {
|
|
commands[i].f();
|
|
continue;
|
|
}
|
|
slot = atoi(cmd);
|
|
if (slot < 0 || slot > MAX_CHAN || !channels[slot]) {
|
|
output("invalid cmd/slot: %s", cmd);
|
|
continue;
|
|
}
|
|
cmd = restofline();
|
|
if (!cmd) {
|
|
output("missing command");
|
|
continue;
|
|
}
|
|
fprintf(channels[slot]->out, "%s\n", cmd);
|
|
fflush(channels[slot]->out);
|
|
sleep(1);
|
|
}
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
(void) argc;
|
|
(void) argv;
|
|
cmd_loop();
|
|
return 0;
|
|
}
|