]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-link.c
networkd: add basic VLAN support
[thirdparty/systemd.git] / src / network / networkd-link.c
CommitLineData
f579559b
TG
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
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 <netinet/ether.h>
23#include <linux/if.h>
24
25#include "networkd.h"
26#include "libudev-private.h"
27#include "util.h"
1346b1f0 28#include "bus-util.h"
f579559b
TG
29
30int link_new(Manager *manager, struct udev_device *device, Link **ret) {
31 _cleanup_link_free_ Link *link = NULL;
8cd11a0f 32 const char *mac;
602cc437 33 struct ether_addr *mac_addr;
c166a070 34 const char *ifname;
f579559b
TG
35 int r;
36
37 assert(device);
38 assert(ret);
39
40 link = new0(Link, 1);
41 if (!link)
42 return -ENOMEM;
43
5a3eb5a7
TG
44 link->manager = manager;
45 link->state = _LINK_STATE_INVALID;
46
0617ffab
TG
47 link->ifindex = udev_device_get_ifindex(device);
48 if (link->ifindex <= 0)
f579559b
TG
49 return -EINVAL;
50
8cd11a0f 51 mac = udev_device_get_sysattr_value(device, "address");
5a3eb5a7
TG
52 if (mac) {
53 mac_addr = ether_aton(mac);
54 if (mac_addr)
55 memcpy(&link->mac, mac_addr, sizeof(struct ether_addr));
56 }
f579559b 57
c166a070
TG
58 ifname = udev_device_get_sysname(device);
59 link->ifname = strdup(ifname);
60
0617ffab 61 r = hashmap_put(manager->links, &link->ifindex, link);
f579559b
TG
62 if (r < 0)
63 return r;
64
65 *ret = link;
66 link = NULL;
67
68 return 0;
69}
70
71void link_free(Link *link) {
72 if (!link)
73 return;
74
0617ffab 75 assert(link->manager);
f579559b 76
f5be5601
TG
77 if (link->dhcp)
78 sd_dhcp_client_free(link->dhcp);
79
80 route_free(link->dhcp_route);
81 link->dhcp_route = NULL;
82
83 address_free(link->dhcp_address);
84 link->dhcp_address = NULL;
85
0617ffab 86 hashmap_remove(link->manager->links, &link->ifindex);
f579559b 87
c166a070
TG
88 free(link->ifname);
89
f579559b
TG
90 free(link);
91}
92
aa3437a5 93int link_add(Manager *m, struct udev_device *device, Link **ret) {
f579559b
TG
94 Link *link;
95 Network *network;
96 int r;
97 uint64_t ifindex;
52433f6b 98 NetdevKind kind;
f579559b
TG
99
100 assert(m);
101 assert(device);
102
103 ifindex = udev_device_get_ifindex(device);
104 link = hashmap_get(m->links, &ifindex);
aa3437a5
TG
105 if (link) {
106 *ret = link;
2672953b 107 return -EEXIST;
aa3437a5 108 }
f579559b
TG
109
110 r = link_new(m, device, &link);
2672953b 111 if (r < 0)
f579559b 112 return r;
f579559b 113
aa3437a5
TG
114 *ret = link;
115
52433f6b
TG
116 kind = netdev_kind_from_string(udev_device_get_devtype(device));
117 if (kind != _NETDEV_KIND_INVALID) {
118 r = netdev_set_link(m, kind, link);
aa3437a5
TG
119 if (r < 0 && r != -ENOENT)
120 return r;
02b59d57
TG
121 }
122
f579559b
TG
123 r = network_get(m, device, &network);
124 if (r < 0)
125 return r == -ENOENT ? 0 : r;
126
127 r = network_apply(m, network, link);
128 if (r < 0)
129 return r;
130
131 return 0;
132}
133
f882c247 134static int link_enter_configured(Link *link) {
ef1ba606
TG
135 assert(link);
136 assert(link->state == LINK_STATE_SETTING_ROUTES);
137
39032b87 138 log_info_link(link, "link configured");
f882c247
TG
139
140 link->state = LINK_STATE_CONFIGURED;
141
142 return 0;
143}
144
ef1ba606
TG
145static void link_enter_failed(Link *link) {
146 assert(link);
f882c247 147
39032b87 148 log_warning_link(link, "failed");
449f7554 149
ef1ba606 150 link->state = LINK_STATE_FAILED;
f882c247
TG
151}
152
f882c247
TG
153static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
154 Link *link = userdata;
155 int r;
156
f5be5601
TG
157 assert(link->route_messages > 0);
158 assert(link->state == LINK_STATE_SETTING_ADDRESSES ||
159 link->state == LINK_STATE_SETTING_ROUTES ||
160 link->state == LINK_STATE_FAILED);
f882c247 161
f5be5601 162 link->route_messages --;
f882c247
TG
163
164 if (link->state == LINK_STATE_FAILED)
165 return 1;
166
167 r = sd_rtnl_message_get_errno(m);
c166a070 168 if (r < 0 && r != -EEXIST)
3333d748 169 log_warning_link(link, "could not set route: %s", strerror(-r));
f882c247 170
f5be5601
TG
171 /* we might have received an old reply after moving back to SETTING_ADDRESSES,
172 * ignore it */
173 if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
39032b87 174 log_debug_link(link, "routes set");
dd3efc09
TG
175 link_enter_configured(link);
176 }
f882c247
TG
177
178 return 1;
179}
180
181static int link_enter_set_routes(Link *link) {
182 Route *route;
183 int r;
184
185 assert(link);
186 assert(link->network);
ef1ba606 187 assert(link->state == LINK_STATE_SETTING_ADDRESSES);
f882c247 188
ef1ba606 189 link->state = LINK_STATE_SETTING_ROUTES;
f882c247 190
f5be5601 191 if (!link->network->static_routes && !link->dhcp_route)
dd3efc09 192 return link_enter_configured(link);
f882c247 193
39032b87 194 log_debug_link(link, "setting routes");
449f7554 195
f048a16b 196 LIST_FOREACH(static_routes, route, link->network->static_routes) {
f882c247 197 r = route_configure(route, link, &route_handler);
dd3efc09 198 if (r < 0) {
3333d748
ZJS
199 log_warning_link(link,
200 "could not set routes: %s", strerror(-r));
ef1ba606
TG
201 link_enter_failed(link);
202 return r;
dd3efc09 203 }
c166a070 204
f5be5601
TG
205 link->route_messages ++;
206 }
207
208 if (link->dhcp_route) {
209 r = route_configure(link->dhcp_route, link, &route_handler);
210 if (r < 0) {
3333d748
ZJS
211 log_warning_link(link,
212 "could not set routes: %s", strerror(-r));
f5be5601
TG
213 link_enter_failed(link);
214 return r;
215 }
216
217 link->route_messages ++;
f882c247
TG
218 }
219
220 return 0;
221}
222
f882c247
TG
223static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
224 Link *link = userdata;
225 int r;
226
f5be5601
TG
227 assert(m);
228 assert(link);
229 assert(link->ifname);
230 assert(link->addr_messages > 0);
ef1ba606 231 assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
f882c247 232
f5be5601 233 link->addr_messages --;
f882c247
TG
234
235 if (link->state == LINK_STATE_FAILED)
236 return 1;
237
238 r = sd_rtnl_message_get_errno(m);
c166a070 239 if (r < 0 && r != -EEXIST)
3333d748
ZJS
240 log_struct_link(LOG_ERR, link,
241 "MESSAGE=%s: could not set address: %s",
242 link->ifname, strerror(-r),
243 "ERRNO=%d", -r,
244 NULL);
f882c247 245
f5be5601 246 if (link->addr_messages == 0) {
39032b87 247 log_debug_link(link, "addresses set");
ef1ba606 248 link_enter_set_routes(link);
dd3efc09 249 }
f882c247
TG
250
251 return 1;
252}
253
254static int link_enter_set_addresses(Link *link) {
255 Address *address;
256 int r;
257
258 assert(link);
259 assert(link->network);
f5be5601 260 assert(link->state != _LINK_STATE_INVALID);
f882c247 261
ef1ba606 262 link->state = LINK_STATE_SETTING_ADDRESSES;
f882c247 263
f5be5601 264 if (!link->network->static_addresses && !link->dhcp_address)
ef1ba606 265 return link_enter_set_routes(link);
f882c247 266
39032b87 267 log_debug_link(link, "setting addresses");
449f7554 268
f048a16b 269 LIST_FOREACH(static_addresses, address, link->network->static_addresses) {
f882c247 270 r = address_configure(address, link, &address_handler);
dd3efc09 271 if (r < 0) {
3333d748
ZJS
272 log_warning_link(link,
273 "could not set addresses: %s", strerror(-r));
ef1ba606
TG
274 link_enter_failed(link);
275 return r;
dd3efc09 276 }
c166a070 277
f5be5601
TG
278 link->addr_messages ++;
279 }
280
281 if (link->dhcp_address) {
282 r = address_configure(link->dhcp_address, link, &address_handler);
283 if (r < 0) {
3333d748
ZJS
284 log_warning_link(link,
285 "could not set addresses: %s", strerror(-r));
f5be5601
TG
286 link_enter_failed(link);
287 return r;
288 }
289
290 link->addr_messages ++;
f882c247
TG
291 }
292
293 return 0;
294}
295
ff254138
TG
296static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
297 Link *link = userdata;
298 int r;
299
300 assert(m);
301 assert(link);
302 assert(link->ifname);
303
304 if (link->state == LINK_STATE_FAILED)
305 return 1;
306
307 r = sd_rtnl_message_get_errno(m);
308 if (r < 0 && r != -EEXIST)
3333d748 309 log_warning_link(link, "could not drop address: %s", strerror(-r));
ff254138
TG
310
311 return 1;
312}
313
1346b1f0
TG
314static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
315 int r;
316
317 r = sd_bus_message_get_errno(m);
318 if (r < 0)
319 log_warning("Could not set hostname: %s", strerror(-r));
320
321 return 1;
322}
323
324static int set_hostname(sd_bus *bus, const char *hostname) {
325 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
326 int r = 0;
327
1346b1f0
TG
328 assert(hostname);
329
330 log_debug("Setting transient hostname: '%s'", hostname);
331
bcbca829
TG
332 if (!bus) { /* TODO: replace by assert when we can rely on kdbus */
333 log_info("Not connected to system bus, ignoring transient hostname.");
334 return 0;
335 }
336
1346b1f0
TG
337 r = sd_bus_message_new_method_call(
338 bus,
339 "org.freedesktop.hostname1",
340 "/org/freedesktop/hostname1",
341 "org.freedesktop.hostname1",
342 "SetHostname",
343 &m);
344 if (r < 0)
345 return r;
346
347 r = sd_bus_message_append(m, "sb", hostname, false);
348 if (r < 0)
349 return r;
350
351 r = sd_bus_call_async(bus, m, set_hostname_handler, NULL, 0, NULL);
352 if (r < 0)
353 log_error("Could not set transient hostname: %s", strerror(-r));
354
355 return r;
356}
357
4f882b2a
TG
358static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
359 Link *link = userdata;
360 int r;
361
362 assert(m);
363 assert(link);
364 assert(link->ifname);
365
366 if (link->state == LINK_STATE_FAILED)
367 return 1;
368
369 r = sd_rtnl_message_get_errno(m);
370 if (r < 0 && r != -EEXIST)
371 log_warning_link(link, "Could not set MTU: %s", strerror(-r));
372
373 return 1;
374}
375
376static int link_set_mtu(Link *link, uint32_t mtu) {
377 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
378 int r;
379
380 assert(link);
381 assert(link->manager);
382 assert(link->manager->rtnl);
383
384 log_debug_link(link, "setting MTU: %" PRIu32, mtu);
385
386 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
387 if (r < 0) {
388 log_error_link(link, "Could not allocate RTM_SETLINK message");
389 return r;
390 }
391
392 r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
393 if (r < 0) {
394 log_error_link(link, "Could not append MTU: %s", strerror(-r));
395 return r;
396 }
397
398 r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL);
399 if (r < 0) {
400 log_error_link(link,
401 "Could not send rtnetlink message: %s", strerror(-r));
402 return r;
403 }
404
405 return 0;
406}
407
ff254138
TG
408static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
409 Link *link = userdata;
410 struct in_addr address;
411 struct in_addr netmask;
412 struct in_addr gateway;
413 int prefixlen;
414 int r;
415
416 assert(link);
5be4d38e 417 assert(link->network);
1346b1f0 418 assert(link->manager);
ff254138
TG
419
420 if (link->state == LINK_STATE_FAILED)
421 return;
422
423 if (event < 0) {
3333d748 424 log_warning_link(link, "DHCP error: %s", strerror(-event));
ff254138
TG
425 link_enter_failed(link);
426 return;
427 }
428
429 if (event == DHCP_EVENT_NO_LEASE)
39032b87 430 log_debug_link(link, "IP address in use.");
ff254138
TG
431
432 if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_EXPIRED ||
433 event == DHCP_EVENT_STOP) {
434 if (link->dhcp_address) {
435 address_drop(link->dhcp_address, link, address_drop_handler);
436
437 address_free(link->dhcp_address);
438 link->dhcp_address = NULL;
439 }
440
441 if (link->dhcp_route) {
442 route_free(link->dhcp_route);
443 link->dhcp_route = NULL;
444 }
4f882b2a
TG
445
446 if (link->network->dhcp_mtu) {
447 uint16_t mtu;
448
449 r = sd_dhcp_client_get_mtu(client, &mtu);
450 if (r >= 0 && link->original_mtu != mtu) {
451 r = link_set_mtu(link, link->original_mtu);
452 if (r < 0) {
453 log_warning_link(link, "DHCP error: could not reset MTU");
454 link_enter_failed(link);
455 return;
456 }
457 }
458 }
1346b1f0
TG
459
460 if (link->network->dhcp_hostname) {
461 r = set_hostname(link->manager->bus, "");
462 if (r < 0)
463 log_error("Failed to reset transient hostname");
464 }
ff254138
TG
465 }
466
467 r = sd_dhcp_client_get_address(client, &address);
468 if (r < 0) {
39032b87 469 log_warning_link(link, "DHCP error: no address");
ff254138
TG
470 link_enter_failed(link);
471 return;
472 }
473
474 r = sd_dhcp_client_get_netmask(client, &netmask);
475 if (r < 0) {
39032b87 476 log_warning_link(link, "DHCP error: no netmask");
ff254138
TG
477 link_enter_failed(link);
478 return;
479 }
480
481 prefixlen = sd_dhcp_client_prefixlen(&netmask);
482 if (prefixlen < 0) {
39032b87 483 log_warning_link(link, "DHCP error: no prefixlen");
ff254138
TG
484 link_enter_failed(link);
485 return;
486 }
487
488 r = sd_dhcp_client_get_router(client, &gateway);
489 if (r < 0) {
39032b87 490 log_warning_link(link, "DHCP error: no router");
ff254138
TG
491 link_enter_failed(link);
492 return;
493 }
494
495 if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_IP_ACQUIRE) {
496 _cleanup_address_free_ Address *addr = NULL;
497 _cleanup_route_free_ Route *rt = NULL;
7ae4ef6d
TG
498 struct in_addr *nameservers;
499 size_t nameservers_size;
ff254138 500
62870613
ZJS
501 log_struct_link(LOG_INFO, link,
502 "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
503 link->ifname,
504 ADDRESS_FMT_VAL(address),
505 prefixlen,
506 ADDRESS_FMT_VAL(gateway),
507 "ADDRESS=%u.%u.%u.%u",
508 ADDRESS_FMT_VAL(address),
509 "PREFIXLEN=%u",
510 prefixlen,
511 "GATEWAY=%u.%u.%u.%u",
512 ADDRESS_FMT_VAL(gateway),
513 NULL);
ff254138
TG
514
515 r = address_new_dynamic(&addr);
516 if (r < 0) {
39032b87 517 log_error_link(link, "Could not allocate address");
ff254138
TG
518 link_enter_failed(link);
519 return;
520 }
521
522 addr->family = AF_INET;
523 addr->in_addr.in = address;
524 addr->prefixlen = prefixlen;
525 addr->netmask = netmask;
526
527 r = route_new_dynamic(&rt);
528 if (r < 0) {
39032b87 529 log_error_link(link, "Could not allocate route");
ff254138
TG
530 link_enter_failed(link);
531 return;
532 }
533
534 rt->family = AF_INET;
535 rt->in_addr.in = gateway;
536
537 link->dhcp_address = addr;
538 link->dhcp_route = rt;
539 addr = NULL;
540 rt = NULL;
541
5be4d38e 542 if (link->network->dhcp_dns) {
7ae4ef6d 543 r = sd_dhcp_client_get_dns(client, &nameservers, &nameservers_size);
5be4d38e
TG
544 if (r >= 0) {
545 r = manager_update_resolv_conf(link->manager);
546 if (r < 0)
547 log_error("Failed to update resolv.conf");
548 }
3bef724f
TG
549 }
550
4f882b2a
TG
551 if (link->network->dhcp_mtu) {
552 uint16_t mtu;
553
554 r = sd_dhcp_client_get_mtu(client, &mtu);
555 if (r >= 0) {
556 r = link_set_mtu(link, mtu);
557 if (r < 0)
558 log_error_link(link, "Failed to set MTU "
559 "to %" PRIu16, mtu);
560 }
561 }
562
1346b1f0
TG
563 if (link->network->dhcp_hostname) {
564 const char *hostname;
565
566 r = sd_dhcp_client_get_hostname(client, &hostname);
567 if (r >= 0) {
568 r = set_hostname(link->manager->bus, hostname);
569 if (r < 0)
570 log_error("Failed to set transient hostname "
571 "to '%s'", hostname);
572 }
573 }
574
ff254138
TG
575 link_enter_set_addresses(link);
576 }
577
578 return;
579}
580
581static int link_acquire_conf(Link *link) {
582 int r;
583
584 assert(link);
585 assert(link->network);
586 assert(link->network->dhcp);
587 assert(link->manager);
588 assert(link->manager->event);
589
590 if (!link->dhcp) {
b25ef18b
TG
591 r = sd_dhcp_client_new(&link->dhcp);
592 if (r < 0)
593 return r;
594
595 r = sd_dhcp_client_attach_event(link->dhcp, NULL, 0);
596 if (r < 0)
597 return r;
ff254138
TG
598
599 r = sd_dhcp_client_set_index(link->dhcp, link->ifindex);
600 if (r < 0)
601 return r;
602
603 r = sd_dhcp_client_set_mac(link->dhcp, &link->mac);
604 if (r < 0)
605 return r;
606
607 r = sd_dhcp_client_set_callback(link->dhcp, dhcp_handler, link);
608 if (r < 0)
609 return r;
6fc73498
TG
610
611 if (link->network->dhcp_mtu) {
612 r = sd_dhcp_client_set_request_option(link->dhcp, 26);
613 if (r < 0)
614 return r;
615 }
ff254138
TG
616 }
617
ab47d620
TG
618 log_debug_link(link, "acquiring DHCPv4 lease");
619
ff254138
TG
620 r = sd_dhcp_client_start(link->dhcp);
621 if (r < 0)
622 return r;
623
624 return 0;
625}
626
627static int link_update_flags(Link *link, unsigned flags) {
628 int r;
629
630 assert(link);
631 assert(link->network);
632
633 if (link->state == LINK_STATE_FAILED)
634 return 0;
635
efbc88b8 636 if (link->flags == flags) {
ab47d620 637 log_debug_link(link, "link status unchanged: %#.8x", flags);
efbc88b8
TG
638 return 0;
639 }
640
3333d748
ZJS
641 if ((link->flags & IFF_UP) != (flags & IFF_UP))
642 log_info_link(link,
e6674986 643 "link is %s", flags & IFF_UP ? "up": "down");
efbc88b8
TG
644
645 if ((link->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
646 if (flags & IFF_LOWER_UP) {
39032b87 647 log_info_link(link, "carrier on");
efbc88b8
TG
648
649 if (link->network->dhcp) {
650 r = link_acquire_conf(link);
651 if (r < 0) {
1f6d9bc9 652 log_warning_link(link, "Could not acquire DHCPv4 lease: %s", strerror(-r));
efbc88b8
TG
653 link_enter_failed(link);
654 return r;
655 }
ff254138 656 }
efbc88b8 657 } else {
39032b87 658 log_info_link(link, "carrier off");
efbc88b8
TG
659
660 if (link->network->dhcp) {
661 r = sd_dhcp_client_stop(link->dhcp);
662 if (r < 0) {
1f6d9bc9 663 log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r));
efbc88b8
TG
664 link_enter_failed(link);
665 return r;
666 }
ff254138
TG
667 }
668 }
669 }
670
3333d748 671 log_debug_link(link,
ab47d620 672 "link status updated: %#.8x -> %#.8x", link->flags, flags);
efbc88b8 673
ff254138
TG
674 link->flags = flags;
675
676 return 0;
677}
678
dd3efc09
TG
679static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
680 Link *link = userdata;
681 int r;
682
1746cf2a
TG
683 assert(link);
684
685 if (link->state == LINK_STATE_FAILED)
686 return 1;
687
dd3efc09
TG
688 r = sd_rtnl_message_get_errno(m);
689 if (r < 0) {
3333d748
ZJS
690 log_warning_link(link,
691 "could not bring up interface: %s", strerror(-r));
dd3efc09
TG
692 link_enter_failed(link);
693 }
f882c247 694
ff254138 695 link_update_flags(link, link->flags | IFF_UP);
1746cf2a 696
f882c247
TG
697 return 1;
698}
699
700static int link_up(Link *link) {
f579559b
TG
701 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
702 int r;
703
f882c247
TG
704 assert(link);
705 assert(link->manager);
706 assert(link->manager->rtnl);
707
39032b87 708 log_debug_link(link, "bringing link up");
449f7554 709
0f49a5f7 710 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
f579559b 711 if (r < 0) {
39032b87 712 log_error_link(link, "Could not allocate RTM_SETLINK message");
f579559b
TG
713 return r;
714 }
715
5d4795f3 716 r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
fc25d7f8 717 if (r < 0) {
3333d748 718 log_error_link(link, "Could not set link flags: %s", strerror(-r));
fc25d7f8
TG
719 return r;
720 }
721
dd3efc09 722 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
f579559b 723 if (r < 0) {
3333d748
ZJS
724 log_error_link(link,
725 "Could not send rtnetlink message: %s", strerror(-r));
f579559b
TG
726 return r;
727 }
728
f882c247
TG
729 return 0;
730}
731
52433f6b 732static int link_enslaved(Link *link) {
f882c247
TG
733 int r;
734
ef1ba606 735 assert(link);
52433f6b 736 assert(link->state == LINK_STATE_ENSLAVING);
f5be5601 737 assert(link->network);
dd3efc09 738
f882c247 739 r = link_up(link);
ef1ba606
TG
740 if (r < 0) {
741 link_enter_failed(link);
742 return r;
743 }
f882c247 744
1746cf2a
TG
745 if (!link->network->dhcp)
746 return link_enter_set_addresses(link);
ef1ba606
TG
747
748 return 0;
02b59d57
TG
749}
750
52433f6b 751static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
02b59d57
TG
752 Link *link = userdata;
753 int r;
754
1746cf2a 755 assert(link);
52433f6b 756 assert(link->state == LINK_STATE_ENSLAVING || link->state == LINK_STATE_FAILED);
ef1ba606 757 assert(link->network);
02b59d57 758
52433f6b
TG
759 link->enslaving --;
760
02b59d57
TG
761 if (link->state == LINK_STATE_FAILED)
762 return 1;
763
764 r = sd_rtnl_message_get_errno(m);
ef1ba606 765 if (r < 0) {
52433f6b
TG
766 log_error_link(link, "could not enslave: %s",
767 strerror(-r));
ef1ba606
TG
768 link_enter_failed(link);
769 return 1;
3333d748 770 }
02b59d57 771
52433f6b 772 log_debug_link(link, "enslaved");
ab47d620 773
52433f6b
TG
774 if (link->enslaving == 0)
775 link_enslaved(link);
02b59d57
TG
776
777 return 1;
778}
779
52433f6b 780static int link_enter_enslave(Link *link) {
02b59d57
TG
781 int r;
782
783 assert(link);
784 assert(link->network);
ef1ba606 785 assert(link->state == _LINK_STATE_INVALID);
02b59d57 786
52433f6b 787 link->state = LINK_STATE_ENSLAVING;
02b59d57 788
54abf461 789 if (!link->network->bridge && !link->network->bond && !link->network->vlan)
52433f6b 790 return link_enslaved(link);
02b59d57 791
52433f6b
TG
792 if (link->network->bridge) {
793 log_struct_link(LOG_DEBUG, link,
794 "MESSAGE=%s: enslaving by '%s'",
795 link->network->bridge->name,
796 NETDEV(link->network->bridge),
797 NULL);
449f7554 798
52433f6b
TG
799 r = netdev_enslave(link->network->bridge, link, &enslave_handler);
800 if (r < 0) {
801 log_struct_link(LOG_WARNING, link,
802 "MESSAGE=%s: could not enslave by '%s': %s",
803 link->network->bridge->name, strerror(-r),
804 NETDEV(link->network->bridge),
805 NULL);
806 link_enter_failed(link);
807 return r;
808 }
809
810 link->enslaving ++;
811 }
812
54abf461 813 if (link->network->vlan) {
52433f6b
TG
814 log_struct_link(LOG_DEBUG, link,
815 "MESSAGE=%s: enslaving by '%s'",
54abf461
TG
816 link->network->vlan->name,
817 NETDEV(link->network->vlan),
3333d748 818 NULL);
52433f6b 819
54abf461 820 r = netdev_enslave(link->network->vlan, link, &enslave_handler);
52433f6b
TG
821 if (r < 0) {
822 log_struct_link(LOG_WARNING, link,
823 "MESSAGE=%s: could not enslave by '%s': %s",
54abf461
TG
824 link->network->vlan->name, strerror(-r),
825 NETDEV(link->network->vlan),
52433f6b
TG
826 NULL);
827 link_enter_failed(link);
828 return r;
829 }
830
831 link->enslaving ++;
ef1ba606
TG
832 }
833
834 return 0;
835}
836
837static int link_get_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
838 Link *link = userdata;
839 int r;
840
1746cf2a
TG
841 assert(link);
842
843 if (link->state == LINK_STATE_FAILED)
844 return 1;
845
ef1ba606
TG
846 r = sd_rtnl_message_get_errno(m);
847 if (r < 0) {
3333d748 848 log_warning_link(link, "could not get state: %s", strerror(-r));
ef1ba606
TG
849 link_enter_failed(link);
850 }
851
39032b87 852 log_debug_link(link, "got link state");
1746cf2a 853
5eb036ca
TG
854 link_update(link, m);
855
ef1ba606
TG
856 return 1;
857}
858
859static int link_get(Link *link) {
860 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
861 int r;
862
863 assert(link);
864 assert(link->manager);
865 assert(link->manager->rtnl);
866
39032b87 867 log_debug_link(link, "requesting link status");
449f7554 868
ef1ba606
TG
869 r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
870 if (r < 0) {
39032b87 871 log_error_link(link, "Could not allocate RTM_GETLINK message");
ef1ba606
TG
872 return r;
873 }
874
875 r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
876 if (r < 0) {
3333d748
ZJS
877 log_error_link(link,
878 "Could not send rtnetlink message: %s", strerror(-r));
ef1ba606 879 return r;
dd3efc09 880 }
02b59d57
TG
881
882 return 0;
883}
884
885int link_configure(Link *link) {
886 int r;
887
ef1ba606
TG
888 assert(link);
889 assert(link->network);
890 assert(link->state == _LINK_STATE_INVALID);
891
dd3efc09 892 r = link_get(link);
ef1ba606
TG
893 if (r < 0) {
894 link_enter_failed(link);
895 return r;
896 }
dd3efc09 897
52433f6b 898 return link_enter_enslave(link);
f579559b 899}
dd3efc09 900
22936833
TG
901int link_update(Link *link, sd_rtnl_message *m) {
902 unsigned flags;
4f882b2a
TG
903 void *data;
904 uint16_t type;
22936833
TG
905 int r;
906
dd3efc09 907 assert(link);
22936833
TG
908 assert(m);
909
1746cf2a
TG
910 if (link->state == LINK_STATE_FAILED)
911 return 0;
912
22936833
TG
913 r = sd_rtnl_message_link_get_flags(m, &flags);
914 if (r < 0) {
4f882b2a 915 log_warning_link(link, "Could not get link flags");
22936833
TG
916 return r;
917 }
dd3efc09 918
4f882b2a 919 while (sd_rtnl_message_read(m, &type, &data) > 0) {
396945dc
TG
920 if (type == IFLA_MTU && link->network->dhcp &&
921 link->network->dhcp_mtu && !link->original_mtu) {
4f882b2a 922 link->original_mtu = *(uint16_t *) data;
396945dc
TG
923 log_debug_link(link, "saved original MTU: %" PRIu16,
924 link->original_mtu);
4f882b2a
TG
925 }
926 }
927
ff254138 928 return link_update_flags(link, flags);
dd3efc09 929}