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