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