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