[lxc-devel] [lxc/master] network: Adds gateway device route mode

tomponline on Github lxc-bot at linuxcontainers.org
Fri May 3 09:24:16 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 474 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190503/2c848fdf/attachment.bin>
-------------- next part --------------
From 9bb8418878be31796ee1dca7cd3e7f07de45e05d Mon Sep 17 00:00:00 2001
From: tomponline <thomas.parrott at canonical.com>
Date: Fri, 3 May 2019 10:21:45 +0100
Subject: [PATCH] network: Adds gateway device route mode

Adds ability to specify "dev" as the gateway value, which will cause a device route to be set as default gateway.

Signed-off-by: tomponline <thomas.parrott at canonical.com>
---
 doc/api-extensions.md         |  7 +++
 src/lxc/api_extensions.h      |  1 +
 src/lxc/confile.c             | 16 +++++-
 src/lxc/confile_utils.c       |  6 +++
 src/lxc/network.c             | 98 ++++++++++++++++++++++-------------
 src/lxc/network.h             |  4 ++
 src/tests/parse_config_file.c | 40 ++++++++++++++
 7 files changed, 133 insertions(+), 39 deletions(-)

diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index d5a0a3af74..6ec6e5a181 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -65,3 +65,10 @@ lxc.net[i].ipvlan.isolation=[bridge|private|vepa] (defaults to bridge)
 lxc.net[i].link=eth0
 lxc.net[i].flags=up
 ```
+
+## network\_gateway\_device\_route
+
+This introduces the ability to specify `lxc.net.[i].veth.ipv4.gateway` and/or
+`lxc.net.[i].veth.ipv6.gateway` with a value of `dev` which will cause the default gateway
+inside the container to be created as a device route without destination gateway IP needed.
+This is primarily intended for use with layer 3 networking devices, such as IPVLAN.
diff --git a/src/lxc/api_extensions.h b/src/lxc/api_extensions.h
index 55d5e9c96e..086977c987 100644
--- a/src/lxc/api_extensions.h
+++ b/src/lxc/api_extensions.h
@@ -46,6 +46,7 @@ static char *api_extensions[] = {
 	"seccomp_notify",
 	"network_veth_routes",
 	"network_ipvlan",
+	"network_gateway_device_route",
 };
 
 static size_t nr_api_extensions = sizeof(api_extensions) / sizeof(*api_extensions);
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index ac7e78eb1b..857fd0c154 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -655,9 +655,13 @@ static int set_config_net_ipv4_gateway(const char *key, const char *value,
 
 	free(netdev->ipv4_gateway);
 
-	if (!strcmp(value, "auto")) {
+	if (strcmp(value, "auto") == 0) {
 		netdev->ipv4_gateway = NULL;
 		netdev->ipv4_gateway_auto = true;
+	} else if (strcmp(value, "dev") == 0) {
+		netdev->ipv4_gateway = NULL;
+		netdev->ipv4_gateway_auto = false;
+		netdev->ipv4_gateway_dev = true;
 	} else {
 		int ret;
 		struct in_addr *gw;
@@ -822,9 +826,13 @@ static int set_config_net_ipv6_gateway(const char *key, const char *value,
 
 	free(netdev->ipv6_gateway);
 
-	if (!strcmp(value, "auto")) {
+	if (strcmp(value, "auto") == 0) {
 		netdev->ipv6_gateway = NULL;
 		netdev->ipv6_gateway_auto = true;
+	} else if (strcmp(value, "dev") == 0) {
+		netdev->ipv6_gateway = NULL;
+		netdev->ipv6_gateway_auto = false;
+		netdev->ipv6_gateway_dev = true;
 	} else {
 		int ret;
 		struct in6_addr *gw;
@@ -5574,6 +5582,8 @@ static int get_config_net_ipv4_gateway(const char *key, char *retv, int inlen,
 
 	if (netdev->ipv4_gateway_auto) {
 		strprint(retv, inlen, "auto");
+	} else if (netdev->ipv4_gateway_dev) {
+		strprint(retv, inlen, "dev");
 	} else if (netdev->ipv4_gateway) {
 		inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf));
 		strprint(retv, inlen, "%s", buf);
@@ -5663,6 +5673,8 @@ static int get_config_net_ipv6_gateway(const char *key, char *retv, int inlen,
 
 	if (netdev->ipv6_gateway_auto) {
 		strprint(retv, inlen, "auto");
+	} else if (netdev->ipv6_gateway_dev) {
+		strprint(retv, inlen, "dev");
 	} else if (netdev->ipv6_gateway) {
 		inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
 		strprint(retv, inlen, "%s", buf);
diff --git a/src/lxc/confile_utils.c b/src/lxc/confile_utils.c
index a43b165ba1..b7d006df3e 100644
--- a/src/lxc/confile_utils.c
+++ b/src/lxc/confile_utils.c
@@ -357,6 +357,9 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
 			TRACE("ipv4 gateway auto: %s",
 			      netdev->ipv4_gateway_auto ? "true" : "false");
 
+			TRACE("ipv4 gateway dev: %s",
+			      netdev->ipv4_gateway_dev ? "true" : "false");
+
 			if (netdev->ipv4_gateway) {
 				inet_ntop(AF_INET, netdev->ipv4_gateway,
 					  bufinet4, sizeof(bufinet4));
@@ -373,6 +376,9 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
 			TRACE("ipv6 gateway auto: %s",
 			      netdev->ipv6_gateway_auto ? "true" : "false");
 
+			TRACE("ipv6 gateway dev: %s",
+			      netdev->ipv6_gateway_dev ? "true" : "false");
+
 			if (netdev->ipv6_gateway) {
 				inet_ntop(AF_INET6, netdev->ipv6_gateway,
 					  bufinet6, sizeof(bufinet6));
diff --git a/src/lxc/network.c b/src/lxc/network.c
index def484613d..0ac7695d30 100644
--- a/src/lxc/network.c
+++ b/src/lxc/network.c
@@ -2027,8 +2027,12 @@ static int ip_gateway_add(int family, int ifindex, void *gw)
 	rt->rtm_dst_len = 0;
 
 	err = -EINVAL;
-	if (nla_put_buffer(nlmsg, RTA_GATEWAY, gw, addrlen))
-		goto out;
+
+	/* If no gateway address is supplied, setup a device route instead */
+	if (gw != NULL) {
+		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.
@@ -3182,12 +3186,12 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
 	}
 
 	/* We can only set up the default routes after bringing
-	 * up the interface, sine bringing up the interface adds
+	 * up the interface, since 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->ipv4_gateway || netdev->ipv4_gateway_dev) {
 		if (!(netdev->flags & IFF_UP)) {
 			ERROR("Cannot add ipv4 gateway for network device "
 			      "\"%s\" when not bringing up the interface", ifname);
@@ -3200,33 +3204,43 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
 			return -1;
 		}
 
-		err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
-		if (err) {
-			err = lxc_ipv4_dest_add(netdev->ifindex, netdev->ipv4_gateway, 32);
-			if (err) {
-				errno = -err;
-				SYSERROR("Failed to add ipv4 dest for network device \"%s\"",
+		/* Setup device route if ipv4_gateway_dev is enabled */
+		if (netdev->ipv4_gateway_dev) {
+			err = lxc_ipv4_gateway_add(netdev->ifindex, NULL);
+			if (err < 0) {
+				SYSERROR("Failed to setup ipv4 gateway to network device \"%s\"",
 				         ifname);
+				return minus_one_set_errno(-err);
 			}
-
+		} else {
 			err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
 			if (err) {
-				errno = -err;
-				SYSERROR("Failed to setup ipv4 gateway for network device \"%s\"",
-				         ifname);
+				err = lxc_ipv4_dest_add(netdev->ifindex, netdev->ipv4_gateway, 32);
+				if (err) {
+					errno = -err;
+					SYSERROR("Failed to add ipv4 dest for network device \"%s\"",
+						ifname);
+				}
+
+				err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
+				if (err) {
+					errno = -err;
+					SYSERROR("Failed to setup ipv4 gateway for network device \"%s\"",
+						ifname);
 
-				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);
+					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;
 				}
-				return -1;
 			}
 		}
 	}
 
 	/* setup ipv6 gateway on the interface */
-	if (netdev->ipv6_gateway) {
+	if (netdev->ipv6_gateway || netdev->ipv6_gateway_dev) {
 		if (!(netdev->flags & IFF_UP)) {
 			ERROR("Cannot add ipv6 gateway for network device "
 			      "\"%s\" when not bringing up the interface", ifname);
@@ -3239,29 +3253,39 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
 			return -1;
 		}
 
-		err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
-		if (err) {
-			err = lxc_ipv6_dest_add(netdev->ifindex, netdev->ipv6_gateway, 128);
-			if (err) {
-				errno = -err;
-				SYSERROR("Failed to add ipv6 dest for network device \"%s\"",
+		/* Setup device route if ipv6_gateway_dev is enabled */
+		if (netdev->ipv6_gateway_dev) {
+			err = lxc_ipv6_gateway_add(netdev->ifindex, NULL);
+			if (err < 0) {
+				SYSERROR("Failed to setup ipv6 gateway to network device \"%s\"",
 				         ifname);
+				return minus_one_set_errno(-err);
 			}
-
+		} else {
 			err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
 			if (err) {
-				errno = -err;
-				SYSERROR("Failed to setup ipv6 gateway for network device \"%s\"",
-				         ifname);
+				err = lxc_ipv6_dest_add(netdev->ifindex, netdev->ipv6_gateway, 128);
+				if (err) {
+					errno = -err;
+					SYSERROR("Failed to add ipv6 dest for network device \"%s\"",
+						ifname);
+				}
 
-				if (netdev->ipv6_gateway_auto) {
-					char buf[INET6_ADDRSTRLEN];
-					inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
-					ERROR("Tried to set autodetected ipv6 "
-					      "gateway for network device "
-					      "\"%s\"", buf);
+				err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
+				if (err) {
+					errno = -err;
+					SYSERROR("Failed to setup ipv6 gateway for network device \"%s\"",
+						ifname);
+
+					if (netdev->ipv6_gateway_auto) {
+						char buf[INET6_ADDRSTRLEN];
+						inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
+						ERROR("Tried to set autodetected ipv6 "
+						"gateway for network device "
+						"\"%s\"", buf);
+					}
+					return -1;
 				}
-				return -1;
 			}
 		}
 	}
diff --git a/src/lxc/network.h b/src/lxc/network.h
index fa80404bc2..e60d30d191 100644
--- a/src/lxc/network.h
+++ b/src/lxc/network.h
@@ -156,9 +156,11 @@ union netdev_p {
  * @ipv6              : a list of ipv6 addresses to be set on the network device
  * @ipv4_gateway_auto : whether the ipv4 gateway is to be automatically gathered
  *                      from the associated @link
+ * @ipv4_gateway_dev  : whether the ipv4 gateway is to be set as a device route
  * @ipv4_gateway      : ipv4 gateway
  * @ipv6_gateway_auto : whether the ipv6 gateway is to be automatically gathered
  *                      from the associated @link
+ * @ipv6_gateway_dev  : whether the ipv6 gateway is to be set as a device route
  * @ipv6_gateway      : ipv6 gateway
  * @upscript          : a script filename to be executed during interface
  *                      configuration
@@ -178,8 +180,10 @@ struct lxc_netdev {
 	struct lxc_list ipv4;
 	struct lxc_list ipv6;
 	bool ipv4_gateway_auto;
+	bool ipv4_gateway_dev;
 	struct in_addr *ipv4_gateway;
 	bool ipv6_gateway_auto;
+	bool ipv6_gateway_dev;
 	struct in6_addr *ipv6_gateway;
 	char *upscript;
 	char *downscript;
diff --git a/src/tests/parse_config_file.c b/src/tests/parse_config_file.c
index ad17867b43..bc68ae24cc 100644
--- a/src/tests/parse_config_file.c
+++ b/src/tests/parse_config_file.c
@@ -108,6 +108,16 @@ static int set_and_clear_complete_netdev(struct lxc_container *c)
 		return -1;
 	}
 
+	if (!c->set_config_item(c, "lxc.net.1.ipv4.gateway", "auto")) {
+		lxc_error("%s\n", "lxc.net.1.ipv4.gateway");
+		return -1;
+	}
+
+	if (!c->set_config_item(c, "lxc.net.1.ipv4.gateway", "dev")) {
+		lxc_error("%s\n", "lxc.net.1.ipv4.gateway");
+		return -1;
+	}
+
 	if (!c->set_config_item(c, "lxc.net.1.ipv6.address",
 				"2003:db8:1:0:214:1234:fe0b:3596/64")) {
 		lxc_error("%s\n", "lxc.net.1.ipv6.address");
@@ -120,6 +130,16 @@ static int set_and_clear_complete_netdev(struct lxc_container *c)
 		return -1;
 	}
 
+	if (!c->set_config_item(c, "lxc.net.1.ipv6.gateway", "auto")) {
+		lxc_error("%s\n", "lxc.net.1.ipv6.gateway");
+		return -1;
+	}
+
+	if (!c->set_config_item(c, "lxc.net.1.ipv6.gateway", "dev")) {
+		lxc_error("%s\n", "lxc.net.1.ipv6.gateway");
+		return -1;
+	}
+
 	if (!c->set_config_item(c, "lxc.net.1.flags", "up")) {
 		lxc_error("%s\n", "lxc.net.1.flags");
 		return -1;
@@ -781,11 +801,31 @@ int main(int argc, char *argv[])
 		goto non_test_error;
 	}
 
+	if (set_get_compare_clear_save_load(c, "lxc.net.0.ipv4.gateway", "auto", tmpf, true)) {
+		lxc_error("%s\n", "lxc.net.0.ipv4.gateway");
+		goto non_test_error;
+	}
+
+	if (set_get_compare_clear_save_load(c, "lxc.net.0.ipv4.gateway", "dev", tmpf, true)) {
+		lxc_error("%s\n", "lxc.net.0.ipv4.gateway");
+		goto non_test_error;
+	}
+
 	if (set_get_compare_clear_save_load(c, "lxc.net.0.ipv6.gateway", "2003:db8:1::1", tmpf, true)) {
 		lxc_error("%s\n", "lxc.net.0.ipv6.gateway");
 		goto non_test_error;
 	}
 
+	if (set_get_compare_clear_save_load(c, "lxc.net.0.ipv6.gateway", "auto", tmpf, true)) {
+		lxc_error("%s\n", "lxc.net.0.ipv6.gateway");
+		goto non_test_error;
+	}
+
+	if (set_get_compare_clear_save_load(c, "lxc.net.0.ipv6.gateway", "dev", tmpf, true)) {
+		lxc_error("%s\n", "lxc.net.0.ipv6.gateway");
+		goto non_test_error;
+	}
+
 	if (set_get_compare_clear_save_load(c, "lxc.net.0.ipv4.address", "10.0.2.3/24", tmpf, true)) {
 		lxc_error("%s\n", "lxc.net.0.ipv4.address");
 		goto non_test_error;


More information about the lxc-devel mailing list