[lxc-devel] [lxc/master] Adds veth router mode

tomponline on Github lxc-bot at linuxcontainers.org
Thu Mar 28 18:24:00 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 2880 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190328/70c510de/attachment.bin>
-------------- next part --------------
From 3403de1d9be44818f50428c8a8ec08baec7bd10f Mon Sep 17 00:00:00 2001
From: tomponline <tomp at tomp.uk>
Date: Tue, 26 Mar 2019 12:31:30 +0000
Subject: [PATCH 1/6] network: Adds mode param (bridge, routed) to veth network
 setting, defaulting to bridge.

Signed-off-by: tomponline <tomp at tomp.uk>
---
 src/lxc/confile.c       | 71 +++++++++++++++++++++++++++++++++++++++++
 src/lxc/confile_utils.c | 24 ++++++++++++++
 src/lxc/confile_utils.h |  1 +
 src/lxc/macro.h         |  8 +++++
 src/lxc/network.h       |  1 +
 5 files changed, 105 insertions(+)

diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 8f94635d1b..c31431a8b2 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -135,6 +135,7 @@ lxc_config_define(net_nic);
 lxc_config_define(net_script_down);
 lxc_config_define(net_script_up);
 lxc_config_define(net_type);
+lxc_config_define(net_veth_mode);
 lxc_config_define(net_veth_pair);
 lxc_config_define(net_vlan_id);
 lxc_config_define(no_new_privs);
@@ -223,6 +224,7 @@ static struct lxc_config_t config_jump_table[] = {
 	{ "lxc.net.script.up",             set_config_net_script_up,               get_config_net_script_up,               clr_config_net_script_up,             },
 	{ "lxc.net.type",                  set_config_net_type,                    get_config_net_type,                    clr_config_net_type,                  },
 	{ "lxc.net.vlan.id",               set_config_net_vlan_id,                 get_config_net_vlan_id,                 clr_config_net_vlan_id,               },
+	{ "lxc.net.veth.mode",             set_config_net_veth_mode,               get_config_net_veth_mode,               clr_config_net_veth_mode,             },
 	{ "lxc.net.veth.pair",             set_config_net_veth_pair,               get_config_net_veth_pair,               clr_config_net_veth_pair,             },
 	{ "lxc.net.",                      set_config_net_nic,                     get_config_net_nic,                     clr_config_net_nic,                   },
 	{ "lxc.net",                       set_config_net,                         get_config_net,                         clr_config_net,                       },
@@ -286,6 +288,8 @@ static int set_config_net_type(const char *key, const char *value,
 
 	if (!strcmp(value, "veth")) {
 		netdev->type = LXC_NET_VETH;
+		lxc_veth_mode_to_flag(&netdev->priv.veth_attr.mode,
+					 "bridge");
 	} else if (!strcmp(value, "macvlan")) {
 		netdev->type = LXC_NET_MACVLAN;
 		lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode,
@@ -401,6 +405,21 @@ static int set_config_net_name(const char *key, const char *value,
 	return network_ifname(netdev->name, value, sizeof(netdev->name));
 }
 
+
+static int set_config_net_veth_mode(const char *key, const char *value,
+				       struct lxc_conf *lxc_conf, void *data)
+{
+	struct lxc_netdev *netdev = data;
+
+	if (lxc_config_value_empty(value))
+		return clr_config_net_veth_mode(key, lxc_conf, data);
+
+	if (!netdev)
+		return -1;
+
+	return lxc_veth_mode_to_flag(&netdev->priv.veth_attr.mode, value);
+}
+
 static int set_config_net_veth_pair(const char *key, const char *value,
 				    struct lxc_conf *lxc_conf, void *data)
 {
@@ -4734,6 +4753,22 @@ static int clr_config_net_macvlan_mode(const char *key,
 	return 0;
 }
 
+static int clr_config_net_veth_mode(const char *key,
+				       struct lxc_conf *lxc_conf, void *data)
+{
+	struct lxc_netdev *netdev = data;
+
+	if (!netdev)
+		return -1;
+
+	if (netdev->type != LXC_NET_VETH)
+		return 0;
+
+	netdev->priv.veth_attr.mode = -1;
+
+	return 0;
+}
+
 static int clr_config_net_veth_pair(const char *key, struct lxc_conf *lxc_conf,
 				    void *data)
 {
@@ -5035,6 +5070,42 @@ static int get_config_net_macvlan_mode(const char *key, char *retv, int inlen,
 	return fulllen;
 }
 
+static int get_config_net_veth_mode(const char *key, char *retv, int inlen,
+				       struct lxc_conf *c, void *data)
+{
+	int len;
+	int fulllen = 0;
+	const char *mode;
+	struct lxc_netdev *netdev = data;
+
+	if (!retv)
+		inlen = 0;
+	else
+		memset(retv, 0, inlen);
+
+	if (!netdev)
+		return -1;
+
+	if (netdev->type != LXC_NET_VETH)
+		return 0;
+
+	switch (netdev->priv.veth_attr.mode) {
+	case VETH_MODE_BRIDGE:
+		mode = "bridge";
+		break;
+	case VETH_MODE_ROUTED:
+		mode = "routed";
+		break;
+	default:
+		mode = "(invalid)";
+		break;
+	}
+
+	strprint(retv, inlen, "%s", mode);
+
+	return fulllen;
+}
+
 static int get_config_net_veth_pair(const char *key, char *retv, int inlen,
 				    struct lxc_conf *c, void *data)
 {
diff --git a/src/lxc/confile_utils.c b/src/lxc/confile_utils.c
index 50777c4481..6dcd72b48c 100644
--- a/src/lxc/confile_utils.c
+++ b/src/lxc/confile_utils.c
@@ -444,6 +444,30 @@ void lxc_free_networks(struct lxc_list *networks)
 	lxc_list_init(networks);
 }
 
+
+static struct lxc_veth_mode {
+	char *name;
+	int mode;
+} veth_mode[] = {
+    { "bridge", VETH_MODE_BRIDGE },
+    { "routed", VETH_MODE_ROUTED },
+};
+
+int lxc_veth_mode_to_flag(int *mode, const char *value)
+{
+	size_t i;
+
+	for (i = 0; i < sizeof(veth_mode) / sizeof(veth_mode[0]); i++) {
+		if (strcmp(veth_mode[i].name, value))
+			continue;
+
+		*mode = veth_mode[i].mode;
+		return 0;
+	}
+
+	return -1;
+}
+
 static struct lxc_macvlan_mode {
 	char *name;
 	int mode;
diff --git a/src/lxc/confile_utils.h b/src/lxc/confile_utils.h
index 5a3bcc914c..85f51c72f5 100644
--- a/src/lxc/confile_utils.h
+++ b/src/lxc/confile_utils.h
@@ -56,6 +56,7 @@ lxc_get_netdev_by_idx(struct lxc_conf *conf, unsigned int idx, bool allocate);
 extern void lxc_log_configured_netdevs(const struct lxc_conf *conf);
 extern bool lxc_remove_nic_by_idx(struct lxc_conf *conf, unsigned int idx);
 extern void lxc_free_networks(struct lxc_list *networks);
+extern int lxc_veth_mode_to_flag(int *mode, const char *value);
 extern int lxc_macvlan_mode_to_flag(int *mode, const char *value);
 extern char *lxc_macvlan_flag_to_mode(int mode);
 
diff --git a/src/lxc/macro.h b/src/lxc/macro.h
index 6e07516f20..01a36da3b8 100644
--- a/src/lxc/macro.h
+++ b/src/lxc/macro.h
@@ -276,6 +276,14 @@ extern int __build_bug_on_failed;
 #define VETH_INFO_PEER 1
 #endif
 
+#ifndef VETH_MODE_BRIDGE
+#define VETH_MODE_BRIDGE 1
+#endif
+
+#ifndef VETH_MODE_ROUTED
+#define VETH_MODE_ROUTED 2
+#endif
+
 #ifndef IFLA_MACVLAN_MODE
 #define IFLA_MACVLAN_MODE 1
 #endif
diff --git a/src/lxc/network.h b/src/lxc/network.h
index ef1b41b897..6b6b8834ed 100644
--- a/src/lxc/network.h
+++ b/src/lxc/network.h
@@ -95,6 +95,7 @@ struct ifla_veth {
 	char pair[IFNAMSIZ];
 	char veth1[IFNAMSIZ];
 	int ifindex;
+	int mode; /* bridge, routed */
 };
 
 struct ifla_vlan {

From 0cd4274459d0c7b3a5641e8529a35ddecdb6b4a3 Mon Sep 17 00:00:00 2001
From: tomponline <tomp at tomp.uk>
Date: Tue, 26 Mar 2019 15:37:09 +0000
Subject: [PATCH 2/6] network: Adds static routes to container IPs on host when
 in veth routed mode.

Signed-off-by: tomponline <tomp at tomp.uk>
---
 src/lxc/network.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 58 insertions(+), 1 deletion(-)

diff --git a/src/lxc/network.c b/src/lxc/network.c
index fc3a8740d6..3987511e89 100644
--- a/src/lxc/network.c
+++ b/src/lxc/network.c
@@ -69,6 +69,47 @@ lxc_log_define(network, lxc);
 
 typedef int (*instantiate_cb)(struct lxc_handler *, struct lxc_netdev *);
 
+static int setup_ipv4_addr_routes(struct lxc_list *ip, int ifindex)
+{
+	struct lxc_list *iterator;
+	int err;
+
+	lxc_list_for_each(iterator, ip) {
+		struct lxc_inetdev *inetdev = iterator->elem;
+
+		err = lxc_ipv4_dest_add(ifindex, &inetdev->addr);
+
+		if (err) {
+			errno = -err;
+			SYSERROR("Failed to setup ipv4 address route for network device "
+			         "with eifindex %d", ifindex);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int setup_ipv6_addr_routes(struct lxc_list *ip, int ifindex)
+{
+	struct lxc_list *iterator;
+	int err;
+
+	lxc_list_for_each(iterator, ip) {
+		struct lxc_inet6dev *inet6dev = iterator->elem;
+
+		err = lxc_ipv6_dest_add(ifindex, &inet6dev->addr);
+		if (err) {
+			errno = -err;
+			SYSERROR("Failed to setup ipv6 address route for network device "
+			         "with eifindex %d", ifindex);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
 static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
 {
 	int bridge_index, err;
@@ -165,7 +206,7 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
 		}
 	}
 
-	if (netdev->link[0] != '\0') {
+	if (netdev->link[0] != '\0' && netdev->priv.veth_attr.mode == VETH_MODE_BRIDGE) {
 		err = lxc_bridge_attach(netdev->link, veth1);
 		if (err) {
 			errno = -err;
@@ -183,6 +224,22 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
 		goto out_delete;
 	}
 
+	if (netdev->priv.veth_attr.mode == VETH_MODE_ROUTED) {
+		/* setup ipv4 address routes on the host interface */
+		if (setup_ipv4_addr_routes(&netdev->ipv4, netdev->priv.veth_attr.ifindex)) {
+			errno = -err;
+			ERROR("Failed to setup ip address routes for network device \"%s\"", veth1);
+			goto out_delete;
+		}
+
+		/* setup ipv6 address routes on the host interface */
+		if (setup_ipv6_addr_routes(&netdev->ipv6, netdev->priv.veth_attr.ifindex)) {
+			errno = -err;
+			ERROR("Failed to setup ip address routes for network device \"%s\"", veth1);
+			goto out_delete;
+		}
+	}
+
 	if (netdev->upscript) {
 		char *argv[] = {
 		    "veth",

From 25ea9a131e73a10fb3b361bb7662a3795e1b1089 Mon Sep 17 00:00:00 2001
From: tomponline <tomp at tomp.uk>
Date: Thu, 28 Mar 2019 10:18:44 +0000
Subject: [PATCH 3/6] network: Changes veth "routed" mode to "router" to align
 with "bridge" as the alternative/default mode.

Signed-off-by: tomponline <tomp at tomp.uk>
---
 src/lxc/confile.c       | 4 ++--
 src/lxc/confile_utils.c | 2 +-
 src/lxc/macro.h         | 4 ++--
 src/lxc/network.c       | 2 +-
 src/lxc/network.h       | 2 +-
 5 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index c31431a8b2..571e44801b 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -5093,8 +5093,8 @@ static int get_config_net_veth_mode(const char *key, char *retv, int inlen,
 	case VETH_MODE_BRIDGE:
 		mode = "bridge";
 		break;
-	case VETH_MODE_ROUTED:
-		mode = "routed";
+	case VETH_MODE_ROUTER:
+		mode = "router";
 		break;
 	default:
 		mode = "(invalid)";
diff --git a/src/lxc/confile_utils.c b/src/lxc/confile_utils.c
index 6dcd72b48c..cf2f6d74e9 100644
--- a/src/lxc/confile_utils.c
+++ b/src/lxc/confile_utils.c
@@ -450,7 +450,7 @@ static struct lxc_veth_mode {
 	int mode;
 } veth_mode[] = {
     { "bridge", VETH_MODE_BRIDGE },
-    { "routed", VETH_MODE_ROUTED },
+    { "router", VETH_MODE_ROUTER },
 };
 
 int lxc_veth_mode_to_flag(int *mode, const char *value)
diff --git a/src/lxc/macro.h b/src/lxc/macro.h
index 01a36da3b8..c48b9bcbce 100644
--- a/src/lxc/macro.h
+++ b/src/lxc/macro.h
@@ -280,8 +280,8 @@ extern int __build_bug_on_failed;
 #define VETH_MODE_BRIDGE 1
 #endif
 
-#ifndef VETH_MODE_ROUTED
-#define VETH_MODE_ROUTED 2
+#ifndef VETH_MODE_ROUTER
+#define VETH_MODE_ROUTER 2
 #endif
 
 #ifndef IFLA_MACVLAN_MODE
diff --git a/src/lxc/network.c b/src/lxc/network.c
index 3987511e89..2d46201f11 100644
--- a/src/lxc/network.c
+++ b/src/lxc/network.c
@@ -224,7 +224,7 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
 		goto out_delete;
 	}
 
-	if (netdev->priv.veth_attr.mode == VETH_MODE_ROUTED) {
+	if (netdev->priv.veth_attr.mode == VETH_MODE_ROUTER) {
 		/* setup ipv4 address routes on the host interface */
 		if (setup_ipv4_addr_routes(&netdev->ipv4, netdev->priv.veth_attr.ifindex)) {
 			errno = -err;
diff --git a/src/lxc/network.h b/src/lxc/network.h
index 6b6b8834ed..615d096355 100644
--- a/src/lxc/network.h
+++ b/src/lxc/network.h
@@ -95,7 +95,7 @@ struct ifla_veth {
 	char pair[IFNAMSIZ];
 	char veth1[IFNAMSIZ];
 	int ifindex;
-	int mode; /* bridge, routed */
+	int mode; /* bridge, router */
 };
 
 struct ifla_vlan {

From 739d36b69c90b1915eb10365b309ffe84a68ccdb Mon Sep 17 00:00:00 2001
From: tomponline <tomp at tomp.uk>
Date: Thu, 28 Mar 2019 11:20:09 +0000
Subject: [PATCH 4/6] network: Activates proxy_ndp on all interfaces if veth is
 in "router" mode.

Signed-off-by: tomponline <tomp at tomp.uk>
---
 src/lxc/network.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/lxc/network.c b/src/lxc/network.c
index 2d46201f11..72fa64df30 100644
--- a/src/lxc/network.c
+++ b/src/lxc/network.c
@@ -225,6 +225,15 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
 	}
 
 	if (netdev->priv.veth_attr.mode == VETH_MODE_ROUTER) {
+		/* Activate IPv6 proxy_ndp on all interfaces to allow container to reach host as gateway.
+		 * IPv4 proxy_arp does not require all interfaces activated, but IPv6 proxy_ndp does.
+		 */
+		if (lxc_neigh_proxy_on("all",AF_INET6)) {
+			errno = -err;
+			ERROR("Failed to activate proxy ndp");
+			goto out_delete;
+		}
+
 		/* setup ipv4 address routes on the host interface */
 		if (setup_ipv4_addr_routes(&netdev->ipv4, netdev->priv.veth_attr.ifindex)) {
 			errno = -err;

From 0369827f0eb10eb63af338045c78a02a8362b990 Mon Sep 17 00:00:00 2001
From: tomponline <tomp at tomp.uk>
Date: Thu, 28 Mar 2019 15:19:17 +0000
Subject: [PATCH 5/6] network: Adds IP gateway neighbour proxy entry on host
 end of veth pair.

Signed-off-by: tomponline <tomp at tomp.uk>
---
 src/lxc/network.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/src/lxc/network.c b/src/lxc/network.c
index 72fa64df30..e1c28aea11 100644
--- a/src/lxc/network.c
+++ b/src/lxc/network.c
@@ -110,6 +110,39 @@ static int setup_ipv6_addr_routes(struct lxc_list *ip, int ifindex)
 	return 0;
 }
 
+struct ip_proxy_args {
+	const char *ip;
+	const char *dev;
+};
+
+static int add_ip_proxy_exec_wrapper(void *data)
+{
+	struct ip_proxy_args *args = data;
+
+	execlp("ip", "ip", "neigh", "add", "proxy", args->ip, "dev", args->dev,
+	       (char *)NULL);
+	return -1;
+}
+
+static int add_ip_proxy(const char *ip, const char *dev)
+{
+	int ret;
+	char cmd_output[PATH_MAX];
+	struct ip_proxy_args args;
+
+	args.ip = ip;
+	args.dev = dev;
+	ret = run_command(cmd_output, sizeof(cmd_output),
+			  add_ip_proxy_exec_wrapper, (void *)&args);
+	if (ret < 0) {
+		ERROR("Failed to add ip proxy \"%s\" to dev \"%s\": "
+		      "%s", ip, dev, cmd_output);
+		return -1;
+	}
+
+	return 0;
+}
+
 static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
 {
 	int bridge_index, err;
@@ -234,6 +267,22 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
 			goto out_delete;
 		}
 
+		char bufinet4[INET_ADDRSTRLEN], bufinet6[INET6_ADDRSTRLEN];
+		inet_ntop(AF_INET, netdev->ipv4_gateway, bufinet4, sizeof(bufinet4));
+		inet_ntop(AF_INET6, netdev->ipv6_gateway, bufinet6, sizeof(bufinet6));
+
+		if (netdev->ipv4_gateway && add_ip_proxy(bufinet4, veth1)) {
+			errno = -err;
+			ERROR("Failed to add gateway ipv4 proxy");
+			goto out_delete;
+		}
+
+		if (netdev->ipv6_gateway && add_ip_proxy(bufinet6, veth1)) {
+			errno = -err;
+			ERROR("Failed to add gateway ipv6 proxy");
+			goto out_delete;
+		}
+
 		/* setup ipv4 address routes on the host interface */
 		if (setup_ipv4_addr_routes(&netdev->ipv4, netdev->priv.veth_attr.ifindex)) {
 			errno = -err;

From 71107e09da1dc1a7aab1630a098e9716fb781c79 Mon Sep 17 00:00:00 2001
From: tomponline <tomp at tomp.uk>
Date: Thu, 28 Mar 2019 15:36:45 +0000
Subject: [PATCH 6/6] network: Activates IP forwarding on host end of veth pair
 when in "router" mode.

Signed-off-by: tomponline <tomp at tomp.uk>
---
 src/lxc/network.c | 82 ++++++++++++++++++++++++++++++++++++-----------
 src/lxc/network.h |  6 ++++
 2 files changed, 69 insertions(+), 19 deletions(-)

diff --git a/src/lxc/network.c b/src/lxc/network.c
index e1c28aea11..eb00f5ccae 100644
--- a/src/lxc/network.c
+++ b/src/lxc/network.c
@@ -258,29 +258,47 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
 	}
 
 	if (netdev->priv.veth_attr.mode == VETH_MODE_ROUTER) {
-		/* Activate IPv6 proxy_ndp on all interfaces to allow container to reach host as gateway.
-		 * IPv4 proxy_arp does not require all interfaces activated, but IPv6 proxy_ndp does.
-		 */
-		if (lxc_neigh_proxy_on("all",AF_INET6)) {
-			errno = -err;
-			ERROR("Failed to activate proxy ndp");
-			goto out_delete;
-		}
+		if (netdev->ipv4_gateway) {
+			char bufinet4[INET_ADDRSTRLEN];
+			inet_ntop(AF_INET, netdev->ipv4_gateway, bufinet4, sizeof(bufinet4));
 
-		char bufinet4[INET_ADDRSTRLEN], bufinet6[INET6_ADDRSTRLEN];
-		inet_ntop(AF_INET, netdev->ipv4_gateway, bufinet4, sizeof(bufinet4));
-		inet_ntop(AF_INET6, netdev->ipv6_gateway, bufinet6, sizeof(bufinet6));
+			if (lxc_ip_forwarding_on(veth1, AF_INET)) {
+				errno = -err;
+				ERROR("Failed to activate ipv4 forwarding on \"%s\"", veth1);
+				goto out_delete;
+			}
 
-		if (netdev->ipv4_gateway && add_ip_proxy(bufinet4, veth1)) {
-			errno = -err;
-			ERROR("Failed to add gateway ipv4 proxy");
-			goto out_delete;
+			if (add_ip_proxy(bufinet4, veth1)) {
+				errno = -err;
+				ERROR("Failed to add gateway ipv4 proxy");
+				goto out_delete;
+			}
 		}
 
-		if (netdev->ipv6_gateway && add_ip_proxy(bufinet6, veth1)) {
-			errno = -err;
-			ERROR("Failed to add gateway ipv6 proxy");
-			goto out_delete;
+		if (netdev->ipv6_gateway) {
+			char bufinet6[INET6_ADDRSTRLEN];
+			inet_ntop(AF_INET6, netdev->ipv6_gateway, bufinet6, sizeof(bufinet6));
+
+			if (lxc_ip_forwarding_on(veth1, AF_INET6)) {
+				errno = -err;
+				ERROR("Failed to activate ipv6 forwarding on \"%s\"", veth1);
+				goto out_delete;
+			}
+
+			/* Activate IPv6 proxy_ndp on all interfaces to allow container to reach host gateway.
+			 * IPv4 proxy_arp does not require all interfaces activated, but IPv6 proxy_ndp does.
+			 */
+			if (lxc_neigh_proxy_on("all", AF_INET6)) {
+				errno = -err;
+				ERROR("Failed to activate proxy ndp");
+				goto out_delete;
+			}
+
+			if (add_ip_proxy(bufinet6, veth1)) {
+				errno = -err;
+				ERROR("Failed to add gateway ipv6 proxy");
+				goto out_delete;
+			}
 		}
 
 		/* setup ipv4 address routes on the host interface */
@@ -1471,6 +1489,32 @@ static int proc_sys_net_write(const char *path, const char *value)
 	return err;
 }
 
+static int ip_forwarding_set(const char *ifname, int family, int flag)
+{
+	int ret;
+	char path[PATH_MAX];
+
+	if (family != AF_INET && family != AF_INET6)
+		return -EINVAL;
+
+	ret = snprintf(path, PATH_MAX, "/proc/sys/net/%s/conf/%s/%s",
+		       family == AF_INET ? "ipv4" : "ipv6", ifname, "forwarding");
+	if (ret < 0 || (size_t)ret >= PATH_MAX)
+		return -E2BIG;
+
+	return proc_sys_net_write(path, flag ? "1" : "0");
+}
+
+int lxc_ip_forwarding_on(const char *name, int family)
+{
+	return ip_forwarding_set(name, family, 1);
+}
+
+int lxc_ip_forwarding_off(const char *name, int family)
+{
+	return ip_forwarding_set(name, family, 0);
+}
+
 static int neigh_proxy_set(const char *ifname, int family, int flag)
 {
 	int ret;
diff --git a/src/lxc/network.h b/src/lxc/network.h
index 615d096355..790c239b1b 100644
--- a/src/lxc/network.h
+++ b/src/lxc/network.h
@@ -249,6 +249,12 @@ extern int lxc_neigh_proxy_on(const char *name, int family);
 /* Disable neighbor proxying. */
 extern int lxc_neigh_proxy_off(const char *name, int family);
 
+/* Activate IP forwarding. */
+extern int lxc_ip_forwarding_on(const char *name, int family);
+
+/* Disable IP forwarding. */
+extern int lxc_ip_forwarding_off(const char *name, int family);
+
 /* Generate a new unique network interface name.
  * Allocated memory must be freed by caller.
  */


More information about the lxc-devel mailing list