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