]> git.proxmox.com Git - mirror_lxc.git/commitdiff
network: Adds support host side veth device static routes
authortomponline <tomp@tomp.uk>
Thu, 25 Apr 2019 11:47:17 +0000 (12:47 +0100)
committertomponline <thomas.parrott@canonical.com>
Mon, 29 Apr 2019 07:38:33 +0000 (08:38 +0100)
Adds the following new config keys:

lxc.net.[i].veth.ipv4.route
lxc.net.[i].veth.ipv6.route
E.g.

lxc.net.0.veth.ipv4.route = 192.0.2.1/32
lxc.net.0.veth.ipv4.route = 192.0.3.0/24
lxc.net.0.veth.ipv6.route = 2001:db8::1/128
lxc.net.0.veth.ipv6.route = 2001:db8:2::/64

Signed-off-by: tomponline <thomas.parrott@canonical.com>
doc/api-extensions.md
doc/lxc.container.conf.sgml.in
src/lxc/api_extensions.h
src/lxc/confile.c
src/lxc/confile_utils.c
src/lxc/network.c
src/lxc/network.h
src/tests/parse_config_file.c

index ae9cced1cbbfdca5cac570568135eaa0259ab7c6..14a57235221e2fc1695cc8ef9b82d0b9cc9f507c 100644 (file)
@@ -32,3 +32,9 @@ until a reboot succeeded. It takes a timeout argument. When set to `> 0`
 This adds support for injecting and removing mounts into/from a running
 containers. Two new API functions `mount()` and `umount()` are added. They
 mirror the current mount and umount API of the kernel.
+
+## network\_veth\_routes
+
+This introduces the `lxc.net.[i].veth.ipv4.route` and `lxc.net.[i].veth.ipv6.route` properties
+on `veth` type network interfaces. This allows adding static routes on host to the container's
+network interface.
index 4ed65f63a06cc545c6ed13a7094e7a65a2d623f0..3b3dd6ddebedb63c995341fb4bba6840f3a021af 100644 (file)
@@ -375,7 +375,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
           <listitem>
             <para>
               The only allowed values are 0 and 1. Set this to 1 to destroy a
-              container on shutdown. 
+              container on shutdown.
             </para>
           </listitem>
         </varlistentry>
@@ -459,6 +459,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
               the <option>lxc.net.[i].veth.pair</option> option (except for
               unprivileged containers where this option is ignored for security
               reasons).
+
+              Static routes can be added on the host pointing to the container using the
+              <option>lxc.net.[i].veth.ipv4.route</option> and
+              <option>lxc.net.[i].veth.ipv6.route</option> options.
+              Several lines specify several routes.
+              The route is in format x.y.z.t/m, eg. 192.168.1.0/24.
             </para>
 
             <para>
@@ -855,7 +861,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
             When manually specifying a size for the log file the value should
             be a power of 2 when converted to bytes. Valid size prefixes are
             'KB', 'MB', 'GB'. (Note that all conversions are based on multiples
-            of 1024. That means 'KB' == 'KiB', 'MB' == 'MiB', 'GB' == 'GiB'. 
+            of 1024. That means 'KB' == 'KiB', 'MB' == 'MiB', 'GB' == 'GiB'.
             Additionally, the case of the suffix is ignored, i.e. 'kB', 'KB' and
             'Kb' are treated equally.)
 
@@ -1629,7 +1635,7 @@ dev/null proc/kcore none bind,relative 0 0
             </para>
 
             <para>
-            To inherit the namespace from another container set the 
+            To inherit the namespace from another container set the
             <option>lxc.namespace.share.[namespace identifier]</option> to the name of
             the container, e.g. <option>lxc.namespace.share.pid=c3</option>.
             </para>
@@ -1708,7 +1714,7 @@ dev/null proc/kcore none bind,relative 0 0
           </term>
           <listitem>
             <para>
-              Specify the kernel parameters to be set. The parameters available 
+              Specify the kernel parameters to be set. The parameters available
               are those listed under /proc/sys/.
               Note that not all sysctls are namespaced. Changing Non-namespaced
               sysctls will cause the system-wide setting to be modified.
@@ -1716,7 +1722,7 @@ dev/null proc/kcore none bind,relative 0 0
                 <refentrytitle><command>sysctl</command></refentrytitle>
                 <manvolnum>8</manvolnum>
               </citerefentry>.
-              If used with no value, lxc will clear the parameters specified up 
+              If used with no value, lxc will clear the parameters specified up
               to this point.
             </para>
           </listitem>
index e87c8e924cde5fe0c1e5fa8b769cd7a4f98b0517..529f19863e5113e82cc1b5ba93ec1d5cdaa09b44 100644 (file)
@@ -44,6 +44,7 @@ static char *api_extensions[] = {
        "mount_injection_file",
        "seccomp_allow_nesting",
        "seccomp_notify",
+       "network_veth_routes",
 };
 
 static size_t nr_api_extensions = sizeof(api_extensions) / sizeof(*api_extensions);
index da5e45ce3cd44c2ebf4d3f8e0169eff42e2f63a7..efcb705aafdc8536ef0628c6b1f986d0df60164c 100644 (file)
@@ -137,6 +137,8 @@ lxc_config_define(net_script_down);
 lxc_config_define(net_script_up);
 lxc_config_define(net_type);
 lxc_config_define(net_veth_pair);
+lxc_config_define(net_veth_ipv4_route);
+lxc_config_define(net_veth_ipv6_route);
 lxc_config_define(net_vlan_id);
 lxc_config_define(no_new_privs);
 lxc_config_define(personality);
@@ -226,6 +228,8 @@ static struct lxc_config_t config_jump_table[] = {
        { "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.pair",             set_config_net_veth_pair,               get_config_net_veth_pair,               clr_config_net_veth_pair,             },
+       { "lxc.net.veth.ipv4.route",       set_config_net_veth_ipv4_route,         get_config_net_veth_ipv4_route,         clr_config_net_veth_ipv4_route,       },
+       { "lxc.net.veth.ipv6.route",       set_config_net_veth_ipv6_route,         get_config_net_veth_ipv6_route,         clr_config_net_veth_ipv6_route,       },
        { "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,                       },
        { "lxc.no_new_privs",              set_config_no_new_privs,                get_config_no_new_privs,                clr_config_no_new_privs,              },
@@ -289,6 +293,8 @@ static int set_config_net_type(const char *key, const char *value,
 
        if (!strcmp(value, "veth")) {
                netdev->type = LXC_NET_VETH;
+               lxc_list_init(&netdev->priv.veth_attr.ipv4_routes);
+               lxc_list_init(&netdev->priv.veth_attr.ipv6_routes);
        } else if (!strcmp(value, "macvlan")) {
                netdev->type = LXC_NET_MACVLAN;
                lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode,
@@ -629,6 +635,69 @@ static int set_config_net_ipv4_gateway(const char *key, const char *value,
        return 0;
 }
 
+static int set_config_net_veth_ipv4_route(const char *key, const char *value,
+                                      struct lxc_conf *lxc_conf, void *data)
+{
+       __do_free char *valdup = NULL;
+       __do_free struct lxc_inetdev *inetdev = NULL;
+       __do_free struct lxc_list *list = NULL;
+       int ret;
+       char *netmask, *slash;
+       struct lxc_netdev *netdev = data;
+
+       if (lxc_config_value_empty(value))
+               return clr_config_net_veth_ipv4_route(key, lxc_conf, data);
+
+       if (!netdev)
+               return minus_one_set_errno(EINVAL);
+
+       if (netdev->type != LXC_NET_VETH) {
+               SYSERROR("Invalid ipv4 route \"%s\", can only be used with veth network", value);
+               return minus_one_set_errno(EINVAL);
+       }
+
+       inetdev = malloc(sizeof(*inetdev));
+       if (!inetdev)
+               return -1;
+       memset(inetdev, 0, sizeof(*inetdev));
+
+       list = malloc(sizeof(*list));
+       if (!list)
+               return -1;
+
+       lxc_list_init(list);
+       list->elem = inetdev;
+
+       valdup = strdup(value);
+       if (!valdup)
+               return -1;
+
+       slash = strchr(valdup, '/');
+       if (!slash)
+               return minus_one_set_errno(EINVAL);
+
+       *slash = '\0';
+       slash++;
+       if (*slash == '\0')
+               return minus_one_set_errno(EINVAL);
+
+       netmask = slash;
+
+       ret = lxc_safe_uint(netmask, &inetdev->prefix);
+       if (ret < 0 || inetdev->prefix > 32)
+               return minus_one_set_errno(EINVAL);
+
+       ret = inet_pton(AF_INET, valdup, &inetdev->addr);
+       if (!ret || ret < 0)
+               return minus_one_set_errno(EINVAL);
+
+       lxc_list_add_tail(&netdev->priv.veth_attr.ipv4_routes, list);
+       move_ptr(inetdev);
+       move_ptr(list);
+
+       return 0;
+}
+
 static int set_config_net_ipv6_address(const char *key, const char *value,
                                       struct lxc_conf *lxc_conf, void *data)
 {
@@ -733,6 +802,69 @@ static int set_config_net_ipv6_gateway(const char *key, const char *value,
        return 0;
 }
 
+static int set_config_net_veth_ipv6_route(const char *key, const char *value,
+                                      struct lxc_conf *lxc_conf, void *data)
+{
+       __do_free char *valdup;
+       __do_free struct lxc_inet6dev *inet6dev;
+       __do_free struct lxc_list *list;
+       int ret;
+       char *netmask, *slash;
+       struct lxc_netdev *netdev = data;
+
+       if (lxc_config_value_empty(value))
+               return clr_config_net_veth_ipv6_route(key, lxc_conf, data);
+
+       if (!netdev)
+               return minus_one_set_errno(EINVAL);
+
+       if (netdev->type != LXC_NET_VETH) {
+               SYSERROR("Invalid ipv6 route \"%s\", can only be used with veth network", value);
+               return minus_one_set_errno(EINVAL);
+       }
+
+       inet6dev = malloc(sizeof(*inet6dev));
+       if (!inet6dev)
+               return -1;
+       memset(inet6dev, 0, sizeof(*inet6dev));
+
+       list = malloc(sizeof(*list));
+       if (!list)
+               return -1;
+
+       lxc_list_init(list);
+       list->elem = inet6dev;
+
+       valdup = strdup(value);
+       if (!valdup)
+               return -1;
+
+       slash = strchr(valdup, '/');
+       if (!slash)
+               return minus_one_set_errno(EINVAL);
+
+       *slash = '\0';
+       slash++;
+       if (*slash == '\0')
+               return minus_one_set_errno(EINVAL);
+
+       netmask = slash;
+
+       ret = lxc_safe_uint(netmask, &inet6dev->prefix);
+       if (ret < 0 || inet6dev->prefix > 128)
+               return minus_one_set_errno(EINVAL);
+
+       ret = inet_pton(AF_INET6, valdup, &inet6dev->addr);
+       if (!ret || ret < 0)
+               return minus_one_set_errno(EINVAL);
+
+       lxc_list_add_tail(&netdev->priv.veth_attr.ipv6_routes, list);
+       move_ptr(inet6dev);
+       move_ptr(list);
+
+       return 0;
+}
+
 static int set_config_net_script_up(const char *key, const char *value,
                                    struct lxc_conf *lxc_conf, void *data)
 {
@@ -4898,6 +5030,24 @@ static int clr_config_net_ipv4_address(const char *key,
        return 0;
 }
 
+static int clr_config_net_veth_ipv4_route(const char *key,
+                                      struct lxc_conf *lxc_conf, void *data)
+{
+       struct lxc_netdev *netdev = data;
+       struct lxc_list *cur, *next;
+
+       if (!netdev)
+               return -1;
+
+       lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv4_routes, next) {
+               lxc_list_del(cur);
+               free(cur->elem);
+               free(cur);
+       }
+
+       return 0;
+}
+
 static int clr_config_net_ipv6_gateway(const char *key,
                                       struct lxc_conf *lxc_conf, void *data)
 {
@@ -4930,6 +5080,24 @@ static int clr_config_net_ipv6_address(const char *key,
        return 0;
 }
 
+static int clr_config_net_veth_ipv6_route(const char *key,
+                                      struct lxc_conf *lxc_conf, void *data)
+{
+       struct lxc_netdev *netdev = data;
+       struct lxc_list *cur, *next;
+
+       if (!netdev)
+               return -1;
+
+       lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv6_routes, next) {
+               lxc_list_del(cur);
+               free(cur->elem);
+               free(cur);
+       }
+
+       return 0;
+}
+
 static int get_config_net_nic(const char *key, char *retv, int inlen,
                              struct lxc_conf *c, void *data)
 {
@@ -5274,6 +5442,39 @@ static int get_config_net_ipv4_address(const char *key, char *retv, int inlen,
        return fulllen;
 }
 
+static int get_config_net_veth_ipv4_route(const char *key, char *retv, int inlen,
+                                      struct lxc_conf *c, void *data)
+{
+       int len;
+       size_t listlen;
+       char buf[INET_ADDRSTRLEN];
+       struct lxc_list *it;
+       int fulllen = 0;
+       struct lxc_netdev *netdev = data;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       if (!netdev)
+               return minus_one_set_errno(EINVAL);
+
+       if (netdev->type != LXC_NET_VETH)
+               return 0;
+
+       listlen = lxc_list_len(&netdev->priv.veth_attr.ipv4_routes);
+
+       lxc_list_for_each(it, &netdev->priv.veth_attr.ipv4_routes) {
+               struct lxc_inetdev *i = it->elem;
+               inet_ntop(AF_INET, &i->addr, buf, sizeof(buf));
+               strprint(retv, inlen, "%s/%u%s", buf, i->prefix,
+                        (listlen-- > 1) ? "\n" : "");
+       }
+
+       return fulllen;
+}
+
 static int get_config_net_ipv6_gateway(const char *key, char *retv, int inlen,
                                       struct lxc_conf *c, void *data)
 {
@@ -5330,6 +5531,39 @@ static int get_config_net_ipv6_address(const char *key, char *retv, int inlen,
        return fulllen;
 }
 
+static int get_config_net_veth_ipv6_route(const char *key, char *retv, int inlen,
+                                      struct lxc_conf *c, void *data)
+{
+       int len;
+       size_t listlen;
+       char buf[INET6_ADDRSTRLEN];
+       struct lxc_list *it;
+       int fulllen = 0;
+       struct lxc_netdev *netdev = data;
+
+       if (!retv)
+               inlen = 0;
+       else
+               memset(retv, 0, inlen);
+
+       if (!netdev)
+               return minus_one_set_errno(EINVAL);
+
+       if (netdev->type != LXC_NET_VETH)
+               return 0;
+
+       listlen = lxc_list_len(&netdev->priv.veth_attr.ipv6_routes);
+
+       lxc_list_for_each(it, &netdev->priv.veth_attr.ipv6_routes) {
+               struct lxc_inet6dev *i = it->elem;
+               inet_ntop(AF_INET6, &i->addr, buf, sizeof(buf));
+               strprint(retv, inlen, "%s/%u%s", buf, i->prefix,
+                        (listlen-- > 1) ? "\n" : "");
+       }
+
+       return fulllen;
+}
+
 int lxc_list_config_items(char *retv, int inlen)
 {
        size_t i;
@@ -5463,6 +5697,8 @@ int lxc_list_net(struct lxc_conf *c, const char *key, char *retv, int inlen)
        switch (netdev->type) {
        case LXC_NET_VETH:
                strprint(retv, inlen, "veth.pair\n");
+               strprint(retv, inlen, "veth.ipv4.route\n");
+               strprint(retv, inlen, "veth.ipv6.route\n");
                break;
        case LXC_NET_MACVLAN:
                strprint(retv, inlen, "macvlan.mode\n");
index 50777c448190db68193ee230a9b08f5baa416d40..cfc23f312bd7fb2816c554808437f5be763e6ca4 100644 (file)
@@ -317,7 +317,7 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
                        TRACE("type: none");
                        break;
                default:
-                       ERROR("invalid network type %d", netdev->type);
+                       ERROR("Invalid network type %d", netdev->type);
                        return;
                }
 
@@ -374,6 +374,28 @@ void lxc_log_configured_netdevs(const struct lxc_conf *conf)
                                          sizeof(bufinet6));
                                TRACE("ipv6 addr: %s", bufinet6);
                        }
+
+                       if (netdev->type == LXC_NET_VETH) {
+                               lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv4_routes, next) {
+                                       inet4dev = cur->elem;
+                                       if (!inet_ntop(AF_INET, &inet4dev->addr, bufinet4, sizeof(bufinet4))) {
+                                               ERROR("Invalid ipv4 veth route");
+                                               return;
+                                       }
+
+                                       TRACE("ipv4 veth route: %s/%u", bufinet4, inet4dev->prefix);
+                               }
+
+                               lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv6_routes, next) {
+                                       inet6dev = cur->elem;
+                                       if (!inet_ntop(AF_INET6, &inet6dev->addr, bufinet6, sizeof(bufinet6))) {
+                                               ERROR("Invalid ipv6 veth route");
+                                               return;
+                                       }
+
+                                       TRACE("ipv6 veth route: %s/%u", bufinet6, inet6dev->prefix);
+                               }
+                       }
                }
        }
 }
@@ -401,6 +423,20 @@ static void lxc_free_netdev(struct lxc_netdev *netdev)
                free(cur);
        }
 
+       if (netdev->type == LXC_NET_VETH) {
+               lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv4_routes, next) {
+                       lxc_list_del(cur);
+                       free(cur->elem);
+                       free(cur);
+               }
+
+               lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv6_routes, next) {
+                       lxc_list_del(cur);
+                       free(cur->elem);
+                       free(cur);
+               }
+       }
+
        free(netdev);
 }
 
index b49aae68cb1eb09cd4dd96967fb69debbb7d2ae5..a31544083ef9324d6c1a16ee414e13e242000692 100644 (file)
@@ -69,6 +69,44 @@ lxc_log_define(network, lxc);
 
 typedef int (*instantiate_cb)(struct lxc_handler *, struct lxc_netdev *);
 
+static int lxc_setup_ipv4_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, inetdev->prefix);
+               if (err) {
+                       SYSERROR("Failed to setup ipv4 route for network device "
+                                "with ifindex %d", ifindex);
+                       return minus_one_set_errno(-err);
+               }
+       }
+
+       return 0;
+}
+
+static int lxc_setup_ipv6_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, inet6dev->prefix);
+               if (err) {
+                       SYSERROR("Failed to setup ipv6 route for network device "
+                                "with ifindex %d", ifindex);
+                       return minus_one_set_errno(-err);
+               }
+       }
+
+       return 0;
+}
+
 static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
 {
        int bridge_index, err;
@@ -183,6 +221,18 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
                goto out_delete;
        }
 
+       /* setup ipv4 routes on the host interface */
+       if (lxc_setup_ipv4_routes(&netdev->priv.veth_attr.ipv4_routes, netdev->priv.veth_attr.ifindex)) {
+               ERROR("Failed to setup ipv4 routes for network device \"%s\"", veth1);
+               goto out_delete;
+       }
+
+       /* setup ipv6 routes on the host interface */
+       if (lxc_setup_ipv6_routes(&netdev->priv.veth_attr.ipv6_routes, netdev->priv.veth_attr.ifindex)) {
+               ERROR("Failed to setup ipv6 routes for network device \"%s\"", veth1);
+               goto out_delete;
+       }
+
        if (netdev->upscript) {
                char *argv[] = {
                    "veth",
@@ -1780,7 +1830,7 @@ int lxc_ipv6_gateway_add(int ifindex, struct in6_addr *gw)
        return ip_gateway_add(AF_INET6, ifindex, gw);
 }
 
-static int ip_route_dest_add(int family, int ifindex, void *dest)
+static int ip_route_dest_add(int family, int ifindex, void *dest, unsigned int netmask)
 {
        int addrlen, err;
        struct nl_handler nlh;
@@ -1815,7 +1865,7 @@ static int ip_route_dest_add(int family, int ifindex, void *dest)
        rt->rtm_scope = RT_SCOPE_LINK;
        rt->rtm_protocol = RTPROT_BOOT;
        rt->rtm_type = RTN_UNICAST;
-       rt->rtm_dst_len = addrlen * 8;
+       rt->rtm_dst_len = netmask;
 
        err = -EINVAL;
        if (nla_put_buffer(nlmsg, RTA_DST, dest, addrlen))
@@ -1830,14 +1880,14 @@ out:
        return err;
 }
 
-int lxc_ipv4_dest_add(int ifindex, struct in_addr *dest)
+int lxc_ipv4_dest_add(int ifindex, struct in_addr *dest, unsigned int netmask)
 {
-       return ip_route_dest_add(AF_INET, ifindex, dest);
+       return ip_route_dest_add(AF_INET, ifindex, dest, netmask);
 }
 
-int lxc_ipv6_dest_add(int ifindex, struct in6_addr *dest)
+int lxc_ipv6_dest_add(int ifindex, struct in6_addr *dest, unsigned int netmask)
 {
-       return ip_route_dest_add(AF_INET6, ifindex, dest);
+       return ip_route_dest_add(AF_INET6, ifindex, dest, netmask);
 }
 
 bool is_ovs_bridge(const char *bridge)
@@ -2807,7 +2857,7 @@ static int setup_ipv4_addr(struct lxc_list *ip, int ifindex)
                if (err) {
                        errno = -err;
                        SYSERROR("Failed to setup ipv4 address for network device "
-                                "with eifindex %d", ifindex);
+                                "with ifindex %d", ifindex);
                        return -1;
                }
        }
@@ -2829,7 +2879,7 @@ static int setup_ipv6_addr(struct lxc_list *ip, int ifindex)
                if (err) {
                        errno = -err;
                        SYSERROR("Failed to setup ipv6 address for network device "
-                                "with eifindex %d", ifindex);
+                                "with ifindex %d", ifindex);
                        return -1;
                }
        }
@@ -2988,7 +3038,7 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
 
                err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
                if (err) {
-                       err = lxc_ipv4_dest_add(netdev->ifindex, netdev->ipv4_gateway);
+                       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\"",
@@ -3027,7 +3077,7 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
 
                err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
                if (err) {
-                       err = lxc_ipv6_dest_add(netdev->ifindex, netdev->ipv6_gateway);
+                       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\"",
index ef1b41b897a3f76a3a82175851c3152e92782df3..1084cae2d46694f3072f7d9e7ec8fb7a0ff98252 100644 (file)
@@ -95,6 +95,8 @@ struct ifla_veth {
        char pair[IFNAMSIZ];
        char veth1[IFNAMSIZ];
        int ifindex;
+       struct lxc_list ipv4_routes;
+       struct lxc_list ipv6_routes;
 };
 
 struct ifla_vlan {
@@ -221,8 +223,8 @@ 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 a destination route to an interface. */
-extern int lxc_ipv4_dest_add(int ifindex, struct in_addr *dest);
-extern int lxc_ipv6_dest_add(int ifindex, struct in6_addr *dest);
+extern int lxc_ipv4_dest_add(int ifindex, struct in_addr *dest, unsigned int netmask);
+extern int lxc_ipv6_dest_add(int ifindex, struct in6_addr *dest, unsigned int netmask);
 
 /* Set default route. */
 extern int lxc_ipv4_gateway_add(int ifindex, struct in_addr *gw);
index b8b71c8e1e5105382bf853f0f3c4b84c270f1f04..63692264d33360a56d2e611a7e22d920cef4cac0 100644 (file)
@@ -134,6 +134,16 @@ static int set_and_clear_complete_netdev(struct lxc_container *c)
                return -1;
        }
 
+       if (!c->set_config_item(c, "lxc.net.1.veth.ipv4.route", "192.0.2.1/32")) {
+               lxc_error("%s\n", "lxc.net.1.veth.ipv4.route");
+               return -1;
+       }
+
+       if (!c->set_config_item(c, "lxc.net.1.veth.ipv6.route", "2001:db8::1/128")) {
+               lxc_error("%s\n", "lxc.net.1.veth.ipv6.route");
+               return -1;
+       }
+
        if (!c->set_config_item(c, "lxc.net.1.hwaddr",
                                "52:54:00:80:7a:5d")) {
                lxc_error("%s\n", "lxc.net.1.hwaddr");
@@ -695,6 +705,16 @@ int main(int argc, char *argv[])
                goto non_test_error;
        }
 
+       if (set_get_compare_clear_save_load_network(c, "lxc.net.0.veth.ipv4.route", "192.0.2.1/32", tmpf, true, "veth")) {
+               lxc_error("%s\n", "lxc.net.0.veth.ipv4.route");
+               return -1;
+       }
+
+       if (set_get_compare_clear_save_load_network(c, "lxc.net.0.veth.ipv6.route", "2001:db8::1/128", tmpf, true, "veth")) {
+               lxc_error("%s\n", "lxc.net.0.veth.ipv6.route");
+               return -1;
+       }
+
        if (set_get_compare_clear_save_load(c, "lxc.net.0.script.up", "/some/up/path", tmpf, true)) {
                lxc_error("%s\n", "lxc.net.0.script.up");
                goto non_test_error;