[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