]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/netdev/netdev.c
network: add NetDevVTable::generate_mac flag
[thirdparty/systemd.git] / src / network / netdev / netdev.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <net/if.h>
4 #include <netinet/in.h>
5
6 #include "alloc-util.h"
7 #include "conf-files.h"
8 #include "conf-parser.h"
9 #include "fd-util.h"
10 #include "list.h"
11 #include "netdev/bond.h"
12 #include "netdev/bridge.h"
13 #include "netdev/dummy.h"
14 #include "netdev/fou-tunnel.h"
15 #include "netdev/geneve.h"
16 #include "netdev/ipvlan.h"
17 #include "netdev/l2tp-tunnel.h"
18 #include "netdev/macsec.h"
19 #include "netdev/macvlan.h"
20 #include "netdev/netdev.h"
21 #include "netdev/netdevsim.h"
22 #include "netdev/tunnel.h"
23 #include "netdev/tuntap.h"
24 #include "netdev/vcan.h"
25 #include "netdev/veth.h"
26 #include "netdev/vlan.h"
27 #include "netdev/vrf.h"
28 #include "netdev/vxcan.h"
29 #include "netdev/vxlan.h"
30 #include "netdev/wireguard.h"
31 #include "netlink-util.h"
32 #include "network-internal.h"
33 #include "networkd-link.h"
34 #include "networkd-manager.h"
35 #include "siphash24.h"
36 #include "stat-util.h"
37 #include "string-table.h"
38 #include "string-util.h"
39 #include "strv.h"
40
41 const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
42 [NETDEV_KIND_BRIDGE] = &bridge_vtable,
43 [NETDEV_KIND_BOND] = &bond_vtable,
44 [NETDEV_KIND_VLAN] = &vlan_vtable,
45 [NETDEV_KIND_MACVLAN] = &macvlan_vtable,
46 [NETDEV_KIND_MACVTAP] = &macvtap_vtable,
47 [NETDEV_KIND_IPVLAN] = &ipvlan_vtable,
48 [NETDEV_KIND_IPVTAP] = &ipvtap_vtable,
49 [NETDEV_KIND_VXLAN] = &vxlan_vtable,
50 [NETDEV_KIND_IPIP] = &ipip_vtable,
51 [NETDEV_KIND_GRE] = &gre_vtable,
52 [NETDEV_KIND_GRETAP] = &gretap_vtable,
53 [NETDEV_KIND_IP6GRE] = &ip6gre_vtable,
54 [NETDEV_KIND_IP6GRETAP] = &ip6gretap_vtable,
55 [NETDEV_KIND_SIT] = &sit_vtable,
56 [NETDEV_KIND_VTI] = &vti_vtable,
57 [NETDEV_KIND_VTI6] = &vti6_vtable,
58 [NETDEV_KIND_VETH] = &veth_vtable,
59 [NETDEV_KIND_DUMMY] = &dummy_vtable,
60 [NETDEV_KIND_TUN] = &tun_vtable,
61 [NETDEV_KIND_TAP] = &tap_vtable,
62 [NETDEV_KIND_IP6TNL] = &ip6tnl_vtable,
63 [NETDEV_KIND_VRF] = &vrf_vtable,
64 [NETDEV_KIND_VCAN] = &vcan_vtable,
65 [NETDEV_KIND_GENEVE] = &geneve_vtable,
66 [NETDEV_KIND_VXCAN] = &vxcan_vtable,
67 [NETDEV_KIND_WIREGUARD] = &wireguard_vtable,
68 [NETDEV_KIND_NETDEVSIM] = &netdevsim_vtable,
69 [NETDEV_KIND_FOU] = &foutnl_vtable,
70 [NETDEV_KIND_ERSPAN] = &erspan_vtable,
71 [NETDEV_KIND_L2TP] = &l2tptnl_vtable,
72 [NETDEV_KIND_MACSEC] = &macsec_vtable,
73 };
74
75 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
76 [NETDEV_KIND_BRIDGE] = "bridge",
77 [NETDEV_KIND_BOND] = "bond",
78 [NETDEV_KIND_VLAN] = "vlan",
79 [NETDEV_KIND_MACVLAN] = "macvlan",
80 [NETDEV_KIND_MACVTAP] = "macvtap",
81 [NETDEV_KIND_IPVLAN] = "ipvlan",
82 [NETDEV_KIND_IPVTAP] = "ipvtap",
83 [NETDEV_KIND_VXLAN] = "vxlan",
84 [NETDEV_KIND_IPIP] = "ipip",
85 [NETDEV_KIND_GRE] = "gre",
86 [NETDEV_KIND_GRETAP] = "gretap",
87 [NETDEV_KIND_IP6GRE] = "ip6gre",
88 [NETDEV_KIND_IP6GRETAP] = "ip6gretap",
89 [NETDEV_KIND_SIT] = "sit",
90 [NETDEV_KIND_VETH] = "veth",
91 [NETDEV_KIND_VTI] = "vti",
92 [NETDEV_KIND_VTI6] = "vti6",
93 [NETDEV_KIND_DUMMY] = "dummy",
94 [NETDEV_KIND_TUN] = "tun",
95 [NETDEV_KIND_TAP] = "tap",
96 [NETDEV_KIND_IP6TNL] = "ip6tnl",
97 [NETDEV_KIND_VRF] = "vrf",
98 [NETDEV_KIND_VCAN] = "vcan",
99 [NETDEV_KIND_GENEVE] = "geneve",
100 [NETDEV_KIND_VXCAN] = "vxcan",
101 [NETDEV_KIND_WIREGUARD] = "wireguard",
102 [NETDEV_KIND_NETDEVSIM] = "netdevsim",
103 [NETDEV_KIND_FOU] = "fou",
104 [NETDEV_KIND_ERSPAN] = "erspan",
105 [NETDEV_KIND_L2TP] = "l2tp",
106 [NETDEV_KIND_MACSEC] = "macsec",
107 };
108
109 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
110
111 int config_parse_netdev_kind(
112 const char *unit,
113 const char *filename,
114 unsigned line,
115 const char *section,
116 unsigned section_line,
117 const char *lvalue,
118 int ltype,
119 const char *rvalue,
120 void *data,
121 void *userdata) {
122
123 NetDevKind k, *kind = data;
124
125 assert(rvalue);
126 assert(data);
127
128 k = netdev_kind_from_string(rvalue);
129 if (k < 0) {
130 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse netdev kind, ignoring assignment: %s", rvalue);
131 return 0;
132 }
133
134 if (*kind != _NETDEV_KIND_INVALID && *kind != k) {
135 log_syntax(unit, LOG_ERR, filename, line, 0,
136 "Specified netdev kind is different from the previous value '%s', ignoring assignment: %s",
137 netdev_kind_to_string(*kind), rvalue);
138 return 0;
139 }
140
141 *kind = k;
142
143 return 0;
144 }
145
146 static void netdev_callbacks_clear(NetDev *netdev) {
147 netdev_join_callback *callback;
148
149 if (!netdev)
150 return;
151
152 while ((callback = netdev->callbacks)) {
153 LIST_REMOVE(callbacks, netdev->callbacks, callback);
154 link_unref(callback->link);
155 free(callback);
156 }
157 }
158
159 bool netdev_is_managed(NetDev *netdev) {
160 if (!netdev || !netdev->manager || !netdev->ifname)
161 return false;
162
163 return hashmap_get(netdev->manager->netdevs, netdev->ifname) == netdev;
164 }
165
166 static void netdev_detach_from_manager(NetDev *netdev) {
167 if (netdev->ifname && netdev->manager)
168 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
169 }
170
171 static NetDev *netdev_free(NetDev *netdev) {
172 assert(netdev);
173
174 netdev_callbacks_clear(netdev);
175
176 netdev_detach_from_manager(netdev);
177
178 free(netdev->filename);
179
180 free(netdev->description);
181 free(netdev->ifname);
182 free(netdev->mac);
183 condition_free_list(netdev->conditions);
184
185 /* Invoke the per-kind done() destructor, but only if the state field is initialized. We conditionalize that
186 * because we parse .netdev files twice: once to determine the kind (with a short, minimal NetDev structure
187 * allocation, with no room for per-kind fields), and once to read the kind's properties (with a full,
188 * comprehensive NetDev structure allocation with enough space for whatever the specific kind needs). Now, in
189 * the first case we shouldn't try to destruct the per-kind NetDev fields on destruction, in the second case we
190 * should. We use the state field to discern the two cases: it's _NETDEV_STATE_INVALID on the first "raw"
191 * call. */
192 if (netdev->state != _NETDEV_STATE_INVALID &&
193 NETDEV_VTABLE(netdev) &&
194 NETDEV_VTABLE(netdev)->done)
195 NETDEV_VTABLE(netdev)->done(netdev);
196
197 return mfree(netdev);
198 }
199
200 DEFINE_TRIVIAL_REF_UNREF_FUNC(NetDev, netdev, netdev_free);
201
202 void netdev_drop(NetDev *netdev) {
203 if (!netdev || netdev->state == NETDEV_STATE_LINGER)
204 return;
205
206 netdev->state = NETDEV_STATE_LINGER;
207
208 log_netdev_debug(netdev, "netdev removed");
209
210 netdev_callbacks_clear(netdev);
211
212 netdev_detach_from_manager(netdev);
213
214 netdev_unref(netdev);
215
216 return;
217 }
218
219 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
220 NetDev *netdev;
221
222 assert(manager);
223 assert(name);
224 assert(ret);
225
226 netdev = hashmap_get(manager->netdevs, name);
227 if (!netdev) {
228 *ret = NULL;
229 return -ENOENT;
230 }
231
232 *ret = netdev;
233
234 return 0;
235 }
236
237 static int netdev_enter_failed(NetDev *netdev) {
238 netdev->state = NETDEV_STATE_FAILED;
239
240 netdev_callbacks_clear(netdev);
241
242 return 0;
243 }
244
245 static int netdev_enslave_ready(NetDev *netdev, Link* link, link_netlink_message_handler_t callback) {
246 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
247 int r;
248
249 assert(netdev);
250 assert(netdev->state == NETDEV_STATE_READY);
251 assert(netdev->manager);
252 assert(netdev->manager->rtnl);
253 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND, NETDEV_KIND_VRF));
254 assert(link);
255 assert(callback);
256
257 if (link->flags & IFF_UP && netdev->kind == NETDEV_KIND_BOND) {
258 log_netdev_debug(netdev, "Link '%s' was up when attempting to enslave it. Bringing link down.", link->ifname);
259 r = link_down(link, NULL);
260 if (r < 0)
261 return log_netdev_error_errno(netdev, r, "Could not bring link down: %m");
262 }
263
264 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
265 if (r < 0)
266 return log_netdev_error_errno(netdev, r, "Could not allocate RTM_SETLINK message: %m");
267
268 r = sd_netlink_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
269 if (r < 0)
270 return log_netdev_error_errno(netdev, r, "Could not append IFLA_MASTER attribute: %m");
271
272 r = netlink_call_async(netdev->manager->rtnl, NULL, req, callback,
273 link_netlink_destroy_callback, link);
274 if (r < 0)
275 return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
276
277 link_ref(link);
278
279 log_netdev_debug(netdev, "Enslaving link '%s'", link->ifname);
280
281 return 0;
282 }
283
284 static int netdev_enter_ready(NetDev *netdev) {
285 netdev_join_callback *callback, *callback_next;
286 int r;
287
288 assert(netdev);
289 assert(netdev->ifname);
290
291 if (netdev->state != NETDEV_STATE_CREATING)
292 return 0;
293
294 netdev->state = NETDEV_STATE_READY;
295
296 log_netdev_info(netdev, "netdev ready");
297
298 LIST_FOREACH_SAFE(callbacks, callback, callback_next, netdev->callbacks) {
299 /* enslave the links that were attempted to be enslaved before the
300 * link was ready */
301 r = netdev_enslave_ready(netdev, callback->link, callback->callback);
302 if (r < 0)
303 return r;
304
305 LIST_REMOVE(callbacks, netdev->callbacks, callback);
306 link_unref(callback->link);
307 free(callback);
308 }
309
310 if (NETDEV_VTABLE(netdev)->post_create)
311 NETDEV_VTABLE(netdev)->post_create(netdev, NULL, NULL);
312
313 return 0;
314 }
315
316 /* callback for netdev's created without a backing Link */
317 static int netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev *netdev) {
318 int r;
319
320 assert(netdev);
321 assert(netdev->state != _NETDEV_STATE_INVALID);
322
323 r = sd_netlink_message_get_errno(m);
324 if (r == -EEXIST)
325 log_netdev_info(netdev, "netdev exists, using existing without changing its parameters");
326 else if (r < 0) {
327 log_netdev_warning_errno(netdev, r, "netdev could not be created: %m");
328 netdev_drop(netdev);
329
330 return 1;
331 }
332
333 log_netdev_debug(netdev, "Created");
334
335 return 1;
336 }
337
338 static int netdev_enslave(NetDev *netdev, Link *link, link_netlink_message_handler_t callback) {
339 int r;
340
341 assert(netdev);
342 assert(netdev->manager);
343 assert(netdev->manager->rtnl);
344 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND, NETDEV_KIND_VRF));
345
346 if (netdev->state == NETDEV_STATE_READY) {
347 r = netdev_enslave_ready(netdev, link, callback);
348 if (r < 0)
349 return r;
350 } else if (IN_SET(netdev->state, NETDEV_STATE_LINGER, NETDEV_STATE_FAILED)) {
351 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
352
353 r = rtnl_message_new_synthetic_error(netdev->manager->rtnl, -ENODEV, 0, &m);
354 if (r >= 0)
355 callback(netdev->manager->rtnl, m, link);
356 } else {
357 /* the netdev is not yet read, save this request for when it is */
358 netdev_join_callback *cb;
359
360 cb = new(netdev_join_callback, 1);
361 if (!cb)
362 return log_oom();
363
364 *cb = (netdev_join_callback) {
365 .callback = callback,
366 .link = link_ref(link),
367 };
368
369 LIST_PREPEND(callbacks, netdev->callbacks, cb);
370
371 log_netdev_debug(netdev, "Will enslave '%s', when ready", link->ifname);
372 }
373
374 return 0;
375 }
376
377 int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *message) {
378 uint16_t type;
379 const char *kind;
380 const char *received_kind;
381 const char *received_name;
382 int r, ifindex;
383
384 assert(netdev);
385 assert(message);
386
387 r = sd_netlink_message_get_type(message, &type);
388 if (r < 0)
389 return log_netdev_error_errno(netdev, r, "Could not get rtnl message type: %m");
390
391 if (type != RTM_NEWLINK) {
392 log_netdev_error(netdev, "Cannot set ifindex from unexpected rtnl message type.");
393 return -EINVAL;
394 }
395
396 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
397 if (r < 0) {
398 log_netdev_error_errno(netdev, r, "Could not get ifindex: %m");
399 netdev_enter_failed(netdev);
400 return r;
401 } else if (ifindex <= 0) {
402 log_netdev_error(netdev, "Got invalid ifindex: %d", ifindex);
403 netdev_enter_failed(netdev);
404 return -EINVAL;
405 }
406
407 if (netdev->ifindex > 0) {
408 if (netdev->ifindex != ifindex) {
409 log_netdev_error(netdev, "Could not set ifindex to %d, already set to %d",
410 ifindex, netdev->ifindex);
411 netdev_enter_failed(netdev);
412 return -EEXIST;
413 } else
414 /* ifindex already set to the same for this netdev */
415 return 0;
416 }
417
418 r = sd_netlink_message_read_string(message, IFLA_IFNAME, &received_name);
419 if (r < 0)
420 return log_netdev_error_errno(netdev, r, "Could not get IFNAME: %m");
421
422 if (!streq(netdev->ifname, received_name)) {
423 log_netdev_error(netdev, "Received newlink with wrong IFNAME %s", received_name);
424 netdev_enter_failed(netdev);
425 return r;
426 }
427
428 r = sd_netlink_message_enter_container(message, IFLA_LINKINFO);
429 if (r < 0)
430 return log_netdev_error_errno(netdev, r, "Could not get LINKINFO: %m");
431
432 r = sd_netlink_message_read_string(message, IFLA_INFO_KIND, &received_kind);
433 if (r < 0)
434 return log_netdev_error_errno(netdev, r, "Could not get KIND: %m");
435
436 r = sd_netlink_message_exit_container(message);
437 if (r < 0)
438 return log_netdev_error_errno(netdev, r, "Could not exit container: %m");
439
440 if (netdev->kind == NETDEV_KIND_TAP)
441 /* the kernel does not distinguish between tun and tap */
442 kind = "tun";
443 else {
444 kind = netdev_kind_to_string(netdev->kind);
445 if (!kind) {
446 log_netdev_error(netdev, "Could not get kind");
447 netdev_enter_failed(netdev);
448 return -EINVAL;
449 }
450 }
451
452 if (!streq(kind, received_kind)) {
453 log_netdev_error(netdev,
454 "Received newlink with wrong KIND %s, "
455 "expected %s", received_kind, kind);
456 netdev_enter_failed(netdev);
457 return r;
458 }
459
460 netdev->ifindex = ifindex;
461
462 log_netdev_debug(netdev, "netdev has index %d", netdev->ifindex);
463
464 netdev_enter_ready(netdev);
465
466 return 0;
467 }
468
469 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
470
471 int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
472 _cleanup_free_ struct ether_addr *mac = NULL;
473 uint64_t result;
474 size_t l, sz;
475 uint8_t *v;
476 int r;
477
478 assert(ifname);
479 assert(ret);
480
481 mac = new0(struct ether_addr, 1);
482 if (!mac)
483 return -ENOMEM;
484
485 l = strlen(ifname);
486 sz = sizeof(sd_id128_t) + l;
487 v = newa(uint8_t, sz);
488
489 /* fetch some persistent data unique to the machine */
490 r = sd_id128_get_machine((sd_id128_t*) v);
491 if (r < 0)
492 return r;
493
494 /* combine with some data unique (on this machine) to this
495 * netdev */
496 memcpy(v + sizeof(sd_id128_t), ifname, l);
497
498 /* Let's hash the host machine ID plus the container name. We
499 * use a fixed, but originally randomly created hash key here. */
500 result = siphash24(v, sz, HASH_KEY.bytes);
501
502 assert_cc(ETH_ALEN <= sizeof(result));
503 memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
504
505 /* see eth_random_addr in the kernel */
506 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
507 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
508
509 *ret = TAKE_PTR(mac);
510
511 return 0;
512 }
513
514 static int netdev_create(NetDev *netdev, Link *link, link_netlink_message_handler_t callback) {
515 int r;
516
517 assert(netdev);
518 assert(!link || callback);
519
520 /* create netdev */
521 if (NETDEV_VTABLE(netdev)->create) {
522 assert(!link);
523
524 r = NETDEV_VTABLE(netdev)->create(netdev);
525 if (r < 0)
526 return r;
527
528 log_netdev_debug(netdev, "Created");
529 } else {
530 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
531
532 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
533 if (r < 0)
534 return log_netdev_error_errno(netdev, r, "Could not allocate RTM_NEWLINK message: %m");
535
536 r = sd_netlink_message_append_string(m, IFLA_IFNAME, netdev->ifname);
537 if (r < 0)
538 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IFNAME, attribute: %m");
539
540 if (netdev->mac) {
541 r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
542 if (r < 0)
543 return log_netdev_error_errno(netdev, r, "Could not append IFLA_ADDRESS attribute: %m");
544 }
545
546 if (netdev->mtu) {
547 r = sd_netlink_message_append_u32(m, IFLA_MTU, netdev->mtu);
548 if (r < 0)
549 return log_netdev_error_errno(netdev, r, "Could not append IFLA_MTU attribute: %m");
550 }
551
552 if (link) {
553 r = sd_netlink_message_append_u32(m, IFLA_LINK, link->ifindex);
554 if (r < 0)
555 return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINK attribute: %m");
556 }
557
558 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
559 if (r < 0)
560 return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
561
562 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind));
563 if (r < 0)
564 return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
565
566 if (NETDEV_VTABLE(netdev)->fill_message_create) {
567 r = NETDEV_VTABLE(netdev)->fill_message_create(netdev, link, m);
568 if (r < 0)
569 return r;
570 }
571
572 r = sd_netlink_message_close_container(m);
573 if (r < 0)
574 return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
575
576 r = sd_netlink_message_close_container(m);
577 if (r < 0)
578 return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
579
580 if (link) {
581 r = netlink_call_async(netdev->manager->rtnl, NULL, m, callback,
582 link_netlink_destroy_callback, link);
583 if (r < 0)
584 return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
585
586 link_ref(link);
587 } else {
588 r = netlink_call_async(netdev->manager->rtnl, NULL, m, netdev_create_handler,
589 netdev_destroy_callback, netdev);
590 if (r < 0)
591 return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
592
593 netdev_ref(netdev);
594 }
595
596 netdev->state = NETDEV_STATE_CREATING;
597
598 log_netdev_debug(netdev, "Creating");
599 }
600
601 return 0;
602 }
603
604 static int netdev_create_after_configured(NetDev *netdev, Link *link) {
605 assert(netdev);
606 assert(link);
607 assert(NETDEV_VTABLE(netdev)->create_after_configured);
608
609 return NETDEV_VTABLE(netdev)->create_after_configured(netdev, link);
610 }
611
612 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
613 int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t callback) {
614 int r;
615
616 assert(netdev);
617 assert(netdev->manager);
618 assert(netdev->manager->rtnl);
619
620 switch (netdev_get_create_type(netdev)) {
621 case NETDEV_CREATE_MASTER:
622 r = netdev_enslave(netdev, link, callback);
623 if (r < 0)
624 return r;
625
626 break;
627 case NETDEV_CREATE_STACKED:
628 r = netdev_create(netdev, link, callback);
629 if (r < 0)
630 return r;
631
632 break;
633 case NETDEV_CREATE_AFTER_CONFIGURED:
634 r = netdev_create_after_configured(netdev, link);
635 if (r < 0)
636 return r;
637 break;
638 default:
639 assert_not_reached("Can not join independent netdev");
640 }
641
642 return 0;
643 }
644
645 int netdev_load_one(Manager *manager, const char *filename) {
646 _cleanup_(netdev_unrefp) NetDev *netdev_raw = NULL, *netdev = NULL;
647 _cleanup_fclose_ FILE *file = NULL;
648 const char *dropin_dirname;
649 bool independent = false;
650 int r;
651
652 assert(manager);
653 assert(filename);
654
655 file = fopen(filename, "re");
656 if (!file) {
657 if (errno == ENOENT)
658 return 0;
659
660 return -errno;
661 }
662
663 if (null_or_empty_fd(fileno(file))) {
664 log_debug("Skipping empty file: %s", filename);
665 return 0;
666 }
667
668 netdev_raw = new(NetDev, 1);
669 if (!netdev_raw)
670 return log_oom();
671
672 *netdev_raw = (NetDev) {
673 .n_ref = 1,
674 .kind = _NETDEV_KIND_INVALID,
675 .state = _NETDEV_STATE_INVALID, /* an invalid state means done() of the implementation won't be called on destruction */
676 };
677
678 dropin_dirname = strjoina(basename(filename), ".d");
679 r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
680 "Match\0NetDev\0",
681 config_item_perf_lookup, network_netdev_gperf_lookup,
682 CONFIG_PARSE_WARN|CONFIG_PARSE_RELAXED, netdev_raw);
683 if (r < 0)
684 return r;
685
686 /* skip out early if configuration does not match the environment */
687 if (!condition_test_list(netdev_raw->conditions, NULL, NULL, NULL)) {
688 log_debug("%s: Conditions in the file do not match the system environment, skipping.", filename);
689 return 0;
690 }
691
692 if (netdev_raw->kind == _NETDEV_KIND_INVALID) {
693 log_warning("NetDev has no Kind= configured in %s. Ignoring", filename);
694 return 0;
695 }
696
697 if (!netdev_raw->ifname) {
698 log_warning("NetDev without Name= configured in %s. Ignoring", filename);
699 return 0;
700 }
701
702 r = fseek(file, 0, SEEK_SET);
703 if (r < 0)
704 return -errno;
705
706 netdev = malloc0(NETDEV_VTABLE(netdev_raw)->object_size);
707 if (!netdev)
708 return log_oom();
709
710 netdev->n_ref = 1;
711 netdev->manager = manager;
712 netdev->kind = netdev_raw->kind;
713 netdev->state = NETDEV_STATE_LOADING; /* we initialize the state here for the first time,
714 so that done() will be called on destruction */
715
716 if (NETDEV_VTABLE(netdev)->init)
717 NETDEV_VTABLE(netdev)->init(netdev);
718
719 r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
720 NETDEV_VTABLE(netdev)->sections,
721 config_item_perf_lookup, network_netdev_gperf_lookup,
722 CONFIG_PARSE_WARN, netdev);
723 if (r < 0)
724 return r;
725
726 /* verify configuration */
727 if (NETDEV_VTABLE(netdev)->config_verify) {
728 r = NETDEV_VTABLE(netdev)->config_verify(netdev, filename);
729 if (r < 0)
730 return 0;
731 }
732
733 netdev->filename = strdup(filename);
734 if (!netdev->filename)
735 return log_oom();
736
737 if (!netdev->mac && NETDEV_VTABLE(netdev)->generate_mac) {
738 r = netdev_get_mac(netdev->ifname, &netdev->mac);
739 if (r < 0)
740 return log_netdev_error_errno(netdev, r,
741 "Failed to generate predictable MAC address for %s: %m",
742 netdev->ifname);
743 }
744
745 r = hashmap_ensure_allocated(&netdev->manager->netdevs, &string_hash_ops);
746 if (r < 0)
747 return r;
748
749 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
750 if (r == -EEXIST) {
751 NetDev *n = hashmap_get(netdev->manager->netdevs, netdev->ifname);
752
753 assert(n);
754 log_netdev_warning_errno(netdev, r,
755 "The setting Name=%s in %s conflicts with the one in %s, ignoring",
756 netdev->ifname, netdev->filename, n->filename);
757
758 /* Clear ifname before netdev_free() is called. Otherwise, the NetDev object 'n' is
759 * removed from the hashmap 'manager->netdevs'. */
760 netdev->ifname = mfree(netdev->ifname);
761 return 0;
762 }
763 if (r < 0)
764 return r;
765
766 LIST_HEAD_INIT(netdev->callbacks);
767
768 log_netdev_debug(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
769
770 if (IN_SET(netdev_get_create_type(netdev), NETDEV_CREATE_MASTER, NETDEV_CREATE_INDEPENDENT)) {
771 r = netdev_create(netdev, NULL, NULL);
772 if (r < 0)
773 return r;
774 }
775
776 switch (netdev->kind) {
777 case NETDEV_KIND_IPIP:
778 independent = IPIP(netdev)->independent;
779 break;
780 case NETDEV_KIND_GRE:
781 independent = GRE(netdev)->independent;
782 break;
783 case NETDEV_KIND_GRETAP:
784 independent = GRETAP(netdev)->independent;
785 break;
786 case NETDEV_KIND_IP6GRE:
787 independent = IP6GRE(netdev)->independent;
788 break;
789 case NETDEV_KIND_IP6GRETAP:
790 independent = IP6GRETAP(netdev)->independent;
791 break;
792 case NETDEV_KIND_SIT:
793 independent = SIT(netdev)->independent;
794 break;
795 case NETDEV_KIND_VTI:
796 independent = VTI(netdev)->independent;
797 break;
798 case NETDEV_KIND_VTI6:
799 independent = VTI6(netdev)->independent;
800 break;
801 case NETDEV_KIND_IP6TNL:
802 independent = IP6TNL(netdev)->independent;
803 break;
804 case NETDEV_KIND_ERSPAN:
805 independent = ERSPAN(netdev)->independent;
806 break;
807 default:
808 break;
809 }
810
811 if (independent) {
812 r = netdev_create(netdev, NULL, NULL);
813 if (r < 0)
814 return r;
815 }
816
817 netdev = NULL;
818
819 return 0;
820 }
821
822 int netdev_load(Manager *manager) {
823 _cleanup_strv_free_ char **files = NULL;
824 char **f;
825 int r;
826
827 assert(manager);
828
829 hashmap_clear_with_destructor(manager->netdevs, netdev_unref);
830
831 r = conf_files_list_strv(&files, ".netdev", NULL, 0, NETWORK_DIRS);
832 if (r < 0)
833 return log_error_errno(r, "Failed to enumerate netdev files: %m");
834
835 STRV_FOREACH(f, files) {
836 r = netdev_load_one(manager, *f);
837 if (r < 0)
838 return r;
839 }
840
841 return 0;
842 }