]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
network: Adds veth router mode static routes and proxy entries
authorThomas Parrott <thomas.parrott@canonical.com>
Fri, 5 Jul 2019 13:46:19 +0000 (14:46 +0100)
committerThomas Parrott <thomas.parrott@canonical.com>
Thu, 11 Jul 2019 11:37:23 +0000 (12:37 +0100)
Signed-off-by: Thomas Parrott <thomas.parrott@canonical.com>
src/lxc/network.c
src/lxc/network.h

index f9b89747030fa23573524d261b8999e7d2c1aed9..9755116ba11524e690234d39203d1c9b26b716da 100644 (file)
@@ -178,6 +178,118 @@ static int lxc_setup_ipv6_routes(struct lxc_list *ip, int ifindex)
        return 0;
 }
 
+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, 32);
+
+               if (err)
+                       return error_log_errno(err,
+                               "Failed to setup ipv4 address route for network device with eifindex %d",
+                               ifindex);
+       }
+
+       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, 128);
+               if (err)
+                       return error_log_errno(err,
+                               "Failed to setup ipv6 address route for network device with eifindex %d",
+                               ifindex);
+       }
+
+       return 0;
+}
+
+struct ip_proxy_args {
+       const char *ip;
+       const char *dev;
+};
+
+static int lxc_add_ip_neigh_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 lxc_del_ip_neigh_proxy_exec_wrapper(void *data)
+{
+       struct ip_proxy_args *args = data;
+
+       execlp("ip", "ip", "neigh", "flush", "proxy", args->ip, "dev", args->dev, (char *)NULL);
+       return -1;
+}
+
+static int lxc_add_ip_neigh_proxy(const char *ip, const char *dev)
+{
+       int ret;
+       char cmd_output[PATH_MAX] = {0};
+       struct ip_proxy_args args = {
+               .ip = ip,
+               .dev = dev,
+       };
+
+       ret = run_command(cmd_output, sizeof(cmd_output), lxc_add_ip_neigh_proxy_exec_wrapper, &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 lxc_del_ip_neigh_proxy(const char *ip, const char *dev)
+{
+       int ret;
+       char cmd_output[PATH_MAX] = {0};
+       struct ip_proxy_args args = {
+               .ip = ip,
+               .dev = dev,
+       };
+
+       ret = run_command(cmd_output, sizeof(cmd_output), lxc_del_ip_neigh_proxy_exec_wrapper, &args);
+       if (ret < 0) {
+               ERROR("Failed to delete ip proxy \"%s\" to dev \"%s\": %s", ip, dev, cmd_output);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int lxc_is_ip_forwarding_enabled(const char *ifname, int family)
+{
+       int ret;
+       char path[PATH_MAX];
+       char buf[1] = "";
+
+       if (family != AF_INET && family != AF_INET6)
+               return minus_one_set_errno(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 minus_one_set_errno(E2BIG);
+
+       return lxc_read_file_expect(path, buf, 1, "1");
+}
+
 static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
 {
        int bridge_index, err;
@@ -276,7 +388,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;
@@ -306,6 +418,78 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
                goto out_delete;
        }
 
+       if (netdev->priv.veth_attr.mode == VETH_MODE_ROUTER) {
+               if (netdev->ipv4_gateway) {
+                       char bufinet4[INET_ADDRSTRLEN];
+                       if (!inet_ntop(AF_INET, netdev->ipv4_gateway, bufinet4, sizeof(bufinet4))) {
+                               error_log_errno(-errno, "Failed to convert gateway ipv4 address on \"%s\"", veth1);
+                               goto out_delete;
+                       }
+
+                       err = lxc_ip_forwarding_on(veth1, AF_INET);
+                       if (err) {
+                               error_log_errno(err, "Failed to activate ipv4 forwarding on \"%s\"", veth1);
+                               goto out_delete;
+                       }
+
+                       err = lxc_add_ip_neigh_proxy(bufinet4, veth1);
+                       if (err) {
+                               error_log_errno(err, "Failed to add gateway ipv4 proxy on \"%s\"", veth1);
+                               goto out_delete;
+                       }
+               }
+
+               if (netdev->ipv6_gateway) {
+                       char bufinet6[INET6_ADDRSTRLEN];
+
+                       if (!inet_ntop(AF_INET6, netdev->ipv6_gateway, bufinet6, sizeof(bufinet6))) {
+                               error_log_errno(-errno, "Failed to convert gateway ipv6 address on \"%s\"", veth1);
+                               goto out_delete;
+                       }
+
+                       /* Check for sysctl net.ipv6.conf.all.forwarding=1
+                          Kernel requires this to route any packets for IPv6.
+                       */
+                       err = lxc_is_ip_forwarding_enabled("all", AF_INET6);
+                       if (err) {
+                               error_log_errno(err, "Requires sysctl net.ipv6.conf.all.forwarding=1");
+                               goto out_delete;
+                       }
+
+                       err = lxc_ip_forwarding_on(veth1, AF_INET6);
+                       if (err) {
+                               error_log_errno(err, "Failed to activate ipv6 forwarding on \"%s\"", veth1);
+                               goto out_delete;
+                       }
+
+                       err = lxc_neigh_proxy_on(veth1, AF_INET6);
+                       if (err) {
+                               error_log_errno(err, "Failed to activate proxy ndp on \"%s\"", veth1);
+                               goto out_delete;
+                       }
+
+                       err = lxc_add_ip_neigh_proxy(bufinet6, veth1);
+                       if (err) {
+                               error_log_errno(err, "Failed to add gateway ipv6 proxy on \"%s\"", veth1);
+                               goto out_delete;
+                       }
+               }
+
+               /* setup ipv4 address routes on the host interface */
+               err = setup_ipv4_addr_routes(&netdev->ipv4, netdev->priv.veth_attr.ifindex);
+               if (err) {
+                       error_log_errno(err, "Failed to setup ip address routes for network device \"%s\"", veth1);
+                       goto out_delete;
+               }
+
+               /* setup ipv6 address routes on the host interface */
+               err = setup_ipv6_addr_routes(&netdev->ipv6, netdev->priv.veth_attr.ifindex);
+               if (err) {
+                       error_log_errno(err, "Failed to setup ip address routes for network device \"%s\"", veth1);
+                       goto out_delete;
+               }
+       }
+
        if (netdev->upscript) {
                char *argv[] = {
                    "veth",
@@ -1798,22 +1982,30 @@ static int proc_sys_net_write(const char *path, const char *value)
        return err;
 }
 
-static int lxc_is_ip_forwarding_enabled(const char *ifname, int family)
+static int ip_forwarding_set(const char *ifname, int family, int flag)
 {
        int ret;
        char path[PATH_MAX];
-       char buf[1] = "";
 
        if (family != AF_INET && family != AF_INET6)
-               return minus_one_set_errno(EINVAL);
+               return -EINVAL;
 
        ret = snprintf(path, PATH_MAX, "/proc/sys/net/%s/conf/%s/%s",
-                      family == AF_INET ? "ipv4" : "ipv6", ifname,
-                      "forwarding");
+                      family == AF_INET ? "ipv4" : "ipv6", ifname, "forwarding");
        if (ret < 0 || (size_t)ret >= PATH_MAX)
-               return minus_one_set_errno(E2BIG);
+               return -E2BIG;
 
-       return lxc_read_file_expect(path, buf, 1, "1");
+       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)
@@ -2867,63 +3059,6 @@ clear_ifindices:
        return true;
 }
 
-struct ip_proxy_args {
-       const char *ip;
-       const char *dev;
-};
-
-static int lxc_add_ip_neigh_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 lxc_del_ip_neigh_proxy_exec_wrapper(void *data)
-{
-       struct ip_proxy_args *args = data;
-
-       execlp("ip", "ip", "neigh", "flush", "proxy", args->ip, "dev", args->dev, (char *)NULL);
-       return -1;
-}
-
-static int lxc_add_ip_neigh_proxy(const char *ip, const char *dev)
-{
-       int ret;
-       char cmd_output[PATH_MAX];
-       struct ip_proxy_args args = {
-               .ip = ip,
-               .dev = dev,
-       };
-
-       ret = run_command(cmd_output, sizeof(cmd_output), lxc_add_ip_neigh_proxy_exec_wrapper, &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 lxc_del_ip_neigh_proxy(const char *ip, const char *dev)
-{
-       int ret;
-       char cmd_output[PATH_MAX];
-       struct ip_proxy_args args = {
-               .ip = ip,
-               .dev = dev,
-       };
-
-       ret = run_command(cmd_output, sizeof(cmd_output), lxc_del_ip_neigh_proxy_exec_wrapper, &args);
-       if (ret < 0) {
-               ERROR("Failed to delete ip proxy \"%s\" to dev \"%s\": %s", ip, dev, cmd_output);
-               return -1;
-       }
-
-       return 0;
-}
-
 static int lxc_setup_l2proxy(struct lxc_netdev *netdev) {
        struct lxc_list *cur, *next;
        struct lxc_inetdev *inet4dev;
index 7361ce5c16cb4f257aab91957f344d3b2eac985d..acfd8a05325bbab4268c98522f856d162deb08f7 100644 (file)
@@ -264,6 +264,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.
  */