]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/nspawn/nspawn-network.c
util-lib: split out allocation calls into alloc-util.[ch]
[thirdparty/systemd.git] / src / nspawn / nspawn-network.c
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
25 #include "libudev.h"
26 #include "sd-id128.h"
27 #include "sd-netlink.h"
28
29 #include "alloc-util.h"
30 #include "ether-addr-util.h"
31 #include "netlink-util.h"
32 #include "siphash24.h"
33 #include "string-util.h"
34 #include "udev-util.h"
35 #include "util.h"
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)
40 #define MACVLAN_HASH_KEY SD_ID128_MAKE(00,13,6d,bc,66,83,44,81,bb,0c,f9,51,1f,24,a6,6f)
41
42 static int generate_mac(
43 const char *machine_name,
44 struct ether_addr *mac,
45 sd_id128_t hash_key,
46 uint64_t idx) {
47
48 uint8_t result[8];
49 size_t l, sz;
50 uint8_t *v, *i;
51 int r;
52
53 l = strlen(machine_name);
54 sz = sizeof(sd_id128_t) + l;
55 if (idx > 0)
56 sz += sizeof(idx);
57
58 v = alloca(sz);
59
60 /* fetch some persistent data unique to the host */
61 r = sd_id128_get_machine((sd_id128_t*) v);
62 if (r < 0)
63 return r;
64
65 /* combine with some data unique (on this host) to this
66 * container instance */
67 i = mempcpy(v + sizeof(sd_id128_t), machine_name, l);
68 if (idx > 0) {
69 idx = htole64(idx);
70 memcpy(i, &idx, sizeof(idx));
71 }
72
73 /* Let's hash the host machine ID plus the container name. We
74 * use a fixed, but originally randomly created hash key here. */
75 siphash24(result, v, sz, hash_key.bytes);
76
77 assert_cc(ETH_ALEN <= sizeof(result));
78 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
79
80 /* see eth_random_addr in the kernel */
81 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
82 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
83
84 return 0;
85 }
86
87 int setup_veth(const char *machine_name,
88 pid_t pid,
89 char iface_name[IFNAMSIZ],
90 bool bridge) {
91
92 _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
93 _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
94 struct ether_addr mac_host, mac_container;
95 int r, i;
96
97 /* Use two different interface name prefixes depending whether
98 * we are in bridge mode or not. */
99 snprintf(iface_name, IFNAMSIZ - 1, "%s-%s",
100 bridge ? "vb" : "ve", machine_name);
101
102 r = generate_mac(machine_name, &mac_container, CONTAINER_HASH_KEY, 0);
103 if (r < 0)
104 return log_error_errno(r, "Failed to generate predictable MAC address for container side: %m");
105
106 r = generate_mac(machine_name, &mac_host, HOST_HASH_KEY, 0);
107 if (r < 0)
108 return log_error_errno(r, "Failed to generate predictable MAC address for host side: %m");
109
110 r = sd_netlink_open(&rtnl);
111 if (r < 0)
112 return log_error_errno(r, "Failed to connect to netlink: %m");
113
114 r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
115 if (r < 0)
116 return log_error_errno(r, "Failed to allocate netlink message: %m");
117
118 r = sd_netlink_message_append_string(m, IFLA_IFNAME, iface_name);
119 if (r < 0)
120 return log_error_errno(r, "Failed to add netlink interface name: %m");
121
122 r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, &mac_host);
123 if (r < 0)
124 return log_error_errno(r, "Failed to add netlink MAC address: %m");
125
126 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
127 if (r < 0)
128 return log_error_errno(r, "Failed to open netlink container: %m");
129
130 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "veth");
131 if (r < 0)
132 return log_error_errno(r, "Failed to open netlink container: %m");
133
134 r = sd_netlink_message_open_container(m, VETH_INFO_PEER);
135 if (r < 0)
136 return log_error_errno(r, "Failed to open netlink container: %m");
137
138 r = sd_netlink_message_append_string(m, IFLA_IFNAME, "host0");
139 if (r < 0)
140 return log_error_errno(r, "Failed to add netlink interface name: %m");
141
142 r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, &mac_container);
143 if (r < 0)
144 return log_error_errno(r, "Failed to add netlink MAC address: %m");
145
146 r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
147 if (r < 0)
148 return log_error_errno(r, "Failed to add netlink namespace field: %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_message_close_container(m);
155 if (r < 0)
156 return log_error_errno(r, "Failed to close netlink container: %m");
157
158 r = sd_netlink_message_close_container(m);
159 if (r < 0)
160 return log_error_errno(r, "Failed to close netlink container: %m");
161
162 r = sd_netlink_call(rtnl, m, 0, NULL);
163 if (r < 0)
164 return log_error_errno(r, "Failed to add new veth interfaces (host0, %s): %m", iface_name);
165
166 i = (int) if_nametoindex(iface_name);
167 if (i <= 0)
168 return log_error_errno(errno, "Failed to resolve interface %s: %m", iface_name);
169
170 return i;
171 }
172
173 int setup_bridge(const char *veth_name, const char *bridge_name) {
174 _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
175 _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
176 int r, bridge_ifi;
177
178 assert(veth_name);
179 assert(bridge_name);
180
181 bridge_ifi = (int) if_nametoindex(bridge_name);
182 if (bridge_ifi <= 0)
183 return log_error_errno(errno, "Failed to resolve interface %s: %m", bridge_name);
184
185 r = sd_netlink_open(&rtnl);
186 if (r < 0)
187 return log_error_errno(r, "Failed to connect to netlink: %m");
188
189 r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, 0);
190 if (r < 0)
191 return log_error_errno(r, "Failed to allocate netlink message: %m");
192
193 r = sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP);
194 if (r < 0)
195 return log_error_errno(r, "Failed to set IFF_UP flag: %m");
196
197 r = sd_netlink_message_append_string(m, IFLA_IFNAME, veth_name);
198 if (r < 0)
199 return log_error_errno(r, "Failed to add netlink interface name field: %m");
200
201 r = sd_netlink_message_append_u32(m, IFLA_MASTER, bridge_ifi);
202 if (r < 0)
203 return log_error_errno(r, "Failed to add netlink master field: %m");
204
205 r = sd_netlink_call(rtnl, m, 0, NULL);
206 if (r < 0)
207 return log_error_errno(r, "Failed to add veth interface to bridge: %m");
208
209 return bridge_ifi;
210 }
211
212 static int parse_interface(struct udev *udev, const char *name) {
213 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
214 char ifi_str[2 + DECIMAL_STR_MAX(int)];
215 int ifi;
216
217 ifi = (int) if_nametoindex(name);
218 if (ifi <= 0)
219 return log_error_errno(errno, "Failed to resolve interface %s: %m", name);
220
221 sprintf(ifi_str, "n%i", ifi);
222 d = udev_device_new_from_device_id(udev, ifi_str);
223 if (!d)
224 return log_error_errno(errno, "Failed to get udev device for interface %s: %m", name);
225
226 if (udev_device_get_is_initialized(d) <= 0) {
227 log_error("Network interface %s is not initialized yet.", name);
228 return -EBUSY;
229 }
230
231 return ifi;
232 }
233
234 int move_network_interfaces(pid_t pid, char **ifaces) {
235 _cleanup_udev_unref_ struct udev *udev = NULL;
236 _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
237 char **i;
238 int r;
239
240 if (strv_isempty(ifaces))
241 return 0;
242
243 r = sd_netlink_open(&rtnl);
244 if (r < 0)
245 return log_error_errno(r, "Failed to connect to netlink: %m");
246
247 udev = udev_new();
248 if (!udev) {
249 log_error("Failed to connect to udev.");
250 return -ENOMEM;
251 }
252
253 STRV_FOREACH(i, ifaces) {
254 _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
255 int ifi;
256
257 ifi = parse_interface(udev, *i);
258 if (ifi < 0)
259 return ifi;
260
261 r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, ifi);
262 if (r < 0)
263 return log_error_errno(r, "Failed to allocate netlink message: %m");
264
265 r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
266 if (r < 0)
267 return log_error_errno(r, "Failed to append namespace PID to netlink message: %m");
268
269 r = sd_netlink_call(rtnl, m, 0, NULL);
270 if (r < 0)
271 return log_error_errno(r, "Failed to move interface %s to namespace: %m", *i);
272 }
273
274 return 0;
275 }
276
277 int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) {
278 _cleanup_udev_unref_ struct udev *udev = NULL;
279 _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
280 unsigned idx = 0;
281 char **i;
282 int r;
283
284 if (strv_isempty(ifaces))
285 return 0;
286
287 r = sd_netlink_open(&rtnl);
288 if (r < 0)
289 return log_error_errno(r, "Failed to connect to netlink: %m");
290
291 udev = udev_new();
292 if (!udev) {
293 log_error("Failed to connect to udev.");
294 return -ENOMEM;
295 }
296
297 STRV_FOREACH(i, ifaces) {
298 _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
299 _cleanup_free_ char *n = NULL;
300 struct ether_addr mac;
301 int ifi;
302
303 ifi = parse_interface(udev, *i);
304 if (ifi < 0)
305 return ifi;
306
307 r = generate_mac(machine_name, &mac, MACVLAN_HASH_KEY, idx++);
308 if (r < 0)
309 return log_error_errno(r, "Failed to create MACVLAN MAC address: %m");
310
311 r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
312 if (r < 0)
313 return log_error_errno(r, "Failed to allocate netlink message: %m");
314
315 r = sd_netlink_message_append_u32(m, IFLA_LINK, ifi);
316 if (r < 0)
317 return log_error_errno(r, "Failed to add netlink interface index: %m");
318
319 n = strappend("mv-", *i);
320 if (!n)
321 return log_oom();
322
323 strshorten(n, IFNAMSIZ-1);
324
325 r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
326 if (r < 0)
327 return log_error_errno(r, "Failed to add netlink interface name: %m");
328
329 r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, &mac);
330 if (r < 0)
331 return log_error_errno(r, "Failed to add netlink MAC address: %m");
332
333 r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
334 if (r < 0)
335 return log_error_errno(r, "Failed to add netlink namespace field: %m");
336
337 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
338 if (r < 0)
339 return log_error_errno(r, "Failed to open netlink container: %m");
340
341 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "macvlan");
342 if (r < 0)
343 return log_error_errno(r, "Failed to open netlink container: %m");
344
345 r = sd_netlink_message_append_u32(m, IFLA_MACVLAN_MODE, MACVLAN_MODE_BRIDGE);
346 if (r < 0)
347 return log_error_errno(r, "Failed to append macvlan mode: %m");
348
349 r = sd_netlink_message_close_container(m);
350 if (r < 0)
351 return log_error_errno(r, "Failed to close netlink container: %m");
352
353 r = sd_netlink_message_close_container(m);
354 if (r < 0)
355 return log_error_errno(r, "Failed to close netlink container: %m");
356
357 r = sd_netlink_call(rtnl, m, 0, NULL);
358 if (r < 0)
359 return log_error_errno(r, "Failed to add new macvlan interfaces: %m");
360 }
361
362 return 0;
363 }
364
365 int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) {
366 _cleanup_udev_unref_ struct udev *udev = NULL;
367 _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
368 char **i;
369 int r;
370
371 if (strv_isempty(ifaces))
372 return 0;
373
374 r = sd_netlink_open(&rtnl);
375 if (r < 0)
376 return log_error_errno(r, "Failed to connect to netlink: %m");
377
378 udev = udev_new();
379 if (!udev) {
380 log_error("Failed to connect to udev.");
381 return -ENOMEM;
382 }
383
384 STRV_FOREACH(i, ifaces) {
385 _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
386 _cleanup_free_ char *n = NULL;
387 int ifi;
388
389 ifi = parse_interface(udev, *i);
390 if (ifi < 0)
391 return ifi;
392
393 r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
394 if (r < 0)
395 return log_error_errno(r, "Failed to allocate netlink message: %m");
396
397 r = sd_netlink_message_append_u32(m, IFLA_LINK, ifi);
398 if (r < 0)
399 return log_error_errno(r, "Failed to add netlink interface index: %m");
400
401 n = strappend("iv-", *i);
402 if (!n)
403 return log_oom();
404
405 strshorten(n, IFNAMSIZ-1);
406
407 r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
408 if (r < 0)
409 return log_error_errno(r, "Failed to add netlink interface name: %m");
410
411 r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
412 if (r < 0)
413 return log_error_errno(r, "Failed to add netlink namespace field: %m");
414
415 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
416 if (r < 0)
417 return log_error_errno(r, "Failed to open netlink container: %m");
418
419 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "ipvlan");
420 if (r < 0)
421 return log_error_errno(r, "Failed to open netlink container: %m");
422
423 r = sd_netlink_message_append_u16(m, IFLA_IPVLAN_MODE, IPVLAN_MODE_L2);
424 if (r < 0)
425 return log_error_errno(r, "Failed to add ipvlan mode: %m");
426
427 r = sd_netlink_message_close_container(m);
428 if (r < 0)
429 return log_error_errno(r, "Failed to close netlink container: %m");
430
431 r = sd_netlink_message_close_container(m);
432 if (r < 0)
433 return log_error_errno(r, "Failed to close netlink container: %m");
434
435 r = sd_netlink_call(rtnl, m, 0, NULL);
436 if (r < 0)
437 return log_error_errno(r, "Failed to add new ipvlan interfaces: %m");
438 }
439
440 return 0;
441 }