]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-link.c
networkd: dhcp - only set the MTU option once
[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"
28
29int link_new(Manager *manager, struct udev_device *device, Link **ret) {
30 _cleanup_link_free_ Link *link = NULL;
8cd11a0f 31 const char *mac;
602cc437 32 struct ether_addr *mac_addr;
c166a070 33 const char *ifname;
f579559b
TG
34 int r;
35
36 assert(device);
37 assert(ret);
38
39 link = new0(Link, 1);
40 if (!link)
41 return -ENOMEM;
42
5a3eb5a7
TG
43 link->manager = manager;
44 link->state = _LINK_STATE_INVALID;
45
0617ffab
TG
46 link->ifindex = udev_device_get_ifindex(device);
47 if (link->ifindex <= 0)
f579559b
TG
48 return -EINVAL;
49
8cd11a0f 50 mac = udev_device_get_sysattr_value(device, "address");
5a3eb5a7
TG
51 if (mac) {
52 mac_addr = ether_aton(mac);
53 if (mac_addr)
54 memcpy(&link->mac, mac_addr, sizeof(struct ether_addr));
55 }
f579559b 56
c166a070
TG
57 ifname = udev_device_get_sysname(device);
58 link->ifname = strdup(ifname);
59
0617ffab 60 r = hashmap_put(manager->links, &link->ifindex, link);
f579559b
TG
61 if (r < 0)
62 return r;
63
64 *ret = link;
65 link = NULL;
66
67 return 0;
68}
69
70void link_free(Link *link) {
71 if (!link)
72 return;
73
0617ffab 74 assert(link->manager);
f579559b 75
f5be5601
TG
76 if (link->dhcp)
77 sd_dhcp_client_free(link->dhcp);
78
79 route_free(link->dhcp_route);
80 link->dhcp_route = NULL;
81
82 address_free(link->dhcp_address);
83 link->dhcp_address = NULL;
84
0617ffab 85 hashmap_remove(link->manager->links, &link->ifindex);
f579559b 86
c166a070
TG
87 free(link->ifname);
88
f579559b
TG
89 free(link);
90}
91
aa3437a5 92int link_add(Manager *m, struct udev_device *device, Link **ret) {
f579559b
TG
93 Link *link;
94 Network *network;
95 int r;
96 uint64_t ifindex;
02b59d57 97 const char *devtype;
f579559b
TG
98
99 assert(m);
100 assert(device);
101
102 ifindex = udev_device_get_ifindex(device);
103 link = hashmap_get(m->links, &ifindex);
aa3437a5
TG
104 if (link) {
105 *ret = link;
2672953b 106 return -EEXIST;
aa3437a5 107 }
f579559b
TG
108
109 r = link_new(m, device, &link);
2672953b 110 if (r < 0)
f579559b 111 return r;
f579559b 112
aa3437a5
TG
113 *ret = link;
114
02b59d57
TG
115 devtype = udev_device_get_devtype(device);
116 if (streq_ptr(devtype, "bridge")) {
117 r = bridge_set_link(m, link);
aa3437a5
TG
118 if (r < 0 && r != -ENOENT)
119 return r;
02b59d57
TG
120 }
121
f579559b
TG
122 r = network_get(m, device, &network);
123 if (r < 0)
124 return r == -ENOENT ? 0 : r;
125
126 r = network_apply(m, network, link);
127 if (r < 0)
128 return r;
129
130 return 0;
131}
132
f882c247 133static int link_enter_configured(Link *link) {
ef1ba606
TG
134 assert(link);
135 assert(link->state == LINK_STATE_SETTING_ROUTES);
136
39032b87 137 log_info_link(link, "link configured");
f882c247
TG
138
139 link->state = LINK_STATE_CONFIGURED;
140
141 return 0;
142}
143
ef1ba606
TG
144static void link_enter_failed(Link *link) {
145 assert(link);
f882c247 146
39032b87 147 log_warning_link(link, "failed");
449f7554 148
ef1ba606 149 link->state = LINK_STATE_FAILED;
f882c247
TG
150}
151
f882c247
TG
152static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
153 Link *link = userdata;
154 int r;
155
f5be5601
TG
156 assert(link->route_messages > 0);
157 assert(link->state == LINK_STATE_SETTING_ADDRESSES ||
158 link->state == LINK_STATE_SETTING_ROUTES ||
159 link->state == LINK_STATE_FAILED);
f882c247 160
f5be5601 161 link->route_messages --;
f882c247
TG
162
163 if (link->state == LINK_STATE_FAILED)
164 return 1;
165
166 r = sd_rtnl_message_get_errno(m);
c166a070 167 if (r < 0 && r != -EEXIST)
3333d748 168 log_warning_link(link, "could not set route: %s", strerror(-r));
f882c247 169
f5be5601
TG
170 /* we might have received an old reply after moving back to SETTING_ADDRESSES,
171 * ignore it */
172 if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
39032b87 173 log_debug_link(link, "routes set");
dd3efc09
TG
174 link_enter_configured(link);
175 }
f882c247
TG
176
177 return 1;
178}
179
180static int link_enter_set_routes(Link *link) {
181 Route *route;
182 int r;
183
184 assert(link);
185 assert(link->network);
ef1ba606 186 assert(link->state == LINK_STATE_SETTING_ADDRESSES);
f882c247 187
ef1ba606 188 link->state = LINK_STATE_SETTING_ROUTES;
f882c247 189
f5be5601 190 if (!link->network->static_routes && !link->dhcp_route)
dd3efc09 191 return link_enter_configured(link);
f882c247 192
39032b87 193 log_debug_link(link, "setting routes");
449f7554 194
f048a16b 195 LIST_FOREACH(static_routes, route, link->network->static_routes) {
f882c247 196 r = route_configure(route, link, &route_handler);
dd3efc09 197 if (r < 0) {
3333d748
ZJS
198 log_warning_link(link,
199 "could not set routes: %s", strerror(-r));
ef1ba606
TG
200 link_enter_failed(link);
201 return r;
dd3efc09 202 }
c166a070 203
f5be5601
TG
204 link->route_messages ++;
205 }
206
207 if (link->dhcp_route) {
208 r = route_configure(link->dhcp_route, link, &route_handler);
209 if (r < 0) {
3333d748
ZJS
210 log_warning_link(link,
211 "could not set routes: %s", strerror(-r));
f5be5601
TG
212 link_enter_failed(link);
213 return r;
214 }
215
216 link->route_messages ++;
f882c247
TG
217 }
218
219 return 0;
220}
221
f882c247
TG
222static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
223 Link *link = userdata;
224 int r;
225
f5be5601
TG
226 assert(m);
227 assert(link);
228 assert(link->ifname);
229 assert(link->addr_messages > 0);
ef1ba606 230 assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
f882c247 231
f5be5601 232 link->addr_messages --;
f882c247
TG
233
234 if (link->state == LINK_STATE_FAILED)
235 return 1;
236
237 r = sd_rtnl_message_get_errno(m);
c166a070 238 if (r < 0 && r != -EEXIST)
3333d748
ZJS
239 log_struct_link(LOG_ERR, link,
240 "MESSAGE=%s: could not set address: %s",
241 link->ifname, strerror(-r),
242 "ERRNO=%d", -r,
243 NULL);
f882c247 244
f5be5601 245 if (link->addr_messages == 0) {
39032b87 246 log_debug_link(link, "addresses set");
ef1ba606 247 link_enter_set_routes(link);
dd3efc09 248 }
f882c247
TG
249
250 return 1;
251}
252
253static int link_enter_set_addresses(Link *link) {
254 Address *address;
255 int r;
256
257 assert(link);
258 assert(link->network);
f5be5601 259 assert(link->state != _LINK_STATE_INVALID);
f882c247 260
ef1ba606 261 link->state = LINK_STATE_SETTING_ADDRESSES;
f882c247 262
f5be5601 263 if (!link->network->static_addresses && !link->dhcp_address)
ef1ba606 264 return link_enter_set_routes(link);
f882c247 265
39032b87 266 log_debug_link(link, "setting addresses");
449f7554 267
f048a16b 268 LIST_FOREACH(static_addresses, address, link->network->static_addresses) {
f882c247 269 r = address_configure(address, link, &address_handler);
dd3efc09 270 if (r < 0) {
3333d748
ZJS
271 log_warning_link(link,
272 "could not set addresses: %s", strerror(-r));
ef1ba606
TG
273 link_enter_failed(link);
274 return r;
dd3efc09 275 }
c166a070 276
f5be5601
TG
277 link->addr_messages ++;
278 }
279
280 if (link->dhcp_address) {
281 r = address_configure(link->dhcp_address, link, &address_handler);
282 if (r < 0) {
3333d748
ZJS
283 log_warning_link(link,
284 "could not set addresses: %s", strerror(-r));
f5be5601
TG
285 link_enter_failed(link);
286 return r;
287 }
288
289 link->addr_messages ++;
f882c247
TG
290 }
291
292 return 0;
293}
294
ff254138
TG
295static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
296 Link *link = userdata;
297 int r;
298
299 assert(m);
300 assert(link);
301 assert(link->ifname);
302
303 if (link->state == LINK_STATE_FAILED)
304 return 1;
305
306 r = sd_rtnl_message_get_errno(m);
307 if (r < 0 && r != -EEXIST)
3333d748 308 log_warning_link(link, "could not drop address: %s", strerror(-r));
ff254138
TG
309
310 return 1;
311}
312
4f882b2a
TG
313static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
314 Link *link = userdata;
315 int r;
316
317 assert(m);
318 assert(link);
319 assert(link->ifname);
320
321 if (link->state == LINK_STATE_FAILED)
322 return 1;
323
324 r = sd_rtnl_message_get_errno(m);
325 if (r < 0 && r != -EEXIST)
326 log_warning_link(link, "Could not set MTU: %s", strerror(-r));
327
328 return 1;
329}
330
331static int link_set_mtu(Link *link, uint32_t mtu) {
332 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
333 int r;
334
335 assert(link);
336 assert(link->manager);
337 assert(link->manager->rtnl);
338
339 log_debug_link(link, "setting MTU: %" PRIu32, mtu);
340
341 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
342 if (r < 0) {
343 log_error_link(link, "Could not allocate RTM_SETLINK message");
344 return r;
345 }
346
347 r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
348 if (r < 0) {
349 log_error_link(link, "Could not append MTU: %s", strerror(-r));
350 return r;
351 }
352
353 r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL);
354 if (r < 0) {
355 log_error_link(link,
356 "Could not send rtnetlink message: %s", strerror(-r));
357 return r;
358 }
359
360 return 0;
361}
362
ff254138
TG
363static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
364 Link *link = userdata;
365 struct in_addr address;
366 struct in_addr netmask;
367 struct in_addr gateway;
368 int prefixlen;
369 int r;
370
371 assert(link);
5be4d38e 372 assert(link->network);
ff254138
TG
373
374 if (link->state == LINK_STATE_FAILED)
375 return;
376
377 if (event < 0) {
3333d748 378 log_warning_link(link, "DHCP error: %s", strerror(-event));
ff254138
TG
379 link_enter_failed(link);
380 return;
381 }
382
383 if (event == DHCP_EVENT_NO_LEASE)
39032b87 384 log_debug_link(link, "IP address in use.");
ff254138
TG
385
386 if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_EXPIRED ||
387 event == DHCP_EVENT_STOP) {
388 if (link->dhcp_address) {
389 address_drop(link->dhcp_address, link, address_drop_handler);
390
391 address_free(link->dhcp_address);
392 link->dhcp_address = NULL;
393 }
394
395 if (link->dhcp_route) {
396 route_free(link->dhcp_route);
397 link->dhcp_route = NULL;
398 }
4f882b2a
TG
399
400 if (link->network->dhcp_mtu) {
401 uint16_t mtu;
402
403 r = sd_dhcp_client_get_mtu(client, &mtu);
404 if (r >= 0 && link->original_mtu != mtu) {
405 r = link_set_mtu(link, link->original_mtu);
406 if (r < 0) {
407 log_warning_link(link, "DHCP error: could not reset MTU");
408 link_enter_failed(link);
409 return;
410 }
411 }
412 }
ff254138
TG
413 }
414
415 r = sd_dhcp_client_get_address(client, &address);
416 if (r < 0) {
39032b87 417 log_warning_link(link, "DHCP error: no address");
ff254138
TG
418 link_enter_failed(link);
419 return;
420 }
421
422 r = sd_dhcp_client_get_netmask(client, &netmask);
423 if (r < 0) {
39032b87 424 log_warning_link(link, "DHCP error: no netmask");
ff254138
TG
425 link_enter_failed(link);
426 return;
427 }
428
429 prefixlen = sd_dhcp_client_prefixlen(&netmask);
430 if (prefixlen < 0) {
39032b87 431 log_warning_link(link, "DHCP error: no prefixlen");
ff254138
TG
432 link_enter_failed(link);
433 return;
434 }
435
436 r = sd_dhcp_client_get_router(client, &gateway);
437 if (r < 0) {
39032b87 438 log_warning_link(link, "DHCP error: no router");
ff254138
TG
439 link_enter_failed(link);
440 return;
441 }
442
443 if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_IP_ACQUIRE) {
444 _cleanup_address_free_ Address *addr = NULL;
445 _cleanup_route_free_ Route *rt = NULL;
3bef724f 446 struct in_addr **nameservers;
ff254138 447
62870613
ZJS
448 log_struct_link(LOG_INFO, link,
449 "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
450 link->ifname,
451 ADDRESS_FMT_VAL(address),
452 prefixlen,
453 ADDRESS_FMT_VAL(gateway),
454 "ADDRESS=%u.%u.%u.%u",
455 ADDRESS_FMT_VAL(address),
456 "PREFIXLEN=%u",
457 prefixlen,
458 "GATEWAY=%u.%u.%u.%u",
459 ADDRESS_FMT_VAL(gateway),
460 NULL);
ff254138
TG
461
462 r = address_new_dynamic(&addr);
463 if (r < 0) {
39032b87 464 log_error_link(link, "Could not allocate address");
ff254138
TG
465 link_enter_failed(link);
466 return;
467 }
468
469 addr->family = AF_INET;
470 addr->in_addr.in = address;
471 addr->prefixlen = prefixlen;
472 addr->netmask = netmask;
473
474 r = route_new_dynamic(&rt);
475 if (r < 0) {
39032b87 476 log_error_link(link, "Could not allocate route");
ff254138
TG
477 link_enter_failed(link);
478 return;
479 }
480
481 rt->family = AF_INET;
482 rt->in_addr.in = gateway;
483
484 link->dhcp_address = addr;
485 link->dhcp_route = rt;
486 addr = NULL;
487 rt = NULL;
488
5be4d38e
TG
489 if (link->network->dhcp_dns) {
490 r = sd_dhcp_client_get_dns(client, &nameservers);
491 if (r >= 0) {
492 r = manager_update_resolv_conf(link->manager);
493 if (r < 0)
494 log_error("Failed to update resolv.conf");
495 }
3bef724f
TG
496 }
497
4f882b2a
TG
498 if (link->network->dhcp_mtu) {
499 uint16_t mtu;
500
501 r = sd_dhcp_client_get_mtu(client, &mtu);
502 if (r >= 0) {
503 r = link_set_mtu(link, mtu);
504 if (r < 0)
505 log_error_link(link, "Failed to set MTU "
506 "to %" PRIu16, mtu);
507 }
508 }
509
ff254138
TG
510 link_enter_set_addresses(link);
511 }
512
513 return;
514}
515
516static int link_acquire_conf(Link *link) {
517 int r;
518
519 assert(link);
520 assert(link->network);
521 assert(link->network->dhcp);
522 assert(link->manager);
523 assert(link->manager->event);
524
525 if (!link->dhcp) {
526 link->dhcp = sd_dhcp_client_new(link->manager->event);
527 if (!link->dhcp)
528 return -ENOMEM;
529
530 r = sd_dhcp_client_set_index(link->dhcp, link->ifindex);
531 if (r < 0)
532 return r;
533
534 r = sd_dhcp_client_set_mac(link->dhcp, &link->mac);
535 if (r < 0)
536 return r;
537
538 r = sd_dhcp_client_set_callback(link->dhcp, dhcp_handler, link);
539 if (r < 0)
540 return r;
6fc73498
TG
541
542 if (link->network->dhcp_mtu) {
543 r = sd_dhcp_client_set_request_option(link->dhcp, 26);
544 if (r < 0)
545 return r;
546 }
ff254138
TG
547 }
548
ab47d620
TG
549 log_debug_link(link, "acquiring DHCPv4 lease");
550
ff254138
TG
551 r = sd_dhcp_client_start(link->dhcp);
552 if (r < 0)
553 return r;
554
555 return 0;
556}
557
558static int link_update_flags(Link *link, unsigned flags) {
559 int r;
560
561 assert(link);
562 assert(link->network);
563
564 if (link->state == LINK_STATE_FAILED)
565 return 0;
566
efbc88b8 567 if (link->flags == flags) {
ab47d620 568 log_debug_link(link, "link status unchanged: %#.8x", flags);
efbc88b8
TG
569 return 0;
570 }
571
3333d748
ZJS
572 if ((link->flags & IFF_UP) != (flags & IFF_UP))
573 log_info_link(link,
574 "power %s", flags & IFF_UP ? "on": "off");
efbc88b8
TG
575
576 if ((link->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
577 if (flags & IFF_LOWER_UP) {
39032b87 578 log_info_link(link, "carrier on");
efbc88b8
TG
579
580 if (link->network->dhcp) {
581 r = link_acquire_conf(link);
582 if (r < 0) {
1f6d9bc9 583 log_warning_link(link, "Could not acquire DHCPv4 lease: %s", strerror(-r));
efbc88b8
TG
584 link_enter_failed(link);
585 return r;
586 }
ff254138 587 }
efbc88b8 588 } else {
39032b87 589 log_info_link(link, "carrier off");
efbc88b8
TG
590
591 if (link->network->dhcp) {
592 r = sd_dhcp_client_stop(link->dhcp);
593 if (r < 0) {
1f6d9bc9 594 log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r));
efbc88b8
TG
595 link_enter_failed(link);
596 return r;
597 }
ff254138
TG
598 }
599 }
600 }
601
3333d748 602 log_debug_link(link,
ab47d620 603 "link status updated: %#.8x -> %#.8x", link->flags, flags);
efbc88b8 604
ff254138
TG
605 link->flags = flags;
606
607 return 0;
608}
609
dd3efc09
TG
610static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
611 Link *link = userdata;
612 int r;
613
1746cf2a
TG
614 assert(link);
615
616 if (link->state == LINK_STATE_FAILED)
617 return 1;
618
dd3efc09
TG
619 r = sd_rtnl_message_get_errno(m);
620 if (r < 0) {
3333d748
ZJS
621 log_warning_link(link,
622 "could not bring up interface: %s", strerror(-r));
dd3efc09
TG
623 link_enter_failed(link);
624 }
f882c247 625
ff254138 626 link_update_flags(link, link->flags | IFF_UP);
1746cf2a 627
f882c247
TG
628 return 1;
629}
630
631static int link_up(Link *link) {
f579559b
TG
632 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
633 int r;
634
f882c247
TG
635 assert(link);
636 assert(link->manager);
637 assert(link->manager->rtnl);
638
39032b87 639 log_debug_link(link, "bringing link up");
449f7554 640
0f49a5f7 641 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
f579559b 642 if (r < 0) {
39032b87 643 log_error_link(link, "Could not allocate RTM_SETLINK message");
f579559b
TG
644 return r;
645 }
646
fc25d7f8
TG
647 r = sd_rtnl_message_link_set_flags(req, IFF_UP);
648 if (r < 0) {
3333d748 649 log_error_link(link, "Could not set link flags: %s", strerror(-r));
fc25d7f8
TG
650 return r;
651 }
652
dd3efc09 653 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
f579559b 654 if (r < 0) {
3333d748
ZJS
655 log_error_link(link,
656 "Could not send rtnetlink message: %s", strerror(-r));
f579559b
TG
657 return r;
658 }
659
f882c247
TG
660 return 0;
661}
662
ef1ba606 663static int link_bridge_joined(Link *link) {
f882c247
TG
664 int r;
665
ef1ba606
TG
666 assert(link);
667 assert(link->state == LINK_STATE_JOINING_BRIDGE);
f5be5601 668 assert(link->network);
dd3efc09 669
f882c247 670 r = link_up(link);
ef1ba606
TG
671 if (r < 0) {
672 link_enter_failed(link);
673 return r;
674 }
f882c247 675
1746cf2a
TG
676 if (!link->network->dhcp)
677 return link_enter_set_addresses(link);
ef1ba606
TG
678
679 return 0;
02b59d57
TG
680}
681
682static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
683 Link *link = userdata;
684 int r;
685
1746cf2a 686 assert(link);
ef1ba606
TG
687 assert(link->state == LINK_STATE_JOINING_BRIDGE || link->state == LINK_STATE_FAILED);
688 assert(link->network);
02b59d57
TG
689
690 if (link->state == LINK_STATE_FAILED)
691 return 1;
692
693 r = sd_rtnl_message_get_errno(m);
ef1ba606 694 if (r < 0) {
3333d748
ZJS
695 log_struct_link(LOG_ERR, link,
696 "MESSAGE=%s: could not join bridge '%s': %s",
697 link->ifname, link->network->bridge->name, strerror(-r),
698 BRIDGE(link->network->bridge),
699 NULL);
ef1ba606
TG
700 link_enter_failed(link);
701 return 1;
3333d748 702 }
02b59d57 703
3333d748
ZJS
704 log_struct_link(LOG_DEBUG, link,
705 "MESSAGE=%s: joined bridge '%s'",
706 link->network->bridge->name,
707 BRIDGE(link->network->bridge),
708 NULL);
ab47d620 709
ef1ba606 710 link_bridge_joined(link);
02b59d57
TG
711
712 return 1;
713}
714
715static int link_enter_join_bridge(Link *link) {
716 int r;
717
718 assert(link);
719 assert(link->network);
ef1ba606 720 assert(link->state == _LINK_STATE_INVALID);
02b59d57 721
ef1ba606 722 link->state = LINK_STATE_JOINING_BRIDGE;
02b59d57 723
ef1ba606
TG
724 if (!link->network->bridge)
725 return link_bridge_joined(link);
02b59d57 726
3333d748
ZJS
727 log_struct_link(LOG_DEBUG, link,
728 "MESSAGE=%s: joining bridge '%s'",
729 link->network->bridge->name,
730 BRIDGE(link->network->bridge),
731 NULL);
39032b87 732 log_debug_link(link, "joining bridge");
449f7554 733
02b59d57 734 r = bridge_join(link->network->bridge, link, &bridge_handler);
dd3efc09 735 if (r < 0) {
3333d748
ZJS
736 log_struct_link(LOG_WARNING, link,
737 "MESSAGE=%s: could not join bridge '%s': %s",
738 link->network->bridge->name, strerror(-r),
739 BRIDGE(link->network->bridge),
740 NULL);
ef1ba606
TG
741 link_enter_failed(link);
742 return r;
743 }
744
745 return 0;
746}
747
748static int link_get_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
749 Link *link = userdata;
750 int r;
751
1746cf2a
TG
752 assert(link);
753
754 if (link->state == LINK_STATE_FAILED)
755 return 1;
756
ef1ba606
TG
757 r = sd_rtnl_message_get_errno(m);
758 if (r < 0) {
3333d748 759 log_warning_link(link, "could not get state: %s", strerror(-r));
ef1ba606
TG
760 link_enter_failed(link);
761 }
762
39032b87 763 log_debug_link(link, "got link state");
1746cf2a 764
5eb036ca
TG
765 link_update(link, m);
766
ef1ba606
TG
767 return 1;
768}
769
770static int link_get(Link *link) {
771 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
772 int r;
773
774 assert(link);
775 assert(link->manager);
776 assert(link->manager->rtnl);
777
39032b87 778 log_debug_link(link, "requesting link status");
449f7554 779
ef1ba606
TG
780 r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
781 if (r < 0) {
39032b87 782 log_error_link(link, "Could not allocate RTM_GETLINK message");
ef1ba606
TG
783 return r;
784 }
785
786 r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
787 if (r < 0) {
3333d748
ZJS
788 log_error_link(link,
789 "Could not send rtnetlink message: %s", strerror(-r));
ef1ba606 790 return r;
dd3efc09 791 }
02b59d57
TG
792
793 return 0;
794}
795
796int link_configure(Link *link) {
797 int r;
798
ef1ba606
TG
799 assert(link);
800 assert(link->network);
801 assert(link->state == _LINK_STATE_INVALID);
802
dd3efc09 803 r = link_get(link);
ef1ba606
TG
804 if (r < 0) {
805 link_enter_failed(link);
806 return r;
807 }
dd3efc09 808
1746cf2a 809 return link_enter_join_bridge(link);
f579559b 810}
dd3efc09 811
22936833
TG
812int link_update(Link *link, sd_rtnl_message *m) {
813 unsigned flags;
4f882b2a
TG
814 void *data;
815 uint16_t type;
22936833
TG
816 int r;
817
dd3efc09 818 assert(link);
22936833
TG
819 assert(m);
820
1746cf2a
TG
821 if (link->state == LINK_STATE_FAILED)
822 return 0;
823
22936833
TG
824 r = sd_rtnl_message_link_get_flags(m, &flags);
825 if (r < 0) {
4f882b2a 826 log_warning_link(link, "Could not get link flags");
22936833
TG
827 return r;
828 }
dd3efc09 829
4f882b2a 830 while (sd_rtnl_message_read(m, &type, &data) > 0) {
396945dc
TG
831 if (type == IFLA_MTU && link->network->dhcp &&
832 link->network->dhcp_mtu && !link->original_mtu) {
4f882b2a 833 link->original_mtu = *(uint16_t *) data;
396945dc
TG
834 log_debug_link(link, "saved original MTU: %" PRIu16,
835 link->original_mtu);
4f882b2a
TG
836 }
837 }
838
ff254138 839 return link_update_flags(link, flags);
dd3efc09 840}