]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/nspawn/nspawn-network.c
tree-wide: add missing includes
[thirdparty/systemd.git] / src / nspawn / nspawn-network.c
CommitLineData
9a2a5625
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2015 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <linux/veth.h>
23#include <net/if.h>
24
07630cea 25#include "libudev.h"
9a2a5625
LP
26#include "sd-id128.h"
27#include "sd-netlink.h"
9a2a5625 28
b5efdb8a 29#include "alloc-util.h"
9a2a5625 30#include "ether-addr-util.h"
9a2a5625 31#include "netlink-util.h"
07630cea
LP
32#include "siphash24.h"
33#include "string-util.h"
9a2a5625 34#include "udev-util.h"
07630cea 35#include "util.h"
9a2a5625
LP
36#include "nspawn-network.h"
37
38#define HOST_HASH_KEY SD_ID128_MAKE(1a,37,6f,c7,46,ec,45,0b,ad,a3,d5,31,06,60,5d,b1)
39#define CONTAINER_HASH_KEY SD_ID128_MAKE(c3,c4,f9,19,b5,57,b2,1c,e6,cf,14,27,03,9c,ee,a2)
f6d6bad1
LP
40#define VETH_EXTRA_HOST_HASH_KEY SD_ID128_MAKE(48,c7,f6,b7,ea,9d,4c,9e,b7,28,d4,de,91,d5,bf,66)
41#define VETH_EXTRA_CONTAINER_HASH_KEY SD_ID128_MAKE(af,50,17,61,ce,f9,4d,35,84,0d,2b,20,54,be,ce,59)
9a2a5625
LP
42#define MACVLAN_HASH_KEY SD_ID128_MAKE(00,13,6d,bc,66,83,44,81,bb,0c,f9,51,1f,24,a6,6f)
43
44static int generate_mac(
45 const char *machine_name,
46 struct ether_addr *mac,
47 sd_id128_t hash_key,
48 uint64_t idx) {
49
dbe81cbd 50 uint64_t result;
9a2a5625
LP
51 size_t l, sz;
52 uint8_t *v, *i;
53 int r;
54
55 l = strlen(machine_name);
56 sz = sizeof(sd_id128_t) + l;
57 if (idx > 0)
58 sz += sizeof(idx);
59
60 v = alloca(sz);
61
62 /* fetch some persistent data unique to the host */
63 r = sd_id128_get_machine((sd_id128_t*) v);
64 if (r < 0)
65 return r;
66
67 /* combine with some data unique (on this host) to this
68 * container instance */
69 i = mempcpy(v + sizeof(sd_id128_t), machine_name, l);
70 if (idx > 0) {
71 idx = htole64(idx);
72 memcpy(i, &idx, sizeof(idx));
73 }
74
75 /* Let's hash the host machine ID plus the container name. We
76 * use a fixed, but originally randomly created hash key here. */
dbe81cbd 77 siphash24(&result, v, sz, hash_key.bytes);
9a2a5625
LP
78
79 assert_cc(ETH_ALEN <= sizeof(result));
dbe81cbd 80 memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
9a2a5625
LP
81
82 /* see eth_random_addr in the kernel */
83 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
84 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
85
86 return 0;
87}
88
f6d6bad1
LP
89static int add_veth(
90 sd_netlink *rtnl,
91 pid_t pid,
92 const char *ifname_host,
93 const struct ether_addr *mac_host,
94 const char *ifname_container,
95 const struct ether_addr *mac_container) {
9a2a5625
LP
96
97 _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
f6d6bad1 98 int r;
9a2a5625 99
f6d6bad1
LP
100 assert(rtnl);
101 assert(ifname_host);
102 assert(mac_host);
103 assert(ifname_container);
104 assert(mac_container);
9a2a5625
LP
105
106 r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
107 if (r < 0)
108 return log_error_errno(r, "Failed to allocate netlink message: %m");
109
f6d6bad1 110 r = sd_netlink_message_append_string(m, IFLA_IFNAME, ifname_host);
9a2a5625
LP
111 if (r < 0)
112 return log_error_errno(r, "Failed to add netlink interface name: %m");
113
f6d6bad1 114 r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, mac_host);
9a2a5625
LP
115 if (r < 0)
116 return log_error_errno(r, "Failed to add netlink MAC address: %m");
117
118 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
119 if (r < 0)
120 return log_error_errno(r, "Failed to open netlink container: %m");
121
122 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "veth");
123 if (r < 0)
124 return log_error_errno(r, "Failed to open netlink container: %m");
125
126 r = sd_netlink_message_open_container(m, VETH_INFO_PEER);
127 if (r < 0)
128 return log_error_errno(r, "Failed to open netlink container: %m");
129
f6d6bad1 130 r = sd_netlink_message_append_string(m, IFLA_IFNAME, ifname_container);
9a2a5625
LP
131 if (r < 0)
132 return log_error_errno(r, "Failed to add netlink interface name: %m");
133
f6d6bad1 134 r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, mac_container);
9a2a5625
LP
135 if (r < 0)
136 return log_error_errno(r, "Failed to add netlink MAC address: %m");
137
138 r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
139 if (r < 0)
140 return log_error_errno(r, "Failed to add netlink namespace field: %m");
141
142 r = sd_netlink_message_close_container(m);
143 if (r < 0)
144 return log_error_errno(r, "Failed to close netlink container: %m");
145
146 r = sd_netlink_message_close_container(m);
147 if (r < 0)
148 return log_error_errno(r, "Failed to close netlink container: %m");
149
150 r = sd_netlink_message_close_container(m);
151 if (r < 0)
152 return log_error_errno(r, "Failed to close netlink container: %m");
153
154 r = sd_netlink_call(rtnl, m, 0, NULL);
155 if (r < 0)
f6d6bad1
LP
156 return log_error_errno(r, "Failed to add new veth interfaces (%s:%s): %m", ifname_host, ifname_container);
157
158 return 0;
159}
160
161int setup_veth(const char *machine_name,
162 pid_t pid,
163 char iface_name[IFNAMSIZ],
164 bool bridge) {
165
166 _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
167 struct ether_addr mac_host, mac_container;
168 int r, i;
169
170 assert(machine_name);
171 assert(pid > 0);
172 assert(iface_name);
173
174 /* Use two different interface name prefixes depending whether
175 * we are in bridge mode or not. */
176 snprintf(iface_name, IFNAMSIZ - 1, "%s-%s",
177 bridge ? "vb" : "ve", machine_name);
178
179 r = generate_mac(machine_name, &mac_container, CONTAINER_HASH_KEY, 0);
180 if (r < 0)
181 return log_error_errno(r, "Failed to generate predictable MAC address for container side: %m");
182
183 r = generate_mac(machine_name, &mac_host, HOST_HASH_KEY, 0);
184 if (r < 0)
185 return log_error_errno(r, "Failed to generate predictable MAC address for host side: %m");
186
187 r = sd_netlink_open(&rtnl);
188 if (r < 0)
189 return log_error_errno(r, "Failed to connect to netlink: %m");
190
191 r = add_veth(rtnl, pid, iface_name, &mac_host, "host0", &mac_container);
192 if (r < 0)
193 return r;
9a2a5625
LP
194
195 i = (int) if_nametoindex(iface_name);
196 if (i <= 0)
197 return log_error_errno(errno, "Failed to resolve interface %s: %m", iface_name);
198
199 return i;
200}
201
f6d6bad1
LP
202int setup_veth_extra(
203 const char *machine_name,
204 pid_t pid,
205 char **pairs) {
206
207 _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
208 uint64_t idx = 0;
209 char **a, **b;
210 int r;
211
212 assert(machine_name);
213 assert(pid > 0);
214
215 if (strv_isempty(pairs))
216 return 0;
217
218 r = sd_netlink_open(&rtnl);
219 if (r < 0)
220 return log_error_errno(r, "Failed to connect to netlink: %m");
221
222 STRV_FOREACH_PAIR(a, b, pairs) {
223 struct ether_addr mac_host, mac_container;
224
225 r = generate_mac(machine_name, &mac_container, VETH_EXTRA_CONTAINER_HASH_KEY, idx);
226 if (r < 0)
227 return log_error_errno(r, "Failed to generate predictable MAC address for container side of extra veth link: %m");
228
229 r = generate_mac(machine_name, &mac_host, VETH_EXTRA_HOST_HASH_KEY, idx);
230 if (r < 0)
231 return log_error_errno(r, "Failed to generate predictable MAC address for container side of extra veth link: %m");
232
233 r = add_veth(rtnl, pid, *a, &mac_host, *b, &mac_container);
234 if (r < 0)
235 return r;
236
237 idx ++;
238 }
239
240 return 0;
241}
242
9a2a5625
LP
243int setup_bridge(const char *veth_name, const char *bridge_name) {
244 _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
245 _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
246 int r, bridge_ifi;
247
248 assert(veth_name);
249 assert(bridge_name);
250
251 bridge_ifi = (int) if_nametoindex(bridge_name);
252 if (bridge_ifi <= 0)
253 return log_error_errno(errno, "Failed to resolve interface %s: %m", bridge_name);
254
255 r = sd_netlink_open(&rtnl);
256 if (r < 0)
257 return log_error_errno(r, "Failed to connect to netlink: %m");
258
259 r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, 0);
260 if (r < 0)
261 return log_error_errno(r, "Failed to allocate netlink message: %m");
262
263 r = sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP);
264 if (r < 0)
265 return log_error_errno(r, "Failed to set IFF_UP flag: %m");
266
267 r = sd_netlink_message_append_string(m, IFLA_IFNAME, veth_name);
268 if (r < 0)
269 return log_error_errno(r, "Failed to add netlink interface name field: %m");
270
271 r = sd_netlink_message_append_u32(m, IFLA_MASTER, bridge_ifi);
272 if (r < 0)
273 return log_error_errno(r, "Failed to add netlink master field: %m");
274
275 r = sd_netlink_call(rtnl, m, 0, NULL);
276 if (r < 0)
277 return log_error_errno(r, "Failed to add veth interface to bridge: %m");
278
279 return bridge_ifi;
280}
281
282static int parse_interface(struct udev *udev, const char *name) {
283 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
284 char ifi_str[2 + DECIMAL_STR_MAX(int)];
285 int ifi;
286
287 ifi = (int) if_nametoindex(name);
288 if (ifi <= 0)
289 return log_error_errno(errno, "Failed to resolve interface %s: %m", name);
290
291 sprintf(ifi_str, "n%i", ifi);
292 d = udev_device_new_from_device_id(udev, ifi_str);
293 if (!d)
294 return log_error_errno(errno, "Failed to get udev device for interface %s: %m", name);
295
296 if (udev_device_get_is_initialized(d) <= 0) {
297 log_error("Network interface %s is not initialized yet.", name);
298 return -EBUSY;
299 }
300
301 return ifi;
302}
303
304int move_network_interfaces(pid_t pid, char **ifaces) {
305 _cleanup_udev_unref_ struct udev *udev = NULL;
306 _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
307 char **i;
308 int r;
309
310 if (strv_isempty(ifaces))
311 return 0;
312
313 r = sd_netlink_open(&rtnl);
314 if (r < 0)
315 return log_error_errno(r, "Failed to connect to netlink: %m");
316
317 udev = udev_new();
318 if (!udev) {
319 log_error("Failed to connect to udev.");
320 return -ENOMEM;
321 }
322
323 STRV_FOREACH(i, ifaces) {
324 _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
325 int ifi;
326
327 ifi = parse_interface(udev, *i);
328 if (ifi < 0)
329 return ifi;
330
331 r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, ifi);
332 if (r < 0)
333 return log_error_errno(r, "Failed to allocate netlink message: %m");
334
335 r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
336 if (r < 0)
337 return log_error_errno(r, "Failed to append namespace PID to netlink message: %m");
338
339 r = sd_netlink_call(rtnl, m, 0, NULL);
340 if (r < 0)
341 return log_error_errno(r, "Failed to move interface %s to namespace: %m", *i);
342 }
343
344 return 0;
345}
346
347int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) {
348 _cleanup_udev_unref_ struct udev *udev = NULL;
349 _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
350 unsigned idx = 0;
351 char **i;
352 int r;
353
354 if (strv_isempty(ifaces))
355 return 0;
356
357 r = sd_netlink_open(&rtnl);
358 if (r < 0)
359 return log_error_errno(r, "Failed to connect to netlink: %m");
360
361 udev = udev_new();
362 if (!udev) {
363 log_error("Failed to connect to udev.");
364 return -ENOMEM;
365 }
366
367 STRV_FOREACH(i, ifaces) {
368 _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
369 _cleanup_free_ char *n = NULL;
370 struct ether_addr mac;
371 int ifi;
372
373 ifi = parse_interface(udev, *i);
374 if (ifi < 0)
375 return ifi;
376
377 r = generate_mac(machine_name, &mac, MACVLAN_HASH_KEY, idx++);
378 if (r < 0)
379 return log_error_errno(r, "Failed to create MACVLAN MAC address: %m");
380
381 r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
382 if (r < 0)
383 return log_error_errno(r, "Failed to allocate netlink message: %m");
384
385 r = sd_netlink_message_append_u32(m, IFLA_LINK, ifi);
386 if (r < 0)
387 return log_error_errno(r, "Failed to add netlink interface index: %m");
388
389 n = strappend("mv-", *i);
390 if (!n)
391 return log_oom();
392
393 strshorten(n, IFNAMSIZ-1);
394
395 r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
396 if (r < 0)
397 return log_error_errno(r, "Failed to add netlink interface name: %m");
398
399 r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, &mac);
400 if (r < 0)
401 return log_error_errno(r, "Failed to add netlink MAC address: %m");
402
403 r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
404 if (r < 0)
405 return log_error_errno(r, "Failed to add netlink namespace field: %m");
406
407 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
408 if (r < 0)
409 return log_error_errno(r, "Failed to open netlink container: %m");
410
411 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "macvlan");
412 if (r < 0)
413 return log_error_errno(r, "Failed to open netlink container: %m");
414
415 r = sd_netlink_message_append_u32(m, IFLA_MACVLAN_MODE, MACVLAN_MODE_BRIDGE);
416 if (r < 0)
417 return log_error_errno(r, "Failed to append macvlan mode: %m");
418
419 r = sd_netlink_message_close_container(m);
420 if (r < 0)
421 return log_error_errno(r, "Failed to close netlink container: %m");
422
423 r = sd_netlink_message_close_container(m);
424 if (r < 0)
425 return log_error_errno(r, "Failed to close netlink container: %m");
426
427 r = sd_netlink_call(rtnl, m, 0, NULL);
428 if (r < 0)
429 return log_error_errno(r, "Failed to add new macvlan interfaces: %m");
430 }
431
432 return 0;
433}
434
435int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) {
436 _cleanup_udev_unref_ struct udev *udev = NULL;
437 _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
438 char **i;
439 int r;
440
441 if (strv_isempty(ifaces))
442 return 0;
443
444 r = sd_netlink_open(&rtnl);
445 if (r < 0)
446 return log_error_errno(r, "Failed to connect to netlink: %m");
447
448 udev = udev_new();
449 if (!udev) {
450 log_error("Failed to connect to udev.");
451 return -ENOMEM;
452 }
453
454 STRV_FOREACH(i, ifaces) {
455 _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
456 _cleanup_free_ char *n = NULL;
457 int ifi;
458
459 ifi = parse_interface(udev, *i);
460 if (ifi < 0)
461 return ifi;
462
463 r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
464 if (r < 0)
465 return log_error_errno(r, "Failed to allocate netlink message: %m");
466
467 r = sd_netlink_message_append_u32(m, IFLA_LINK, ifi);
468 if (r < 0)
469 return log_error_errno(r, "Failed to add netlink interface index: %m");
470
471 n = strappend("iv-", *i);
472 if (!n)
473 return log_oom();
474
475 strshorten(n, IFNAMSIZ-1);
476
477 r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
478 if (r < 0)
479 return log_error_errno(r, "Failed to add netlink interface name: %m");
480
481 r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
482 if (r < 0)
483 return log_error_errno(r, "Failed to add netlink namespace field: %m");
484
485 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
486 if (r < 0)
487 return log_error_errno(r, "Failed to open netlink container: %m");
488
489 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "ipvlan");
490 if (r < 0)
491 return log_error_errno(r, "Failed to open netlink container: %m");
492
493 r = sd_netlink_message_append_u16(m, IFLA_IPVLAN_MODE, IPVLAN_MODE_L2);
494 if (r < 0)
495 return log_error_errno(r, "Failed to add ipvlan mode: %m");
496
497 r = sd_netlink_message_close_container(m);
498 if (r < 0)
499 return log_error_errno(r, "Failed to close netlink container: %m");
500
501 r = sd_netlink_message_close_container(m);
502 if (r < 0)
503 return log_error_errno(r, "Failed to close netlink container: %m");
504
505 r = sd_netlink_call(rtnl, m, 0, NULL);
506 if (r < 0)
507 return log_error_errno(r, "Failed to add new ipvlan interfaces: %m");
508 }
509
510 return 0;
511}
f6d6bad1
LP
512
513int veth_extra_parse(char ***l, const char *p) {
514 _cleanup_free_ char *a = NULL, *b = NULL;
515 int r;
516
517 r = extract_first_word(&p, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
518 if (r < 0)
519 return r;
520 if (r == 0 || isempty(a))
521 return -EINVAL;
522
523 r = extract_first_word(&p, &b, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
524 if (r < 0)
525 return r;
526 if (r == 0 || isempty(b)) {
527 free(b);
528 b = strdup(a);
529 if (!b)
530 return -ENOMEM;
531 }
532
533 if (p)
534 return -EINVAL;
535
536 r = strv_push_pair(l, a, b);
537 if (r < 0)
538 return -ENOMEM;
539
540 a = b = NULL;
541 return 0;
542}