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