From f8fee0e2c399af59ee30c62234b47505fbd93725 Mon Sep 17 00:00:00 2001
From: Matthijs Kooijman <matthijs@stdin.nl>
Date: Tue, 30 Aug 2011 23:50:23 +0200
Subject: [PATCH 1/3] .gateway configuration

This directive adds a default route to the guest at startup.

syntax:
	lxc.network.ipv4.gateway = 10.0.0.1
	lxc.network.ipv6.gateway = 2001:db8:85a3::8a2e:370:7334

Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
---
 src/lxc/conf.c    |   45 ++++++++++++++++++++++++++++++++++
 src/lxc/conf.h    |    2 +
 src/lxc/confile.c |   66 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/lxc/network.c |   70 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/lxc/network.h |    6 ++++
 5 files changed, 189 insertions(+), 0 deletions(-)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 2eb598b..751dce0 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -1321,6 +1321,51 @@ static int setup_netdev(struct lxc_netdev *netdev)
 		}
 	}
 
+	/* We can only set up the default routes after bringing
+	 * up the interface, sine bringing up the interface adds
+	 * the link-local routes and we can't add a default
+	 * route if the gateway is not reachable. */
+
+	/* setup ipv4 gateway on the interface */
+	if (netdev->ipv4_gateway) {
+		if (!(netdev->flags & IFF_UP)) {
+			ERROR("Cannot add ipv4 gateway for %s when not bringing up the interface", ifname);
+			return -1;
+		}
+
+		if (lxc_list_empty(&netdev->ipv4)) {
+			ERROR("Cannot add ipv4 gateway for %s when not assigning an address", ifname);
+			return -1;
+		}
+
+		err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
+		if (err) {
+			ERROR("failed to setup ipv4 gateway for '%s': %s",
+				      ifname, strerror(-err));
+			return -1;
+		}
+	}
+
+	/* setup ipv6 gateway on the interface */
+	if (netdev->ipv6_gateway) {
+		if (!(netdev->flags & IFF_UP)) {
+			ERROR("Cannot add ipv6 gateway for %s when not bringing up the interface", ifname);
+			return -1;
+		}
+
+		if (lxc_list_empty(&netdev->ipv6) && !IN6_IS_ADDR_LINKLOCAL(netdev->ipv6_gateway)) {
+			ERROR("Cannot add ipv6 gateway for %s when not assigning an address", ifname);
+			return -1;
+		}
+
+		err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
+		if (err) {
+			ERROR("failed to setup ipv6 gateway for '%s': %s",
+				      ifname, strerror(-err));
+			return -1;
+		}
+	}
+
 	DEBUG("'%s' has been setup", current_ifname);
 
 	return 0;
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index 8fd3dd8..328d236 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -114,6 +114,8 @@ struct lxc_netdev {
 	union netdev_p priv;
 	struct lxc_list ipv4;
 	struct lxc_list ipv6;
+	struct in_addr *ipv4_gateway;
+	struct in6_addr *ipv6_gateway;
 	char *upscript;
 };
 
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 8d8d8e5..8e215f8 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -63,8 +63,10 @@ static int config_network_hwaddr(const char *, char *, struct lxc_conf *);
 static int config_network_vlan_id(const char *, char *, struct lxc_conf *);
 static int config_network_mtu(const char *, char *, struct lxc_conf *);
 static int config_network_ipv4(const char *, char *, struct lxc_conf *);
+static int config_network_ipv4_gateway(const char *, char *, struct lxc_conf *);
 static int config_network_script(const char *, char *, struct lxc_conf *);
 static int config_network_ipv6(const char *, char *, struct lxc_conf *);
+static int config_network_ipv6_gateway(const char *, char *, struct lxc_conf *);
 static int config_cap_drop(const char *, char *, struct lxc_conf *);
 static int config_console(const char *, char *, struct lxc_conf *);
 
@@ -96,7 +98,9 @@ static struct config config[] = {
 	{ "lxc.network.hwaddr",       config_network_hwaddr       },
 	{ "lxc.network.mtu",          config_network_mtu          },
 	{ "lxc.network.vlan.id",      config_network_vlan_id      },
+	{ "lxc.network.ipv4.gateway", config_network_ipv4_gateway },
 	{ "lxc.network.ipv4",         config_network_ipv4         },
+	{ "lxc.network.ipv6.gateway", config_network_ipv6_gateway },
 	{ "lxc.network.ipv6",         config_network_ipv6         },
 	{ "lxc.cap.drop",             config_cap_drop             },
 	{ "lxc.console",              config_console              },
@@ -433,6 +437,37 @@ static int config_network_ipv4(const char *key, char *value,
 	return 0;
 }
 
+static int config_network_ipv4_gateway(const char *key, char *value,
+			               struct lxc_conf *lxc_conf)
+{
+	struct lxc_netdev *netdev;
+	struct in_addr *gw;
+
+	netdev = network_netdev(key, value, &lxc_conf->network);
+	if (!netdev)
+		return -1;
+
+	gw = malloc(sizeof(*gw));
+	if (!gw) {
+		SYSERROR("failed to allocate ipv4 gateway address");
+		return -1;
+	}
+
+	if (!value) {
+		ERROR("no ipv4 gateway address specified");
+		return -1;
+	}
+
+	if (!inet_pton(AF_INET, value, gw)) {
+		SYSERROR("invalid ipv4 gateway address: %s", value);
+		return -1;
+	}
+
+	netdev->ipv4_gateway = gw;
+
+	return 0;
+}
+
 static int config_network_ipv6(const char *key, char *value,
 			       struct lxc_conf *lxc_conf)
 {
@@ -480,6 +515,37 @@ static int config_network_ipv6(const char *key, char *value,
 	return 0;
 }
 
+static int config_network_ipv6_gateway(const char *key, char *value,
+			               struct lxc_conf *lxc_conf)
+{
+	struct lxc_netdev *netdev;
+	struct in6_addr *gw;
+
+	netdev = network_netdev(key, value, &lxc_conf->network);
+	if (!netdev)
+		return -1;
+
+	gw = malloc(sizeof(*gw));
+	if (!gw) {
+		SYSERROR("failed to allocate ipv6 gateway address");
+		return -1;
+	}
+
+	if (!value) {
+		ERROR("no ipv6 gateway address specified");
+		return -1;
+	}
+
+	if (!inet_pton(AF_INET6, value, gw)) {
+		SYSERROR("invalid ipv6 gateway address: %s", value);
+		return -1;
+	}
+
+	netdev->ipv6_gateway = gw;
+
+	return 0;
+}
+
 static int config_network_script(const char *key, char *value,
 				 struct lxc_conf *lxc_conf)
 {
diff --git a/src/lxc/network.c b/src/lxc/network.c
index 420117a..b1d60f2 100644
--- a/src/lxc/network.c
+++ b/src/lxc/network.c
@@ -89,6 +89,11 @@ struct ip_req {
 	struct ifaddrmsg ifa;
 };
 
+struct rt_req {
+	struct nlmsg nlmsg;
+	struct rtmsg rt;
+};
+
 int lxc_netdev_move_by_index(int ifindex, pid_t pid)
 {
 	struct nl_handler nlh;
@@ -741,6 +746,71 @@ int lxc_ipv4_addr_add(int ifindex, struct in_addr *addr,
 	return ip_addr_add(AF_INET, ifindex, addr, bcast, NULL, prefix);
 }
 
+static int ip_gateway_add(int family, int ifindex, void *gw)
+{
+	struct nl_handler nlh;
+	struct nlmsg *nlmsg = NULL, *answer = NULL;
+	struct rt_req *rt_req;
+	int addrlen;
+	int err;
+
+	addrlen = family == AF_INET ? sizeof(struct in_addr) :
+		sizeof(struct in6_addr);
+
+	err = netlink_open(&nlh, NETLINK_ROUTE);
+	if (err)
+		return err;
+
+	err = -ENOMEM;
+	nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
+	if (!nlmsg)
+		goto out;
+
+	answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+	if (!answer)
+		goto out;
+
+	rt_req = (struct rt_req *)nlmsg;
+	rt_req->nlmsg.nlmsghdr.nlmsg_len =
+		NLMSG_LENGTH(sizeof(struct rtmsg));
+	rt_req->nlmsg.nlmsghdr.nlmsg_flags =
+		NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL;
+	rt_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWROUTE;
+	rt_req->rt.rtm_family = family;
+	rt_req->rt.rtm_table = RT_TABLE_MAIN;
+	rt_req->rt.rtm_scope = RT_SCOPE_UNIVERSE;
+	rt_req->rt.rtm_protocol = RTPROT_BOOT;
+	rt_req->rt.rtm_type = RTN_UNICAST;
+	/* "default" destination */
+	rt_req->rt.rtm_dst_len = 0;
+
+	err = -EINVAL;
+	if (nla_put_buffer(nlmsg, RTA_GATEWAY, gw, addrlen))
+		goto out;
+
+	/* Adding the interface index enables the use of link-local
+	 * addresses for the gateway */
+	if (nla_put_u32(nlmsg, RTA_OIF, ifindex))
+		goto out;
+
+	err = netlink_transaction(&nlh, nlmsg, answer);
+out:
+	netlink_close(&nlh);
+	nlmsg_free(answer);
+	nlmsg_free(nlmsg);
+	return err;
+}
+
+int lxc_ipv4_gateway_add(int ifindex, struct in_addr *gw)
+{
+	return ip_gateway_add(AF_INET, ifindex, gw);
+}
+
+int lxc_ipv6_gateway_add(int ifindex, struct in6_addr *gw)
+{
+	return ip_gateway_add(AF_INET6, ifindex, gw);
+}
+
 /*
  * There is a lxc_bridge_attach, but no need of a bridge detach
  * as automatically done by kernel when a netdev is deleted.
diff --git a/src/lxc/network.h b/src/lxc/network.h
index 0d6eb4c..5a1fd50 100644
--- a/src/lxc/network.h
+++ b/src/lxc/network.h
@@ -84,6 +84,12 @@ extern int lxc_ipv4_addr_add(int ifindex, struct in_addr *addr,
 			     struct in_addr *bcast, int prefix);
 
 /*
+ * Set default route.
+ */
+extern int lxc_ipv4_gateway_add(int ifindex, struct in_addr *gw);
+extern int lxc_ipv6_gateway_add(int ifindex, struct in6_addr *gw);
+
+/*
  * Attach an interface to the bridge
  */
 extern int lxc_bridge_attach(const char *bridge, const char *ifname);
-- 
1.7.7


From 19a26f82145042062cb2b11292622efb3ccac37f Mon Sep 17 00:00:00 2001
From: Matthijs Kooijman <matthijs@stdin.nl>
Date: Tue, 30 Aug 2011 23:50:23 +0200
Subject: [PATCH 2/3] add autodetection of the gateway address

For veth and macvlan networks, this can look up the host address on the
bridge (link) interface and add a default route on the guest to that
address. This facilitates a typical setup where guests are bridged
together.

syntax:
	lxc.ipv4.gateway = auto
	lxc.ipv6.gateway = auto

Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
---
 src/lxc/conf.c    |   58 ++++++++++++++++++++
 src/lxc/conf.h    |    4 ++
 src/lxc/confile.c |   32 ++++++++----
 src/lxc/network.c |  157 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/lxc/network.h |    6 ++
 src/lxc/start.c   |   10 ++++
 6 files changed, 257 insertions(+), 10 deletions(-)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 751dce0..613e476 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -1342,6 +1342,11 @@ static int setup_netdev(struct lxc_netdev *netdev)
 		if (err) {
 			ERROR("failed to setup ipv4 gateway for '%s': %s",
 				      ifname, strerror(-err));
+			if (netdev->ipv4_gateway_auto) {
+				char buf[INET_ADDRSTRLEN];
+				inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf));
+				ERROR("tried to set autodetected ipv4 gateway '%s'", buf);
+			}
 			return -1;
 		}
 	}
@@ -1362,6 +1367,11 @@ static int setup_netdev(struct lxc_netdev *netdev)
 		if (err) {
 			ERROR("failed to setup ipv6 gateway for '%s': %s",
 				      ifname, strerror(-err));
+			if (netdev->ipv6_gateway_auto) {
+				char buf[INET6_ADDRSTRLEN];
+				inet_ntop(AF_INET, netdev->ipv6_gateway, buf, sizeof(buf));
+				ERROR("tried to set autodetected ipv6 gateway '%s'", buf);
+			}
 			return -1;
 		}
 	}
@@ -1684,6 +1694,54 @@ int lxc_assign_network(struct lxc_list *network, pid_t pid)
 	return 0;
 }
 
+int lxc_find_gateway_addresses(struct lxc_handler *handler)
+{
+	struct lxc_list *network = &handler->conf->network;
+	struct lxc_list *iterator;
+	struct lxc_netdev *netdev;
+	int link_index;
+
+	lxc_list_for_each(iterator, network) {
+		netdev = iterator->elem;
+
+		if (!netdev->ipv4_gateway_auto && !netdev->ipv6_gateway_auto)
+			continue;
+
+		if (netdev->type != LXC_NET_VETH && netdev->type != LXC_NET_MACVLAN) {
+			ERROR("gateway = auto only supported for "
+			      "veth and macvlan");
+			return -1;
+		}
+
+		if (!netdev->link) {
+			ERROR("gateway = auto needs a link interface");
+			return -1;
+		}
+
+		link_index = if_nametoindex(netdev->link);
+		if (!link_index)
+			return -EINVAL;
+
+		if (netdev->ipv4_gateway_auto) {
+			if (lxc_ipv4_addr_get(link_index, &netdev->ipv4_gateway)) {
+				ERROR("failed to automatically find ipv4 gateway "
+				      "address from link interface '%s'", netdev->link);
+				return -1;
+			}
+		}
+
+		if (netdev->ipv6_gateway_auto) {
+			if (lxc_ipv6_addr_get(link_index, &netdev->ipv6_gateway)) {
+				ERROR("failed to automatically find ipv6 gateway "
+				      "address from link interface '%s'", netdev->link);
+				return -1;
+			}
+		}
+	}
+
+	return 0;
+}
+
 int lxc_create_tty(const char *name, struct lxc_conf *conf)
 {
 	struct lxc_tty_info *tty_info = &conf->tty_info;
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index 328d236..973f694 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -25,6 +25,7 @@
 
 #include <netinet/in.h>
 #include <sys/param.h>
+#include <stdbool.h>
 
 #include <lxc/list.h>
 
@@ -115,7 +116,9 @@ struct lxc_netdev {
 	struct lxc_list ipv4;
 	struct lxc_list ipv6;
 	struct in_addr *ipv4_gateway;
+	bool ipv4_gateway_auto;
 	struct in6_addr *ipv6_gateway;
+	bool ipv6_gateway_auto;
 	char *upscript;
 };
 
@@ -219,6 +222,7 @@ extern struct lxc_conf *lxc_conf_init(void);
 extern int lxc_create_network(struct lxc_handler *handler);
 extern void lxc_delete_network(struct lxc_list *networks);
 extern int lxc_assign_network(struct lxc_list *networks, pid_t pid);
+extern int lxc_find_gateway_addresses(struct lxc_handler *handler);
 
 extern int lxc_create_tty(const char *name, struct lxc_conf *conf);
 extern void lxc_delete_tty(struct lxc_tty_info *tty_info);
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 8e215f8..550102c 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -458,12 +458,18 @@ static int config_network_ipv4_gateway(const char *key, char *value,
 		return -1;
 	}
 
-	if (!inet_pton(AF_INET, value, gw)) {
-		SYSERROR("invalid ipv4 gateway address: %s", value);
-		return -1;
-	}
+	if (!strcmp(value, "auto")) {
+		netdev->ipv4_gateway = NULL;
+		netdev->ipv4_gateway_auto = true;
+	} else {
+		if (!inet_pton(AF_INET, value, gw)) {
+			SYSERROR("invalid ipv4 gateway address: %s", value);
+			return -1;
+		}
 
-	netdev->ipv4_gateway = gw;
+		netdev->ipv4_gateway = gw;
+		netdev->ipv4_gateway_auto = false;
+	}
 
 	return 0;
 }
@@ -536,12 +542,18 @@ static int config_network_ipv6_gateway(const char *key, char *value,
 		return -1;
 	}
 
-	if (!inet_pton(AF_INET6, value, gw)) {
-		SYSERROR("invalid ipv6 gateway address: %s", value);
-		return -1;
-	}
+	if (!strcmp(value, "auto")) {
+		netdev->ipv6_gateway = NULL;
+		netdev->ipv6_gateway_auto = true;
+	} else {
+		if (!inet_pton(AF_INET6, value, gw)) {
+			SYSERROR("invalid ipv6 gateway address: %s", value);
+			return -1;
+		}
 
-	netdev->ipv6_gateway = gw;
+		netdev->ipv6_gateway = gw;
+		netdev->ipv6_gateway_auto = false;
+	}
 
 	return 0;
 }
diff --git a/src/lxc/network.c b/src/lxc/network.c
index b1d60f2..5110ca7 100644
--- a/src/lxc/network.c
+++ b/src/lxc/network.c
@@ -746,6 +746,163 @@ int lxc_ipv4_addr_add(int ifindex, struct in_addr *addr,
 	return ip_addr_add(AF_INET, ifindex, addr, bcast, NULL, prefix);
 }
 
+/* Find an IFA_LOCAL (or IFA_ADDRESS if not IFA_LOCAL is present)
+ * address from the given RTM_NEWADDR message.  Allocates memory for the
+ * address and stores that pointer in *res (so res should be an
+ * in_addr** or in6_addr**).
+ */
+static int ifa_get_local_ip(int family, struct ip_req *ip_info, void** res) {
+	struct rtattr *rta = IFA_RTA(&ip_info->ifa);
+	int attr_len = IFA_PAYLOAD(&ip_info->nlmsg.nlmsghdr);
+	int addrlen;
+
+	if (ip_info->ifa.ifa_family != family)
+		return 0;
+
+	addrlen = family == AF_INET ? sizeof(struct in_addr) :
+		sizeof(struct in6_addr);
+
+	/* Loop over the rtattr's in this message */
+	while(RTA_OK(rta, attr_len)) {
+		/* Found a local address for the requested interface,
+		 * return it. */
+		if (rta->rta_type == IFA_LOCAL || rta->rta_type == IFA_ADDRESS) {
+			/* Sanity check. The family check above should
+			 * make sure the address length is correct, but
+			 * check here just in case */
+			if (RTA_PAYLOAD(rta) != addrlen)
+				return -1;
+
+			/* We might have found an IFA_ADDRESS before,
+			 * which we now overwrite with an IFA_LOCAL. */
+			if (!*res)
+				*res = malloc(addrlen);
+
+			memcpy(*res, RTA_DATA(rta), addrlen);
+
+			if (rta->rta_type == IFA_LOCAL)
+				break;
+		}
+		rta = RTA_NEXT(rta, attr_len);
+	}
+	return 0;
+}
+
+static int ip_addr_get(int family, int ifindex, void **res)
+{
+	struct nl_handler nlh;
+	struct nlmsg *nlmsg = NULL, *answer = NULL;
+	struct ip_req *ip_req, *ip_info;
+	struct nlmsghdr *msg;
+	int err;
+	int recv_len = 0, answer_len;
+	int readmore = 0;
+
+	err = netlink_open(&nlh, NETLINK_ROUTE);
+	if (err)
+		return err;
+
+	err = -ENOMEM;
+	nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
+	if (!nlmsg)
+		goto out;
+
+	answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+	if (!answer)
+		goto out;
+
+	/* Save the answer buffer length, since it will be overwritten
+	 * on the first receive (and we might need to receive more than
+	 * once. */
+	answer_len = answer->nlmsghdr.nlmsg_len;
+
+	ip_req = (struct ip_req *)nlmsg;
+	ip_req->nlmsg.nlmsghdr.nlmsg_len =
+		NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+	ip_req->nlmsg.nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ROOT;
+	ip_req->nlmsg.nlmsghdr.nlmsg_type = RTM_GETADDR;
+	ip_req->ifa.ifa_family = family;
+
+	/* Send the request for addresses, which returns all addresses
+	 * on all interfaces. */
+	err = netlink_send(&nlh, nlmsg);
+	if (err < 0)
+		goto out;
+	err = 0;
+
+	do {
+		/* Restore the answer buffer length, it might have been
+		 * overwritten by a previous receive. */
+		answer->nlmsghdr.nlmsg_len = answer_len;
+
+		/* Get the (next) batch of reply messages */
+		err = netlink_rcv(&nlh, answer);
+		if (err < 0)
+			goto out;
+
+		recv_len = err;
+		err = 0;
+
+		/* Satisfy the typing for the netlink macros */
+		msg = &answer->nlmsghdr;
+
+		while (NLMSG_OK(msg, recv_len)) {
+			/* Stop reading if we see an error message */
+			if (msg->nlmsg_type == NLMSG_ERROR) {
+				struct nlmsgerr *errmsg = (struct nlmsgerr*)NLMSG_DATA(msg);
+				err = errmsg->error;
+				goto out;
+			}
+
+			/* Stop reading if we see a NLMSG_DONE message */
+			if (msg->nlmsg_type == NLMSG_DONE) {
+				readmore = 0;
+				break;
+			}
+
+			if (msg->nlmsg_type != RTM_NEWADDR) {
+				err = -1;
+				goto out;
+			}
+
+			ip_info = (struct ip_req *)msg;
+			if (ip_info->ifa.ifa_index == ifindex) {
+				ifa_get_local_ip(family, ip_info, res);
+				/* Found a result, stop searching */
+				if (*res)
+					goto out;
+			}
+
+			/* Keep reading more data from the socket if the
+			 * last message had the NLF_F_MULTI flag set */
+			readmore = (msg->nlmsg_flags & NLM_F_MULTI);
+
+			/* Look at the next message received in this buffer */
+			msg = NLMSG_NEXT(msg, recv_len);
+		}
+	} while (readmore);
+
+	/* If we end up here, we didn't find any result, so signal an
+	 * error */
+	err = -1;
+
+out:
+	netlink_close(&nlh);
+	nlmsg_free(answer);
+	nlmsg_free(nlmsg);
+	return err;
+}
+
+int lxc_ipv6_addr_get(int ifindex, struct in6_addr **res)
+{
+	return ip_addr_get(AF_INET6, ifindex, (void**)res);
+}
+
+int lxc_ipv4_addr_get(int ifindex, struct in_addr** res)
+{
+	return ip_addr_get(AF_INET, ifindex, (void**)res);
+}
+
 static int ip_gateway_add(int family, int ifindex, void *gw)
 {
 	struct nl_handler nlh;
diff --git a/src/lxc/network.h b/src/lxc/network.h
index 5a1fd50..0fd5e5d 100644
--- a/src/lxc/network.h
+++ b/src/lxc/network.h
@@ -84,6 +84,12 @@ extern int lxc_ipv4_addr_add(int ifindex, struct in_addr *addr,
 			     struct in_addr *bcast, int prefix);
 
 /*
+ * Get ip address
+ */
+extern int lxc_ipv4_addr_get(int ifindex, struct in_addr **res);
+extern int lxc_ipv6_addr_get(int ifindex, struct in6_addr **res);
+
+/*
  * Set default route.
  */
 extern int lxc_ipv4_gateway_add(int ifindex, struct in_addr *gw);
diff --git a/src/lxc/start.c b/src/lxc/start.c
index b8ceff6..6737a44 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -483,6 +483,16 @@ int lxc_spawn(struct lxc_handler *handler)
 
 		clone_flags |= CLONE_NEWNET;
 
+		/* Find gateway addresses from the link device, which is
+		 * no longer accessible inside the container. Do this
+		 * before creating network interfaces, since goto
+		 * out_delete_net does not work before lxc_clone. */
+		if (lxc_find_gateway_addresses(handler)) {
+			ERROR("failed to find gateway addresses");
+			lxc_sync_fini(handler);
+			return -1;
+		}
+
 		/* that should be done before the clone because we will
 		 * fill the netdev index and use them in the child
 		 */
-- 
1.7.7


From be58c6b5b4110a3136f26b69394de725a4318619 Mon Sep 17 00:00:00 2001
From: Matthijs Kooijman <matthijs@stdin.nl>
Date: Tue, 30 Aug 2011 23:50:23 +0200
Subject: [PATCH 3/3] .gateway options

Man for the gateway option.

Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
---
 doc/lxc.conf.sgml.in |   43 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 43 insertions(+), 0 deletions(-)

diff --git a/doc/lxc.conf.sgml.in b/doc/lxc.conf.sgml.in
index cfaa686..532739e 100644
--- a/doc/lxc.conf.sgml.in
+++ b/doc/lxc.conf.sgml.in
@@ -300,6 +300,28 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
 	<varlistentry>
 	  <term>
+	    <option>lxc.network.ipv4.gateway</option>
+	  </term>
+	  <listitem>
+	    <para>
+	      specify the ipv4 address to use as the gateway inside the
+	      container. The address is in format x.y.z.t, eg.
+	      192.168.1.123.
+
+	      Can also have the special value <option>auto</option>,
+	      which means to take the primary address from the bridge
+	      interface (as specified by the
+	      <option>lxc.network.link</option> option) and use that as
+	      the gateway. <option>auto</option> is only available when
+	      using the <option>veth</option> and
+	      <option>macvlan</option> network types.
+	    </para>
+	  </listitem>
+	</varlistentry>
+
+
+	<varlistentry>
+	  <term>
 	    <option>lxc.network.ipv6</option>
 	  </term>
 	  <listitem>
@@ -314,6 +336,27 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
 	<varlistentry>
 	  <term>
+	    <option>lxc.network.ipv6.gateway</option>
+	  </term>
+	  <listitem>
+	    <para>
+	      specify the ipv6 address to use as the gateway inside the
+	      container. The address is in format x::y,
+	      eg. 2003:db8:1:0::1
+
+	      Can also have the special value <option>auto</option>,
+	      which means to take the primary address from the bridge
+	      interface (as specified by the
+	      <option>lxc.network.link</option> option) and use that as
+	      the gateway. <option>auto</option> is only available when
+	      using the <option>veth</option> and
+	      <option>macvlan</option> network types.
+	    </para>
+	  </listitem>
+	</varlistentry>
+
+	<varlistentry>
+	  <term>
 	    <option>lxc.network.script.up</option>
 	  </term>
 	  <listitem>
-- 
1.7.7

