]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-link.c
udev/rules: setup tty permissions and group for sclp_line, ttysclp and 3270/tty
[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"
377a218f 29#include "net-util.h"
f579559b
TG
30
31int link_new(Manager *manager, struct udev_device *device, Link **ret) {
32 _cleanup_link_free_ Link *link = NULL;
8cd11a0f 33 const char *mac;
602cc437 34 struct ether_addr *mac_addr;
c166a070 35 const char *ifname;
f579559b
TG
36 int r;
37
0c2f9b84
TG
38 assert(manager);
39 assert(manager->links);
f579559b
TG
40 assert(device);
41 assert(ret);
42
43 link = new0(Link, 1);
44 if (!link)
45 return -ENOMEM;
46
5a3eb5a7
TG
47 link->manager = manager;
48 link->state = _LINK_STATE_INVALID;
49
0617ffab
TG
50 link->ifindex = udev_device_get_ifindex(device);
51 if (link->ifindex <= 0)
f579559b
TG
52 return -EINVAL;
53
8cd11a0f 54 mac = udev_device_get_sysattr_value(device, "address");
5a3eb5a7
TG
55 if (mac) {
56 mac_addr = ether_aton(mac);
57 if (mac_addr)
58 memcpy(&link->mac, mac_addr, sizeof(struct ether_addr));
59 }
f579559b 60
c166a070
TG
61 ifname = udev_device_get_sysname(device);
62 link->ifname = strdup(ifname);
63
0617ffab 64 r = hashmap_put(manager->links, &link->ifindex, link);
f579559b
TG
65 if (r < 0)
66 return r;
67
68 *ret = link;
69 link = NULL;
70
71 return 0;
72}
73
74void link_free(Link *link) {
75 if (!link)
76 return;
77
0617ffab 78 assert(link->manager);
f579559b 79
a6cc569e
TG
80 sd_dhcp_client_free(link->dhcp_client);
81 sd_dhcp_lease_unref(link->dhcp_lease);
f5be5601 82
0617ffab 83 hashmap_remove(link->manager->links, &link->ifindex);
f579559b 84
c166a070
TG
85 free(link->ifname);
86
f579559b
TG
87 free(link);
88}
89
11a7f229
TG
90int link_get(Manager *m, int ifindex, Link **ret) {
91 Link *link;
92 uint64_t ifindex_64;
93
94 assert(m);
95 assert(m->links);
96 assert(ifindex);
97 assert(ret);
98
99 ifindex_64 = ifindex;
100 link = hashmap_get(m->links, &ifindex_64);
101 if (!link)
102 return -ENODEV;
103
104 *ret = link;
105
106 return 0;
107}
108
aa3437a5 109int link_add(Manager *m, struct udev_device *device, Link **ret) {
39883f62 110 Link *link = NULL;
f579559b
TG
111 Network *network;
112 int r;
f579559b
TG
113
114 assert(m);
115 assert(device);
116
f579559b 117 r = link_new(m, device, &link);
2672953b 118 if (r < 0)
f579559b 119 return r;
f579559b 120
aa3437a5
TG
121 *ret = link;
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)
c9ccc19f
TG
169 log_struct_link(LOG_WARNING, link,
170 "MESSAGE=%s: could not set route: %s",
171 link->ifname, strerror(-r),
172 "ERRNO=%d", -r,
173 NULL);
f882c247 174
f5be5601
TG
175 /* we might have received an old reply after moving back to SETTING_ADDRESSES,
176 * ignore it */
177 if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
39032b87 178 log_debug_link(link, "routes set");
dd3efc09
TG
179 link_enter_configured(link);
180 }
f882c247
TG
181
182 return 1;
183}
184
185static int link_enter_set_routes(Link *link) {
a6cc569e 186 Route *rt;
f882c247
TG
187 int r;
188
189 assert(link);
190 assert(link->network);
ef1ba606 191 assert(link->state == LINK_STATE_SETTING_ADDRESSES);
f882c247 192
ef1ba606 193 link->state = LINK_STATE_SETTING_ROUTES;
f882c247 194
a6cc569e 195 if (!link->network->static_routes && !link->dhcp_lease)
dd3efc09 196 return link_enter_configured(link);
f882c247 197
39032b87 198 log_debug_link(link, "setting routes");
449f7554 199
a6cc569e
TG
200 LIST_FOREACH(static_routes, rt, link->network->static_routes) {
201 r = route_configure(rt, link, &route_handler);
dd3efc09 202 if (r < 0) {
3333d748
ZJS
203 log_warning_link(link,
204 "could not set routes: %s", strerror(-r));
ef1ba606
TG
205 link_enter_failed(link);
206 return r;
dd3efc09 207 }
c166a070 208
f5be5601
TG
209 link->route_messages ++;
210 }
211
a6cc569e
TG
212 if (link->dhcp_lease) {
213 _cleanup_route_free_ Route *route = NULL;
214 struct in_addr gateway;
215
216 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
217 if (r < 0) {
218 log_warning_link(link, "DHCP error: no router: %s",
219 strerror(-r));
220 return r;
221 }
222
223 r = route_new_dynamic(&route);
224 if (r < 0) {
225 log_error_link(link, "Could not allocate route: %s",
226 strerror(-r));
227 return r;
228 }
229
230 route->family = AF_INET;
231 route->in_addr.in = gateway;
232
233 r = route_configure(route, link, &route_handler);
f5be5601 234 if (r < 0) {
3333d748
ZJS
235 log_warning_link(link,
236 "could not set routes: %s", strerror(-r));
f5be5601
TG
237 link_enter_failed(link);
238 return r;
239 }
240
241 link->route_messages ++;
f882c247
TG
242 }
243
244 return 0;
245}
246
f882c247
TG
247static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
248 Link *link = userdata;
249 int r;
250
f5be5601
TG
251 assert(m);
252 assert(link);
253 assert(link->ifname);
254 assert(link->addr_messages > 0);
ef1ba606 255 assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
f882c247 256
f5be5601 257 link->addr_messages --;
f882c247
TG
258
259 if (link->state == LINK_STATE_FAILED)
260 return 1;
261
262 r = sd_rtnl_message_get_errno(m);
c166a070 263 if (r < 0 && r != -EEXIST)
c9ccc19f 264 log_struct_link(LOG_WARNING, link,
3333d748
ZJS
265 "MESSAGE=%s: could not set address: %s",
266 link->ifname, strerror(-r),
267 "ERRNO=%d", -r,
268 NULL);
f882c247 269
f5be5601 270 if (link->addr_messages == 0) {
39032b87 271 log_debug_link(link, "addresses set");
ef1ba606 272 link_enter_set_routes(link);
dd3efc09 273 }
f882c247
TG
274
275 return 1;
276}
277
278static int link_enter_set_addresses(Link *link) {
a6cc569e 279 Address *ad;
f882c247
TG
280 int r;
281
282 assert(link);
283 assert(link->network);
f5be5601 284 assert(link->state != _LINK_STATE_INVALID);
f882c247 285
ef1ba606 286 link->state = LINK_STATE_SETTING_ADDRESSES;
f882c247 287
a6cc569e 288 if (!link->network->static_addresses && !link->dhcp_lease)
ef1ba606 289 return link_enter_set_routes(link);
f882c247 290
39032b87 291 log_debug_link(link, "setting addresses");
449f7554 292
a6cc569e
TG
293 LIST_FOREACH(static_addresses, ad, link->network->static_addresses) {
294 r = address_configure(ad, link, &address_handler);
dd3efc09 295 if (r < 0) {
3333d748
ZJS
296 log_warning_link(link,
297 "could not set addresses: %s", strerror(-r));
ef1ba606
TG
298 link_enter_failed(link);
299 return r;
dd3efc09 300 }
c166a070 301
f5be5601
TG
302 link->addr_messages ++;
303 }
304
a6cc569e
TG
305 if (link->dhcp_lease) {
306 _cleanup_address_free_ Address *address = NULL;
307 struct in_addr addr;
308 struct in_addr netmask;
309 unsigned prefixlen;
310
311 r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
312 if (r < 0) {
313 log_warning_link(link, "DHCP error: no address: %s",
314 strerror(-r));
315 return r;
316 }
317
318 r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
319 if (r < 0) {
320 log_warning_link(link, "DHCP error: no netmask: %s",
321 strerror(-r));
322 return r;
323 }
324
325 prefixlen = net_netmask_to_prefixlen(&netmask);
326
327 r = address_new_dynamic(&address);
328 if (r < 0) {
329 log_error_link(link, "Could not allocate address: %s",
330 strerror(-r));
331 return r;
332 }
333
334 address->family = AF_INET;
335 address->in_addr.in = addr;
336 address->prefixlen = prefixlen;
337 address->broadcast.s_addr = addr.s_addr | ~netmask.s_addr;
338
339 r = address_configure(address, link, &address_handler);
f5be5601 340 if (r < 0) {
3333d748
ZJS
341 log_warning_link(link,
342 "could not set addresses: %s", strerror(-r));
f5be5601
TG
343 link_enter_failed(link);
344 return r;
345 }
346
347 link->addr_messages ++;
f882c247
TG
348 }
349
350 return 0;
351}
352
ff254138
TG
353static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
354 Link *link = userdata;
355 int r;
356
357 assert(m);
358 assert(link);
359 assert(link->ifname);
360
361 if (link->state == LINK_STATE_FAILED)
362 return 1;
363
364 r = sd_rtnl_message_get_errno(m);
c9ccc19f
TG
365 if (r < 0 && r != -ENOENT)
366 log_struct_link(LOG_WARNING, link,
367 "MESSAGE=%s: could not drop address: %s",
368 link->ifname, strerror(-r),
369 "ERRNO=%d", -r,
370 NULL);
ff254138
TG
371
372 return 1;
373}
374
1346b1f0
TG
375static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
376 int r;
377
378 r = sd_bus_message_get_errno(m);
379 if (r < 0)
380 log_warning("Could not set hostname: %s", strerror(-r));
381
382 return 1;
383}
384
385static int set_hostname(sd_bus *bus, const char *hostname) {
386 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
387 int r = 0;
388
1346b1f0
TG
389 assert(hostname);
390
391 log_debug("Setting transient hostname: '%s'", hostname);
392
bcbca829
TG
393 if (!bus) { /* TODO: replace by assert when we can rely on kdbus */
394 log_info("Not connected to system bus, ignoring transient hostname.");
395 return 0;
396 }
397
1346b1f0
TG
398 r = sd_bus_message_new_method_call(
399 bus,
151b9b96 400 &m,
1346b1f0
TG
401 "org.freedesktop.hostname1",
402 "/org/freedesktop/hostname1",
403 "org.freedesktop.hostname1",
151b9b96 404 "SetHostname");
1346b1f0
TG
405 if (r < 0)
406 return r;
407
408 r = sd_bus_message_append(m, "sb", hostname, false);
409 if (r < 0)
410 return r;
411
412 r = sd_bus_call_async(bus, m, set_hostname_handler, NULL, 0, NULL);
413 if (r < 0)
414 log_error("Could not set transient hostname: %s", strerror(-r));
415
416 return r;
417}
418
4f882b2a
TG
419static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
420 Link *link = userdata;
421 int r;
422
423 assert(m);
424 assert(link);
425 assert(link->ifname);
426
427 if (link->state == LINK_STATE_FAILED)
428 return 1;
429
430 r = sd_rtnl_message_get_errno(m);
c9ccc19f
TG
431 if (r < 0)
432 log_struct_link(LOG_WARNING, link,
433 "MESSAGE=%s: could not set MTU: %s",
434 link->ifname, strerror(-r),
435 "ERRNO=%d", -r,
436 NULL);
4f882b2a
TG
437
438 return 1;
439}
440
441static int link_set_mtu(Link *link, uint32_t mtu) {
cf6a8911 442 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
4f882b2a
TG
443 int r;
444
445 assert(link);
446 assert(link->manager);
447 assert(link->manager->rtnl);
448
449 log_debug_link(link, "setting MTU: %" PRIu32, mtu);
450
151b9b96
LP
451 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
452 RTM_SETLINK, link->ifindex);
4f882b2a
TG
453 if (r < 0) {
454 log_error_link(link, "Could not allocate RTM_SETLINK message");
455 return r;
456 }
457
458 r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
459 if (r < 0) {
460 log_error_link(link, "Could not append MTU: %s", strerror(-r));
461 return r;
462 }
463
464 r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL);
465 if (r < 0) {
466 log_error_link(link,
467 "Could not send rtnetlink message: %s", strerror(-r));
468 return r;
469 }
470
471 return 0;
472}
473
a6cc569e
TG
474static int dhcp_lease_lost(Link *link) {
475 _cleanup_address_free_ Address *address = NULL;
476 struct in_addr addr;
477 struct in_addr netmask;
478 unsigned prefixlen;
ff254138
TG
479 int r;
480
481 assert(link);
a6cc569e 482 assert(link->dhcp_lease);
ff254138 483
14efd761
TG
484 log_warning_link(link, "DHCP lease lost");
485
a6cc569e
TG
486 r = address_new_dynamic(&address);
487 if (r >= 0) {
488 sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
489 sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
490 prefixlen = net_netmask_to_prefixlen(&netmask);
ff254138 491
a6cc569e
TG
492 address->family = AF_INET;
493 address->in_addr.in = addr;
494 address->prefixlen = prefixlen;
ff254138 495
a6cc569e 496 address_drop(address, link, address_drop_handler);
c07aeadf 497 }
eb27aeca 498
c07aeadf
TG
499 if (link->network->dhcp_mtu) {
500 uint16_t mtu;
ff254138 501
a6cc569e 502 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
c07aeadf
TG
503 if (r >= 0 && link->original_mtu != mtu) {
504 r = link_set_mtu(link, link->original_mtu);
505 if (r < 0) {
506 log_warning_link(link, "DHCP error: could not reset MTU");
507 link_enter_failed(link);
508 return r;
509 }
ff254138 510 }
c07aeadf 511 }
ff254138 512
c07aeadf 513 if (link->network->dhcp_hostname) {
216816c6
TG
514 const char *hostname = NULL;
515
516 r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
517 if (r >= 0 && hostname) {
518 r = set_hostname(link->manager->bus, "");
519 if (r < 0)
520 log_error("Failed to reset transient hostname");
521 }
c07aeadf 522 }
4f882b2a 523
a6cc569e
TG
524 link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
525
c07aeadf
TG
526 return 0;
527}
4f882b2a 528
c07aeadf 529static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
a6cc569e 530 sd_dhcp_lease *lease;
c07aeadf
TG
531 struct in_addr address;
532 struct in_addr netmask;
533 struct in_addr gateway;
534 unsigned prefixlen;
c07aeadf
TG
535 struct in_addr *nameservers;
536 size_t nameservers_size;
537 int r;
1346b1f0 538
c07aeadf
TG
539 assert(client);
540 assert(link);
ff254138 541
a6cc569e
TG
542 r = sd_dhcp_client_get_lease(client, &lease);
543 if (r < 0) {
544 log_warning_link(link, "DHCP error: no lease: %s",
545 strerror(-r));
546 return r;
547 }
548
549 r = sd_dhcp_lease_get_address(lease, &address);
ff254138 550 if (r < 0) {
c07aeadf
TG
551 log_warning_link(link, "DHCP error: no address: %s",
552 strerror(-r));
553 return r;
ff254138
TG
554 }
555
a6cc569e 556 r = sd_dhcp_lease_get_netmask(lease, &netmask);
ff254138 557 if (r < 0) {
c07aeadf
TG
558 log_warning_link(link, "DHCP error: no netmask: %s",
559 strerror(-r));
560 return r;
ff254138
TG
561 }
562
377a218f 563 prefixlen = net_netmask_to_prefixlen(&netmask);
ff254138 564
a6cc569e 565 r = sd_dhcp_lease_get_router(lease, &gateway);
ff254138 566 if (r < 0) {
c07aeadf
TG
567 log_warning_link(link, "DHCP error: no router: %s",
568 strerror(-r));
569 return r;
ff254138
TG
570 }
571
c07aeadf
TG
572 log_struct_link(LOG_INFO, link,
573 "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
574 link->ifname,
575 ADDRESS_FMT_VAL(address),
576 prefixlen,
577 ADDRESS_FMT_VAL(gateway),
578 "ADDRESS=%u.%u.%u.%u",
579 ADDRESS_FMT_VAL(address),
580 "PREFIXLEN=%u",
581 prefixlen,
582 "GATEWAY=%u.%u.%u.%u",
583 ADDRESS_FMT_VAL(gateway),
584 NULL);
585
d50cf59b
TG
586 link->dhcp_lease = lease;
587
c07aeadf 588 if (link->network->dhcp_dns) {
a6cc569e 589 r = sd_dhcp_lease_get_dns(lease, &nameservers, &nameservers_size);
c07aeadf
TG
590 if (r >= 0) {
591 r = manager_update_resolv_conf(link->manager);
592 if (r < 0)
593 log_error("Failed to update resolv.conf");
ff254138 594 }
c07aeadf 595 }
ff254138 596
c07aeadf
TG
597 if (link->network->dhcp_mtu) {
598 uint16_t mtu;
599
a6cc569e 600 r = sd_dhcp_lease_get_mtu(lease, &mtu);
c07aeadf
TG
601 if (r >= 0) {
602 r = link_set_mtu(link, mtu);
603 if (r < 0)
604 log_error_link(link, "Failed to set MTU "
605 "to %" PRIu16, mtu);
606 }
607 }
ff254138 608
c07aeadf
TG
609 if (link->network->dhcp_hostname) {
610 const char *hostname;
ff254138 611
a6cc569e 612 r = sd_dhcp_lease_get_hostname(lease, &hostname);
c07aeadf
TG
613 if (r >= 0) {
614 r = set_hostname(link->manager->bus, hostname);
615 if (r < 0)
616 log_error("Failed to set transient hostname "
617 "to '%s'", hostname);
3bef724f 618 }
c07aeadf 619 }
3bef724f 620
c07aeadf
TG
621 link_enter_set_addresses(link);
622
623 return 0;
624}
625
626static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
627 Link *link = userdata;
628 int r;
629
630 assert(link);
631 assert(link->network);
632 assert(link->manager);
633
634 if (link->state == LINK_STATE_FAILED)
635 return;
636
637 switch (event) {
638 case DHCP_EVENT_NO_LEASE:
639 log_debug_link(link, "IP address in use.");
640 break;
641 case DHCP_EVENT_EXPIRED:
642 case DHCP_EVENT_STOP:
643 case DHCP_EVENT_IP_CHANGE:
644 if (link->network->dhcp_critical) {
645 log_error_link(link, "DHCPv4 connection considered system critical, "
646 "ignoring request to reconfigure it.");
647 return;
4f882b2a 648 }
4f882b2a 649
17256461
UTL
650 if (link->dhcp_lease) {
651 r = dhcp_lease_lost(link);
652 if (r < 0) {
653 link_enter_failed(link);
654 return;
655 }
c07aeadf 656 }
1346b1f0 657
c07aeadf
TG
658 if (event == DHCP_EVENT_IP_CHANGE) {
659 r = dhcp_lease_acquired(client, link);
660 if (r < 0) {
661 link_enter_failed(link);
662 return;
663 }
1346b1f0 664 }
1346b1f0 665
c07aeadf
TG
666 break;
667 case DHCP_EVENT_IP_ACQUIRE:
668 r = dhcp_lease_acquired(client, link);
669 if (r < 0) {
670 link_enter_failed(link);
671 return;
672 }
673 break;
674 default:
675 if (event < 0)
676 log_warning_link(link, "DHCP error: %s", strerror(-event));
677 else
678 log_warning_link(link, "DHCP unknown event: %d", event);
c07aeadf 679 break;
ff254138
TG
680 }
681
682 return;
683}
684
685static int link_acquire_conf(Link *link) {
686 int r;
687
688 assert(link);
689 assert(link->network);
690 assert(link->network->dhcp);
691 assert(link->manager);
692 assert(link->manager->event);
693
a6cc569e
TG
694 if (!link->dhcp_client) {
695 r = sd_dhcp_client_new(&link->dhcp_client);
b25ef18b
TG
696 if (r < 0)
697 return r;
698
a6cc569e 699 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
b25ef18b
TG
700 if (r < 0)
701 return r;
ff254138 702
a6cc569e 703 r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex);
ff254138
TG
704 if (r < 0)
705 return r;
706
a6cc569e 707 r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
ff254138
TG
708 if (r < 0)
709 return r;
710
a6cc569e 711 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp_handler, link);
ff254138
TG
712 if (r < 0)
713 return r;
6fc73498
TG
714
715 if (link->network->dhcp_mtu) {
a6cc569e 716 r = sd_dhcp_client_set_request_option(link->dhcp_client, 26);
6fc73498
TG
717 if (r < 0)
718 return r;
719 }
ff254138
TG
720 }
721
ab47d620
TG
722 log_debug_link(link, "acquiring DHCPv4 lease");
723
a6cc569e 724 r = sd_dhcp_client_start(link->dhcp_client);
ff254138
TG
725 if (r < 0)
726 return r;
727
728 return 0;
729}
730
731static int link_update_flags(Link *link, unsigned flags) {
732 int r;
733
734 assert(link);
735 assert(link->network);
736
737 if (link->state == LINK_STATE_FAILED)
738 return 0;
739
efbc88b8 740 if (link->flags == flags) {
ab47d620 741 log_debug_link(link, "link status unchanged: %#.8x", flags);
efbc88b8
TG
742 return 0;
743 }
744
3333d748
ZJS
745 if ((link->flags & IFF_UP) != (flags & IFF_UP))
746 log_info_link(link,
e6674986 747 "link is %s", flags & IFF_UP ? "up": "down");
efbc88b8
TG
748
749 if ((link->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
750 if (flags & IFF_LOWER_UP) {
39032b87 751 log_info_link(link, "carrier on");
efbc88b8
TG
752
753 if (link->network->dhcp) {
754 r = link_acquire_conf(link);
755 if (r < 0) {
1f6d9bc9 756 log_warning_link(link, "Could not acquire DHCPv4 lease: %s", strerror(-r));
efbc88b8
TG
757 link_enter_failed(link);
758 return r;
759 }
ff254138 760 }
efbc88b8 761 } else {
39032b87 762 log_info_link(link, "carrier off");
efbc88b8
TG
763
764 if (link->network->dhcp) {
a6cc569e 765 r = sd_dhcp_client_stop(link->dhcp_client);
efbc88b8 766 if (r < 0) {
1f6d9bc9 767 log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r));
efbc88b8
TG
768 link_enter_failed(link);
769 return r;
770 }
ff254138
TG
771 }
772 }
773 }
774
3333d748 775 log_debug_link(link,
ab47d620 776 "link status updated: %#.8x -> %#.8x", link->flags, flags);
efbc88b8 777
ff254138
TG
778 link->flags = flags;
779
780 return 0;
781}
782
dd3efc09
TG
783static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
784 Link *link = userdata;
785 int r;
786
1746cf2a
TG
787 assert(link);
788
789 if (link->state == LINK_STATE_FAILED)
790 return 1;
791
dd3efc09
TG
792 r = sd_rtnl_message_get_errno(m);
793 if (r < 0) {
c9ccc19f
TG
794 log_struct_link(LOG_ERR, link,
795 "MESSAGE=%s: could not bring up interface: %s",
796 link->ifname, strerror(-r),
797 "ERRNO=%d", -r,
798 NULL);
dd3efc09 799 link_enter_failed(link);
c9ccc19f 800 return 1;
dd3efc09 801 }
f882c247 802
ff254138 803 link_update_flags(link, link->flags | IFF_UP);
1746cf2a 804
f882c247
TG
805 return 1;
806}
807
808static int link_up(Link *link) {
cf6a8911 809 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
f579559b
TG
810 int r;
811
f882c247
TG
812 assert(link);
813 assert(link->manager);
814 assert(link->manager->rtnl);
815
39032b87 816 log_debug_link(link, "bringing link up");
449f7554 817
151b9b96
LP
818 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
819 RTM_SETLINK, link->ifindex);
f579559b 820 if (r < 0) {
39032b87 821 log_error_link(link, "Could not allocate RTM_SETLINK message");
f579559b
TG
822 return r;
823 }
824
5d4795f3 825 r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
fc25d7f8 826 if (r < 0) {
3333d748 827 log_error_link(link, "Could not set link flags: %s", strerror(-r));
fc25d7f8
TG
828 return r;
829 }
830
dd3efc09 831 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
f579559b 832 if (r < 0) {
3333d748
ZJS
833 log_error_link(link,
834 "Could not send rtnetlink message: %s", strerror(-r));
f579559b
TG
835 return r;
836 }
837
f882c247
TG
838 return 0;
839}
840
52433f6b 841static int link_enslaved(Link *link) {
f882c247
TG
842 int r;
843
ef1ba606 844 assert(link);
52433f6b 845 assert(link->state == LINK_STATE_ENSLAVING);
f5be5601 846 assert(link->network);
dd3efc09 847
f882c247 848 r = link_up(link);
ef1ba606
TG
849 if (r < 0) {
850 link_enter_failed(link);
851 return r;
852 }
f882c247 853
1746cf2a
TG
854 if (!link->network->dhcp)
855 return link_enter_set_addresses(link);
ef1ba606
TG
856
857 return 0;
02b59d57
TG
858}
859
52433f6b 860static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
02b59d57
TG
861 Link *link = userdata;
862 int r;
863
1746cf2a 864 assert(link);
52433f6b 865 assert(link->state == LINK_STATE_ENSLAVING || link->state == LINK_STATE_FAILED);
ef1ba606 866 assert(link->network);
02b59d57 867
52433f6b
TG
868 link->enslaving --;
869
02b59d57
TG
870 if (link->state == LINK_STATE_FAILED)
871 return 1;
872
873 r = sd_rtnl_message_get_errno(m);
ef1ba606 874 if (r < 0) {
c9ccc19f
TG
875 log_struct_link(LOG_ERR, link,
876 "MESSAGE=%s: could not enslave: %s",
877 link->ifname, strerror(-r),
878 "ERRNO=%d", -r,
879 NULL);
ef1ba606
TG
880 link_enter_failed(link);
881 return 1;
3333d748 882 }
02b59d57 883
52433f6b 884 log_debug_link(link, "enslaved");
ab47d620 885
52433f6b
TG
886 if (link->enslaving == 0)
887 link_enslaved(link);
02b59d57
TG
888
889 return 1;
890}
891
52433f6b 892static int link_enter_enslave(Link *link) {
fe6b2d55 893 NetDev *vlan, *macvlan;
672682a6 894 Iterator i;
02b59d57
TG
895 int r;
896
897 assert(link);
898 assert(link->network);
ef1ba606 899 assert(link->state == _LINK_STATE_INVALID);
02b59d57 900
52433f6b 901 link->state = LINK_STATE_ENSLAVING;
02b59d57 902
63ffa720 903 if (!link->network->bridge && !link->network->bond &&
fe6b2d55
TG
904 hashmap_isempty(link->network->vlans) &&
905 hashmap_isempty(link->network->macvlans))
52433f6b 906 return link_enslaved(link);
02b59d57 907
52433f6b
TG
908 if (link->network->bridge) {
909 log_struct_link(LOG_DEBUG, link,
910 "MESSAGE=%s: enslaving by '%s'",
c9ccc19f 911 link->ifname, link->network->bridge->name,
52433f6b
TG
912 NETDEV(link->network->bridge),
913 NULL);
449f7554 914
52433f6b
TG
915 r = netdev_enslave(link->network->bridge, link, &enslave_handler);
916 if (r < 0) {
917 log_struct_link(LOG_WARNING, link,
918 "MESSAGE=%s: could not enslave by '%s': %s",
c9ccc19f 919 link->ifname, link->network->bridge->name, strerror(-r),
52433f6b
TG
920 NETDEV(link->network->bridge),
921 NULL);
922 link_enter_failed(link);
923 return r;
924 }
925
926 link->enslaving ++;
927 }
928
672682a6 929 HASHMAP_FOREACH(vlan, link->network->vlans, i) {
52433f6b
TG
930 log_struct_link(LOG_DEBUG, link,
931 "MESSAGE=%s: enslaving by '%s'",
672682a6 932 link->ifname, vlan->name, NETDEV(vlan), NULL);
52433f6b 933
672682a6 934 r = netdev_enslave(vlan, link, &enslave_handler);
52433f6b
TG
935 if (r < 0) {
936 log_struct_link(LOG_WARNING, link,
937 "MESSAGE=%s: could not enslave by '%s': %s",
672682a6
TG
938 link->ifname, vlan->name, strerror(-r),
939 NETDEV(vlan), NULL);
52433f6b
TG
940 link_enter_failed(link);
941 return r;
942 }
943
944 link->enslaving ++;
ef1ba606
TG
945 }
946
fe6b2d55
TG
947 HASHMAP_FOREACH(macvlan, link->network->macvlans, i) {
948 log_struct_link(LOG_DEBUG, link,
949 "MESSAGE=%s: enslaving by '%s'",
950 link->ifname, macvlan->name, NETDEV(macvlan), NULL);
951
952 r = netdev_enslave(macvlan, link, &enslave_handler);
953 if (r < 0) {
954 log_struct_link(LOG_WARNING, link,
955 "MESSAGE=%s: could not enslave by '%s': %s",
956 link->ifname, macvlan->name, strerror(-r),
957 NETDEV(macvlan), NULL);
958 link_enter_failed(link);
959 return r;
960 }
961
962 link->enslaving ++;
963 }
964
ef1ba606
TG
965 return 0;
966}
967
11a7f229
TG
968static int link_getlink_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
969 void *userdata) {
ef1ba606
TG
970 Link *link = userdata;
971 int r;
972
1746cf2a
TG
973 assert(link);
974
975 if (link->state == LINK_STATE_FAILED)
976 return 1;
977
ef1ba606
TG
978 r = sd_rtnl_message_get_errno(m);
979 if (r < 0) {
c9ccc19f
TG
980 log_struct_link(LOG_ERR, link,
981 "MESSAGE=%s: could not get state: %s",
982 link->ifname, strerror(-r),
983 "ERRNO=%d", -r,
984 NULL);
ef1ba606 985 link_enter_failed(link);
c9ccc19f 986 return 1;
ef1ba606
TG
987 }
988
39032b87 989 log_debug_link(link, "got link state");
1746cf2a 990
5eb036ca
TG
991 link_update(link, m);
992
ef1ba606
TG
993 return 1;
994}
995
11a7f229 996static int link_getlink(Link *link) {
cf6a8911 997 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
ef1ba606
TG
998 int r;
999
1000 assert(link);
1001 assert(link->manager);
1002 assert(link->manager->rtnl);
1003
39032b87 1004 log_debug_link(link, "requesting link status");
449f7554 1005
151b9b96
LP
1006 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
1007 RTM_GETLINK, link->ifindex);
ef1ba606 1008 if (r < 0) {
39032b87 1009 log_error_link(link, "Could not allocate RTM_GETLINK message");
ef1ba606
TG
1010 return r;
1011 }
1012
11a7f229
TG
1013 r = sd_rtnl_call_async(link->manager->rtnl, req, link_getlink_handler,
1014 link, 0, NULL);
ef1ba606 1015 if (r < 0) {
3333d748
ZJS
1016 log_error_link(link,
1017 "Could not send rtnetlink message: %s", strerror(-r));
ef1ba606 1018 return r;
dd3efc09 1019 }
02b59d57
TG
1020
1021 return 0;
1022}
1023
1024int link_configure(Link *link) {
1025 int r;
1026
ef1ba606
TG
1027 assert(link);
1028 assert(link->network);
1029 assert(link->state == _LINK_STATE_INVALID);
1030
11a7f229 1031 r = link_getlink(link);
ef1ba606
TG
1032 if (r < 0) {
1033 link_enter_failed(link);
1034 return r;
1035 }
dd3efc09 1036
52433f6b 1037 return link_enter_enslave(link);
f579559b 1038}
dd3efc09 1039
22936833
TG
1040int link_update(Link *link, sd_rtnl_message *m) {
1041 unsigned flags;
4f882b2a
TG
1042 void *data;
1043 uint16_t type;
22936833
TG
1044 int r;
1045
dd3efc09 1046 assert(link);
22936833
TG
1047 assert(m);
1048
1746cf2a
TG
1049 if (link->state == LINK_STATE_FAILED)
1050 return 0;
1051
22936833
TG
1052 r = sd_rtnl_message_link_get_flags(m, &flags);
1053 if (r < 0) {
4f882b2a 1054 log_warning_link(link, "Could not get link flags");
22936833
TG
1055 return r;
1056 }
dd3efc09 1057
4f882b2a 1058 while (sd_rtnl_message_read(m, &type, &data) > 0) {
396945dc
TG
1059 if (type == IFLA_MTU && link->network->dhcp &&
1060 link->network->dhcp_mtu && !link->original_mtu) {
4f882b2a 1061 link->original_mtu = *(uint16_t *) data;
396945dc
TG
1062 log_debug_link(link, "saved original MTU: %" PRIu16,
1063 link->original_mtu);
4f882b2a
TG
1064 }
1065 }
1066
ff254138 1067 return link_update_flags(link, flags);
dd3efc09 1068}