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