]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/network.c
tests: Adds test for lxc.net.0.veth.vlan.tagged.id config key
[mirror_lxc.git] / src / lxc / network.c
CommitLineData
cc73685d 1/* SPDX-License-Identifier: LGPL-2.1+ */
cb0dc11b 2
d38dd64a
CB
3#ifndef _GNU_SOURCE
4#define _GNU_SOURCE 1
5#endif
6#include <arpa/inet.h>
cb0dc11b
CB
7#include <ctype.h>
8#include <errno.h>
9#include <fcntl.h>
0ad19a3f 10#include <linux/netlink.h>
11#include <linux/rtnetlink.h>
12#include <linux/sockios.h>
cb0dc11b
CB
13#include <net/ethernet.h>
14#include <net/if.h>
15#include <net/if_arp.h>
16#include <netinet/in.h>
d38dd64a
CB
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
cb0dc11b
CB
20#include <sys/inotify.h>
21#include <sys/ioctl.h>
22#include <sys/param.h>
23#include <sys/socket.h>
24#include <sys/stat.h>
25#include <sys/types.h>
d38dd64a
CB
26#include <time.h>
27#include <unistd.h>
f549edcc 28
d38dd64a 29#include "../include/netns_ifaddrs.h"
7ab1ba02 30#include "af_unix.h"
72d0e1cb 31#include "conf.h"
811ef482 32#include "config.h"
e3233f26 33#include "file_utils.h"
cb0dc11b 34#include "log.h"
8335fd40 35#include "macro.h"
95ea3d1f 36#include "memory_utils.h"
cb0dc11b
CB
37#include "network.h"
38#include "nl.h"
f40988c7 39#include "process_utils.h"
59524108 40#include "syscall_wrappers.h"
0d204771 41#include "utils.h"
0ad19a3f 42
9de31d5a
CB
43#ifndef HAVE_STRLCPY
44#include "include/strlcpy.h"
45#endif
46
ac2cecc4 47lxc_log_define(network, lxc);
f8fee0e2 48
811ef482 49typedef int (*instantiate_cb)(struct lxc_handler *, struct lxc_netdev *);
8bf64b77 50typedef int (*instantiate_ns_cb)(struct lxc_netdev *);
3ebffb98 51static const char loop_device[] = "lo";
811ef482 52
b670016a 53static int lxc_ip_route_dest(__u16 nlmsg_type, int family, int ifindex, void *dest, unsigned int netmask)
8f82874c 54{
d16bda44 55 call_cleaner(nlmsg_free) struct nlmsg *answer = NULL, *nlmsg = NULL;
8f82874c 56 struct nl_handler nlh;
d16bda44
CB
57 call_cleaner(netlink_close) struct nl_handler *nlh_ptr = &nlh;
58 int addrlen, err;
8f82874c 59 struct rtmsg *rt;
8f82874c 60
61 addrlen = family == AF_INET ? sizeof(struct in_addr)
62 : sizeof(struct in6_addr);
63
d16bda44 64 err = netlink_open(nlh_ptr, NETLINK_ROUTE);
8f82874c 65 if (err)
66 return err;
67
8f82874c 68 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
69 if (!nlmsg)
d16bda44 70 return -ENOMEM;
8f82874c 71
72 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
73 if (!answer)
a5f5cb41 74 return -ENOMEM;
8f82874c 75
76 nlmsg->nlmsghdr->nlmsg_flags =
77 NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
b670016a 78 nlmsg->nlmsghdr->nlmsg_type = nlmsg_type;
8f82874c 79
80 rt = nlmsg_reserve(nlmsg, sizeof(struct rtmsg));
81 if (!rt)
a5f5cb41 82 return -ENOMEM;
d16bda44 83
8f82874c 84 rt->rtm_family = family;
85 rt->rtm_table = RT_TABLE_MAIN;
86 rt->rtm_scope = RT_SCOPE_LINK;
87 rt->rtm_protocol = RTPROT_BOOT;
88 rt->rtm_type = RTN_UNICAST;
89 rt->rtm_dst_len = netmask;
90
8f82874c 91 if (nla_put_buffer(nlmsg, RTA_DST, dest, addrlen))
d16bda44
CB
92 return -EINVAL;
93
8f82874c 94 if (nla_put_u32(nlmsg, RTA_OIF, ifindex))
d16bda44
CB
95 return -EINVAL;
96
97 return netlink_transaction(nlh_ptr, nlmsg, answer);
8f82874c 98}
99
100static int lxc_ipv4_dest_add(int ifindex, struct in_addr *dest, unsigned int netmask)
101{
b670016a 102 return lxc_ip_route_dest(RTM_NEWROUTE, AF_INET, ifindex, dest, netmask);
8f82874c 103}
104
105static int lxc_ipv6_dest_add(int ifindex, struct in6_addr *dest, unsigned int netmask)
106{
b670016a 107 return lxc_ip_route_dest(RTM_NEWROUTE, AF_INET6, ifindex, dest, netmask);
108}
109
110static int lxc_ipv4_dest_del(int ifindex, struct in_addr *dest, unsigned int netmask)
111{
112 return lxc_ip_route_dest(RTM_DELROUTE, AF_INET, ifindex, dest, netmask);
113}
114
115static int lxc_ipv6_dest_del(int ifindex, struct in6_addr *dest, unsigned int netmask)
116{
117 return lxc_ip_route_dest(RTM_DELROUTE, AF_INET6, ifindex, dest, netmask);
8f82874c 118}
119
d4a7da46 120static int lxc_setup_ipv4_routes(struct lxc_list *ip, int ifindex)
121{
122 struct lxc_list *iterator;
123 int err;
124
125 lxc_list_for_each(iterator, ip) {
126 struct lxc_inetdev *inetdev = iterator->elem;
127
128 err = lxc_ipv4_dest_add(ifindex, &inetdev->addr, inetdev->prefix);
9c66dc4f
CB
129 if (err)
130 return log_error_errno(-1, -err, "Failed to setup ipv4 route for network device with ifindex %d", ifindex);
d4a7da46 131 }
132
133 return 0;
134}
135
136static int lxc_setup_ipv6_routes(struct lxc_list *ip, int ifindex)
137{
138 struct lxc_list *iterator;
139 int err;
140
141 lxc_list_for_each(iterator, ip) {
142 struct lxc_inet6dev *inet6dev = iterator->elem;
143
144 err = lxc_ipv6_dest_add(ifindex, &inet6dev->addr, inet6dev->prefix);
9c66dc4f
CB
145 if (err)
146 return log_error_errno(-1, -err, "Failed to setup ipv6 route for network device with ifindex %d", ifindex);
d4a7da46 147 }
148
149 return 0;
150}
151
6dfa9581
TP
152static int setup_ipv4_addr_routes(struct lxc_list *ip, int ifindex)
153{
154 struct lxc_list *iterator;
155 int err;
156
157 lxc_list_for_each(iterator, ip) {
158 struct lxc_inetdev *inetdev = iterator->elem;
159
160 err = lxc_ipv4_dest_add(ifindex, &inetdev->addr, 32);
161
162 if (err)
9c66dc4f 163 return log_error_errno(-1, err, "Failed to setup ipv4 address route for network device with eifindex %d", ifindex);
6dfa9581
TP
164 }
165
166 return 0;
167}
168
169static int setup_ipv6_addr_routes(struct lxc_list *ip, int ifindex)
170{
171 struct lxc_list *iterator;
172 int err;
173
174 lxc_list_for_each(iterator, ip) {
175 struct lxc_inet6dev *inet6dev = iterator->elem;
176
177 err = lxc_ipv6_dest_add(ifindex, &inet6dev->addr, 128);
178 if (err)
9c66dc4f 179 return log_error_errno(-1, err, "Failed to setup ipv6 address route for network device with eifindex %d", ifindex);
6dfa9581
TP
180 }
181
182 return 0;
183}
184
185struct ip_proxy_args {
186 const char *ip;
187 const char *dev;
188};
189
5fe147e9 190static int lxc_ip_neigh_proxy(__u16 nlmsg_type, int family, int ifindex, void *dest)
6dfa9581 191{
d16bda44 192 call_cleaner(nlmsg_free) struct nlmsg *answer = NULL, *nlmsg = NULL;
5fe147e9 193 struct nl_handler nlh;
d16bda44
CB
194 call_cleaner(netlink_close) struct nl_handler *nlh_ptr = &nlh;
195 int addrlen, err;
5fe147e9 196 struct ndmsg *rt;
6dfa9581 197
5fe147e9 198 addrlen = family == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr);
6dfa9581 199
d16bda44 200 err = netlink_open(nlh_ptr, NETLINK_ROUTE);
5fe147e9
TP
201 if (err)
202 return err;
6dfa9581 203
5fe147e9
TP
204 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
205 if (!nlmsg)
d16bda44 206 return -ENOMEM;
6dfa9581 207
5fe147e9
TP
208 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
209 if (!answer)
d16bda44 210 return -ENOMEM;
6dfa9581 211
5fe147e9
TP
212 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
213 nlmsg->nlmsghdr->nlmsg_type = nlmsg_type;
6dfa9581 214
5fe147e9
TP
215 rt = nlmsg_reserve(nlmsg, sizeof(struct ndmsg));
216 if (!rt)
d16bda44
CB
217 return -ENOMEM;
218
5fe147e9
TP
219 rt->ndm_ifindex = ifindex;
220 rt->ndm_flags = NTF_PROXY;
221 rt->ndm_type = NDA_DST;
222 rt->ndm_family = family;
6dfa9581 223
5fe147e9 224 if (nla_put_buffer(nlmsg, NDA_DST, dest, addrlen))
d16bda44 225 return -EINVAL;
6dfa9581 226
d16bda44 227 return netlink_transaction(nlh_ptr, nlmsg, answer);
6dfa9581
TP
228}
229
230static int lxc_is_ip_forwarding_enabled(const char *ifname, int family)
231{
232 int ret;
233 char path[PATH_MAX];
234 char buf[1] = "";
235
236 if (family != AF_INET && family != AF_INET6)
596a002c 237 return ret_set_errno(-1, EINVAL);
6dfa9581 238
9c66dc4f 239 ret = snprintf(path, sizeof(path), "/proc/sys/net/%s/conf/%s/%s",
6dfa9581
TP
240 family == AF_INET ? "ipv4" : "ipv6", ifname,
241 "forwarding");
9c66dc4f 242 if (ret < 0 || (size_t)ret >= sizeof(path))
596a002c 243 return ret_set_errno(-1, E2BIG);
6dfa9581
TP
244
245 return lxc_read_file_expect(path, buf, 1, "1");
246}
247
811ef482
CB
248static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
249{
54256301 250 int err;
a00fbab5 251 unsigned int mtu = 1500;
811ef482
CB
252 char *veth1, *veth2;
253 char veth1buf[IFNAMSIZ], veth2buf[IFNAMSIZ];
811ef482 254
f2711167 255 if (!is_empty_string(netdev->priv.veth_attr.pair)) {
811ef482
CB
256 veth1 = netdev->priv.veth_attr.pair;
257 if (handler->conf->reboot)
258 lxc_netdev_delete_by_name(veth1);
259 } else {
260 err = snprintf(veth1buf, sizeof(veth1buf), "vethXXXXXX");
261 if (err < 0 || (size_t)err >= sizeof(veth1buf))
262 return -1;
263
3646ffd9 264 veth1 = lxc_ifname_alnum_case_sensitive(veth1buf);
811ef482
CB
265 if (!veth1)
266 return -1;
267
268 /* store away for deconf */
269 memcpy(netdev->priv.veth_attr.veth1, veth1, IFNAMSIZ);
270 }
271
d34212ad
CB
272 err = snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
273 if (err < 0 || (size_t)err >= sizeof(veth2buf))
274 return -1;
275
3646ffd9 276 veth2 = lxc_ifname_alnum_case_sensitive(veth2buf);
811ef482 277 if (!veth2)
54256301
CB
278 return -1;
279
a00fbab5
TP
280 /* if mtu is specified in config then use that, otherwise inherit from link device if provided. */
281 if (netdev->mtu) {
282 if (lxc_safe_uint(netdev->mtu, &mtu))
283 return log_error_errno(-1, errno, "Failed to parse mtu");
f2711167 284 } else if (!is_empty_string(netdev->link)) {
54256301 285 int ifindex_mtu;
811ef482 286
54256301
CB
287 ifindex_mtu = if_nametoindex(netdev->link);
288 if (ifindex_mtu) {
289 mtu = netdev_get_mtu(ifindex_mtu);
290 INFO("Retrieved mtu %d from %s", mtu, netdev->link);
291 }
292 }
293
294 err = lxc_veth_create(veth1, veth2, handler->pid, mtu);
9c66dc4f
CB
295 if (err)
296 return log_error_errno(-1, -err, "Failed to create veth pair \"%s\" and \"%s\"", veth1, veth2);
811ef482 297
24190194
CB
298 strlcpy(netdev->created_name, veth2, IFNAMSIZ);
299
811ef482
CB
300 /* changing the high byte of the mac address to 0xfe, the bridge interface
301 * will always keep the host's mac address and not take the mac address
302 * of a container */
303 err = setup_private_host_hw_addr(veth1);
304 if (err) {
6d1400b5 305 errno = -err;
306 SYSERROR("Failed to change mac address of host interface \"%s\"", veth1);
811ef482
CB
307 goto out_delete;
308 }
309
8da62485
CB
310 /* Retrieve ifindex of the host's veth device. */
311 netdev->priv.veth_attr.ifindex = if_nametoindex(veth1);
312 if (!netdev->priv.veth_attr.ifindex) {
313 ERROR("Failed to retrieve ifindex for \"%s\"", veth1);
314 goto out_delete;
315 }
316
811ef482
CB
317 if (mtu) {
318 err = lxc_netdev_set_mtu(veth1, mtu);
811ef482 319 if (err) {
6d1400b5 320 errno = -err;
54256301 321 SYSERROR("Failed to set mtu \"%d\" for veth pair \"%s\" ", mtu, veth1);
811ef482
CB
322 goto out_delete;
323 }
324 }
325
f2711167 326 if (!is_empty_string(netdev->link) && netdev->priv.veth_attr.mode == VETH_MODE_BRIDGE) {
26da53c3
TP
327 if (!lxc_nic_exists(netdev->link)) {
328 SYSERROR("Failed to attach \"%s\" to bridge \"%s\", bridge interface doesn't exist", veth1, netdev->link);
329 goto out_delete;
330 }
331
811ef482
CB
332 err = lxc_bridge_attach(netdev->link, veth1);
333 if (err) {
6d1400b5 334 errno = -err;
26da53c3 335 SYSERROR("Failed to attach \"%s\" to bridge \"%s\"", veth1, netdev->link);
811ef482
CB
336 goto out_delete;
337 }
338 INFO("Attached \"%s\" to bridge \"%s\"", veth1, netdev->link);
339 }
340
341 err = lxc_netdev_up(veth1);
342 if (err) {
6d1400b5 343 errno = -err;
344 SYSERROR("Failed to set \"%s\" up", veth1);
811ef482
CB
345 goto out_delete;
346 }
347
d4a7da46 348 /* setup ipv4 routes on the host interface */
349 if (lxc_setup_ipv4_routes(&netdev->priv.veth_attr.ipv4_routes, netdev->priv.veth_attr.ifindex)) {
350 ERROR("Failed to setup ipv4 routes for network device \"%s\"", veth1);
351 goto out_delete;
352 }
353
354 /* setup ipv6 routes on the host interface */
355 if (lxc_setup_ipv6_routes(&netdev->priv.veth_attr.ipv6_routes, netdev->priv.veth_attr.ifindex)) {
356 ERROR("Failed to setup ipv6 routes for network device \"%s\"", veth1);
357 goto out_delete;
358 }
359
6dfa9581 360 if (netdev->priv.veth_attr.mode == VETH_MODE_ROUTER) {
954e36b4
TP
361 /* sleep for a short period of time to work around a bug that intermittently prevents IP neighbour
362 proxy entries from being added using lxc_ip_neigh_proxy below. When the issue occurs the entries
363 appear to be added successfully but then do not appear in the proxy list. The length of time
364 slept doesn't appear to be important, only that the process sleeps for a short period of time.
365 */
366 nanosleep((const struct timespec[]){{0, 1000}}, NULL);
367
6dfa9581
TP
368 if (netdev->ipv4_gateway) {
369 char bufinet4[INET_ADDRSTRLEN];
370 if (!inet_ntop(AF_INET, netdev->ipv4_gateway, bufinet4, sizeof(bufinet4))) {
9c66dc4f 371 SYSERROR("Failed to convert gateway ipv4 address on \"%s\"", veth1);
6dfa9581
TP
372 goto out_delete;
373 }
374
375 err = lxc_ip_forwarding_on(veth1, AF_INET);
376 if (err) {
9c66dc4f 377 SYSERROR("Failed to activate ipv4 forwarding on \"%s\"", veth1);
6dfa9581
TP
378 goto out_delete;
379 }
380
5fe147e9 381 err = lxc_ip_neigh_proxy(RTM_NEWNEIGH, AF_INET, netdev->priv.veth_attr.ifindex, netdev->ipv4_gateway);
6dfa9581 382 if (err) {
9c66dc4f 383 SYSERROR("Failed to add gateway ipv4 proxy on \"%s\"", veth1);
6dfa9581
TP
384 goto out_delete;
385 }
386 }
387
388 if (netdev->ipv6_gateway) {
389 char bufinet6[INET6_ADDRSTRLEN];
390
391 if (!inet_ntop(AF_INET6, netdev->ipv6_gateway, bufinet6, sizeof(bufinet6))) {
9c66dc4f 392 SYSERROR("Failed to convert gateway ipv6 address on \"%s\"", veth1);
6dfa9581
TP
393 goto out_delete;
394 }
395
396 /* Check for sysctl net.ipv6.conf.all.forwarding=1
397 Kernel requires this to route any packets for IPv6.
398 */
399 err = lxc_is_ip_forwarding_enabled("all", AF_INET6);
400 if (err) {
9c66dc4f 401 SYSERROR("Requires sysctl net.ipv6.conf.all.forwarding=1");
6dfa9581
TP
402 goto out_delete;
403 }
404
405 err = lxc_ip_forwarding_on(veth1, AF_INET6);
406 if (err) {
9c66dc4f 407 SYSERROR("Failed to activate ipv6 forwarding on \"%s\"", veth1);
6dfa9581
TP
408 goto out_delete;
409 }
410
411 err = lxc_neigh_proxy_on(veth1, AF_INET6);
412 if (err) {
9c66dc4f 413 SYSERROR("Failed to activate proxy ndp on \"%s\"", veth1);
6dfa9581
TP
414 goto out_delete;
415 }
416
5fe147e9 417 err = lxc_ip_neigh_proxy(RTM_NEWNEIGH, AF_INET6, netdev->priv.veth_attr.ifindex, netdev->ipv6_gateway);
6dfa9581 418 if (err) {
9c66dc4f 419 SYSERROR("Failed to add gateway ipv6 proxy on \"%s\"", veth1);
6dfa9581
TP
420 goto out_delete;
421 }
422 }
423
424 /* setup ipv4 address routes on the host interface */
425 err = setup_ipv4_addr_routes(&netdev->ipv4, netdev->priv.veth_attr.ifindex);
426 if (err) {
9c66dc4f 427 SYSERROR("Failed to setup ip address routes for network device \"%s\"", veth1);
6dfa9581
TP
428 goto out_delete;
429 }
430
431 /* setup ipv6 address routes on the host interface */
432 err = setup_ipv6_addr_routes(&netdev->ipv6, netdev->priv.veth_attr.ifindex);
433 if (err) {
9c66dc4f 434 SYSERROR("Failed to setup ip address routes for network device \"%s\"", veth1);
6dfa9581
TP
435 goto out_delete;
436 }
437 }
438
811ef482 439 if (netdev->upscript) {
14a7b0f9
CB
440 char *argv[] = {
441 "veth",
442 netdev->link,
990b9ac3 443 veth1,
14a7b0f9
CB
444 NULL,
445 };
446
447 err = run_script_argv(handler->name,
448 handler->conf->hooks_version, "net",
449 netdev->upscript, "up", argv);
450 if (err < 0)
811ef482
CB
451 goto out_delete;
452 }
453
54256301 454 DEBUG("Instantiated veth tunnel \"%s <--> %s\"", veth1, veth2);
811ef482
CB
455
456 return 0;
457
458out_delete:
54256301 459 lxc_netdev_delete_by_name(veth1);
811ef482
CB
460 return -1;
461}
462
463static int instantiate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
464{
8021de25 465 char peer[IFNAMSIZ];
811ef482
CB
466 int err;
467
f2711167 468 if (is_empty_string(netdev->link)) {
811ef482
CB
469 ERROR("No link for macvlan network device specified");
470 return -1;
471 }
472
8021de25
CB
473 err = snprintf(peer, sizeof(peer), "mcXXXXXX");
474 if (err < 0 || (size_t)err >= sizeof(peer))
811ef482
CB
475 return -1;
476
3646ffd9 477 if (!lxc_ifname_alnum_case_sensitive(peer))
811ef482
CB
478 return -1;
479
480 err = lxc_macvlan_create(netdev->link, peer,
481 netdev->priv.macvlan_attr.mode);
482 if (err) {
6d1400b5 483 errno = -err;
484 SYSERROR("Failed to create macvlan interface \"%s\" on \"%s\"",
485 peer, netdev->link);
966e9f1f 486 goto on_error;
811ef482
CB
487 }
488
9f8cf6e1
CB
489 strlcpy(netdev->created_name, peer, IFNAMSIZ);
490
811ef482
CB
491 netdev->ifindex = if_nametoindex(peer);
492 if (!netdev->ifindex) {
493 ERROR("Failed to retrieve ifindex for \"%s\"", peer);
966e9f1f 494 goto on_error;
811ef482
CB
495 }
496
3bef7b7b 497 if (netdev->mtu) {
54256301
CB
498 unsigned int mtu;
499
3bef7b7b
TP
500 err = lxc_safe_uint(netdev->mtu, &mtu);
501 if (err < 0) {
502 errno = -err;
503 SYSERROR("Failed to parse mtu \"%s\" for interface \"%s\"", netdev->mtu, peer);
504 goto on_error;
505 }
506
507 err = lxc_netdev_set_mtu(peer, mtu);
508 if (err < 0) {
509 errno = -err;
510 SYSERROR("Failed to set mtu \"%s\" for interface \"%s\"", netdev->mtu, peer);
511 goto on_error;
512 }
513 }
514
811ef482 515 if (netdev->upscript) {
14a7b0f9
CB
516 char *argv[] = {
517 "macvlan",
518 netdev->link,
519 NULL,
520 };
521
522 err = run_script_argv(handler->name,
523 handler->conf->hooks_version, "net",
524 netdev->upscript, "up", argv);
525 if (err < 0)
966e9f1f 526 goto on_error;
811ef482
CB
527 }
528
529 DEBUG("Instantiated macvlan \"%s\" with ifindex is %d and mode %d",
530 peer, netdev->ifindex, netdev->priv.macvlan_attr.mode);
531
532 return 0;
966e9f1f
CB
533
534on_error:
811ef482 535 lxc_netdev_delete_by_name(peer);
811ef482
CB
536 return -1;
537}
538
c9f52382 539static int lxc_ipvlan_create(const char *master, const char *name, int mode, int isolation)
540{
d16bda44
CB
541 call_cleaner(nlmsg_free) struct nlmsg *answer = NULL, *nlmsg = NULL;
542 struct nl_handler nlh;
543 call_cleaner(netlink_close) struct nl_handler *nlh_ptr = &nlh;
c9f52382 544 int err, index, len;
545 struct ifinfomsg *ifi;
c9f52382 546 struct rtattr *nest, *nest2;
c9f52382 547
548 len = strlen(master);
549 if (len == 1 || len >= IFNAMSIZ)
d16bda44 550 return ret_errno(EINVAL);
c9f52382 551
552 len = strlen(name);
553 if (len == 1 || len >= IFNAMSIZ)
d16bda44 554 return ret_errno(EINVAL);
c9f52382 555
556 index = if_nametoindex(master);
557 if (!index)
d16bda44 558 return ret_errno(EINVAL);
c9f52382 559
d16bda44 560 err = netlink_open(nlh_ptr, NETLINK_ROUTE);
c9f52382 561 if (err)
d16bda44 562 return ret_errno(-err);
c9f52382 563
c9f52382 564 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
565 if (!nlmsg)
d16bda44 566 return ret_errno(ENOMEM);
c9f52382 567
568 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
569 if (!answer)
d16bda44 570 return ret_errno(ENOMEM);
c9f52382 571
572 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
573 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
574
575 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
d16bda44
CB
576 if (!ifi)
577 return ret_errno(ENOMEM);
c9f52382 578 ifi->ifi_family = AF_UNSPEC;
579
c9f52382 580 nest = nla_begin_nested(nlmsg, IFLA_LINKINFO);
581 if (!nest)
d16bda44 582 return ret_errno(EPROTO);
c9f52382 583
584 if (nla_put_string(nlmsg, IFLA_INFO_KIND, "ipvlan"))
d16bda44 585 return ret_errno(EPROTO);
c9f52382 586
5755765e
KT
587 nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA);
588 if (!nest2)
589 return ret_errno(EPROTO);
590
3a934e2e 591 if (nla_put_u16(nlmsg, IFLA_IPVLAN_MODE, mode))
5755765e
KT
592 return ret_errno(EPROTO);
593
cf88a827
TP
594 /* if_link.h does not define the isolation flag value for bridge mode (unlike IPVLAN_F_PRIVATE and
595 * IPVLAN_F_VEPA) so we define it as 0 and only send mode if mode >0 as default mode is bridge anyway
596 * according to ipvlan docs.
5755765e 597 */
cf88a827 598 if (isolation > 0 && nla_put_u16(nlmsg, IFLA_IPVLAN_ISOLATION, isolation))
5755765e 599 return ret_errno(EPROTO);
c9f52382 600
5755765e 601 nla_end_nested(nlmsg, nest2);
c9f52382 602 nla_end_nested(nlmsg, nest);
603
604 if (nla_put_u32(nlmsg, IFLA_LINK, index))
d16bda44 605 return ret_errno(EPROTO);
c9f52382 606
607 if (nla_put_string(nlmsg, IFLA_IFNAME, name))
d16bda44
CB
608 return ret_errno(EPROTO);
609
610 return netlink_transaction(nlh_ptr, nlmsg, answer);
c9f52382 611}
612
613static int instantiate_ipvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
614{
dd119206 615 char peer[IFNAMSIZ];
c9f52382 616 int err;
617
f2711167 618 if (is_empty_string(netdev->link)) {
c9f52382 619 ERROR("No link for ipvlan network device specified");
620 return -1;
621 }
622
dd119206
CB
623 err = snprintf(peer, sizeof(peer), "ipXXXXXX");
624 if (err < 0 || (size_t)err >= sizeof(peer))
c9f52382 625 return -1;
626
3646ffd9 627 if (!lxc_ifname_alnum_case_sensitive(peer))
c9f52382 628 return -1;
629
dd119206
CB
630 err = lxc_ipvlan_create(netdev->link, peer, netdev->priv.ipvlan_attr.mode,
631 netdev->priv.ipvlan_attr.isolation);
c9f52382 632 if (err) {
dd119206
CB
633 SYSERROR("Failed to create ipvlan interface \"%s\" on \"%s\"",
634 peer, netdev->link);
c9f52382 635 goto on_error;
636 }
637
e7fdd504
CB
638 strlcpy(netdev->created_name, peer, IFNAMSIZ);
639
c9f52382 640 netdev->ifindex = if_nametoindex(peer);
641 if (!netdev->ifindex) {
642 ERROR("Failed to retrieve ifindex for \"%s\"", peer);
643 goto on_error;
644 }
645
006e135e 646 if (netdev->mtu) {
54256301
CB
647 unsigned int mtu;
648
006e135e 649 err = lxc_safe_uint(netdev->mtu, &mtu);
650 if (err < 0) {
651 errno = -err;
54256301 652 SYSERROR("Failed to parse mtu \"%s\" for interface \"%s\"", netdev->mtu, peer);
006e135e 653 goto on_error;
654 }
655
656 err = lxc_netdev_set_mtu(peer, mtu);
657 if (err < 0) {
658 errno = -err;
54256301 659 SYSERROR("Failed to set mtu \"%s\" for interface \"%s\"", netdev->mtu, peer);
006e135e 660 goto on_error;
661 }
662 }
663
c9f52382 664 if (netdev->upscript) {
665 char *argv[] = {
666 "ipvlan",
667 netdev->link,
668 NULL,
669 };
670
dd119206
CB
671 err = run_script_argv(handler->name, handler->conf->hooks_version,
672 "net", netdev->upscript, "up", argv);
c9f52382 673 if (err < 0)
674 goto on_error;
675 }
676
dd119206
CB
677 DEBUG("Instantiated ipvlan \"%s\" with ifindex is %d and mode %d", peer,
678 netdev->ifindex, netdev->priv.macvlan_attr.mode);
c9f52382 679
680 return 0;
681
682on_error:
683 lxc_netdev_delete_by_name(peer);
684 return -1;
685}
686
811ef482
CB
687static int instantiate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
688{
689 char peer[IFNAMSIZ];
690 int err;
691 static uint16_t vlan_cntr = 0;
811ef482 692
f2711167 693 if (is_empty_string(netdev->link)) {
811ef482
CB
694 ERROR("No link for vlan network device specified");
695 return -1;
696 }
697
d4d68410
CB
698 err = snprintf(peer, sizeof(peer), "vlan%d-%d",
699 netdev->priv.vlan_attr.vid, vlan_cntr++);
811ef482
CB
700 if (err < 0 || (size_t)err >= sizeof(peer))
701 return -1;
702
703 err = lxc_vlan_create(netdev->link, peer, netdev->priv.vlan_attr.vid);
704 if (err) {
6d1400b5 705 errno = -err;
706 SYSERROR("Failed to create vlan interface \"%s\" on \"%s\"",
707 peer, netdev->link);
811ef482
CB
708 return -1;
709 }
710
83530dba
CB
711 strlcpy(netdev->created_name, peer, IFNAMSIZ);
712
811ef482
CB
713 netdev->ifindex = if_nametoindex(peer);
714 if (!netdev->ifindex) {
715 ERROR("Failed to retrieve ifindex for \"%s\"", peer);
3e2a7b08 716 goto on_error;
717 }
718
719 if (netdev->mtu) {
54256301
CB
720 unsigned int mtu;
721
3e2a7b08 722 err = lxc_safe_uint(netdev->mtu, &mtu);
723 if (err < 0) {
724 errno = -err;
54256301 725 SYSERROR("Failed to parse mtu \"%s\" for interface \"%s\"", netdev->mtu, peer);
3e2a7b08 726 goto on_error;
727 }
728
729 err = lxc_netdev_set_mtu(peer, mtu);
54256301 730 if (err < 0) {
3e2a7b08 731 errno = -err;
54256301 732 SYSERROR("Failed to set mtu \"%s\" for interface \"%s\"", netdev->mtu, peer);
3e2a7b08 733 goto on_error;
734 }
811ef482
CB
735 }
736
3a73d9f1 737 if (netdev->upscript) {
738 char *argv[] = {
739 "vlan",
740 netdev->link,
741 NULL,
742 };
743
d4d68410
CB
744 err = run_script_argv(handler->name, handler->conf->hooks_version,
745 "net", netdev->upscript, "up", argv);
19abca58 746 if (err < 0) {
3e2a7b08 747 goto on_error;
19abca58 748 }
3a73d9f1 749 }
750
d4d68410
CB
751 DEBUG("Instantiated vlan \"%s\" with ifindex is \"%d\"", peer,
752 netdev->ifindex);
811ef482
CB
753
754 return 0;
3e2a7b08 755
756on_error:
757 lxc_netdev_delete_by_name(peer);
758 return -1;
811ef482
CB
759}
760
761static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
762{
0b154989 763 int err, mtu_orig = 0;
14a7b0f9 764
9c66dc4f
CB
765 if (is_empty_string(netdev->link))
766 return log_error_errno(-1, errno, "No link for physical interface specified");
811ef482 767
75b074ee
CB
768 /*
769 * Note that we're retrieving the container's ifindex in the host's
790255cf
CB
770 * network namespace because we need it to move the device from the
771 * host's network namespace to the container's network namespace later
772 * on.
773 * Note that netdev->link will contain the name of the physical network
774 * device in the host's namespace.
775 */
811ef482 776 netdev->ifindex = if_nametoindex(netdev->link);
9c66dc4f
CB
777 if (!netdev->ifindex)
778 return log_error_errno(-1, errno, "Failed to retrieve ifindex for \"%s\"", netdev->link);
811ef482 779
61302ef7 780 strlcpy(netdev->created_name, netdev->link, IFNAMSIZ);
3473ca76 781 if (is_empty_string(netdev->name))
8bf64b77 782 (void)strlcpy(netdev->name, netdev->link, IFNAMSIZ);
61302ef7 783
75b074ee
CB
784 /*
785 * Store the ifindex of the host's network device in the host's
790255cf
CB
786 * namespace.
787 */
788 netdev->priv.phys_attr.ifindex = netdev->ifindex;
789
75b074ee
CB
790 /*
791 * Get original device MTU setting and store for restoration after
792 * container shutdown.
793 */
0b154989 794 mtu_orig = netdev_get_mtu(netdev->ifindex);
9c66dc4f
CB
795 if (mtu_orig < 0)
796 return log_error_errno(-1, -mtu_orig, "Failed to get original mtu for interface \"%s\"", netdev->link);
0b154989
TP
797
798 netdev->priv.phys_attr.mtu = mtu_orig;
799
3bef7b7b 800 if (netdev->mtu) {
54256301
CB
801 unsigned int mtu;
802
3bef7b7b 803 err = lxc_safe_uint(netdev->mtu, &mtu);
9c66dc4f
CB
804 if (err < 0)
805 return log_error_errno(-1, -err, "Failed to parse mtu \"%s\" for interface \"%s\"", netdev->mtu, netdev->link);
14a7b0f9 806
3bef7b7b 807 err = lxc_netdev_set_mtu(netdev->link, mtu);
9c66dc4f
CB
808 if (err < 0)
809 return log_error_errno(-1, -err, "Failed to set mtu \"%s\" for interface \"%s\"", netdev->mtu, netdev->link);
3bef7b7b
TP
810 }
811
812 if (netdev->upscript) {
813 char *argv[] = {
814 "phys",
815 netdev->link,
816 NULL,
817 };
818
75b074ee
CB
819 err = run_script_argv(handler->name, handler->conf->hooks_version,
820 "net", netdev->upscript, "up", argv);
9c66dc4f 821 if (err < 0)
3bef7b7b 822 return -1;
3bef7b7b
TP
823 }
824
75b074ee
CB
825 DEBUG("Instantiated phys \"%s\" with ifindex is \"%d\"", netdev->link,
826 netdev->ifindex);
811ef482
CB
827
828 return 0;
829}
830
831static int instantiate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
832{
14a7b0f9
CB
833 int ret;
834 char *argv[] = {
835 "empty",
836 NULL,
837 };
838
811ef482 839 netdev->ifindex = 0;
14a7b0f9
CB
840 if (!netdev->upscript)
841 return 0;
842
843 ret = run_script_argv(handler->name, handler->conf->hooks_version,
844 "net", netdev->upscript, "up", argv);
845 if (ret < 0)
846 return -1;
847
811ef482
CB
848 return 0;
849}
850
851static int instantiate_none(struct lxc_handler *handler, struct lxc_netdev *netdev)
852{
853 netdev->ifindex = 0;
854 return 0;
855}
856
857static instantiate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = {
858 [LXC_NET_VETH] = instantiate_veth,
859 [LXC_NET_MACVLAN] = instantiate_macvlan,
c9f52382 860 [LXC_NET_IPVLAN] = instantiate_ipvlan,
811ef482
CB
861 [LXC_NET_VLAN] = instantiate_vlan,
862 [LXC_NET_PHYS] = instantiate_phys,
863 [LXC_NET_EMPTY] = instantiate_empty,
864 [LXC_NET_NONE] = instantiate_none,
865};
866
9d0406c7 867static int __instantiate_ns_common(struct lxc_netdev *netdev)
8bf64b77
CB
868{
869 char current_ifname[IFNAMSIZ];
870
871 netdev->ifindex = if_nametoindex(netdev->created_name);
872 if (!netdev->ifindex)
873 return log_error_errno(-1,
874 errno, "Failed to retrieve ifindex for network device with name %s",
875 netdev->created_name);
876
3473ca76 877 if (is_empty_string(netdev->name))
8bf64b77
CB
878 (void)strlcpy(netdev->name, "eth%d", IFNAMSIZ);
879
880 if (strcmp(netdev->created_name, netdev->name) != 0) {
881 int ret;
882
883 ret = lxc_netdev_rename_by_name(netdev->created_name, netdev->name);
884 if (ret)
9c66dc4f 885 return log_error_errno(-1, -ret, "Failed to rename network device \"%s\" to \"%s\"",
8bf64b77
CB
886 netdev->created_name,
887 netdev->name);
888
889 TRACE("Renamed network device from \"%s\" to \"%s\"", netdev->created_name, netdev->name);
890 }
891
892 /*
893 * Re-read the name of the interface because its name has changed and
894 * would be automatically allocated by the system
895 */
896 if (!if_indextoname(netdev->ifindex, current_ifname))
9c66dc4f 897 return log_error_errno(-1, errno, "Failed get name for network device with ifindex %d", netdev->ifindex);
8bf64b77
CB
898
899 /*
900 * Now update the recorded name of the network device to reflect the
901 * name of the network device in the child's network namespace. We will
902 * later on send this information back to the parent.
903 */
904 (void)strlcpy(netdev->name, current_ifname, IFNAMSIZ);
905
906 return 0;
907}
908
717f77f2 909static int instantiate_ns_veth(struct lxc_netdev *netdev)
8bf64b77 910{
8bf64b77 911
9d0406c7 912 return __instantiate_ns_common(netdev);
8bf64b77
CB
913}
914
915static int instantiate_ns_macvlan(struct lxc_netdev *netdev)
916{
9d0406c7 917 return __instantiate_ns_common(netdev);
8bf64b77
CB
918}
919
920static int instantiate_ns_ipvlan(struct lxc_netdev *netdev)
921{
9d0406c7 922 return __instantiate_ns_common(netdev);
8bf64b77
CB
923}
924
925static int instantiate_ns_vlan(struct lxc_netdev *netdev)
926{
9d0406c7 927 return __instantiate_ns_common(netdev);
8bf64b77
CB
928}
929
930static int instantiate_ns_phys(struct lxc_netdev *netdev)
931{
9d0406c7 932 return __instantiate_ns_common(netdev);
8bf64b77
CB
933}
934
935static int instantiate_ns_empty(struct lxc_netdev *netdev)
936{
937 return 0;
938}
939
940static int instantiate_ns_none(struct lxc_netdev *netdev)
941{
942 return 0;
943}
944
945static instantiate_ns_cb netdev_ns_conf[LXC_NET_MAXCONFTYPE + 1] = {
946 [LXC_NET_VETH] = instantiate_ns_veth,
947 [LXC_NET_MACVLAN] = instantiate_ns_macvlan,
948 [LXC_NET_IPVLAN] = instantiate_ns_ipvlan,
949 [LXC_NET_VLAN] = instantiate_ns_vlan,
950 [LXC_NET_PHYS] = instantiate_ns_phys,
951 [LXC_NET_EMPTY] = instantiate_ns_empty,
952 [LXC_NET_NONE] = instantiate_ns_none,
953};
954
811ef482
CB
955static int shutdown_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
956{
14a7b0f9
CB
957 int ret;
958 char *argv[] = {
959 "veth",
960 netdev->link,
961 NULL,
962 NULL,
963 };
964
965 if (!netdev->downscript)
966 return 0;
811ef482 967
f2711167 968 if (!is_empty_string(netdev->priv.veth_attr.pair))
14a7b0f9 969 argv[2] = netdev->priv.veth_attr.pair;
811ef482 970 else
14a7b0f9
CB
971 argv[2] = netdev->priv.veth_attr.veth1;
972
973 ret = run_script_argv(handler->name,
974 handler->conf->hooks_version, "net",
975 netdev->downscript, "down", argv);
976 if (ret < 0)
977 return -1;
811ef482 978
811ef482
CB
979 return 0;
980}
981
982static int shutdown_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
983{
14a7b0f9
CB
984 int ret;
985 char *argv[] = {
986 "macvlan",
987 netdev->link,
988 NULL,
989 };
990
991 if (!netdev->downscript)
992 return 0;
993
994 ret = run_script_argv(handler->name, handler->conf->hooks_version,
995 "net", netdev->downscript, "down", argv);
996 if (ret < 0)
997 return -1;
811ef482 998
811ef482
CB
999 return 0;
1000}
1001
c9f52382 1002static int shutdown_ipvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
1003{
1004 int ret;
1005 char *argv[] = {
1006 "ipvlan",
1007 netdev->link,
1008 NULL,
1009 };
1010
1011 if (!netdev->downscript)
1012 return 0;
1013
1014 ret = run_script_argv(handler->name, handler->conf->hooks_version,
1015 "net", netdev->downscript, "down", argv);
1016 if (ret < 0)
1017 return -1;
1018
1019 return 0;
1020}
1021
811ef482
CB
1022static int shutdown_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
1023{
3a73d9f1 1024 int ret;
1025 char *argv[] = {
1026 "vlan",
1027 netdev->link,
1028 NULL,
1029 };
1030
1031 if (!netdev->downscript)
1032 return 0;
1033
1034 ret = run_script_argv(handler->name, handler->conf->hooks_version,
1035 "net", netdev->downscript, "down", argv);
1036 if (ret < 0)
1037 return -1;
1038
811ef482
CB
1039 return 0;
1040}
1041
1042static int shutdown_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
1043{
14a7b0f9
CB
1044 int ret;
1045 char *argv[] = {
1046 "phys",
1047 netdev->link,
1048 NULL,
1049 };
1050
1051 if (!netdev->downscript)
1052 return 0;
1053
1054 ret = run_script_argv(handler->name, handler->conf->hooks_version,
1055 "net", netdev->downscript, "down", argv);
1056 if (ret < 0)
1057 return -1;
811ef482 1058
811ef482
CB
1059 return 0;
1060}
1061
1062static int shutdown_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
1063{
14a7b0f9
CB
1064 int ret;
1065 char *argv[] = {
1066 "empty",
1067 NULL,
1068 };
1069
1070 if (!netdev->downscript)
1071 return 0;
1072
1073 ret = run_script_argv(handler->name, handler->conf->hooks_version,
1074 "net", netdev->downscript, "down", argv);
1075 if (ret < 0)
1076 return -1;
811ef482 1077
811ef482
CB
1078 return 0;
1079}
1080
1081static int shutdown_none(struct lxc_handler *handler, struct lxc_netdev *netdev)
1082{
1083 return 0;
1084}
1085
1086static instantiate_cb netdev_deconf[LXC_NET_MAXCONFTYPE + 1] = {
1087 [LXC_NET_VETH] = shutdown_veth,
1088 [LXC_NET_MACVLAN] = shutdown_macvlan,
c9f52382 1089 [LXC_NET_IPVLAN] = shutdown_ipvlan,
811ef482
CB
1090 [LXC_NET_VLAN] = shutdown_vlan,
1091 [LXC_NET_PHYS] = shutdown_phys,
1092 [LXC_NET_EMPTY] = shutdown_empty,
1093 [LXC_NET_NONE] = shutdown_none,
1094};
1095
0037ab49
TP
1096static int lxc_netdev_move_by_index_fd(int ifindex, int fd, const char *ifname)
1097{
d16bda44 1098 call_cleaner(nlmsg_free) struct nlmsg *nlmsg = NULL;
0037ab49 1099 struct nl_handler nlh;
d16bda44
CB
1100 call_cleaner(netlink_close) struct nl_handler *nlh_ptr = &nlh;
1101 int err;
0037ab49 1102 struct ifinfomsg *ifi;
0037ab49 1103
d16bda44 1104 err = netlink_open(nlh_ptr, NETLINK_ROUTE);
0037ab49
TP
1105 if (err)
1106 return err;
1107
0037ab49
TP
1108 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
1109 if (!nlmsg)
d16bda44 1110 return ret_errno(ENOMEM);
0037ab49
TP
1111
1112 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1113 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
1114
1115 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
1116 if (!ifi)
d16bda44
CB
1117 return ret_errno(ENOMEM);
1118
0037ab49
TP
1119 ifi->ifi_family = AF_UNSPEC;
1120 ifi->ifi_index = ifindex;
1121
1122 if (nla_put_u32(nlmsg, IFLA_NET_NS_FD, fd))
d16bda44 1123 return ret_errno(ENOMEM);
0037ab49 1124
3473ca76 1125 if (!is_empty_string(ifname) && nla_put_string(nlmsg, IFLA_IFNAME, ifname))
d16bda44 1126 return ret_errno(ENOMEM);
0037ab49 1127
d16bda44 1128 return netlink_transaction(nlh_ptr, nlmsg, nlmsg);
0037ab49
TP
1129}
1130
ebc73a67 1131int lxc_netdev_move_by_index(int ifindex, pid_t pid, const char *ifname)
0ad19a3f 1132{
d16bda44 1133 call_cleaner(nlmsg_free) struct nlmsg *nlmsg = NULL;
0ad19a3f 1134 struct nl_handler nlh;
d16bda44
CB
1135 call_cleaner(netlink_close) struct nl_handler *nlh_ptr = &nlh;
1136 int err;
06f976ca 1137 struct ifinfomsg *ifi;
0ad19a3f 1138
d16bda44 1139 err = netlink_open(nlh_ptr, NETLINK_ROUTE);
3cfc0f3a
MN
1140 if (err)
1141 return err;
0ad19a3f 1142
0ad19a3f 1143 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
1144 if (!nlmsg)
d16bda44 1145 return ret_errno(ENOMEM);
0ad19a3f 1146
ebc73a67 1147 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
06f976ca
SZ
1148 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
1149
1150 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
25a9939b 1151 if (!ifi)
d16bda44
CB
1152 return ret_errno(ENOMEM);
1153
06f976ca
SZ
1154 ifi->ifi_family = AF_UNSPEC;
1155 ifi->ifi_index = ifindex;
0ad19a3f 1156
1157 if (nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid))
d16bda44 1158 return ret_errno(ENOMEM);
0ad19a3f 1159
3473ca76 1160 if (!is_empty_string(ifname) && nla_put_string(nlmsg, IFLA_IFNAME, ifname))
d16bda44 1161 return ret_errno(ENOMEM);
8d357196 1162
d16bda44 1163 return netlink_transaction(nlh_ptr, nlmsg, nlmsg);
0ad19a3f 1164}
1165
ebc73a67
CB
1166/* If we are asked to move a wireless interface, then we must actually move its
1167 * phyN device. Detect that condition and return the physname here. The physname
1168 * will be passed to lxc_netdev_move_wlan() which will free it when done.
e5848d39
SH
1169 */
1170#define PHYSNAME "/sys/class/net/%s/phy80211/name"
e4103cf6 1171char *is_wlan(const char *ifname)
e5848d39 1172{
4110345b
CB
1173 __do_fclose FILE *f = NULL;
1174 __do_free char *path = NULL, *physname = NULL;
ebc73a67 1175 int i, ret;
e5848d39 1176 long physlen;
ebc73a67 1177 size_t len;
e5848d39 1178
ebc73a67 1179 len = strlen(ifname) + strlen(PHYSNAME) - 1;
95ea3d1f 1180 path = must_realloc(NULL, len + 1);
e5848d39 1181 ret = snprintf(path, len, PHYSNAME, ifname);
ebc73a67 1182 if (ret < 0 || (size_t)ret >= len)
4110345b 1183 return NULL;
ebc73a67 1184
4110345b 1185 f = fopen(path, "re");
ebc73a67 1186 if (!f)
4110345b 1187 return NULL;
ebc73a67 1188
1a0e70ac 1189 /* Feh - sb.st_size is always 4096. */
e5848d39
SH
1190 fseek(f, 0, SEEK_END);
1191 physlen = ftell(f);
1192 fseek(f, 0, SEEK_SET);
4110345b
CB
1193 if (physlen < 0)
1194 return NULL;
ebc73a67
CB
1195
1196 physname = malloc(physlen + 1);
4110345b
CB
1197 if (!physname)
1198 return NULL;
ebc73a67
CB
1199
1200 memset(physname, 0, physlen + 1);
e5848d39 1201 ret = fread(physname, 1, physlen, f);
e5848d39 1202 if (ret < 0)
4110345b 1203 return NULL;
e5848d39 1204
ebc73a67 1205 for (i = 0; i < physlen; i++) {
e5848d39
SH
1206 if (physname[i] == '\n')
1207 physname[i] = '\0';
ebc73a67 1208
e5848d39
SH
1209 if (physname[i] == '\0')
1210 break;
1211 }
1212
4110345b 1213 return move_ptr(physname);
e5848d39
SH
1214}
1215
ebc73a67
CB
1216static int lxc_netdev_rename_by_name_in_netns(pid_t pid, const char *old,
1217 const char *new)
e5848d39 1218{
ebc73a67 1219 pid_t fpid;
e5848d39 1220
ebc73a67 1221 fpid = fork();
e5848d39
SH
1222 if (fpid < 0)
1223 return -1;
ebc73a67 1224
e5848d39
SH
1225 if (fpid != 0)
1226 return wait_for_pid(fpid);
ebc73a67 1227
e5848d39
SH
1228 if (!switch_to_ns(pid, "net"))
1229 return -1;
ebc73a67 1230
05ec44f8 1231 _exit(lxc_netdev_rename_by_name(old, new));
e5848d39
SH
1232}
1233
e4103cf6 1234int lxc_netdev_move_wlan(char *physname, const char *ifname, pid_t pid,
ebc73a67 1235 const char *newname)
e5848d39 1236{
3dd78294 1237 __do_free char *cmd = NULL;
ebc73a67 1238 pid_t fpid;
e5848d39
SH
1239
1240 /* Move phyN into the container. TODO - do this using netlink.
ebc73a67
CB
1241 * However, IIUC this involves a bit more complicated work to talk to
1242 * the 80211 module, so for now just call out to iw.
e5848d39
SH
1243 */
1244 cmd = on_path("iw", NULL);
9c66dc4f 1245 if (!cmd)
3dd78294 1246 return -1;
e5848d39
SH
1247
1248 fpid = fork();
1249 if (fpid < 0)
3dd78294 1250 return -1;
ebc73a67 1251
e5848d39
SH
1252 if (fpid == 0) {
1253 char pidstr[30];
1254 sprintf(pidstr, "%d", pid);
9c66dc4f 1255 execlp("iw", "iw", "phy", physname, "set", "netns", pidstr, (char *)NULL);
ebd582ae 1256 _exit(EXIT_FAILURE);
e5848d39 1257 }
ebc73a67 1258
e5848d39 1259 if (wait_for_pid(fpid))
3dd78294 1260 return -1;
e5848d39 1261
e5848d39 1262 if (newname)
3dd78294 1263 return lxc_netdev_rename_by_name_in_netns(pid, ifname, newname);
e5848d39 1264
3dd78294 1265 return 0;
e5848d39
SH
1266}
1267
8d357196 1268int lxc_netdev_move_by_name(const char *ifname, pid_t pid, const char* newname)
8befa924 1269{
3dd78294 1270 __do_free char *physname = NULL;
8befa924
SH
1271 int index;
1272
8befa924
SH
1273 if (!ifname)
1274 return -EINVAL;
1275
32571606 1276 index = if_nametoindex(ifname);
49428bf3
DY
1277 if (!index)
1278 return -EINVAL;
32571606 1279
ebc73a67
CB
1280 physname = is_wlan(ifname);
1281 if (physname)
e5848d39
SH
1282 return lxc_netdev_move_wlan(physname, ifname, pid, newname);
1283
8d357196 1284 return lxc_netdev_move_by_index(index, pid, newname);
8befa924
SH
1285}
1286
b84f58b9 1287int lxc_netdev_delete_by_index(int ifindex)
0ad19a3f 1288{
d16bda44
CB
1289 call_cleaner(nlmsg_free) struct nlmsg *answer = NULL, *nlmsg = NULL;
1290 struct nl_handler nlh;
1291 call_cleaner(netlink_close) struct nl_handler *nlh_ptr = &nlh;
b84f58b9 1292 int err;
ebc73a67 1293 struct ifinfomsg *ifi;
0ad19a3f 1294
d16bda44 1295 err = netlink_open(nlh_ptr, NETLINK_ROUTE);
3cfc0f3a
MN
1296 if (err)
1297 return err;
0ad19a3f 1298
0ad19a3f 1299 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
1300 if (!nlmsg)
d16bda44 1301 return ret_errno(ENOMEM);
0ad19a3f 1302
06f976ca 1303 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
0ad19a3f 1304 if (!answer)
d16bda44 1305 return ret_errno(ENOMEM);
0ad19a3f 1306
ebc73a67 1307 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_ACK | NLM_F_REQUEST;
06f976ca
SZ
1308 nlmsg->nlmsghdr->nlmsg_type = RTM_DELLINK;
1309
1310 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
25a9939b 1311 if (!ifi)
d16bda44
CB
1312 return ret_errno(ENOMEM);
1313
06f976ca
SZ
1314 ifi->ifi_family = AF_UNSPEC;
1315 ifi->ifi_index = ifindex;
0ad19a3f 1316
d16bda44 1317 return netlink_transaction(nlh_ptr, nlmsg, answer);
0ad19a3f 1318}
1319
b84f58b9
DL
1320int lxc_netdev_delete_by_name(const char *name)
1321{
1322 int index;
1323
1324 index = if_nametoindex(name);
1325 if (!index)
1326 return -EINVAL;
1327
1328 return lxc_netdev_delete_by_index(index);
1329}
1330
1331int lxc_netdev_rename_by_index(int ifindex, const char *newname)
b9a5bb58 1332{
d16bda44
CB
1333 call_cleaner(nlmsg_free) struct nlmsg *answer = NULL, *nlmsg = NULL;
1334 struct nl_handler nlh;
1335 call_cleaner(netlink_close) struct nl_handler *nlh_ptr = &nlh;
ebc73a67 1336 int err, len;
06f976ca 1337 struct ifinfomsg *ifi;
b9a5bb58 1338
d16bda44 1339 err = netlink_open(nlh_ptr, NETLINK_ROUTE);
3cfc0f3a
MN
1340 if (err)
1341 return err;
b9a5bb58 1342
b84f58b9 1343 len = strlen(newname);
d16bda44
CB
1344 if (len == 1 || len >= IFNAMSIZ)
1345 return ret_errno(EINVAL);
b84f58b9 1346
b9a5bb58
DL
1347 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
1348 if (!nlmsg)
d16bda44 1349 return ret_errno(ENOMEM);
b9a5bb58 1350
06f976ca 1351 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
b9a5bb58 1352 if (!answer)
d16bda44 1353 return ret_errno(ENOMEM);
b9a5bb58 1354
ebc73a67 1355 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_ACK | NLM_F_REQUEST;
06f976ca
SZ
1356 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
1357
1358 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
25a9939b 1359 if (!ifi)
d16bda44
CB
1360 return ret_errno(ENOMEM);
1361
06f976ca
SZ
1362 ifi->ifi_family = AF_UNSPEC;
1363 ifi->ifi_index = ifindex;
b84f58b9
DL
1364
1365 if (nla_put_string(nlmsg, IFLA_IFNAME, newname))
d16bda44 1366 return ret_errno(ENOMEM);
b9a5bb58 1367
d16bda44 1368 return netlink_transaction(nlh_ptr, nlmsg, answer);
b9a5bb58
DL
1369}
1370
b84f58b9
DL
1371int lxc_netdev_rename_by_name(const char *oldname, const char *newname)
1372{
1373 int len, index;
1374
1375 len = strlen(oldname);
dae3fdf6 1376 if (len == 1 || len >= IFNAMSIZ)
b84f58b9
DL
1377 return -EINVAL;
1378
1379 index = if_nametoindex(oldname);
1380 if (!index)
1381 return -EINVAL;
1382
1383 return lxc_netdev_rename_by_index(index, newname);
1384}
1385
8befa924 1386int netdev_set_flag(const char *name, int flag)
0ad19a3f 1387{
d16bda44
CB
1388 call_cleaner(nlmsg_free) struct nlmsg *answer = NULL, *nlmsg = NULL;
1389 struct nl_handler nlh;
1390 call_cleaner(netlink_close) struct nl_handler *nlh_ptr = &nlh;
ebc73a67 1391 int err, index, len;
06f976ca 1392 struct ifinfomsg *ifi;
0ad19a3f 1393
d16bda44 1394 err = netlink_open(nlh_ptr, NETLINK_ROUTE);
3cfc0f3a
MN
1395 if (err)
1396 return err;
0ad19a3f 1397
1398 len = strlen(name);
dae3fdf6 1399 if (len == 1 || len >= IFNAMSIZ)
d16bda44 1400 return ret_errno(EINVAL);
0ad19a3f 1401
1402 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
1403 if (!nlmsg)
d16bda44 1404 return ret_errno(ENOMEM);
0ad19a3f 1405
06f976ca 1406 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
0ad19a3f 1407 if (!answer)
d16bda44 1408 return ret_errno(ENOMEM);
0ad19a3f 1409
1410 index = if_nametoindex(name);
1411 if (!index)
d16bda44 1412 return ret_errno(EINVAL);
0ad19a3f 1413
ebc73a67 1414 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
06f976ca
SZ
1415 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
1416
1417 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
d16bda44
CB
1418 if (!ifi)
1419 return ret_errno(ENOMEM);
1420
06f976ca
SZ
1421 ifi->ifi_family = AF_UNSPEC;
1422 ifi->ifi_index = index;
1423 ifi->ifi_change |= IFF_UP;
1424 ifi->ifi_flags |= flag;
0ad19a3f 1425
d16bda44 1426 return netlink_transaction(nlh_ptr, nlmsg, answer);
0ad19a3f 1427}
1428
ebc73a67 1429int netdev_get_flag(const char *name, int *flag)
efa1cf45 1430{
d16bda44
CB
1431 call_cleaner(nlmsg_free) struct nlmsg *answer = NULL, *nlmsg = NULL;
1432 struct nl_handler nlh;
1433 call_cleaner(netlink_close) struct nl_handler *nlh_ptr = &nlh;
ebc73a67 1434 int err, index, len;
a4318300 1435 struct ifinfomsg *ifi;
efa1cf45
DY
1436
1437 if (!name)
d16bda44 1438 return ret_errno(EINVAL);
efa1cf45 1439
d16bda44 1440 err = netlink_open(nlh_ptr, NETLINK_ROUTE);
efa1cf45
DY
1441 if (err)
1442 return err;
1443
efa1cf45
DY
1444 len = strlen(name);
1445 if (len == 1 || len >= IFNAMSIZ)
d16bda44 1446 return ret_errno(EINVAL);
efa1cf45 1447
efa1cf45
DY
1448 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
1449 if (!nlmsg)
d16bda44 1450 return ret_errno(ENOMEM);
efa1cf45 1451
06f976ca 1452 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
efa1cf45 1453 if (!answer)
d16bda44 1454 return ret_errno(ENOMEM);
efa1cf45 1455
efa1cf45
DY
1456 index = if_nametoindex(name);
1457 if (!index)
d16bda44 1458 return ret_errno(EINVAL);
efa1cf45 1459
06f976ca
SZ
1460 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST;
1461 nlmsg->nlmsghdr->nlmsg_type = RTM_GETLINK;
1462
1463 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
d16bda44
CB
1464 if (!ifi)
1465 return ret_errno(ENOMEM);
1466
06f976ca
SZ
1467 ifi->ifi_family = AF_UNSPEC;
1468 ifi->ifi_index = index;
efa1cf45 1469
d16bda44 1470 err = netlink_transaction(nlh_ptr, nlmsg, answer);
efa1cf45 1471 if (err)
d16bda44 1472 return ret_set_errno(-1, errno);
efa1cf45 1473
06f976ca 1474 ifi = NLMSG_DATA(answer->nlmsghdr);
efa1cf45
DY
1475
1476 *flag = ifi->ifi_flags;
efa1cf45
DY
1477 return err;
1478}
1479
1480/*
1481 * \brief Check a interface is up or not.
1482 *
1483 * \param name: name for the interface.
1484 *
1485 * \return int.
1486 * 0 means interface is down.
1487 * 1 means interface is up.
1488 * Others means error happened, and ret-value is the error number.
1489 */
ebc73a67 1490int lxc_netdev_isup(const char *name)
efa1cf45 1491{
ebc73a67 1492 int err, flag;
efa1cf45
DY
1493
1494 err = netdev_get_flag(name, &flag);
1495 if (err)
ebc73a67
CB
1496 return err;
1497
efa1cf45
DY
1498 if (flag & IFF_UP)
1499 return 1;
ebc73a67 1500
efa1cf45 1501 return 0;
efa1cf45
DY
1502}
1503
0130df54
SH
1504int netdev_get_mtu(int ifindex)
1505{
a5f5cb41 1506 call_cleaner(nlmsg_free) struct nlmsg *answer = NULL, *nlmsg = NULL;
0130df54 1507 struct nl_handler nlh;
a5f5cb41
CB
1508 call_cleaner(netlink_close) struct nl_handler *nlh_ptr = &nlh;
1509 int readmore = 0, recv_len = 0;
1510 int answer_len, err, res;
06f976ca 1511 struct ifinfomsg *ifi;
0130df54 1512 struct nlmsghdr *msg;
0130df54 1513
a5f5cb41 1514 err = netlink_open(nlh_ptr, NETLINK_ROUTE);
0130df54
SH
1515 if (err)
1516 return err;
1517
0130df54
SH
1518 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
1519 if (!nlmsg)
a5f5cb41 1520 return ret_errno(ENOMEM);
0130df54 1521
06f976ca 1522 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
0130df54 1523 if (!answer)
a5f5cb41 1524 return ret_errno(ENOMEM);
0130df54
SH
1525
1526 /* Save the answer buffer length, since it will be overwritten
1527 * on the first receive (and we might need to receive more than
ebc73a67
CB
1528 * once.
1529 */
06f976ca
SZ
1530 answer_len = answer->nlmsghdr->nlmsg_len;
1531
ebc73a67 1532 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
06f976ca 1533 nlmsg->nlmsghdr->nlmsg_type = RTM_GETLINK;
0130df54 1534
06f976ca 1535 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
25a9939b 1536 if (!ifi)
a5f5cb41
CB
1537 return ret_errno(ENOMEM);
1538
06f976ca 1539 ifi->ifi_family = AF_UNSPEC;
0130df54
SH
1540
1541 /* Send the request for addresses, which returns all addresses
1542 * on all interfaces. */
a5f5cb41 1543 err = netlink_send(nlh_ptr, nlmsg);
0130df54 1544 if (err < 0)
a5f5cb41 1545 return ret_set_errno(-1, errno);
0130df54 1546
6ce39620
CB
1547#pragma GCC diagnostic push
1548#pragma GCC diagnostic ignored "-Wcast-align"
1549
0130df54
SH
1550 do {
1551 /* Restore the answer buffer length, it might have been
ebc73a67
CB
1552 * overwritten by a previous receive.
1553 */
06f976ca 1554 answer->nlmsghdr->nlmsg_len = answer_len;
0130df54
SH
1555
1556 /* Get the (next) batch of reply messages */
a5f5cb41 1557 err = netlink_rcv(nlh_ptr, answer);
0130df54 1558 if (err < 0)
a5f5cb41 1559 return ret_set_errno(-1, errno);
0130df54
SH
1560
1561 recv_len = err;
0130df54
SH
1562
1563 /* Satisfy the typing for the netlink macros */
06f976ca 1564 msg = answer->nlmsghdr;
0130df54
SH
1565
1566 while (NLMSG_OK(msg, recv_len)) {
0130df54
SH
1567 /* Stop reading if we see an error message */
1568 if (msg->nlmsg_type == NLMSG_ERROR) {
a5f5cb41
CB
1569 struct nlmsgerr *errmsg = (struct nlmsgerr *)NLMSG_DATA(msg);
1570 return ret_set_errno(errmsg->error, errno);
0130df54
SH
1571 }
1572
1573 /* Stop reading if we see a NLMSG_DONE message */
1574 if (msg->nlmsg_type == NLMSG_DONE) {
1575 readmore = 0;
1576 break;
1577 }
1578
06f976ca 1579 ifi = NLMSG_DATA(msg);
0130df54
SH
1580 if (ifi->ifi_index == ifindex) {
1581 struct rtattr *rta = IFLA_RTA(ifi);
a5f5cb41
CB
1582 int attr_len = msg->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
1583
0130df54 1584 res = 0;
ebc73a67 1585 while (RTA_OK(rta, attr_len)) {
9c66dc4f 1586 /*
a5f5cb41 1587 * Found a local address for the
ebc73a67
CB
1588 * requested interface, return it.
1589 */
0130df54 1590 if (rta->rta_type == IFLA_MTU) {
a5f5cb41
CB
1591 memcpy(&res, RTA_DATA(rta), sizeof(int));
1592 return res;
0130df54 1593 }
a5f5cb41 1594
0130df54
SH
1595 rta = RTA_NEXT(rta, attr_len);
1596 }
0130df54
SH
1597 }
1598
ebc73a67
CB
1599 /* Keep reading more data from the socket if the last
1600 * message had the NLF_F_MULTI flag set.
1601 */
0130df54
SH
1602 readmore = (msg->nlmsg_flags & NLM_F_MULTI);
1603
ebc73a67 1604 /* Look at the next message received in this buffer. */
0130df54
SH
1605 msg = NLMSG_NEXT(msg, recv_len);
1606 }
1607 } while (readmore);
1608
6ce39620
CB
1609#pragma GCC diagnostic pop
1610
ebc73a67 1611 /* If we end up here, we didn't find any result, so signal an error. */
a5f5cb41 1612 return -1;
0130df54
SH
1613}
1614
d472214b 1615int lxc_netdev_set_mtu(const char *name, int mtu)
75d09f83 1616{
a5f5cb41
CB
1617 call_cleaner(nlmsg_free) struct nlmsg *answer = NULL, *nlmsg = NULL;
1618 struct nl_handler nlh;
1619 call_cleaner(netlink_close) struct nl_handler *nlh_ptr = &nlh;
54256301 1620 int err, len;
06f976ca 1621 struct ifinfomsg *ifi;
75d09f83 1622
a5f5cb41 1623 err = netlink_open(nlh_ptr, NETLINK_ROUTE);
3cfc0f3a
MN
1624 if (err)
1625 return err;
75d09f83
DL
1626
1627 len = strlen(name);
dae3fdf6 1628 if (len == 1 || len >= IFNAMSIZ)
a5f5cb41 1629 return ret_errno(EINVAL);
75d09f83
DL
1630
1631 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
1632 if (!nlmsg)
a5f5cb41 1633 return ret_errno(ENOMEM);
75d09f83 1634
06f976ca 1635 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
75d09f83 1636 if (!answer)
a5f5cb41 1637 return ret_errno(ENOMEM);
75d09f83 1638
ebc73a67 1639 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
06f976ca
SZ
1640 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
1641
1642 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
a5f5cb41
CB
1643 if (!ifi)
1644 return ret_errno(ENOMEM);
1645
06f976ca 1646 ifi->ifi_family = AF_UNSPEC;
54256301
CB
1647
1648 if (nla_put_string(nlmsg, IFLA_IFNAME, name))
a5f5cb41 1649 return ret_errno(ENOMEM);
75d09f83
DL
1650
1651 if (nla_put_u32(nlmsg, IFLA_MTU, mtu))
a5f5cb41 1652 return ret_errno(ENOMEM);
75d09f83 1653
a5f5cb41 1654 return netlink_transaction(nlh_ptr, nlmsg, answer);
75d09f83
DL
1655}
1656
d472214b 1657int lxc_netdev_up(const char *name)
0ad19a3f 1658{
d472214b 1659 return netdev_set_flag(name, IFF_UP);
0ad19a3f 1660}
1661
d472214b 1662int lxc_netdev_down(const char *name)
0ad19a3f 1663{
d472214b 1664 return netdev_set_flag(name, 0);
0ad19a3f 1665}
1666
54256301 1667int lxc_veth_create(const char *name1, const char *name2, pid_t pid, unsigned int mtu)
0ad19a3f 1668{
a5f5cb41
CB
1669 call_cleaner(nlmsg_free) struct nlmsg *answer = NULL, *nlmsg = NULL;
1670 struct nl_handler nlh;
1671 call_cleaner(netlink_close) struct nl_handler *nlh_ptr = &nlh;
ebc73a67 1672 int err, len;
06f976ca 1673 struct ifinfomsg *ifi;
0ad19a3f 1674 struct rtattr *nest1, *nest2, *nest3;
0ad19a3f 1675
a5f5cb41 1676 err = netlink_open(nlh_ptr, NETLINK_ROUTE);
3cfc0f3a
MN
1677 if (err)
1678 return err;
0ad19a3f 1679
1680 len = strlen(name1);
dae3fdf6 1681 if (len == 1 || len >= IFNAMSIZ)
a5f5cb41 1682 return ret_errno(EINVAL);
0ad19a3f 1683
1684 len = strlen(name2);
dae3fdf6 1685 if (len == 1 || len >= IFNAMSIZ)
a5f5cb41 1686 return ret_errno(EINVAL);
0ad19a3f 1687
1688 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
1689 if (!nlmsg)
a5f5cb41 1690 return ret_errno(ENOMEM);
0ad19a3f 1691
06f976ca 1692 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
0ad19a3f 1693 if (!answer)
a5f5cb41 1694 return ret_errno(ENOMEM);
0ad19a3f 1695
a5f5cb41 1696 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
06f976ca
SZ
1697 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
1698
1699 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
25a9939b 1700 if (!ifi)
a5f5cb41
CB
1701 return ret_errno(ENOMEM);
1702
06f976ca 1703 ifi->ifi_family = AF_UNSPEC;
0ad19a3f 1704
79e68309 1705 nest1 = nla_begin_nested(nlmsg, IFLA_LINKINFO);
0ad19a3f 1706 if (!nest1)
a5f5cb41 1707 return ret_errno(EINVAL);
0ad19a3f 1708
1709 if (nla_put_string(nlmsg, IFLA_INFO_KIND, "veth"))
a5f5cb41 1710 return ret_errno(ENOMEM);
0ad19a3f 1711
1712 nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA);
1713 if (!nest2)
a5f5cb41 1714 return ret_errno(ENOMEM);
0ad19a3f 1715
1716 nest3 = nla_begin_nested(nlmsg, VETH_INFO_PEER);
1717 if (!nest3)
a5f5cb41 1718 return ret_errno(ENOMEM);
0ad19a3f 1719
06f976ca 1720 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
a5f5cb41
CB
1721 if (!ifi)
1722 return ret_errno(ENOMEM);
0ad19a3f 1723
1724 if (nla_put_string(nlmsg, IFLA_IFNAME, name2))
a5f5cb41 1725 return ret_errno(ENOMEM);
0ad19a3f 1726
54256301 1727 if (mtu > 0 && nla_put_u32(nlmsg, IFLA_MTU, mtu))
a5f5cb41 1728 return ret_errno(ENOMEM);
54256301
CB
1729
1730 if (pid > 0 && nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid))
a5f5cb41 1731 return ret_errno(ENOMEM);
54256301 1732
0ad19a3f 1733 nla_end_nested(nlmsg, nest3);
0ad19a3f 1734 nla_end_nested(nlmsg, nest2);
0ad19a3f 1735 nla_end_nested(nlmsg, nest1);
1736
1737 if (nla_put_string(nlmsg, IFLA_IFNAME, name1))
a5f5cb41 1738 return ret_errno(ENOMEM);
0ad19a3f 1739
a5f5cb41 1740 return netlink_transaction(nlh_ptr, nlmsg, answer);
0ad19a3f 1741}
1742
ebc73a67 1743/* TODO: merge with lxc_macvlan_create */
7c11d57a 1744int lxc_vlan_create(const char *master, const char *name, unsigned short vlanid)
26c39028 1745{
a5f5cb41
CB
1746 call_cleaner(nlmsg_free) struct nlmsg *answer = NULL, *nlmsg = NULL;
1747 struct nl_handler nlh;
1748 call_cleaner(netlink_close) struct nl_handler *nlh_ptr = &nlh;
ebc73a67 1749 int err, len, lindex;
06f976ca 1750 struct ifinfomsg *ifi;
26c39028 1751 struct rtattr *nest, *nest2;
26c39028 1752
a5f5cb41 1753 err = netlink_open(nlh_ptr, NETLINK_ROUTE);
3cfc0f3a
MN
1754 if (err)
1755 return err;
26c39028
JHS
1756
1757 len = strlen(master);
dae3fdf6 1758 if (len == 1 || len >= IFNAMSIZ)
a5f5cb41 1759 return ret_errno(EINVAL);
26c39028
JHS
1760
1761 len = strlen(name);
dae3fdf6 1762 if (len == 1 || len >= IFNAMSIZ)
a5f5cb41 1763 return ret_errno(EINVAL);
26c39028
JHS
1764
1765 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
1766 if (!nlmsg)
a5f5cb41 1767 return ret_errno(ENOMEM);
26c39028 1768
06f976ca 1769 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
26c39028 1770 if (!answer)
a5f5cb41 1771 return ret_errno(ENOMEM);
26c39028
JHS
1772
1773 lindex = if_nametoindex(master);
1774 if (!lindex)
a5f5cb41 1775 return ret_errno(EINVAL);
26c39028 1776
a5f5cb41 1777 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
06f976ca
SZ
1778 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
1779
1780 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
a5f5cb41
CB
1781 if (!ifi)
1782 return ret_errno(ENOMEM);
1783
06f976ca 1784 ifi->ifi_family = AF_UNSPEC;
26c39028 1785
79e68309 1786 nest = nla_begin_nested(nlmsg, IFLA_LINKINFO);
26c39028 1787 if (!nest)
a5f5cb41 1788 return ret_errno(ENOMEM);
26c39028
JHS
1789
1790 if (nla_put_string(nlmsg, IFLA_INFO_KIND, "vlan"))
a5f5cb41 1791 return ret_errno(ENOMEM);
26c39028
JHS
1792
1793 nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA);
1794 if (!nest2)
a5f5cb41 1795 return ret_errno(ENOMEM);
e892973e 1796
26c39028 1797 if (nla_put_u16(nlmsg, IFLA_VLAN_ID, vlanid))
a5f5cb41 1798 return ret_errno(ENOMEM);
e892973e 1799
26c39028 1800 nla_end_nested(nlmsg, nest2);
26c39028
JHS
1801 nla_end_nested(nlmsg, nest);
1802
1803 if (nla_put_u32(nlmsg, IFLA_LINK, lindex))
a5f5cb41 1804 return ret_errno(ENOMEM);
26c39028
JHS
1805
1806 if (nla_put_string(nlmsg, IFLA_IFNAME, name))
a5f5cb41
CB
1807 return ret_errno(ENOMEM);
1808
1809 return netlink_transaction(nlh_ptr, nlmsg, answer);
26c39028
JHS
1810}
1811
e892973e 1812int lxc_macvlan_create(const char *master, const char *name, int mode)
0ad19a3f 1813{
a5f5cb41
CB
1814 call_cleaner(nlmsg_free) struct nlmsg *answer = NULL, *nlmsg = NULL;
1815 struct nl_handler nlh;
1816 call_cleaner(netlink_close) struct nl_handler *nlh_ptr = &nlh;
ebc73a67 1817 int err, index, len;
06f976ca 1818 struct ifinfomsg *ifi;
e892973e 1819 struct rtattr *nest, *nest2;
0ad19a3f 1820
a5f5cb41 1821 err = netlink_open(nlh_ptr, NETLINK_ROUTE);
3cfc0f3a
MN
1822 if (err)
1823 return err;
0ad19a3f 1824
1825 len = strlen(master);
dae3fdf6 1826 if (len == 1 || len >= IFNAMSIZ)
a5f5cb41 1827 return ret_errno(EINVAL);
0ad19a3f 1828
1829 len = strlen(name);
dae3fdf6 1830 if (len == 1 || len >= IFNAMSIZ)
a5f5cb41 1831 return ret_errno(EINVAL);
0ad19a3f 1832
1833 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
1834 if (!nlmsg)
a5f5cb41 1835 return ret_errno(ENOMEM);
0ad19a3f 1836
06f976ca 1837 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
0ad19a3f 1838 if (!answer)
a5f5cb41 1839 return ret_errno(ENOMEM);
0ad19a3f 1840
1841 index = if_nametoindex(master);
1842 if (!index)
a5f5cb41 1843 return ret_errno(EINVAL);
0ad19a3f 1844
a5f5cb41 1845 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
06f976ca
SZ
1846 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;
1847
1848 ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
a5f5cb41
CB
1849 if (!ifi)
1850 return ret_errno(ENOMEM);
1851
06f976ca 1852 ifi->ifi_family = AF_UNSPEC;
0ad19a3f 1853
79e68309 1854 nest = nla_begin_nested(nlmsg, IFLA_LINKINFO);
0ad19a3f 1855 if (!nest)
a5f5cb41 1856 return ret_errno(ENOMEM);
0ad19a3f 1857
1858 if (nla_put_string(nlmsg, IFLA_INFO_KIND, "macvlan"))
a5f5cb41 1859 return ret_errno(ENOMEM);
0ad19a3f 1860
e892973e
DL
1861 if (mode) {
1862 nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA);
1863 if (!nest2)
a5f5cb41 1864 return ret_errno(ENOMEM);
e892973e
DL
1865
1866 if (nla_put_u32(nlmsg, IFLA_MACVLAN_MODE, mode))
a5f5cb41 1867 return ret_errno(ENOMEM);
e892973e
DL
1868
1869 nla_end_nested(nlmsg, nest2);
1870 }
1871
0ad19a3f 1872 nla_end_nested(nlmsg, nest);
1873
1874 if (nla_put_u32(nlmsg, IFLA_LINK, index))
a5f5cb41 1875 return ret_errno(ENOMEM);
0ad19a3f 1876
1877 if (nla_put_string(nlmsg, IFLA_IFNAME, name))
a5f5cb41 1878 return ret_errno(ENOMEM);
0ad19a3f 1879
a5f5cb41 1880 return netlink_transaction(nlh_ptr, nlmsg, answer);
0ad19a3f 1881}
1882
1883static int proc_sys_net_write(const char *path, const char *value)
1884{
ebc73a67
CB
1885 int fd;
1886 int err = 0;
0ad19a3f 1887
1888 fd = open(path, O_WRONLY);
1889 if (fd < 0)
1890 return -errno;
1891
f640cf46 1892 if (lxc_write_nointr(fd, value, strlen(value)) < 0)
0ad19a3f 1893 err = -errno;
1894
1895 close(fd);
1896 return err;
1897}
1898
6dfa9581 1899static int ip_forwarding_set(const char *ifname, int family, int flag)
6509154d 1900{
1901 int ret;
1902 char path[PATH_MAX];
6509154d 1903
1904 if (family != AF_INET && family != AF_INET6)
6dfa9581 1905 return -EINVAL;
6509154d 1906
9c66dc4f 1907 ret = snprintf(path, sizeof(path), "/proc/sys/net/%s/conf/%s/%s",
6dfa9581 1908 family == AF_INET ? "ipv4" : "ipv6", ifname, "forwarding");
9c66dc4f 1909 if (ret < 0 || (size_t)ret >= sizeof(path))
6dfa9581 1910 return -E2BIG;
6509154d 1911
6dfa9581
TP
1912 return proc_sys_net_write(path, flag ? "1" : "0");
1913}
1914
1915int lxc_ip_forwarding_on(const char *name, int family)
1916{
1917 return ip_forwarding_set(name, family, 1);
1918}
1919
1920int lxc_ip_forwarding_off(const char *name, int family)
1921{
1922 return ip_forwarding_set(name, family, 0);
6509154d 1923}
1924
0ad19a3f 1925static int neigh_proxy_set(const char *ifname, int family, int flag)
1926{
9ba8130c 1927 int ret;
419590da 1928 char path[PATH_MAX];
0ad19a3f 1929
1930 if (family != AF_INET && family != AF_INET6)
3cfc0f3a 1931 return -EINVAL;
0ad19a3f 1932
9c66dc4f 1933 ret = snprintf(path, sizeof(path), "/proc/sys/net/%s/conf/%s/%s",
ebc73a67
CB
1934 family == AF_INET ? "ipv4" : "ipv6", ifname,
1935 family == AF_INET ? "proxy_arp" : "proxy_ndp");
9c66dc4f 1936 if (ret < 0 || (size_t)ret >= sizeof(path))
9ba8130c 1937 return -E2BIG;
0ad19a3f 1938
ebc73a67 1939 return proc_sys_net_write(path, flag ? "1" : "0");
0ad19a3f 1940}
1941
6509154d 1942static int lxc_is_ip_neigh_proxy_enabled(const char *ifname, int family)
1943{
1944 int ret;
1945 char path[PATH_MAX];
1946 char buf[1] = "";
1947
1948 if (family != AF_INET && family != AF_INET6)
596a002c 1949 return ret_set_errno(-1, EINVAL);
6509154d 1950
9c66dc4f 1951 ret = snprintf(path, sizeof(path), "/proc/sys/net/%s/conf/%s/%s",
6509154d 1952 family == AF_INET ? "ipv4" : "ipv6", ifname,
1953 family == AF_INET ? "proxy_arp" : "proxy_ndp");
9c66dc4f 1954 if (ret < 0 || (size_t)ret >= sizeof(path))
596a002c 1955 return ret_set_errno(-1, E2BIG);
6509154d 1956
1957 return lxc_read_file_expect(path, buf, 1, "1");
1958}
1959
497353b6 1960int lxc_neigh_proxy_on(const char *name, int family)
0ad19a3f 1961{
1962 return neigh_proxy_set(name, family, 1);
1963}
1964
497353b6 1965int lxc_neigh_proxy_off(const char *name, int family)
0ad19a3f 1966{
1967 return neigh_proxy_set(name, family, 0);
1968}
1969
1970int lxc_convert_mac(char *macaddr, struct sockaddr *sockaddr)
1971{
1f1b18e7
DL
1972 int i = 0;
1973 unsigned val;
ebc73a67
CB
1974 char c;
1975 unsigned char *data;
1f1b18e7
DL
1976
1977 sockaddr->sa_family = ARPHRD_ETHER;
1978 data = (unsigned char *)sockaddr->sa_data;
1979
1980 while ((*macaddr != '\0') && (i < ETH_ALEN)) {
ebc73a67
CB
1981 c = *macaddr++;
1982 if (isdigit(c))
1983 val = c - '0';
1984 else if (c >= 'a' && c <= 'f')
1985 val = c - 'a' + 10;
1986 else if (c >= 'A' && c <= 'F')
1987 val = c - 'A' + 10;
1988 else
1989 return -EINVAL;
1990
1991 val <<= 4;
1992 c = *macaddr;
1993 if (isdigit(c))
1994 val |= c - '0';
1995 else if (c >= 'a' && c <= 'f')
1996 val |= c - 'a' + 10;
1997 else if (c >= 'A' && c <= 'F')
1998 val |= c - 'A' + 10;
1999 else if (c == ':' || c == 0)
2000 val >>= 4;
2001 else
2002 return -EINVAL;
2003 if (c != 0)
2004 macaddr++;
2005 *data++ = (unsigned char)(val & 0377);
2006 i++;
2007
2008 if (*macaddr == ':')
2009 macaddr++;
0ad19a3f 2010 }
0ad19a3f 2011
1f1b18e7 2012 return 0;
0ad19a3f 2013}
2014
ebc73a67
CB
2015static int ip_addr_add(int family, int ifindex, void *addr, void *bcast,
2016 void *acast, int prefix)
0ad19a3f 2017{
a5f5cb41
CB
2018 call_cleaner(nlmsg_free) struct nlmsg *answer = NULL, *nlmsg = NULL;
2019 struct nl_handler nlh;
2020 call_cleaner(netlink_close) struct nl_handler *nlh_ptr = &nlh;
ebc73a67 2021 int addrlen, err;
06f976ca 2022 struct ifaddrmsg *ifa;
0ad19a3f 2023
ebc73a67
CB
2024 addrlen = family == AF_INET ? sizeof(struct in_addr)
2025 : sizeof(struct in6_addr);
4bf1968d 2026
a5f5cb41 2027 err = netlink_open(nlh_ptr, NETLINK_ROUTE);
3cfc0f3a
MN
2028 if (err)
2029 return err;
0ad19a3f 2030
0ad19a3f 2031 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
2032 if (!nlmsg)
a5f5cb41 2033 return ret_errno(ENOMEM);
0ad19a3f 2034
06f976ca 2035 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
0ad19a3f 2036 if (!answer)
a5f5cb41 2037 return ret_errno(ENOMEM);
0ad19a3f 2038
a5f5cb41 2039 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
06f976ca
SZ
2040 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWADDR;
2041
2042 ifa = nlmsg_reserve(nlmsg, sizeof(struct ifaddrmsg));
acf47e1b 2043 if (!ifa)
a5f5cb41
CB
2044 return ret_errno(ENOMEM);
2045
06f976ca
SZ
2046 ifa->ifa_prefixlen = prefix;
2047 ifa->ifa_index = ifindex;
2048 ifa->ifa_family = family;
2049 ifa->ifa_scope = 0;
acf47e1b 2050
4bf1968d 2051 if (nla_put_buffer(nlmsg, IFA_LOCAL, addr, addrlen))
a5f5cb41 2052 return ret_errno(EINVAL);
0ad19a3f 2053
4bf1968d 2054 if (nla_put_buffer(nlmsg, IFA_ADDRESS, addr, addrlen))
a5f5cb41 2055 return ret_errno(EINVAL);
0ad19a3f 2056
d8948a52 2057 if (nla_put_buffer(nlmsg, IFA_BROADCAST, bcast, addrlen))
a5f5cb41 2058 return ret_errno(EINVAL);
1f1b18e7 2059
ebc73a67 2060 /* TODO: multicast, anycast with ipv6 */
79881dc6
DL
2061 if (family == AF_INET6 &&
2062 (memcmp(bcast, &in6addr_any, sizeof(in6addr_any)) ||
2063 memcmp(acast, &in6addr_any, sizeof(in6addr_any))))
a5f5cb41 2064 return ret_errno(EPROTONOSUPPORT);
0ad19a3f 2065
a5f5cb41 2066 return netlink_transaction(nlh_ptr, nlmsg, answer);
0ad19a3f 2067}
2068
1f1b18e7 2069int lxc_ipv6_addr_add(int ifindex, struct in6_addr *addr,
ebc73a67
CB
2070 struct in6_addr *mcast, struct in6_addr *acast,
2071 int prefix)
1f1b18e7
DL
2072{
2073 return ip_addr_add(AF_INET6, ifindex, addr, mcast, acast, prefix);
2074}
2075
ebc73a67
CB
2076int lxc_ipv4_addr_add(int ifindex, struct in_addr *addr, struct in_addr *bcast,
2077 int prefix)
1f1b18e7
DL
2078{
2079 return ip_addr_add(AF_INET, ifindex, addr, bcast, NULL, prefix);
2080}
2081
ebc73a67
CB
2082/* Find an IFA_LOCAL (or IFA_ADDRESS if not IFA_LOCAL is present) address from
2083 * the given RTM_NEWADDR message. Allocates memory for the address and stores
2084 * that pointer in *res (so res should be an in_addr** or in6_addr**).
19a26f82 2085 */
6ce39620
CB
2086#pragma GCC diagnostic push
2087#pragma GCC diagnostic ignored "-Wcast-align"
2088
ebc73a67
CB
2089static int ifa_get_local_ip(int family, struct nlmsghdr *msg, void **res)
2090{
2091 int addrlen;
06f976ca
SZ
2092 struct ifaddrmsg *ifa = NLMSG_DATA(msg);
2093 struct rtattr *rta = IFA_RTA(ifa);
2094 int attr_len = NLMSG_PAYLOAD(msg, sizeof(struct ifaddrmsg));
19a26f82 2095
06f976ca 2096 if (ifa->ifa_family != family)
19a26f82
MK
2097 return 0;
2098
ebc73a67
CB
2099 addrlen = family == AF_INET ? sizeof(struct in_addr)
2100 : sizeof(struct in6_addr);
19a26f82
MK
2101
2102 /* Loop over the rtattr's in this message */
ebc73a67 2103 while (RTA_OK(rta, attr_len)) {
19a26f82 2104 /* Found a local address for the requested interface,
ebc73a67
CB
2105 * return it.
2106 */
2107 if (rta->rta_type == IFA_LOCAL ||
2108 rta->rta_type == IFA_ADDRESS) {
2109 /* Sanity check. The family check above should make sure
2110 * the address length is correct, but check here just in
2111 * case.
2112 */
19a26f82
MK
2113 if (RTA_PAYLOAD(rta) != addrlen)
2114 return -1;
2115
ebc73a67
CB
2116 /* We might have found an IFA_ADDRESS before, which we
2117 * now overwrite with an IFA_LOCAL.
2118 */
dd66e5ad 2119 if (!*res) {
19a26f82 2120 *res = malloc(addrlen);
dd66e5ad
DE
2121 if (!*res)
2122 return -1;
2123 }
19a26f82
MK
2124
2125 memcpy(*res, RTA_DATA(rta), addrlen);
19a26f82
MK
2126 if (rta->rta_type == IFA_LOCAL)
2127 break;
2128 }
2129 rta = RTA_NEXT(rta, attr_len);
2130 }
2131 return 0;
2132}
2133
6ce39620
CB
2134#pragma GCC diagnostic pop
2135
19a26f82
MK
2136static int ip_addr_get(int family, int ifindex, void **res)
2137{
a5f5cb41
CB
2138 call_cleaner(nlmsg_free) struct nlmsg *answer = NULL, *nlmsg = NULL;
2139 struct nl_handler nlh;
2140 call_cleaner(netlink_close) struct nl_handler *nlh_ptr = &nlh;
ebc73a67 2141 int answer_len, err;
06f976ca 2142 struct ifaddrmsg *ifa;
19a26f82 2143 struct nlmsghdr *msg;
ebc73a67 2144 int readmore = 0, recv_len = 0;
19a26f82 2145
a5f5cb41 2146 err = netlink_open(nlh_ptr, NETLINK_ROUTE);
19a26f82
MK
2147 if (err)
2148 return err;
2149
19a26f82
MK
2150 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
2151 if (!nlmsg)
a5f5cb41 2152 return ret_errno(ENOMEM);
19a26f82 2153
06f976ca 2154 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
19a26f82 2155 if (!answer)
a5f5cb41 2156 return ret_errno(ENOMEM);
19a26f82 2157
ebc73a67
CB
2158 /* Save the answer buffer length, since it will be overwritten on the
2159 * first receive (and we might need to receive more than once).
2160 */
06f976ca
SZ
2161 answer_len = answer->nlmsghdr->nlmsg_len;
2162
ebc73a67 2163 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
06f976ca 2164 nlmsg->nlmsghdr->nlmsg_type = RTM_GETADDR;
19a26f82 2165
06f976ca 2166 ifa = nlmsg_reserve(nlmsg, sizeof(struct ifaddrmsg));
25a9939b 2167 if (!ifa)
a5f5cb41
CB
2168 return ret_errno(ENOMEM);
2169
06f976ca 2170 ifa->ifa_family = family;
19a26f82 2171
ebc73a67
CB
2172 /* Send the request for addresses, which returns all addresses on all
2173 * interfaces.
2174 */
a5f5cb41 2175 err = netlink_send(nlh_ptr, nlmsg);
19a26f82 2176 if (err < 0)
a5f5cb41 2177 return ret_set_errno(err, errno);
19a26f82 2178
6ce39620
CB
2179#pragma GCC diagnostic push
2180#pragma GCC diagnostic ignored "-Wcast-align"
2181
19a26f82
MK
2182 do {
2183 /* Restore the answer buffer length, it might have been
ebc73a67
CB
2184 * overwritten by a previous receive.
2185 */
06f976ca 2186 answer->nlmsghdr->nlmsg_len = answer_len;
19a26f82 2187
ebc73a67 2188 /* Get the (next) batch of reply messages. */
a5f5cb41 2189 err = netlink_rcv(nlh_ptr, answer);
19a26f82 2190 if (err < 0)
a5f5cb41 2191 return ret_set_errno(err, errno);
19a26f82
MK
2192
2193 recv_len = err;
2194 err = 0;
2195
ebc73a67 2196 /* Satisfy the typing for the netlink macros. */
06f976ca 2197 msg = answer->nlmsghdr;
19a26f82
MK
2198
2199 while (NLMSG_OK(msg, recv_len)) {
ebc73a67 2200 /* Stop reading if we see an error message. */
19a26f82 2201 if (msg->nlmsg_type == NLMSG_ERROR) {
a5f5cb41
CB
2202 struct nlmsgerr *errmsg = (struct nlmsgerr *)NLMSG_DATA(msg);
2203 return ret_set_errno(errmsg->error, errno);
19a26f82
MK
2204 }
2205
ebc73a67 2206 /* Stop reading if we see a NLMSG_DONE message. */
19a26f82
MK
2207 if (msg->nlmsg_type == NLMSG_DONE) {
2208 readmore = 0;
2209 break;
2210 }
2211
a5f5cb41
CB
2212 if (msg->nlmsg_type != RTM_NEWADDR)
2213 return ret_errno(EINVAL);
19a26f82 2214
06f976ca
SZ
2215 ifa = (struct ifaddrmsg *)NLMSG_DATA(msg);
2216 if (ifa->ifa_index == ifindex) {
a5f5cb41
CB
2217 if (ifa_get_local_ip(family, msg, res) < 0)
2218 return ret_errno(EINVAL);
51e7a874 2219
ebc73a67 2220 /* Found a result, stop searching. */
19a26f82 2221 if (*res)
a5f5cb41 2222 return 0;
19a26f82
MK
2223 }
2224
ebc73a67
CB
2225 /* Keep reading more data from the socket if the last
2226 * message had the NLF_F_MULTI flag set.
2227 */
19a26f82
MK
2228 readmore = (msg->nlmsg_flags & NLM_F_MULTI);
2229
ebc73a67 2230 /* Look at the next message received in this buffer. */
19a26f82
MK
2231 msg = NLMSG_NEXT(msg, recv_len);
2232 }
2233 } while (readmore);
2234
6ce39620
CB
2235#pragma GCC diagnostic pop
2236
19a26f82 2237 /* If we end up here, we didn't find any result, so signal an
ebc73a67
CB
2238 * error.
2239 */
a5f5cb41 2240 return -1;
19a26f82
MK
2241}
2242
2243int lxc_ipv6_addr_get(int ifindex, struct in6_addr **res)
2244{
ebc73a67 2245 return ip_addr_get(AF_INET6, ifindex, (void **)res);
19a26f82
MK
2246}
2247
ebc73a67 2248int lxc_ipv4_addr_get(int ifindex, struct in_addr **res)
19a26f82 2249{
ebc73a67 2250 return ip_addr_get(AF_INET, ifindex, (void **)res);
19a26f82
MK
2251}
2252
f8fee0e2
MK
2253static int ip_gateway_add(int family, int ifindex, void *gw)
2254{
a5f5cb41 2255 call_cleaner(nlmsg_free) struct nlmsg *answer = NULL, *nlmsg = NULL;
f8fee0e2 2256 struct nl_handler nlh;
a5f5cb41
CB
2257 call_cleaner(netlink_close) struct nl_handler *nlh_ptr = &nlh;
2258 int addrlen, err;
06f976ca 2259 struct rtmsg *rt;
f8fee0e2 2260
ebc73a67
CB
2261 addrlen = family == AF_INET ? sizeof(struct in_addr)
2262 : sizeof(struct in6_addr);
f8fee0e2 2263
a5f5cb41 2264 err = netlink_open(nlh_ptr, NETLINK_ROUTE);
f8fee0e2
MK
2265 if (err)
2266 return err;
2267
f8fee0e2
MK
2268 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
2269 if (!nlmsg)
a5f5cb41 2270 return ret_errno(ENOMEM);
f8fee0e2 2271
06f976ca 2272 answer = nlmsg_alloc_reserve(NLMSG_GOOD_SIZE);
f8fee0e2 2273 if (!answer)
a5f5cb41 2274 return ret_errno(ENOMEM);
f8fee0e2 2275
a5f5cb41 2276 nlmsg->nlmsghdr->nlmsg_flags = NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
06f976ca
SZ
2277 nlmsg->nlmsghdr->nlmsg_type = RTM_NEWROUTE;
2278
2279 rt = nlmsg_reserve(nlmsg, sizeof(struct rtmsg));
25a9939b 2280 if (!rt)
a5f5cb41
CB
2281 return ret_errno(ENOMEM);
2282
06f976ca
SZ
2283 rt->rtm_family = family;
2284 rt->rtm_table = RT_TABLE_MAIN;
2285 rt->rtm_scope = RT_SCOPE_UNIVERSE;
2286 rt->rtm_protocol = RTPROT_BOOT;
2287 rt->rtm_type = RTN_UNICAST;
f8fee0e2 2288 /* "default" destination */
06f976ca 2289 rt->rtm_dst_len = 0;
f8fee0e2 2290
a2f9a670 2291 /* If gateway address not supplied, then a device route will be created instead */
a5f5cb41
CB
2292 if (gw && nla_put_buffer(nlmsg, RTA_GATEWAY, gw, addrlen))
2293 return ret_errno(ENOMEM);
f8fee0e2
MK
2294
2295 /* Adding the interface index enables the use of link-local
ebc73a67
CB
2296 * addresses for the gateway.
2297 */
f8fee0e2 2298 if (nla_put_u32(nlmsg, RTA_OIF, ifindex))
a5f5cb41 2299 return ret_errno(EINVAL);
f8fee0e2 2300
a5f5cb41 2301 return netlink_transaction(nlh_ptr, nlmsg, answer);
f8fee0e2
MK
2302}
2303
2304int lxc_ipv4_gateway_add(int ifindex, struct in_addr *gw)
2305{
2306 return ip_gateway_add(AF_INET, ifindex, gw);
2307}
2308
2309int lxc_ipv6_gateway_add(int ifindex, struct in6_addr *gw)
2310{
2311 return ip_gateway_add(AF_INET6, ifindex, gw);
2312}
581c75e7 2313bool is_ovs_bridge(const char *bridge)
0d204771 2314{
ebc73a67 2315 int ret;
0d204771 2316 struct stat sb;
ebc73a67 2317 char brdirname[22 + IFNAMSIZ + 1] = {0};
0d204771 2318
ebc73a67
CB
2319 ret = snprintf(brdirname, 22 + IFNAMSIZ + 1, "/sys/class/net/%s/bridge",
2320 bridge);
2321 if (ret < 0 || (size_t)ret >= 22 + IFNAMSIZ + 1)
2322 return false;
2323
2324 ret = stat(brdirname, &sb);
2325 if (ret < 0 && errno == ENOENT)
0d204771 2326 return true;
ebc73a67 2327
0d204771
SH
2328 return false;
2329}
2330
581c75e7
CB
2331struct ovs_veth_args {
2332 const char *bridge;
2333 const char *nic;
2334};
2335
cb0dc11b
CB
2336/* Called from a background thread - when nic goes away, remove it from the
2337 * bridge.
c43cbc04 2338 */
581c75e7 2339static int lxc_ovs_delete_port_exec(void *data)
c43cbc04 2340{
581c75e7 2341 struct ovs_veth_args *args = data;
cb0dc11b 2342
9c66dc4f 2343 execlp("ovs-vsctl", "ovs-vsctl", "del-port", args->bridge, args->nic, (char *)NULL);
581c75e7 2344 return -1;
c43cbc04
SH
2345}
2346
581c75e7 2347int lxc_ovs_delete_port(const char *bridge, const char *nic)
0d204771 2348{
c43cbc04 2349 int ret;
419590da 2350 char cmd_output[PATH_MAX];
581c75e7 2351 struct ovs_veth_args args;
6ad22d06 2352
581c75e7
CB
2353 args.bridge = bridge;
2354 args.nic = nic;
2355 ret = run_command(cmd_output, sizeof(cmd_output),
2356 lxc_ovs_delete_port_exec, (void *)&args);
9c66dc4f
CB
2357 if (ret < 0)
2358 return log_error(-1, "Failed to delete \"%s\" from openvswitch bridge \"%s\": %s", nic, bridge, cmd_output);
0d204771 2359
581c75e7
CB
2360 return 0;
2361}
ebc73a67 2362
581c75e7
CB
2363static int lxc_ovs_attach_bridge_exec(void *data)
2364{
2365 struct ovs_veth_args *args = data;
ebc73a67 2366
9c66dc4f 2367 execlp("ovs-vsctl", "ovs-vsctl", "add-port", args->bridge, args->nic, (char *)NULL);
581c75e7
CB
2368 return -1;
2369}
ebc73a67 2370
581c75e7
CB
2371static int lxc_ovs_attach_bridge(const char *bridge, const char *nic)
2372{
2373 int ret;
419590da 2374 char cmd_output[PATH_MAX];
581c75e7 2375 struct ovs_veth_args args;
ebc73a67 2376
581c75e7
CB
2377 args.bridge = bridge;
2378 args.nic = nic;
2379 ret = run_command(cmd_output, sizeof(cmd_output),
2380 lxc_ovs_attach_bridge_exec, (void *)&args);
9c66dc4f
CB
2381 if (ret < 0)
2382 return log_error(-1, "Failed to attach \"%s\" to openvswitch bridge \"%s\": %s", nic, bridge, cmd_output);
0d204771 2383
581c75e7 2384 return 0;
0d204771 2385}
0d204771 2386
581c75e7 2387int lxc_bridge_attach(const char *bridge, const char *ifname)
0ad19a3f 2388{
ebc73a67 2389 int err, fd, index;
9de31d5a 2390 size_t retlen;
0ad19a3f 2391 struct ifreq ifr;
2392
dae3fdf6 2393 if (strlen(ifname) >= IFNAMSIZ)
3cfc0f3a 2394 return -EINVAL;
0ad19a3f 2395
2396 index = if_nametoindex(ifname);
2397 if (!index)
3cfc0f3a 2398 return -EINVAL;
0ad19a3f 2399
0d204771 2400 if (is_ovs_bridge(bridge))
581c75e7 2401 return lxc_ovs_attach_bridge(bridge, ifname);
0d204771 2402
ad9429e5 2403 fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
0ad19a3f 2404 if (fd < 0)
3cfc0f3a 2405 return -errno;
0ad19a3f 2406
9de31d5a 2407 retlen = strlcpy(ifr.ifr_name, bridge, IFNAMSIZ);
42cc4083
CB
2408 if (retlen >= IFNAMSIZ) {
2409 close(fd);
9de31d5a 2410 return -E2BIG;
42cc4083 2411 }
9de31d5a 2412
ebc73a67 2413 ifr.ifr_name[IFNAMSIZ - 1] = '\0';
0ad19a3f 2414 ifr.ifr_ifindex = index;
7d163508 2415 err = ioctl(fd, SIOCBRADDIF, &ifr);
0ad19a3f 2416 close(fd);
3cfc0f3a
MN
2417 if (err)
2418 err = -errno;
0ad19a3f 2419
2420 return err;
2421}
72d0e1cb 2422
ebc73a67 2423static const char *const lxc_network_types[LXC_NET_MAXCONFTYPE + 1] = {
b343592b 2424 [LXC_NET_EMPTY] = "empty",
72d0e1cb
SG
2425 [LXC_NET_VETH] = "veth",
2426 [LXC_NET_MACVLAN] = "macvlan",
c9f52382 2427 [LXC_NET_IPVLAN] = "ipvlan",
72d0e1cb 2428 [LXC_NET_PHYS] = "phys",
b343592b
BP
2429 [LXC_NET_VLAN] = "vlan",
2430 [LXC_NET_NONE] = "none",
72d0e1cb
SG
2431};
2432
2433const char *lxc_net_type_to_str(int type)
2434{
2435 if (type < 0 || type > LXC_NET_MAXCONFTYPE)
2436 return NULL;
ebc73a67 2437
72d0e1cb
SG
2438 return lxc_network_types[type];
2439}
8befa924 2440
3646ffd9 2441static const char padchar[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
a0265685 2442
3646ffd9 2443char *lxc_ifname_alnum_case_sensitive(char *template)
a0265685 2444{
2d7bf744 2445 int ret;
b1e44ed1 2446 struct netns_ifaddrs *ifa, *ifaddr;
966e9f1f
CB
2447 char name[IFNAMSIZ];
2448 bool exists = false;
2449 size_t i = 0;
280cc35f 2450#ifdef HAVE_RAND_R
2451 unsigned int seed;
2452
2453 seed = randseed(false);
2454#else
2455
2456 (void)randseed(true);
2457#endif
a0265685 2458
535e8859
CB
2459 if (strlen(template) >= IFNAMSIZ)
2460 return NULL;
2461
ebc73a67 2462 /* Get all the network interfaces. */
b1e44ed1 2463 ret = netns_getifaddrs(&ifaddr, -1, &(bool){false});
9c66dc4f
CB
2464 if (ret < 0)
2465 return log_error_errno(NULL, errno, "Failed to get network interfaces");
a0265685 2466
ebc73a67 2467 /* Generate random names until we find one that doesn't exist. */
51a8a74c 2468 for (;;) {
966e9f1f 2469 name[0] = '\0';
94b1cade 2470 (void)strlcpy(name, template, IFNAMSIZ);
a0265685 2471
966e9f1f 2472 exists = false;
280cc35f 2473
a0265685
SG
2474 for (i = 0; i < strlen(name); i++) {
2475 if (name[i] == 'X') {
2476#ifdef HAVE_RAND_R
8523344a 2477 name[i] = padchar[rand_r(&seed) % strlen(padchar)];
a0265685 2478#else
8523344a 2479 name[i] = padchar[rand() % strlen(padchar)];
a0265685
SG
2480#endif
2481 }
2482 }
2483
2484 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
966e9f1f
CB
2485 if (!strcmp(ifa->ifa_name, name)) {
2486 exists = true;
a0265685
SG
2487 break;
2488 }
2489 }
2490
966e9f1f 2491 if (!exists)
a0265685 2492 break;
a0265685
SG
2493 }
2494
b1e44ed1 2495 netns_freeifaddrs(ifaddr);
94b1cade
DJ
2496 (void)strlcpy(template, name, strlen(template) + 1);
2497
2498 return template;
a0265685
SG
2499}
2500
8befa924
SH
2501int setup_private_host_hw_addr(char *veth1)
2502{
ebc73a67 2503 int err, sockfd;
8befa924 2504 struct ifreq ifr;
8befa924 2505
ad9429e5 2506 sockfd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
8befa924
SH
2507 if (sockfd < 0)
2508 return -errno;
2509
ebc73a67 2510 err = snprintf((char *)ifr.ifr_name, IFNAMSIZ, "%s", veth1);
87c6e5db
DJ
2511 if (err < 0 || (size_t)err >= IFNAMSIZ) {
2512 close(sockfd);
ebc73a67 2513 return -E2BIG;
87c6e5db 2514 }
ebc73a67 2515
8befa924
SH
2516 err = ioctl(sockfd, SIOCGIFHWADDR, &ifr);
2517 if (err < 0) {
8befa924 2518 close(sockfd);
8befa924
SH
2519 return -errno;
2520 }
2521
2522 ifr.ifr_hwaddr.sa_data[0] = 0xfe;
2523 err = ioctl(sockfd, SIOCSIFHWADDR, &ifr);
8befa924 2524 close(sockfd);
8befa924
SH
2525 if (err < 0)
2526 return -errno;
2527
2528 return 0;
2529}
811ef482
CB
2530
2531int lxc_find_gateway_addresses(struct lxc_handler *handler)
2532{
2533 struct lxc_list *network = &handler->conf->network;
2534 struct lxc_list *iterator;
2535 struct lxc_netdev *netdev;
2536 int link_index;
2537
2538 lxc_list_for_each(iterator, network) {
2539 netdev = iterator->elem;
2540
2541 if (!netdev->ipv4_gateway_auto && !netdev->ipv6_gateway_auto)
2542 continue;
2543
9c66dc4f
CB
2544 if (netdev->type != LXC_NET_VETH && netdev->type != LXC_NET_MACVLAN)
2545 return log_error_errno(-1, EINVAL, "Automatic gateway detection is only supported for veth and macvlan");
811ef482 2546
f2711167 2547 if (is_empty_string(netdev->link)) {
9c66dc4f 2548 return log_error_errno(-1, errno, "Automatic gateway detection needs a link interface");
811ef482
CB
2549 }
2550
2551 link_index = if_nametoindex(netdev->link);
2552 if (!link_index)
2553 return -EINVAL;
2554
2555 if (netdev->ipv4_gateway_auto) {
9c66dc4f
CB
2556 if (lxc_ipv4_addr_get(link_index, &netdev->ipv4_gateway))
2557 return log_error_errno(-1, errno, "Failed to automatically find ipv4 gateway address from link interface \"%s\"", netdev->link);
811ef482
CB
2558 }
2559
2560 if (netdev->ipv6_gateway_auto) {
9c66dc4f
CB
2561 if (lxc_ipv6_addr_get(link_index, &netdev->ipv6_gateway))
2562 return log_error_errno(-1, errno, "Failed to automatically find ipv6 gateway address from link interface \"%s\"", netdev->link);
811ef482
CB
2563 }
2564 }
2565
2566 return 0;
2567}
2568
2569#define LXC_USERNIC_PATH LIBEXECDIR "/lxc/lxc-user-nic"
f0ecc19d 2570static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcname,
4d781681 2571 struct lxc_netdev *netdev, pid_t pid, unsigned int hooks_version)
811ef482
CB
2572{
2573 int ret;
2574 pid_t child;
2575 int bytes, pipefd[2];
2576 char *token, *saveptr = NULL;
095ead80 2577 char netdev_link[IFNAMSIZ];
419590da 2578 char buffer[PATH_MAX] = {0};
94b1cade 2579 size_t retlen;
811ef482 2580
9c66dc4f
CB
2581 if (netdev->type != LXC_NET_VETH)
2582 return log_error_errno(-1, errno, "Network type %d not support for unprivileged use", netdev->type);
811ef482
CB
2583
2584 ret = pipe(pipefd);
9c66dc4f
CB
2585 if (ret < 0)
2586 return log_error_errno(-1, errno, "Failed to create pipe");
811ef482
CB
2587
2588 child = fork();
2589 if (child < 0) {
811ef482
CB
2590 close(pipefd[0]);
2591 close(pipefd[1]);
9c66dc4f 2592 return log_error_errno(-1, errno, "Failed to create new process");
811ef482
CB
2593 }
2594
2595 if (child == 0) {
8335fd40 2596 char pidstr[INTTYPE_TO_STRLEN(pid_t)];
811ef482
CB
2597
2598 close(pipefd[0]);
2599
2600 ret = dup2(pipefd[1], STDOUT_FILENO);
2601 if (ret >= 0)
2602 ret = dup2(pipefd[1], STDERR_FILENO);
2603 close(pipefd[1]);
2604 if (ret < 0) {
2605 SYSERROR("Failed to duplicate std{err,out} file descriptor");
78070056 2606 _exit(EXIT_FAILURE);
811ef482
CB
2607 }
2608
f2711167 2609 if (!is_empty_string(netdev->link))
9de31d5a 2610 retlen = strlcpy(netdev_link, netdev->link, IFNAMSIZ);
811ef482 2611 else
9de31d5a
CB
2612 retlen = strlcpy(netdev_link, "none", IFNAMSIZ);
2613 if (retlen >= IFNAMSIZ) {
2614 SYSERROR("Invalid network device name");
2615 _exit(EXIT_FAILURE);
2616 }
811ef482 2617
8335fd40
CB
2618 ret = snprintf(pidstr, sizeof(pidstr), "%d", pid);
2619 if (ret < 0 || ret >= sizeof(pidstr))
78070056 2620 _exit(EXIT_FAILURE);
8335fd40 2621 pidstr[sizeof(pidstr) - 1] = '\0';
811ef482
CB
2622
2623 INFO("Execing lxc-user-nic create %s %s %s veth %s %s", lxcpath,
2624 lxcname, pidstr, netdev_link,
3473ca76
CB
2625 !is_empty_string(netdev->name) ? netdev->name : "(null)");
2626 if (!is_empty_string(netdev->name))
811ef482
CB
2627 execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, "create",
2628 lxcpath, lxcname, pidstr, "veth", netdev_link,
2629 netdev->name, (char *)NULL);
2630 else
2631 execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, "create",
2632 lxcpath, lxcname, pidstr, "veth", netdev_link,
2633 (char *)NULL);
2634 SYSERROR("Failed to execute lxc-user-nic");
78070056 2635 _exit(EXIT_FAILURE);
811ef482
CB
2636 }
2637
2638 /* close the write-end of the pipe */
2639 close(pipefd[1]);
2640
9c66dc4f 2641 bytes = lxc_read_nointr(pipefd[0], &buffer, sizeof(buffer));
811ef482 2642 if (bytes < 0) {
74c6e2b0 2643 SYSERROR("Failed to read from pipe file descriptor");
811ef482 2644 close(pipefd[0]);
6b9f82a9
CB
2645 } else {
2646 buffer[bytes - 1] = '\0';
811ef482 2647 }
811ef482
CB
2648
2649 ret = wait_for_pid(child);
2650 close(pipefd[0]);
9c66dc4f
CB
2651 if (ret != 0 || bytes < 0)
2652 return log_error(-1, "lxc-user-nic failed to configure requested network: %s", buffer[0] != '\0' ? buffer : "(null)");
811ef482
CB
2653 TRACE("Received output \"%s\" from lxc-user-nic", buffer);
2654
2655 /* netdev->name */
2656 token = strtok_r(buffer, ":", &saveptr);
9c66dc4f
CB
2657 if (!token)
2658 return log_error(-1, "Failed to parse lxc-user-nic output");
811ef482 2659
e389f2af
CB
2660 /*
2661 * lxc-user-nic will take care of proper network device naming. So
2662 * netdev->name and netdev->created_name need to be identical to not
2663 * trigger another rename later on.
2664 */
2665 retlen = strlcpy(netdev->name, token, IFNAMSIZ);
2666 if (retlen < IFNAMSIZ)
2667 retlen = strlcpy(netdev->created_name, token, IFNAMSIZ);
9c66dc4f
CB
2668 if (retlen >= IFNAMSIZ)
2669 return log_error_errno(-1, E2BIG, "Container side veth device name returned by lxc-user-nic is too long");
811ef482 2670
74c6e2b0 2671 /* netdev->ifindex */
811ef482 2672 token = strtok_r(NULL, ":", &saveptr);
9c66dc4f
CB
2673 if (!token)
2674 return log_error(-1, "Failed to parse lxc-user-nic output");
811ef482 2675
74c6e2b0 2676 ret = lxc_safe_int(token, &netdev->ifindex);
9c66dc4f
CB
2677 if (ret < 0)
2678 return log_error_errno(-1, -ret, "Failed to convert string \"%s\" to integer", token);
811ef482 2679
74c6e2b0 2680 /* netdev->priv.veth_attr.veth1 */
811ef482 2681 token = strtok_r(NULL, ":", &saveptr);
9c66dc4f
CB
2682 if (!token)
2683 return log_error(-1, "Failed to parse lxc-user-nic output");
811ef482 2684
94b1cade 2685 retlen = strlcpy(netdev->priv.veth_attr.veth1, token, IFNAMSIZ);
9c66dc4f
CB
2686 if (retlen >= IFNAMSIZ)
2687 return log_error_errno(-1, E2BIG, "Host side veth device name returned by lxc-user-nic is too long");
74c6e2b0
CB
2688
2689 /* netdev->priv.veth_attr.ifindex */
2690 token = strtok_r(NULL, ":", &saveptr);
9c66dc4f
CB
2691 if (!token)
2692 return log_error(-1, "Failed to parse lxc-user-nic output");
74c6e2b0
CB
2693
2694 ret = lxc_safe_int(token, &netdev->priv.veth_attr.ifindex);
9c66dc4f
CB
2695 if (ret < 0)
2696 return log_error_errno(-1, -ret, "Failed to convert string \"%s\" to integer", token);
811ef482 2697
4d781681 2698 if (netdev->upscript) {
2699 char *argv[] = {
2700 "veth",
2701 netdev->link,
2702 netdev->priv.veth_attr.veth1,
2703 NULL,
2704 };
2705
e389f2af
CB
2706 ret = run_script_argv(lxcname, hooks_version, "net",
2707 netdev->upscript, "up", argv);
4d781681 2708 if (ret < 0)
2709 return -1;
2710 }
2711
811ef482
CB
2712 return 0;
2713}
2714
f0ecc19d 2715static int lxc_delete_network_unpriv_exec(const char *lxcpath, const char *lxcname,
1bd8d726
CB
2716 struct lxc_netdev *netdev,
2717 const char *netns_path)
811ef482
CB
2718{
2719 int bytes, ret;
2720 pid_t child;
2721 int pipefd[2];
419590da 2722 char buffer[PATH_MAX] = {0};
811ef482 2723
9c66dc4f
CB
2724 if (netdev->type != LXC_NET_VETH)
2725 return log_error_errno(-1, EINVAL, "Network type %d not support for unprivileged use", netdev->type);
811ef482
CB
2726
2727 ret = pipe(pipefd);
9c66dc4f
CB
2728 if (ret < 0)
2729 return log_error_errno(-1, errno, "Failed to create pipe");
811ef482
CB
2730
2731 child = fork();
2732 if (child < 0) {
811ef482
CB
2733 close(pipefd[0]);
2734 close(pipefd[1]);
9c66dc4f 2735 return log_error_errno(-1, errno, "Failed to create new process");
811ef482
CB
2736 }
2737
2738 if (child == 0) {
8843fde4 2739 char *hostveth;
811ef482
CB
2740
2741 close(pipefd[0]);
2742
2743 ret = dup2(pipefd[1], STDOUT_FILENO);
2744 if (ret >= 0)
2745 ret = dup2(pipefd[1], STDERR_FILENO);
2746 close(pipefd[1]);
2747 if (ret < 0) {
2748 SYSERROR("Failed to duplicate std{err,out} file descriptor");
a30b9023 2749 _exit(EXIT_FAILURE);
811ef482
CB
2750 }
2751
f2711167 2752 if (!is_empty_string(netdev->priv.veth_attr.pair))
8843fde4
CB
2753 hostveth = netdev->priv.veth_attr.pair;
2754 else
2755 hostveth = netdev->priv.veth_attr.veth1;
f2711167 2756 if (is_empty_string(hostveth)) {
74c6e2b0 2757 SYSERROR("Host side veth device name is missing");
a30b9023 2758 _exit(EXIT_FAILURE);
74c6e2b0
CB
2759 }
2760
f2711167
CB
2761 if (is_empty_string(netdev->link)) {
2762 SYSERROR("Network link for network device \"%s\" is missing", netdev->priv.veth_attr.veth1);
a30b9023 2763 _exit(EXIT_FAILURE);
74c6e2b0 2764 }
811ef482 2765
811ef482 2766 INFO("Execing lxc-user-nic delete %s %s %s veth %s %s", lxcpath,
8843fde4 2767 lxcname, netns_path, netdev->link, hostveth);
811ef482 2768 execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, "delete", lxcpath,
8843fde4
CB
2769 lxcname, netns_path, "veth", netdev->link, hostveth,
2770 (char *)NULL);
811ef482 2771 SYSERROR("Failed to exec lxc-user-nic.");
a30b9023 2772 _exit(EXIT_FAILURE);
811ef482
CB
2773 }
2774
2775 close(pipefd[1]);
2776
9c66dc4f 2777 bytes = lxc_read_nointr(pipefd[0], &buffer, sizeof(buffer));
811ef482
CB
2778 if (bytes < 0) {
2779 SYSERROR("Failed to read from pipe file descriptor.");
2780 close(pipefd[0]);
6b9f82a9
CB
2781 } else {
2782 buffer[bytes - 1] = '\0';
811ef482 2783 }
811ef482 2784
6b9f82a9 2785 ret = wait_for_pid(child);
9c66dc4f
CB
2786 close_prot_errno_disarm(pipefd[0]);
2787 if (ret != 0 || bytes < 0)
2788 return log_error_errno(-1, errno, "lxc-user-nic failed to delete requested network: %s",
2789 !is_empty_string(buffer) ? buffer : "(null)");
811ef482 2790
811ef482
CB
2791 return 0;
2792}
2793
1bd8d726
CB
2794bool lxc_delete_network_unpriv(struct lxc_handler *handler)
2795{
2796 int ret;
2797 struct lxc_list *iterator;
2798 struct lxc_list *network = &handler->conf->network;
2799 /* strlen("/proc/") = 6
2800 * +
8335fd40 2801 * INTTYPE_TO_STRLEN(pid_t)
1bd8d726
CB
2802 * +
2803 * strlen("/fd/") = 4
2804 * +
8335fd40 2805 * INTTYPE_TO_STRLEN(int)
1bd8d726
CB
2806 * +
2807 * \0
2808 */
8335fd40 2809 char netns_path[6 + INTTYPE_TO_STRLEN(pid_t) + 4 + INTTYPE_TO_STRLEN(int) + 1];
1bd8d726
CB
2810
2811 *netns_path = '\0';
2812
9c66dc4f
CB
2813 if (handler->nsfd[LXC_NS_NET] < 0)
2814 return log_debug(false, "Cannot not guarantee safe deletion of network devices. Manual cleanup maybe needed");
1bd8d726
CB
2815
2816 ret = snprintf(netns_path, sizeof(netns_path), "/proc/%d/fd/%d",
0059379f 2817 lxc_raw_getpid(), handler->nsfd[LXC_NS_NET]);
1bd8d726
CB
2818 if (ret < 0 || ret >= sizeof(netns_path))
2819 return false;
2820
2821 lxc_list_for_each(iterator, network) {
2822 char *hostveth = NULL;
2823 struct lxc_netdev *netdev = iterator->elem;
2824
2825 /* We can only delete devices whose ifindex we have. If we don't
2826 * have the index it means that we didn't create it.
2827 */
2828 if (!netdev->ifindex)
2829 continue;
2830
2831 if (netdev->type == LXC_NET_PHYS) {
2832 ret = lxc_netdev_rename_by_index(netdev->ifindex,
2833 netdev->link);
2834 if (ret < 0)
9c66dc4f 2835 WARN("Failed to rename interface with index %d to its initial name \"%s\"",
1bd8d726
CB
2836 netdev->ifindex, netdev->link);
2837 else
9c66dc4f 2838 TRACE("Renamed interface with index %d to its initial name \"%s\"",
1bd8d726 2839 netdev->ifindex, netdev->link);
b3259dc6
TP
2840
2841 ret = netdev_deconf[netdev->type](handler, netdev);
40a22043
CB
2842 if (ret < 0)
2843 WARN("Failed to deconfigure interface with index %d and initial name \"%s\"",
2844 netdev->ifindex, netdev->link);
66a7c406 2845 goto clear_ifindices;
1bd8d726
CB
2846 }
2847
2848 ret = netdev_deconf[netdev->type](handler, netdev);
2849 if (ret < 0)
2850 WARN("Failed to deconfigure network device");
2851
2852 if (netdev->type != LXC_NET_VETH)
66a7c406 2853 goto clear_ifindices;
1bd8d726 2854
f2711167 2855 if (is_empty_string(netdev->link) || !is_ovs_bridge(netdev->link))
66a7c406 2856 goto clear_ifindices;
1bd8d726 2857
f2711167 2858 if (!is_empty_string(netdev->priv.veth_attr.pair))
8843fde4
CB
2859 hostveth = netdev->priv.veth_attr.pair;
2860 else
2861 hostveth = netdev->priv.veth_attr.veth1;
f2711167 2862 if (is_empty_string(hostveth))
66a7c406 2863 goto clear_ifindices;
8843fde4 2864
1bd8d726
CB
2865 ret = lxc_delete_network_unpriv_exec(handler->lxcpath,
2866 handler->name, netdev,
2867 netns_path);
2868 if (ret < 0) {
9c66dc4f 2869 WARN("Failed to remove port \"%s\" from openvswitch bridge \"%s\"", hostveth, netdev->link);
66a7c406 2870 goto clear_ifindices;
1bd8d726 2871 }
9c66dc4f 2872 INFO("Removed interface \"%s\" from \"%s\"", hostveth, netdev->link);
66a7c406
CB
2873
2874clear_ifindices:
0858c829
CB
2875 /*
2876 * We need to clear any ifindices we recorded so liblxc won't
2877 * have cached stale data which would cause it to fail on
2878 * reboot where we don't re-read the on-disk config file.
66a7c406
CB
2879 */
2880 netdev->ifindex = 0;
2881 if (netdev->type == LXC_NET_PHYS) {
2882 netdev->priv.phys_attr.ifindex = 0;
2883 } else if (netdev->type == LXC_NET_VETH) {
2884 netdev->priv.veth_attr.veth1[0] = '\0';
2885 netdev->priv.veth_attr.ifindex = 0;
2886 }
1bd8d726
CB
2887 }
2888
bb84beda 2889 return true;
1bd8d726
CB
2890}
2891
6509154d 2892static int lxc_setup_l2proxy(struct lxc_netdev *netdev) {
2893 struct lxc_list *cur, *next;
2894 struct lxc_inetdev *inet4dev;
2895 struct lxc_inet6dev *inet6dev;
2896 char bufinet4[INET_ADDRSTRLEN], bufinet6[INET6_ADDRSTRLEN];
b670016a 2897 int err = 0;
5fe147e9
TP
2898 unsigned int lo_ifindex = 0, link_ifindex = 0;
2899
2900 link_ifindex = if_nametoindex(netdev->link);
9c66dc4f
CB
2901 if (link_ifindex == 0)
2902 return log_error_errno(-1, errno, "Failed to retrieve ifindex for \"%s\" l2proxy setup", netdev->link);
5fe147e9 2903
6509154d 2904
2905 /* If IPv4 addresses are specified, then check that sysctl is configured correctly. */
2906 if (!lxc_list_empty(&netdev->ipv4)) {
2907 /* Check for net.ipv4.conf.[link].forwarding=1 */
9c66dc4f
CB
2908 if (lxc_is_ip_forwarding_enabled(netdev->link, AF_INET) < 0)
2909 return log_error_errno(-1, EINVAL, "Requires sysctl net.ipv4.conf.%s.forwarding=1", netdev->link);
6509154d 2910 }
2911
2912 /* If IPv6 addresses are specified, then check that sysctl is configured correctly. */
2913 if (!lxc_list_empty(&netdev->ipv6)) {
2914 /* Check for net.ipv6.conf.[link].proxy_ndp=1 */
9c66dc4f
CB
2915 if (lxc_is_ip_neigh_proxy_enabled(netdev->link, AF_INET6) < 0)
2916 return log_error_errno(-1, EINVAL, "Requires sysctl net.ipv6.conf.%s.proxy_ndp=1", netdev->link);
6509154d 2917
2918 /* Check for net.ipv6.conf.[link].forwarding=1 */
9c66dc4f
CB
2919 if (lxc_is_ip_forwarding_enabled(netdev->link, AF_INET6) < 0)
2920 return log_error_errno(-1, EINVAL, "Requires sysctl net.ipv6.conf.%s.forwarding=1", netdev->link);
6509154d 2921 }
2922
b670016a 2923 /* Perform IPVLAN specific checks. */
2924 if (netdev->type == LXC_NET_IPVLAN) {
2925 /* Check mode is l3s as other modes do not work with l2proxy. */
9c66dc4f
CB
2926 if (netdev->priv.ipvlan_attr.mode != IPVLAN_MODE_L3S)
2927 return log_error_errno(-1, EINVAL, "Requires ipvlan mode on dev \"%s\" be l3s when used with l2proxy", netdev->link);
b670016a 2928
2929 /* Retrieve local-loopback interface index for use with IPVLAN static routes. */
3ebffb98 2930 lo_ifindex = if_nametoindex(loop_device);
9c66dc4f
CB
2931 if (lo_ifindex == 0)
2932 return log_error_errno(-1, EINVAL, "Failed to retrieve ifindex for \"%s\" routing cleanup", loop_device);
b670016a 2933 }
2934
6509154d 2935 lxc_list_for_each_safe(cur, &netdev->ipv4, next) {
2936 inet4dev = cur->elem;
2937 if (!inet_ntop(AF_INET, &inet4dev->addr, bufinet4, sizeof(bufinet4)))
596a002c 2938 return ret_set_errno(-1, -errno);
6509154d 2939
5fe147e9 2940 if (lxc_ip_neigh_proxy(RTM_NEWNEIGH, AF_INET, link_ifindex, &inet4dev->addr) < 0)
596a002c 2941 return ret_set_errno(-1, EINVAL);
b670016a 2942
2943 /* IPVLAN requires a route to local-loopback to trigger l2proxy. */
2944 if (netdev->type == LXC_NET_IPVLAN) {
2945 err = lxc_ipv4_dest_add(lo_ifindex, &inet4dev->addr, 32);
9c66dc4f
CB
2946 if (err < 0)
2947 return log_error_errno(-1, -err, "Failed to add ipv4 dest \"%s\" for network device \"%s\"", bufinet4, loop_device);
b670016a 2948 }
6509154d 2949 }
2950
2951 lxc_list_for_each_safe(cur, &netdev->ipv6, next) {
2952 inet6dev = cur->elem;
2953 if (!inet_ntop(AF_INET6, &inet6dev->addr, bufinet6, sizeof(bufinet6)))
596a002c 2954 return ret_set_errno(-1, -errno);
6509154d 2955
5fe147e9 2956 if (lxc_ip_neigh_proxy(RTM_NEWNEIGH, AF_INET6, link_ifindex, &inet6dev->addr) < 0)
596a002c 2957 return ret_set_errno(-1, EINVAL);
b670016a 2958
2959 /* IPVLAN requires a route to local-loopback to trigger l2proxy. */
2960 if (netdev->type == LXC_NET_IPVLAN) {
2961 err = lxc_ipv6_dest_add(lo_ifindex, &inet6dev->addr, 128);
9c66dc4f
CB
2962 if (err < 0)
2963 return log_error_errno(-1, -err, "Failed to add ipv6 dest \"%s\" for network device \"%s\"", bufinet6, loop_device);
b670016a 2964 }
6509154d 2965 }
2966
2967 return 0;
2968}
2969
9c66dc4f
CB
2970static int lxc_delete_ipv4_l2proxy(struct in_addr *ip, char *link, unsigned int lo_ifindex)
2971{
b670016a 2972 char bufinet4[INET_ADDRSTRLEN];
9c66dc4f
CB
2973 bool had_error = false;
2974 unsigned int link_ifindex = 0;
b670016a 2975
9c66dc4f
CB
2976 if (!inet_ntop(AF_INET, ip, bufinet4, sizeof(bufinet4)))
2977 return log_error_errno(-1, EINVAL, "Failed to convert IP for l2proxy ipv4 removal on dev \"%s\"", link);
b670016a 2978
2979 /* If a local-loopback ifindex supplied remove the static route to the lo device. */
2980 if (lo_ifindex > 0) {
2981 if (lxc_ipv4_dest_del(lo_ifindex, ip, 32) < 0) {
9c66dc4f 2982 had_error = true;
b670016a 2983 ERROR("Failed to delete ipv4 dest \"%s\" for network ifindex \"%u\"", bufinet4, lo_ifindex);
2984 }
2985 }
2986
2987 /* If link is supplied remove the IP neigh proxy entry for this IP on the device. */
f2711167 2988 if (!is_empty_string(link)) {
5fe147e9 2989 link_ifindex = if_nametoindex(link);
9c66dc4f
CB
2990 if (link_ifindex == 0)
2991 return log_error_errno(-1, EINVAL, "Failed to retrieve ifindex for \"%s\" l2proxy cleanup", link);
5fe147e9
TP
2992
2993 if (lxc_ip_neigh_proxy(RTM_DELNEIGH, AF_INET, link_ifindex, ip) < 0)
9c66dc4f 2994 had_error = true;
b670016a 2995 }
2996
9c66dc4f 2997 if (had_error)
596a002c 2998 return ret_set_errno(-1, EINVAL);
b670016a 2999
3000 return 0;
3001}
3002
9c66dc4f
CB
3003static int lxc_delete_ipv6_l2proxy(struct in6_addr *ip, char *link, unsigned int lo_ifindex)
3004{
b670016a 3005 char bufinet6[INET6_ADDRSTRLEN];
9c66dc4f
CB
3006 bool had_error = false;
3007 unsigned int link_ifindex = 0;
b670016a 3008
9c66dc4f
CB
3009 if (!inet_ntop(AF_INET6, ip, bufinet6, sizeof(bufinet6)))
3010 return log_error_errno(-1, EINVAL, "Failed to convert IP for l2proxy ipv6 removal on dev \"%s\"", link);
b670016a 3011
3012 /* If a local-loopback ifindex supplied remove the static route to the lo device. */
3013 if (lo_ifindex > 0) {
3014 if (lxc_ipv6_dest_del(lo_ifindex, ip, 128) < 0) {
9c66dc4f 3015 had_error = true;
b670016a 3016 ERROR("Failed to delete ipv6 dest \"%s\" for network ifindex \"%u\"", bufinet6, lo_ifindex);
3017 }
3018 }
3019
3020 /* If link is supplied remove the IP neigh proxy entry for this IP on the device. */
f2711167 3021 if (!is_empty_string(link)) {
5fe147e9
TP
3022 link_ifindex = if_nametoindex(link);
3023 if (link_ifindex == 0) {
3024 ERROR("Failed to retrieve ifindex for \"%s\" l2proxy cleanup", link);
3025 return ret_set_errno(-1, EINVAL);
3026 }
3027
3028 if (lxc_ip_neigh_proxy(RTM_DELNEIGH, AF_INET6, link_ifindex, ip) < 0)
9c66dc4f 3029 had_error = true;
b670016a 3030 }
3031
9c66dc4f 3032 if (had_error)
596a002c 3033 return ret_set_errno(-1, EINVAL);
b670016a 3034
3035 return 0;
3036}
3037
6509154d 3038static int lxc_delete_l2proxy(struct lxc_netdev *netdev) {
b670016a 3039 unsigned int lo_ifindex = 0;
3040 unsigned int errCount = 0;
6509154d 3041 struct lxc_list *cur, *next;
3042 struct lxc_inetdev *inet4dev;
3043 struct lxc_inet6dev *inet6dev;
6509154d 3044
b670016a 3045 /* Perform IPVLAN specific checks. */
3046 if (netdev->type == LXC_NET_IPVLAN) {
3047 /* Retrieve local-loopback interface index for use with IPVLAN static routes. */
3ebffb98 3048 lo_ifindex = if_nametoindex(loop_device);
b670016a 3049 if (lo_ifindex == 0) {
3050 errCount++;
3ebffb98 3051 ERROR("Failed to retrieve ifindex for \"%s\" routing cleanup", loop_device);
6509154d 3052 }
b670016a 3053 }
6509154d 3054
b670016a 3055 lxc_list_for_each_safe(cur, &netdev->ipv4, next) {
3056 inet4dev = cur->elem;
3057 if (lxc_delete_ipv4_l2proxy(&inet4dev->addr, netdev->link, lo_ifindex) < 0)
3058 errCount++;
6509154d 3059 }
3060
3061 lxc_list_for_each_safe(cur, &netdev->ipv6, next) {
3062 inet6dev = cur->elem;
b670016a 3063 if (lxc_delete_ipv6_l2proxy(&inet6dev->addr, netdev->link, lo_ifindex) < 0)
3064 errCount++;
6509154d 3065 }
3066
b670016a 3067 if (errCount > 0)
596a002c 3068 return ret_set_errno(-1, EINVAL);
6509154d 3069
3070 return 0;
3071}
3072
e389f2af 3073static int lxc_create_network_priv(struct lxc_handler *handler)
811ef482 3074{
811ef482
CB
3075 struct lxc_list *iterator;
3076 struct lxc_list *network = &handler->conf->network;
3077
811ef482
CB
3078 lxc_list_for_each(iterator, network) {
3079 struct lxc_netdev *netdev = iterator->elem;
3080
9c66dc4f
CB
3081 if (netdev->type < 0 || netdev->type > LXC_NET_MAXCONFTYPE)
3082 return log_error_errno(-1, EINVAL, "Invalid network configuration type %d", netdev->type);
811ef482 3083
6509154d 3084 /* Setup l2proxy entries if enabled and used with a link property */
f2711167 3085 if (netdev->l2proxy && !is_empty_string(netdev->link)) {
9c66dc4f
CB
3086 if (lxc_setup_l2proxy(netdev))
3087 return log_error_errno(-1, errno, "Failed to setup l2proxy");
6509154d 3088 }
3089
9c66dc4f
CB
3090 if (netdev_conf[netdev->type](handler, netdev))
3091 return log_error_errno(-1, errno, "Failed to create network device");
811ef482
CB
3092 }
3093
3094 return 0;
3095}
3096
e389f2af 3097int lxc_network_move_created_netdev_priv(struct lxc_handler *handler)
811ef482 3098{
e389f2af
CB
3099 pid_t pid = handler->pid;
3100 struct lxc_list *network = &handler->conf->network;
811ef482
CB
3101 struct lxc_list *iterator;
3102
e0010464 3103 if (am_guest_unpriv())
74c6e2b0 3104 return 0;
811ef482
CB
3105
3106 lxc_list_for_each(iterator, network) {
3dd78294 3107 __do_free char *physname = NULL;
e389f2af 3108 int ret;
811ef482
CB
3109 struct lxc_netdev *netdev = iterator->elem;
3110
811ef482
CB
3111 if (!netdev->ifindex)
3112 continue;
3113
3dd78294
CB
3114 if (netdev->type == LXC_NET_PHYS)
3115 physname = is_wlan(netdev->link);
3116
3117 if (physname)
9f8cf6e1 3118 ret = lxc_netdev_move_wlan(physname, netdev->link, pid, NULL);
3dd78294 3119 else
9f8cf6e1 3120 ret = lxc_netdev_move_by_index(netdev->ifindex, pid, NULL);
9c66dc4f
CB
3121 if (ret)
3122 return log_error_errno(-1, -ret, "Failed to move network device \"%s\" with ifindex %d to network namespace %d",
3123 netdev->created_name,
3124 netdev->ifindex, pid);
811ef482 3125
24190194
CB
3126 DEBUG("Moved network device \"%s\" with ifindex %d to network namespace of %d",
3127 netdev->created_name, netdev->ifindex, pid);
811ef482
CB
3128 }
3129
3130 return 0;
3131}
3132
3c09b97c
CB
3133static int network_requires_advanced_setup(int type)
3134{
3135 if (type == LXC_NET_EMPTY)
3136 return false;
3137
3138 if (type == LXC_NET_NONE)
3139 return false;
3140
3141 return true;
3142}
3143
e389f2af 3144static int lxc_create_network_unpriv(struct lxc_handler *handler)
74c6e2b0 3145{
e389f2af
CB
3146 int hooks_version = handler->conf->hooks_version;
3147 const char *lxcname = handler->name;
3148 const char *lxcpath = handler->lxcpath;
3149 struct lxc_list *network = &handler->conf->network;
3150 pid_t pid = handler->pid;
74c6e2b0
CB
3151 struct lxc_list *iterator;
3152
74c6e2b0
CB
3153 lxc_list_for_each(iterator, network) {
3154 struct lxc_netdev *netdev = iterator->elem;
3155
3c09b97c 3156 if (!network_requires_advanced_setup(netdev->type))
74c6e2b0
CB
3157 continue;
3158
9c66dc4f
CB
3159 if (netdev->type != LXC_NET_VETH)
3160 return log_error_errno(-1, EINVAL, "Networks of type %s are not supported by unprivileged containers",
3161 lxc_net_type_to_str(netdev->type));
74c6e2b0
CB
3162
3163 if (netdev->mtu)
3164 INFO("mtu ignored due to insufficient privilege");
3165
e389f2af
CB
3166 if (lxc_create_network_unpriv_exec(lxcpath, lxcname, netdev,
3167 pid, hooks_version))
74c6e2b0
CB
3168 return -1;
3169 }
3170
3171 return 0;
3172}
3173
1bd8d726 3174bool lxc_delete_network_priv(struct lxc_handler *handler)
811ef482
CB
3175{
3176 int ret;
3177 struct lxc_list *iterator;
3178 struct lxc_list *network = &handler->conf->network;
1bd8d726 3179
811ef482
CB
3180 lxc_list_for_each(iterator, network) {
3181 char *hostveth = NULL;
3182 struct lxc_netdev *netdev = iterator->elem;
3183
3184 /* We can only delete devices whose ifindex we have. If we don't
3185 * have the index it means that we didn't create it.
3186 */
3187 if (!netdev->ifindex)
3188 continue;
3189
0104c121
CB
3190 /*
3191 * If the network device has been moved back from the
3192 * containers network namespace, update the ifindex.
3193 */
3194 netdev->ifindex = if_nametoindex(netdev->name);
3195
6509154d 3196 /* Delete l2proxy entries if enabled and used with a link property */
f2711167 3197 if (netdev->l2proxy && !is_empty_string(netdev->link)) {
6509154d 3198 if (lxc_delete_l2proxy(netdev))
3199 WARN("Failed to delete all l2proxy config");
3200 /* Don't return, let the network be cleaned up as normal. */
3201 }
3202
811ef482
CB
3203 if (netdev->type == LXC_NET_PHYS) {
3204 ret = lxc_netdev_rename_by_index(netdev->ifindex, netdev->link);
3205 if (ret < 0)
3206 WARN("Failed to rename interface with index %d "
b809f232
CB
3207 "from \"%s\" to its initial name \"%s\"",
3208 netdev->ifindex, netdev->name, netdev->link);
0b154989 3209 else {
29589196
CB
3210 TRACE("Renamed interface with index %d from "
3211 "\"%s\" to its initial name \"%s\"",
3212 netdev->ifindex, netdev->name,
3213 netdev->link);
0b154989
TP
3214
3215 /* Restore original MTU */
3216 ret = lxc_netdev_set_mtu(netdev->link, netdev->priv.phys_attr.mtu);
3217 if (ret < 0) {
3218 WARN("Failed to set interface \"%s\" to its initial mtu \"%d\"",
3219 netdev->link, netdev->priv.phys_attr.mtu);
3220 } else {
3221 TRACE("Restored interface \"%s\" to its initial mtu \"%d\"",
3222 netdev->link, netdev->priv.phys_attr.mtu);
3223 }
3224 }
b3259dc6
TP
3225
3226 ret = netdev_deconf[netdev->type](handler, netdev);
40a22043
CB
3227 if (ret < 0)
3228 WARN("Failed to deconfigure interface with index %d and initial name \"%s\"",
3229 netdev->ifindex, netdev->link);
66a7c406 3230 goto clear_ifindices;
811ef482
CB
3231 }
3232
3233 ret = netdev_deconf[netdev->type](handler, netdev);
3234 if (ret < 0)
3235 WARN("Failed to deconfigure network device");
3236
811ef482 3237 if (netdev->type != LXC_NET_VETH)
66a7c406 3238 goto clear_ifindices;
811ef482 3239
811ef482
CB
3240 /* Explicitly delete host veth device to prevent lingering
3241 * devices. We had issues in LXD around this.
3242 */
f2711167 3243 if (!is_empty_string(netdev->priv.veth_attr.pair))
811ef482
CB
3244 hostveth = netdev->priv.veth_attr.pair;
3245 else
3246 hostveth = netdev->priv.veth_attr.veth1;
f2711167 3247 if (is_empty_string(hostveth))
66a7c406 3248 goto clear_ifindices;
811ef482 3249
1ee56cff
CB
3250 if (is_empty_string(netdev->link) || !is_ovs_bridge(netdev->link)) {
3251 ret = lxc_netdev_delete_by_name(hostveth);
3252 if (ret < 0)
3253 WARN("Failed to remove interface \"%s\" from \"%s\"", hostveth, netdev->link);
811ef482 3254
1ee56cff
CB
3255 INFO("Removed interface \"%s\" from \"%s\"", hostveth, netdev->link);
3256 } else if (!is_empty_string(netdev->link)) {
3257 ret = lxc_ovs_delete_port(netdev->link, hostveth);
3258 if (ret < 0)
3259 WARN("Failed to remove port \"%s\" from openvswitch bridge \"%s\"", hostveth, netdev->link);
811ef482 3260
1ee56cff
CB
3261 INFO("Removed port \"%s\" from openvswitch bridge \"%s\"", hostveth, netdev->link);
3262 }
811ef482 3263
66a7c406 3264clear_ifindices:
ad2ddfcd 3265 /* We need to clear any ifindices we recorded so liblxc won't
66a7c406
CB
3266 * have cached stale data which would cause it to fail on reboot
3267 * we're we don't re-read the on-disk config file.
3268 */
3269 netdev->ifindex = 0;
3270 if (netdev->type == LXC_NET_PHYS) {
3271 netdev->priv.phys_attr.ifindex = 0;
3272 } else if (netdev->type == LXC_NET_VETH) {
3273 netdev->priv.veth_attr.veth1[0] = '\0';
3274 netdev->priv.veth_attr.ifindex = 0;
3275 }
811ef482
CB
3276 }
3277
bb84beda 3278 return true;
811ef482
CB
3279}
3280
3281int lxc_requests_empty_network(struct lxc_handler *handler)
3282{
3283 struct lxc_list *network = &handler->conf->network;
3284 struct lxc_list *iterator;
3285 bool found_none = false, found_nic = false;
3286
3287 if (lxc_list_empty(network))
3288 return 0;
3289
9c66dc4f 3290 lxc_list_for_each (iterator, network) {
811ef482
CB
3291 struct lxc_netdev *netdev = iterator->elem;
3292
3293 if (netdev->type == LXC_NET_NONE)
3294 found_none = true;
3295 else
3296 found_nic = true;
3297 }
9c66dc4f 3298
811ef482
CB
3299 if (found_none && !found_nic)
3300 return 1;
9c66dc4f 3301
811ef482
CB
3302 return 0;
3303}
3304
3305/* try to move physical nics to the init netns */
b809f232 3306int lxc_restore_phys_nics_to_netns(struct lxc_handler *handler)
811ef482 3307{
9c66dc4f
CB
3308 __do_close int oldfd = -EBADF;
3309 int netnsfd = handler->nsfd[LXC_NS_NET];
3310 struct lxc_conf *conf = handler->conf;
811ef482 3311 int ret;
811ef482 3312 char ifname[IFNAMSIZ];
b809f232 3313 struct lxc_list *iterator;
811ef482 3314
b809f232
CB
3315 /* We need CAP_NET_ADMIN in the parent namespace in order to setns() to
3316 * the parent network namespace. We won't have this capability if we are
3317 * unprivileged.
3318 */
d0fbc7ba 3319 if (!handler->am_root)
b809f232 3320 return 0;
811ef482 3321
b809f232 3322 TRACE("Moving physical network devices back to parent network namespace");
811ef482 3323
0037ab49 3324 oldfd = lxc_preserve_ns(handler->monitor_pid, "net");
9c66dc4f
CB
3325 if (oldfd < 0)
3326 return log_error_errno(-1, errno, "Failed to preserve network namespace");
811ef482 3327
b809f232 3328 ret = setns(netnsfd, CLONE_NEWNET);
9c66dc4f
CB
3329 if (ret < 0)
3330 return log_error_errno(-1, errno, "Failed to enter network namespace");
811ef482 3331
b809f232
CB
3332 lxc_list_for_each(iterator, &conf->network) {
3333 struct lxc_netdev *netdev = iterator->elem;
811ef482 3334
b809f232
CB
3335 if (netdev->type != LXC_NET_PHYS)
3336 continue;
3337
3338 /* Retrieve the name of the interface in the container's network
3339 * namespace.
3340 */
3341 if (!if_indextoname(netdev->ifindex, ifname)) {
9c66dc4f 3342 WARN("No interface corresponding to ifindex %d", netdev->ifindex);
811ef482
CB
3343 continue;
3344 }
b809f232 3345
0037ab49 3346 ret = lxc_netdev_move_by_index_fd(netdev->ifindex, oldfd, netdev->link);
b809f232 3347 if (ret < 0)
9c66dc4f 3348 WARN("Error moving network device \"%s\" back to network namespace", ifname);
b809f232 3349 else
9c66dc4f 3350 TRACE("Moved network device \"%s\" back to network namespace", ifname);
811ef482 3351 }
811ef482 3352
b809f232 3353 ret = setns(oldfd, CLONE_NEWNET);
9c66dc4f
CB
3354 if (ret < 0)
3355 return log_error_errno(-1, errno, "Failed to enter network namespace");
b809f232
CB
3356
3357 return 0;
811ef482
CB
3358}
3359
3360static int setup_hw_addr(char *hwaddr, const char *ifname)
3361{
9c66dc4f 3362 __do_close int fd = -EBADF;
811ef482
CB
3363 struct sockaddr sockaddr;
3364 struct ifreq ifr;
9c66dc4f 3365 int ret;
811ef482
CB
3366
3367 ret = lxc_convert_mac(hwaddr, &sockaddr);
9c66dc4f
CB
3368 if (ret)
3369 return log_error_errno(-1, -ret, "Mac address \"%s\" conversion failed", hwaddr);
811ef482
CB
3370
3371 memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
3372 ifr.ifr_name[IFNAMSIZ-1] = '\0';
3373 memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr));
3374
ad9429e5 3375 fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
811ef482
CB
3376 if (fd < 0)
3377 return -1;
3378
3379 ret = ioctl(fd, SIOCSIFHWADDR, &ifr);
811ef482 3380 if (ret)
6d1400b5 3381 SYSERROR("Failed to perform ioctl");
3382
9c66dc4f 3383 DEBUG("Mac address \"%s\" on \"%s\" has been setup", hwaddr, ifr.ifr_name);
811ef482
CB
3384
3385 return ret;
3386}
3387
3388static int setup_ipv4_addr(struct lxc_list *ip, int ifindex)
3389{
3390 struct lxc_list *iterator;
3391 int err;
3392
3393 lxc_list_for_each(iterator, ip) {
3394 struct lxc_inetdev *inetdev = iterator->elem;
3395
3396 err = lxc_ipv4_addr_add(ifindex, &inetdev->addr,
3397 &inetdev->bcast, inetdev->prefix);
9c66dc4f
CB
3398 if (err)
3399 return log_error_errno(-1, -err, "Failed to setup ipv4 address for network device with ifindex %d", ifindex);
811ef482
CB
3400 }
3401
3402 return 0;
3403}
3404
3405static int setup_ipv6_addr(struct lxc_list *ip, int ifindex)
3406{
3407 struct lxc_list *iterator;
3408 int err;
3409
3410 lxc_list_for_each(iterator, ip) {
3411 struct lxc_inet6dev *inet6dev = iterator->elem;
3412
3413 err = lxc_ipv6_addr_add(ifindex, &inet6dev->addr,
3414 &inet6dev->mcast, &inet6dev->acast,
3415 inet6dev->prefix);
9c66dc4f
CB
3416 if (err)
3417 return log_error_errno(-1, -err, "Failed to setup ipv6 address for network device with ifindex %d", ifindex);
811ef482
CB
3418 }
3419
3420 return 0;
3421}
3422
8bf64b77 3423static int lxc_network_setup_in_child_namespaces_common(struct lxc_netdev *netdev)
811ef482 3424{
811ef482 3425 int err;
009d6127 3426 char bufinet4[INET_ADDRSTRLEN], bufinet6[INET6_ADDRSTRLEN];
811ef482
CB
3427
3428 /* empty network namespace */
8bf64b77
CB
3429 if (!netdev->ifindex && netdev->flags & IFF_UP) {
3430 err = lxc_netdev_up("lo");
9c66dc4f
CB
3431 if (err)
3432 return log_error_errno(-1, -err, "Failed to set the loopback network device up");
811ef482
CB
3433 }
3434
811ef482 3435 /* set a mac address */
9c66dc4f
CB
3436 if (netdev->hwaddr && setup_hw_addr(netdev->hwaddr, netdev->name))
3437 return log_error_errno(-1, errno, "Failed to setup hw address for network device \"%s\"", netdev->name);
811ef482
CB
3438
3439 /* setup ipv4 addresses on the interface */
9c66dc4f
CB
3440 if (setup_ipv4_addr(&netdev->ipv4, netdev->ifindex))
3441 return log_error_errno(-1, errno, "Failed to setup ip addresses for network device \"%s\"", netdev->name);
811ef482
CB
3442
3443 /* setup ipv6 addresses on the interface */
9c66dc4f
CB
3444 if (setup_ipv6_addr(&netdev->ipv6, netdev->ifindex))
3445 return log_error_errno(-1, errno, "Failed to setup ipv6 addresses for network device \"%s\"", netdev->name);
811ef482
CB
3446
3447 /* set the network device up */
3448 if (netdev->flags & IFF_UP) {
8bf64b77 3449 err = lxc_netdev_up(netdev->name);
9c66dc4f
CB
3450 if (err)
3451 return log_error_errno(-1, -err, "Failed to set network device \"%s\" up", netdev->name);
811ef482
CB
3452
3453 /* the network is up, make the loopback up too */
3454 err = lxc_netdev_up("lo");
9c66dc4f
CB
3455 if (err)
3456 return log_error_errno(-1, -err, "Failed to set the loopback network device up");
811ef482
CB
3457 }
3458
811ef482 3459 /* setup ipv4 gateway on the interface */
a2f9a670 3460 if (netdev->ipv4_gateway || netdev->ipv4_gateway_dev) {
9c66dc4f
CB
3461 if (!(netdev->flags & IFF_UP))
3462 return log_error(-1, "Cannot add ipv4 gateway for network device \"%s\" when not bringing up the interface", netdev->name);
811ef482 3463
9c66dc4f
CB
3464 if (lxc_list_empty(&netdev->ipv4))
3465 return log_error(-1, "Cannot add ipv4 gateway for network device \"%s\" when not assigning an address", netdev->name);
811ef482 3466
a2f9a670 3467 /* Setup device route if ipv4_gateway_dev is enabled */
3468 if (netdev->ipv4_gateway_dev) {
3469 err = lxc_ipv4_gateway_add(netdev->ifindex, NULL);
9c66dc4f
CB
3470 if (err < 0)
3471 return log_error_errno(-1, -err, "Failed to setup ipv4 gateway to network device \"%s\"", netdev->name);
a2f9a670 3472 } else {
009d6127 3473 /* Check the gateway address is valid */
3474 if (!inet_ntop(AF_INET, netdev->ipv4_gateway, bufinet4, sizeof(bufinet4)))
596a002c 3475 return ret_set_errno(-1, errno);
009d6127 3476
3477 /* Try adding a default route to the gateway address */
811ef482 3478 err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
009d6127 3479 if (err < 0) {
3480 /* If adding the default route fails, this could be because the
3481 * gateway address is in a different subnet to the container's address.
3482 * To work around this, we try adding a static device route to the
3483 * gateway address first, and then try again.
3484 */
a2f9a670 3485 err = lxc_ipv4_dest_add(netdev->ifindex, netdev->ipv4_gateway, 32);
9c66dc4f
CB
3486 if (err < 0)
3487 return log_error_errno(-1, -err, "Failed to add ipv4 dest \"%s\" for network device \"%s\"", bufinet4, netdev->name);
6d1400b5 3488
a2f9a670 3489 err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
9c66dc4f
CB
3490 if (err < 0)
3491 return log_error_errno(-1, -err, "Failed to setup ipv4 gateway \"%s\" for network device \"%s\"", bufinet4, netdev->name);
811ef482
CB
3492 }
3493 }
3494 }
3495
3496 /* setup ipv6 gateway on the interface */
a2f9a670 3497 if (netdev->ipv6_gateway || netdev->ipv6_gateway_dev) {
9c66dc4f
CB
3498 if (!(netdev->flags & IFF_UP))
3499 return log_error(-1, "Cannot add ipv6 gateway for network device \"%s\" when not bringing up the interface", netdev->name);
811ef482 3500
9c66dc4f
CB
3501 if (lxc_list_empty(&netdev->ipv6) && !IN6_IS_ADDR_LINKLOCAL(netdev->ipv6_gateway))
3502 return log_error(-1, "Cannot add ipv6 gateway for network device \"%s\" when not assigning an address", netdev->name);
811ef482 3503
a2f9a670 3504 /* Setup device route if ipv6_gateway_dev is enabled */
3505 if (netdev->ipv6_gateway_dev) {
3506 err = lxc_ipv6_gateway_add(netdev->ifindex, NULL);
9c66dc4f
CB
3507 if (err < 0)
3508 return log_error_errno(-1, -err, "Failed to setup ipv6 gateway to network device \"%s\"", netdev->name);
a2f9a670 3509 } else {
009d6127 3510 /* Check the gateway address is valid */
3511 if (!inet_ntop(AF_INET6, netdev->ipv6_gateway, bufinet6, sizeof(bufinet6)))
596a002c 3512 return ret_set_errno(-1, errno);
009d6127 3513
3514 /* Try adding a default route to the gateway address */
811ef482 3515 err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
009d6127 3516 if (err < 0) {
3517 /* If adding the default route fails, this could be because the
3518 * gateway address is in a different subnet to the container's address.
3519 * To work around this, we try adding a static device route to the
3520 * gateway address first, and then try again.
3521 */
a2f9a670 3522 err = lxc_ipv6_dest_add(netdev->ifindex, netdev->ipv6_gateway, 128);
9c66dc4f
CB
3523 if (err < 0)
3524 return log_error_errno(-1, errno, "Failed to add ipv6 dest \"%s\" for network device \"%s\"", bufinet6, netdev->name);
6d1400b5 3525
a2f9a670 3526 err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
9c66dc4f
CB
3527 if (err < 0)
3528 return log_error_errno(-1, -err, "Failed to setup ipv6 gateway \"%s\" for network device \"%s\"", bufinet6, netdev->name);
811ef482
CB
3529 }
3530 }
3531 }
3532
8bf64b77 3533 DEBUG("Network device \"%s\" has been setup", netdev->name);
811ef482
CB
3534
3535 return 0;
3536}
3537
3538int lxc_setup_network_in_child_namespaces(const struct lxc_conf *conf,
3539 struct lxc_list *network)
3540{
3541 struct lxc_list *iterator;
811ef482 3542
8bf64b77 3543 lxc_list_for_each (iterator, network) {
e389f2af 3544 struct lxc_netdev *netdev = iterator->elem;
8bf64b77 3545 int ret;
811ef482 3546
8bf64b77
CB
3547 ret = netdev_ns_conf[netdev->type](netdev);
3548 if (!ret)
3549 ret = lxc_network_setup_in_child_namespaces_common(netdev);
9c66dc4f
CB
3550 if (ret)
3551 return log_error_errno(-1, errno, "Failed to setup netdev");
811ef482
CB
3552 }
3553
3554 if (!lxc_list_empty(network))
e389f2af 3555 INFO("Network has been setup");
811ef482
CB
3556
3557 return 0;
3558}
7ab1ba02 3559
3c09b97c 3560int lxc_network_send_to_child(struct lxc_handler *handler)
7ab1ba02
CB
3561{
3562 struct lxc_list *iterator;
3563 struct lxc_list *network = &handler->conf->network;
3564 int data_sock = handler->data_sock[0];
3565
7ab1ba02
CB
3566 lxc_list_for_each(iterator, network) {
3567 int ret;
3568 struct lxc_netdev *netdev = iterator->elem;
3569
3c09b97c 3570 if (!network_requires_advanced_setup(netdev->type))
7ab1ba02
CB
3571 continue;
3572
7fbb15ec 3573 ret = lxc_send_nointr(data_sock, netdev->name, IFNAMSIZ, MSG_NOSIGNAL);
7729f8e5 3574 if (ret < 0)
7ab1ba02 3575 return -1;
e389f2af
CB
3576
3577 ret = lxc_send_nointr(data_sock, netdev->created_name, IFNAMSIZ, MSG_NOSIGNAL);
3578 if (ret < 0)
3579 return -1;
3580
3581 TRACE("Sent network device name \"%s\" to child", netdev->created_name);
7ab1ba02
CB
3582 }
3583
3584 return 0;
3585}
3586
3c09b97c 3587int lxc_network_recv_from_parent(struct lxc_handler *handler)
7ab1ba02
CB
3588{
3589 struct lxc_list *iterator;
3590 struct lxc_list *network = &handler->conf->network;
3591 int data_sock = handler->data_sock[1];
3592
7ab1ba02
CB
3593 lxc_list_for_each(iterator, network) {
3594 int ret;
3595 struct lxc_netdev *netdev = iterator->elem;
3596
3c09b97c 3597 if (!network_requires_advanced_setup(netdev->type))
7ab1ba02
CB
3598 continue;
3599
e3233f26 3600 ret = lxc_recv_nointr(data_sock, netdev->name, IFNAMSIZ, 0);
7729f8e5 3601 if (ret < 0)
7ab1ba02 3602 return -1;
e389f2af
CB
3603
3604 ret = lxc_recv_nointr(data_sock, netdev->created_name, IFNAMSIZ, 0);
3605 if (ret < 0)
3606 return -1;
54256301 3607
e389f2af 3608 TRACE("Received network device name \"%s\" from parent", netdev->created_name);
7ab1ba02
CB
3609 }
3610
3611 return 0;
3612}
a1ae535a
CB
3613
3614int lxc_network_send_name_and_ifindex_to_parent(struct lxc_handler *handler)
3615{
3616 struct lxc_list *iterator, *network;
3617 int data_sock = handler->data_sock[0];
3618
3619 if (!handler->am_root)
3620 return 0;
3621
3622 network = &handler->conf->network;
3623 lxc_list_for_each(iterator, network) {
3624 int ret;
3625 struct lxc_netdev *netdev = iterator->elem;
3626
3627 /* Send network device name in the child's namespace to parent. */
7fbb15ec 3628 ret = lxc_send_nointr(data_sock, netdev->name, IFNAMSIZ, MSG_NOSIGNAL);
a1ae535a 3629 if (ret < 0)
7729f8e5 3630 return -1;
a1ae535a
CB
3631
3632 /* Send network device ifindex in the child's namespace to
3633 * parent.
3634 */
7fbb15ec 3635 ret = lxc_send_nointr(data_sock, &netdev->ifindex, sizeof(netdev->ifindex), MSG_NOSIGNAL);
a1ae535a 3636 if (ret < 0)
7729f8e5 3637 return -1;
a1ae535a
CB
3638 }
3639
e389f2af
CB
3640 if (!lxc_list_empty(network))
3641 TRACE("Sent network device names and ifindices to parent");
3642
a1ae535a 3643 return 0;
a1ae535a
CB
3644}
3645
3646int lxc_network_recv_name_and_ifindex_from_child(struct lxc_handler *handler)
3647{
3648 struct lxc_list *iterator, *network;
3649 int data_sock = handler->data_sock[1];
3650
3651 if (!handler->am_root)
3652 return 0;
3653
3654 network = &handler->conf->network;
3655 lxc_list_for_each(iterator, network) {
3656 int ret;
3657 struct lxc_netdev *netdev = iterator->elem;
3658
3659 /* Receive network device name in the child's namespace to
3660 * parent.
3661 */
e3233f26 3662 ret = lxc_recv_nointr(data_sock, netdev->name, IFNAMSIZ, 0);
a1ae535a 3663 if (ret < 0)
7729f8e5 3664 return -1;
a1ae535a
CB
3665
3666 /* Receive network device ifindex in the child's namespace to
3667 * parent.
3668 */
e3233f26 3669 ret = lxc_recv_nointr(data_sock, &netdev->ifindex, sizeof(netdev->ifindex), 0);
a1ae535a 3670 if (ret < 0)
7729f8e5 3671 return -1;
a1ae535a
CB
3672 }
3673
3674 return 0;
a1ae535a 3675}
bb84beda
CB
3676
3677void lxc_delete_network(struct lxc_handler *handler)
3678{
3679 bool bret;
3680
3681 if (handler->am_root)
3682 bret = lxc_delete_network_priv(handler);
3683 else
3684 bret = lxc_delete_network_unpriv(handler);
3685 if (!bret)
3686 DEBUG("Failed to delete network devices");
3687 else
3688 DEBUG("Deleted network devices");
3689}
1cd95214 3690
1cd95214
CB
3691int lxc_netns_set_nsid(int fd)
3692{
41a3300d 3693 int ret;
0ce60f0d
CB
3694 char buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
3695 NLMSG_ALIGN(sizeof(struct rtgenmsg)) +
3696 NLMSG_ALIGN(1024)];
1cd95214 3697 struct nl_handler nlh;
a5f5cb41 3698 call_cleaner(netlink_close) struct nl_handler *nlh_ptr = &nlh;
0ce60f0d
CB
3699 struct nlmsghdr *hdr;
3700 struct rtgenmsg *msg;
9d036caa
CB
3701 const __s32 ns_id = -1;
3702 const __u32 netns_fd = fd;
1cd95214 3703
a5f5cb41 3704 ret = netlink_open(nlh_ptr, NETLINK_ROUTE);
1cd95214 3705 if (ret < 0)
41a3300d 3706 return -1;
1cd95214 3707
0ce60f0d 3708 memset(buf, 0, sizeof(buf));
6ce39620
CB
3709
3710#pragma GCC diagnostic push
3711#pragma GCC diagnostic ignored "-Wcast-align"
0ce60f0d
CB
3712 hdr = (struct nlmsghdr *)buf;
3713 msg = (struct rtgenmsg *)NLMSG_DATA(hdr);
6ce39620 3714#pragma GCC diagnostic pop
1cd95214 3715
0ce60f0d
CB
3716 hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*msg));
3717 hdr->nlmsg_type = RTM_NEWNSID;
3718 hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
3719 hdr->nlmsg_pid = 0;
3720 hdr->nlmsg_seq = RTM_NEWNSID;
3721 msg->rtgen_family = AF_UNSPEC;
1cd95214 3722
9d036caa
CB
3723 ret = addattr(hdr, 1024, __LXC_NETNSA_FD, &netns_fd, sizeof(netns_fd));
3724 if (ret < 0)
a5f5cb41 3725 return ret_errno(ENOMEM);
9d036caa
CB
3726
3727 ret = addattr(hdr, 1024, __LXC_NETNSA_NSID, &ns_id, sizeof(ns_id));
3728 if (ret < 0)
a5f5cb41 3729 return ret_errno(ENOMEM);
1cd95214 3730
a5f5cb41 3731 return __netlink_transaction(nlh_ptr, hdr, hdr);
1cd95214 3732}
938980ba
CB
3733
3734static int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
3735{
3736
3737 memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
3738
3739 while (RTA_OK(rta, len)) {
3740 unsigned short type = rta->rta_type;
3741
3742 if ((type <= max) && (!tb[type]))
3743 tb[type] = rta;
3744
6ce39620
CB
3745#pragma GCC diagnostic push
3746#pragma GCC diagnostic ignored "-Wcast-align"
938980ba 3747 rta = RTA_NEXT(rta, len);
6ce39620 3748#pragma GCC diagnostic pop
938980ba
CB
3749 }
3750
3751 return 0;
3752}
3753
3754static inline __s32 rta_getattr_s32(const struct rtattr *rta)
3755{
3756 return *(__s32 *)RTA_DATA(rta);
3757}
3758
3759#ifndef NETNS_RTA
3760#define NETNS_RTA(r) \
3761 ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))))
3762#endif
3763
3764int lxc_netns_get_nsid(int fd)
3765{
a5f5cb41
CB
3766 struct nl_handler nlh;
3767 call_cleaner(netlink_close) struct nl_handler *nlh_ptr = &nlh;
938980ba
CB
3768 int ret;
3769 ssize_t len;
3770 char buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
9d036caa
CB
3771 NLMSG_ALIGN(sizeof(struct rtgenmsg)) +
3772 NLMSG_ALIGN(1024)];
938980ba 3773 struct rtattr *tb[__LXC_NETNSA_MAX + 1];
938980ba
CB
3774 struct nlmsghdr *hdr;
3775 struct rtgenmsg *msg;
938980ba
CB
3776 __u32 netns_fd = fd;
3777
a5f5cb41 3778 ret = netlink_open(nlh_ptr, NETLINK_ROUTE);
938980ba
CB
3779 if (ret < 0)
3780 return -1;
3781
3782 memset(buf, 0, sizeof(buf));
6ce39620
CB
3783
3784#pragma GCC diagnostic push
3785#pragma GCC diagnostic ignored "-Wcast-align"
938980ba
CB
3786 hdr = (struct nlmsghdr *)buf;
3787 msg = (struct rtgenmsg *)NLMSG_DATA(hdr);
6ce39620 3788#pragma GCC diagnostic pop
938980ba
CB
3789
3790 hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*msg));
3791 hdr->nlmsg_type = RTM_GETNSID;
3792 hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
3793 hdr->nlmsg_pid = 0;
3794 hdr->nlmsg_seq = RTM_GETNSID;
3795 msg->rtgen_family = AF_UNSPEC;
3796
9d036caa 3797 ret = addattr(hdr, 1024, __LXC_NETNSA_FD, &netns_fd, sizeof(netns_fd));
a5f5cb41
CB
3798 if (ret < 0)
3799 return ret_errno(ENOMEM);
938980ba 3800
a5f5cb41 3801 ret = __netlink_transaction(nlh_ptr, hdr, hdr);
938980ba
CB
3802 if (ret < 0)
3803 return -1;
3804
3805 msg = NLMSG_DATA(hdr);
3806 len = hdr->nlmsg_len - NLMSG_SPACE(sizeof(*msg));
3807 if (len < 0)
a5f5cb41 3808 return ret_errno(EINVAL);
938980ba 3809
6ce39620
CB
3810#pragma GCC diagnostic push
3811#pragma GCC diagnostic ignored "-Wcast-align"
938980ba
CB
3812 parse_rtattr(tb, __LXC_NETNSA_MAX, NETNS_RTA(msg), len);
3813 if (tb[__LXC_NETNSA_NSID])
3814 return rta_getattr_s32(tb[__LXC_NETNSA_NSID]);
6ce39620 3815#pragma GCC diagnostic pop
938980ba
CB
3816
3817 return -1;
3818}
e389f2af
CB
3819
3820int lxc_create_network(struct lxc_handler *handler)
3821{
3822 int ret;
3823
e389f2af
CB
3824 if (handler->am_root) {
3825 ret = lxc_create_network_priv(handler);
3826 if (ret)
3827 return -1;
3828
3829 return lxc_network_move_created_netdev_priv(handler);
3830 }
3831
3832 return lxc_create_network_unpriv(handler);
3833}