[Lguest] [RFC 6/6] lguest: IPv6 tunnet configuration
Sakari Ailus
sakari.ailus at iki.fi
Sun Sep 2 02:07:48 EST 2012
Implement IPv6 tunnet configuration for lguest. This changes the format of
--tunnet option but the old format is still supported, albeit no longer
documented.
Signed-off-by: Sakari Ailus <sakari.ailus at iki.fi>
---
tools/lguest/lguest.c | 173 +++++++++++++++++++++++++++++++++++++++----------
1 files changed, 139 insertions(+), 34 deletions(-)
diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c
index b316b8f..d6e5f1f 100644
--- a/tools/lguest/lguest.c
+++ b/tools/lguest/lguest.c
@@ -28,6 +28,7 @@
#include <sys/time.h>
#include <time.h>
#include <netinet/in.h>
+#include <arpa/inet.h>
#include <net/if.h>
#include <linux/sockios.h>
#include <linux/if_tun.h>
@@ -66,6 +67,14 @@ typedef uint8_t u8;
/*:*/
#define BRIDGE_PFX "bridge:"
+#ifndef in6_ifreq
+struct in6_ifreq {
+ struct in6_addr ifr6_addr;
+ __u32 ifr6_prefixlen;
+ int ifr6_ifindex;
+};
+#endif
+
#ifndef SIOCBRADDIF
#define SIOCBRADDIF 0x89a2 /* add interface to bridge */
#endif
@@ -1457,6 +1466,25 @@ static void configure_device(int fd, const char *tapif, u32 ipaddr,
err(1, "Setting %s interface netmask", tapif);
}
+static void configure_device6(int fd, const char *tapif, struct in6_addr *ip6,
+ unsigned int prefixlen)
+{
+ struct ifreq ifr;
+ struct in6_ifreq ifr6;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, tapif);
+
+ if (ioctl(fd, SIOGIFINDEX, &ifr) != 0)
+ err(1, "Getting interface index failed, iface %s", tapif);
+
+ ifr6.ifr6_ifindex = ifr.ifr_ifindex;
+ ifr6.ifr6_addr = *ip6;
+ ifr6.ifr6_prefixlen = prefixlen;
+ if (ioctl(fd, SIOCSIFADDR, &ifr6) != 0)
+ err(1, "Setting %s interface IPv6 address", tapif);
+}
+
static void set_up_device(int fd, const char *tapif)
{
struct ifreq ifr;
@@ -1513,12 +1541,15 @@ static void setup_tun_net(char *arg)
{
struct device *dev;
struct net_info *net_info = malloc(sizeof(*net_info));
- int ipfd;
+ int ip4fd, ip6fd, ipfd;
u32 ip = INADDR_ANY;
+ bool has_ip6 = false;
+ struct in6_addr ip6 = IN6ADDR_ANY_INIT;
+ unsigned int prefixlen[2] = { 24, 64 };
+ char tapif[IFNAMSIZ];
bool bridging = false;
- char tapif[IFNAMSIZ], *p;
- struct virtio_net_config virtio_conf;
bool has_virtio_conf = false;
+ struct virtio_net_config virtio_conf;
if (!net_info)
err(1, "can't allocate struct net_info");
@@ -1534,36 +1565,103 @@ static void setup_tun_net(char *arg)
add_virtqueue(dev, VIRTQUEUE_NUM, net_output);
/*
- * We need a socket to perform the magic network ioctls to bring up the
- * tap interface, connect to the bridge etc. Any socket will do!
+ * We need a socket to perform the magic network ioctls to bring up
+ * the tap interface, connect to the bridge etc. Open IPv6 socket as
+ * well to configure IPv6 networking.
*/
- ipfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
- if (ipfd < 0)
- err(1, "opening IP socket");
-
- /* If the command line was --tunnet=bridge:<name> do bridging. */
- if (!strncmp(BRIDGE_PFX, arg, strlen(BRIDGE_PFX))) {
- arg += strlen(BRIDGE_PFX);
- bridging = true;
- }
+ ip4fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+ ip6fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP);
+
+ /* We need either one at least. */
+ if (ip4fd != -1)
+ ipfd = ip4fd;
+ else if (ip6fd != -1)
+ ipfd = ip6fd;
+ else
+ err(1, "opening socket");
- /* A mac address may follow the bridge name or IP address */
- p = strchr(arg, ':');
- if (p) {
- has_virtio_conf = true;
- str2mac(p+1, virtio_conf.mac);
- add_feature(dev, VIRTIO_NET_F_MAC);
- *p = '\0';
+ memset(&virtio_conf, 0, sizeof(virtio_conf));
+
+ if (arg && (isdigit(*arg) || !strcmp(arg, BRIDGE_PFX))) {
+ char *p;
+
+ warnx("warning: using compatibility syntax for tunnet configuration");
+ if (!strncmp(BRIDGE_PFX, arg, strlen(BRIDGE_PFX))) {
+ arg += strlen(BRIDGE_PFX);
+ bridging = true;
+ }
+ /* A mac address may follow the bridge name or IP address */
+ p = strchr(arg, ':');
+ if (p) {
+ has_virtio_conf = true;
+ str2mac(p+1, virtio_conf.mac);
+ *p = '\0';
+ }
+ if (bridging)
+ add_to_bridge(ipfd, tapif, arg);
+ else
+ ip = str2ip(arg);
+
+ /* We already processed the arguments, so don't do it again. */
+ arg = NULL;
}
- /* arg is now either an IP address or a bridge name */
- if (bridging)
- add_to_bridge(ipfd, tapif, arg);
- else
- ip = str2ip(arg);
+ while (arg && *arg) {
+ int is_6 = 0;
+ char *name = arg;
+ char *equals = strchr(arg, '=');
+ char *next = strchr(arg, ',');
+ char *mask = NULL;
+ char *value;
+
+ if (!equals || (equals > next && next != NULL))
+ errx(1, "unable to parse: %s", arg);
+
+ *equals = 0;
+ value = equals + 1;
+ if (next) {
+ *next = 0;
+ next++;
+ }
+
+ if (!strcmp(name, "bridge")) {
+ bridging = true;
+ add_to_bridge(ipfd, tapif, value);
+ } else if (!strcmp(name, "mac")) {
+ has_virtio_conf = true;
+ str2mac(value, virtio_conf.mac);
+ } else if (!strcmp(name, "ip6")) {
+ if (ip6fd == -1)
+ errx(1, "no IP6 socket but IPv6 address given");
+ mask = strchr(value, '/');
+ if (mask)
+ *mask = 0;
+ if (inet_pton(AF_INET6, value, &ip6) <= 0)
+ errx(1, "bad IPv6 address\n");
+ has_ip6 = true;
+ is_6 = 1;
+ } else if (!strcmp(name, "ip")) {
+ mask = strchr(value, '/');
+ ip = str2ip(value);
+ } else {
+ errx(1, "unrecognised token %s\n", name);
+ }
+ if (mask)
+ prefixlen[is_6] = atoi(mask + 1);
+ arg = next;
+ }
/* Set up the tun device. */
- configure_device(ipfd, tapif, ip, 24);
+ if (!bridging) {
+ if (ip4fd != -1)
+ configure_device(ip4fd, tapif, ip, prefixlen[0]);
+ if (ip6fd != -1 && has_ip6)
+ configure_device6(ip6fd, tapif, &ip6, prefixlen[1]);
+ }
+ if (has_virtio_conf) {
+ add_feature(dev, VIRTIO_NET_F_MAC);
+ set_config(dev, sizeof(virtio_conf), &virtio_conf);
+ }
set_up_device(ipfd, tapif);
/* Expect Guest to handle everything except UFO */
@@ -1577,11 +1675,10 @@ static void setup_tun_net(char *arg)
add_feature(dev, VIRTIO_NET_F_HOST_ECN);
/* We handle indirect ring entries */
add_feature(dev, VIRTIO_RING_F_INDIRECT_DESC);
- if (has_virtio_conf)
- set_config(dev, sizeof(virtio_conf), &virtio_conf);
/* We don't need the socket any more; setup is done. */
- close(ipfd);
+ close(ip6fd);
+ close(ip4fd);
devices.device_num++;
@@ -1895,10 +1992,18 @@ static struct option opts[] = {
};
static void usage(void)
{
- errx(1, "Usage: lguest [--verbose] "
- "[--tunnet=(<ipaddr>:<macaddr>|bridge:<bridgename>:<macaddr>)\n"
- "|--block=<filename>|--initrd=<filename>]...\n"
- "<mem-in-mb> vmlinux [args...]");
+ errx(1, "Usage: lguest [--verbose]\n"
+ "\t[--tunnet=netcfg|brcfg]\n"
+ "\t[--block=<filename>|--initrd=<filename>]...\n"
+ "\t<mem-in-mb> vmlinux [args...]\n\n"
+ " where\n"
+ " netcfg = ip|ip6[,ip|ip6]...\n"
+ " ip = ipaddr[/mask]\n"
+ " ip6 = ip6addr[/mask6]\n"
+ " brcfg = bridge=bridgename,mac=macaddr\n"
+ " defaults\n"
+ " mask = 24\n"
+ " mask6 = 64");
}
/*L:105 The main routine is where the real work begins: */
--
1.7.2.5
More information about the Lguest
mailing list