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