]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-link.c
pam: use correct log level
[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) {
429 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
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
438 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
439 if (r < 0) {
440 log_error_link(link, "Could not allocate RTM_SETLINK message");
441 return r;
442 }
443
444 r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
445 if (r < 0) {
446 log_error_link(link, "Could not append MTU: %s", strerror(-r));
447 return r;
448 }
449
450 r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL);
451 if (r < 0) {
452 log_error_link(link,
453 "Could not send rtnetlink message: %s", strerror(-r));
454 return r;
455 }
456
457 return 0;
458}
459
a6cc569e
TG
460static int dhcp_lease_lost(Link *link) {
461 _cleanup_address_free_ Address *address = NULL;
462 struct in_addr addr;
463 struct in_addr netmask;
464 unsigned prefixlen;
ff254138
TG
465 int r;
466
467 assert(link);
a6cc569e 468 assert(link->dhcp_lease);
ff254138 469
a6cc569e
TG
470 r = address_new_dynamic(&address);
471 if (r >= 0) {
472 sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
473 sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
474 prefixlen = net_netmask_to_prefixlen(&netmask);
ff254138 475
a6cc569e
TG
476 address->family = AF_INET;
477 address->in_addr.in = addr;
478 address->prefixlen = prefixlen;
ff254138 479
a6cc569e 480 address_drop(address, link, address_drop_handler);
c07aeadf 481 }
eb27aeca 482
c07aeadf
TG
483 if (link->network->dhcp_mtu) {
484 uint16_t mtu;
ff254138 485
a6cc569e 486 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
c07aeadf
TG
487 if (r >= 0 && link->original_mtu != mtu) {
488 r = link_set_mtu(link, link->original_mtu);
489 if (r < 0) {
490 log_warning_link(link, "DHCP error: could not reset MTU");
491 link_enter_failed(link);
492 return r;
493 }
ff254138 494 }
c07aeadf 495 }
ff254138 496
c07aeadf
TG
497 if (link->network->dhcp_hostname) {
498 r = set_hostname(link->manager->bus, "");
499 if (r < 0)
500 log_error("Failed to reset transient hostname");
501 }
4f882b2a 502
a6cc569e
TG
503 link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
504
c07aeadf
TG
505 return 0;
506}
4f882b2a 507
c07aeadf 508static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
a6cc569e 509 sd_dhcp_lease *lease;
c07aeadf
TG
510 struct in_addr address;
511 struct in_addr netmask;
512 struct in_addr gateway;
513 unsigned prefixlen;
c07aeadf
TG
514 struct in_addr *nameservers;
515 size_t nameservers_size;
516 int r;
1346b1f0 517
c07aeadf
TG
518 assert(client);
519 assert(link);
ff254138 520
a6cc569e
TG
521 r = sd_dhcp_client_get_lease(client, &lease);
522 if (r < 0) {
523 log_warning_link(link, "DHCP error: no lease: %s",
524 strerror(-r));
525 return r;
526 }
527
528 r = sd_dhcp_lease_get_address(lease, &address);
ff254138 529 if (r < 0) {
c07aeadf
TG
530 log_warning_link(link, "DHCP error: no address: %s",
531 strerror(-r));
532 return r;
ff254138
TG
533 }
534
a6cc569e 535 r = sd_dhcp_lease_get_netmask(lease, &netmask);
ff254138 536 if (r < 0) {
c07aeadf
TG
537 log_warning_link(link, "DHCP error: no netmask: %s",
538 strerror(-r));
539 return r;
ff254138
TG
540 }
541
377a218f 542 prefixlen = net_netmask_to_prefixlen(&netmask);
ff254138 543
a6cc569e 544 r = sd_dhcp_lease_get_router(lease, &gateway);
ff254138 545 if (r < 0) {
c07aeadf
TG
546 log_warning_link(link, "DHCP error: no router: %s",
547 strerror(-r));
548 return r;
ff254138
TG
549 }
550
c07aeadf
TG
551 log_struct_link(LOG_INFO, link,
552 "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
553 link->ifname,
554 ADDRESS_FMT_VAL(address),
555 prefixlen,
556 ADDRESS_FMT_VAL(gateway),
557 "ADDRESS=%u.%u.%u.%u",
558 ADDRESS_FMT_VAL(address),
559 "PREFIXLEN=%u",
560 prefixlen,
561 "GATEWAY=%u.%u.%u.%u",
562 ADDRESS_FMT_VAL(gateway),
563 NULL);
564
d50cf59b
TG
565 link->dhcp_lease = lease;
566
c07aeadf 567 if (link->network->dhcp_dns) {
a6cc569e 568 r = sd_dhcp_lease_get_dns(lease, &nameservers, &nameservers_size);
c07aeadf
TG
569 if (r >= 0) {
570 r = manager_update_resolv_conf(link->manager);
571 if (r < 0)
572 log_error("Failed to update resolv.conf");
ff254138 573 }
c07aeadf 574 }
ff254138 575
c07aeadf
TG
576 if (link->network->dhcp_mtu) {
577 uint16_t mtu;
578
a6cc569e 579 r = sd_dhcp_lease_get_mtu(lease, &mtu);
c07aeadf
TG
580 if (r >= 0) {
581 r = link_set_mtu(link, mtu);
582 if (r < 0)
583 log_error_link(link, "Failed to set MTU "
584 "to %" PRIu16, mtu);
585 }
586 }
ff254138 587
c07aeadf
TG
588 if (link->network->dhcp_hostname) {
589 const char *hostname;
ff254138 590
a6cc569e 591 r = sd_dhcp_lease_get_hostname(lease, &hostname);
c07aeadf
TG
592 if (r >= 0) {
593 r = set_hostname(link->manager->bus, hostname);
594 if (r < 0)
595 log_error("Failed to set transient hostname "
596 "to '%s'", hostname);
3bef724f 597 }
c07aeadf 598 }
3bef724f 599
c07aeadf
TG
600 link_enter_set_addresses(link);
601
602 return 0;
603}
604
605static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
606 Link *link = userdata;
607 int r;
608
609 assert(link);
610 assert(link->network);
611 assert(link->manager);
612
613 if (link->state == LINK_STATE_FAILED)
614 return;
615
616 switch (event) {
617 case DHCP_EVENT_NO_LEASE:
618 log_debug_link(link, "IP address in use.");
619 break;
620 case DHCP_EVENT_EXPIRED:
621 case DHCP_EVENT_STOP:
622 case DHCP_EVENT_IP_CHANGE:
623 if (link->network->dhcp_critical) {
624 log_error_link(link, "DHCPv4 connection considered system critical, "
625 "ignoring request to reconfigure it.");
626 return;
4f882b2a 627 }
4f882b2a 628
a6cc569e 629 r = dhcp_lease_lost(link);
c07aeadf
TG
630 if (r < 0) {
631 link_enter_failed(link);
632 return;
633 }
1346b1f0 634
c07aeadf
TG
635 if (event == DHCP_EVENT_IP_CHANGE) {
636 r = dhcp_lease_acquired(client, link);
637 if (r < 0) {
638 link_enter_failed(link);
639 return;
640 }
1346b1f0 641 }
1346b1f0 642
c07aeadf
TG
643 break;
644 case DHCP_EVENT_IP_ACQUIRE:
645 r = dhcp_lease_acquired(client, link);
646 if (r < 0) {
647 link_enter_failed(link);
648 return;
649 }
650 break;
651 default:
652 if (event < 0)
653 log_warning_link(link, "DHCP error: %s", strerror(-event));
654 else
655 log_warning_link(link, "DHCP unknown event: %d", event);
c07aeadf 656 break;
ff254138
TG
657 }
658
659 return;
660}
661
662static int link_acquire_conf(Link *link) {
663 int r;
664
665 assert(link);
666 assert(link->network);
667 assert(link->network->dhcp);
668 assert(link->manager);
669 assert(link->manager->event);
670
a6cc569e
TG
671 if (!link->dhcp_client) {
672 r = sd_dhcp_client_new(&link->dhcp_client);
b25ef18b
TG
673 if (r < 0)
674 return r;
675
a6cc569e 676 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
b25ef18b
TG
677 if (r < 0)
678 return r;
ff254138 679
a6cc569e 680 r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex);
ff254138
TG
681 if (r < 0)
682 return r;
683
a6cc569e 684 r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
ff254138
TG
685 if (r < 0)
686 return r;
687
a6cc569e 688 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp_handler, link);
ff254138
TG
689 if (r < 0)
690 return r;
6fc73498
TG
691
692 if (link->network->dhcp_mtu) {
a6cc569e 693 r = sd_dhcp_client_set_request_option(link->dhcp_client, 26);
6fc73498
TG
694 if (r < 0)
695 return r;
696 }
ff254138
TG
697 }
698
ab47d620
TG
699 log_debug_link(link, "acquiring DHCPv4 lease");
700
a6cc569e 701 r = sd_dhcp_client_start(link->dhcp_client);
ff254138
TG
702 if (r < 0)
703 return r;
704
705 return 0;
706}
707
708static int link_update_flags(Link *link, unsigned flags) {
709 int r;
710
711 assert(link);
712 assert(link->network);
713
714 if (link->state == LINK_STATE_FAILED)
715 return 0;
716
efbc88b8 717 if (link->flags == flags) {
ab47d620 718 log_debug_link(link, "link status unchanged: %#.8x", flags);
efbc88b8
TG
719 return 0;
720 }
721
3333d748
ZJS
722 if ((link->flags & IFF_UP) != (flags & IFF_UP))
723 log_info_link(link,
e6674986 724 "link is %s", flags & IFF_UP ? "up": "down");
efbc88b8
TG
725
726 if ((link->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
727 if (flags & IFF_LOWER_UP) {
39032b87 728 log_info_link(link, "carrier on");
efbc88b8
TG
729
730 if (link->network->dhcp) {
731 r = link_acquire_conf(link);
732 if (r < 0) {
1f6d9bc9 733 log_warning_link(link, "Could not acquire DHCPv4 lease: %s", strerror(-r));
efbc88b8
TG
734 link_enter_failed(link);
735 return r;
736 }
ff254138 737 }
efbc88b8 738 } else {
39032b87 739 log_info_link(link, "carrier off");
efbc88b8
TG
740
741 if (link->network->dhcp) {
a6cc569e 742 r = sd_dhcp_client_stop(link->dhcp_client);
efbc88b8 743 if (r < 0) {
1f6d9bc9 744 log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r));
efbc88b8
TG
745 link_enter_failed(link);
746 return r;
747 }
ff254138
TG
748 }
749 }
750 }
751
3333d748 752 log_debug_link(link,
ab47d620 753 "link status updated: %#.8x -> %#.8x", link->flags, flags);
efbc88b8 754
ff254138
TG
755 link->flags = flags;
756
757 return 0;
758}
759
dd3efc09
TG
760static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
761 Link *link = userdata;
762 int r;
763
1746cf2a
TG
764 assert(link);
765
766 if (link->state == LINK_STATE_FAILED)
767 return 1;
768
dd3efc09
TG
769 r = sd_rtnl_message_get_errno(m);
770 if (r < 0) {
c9ccc19f
TG
771 log_struct_link(LOG_ERR, link,
772 "MESSAGE=%s: could not bring up interface: %s",
773 link->ifname, strerror(-r),
774 "ERRNO=%d", -r,
775 NULL);
dd3efc09 776 link_enter_failed(link);
c9ccc19f 777 return 1;
dd3efc09 778 }
f882c247 779
ff254138 780 link_update_flags(link, link->flags | IFF_UP);
1746cf2a 781
f882c247
TG
782 return 1;
783}
784
785static int link_up(Link *link) {
f579559b
TG
786 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
787 int r;
788
f882c247
TG
789 assert(link);
790 assert(link->manager);
791 assert(link->manager->rtnl);
792
39032b87 793 log_debug_link(link, "bringing link up");
449f7554 794
0f49a5f7 795 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
f579559b 796 if (r < 0) {
39032b87 797 log_error_link(link, "Could not allocate RTM_SETLINK message");
f579559b
TG
798 return r;
799 }
800
5d4795f3 801 r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
fc25d7f8 802 if (r < 0) {
3333d748 803 log_error_link(link, "Could not set link flags: %s", strerror(-r));
fc25d7f8
TG
804 return r;
805 }
806
dd3efc09 807 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
f579559b 808 if (r < 0) {
3333d748
ZJS
809 log_error_link(link,
810 "Could not send rtnetlink message: %s", strerror(-r));
f579559b
TG
811 return r;
812 }
813
f882c247
TG
814 return 0;
815}
816
52433f6b 817static int link_enslaved(Link *link) {
f882c247
TG
818 int r;
819
ef1ba606 820 assert(link);
52433f6b 821 assert(link->state == LINK_STATE_ENSLAVING);
f5be5601 822 assert(link->network);
dd3efc09 823
f882c247 824 r = link_up(link);
ef1ba606
TG
825 if (r < 0) {
826 link_enter_failed(link);
827 return r;
828 }
f882c247 829
1746cf2a
TG
830 if (!link->network->dhcp)
831 return link_enter_set_addresses(link);
ef1ba606
TG
832
833 return 0;
02b59d57
TG
834}
835
52433f6b 836static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
02b59d57
TG
837 Link *link = userdata;
838 int r;
839
1746cf2a 840 assert(link);
52433f6b 841 assert(link->state == LINK_STATE_ENSLAVING || link->state == LINK_STATE_FAILED);
ef1ba606 842 assert(link->network);
02b59d57 843
52433f6b
TG
844 link->enslaving --;
845
02b59d57
TG
846 if (link->state == LINK_STATE_FAILED)
847 return 1;
848
849 r = sd_rtnl_message_get_errno(m);
ef1ba606 850 if (r < 0) {
c9ccc19f
TG
851 log_struct_link(LOG_ERR, link,
852 "MESSAGE=%s: could not enslave: %s",
853 link->ifname, strerror(-r),
854 "ERRNO=%d", -r,
855 NULL);
ef1ba606
TG
856 link_enter_failed(link);
857 return 1;
3333d748 858 }
02b59d57 859
52433f6b 860 log_debug_link(link, "enslaved");
ab47d620 861
52433f6b
TG
862 if (link->enslaving == 0)
863 link_enslaved(link);
02b59d57
TG
864
865 return 1;
866}
867
52433f6b 868static int link_enter_enslave(Link *link) {
02b59d57
TG
869 int r;
870
871 assert(link);
872 assert(link->network);
ef1ba606 873 assert(link->state == _LINK_STATE_INVALID);
02b59d57 874
52433f6b 875 link->state = LINK_STATE_ENSLAVING;
02b59d57 876
54abf461 877 if (!link->network->bridge && !link->network->bond && !link->network->vlan)
52433f6b 878 return link_enslaved(link);
02b59d57 879
52433f6b
TG
880 if (link->network->bridge) {
881 log_struct_link(LOG_DEBUG, link,
882 "MESSAGE=%s: enslaving by '%s'",
c9ccc19f 883 link->ifname, link->network->bridge->name,
52433f6b
TG
884 NETDEV(link->network->bridge),
885 NULL);
449f7554 886
52433f6b
TG
887 r = netdev_enslave(link->network->bridge, link, &enslave_handler);
888 if (r < 0) {
889 log_struct_link(LOG_WARNING, link,
890 "MESSAGE=%s: could not enslave by '%s': %s",
c9ccc19f 891 link->ifname, link->network->bridge->name, strerror(-r),
52433f6b
TG
892 NETDEV(link->network->bridge),
893 NULL);
894 link_enter_failed(link);
895 return r;
896 }
897
898 link->enslaving ++;
899 }
900
54abf461 901 if (link->network->vlan) {
52433f6b
TG
902 log_struct_link(LOG_DEBUG, link,
903 "MESSAGE=%s: enslaving by '%s'",
c9ccc19f 904 link->ifname, link->network->vlan->name,
54abf461 905 NETDEV(link->network->vlan),
3333d748 906 NULL);
52433f6b 907
54abf461 908 r = netdev_enslave(link->network->vlan, link, &enslave_handler);
52433f6b
TG
909 if (r < 0) {
910 log_struct_link(LOG_WARNING, link,
911 "MESSAGE=%s: could not enslave by '%s': %s",
c9ccc19f
TG
912 link->ifname, link->network->vlan->name,
913 strerror(-r), NETDEV(link->network->vlan),
52433f6b
TG
914 NULL);
915 link_enter_failed(link);
916 return r;
917 }
918
919 link->enslaving ++;
ef1ba606
TG
920 }
921
922 return 0;
923}
924
925static int link_get_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
926 Link *link = userdata;
927 int r;
928
1746cf2a
TG
929 assert(link);
930
931 if (link->state == LINK_STATE_FAILED)
932 return 1;
933
ef1ba606
TG
934 r = sd_rtnl_message_get_errno(m);
935 if (r < 0) {
c9ccc19f
TG
936 log_struct_link(LOG_ERR, link,
937 "MESSAGE=%s: could not get state: %s",
938 link->ifname, strerror(-r),
939 "ERRNO=%d", -r,
940 NULL);
ef1ba606 941 link_enter_failed(link);
c9ccc19f 942 return 1;
ef1ba606
TG
943 }
944
39032b87 945 log_debug_link(link, "got link state");
1746cf2a 946
5eb036ca
TG
947 link_update(link, m);
948
ef1ba606
TG
949 return 1;
950}
951
952static int link_get(Link *link) {
953 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
954 int r;
955
956 assert(link);
957 assert(link->manager);
958 assert(link->manager->rtnl);
959
39032b87 960 log_debug_link(link, "requesting link status");
449f7554 961
ef1ba606
TG
962 r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
963 if (r < 0) {
39032b87 964 log_error_link(link, "Could not allocate RTM_GETLINK message");
ef1ba606
TG
965 return r;
966 }
967
968 r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
969 if (r < 0) {
3333d748
ZJS
970 log_error_link(link,
971 "Could not send rtnetlink message: %s", strerror(-r));
ef1ba606 972 return r;
dd3efc09 973 }
02b59d57
TG
974
975 return 0;
976}
977
978int link_configure(Link *link) {
979 int r;
980
ef1ba606
TG
981 assert(link);
982 assert(link->network);
983 assert(link->state == _LINK_STATE_INVALID);
984
dd3efc09 985 r = link_get(link);
ef1ba606
TG
986 if (r < 0) {
987 link_enter_failed(link);
988 return r;
989 }
dd3efc09 990
52433f6b 991 return link_enter_enslave(link);
f579559b 992}
dd3efc09 993
22936833
TG
994int link_update(Link *link, sd_rtnl_message *m) {
995 unsigned flags;
4f882b2a
TG
996 void *data;
997 uint16_t type;
22936833
TG
998 int r;
999
dd3efc09 1000 assert(link);
22936833
TG
1001 assert(m);
1002
1746cf2a
TG
1003 if (link->state == LINK_STATE_FAILED)
1004 return 0;
1005
22936833
TG
1006 r = sd_rtnl_message_link_get_flags(m, &flags);
1007 if (r < 0) {
4f882b2a 1008 log_warning_link(link, "Could not get link flags");
22936833
TG
1009 return r;
1010 }
dd3efc09 1011
4f882b2a 1012 while (sd_rtnl_message_read(m, &type, &data) > 0) {
396945dc
TG
1013 if (type == IFLA_MTU && link->network->dhcp &&
1014 link->network->dhcp_mtu && !link->original_mtu) {
4f882b2a 1015 link->original_mtu = *(uint16_t *) data;
396945dc
TG
1016 log_debug_link(link, "saved original MTU: %" PRIu16,
1017 link->original_mtu);
4f882b2a
TG
1018 }
1019 }
1020
ff254138 1021 return link_update_flags(link, flags);
dd3efc09 1022}