Skip to content

Commit

Permalink
Merge pull request #12 from upa/nuse-config-file
Browse files Browse the repository at this point in the history
add nuse-config.c and nuse.conf instead of env variables for the issue #6
  • Loading branch information
thehajime committed Nov 17, 2014
2 parents b21e5a8 + 66cbd91 commit f4718be
Show file tree
Hide file tree
Showing 7 changed files with 459 additions and 172 deletions.
58 changes: 30 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,52 +20,54 @@ you should see libnuse-linux.so.

## Run

Then, a wrapper script called **nuse** takes your application running with NUSE.
At 1st, please write a configuration file for nuse **nuse.conf**.
Example of nuse.conf is shown below.

```
sudo NUSEDEV=eth0 nuse-eth0=192.168.209.39 ./nuse ping 192.168.209.1
# Interface definition.
interface eth0
address 192.168.0.10
netmask 255.255.255.0
macaddr 00:01:01:01:01:01
viftype TAP
interface p1p1
address 172.16.0.1
netmask 255.255.255.0
macaddr 00:01:01:01:01:02
# route entry definition.
route
network 0.0.0.0
netmask 0.0.0.0
gateway 192.168.0.1
```

where an environmental variable **nuse-(interface name)** indicates an IPv4 address for an interface under NUSE, instead of host OS's one.

and if you want to use netmap for network i/o, specify **NUSEVIF=NETMAP** as an env variable. The default interface will be raw socket based network i/o.
When viftype is TAP, the interface name attached to nuse process is
not restricted to be same as physical interfaces of host
stack. However, viftype RAW and NETMAP requires that an interface name
must be same as a physical interface of host stack.

```
sudo NUSEVIF=NETMAP NUSEDEV=eth0 nuse-eth0=192.168.209.39 ./nuse ping 192.168.209.1
```
The default interface will be raw socket based network i/o.

And if you want to use tun/tap driver for network i/o, **NUSEVIF=TAP** is offered. When NUSEVIF is TAP, a name of interface attached to a nuse process is not restricted to existing interface names of host stack.

```
sudo NUSEVIF=TAP NUSEDEV=eth0 nuse-eth0=192.168.209.39 ./nuse ping 192.168.209.1
~ host stack ~
ifconfig nuse-eth0
nuse-eth0 Link encap:Ethernet HWaddr d6:d6:86:74:bf:5e
inet6 addr: fe80::d4d6:86ff:fe74:bf5e/64 Scope:Link
UP BROADCAST RUNNING MTU:1500 Metric:1
RX packets:11 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:500
RX bytes:462 (462.0 B) TX bytes:648 (648.0 B)
```
Then, a wrapper script called **nuse** takes your application running with NUSE.

How to set default route of nuse process.
```
sudo NUSEVIF=TAP NUSEDEV=eth0 nuse-eth0=192.168.0.10 DEFAULTROUTE=192.168.0.1 ./nuse ping 172.16.0.1
sudo NUSECONF=nuse.conf ./nuse ping 172.16.0.2
```

And, iperf

```
sudo NUSEDEV=eth0 nuse-eth0=192.168.209.39 ./nuse iperf -c 192.168.209.1 -u
sudo NUSECONF=nuse.conf ./nuse iperf -c 192.168.209.1 -u
```

should just work fine !

since the LD_PRELOAD with sudo technique requires additional copy and permission changes to the library, the script will automatically conduct such an operation.

## Tested platform
Fedora 19 64bits
Ubuntu 13.04 64bits
Ubuntu 14.04 64bits
- Fedora 19 64bits
- Ubuntu 13.04 64bits
- Ubuntu 14.04 64bits
2 changes: 1 addition & 1 deletion arch/sim/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ netmap_no=

NUSE_SRC=\
nuse.c nuse-fiber.c nuse-vif.c nuse-poll.c \
nuse-vif-rawsock.c nuse-glue.c nuse-hostcalls.c \
nuse-vif-rawsock.c nuse-glue.c nuse-hostcalls.c nuse-config.c \
nuse-vif-tap.c $(netmap_$(NETMAP))

SIM_SRC=\
Expand Down
250 changes: 250 additions & 0 deletions arch/sim/nuse-config.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@

#include <stdio.h>
#include <linux/socket.h>
#include <uapi/linux/in.h>
#include "nuse-config.h"

typedef unsigned int uint32_t;

/* sdlib.h */
extern void *malloc (size_t size);
extern void free (void * ptr);


/* ipaddress config */
typedef uint32_t in_addr_t;
extern in_addr_t inet_addr (const char * cp);



static int
strsplit (char * str, char ** args, int max)
{
int argc;
char * c;

for (argc = 0, c = str; *c == ' ' || *c == '\t' || *c == '\n'; c++);
while (*c && argc < max) {
args[argc++] = c;
while (*c && *c > ' ') c++;
while (*c && *c <= ' ') *c++ = '\0';
}

return argc;
}

static int
nuse_config_parse_interface (char * line, FILE * fp, struct nuse_config * cf)
{
int ret;
char buf[1024], *p, * args[2];
struct nuse_vif_config * vifcf;
struct sockaddr_in * sin;

memset (buf, 0, sizeof (buf));

vifcf = (struct nuse_vif_config *)
malloc (sizeof (struct nuse_vif_config));

memset (vifcf, 0, sizeof (struct nuse_vif_config));
vifcf->type = NUSE_VIF_RAWSOCK; // default

strsplit (line, args, sizeof (args));

strncpy (vifcf->ifname, args[1], IFNAMSIZ);

while ((p = fgets (buf, sizeof (buf), fp)) != NULL) {

ret = strsplit (buf, args, sizeof (args));

if (ret == 0) {
/* no item in the line */
break;
}

if (strncmp (args[0], "address", 7) == 0) {
strncpy (vifcf->address, args[1], NUSE_ADDR_STRLEN);
}
if (strncmp (args[0], "netmask", 7) == 0) {
strncpy (vifcf->netmask, args[1], NUSE_ADDR_STRLEN);
}
if (strncmp (args[0], "macaddr", 7) == 0) {
strncpy (vifcf->macaddr, args[1], NUSE_MACADDR_STRLEN);
}
if (strncmp (args[0], "viftype", 7) == 0) {
if (strncmp (args[1], "RAW", 3) == 0) {
vifcf->type = NUSE_VIF_RAWSOCK;
} else if (strncmp (args[1], "NETMAP", 6) == 0) {
vifcf->type = NUSE_VIF_NETMAP;
} else if (strncmp (args[1], "TAP", 3) == 0) {
vifcf->type = NUSE_VIF_TAP;
} else {
printf ("invalid vif type %s\n", args[1]);
return 0;
}
}
}

if (!p) {
printf ("Config error for interface %s\n", vifcf->ifname);
free (vifcf);
return 0;
}

/* setup ifreq */
sin = (struct sockaddr_in *)&vifcf->ifr_vif_addr.ifr_addr;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = inet_addr (vifcf->address);

sin = (struct sockaddr_in *)&vifcf->ifr_vif_mask.ifr_netmask;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = inet_addr (vifcf->netmask);

/* XXX: ifname attached to nuse process is same as host stck */
strncpy (vifcf->ifr_vif_addr.ifr_name, vifcf->ifname, IFNAMSIZ);
strncpy (vifcf->ifr_vif_mask.ifr_name, vifcf->ifname, IFNAMSIZ);

/* reassemble mac address */
if (sscanf (vifcf->macaddr, "%u:%u:%u:%u:%u:%u",
(unsigned int *)&vifcf->mac[0],
(unsigned int *)&vifcf->mac[1],
(unsigned int *)&vifcf->mac[2],
(unsigned int *)&vifcf->mac[3],
(unsigned int *)&vifcf->mac[4],
(unsigned int *)&vifcf->mac[5]) < 1) {
printf ("failed to parse mac address %s\n", vifcf->macaddr);
free (vifcf);
return 0;
}

cf->vifs[cf->vif_cnt++] = vifcf;

return 1;
}

static int
nuse_config_parse_route (char * line, FILE * fp, struct nuse_config * cf)
{
int ret, net, mask, gate;
char buf[1024], * p, * args[2];
struct nuse_route_config * rtcf;
struct sockaddr_in * sin;

net = 0;
mask = 0;
gate = 0;

memset (buf, 0, sizeof (buf));

rtcf = (struct nuse_route_config *)
malloc (sizeof (struct nuse_route_config));

while ((p = fgets (buf, sizeof (buf), fp)) != NULL) {

ret = strsplit (buf, args, sizeof (args));

if (ret == 0) {
/* no item in the line */
break;
}

if (strncmp (args[0], "network", 7) == 0) {
strncpy (rtcf->network, args[1], NUSE_ADDR_STRLEN);
net = 1;
}
if (strncmp (args[0], "netmask", 7) == 0) {
strncpy (rtcf->netmask, args[1], NUSE_ADDR_STRLEN);
mask = 1;
}
if (strncmp (args[0], "gateway", 7) == 0) {
strncpy (rtcf->gateway, args[1], NUSE_ADDR_STRLEN);
gate = 1;
}

if (net && mask && gate)
break;
}

if (!p) {
printf ("Config error for route entry\n");
free (rtcf);
return 0;
}

if (!net)
printf ("network is not configured !\n");
if (!mask)
printf ("netmask is not configured !\n");
if (!gate)
printf ("netmask is not configured !\n");

if (!net || !mask || !gate)
return 0;

/* setup rtentry */
sin = (struct sockaddr_in *)&rtcf->route.rt_dst;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = inet_addr (rtcf->network);

sin = (struct sockaddr_in *) &rtcf->route.rt_genmask;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = inet_addr (rtcf->netmask);

sin = (struct sockaddr_in *) &rtcf->route.rt_gateway;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = inet_addr (rtcf->gateway);

rtcf->route.rt_flags = RTF_UP | RTF_GATEWAY;
rtcf->route.rt_metric = 0;

cf->routes[cf->route_cnt++] = rtcf;

return 1;
}


int
nuse_config_parse (struct nuse_config * cf, char * cfname)
{
FILE * fp;
int ret;
char buf[1024];

memset (cf, 0, sizeof (struct nuse_config));

if ((fp = fopen (cfname, "r")) == NULL) {
perror ("fopen");
return 0;
}

while (fgets (buf, sizeof (buf), fp) != NULL) {
if (strncmp (buf, "interface ", 10) == 0) {
ret = nuse_config_parse_interface (buf, fp, cf);
} else if (strncmp (buf, "route", 5) == 0) {
ret = nuse_config_parse_route (buf, fp, cf);
}
if (!ret)
break;
}

fclose (fp);

return ret;
}

void
nuse_config_free (struct nuse_config * cf)
{
int n;

for (n = 0; n < cf->vif_cnt; n++) {
free (cf->vifs[n]);
}

for (n = 0; n < cf->route_cnt; n++) {
free (cf->routes[n]);
}

return;
}

53 changes: 53 additions & 0 deletions arch/sim/nuse-config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@

#ifndef _NUSE_CONFIG_H_
#define _NUSE_CONFIG_H_

#include <uapi/linux/if_ether.h>
#include <uapi/linux/route.h>
#include "nuse-vif.h"


#define NUSE_VIF_MAX 16
#define NUSE_ROUTE_MAX 16
#define NUSE_ADDR_STRLEN 16
#define NUSE_MACADDR_STRLEN 20


struct nuse_vif_config {
char ifname[IFNAMSIZ];
char address[NUSE_ADDR_STRLEN];
char netmask[NUSE_ADDR_STRLEN];
char macaddr[NUSE_MACADDR_STRLEN];

enum viftype type;

u_char mac[ETH_ALEN];

struct ifreq ifr_vif_addr;
struct ifreq ifr_vif_mask;
};

struct nuse_route_config {
char network[NUSE_ADDR_STRLEN];
char netmask[NUSE_ADDR_STRLEN];
char gateway[NUSE_ADDR_STRLEN];

struct rtentry route;
};

struct nuse_config {
int vif_cnt, route_cnt;
struct nuse_vif_config * vifs[NUSE_VIF_MAX];
struct nuse_route_config * routes[NUSE_ROUTE_MAX];
};


/* open cfname and return struct nuse_config */
int nuse_config_parse (struct nuse_config * cf, char * cfname);

/* free cf->nuse_vif_config and cf->nuse_route_config */
void nuse_config_free (struct nuse_config * cf);



#endif /* _NUSE_CONFIG_H_ */
Loading

0 comments on commit f4718be

Please sign in to comment.