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