]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-link.c
networkd: add DHCPv4 support
[thirdparty/systemd.git] / src / network / networkd-link.c
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
29 int link_new(Manager *manager, struct udev_device *device, Link **ret) {
30 _cleanup_link_free_ Link *link = NULL;
31 const char *mac;
32 struct ether_addr *mac_addr;
33 const char *ifname;
34 int r;
35
36 assert(device);
37 assert(ret);
38
39 link = new0(Link, 1);
40 if (!link)
41 return -ENOMEM;
42
43 link->manager = manager;
44 link->state = _LINK_STATE_INVALID;
45
46 link->ifindex = udev_device_get_ifindex(device);
47 if (link->ifindex <= 0)
48 return -EINVAL;
49
50 mac = udev_device_get_sysattr_value(device, "address");
51 if (mac) {
52 mac_addr = ether_aton(mac);
53 if (mac_addr)
54 memcpy(&link->mac, mac_addr, sizeof(struct ether_addr));
55 }
56
57 ifname = udev_device_get_sysname(device);
58 link->ifname = strdup(ifname);
59
60 r = hashmap_put(manager->links, &link->ifindex, link);
61 if (r < 0)
62 return r;
63
64 *ret = link;
65 link = NULL;
66
67 return 0;
68 }
69
70 void link_free(Link *link) {
71 if (!link)
72 return;
73
74 assert(link->manager);
75
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
85 hashmap_remove(link->manager->links, &link->ifindex);
86
87 free(link->ifname);
88
89 free(link);
90 }
91
92 int link_add(Manager *m, struct udev_device *device) {
93 Link *link;
94 Network *network;
95 int r;
96 uint64_t ifindex;
97 const char *devtype;
98
99 assert(m);
100 assert(device);
101
102 ifindex = udev_device_get_ifindex(device);
103 link = hashmap_get(m->links, &ifindex);
104 if (link)
105 return 0;
106
107 r = link_new(m, device, &link);
108 if (r < 0) {
109 log_error("Could not create link: %s", strerror(-r));
110 return r;
111 }
112
113 devtype = udev_device_get_devtype(device);
114 if (streq_ptr(devtype, "bridge")) {
115 r = bridge_set_link(m, link);
116 if (r < 0)
117 return r == -ENOENT ? 0 : r;
118 }
119
120 r = network_get(m, device, &network);
121 if (r < 0)
122 return r == -ENOENT ? 0 : r;
123
124 r = network_apply(m, network, link);
125 if (r < 0)
126 return r;
127
128 return 0;
129 }
130
131 static int link_enter_configured(Link *link) {
132 assert(link);
133 assert(link->state == LINK_STATE_SETTING_ROUTES);
134
135 log_info("Link '%s' configured", link->ifname);
136
137 link->state = LINK_STATE_CONFIGURED;
138
139 return 0;
140 }
141
142 static void link_enter_failed(Link *link) {
143 assert(link);
144
145 link->state = LINK_STATE_FAILED;
146 }
147
148 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
149 Link *link = userdata;
150 int r;
151
152 assert(link->route_messages > 0);
153 assert(link->state == LINK_STATE_SETTING_ADDRESSES ||
154 link->state == LINK_STATE_SETTING_ROUTES ||
155 link->state == LINK_STATE_FAILED);
156
157 link->route_messages --;
158
159 if (link->state == LINK_STATE_FAILED)
160 return 1;
161
162 r = sd_rtnl_message_get_errno(m);
163 if (r < 0 && r != -EEXIST)
164 log_warning("Could not set route on interface '%s': %s",
165 link->ifname, strerror(-r));
166
167 /* we might have received an old reply after moving back to SETTING_ADDRESSES,
168 * ignore it */
169 if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
170 log_info("Routes set for link '%s'", link->ifname);
171 link_enter_configured(link);
172 }
173
174 return 1;
175 }
176
177 static int link_enter_set_routes(Link *link) {
178 Route *route;
179 int r;
180
181 assert(link);
182 assert(link->network);
183 assert(link->state == LINK_STATE_SETTING_ADDRESSES);
184
185 link->state = LINK_STATE_SETTING_ROUTES;
186
187 if (!link->network->static_routes && !link->dhcp_route)
188 return link_enter_configured(link);
189
190 LIST_FOREACH(static_routes, route, link->network->static_routes) {
191 r = route_configure(route, link, &route_handler);
192 if (r < 0) {
193 log_warning("Could not set routes for link '%s'", link->ifname);
194 link_enter_failed(link);
195 return r;
196 }
197
198 link->route_messages ++;
199 }
200
201 if (link->dhcp_route) {
202 r = route_configure(link->dhcp_route, link, &route_handler);
203 if (r < 0) {
204 log_warning("Could not set routes for link '%s'", link->ifname);
205 link_enter_failed(link);
206 return r;
207 }
208
209 link->route_messages ++;
210 }
211
212 return 0;
213 }
214
215 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
216 Link *link = userdata;
217 int r;
218
219 assert(m);
220 assert(link);
221 assert(link->ifname);
222 assert(link->addr_messages > 0);
223 assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
224
225 link->addr_messages --;
226
227 if (link->state == LINK_STATE_FAILED)
228 return 1;
229
230 r = sd_rtnl_message_get_errno(m);
231 if (r < 0 && r != -EEXIST)
232 log_warning("Could not set address on interface '%s': %s",
233 link->ifname, strerror(-r));
234
235 if (link->addr_messages == 0) {
236 log_info("Addresses set for link '%s'", link->ifname);
237 link_enter_set_routes(link);
238 }
239
240 return 1;
241 }
242
243 static int link_enter_set_addresses(Link *link) {
244 Address *address;
245 int r;
246
247 assert(link);
248 assert(link->network);
249 assert(link->state != _LINK_STATE_INVALID);
250
251 link->state = LINK_STATE_SETTING_ADDRESSES;
252
253 if (!link->network->static_addresses && !link->dhcp_address)
254 return link_enter_set_routes(link);
255
256 LIST_FOREACH(static_addresses, address, link->network->static_addresses) {
257 r = address_configure(address, link, &address_handler);
258 if (r < 0) {
259 log_warning("Could not set addresses for link '%s'", link->ifname);
260 link_enter_failed(link);
261 return r;
262 }
263
264 link->addr_messages ++;
265 }
266
267 if (link->dhcp_address) {
268 r = address_configure(link->dhcp_address, link, &address_handler);
269 if (r < 0) {
270 log_warning("Could not set addresses for link '%s'", link->ifname);
271 link_enter_failed(link);
272 return r;
273 }
274
275 link->addr_messages ++;
276 }
277
278 return 0;
279 }
280
281 static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
282 Link *link = userdata;
283 int r;
284
285 r = sd_rtnl_message_get_errno(m);
286 if (r < 0) {
287 log_warning("Could not bring up interface '%s': %s",
288 link->ifname, strerror(-r));
289 link_enter_failed(link);
290 }
291
292 return 1;
293 }
294
295 static int link_up(Link *link) {
296 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
297 int r;
298
299 assert(link);
300 assert(link->manager);
301 assert(link->manager->rtnl);
302
303 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
304 if (r < 0) {
305 log_error("Could not allocate RTM_SETLINK message");
306 return r;
307 }
308
309 r = sd_rtnl_message_link_set_flags(req, IFF_UP);
310 if (r < 0) {
311 log_error("Could not set link flags");
312 return r;
313 }
314
315 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
316 if (r < 0) {
317 log_error("Could not send rtnetlink message: %s", strerror(-r));
318 return r;
319 }
320
321 return 0;
322 }
323
324 static int link_bridge_joined(Link *link) {
325 int r;
326
327 assert(link);
328 assert(link->state == LINK_STATE_JOINING_BRIDGE);
329 assert(link->network);
330
331 r = link_up(link);
332 if (r < 0) {
333 link_enter_failed(link);
334 return r;
335 }
336
337 if (!link->network->dhcp) {
338 r = link_enter_set_addresses(link);
339 if (r < 0)
340 link_enter_failed(link);
341 return r;
342 }
343
344 return 0;
345 }
346
347 static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
348 Link *link = userdata;
349 int r;
350
351 assert(link->state == LINK_STATE_JOINING_BRIDGE || link->state == LINK_STATE_FAILED);
352 assert(link->network);
353
354 if (link->state == LINK_STATE_FAILED)
355 return 1;
356
357 r = sd_rtnl_message_get_errno(m);
358 if (r < 0) {
359 log_warning("Could not join interface '%s' to bridge '%s': %s",
360 link->ifname, link->network->bridge->name, strerror(-r));
361 link_enter_failed(link);
362 return 1;
363 } else
364 log_info("Join interface '%s' to bridge: %s",
365 link->ifname, link->network->bridge->name);
366
367 link_bridge_joined(link);
368
369 return 1;
370 }
371
372 static int link_enter_join_bridge(Link *link) {
373 int r;
374
375 assert(link);
376 assert(link->network);
377 assert(link->state == _LINK_STATE_INVALID);
378
379 link->state = LINK_STATE_JOINING_BRIDGE;
380
381 if (!link->network->bridge)
382 return link_bridge_joined(link);
383
384 r = bridge_join(link->network->bridge, link, &bridge_handler);
385 if (r < 0) {
386 log_warning("Could not join link '%s' to bridge '%s'", link->ifname,
387 link->network->bridge->name);
388 link_enter_failed(link);
389 return r;
390 }
391
392 return 0;
393 }
394
395 static int link_get_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
396 Link *link = userdata;
397 int r;
398
399 r = sd_rtnl_message_get_errno(m);
400 if (r < 0) {
401 log_warning("Could not get state of interface '%s': %s",
402 link->ifname, strerror(-r));
403 link_enter_failed(link);
404 }
405
406 return 1;
407 }
408
409 static int link_get(Link *link) {
410 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
411 int r;
412
413 assert(link);
414 assert(link->manager);
415 assert(link->manager->rtnl);
416
417 r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
418 if (r < 0) {
419 log_error("Could not allocate RTM_GETLINK message");
420 return r;
421 }
422
423 r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
424 if (r < 0) {
425 log_error("Could not send rtnetlink message: %s", strerror(-r));
426 return r;
427 }
428
429 return 0;
430 }
431
432 int link_configure(Link *link) {
433 int r;
434
435 assert(link);
436 assert(link->network);
437 assert(link->state == _LINK_STATE_INVALID);
438
439 r = link_get(link);
440 if (r < 0) {
441 link_enter_failed(link);
442 return r;
443 }
444
445 r = link_enter_join_bridge(link);
446 if (r < 0)
447 return r;
448
449 return 0;
450 }
451
452 static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
453 Link *link = userdata;
454 int r;
455
456 assert(m);
457 assert(link);
458 assert(link->ifname);
459
460 if (link->state == LINK_STATE_FAILED)
461 return 1;
462
463 r = sd_rtnl_message_get_errno(m);
464 if (r < 0 && r != -EEXIST)
465 log_warning("Could not drop address from interface '%s': %s",
466 link->ifname, strerror(-r));
467
468 return 1;
469 }
470
471 static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
472 Link *link = userdata;
473 struct in_addr address;
474 struct in_addr netmask;
475 struct in_addr gateway;
476 int prefixlen;
477 int r;
478
479 if (link->state == LINK_STATE_FAILED)
480 return;
481
482 if (event < 0) {
483 log_warning("DHCP error: %s", strerror(-event));
484 link_enter_failed(link);
485 return;
486 }
487
488 if (event == DHCP_EVENT_NO_LEASE)
489 log_info("IP address in use.");
490
491 if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_EXPIRED ||
492 event == DHCP_EVENT_STOP) {
493 address_drop(link->dhcp_address, link, address_drop_handler);
494
495 address_free(link->dhcp_address);
496 link->dhcp_address = NULL;
497
498 route_free(link->dhcp_route);
499 link->dhcp_route = NULL;
500 }
501
502 r = sd_dhcp_client_get_address(client, &address);
503 if (r < 0) {
504 log_warning("DHCP error: no address");
505 link_enter_failed(link);
506 return;
507 }
508
509 r = sd_dhcp_client_get_netmask(client, &netmask);
510 if (r < 0) {
511 log_warning("DHCP error: no netmask");
512 link_enter_failed(link);
513 return;
514 }
515
516 prefixlen = sd_dhcp_client_prefixlen(&netmask);
517 if (prefixlen < 0) {
518 log_warning("DHCP error: no prefixlen");
519 link_enter_failed(link);
520 return;
521 }
522
523 r = sd_dhcp_client_get_router(client, &gateway);
524 if (r < 0) {
525 log_warning("DHCP error: no router");
526 link_enter_failed(link);
527 return;
528 }
529
530 if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_IP_ACQUIRE) {
531 _cleanup_address_free_ Address *addr = NULL;
532 _cleanup_route_free_ Route *rt = NULL;
533
534 log_info("Received config over DHCPv4");
535
536 r = address_new_dynamic(&addr);
537 if (r < 0) {
538 log_error("Could not allocate address");
539 link_enter_failed(link);
540 return;
541 }
542
543 addr->family = AF_INET;
544 addr->in_addr.in = address;
545 addr->prefixlen = prefixlen;
546 addr->netmask = netmask;
547
548 r = route_new_dynamic(&rt);
549 if (r < 0) {
550 log_error("Could not allocate route");
551 link_enter_failed(link);
552 return;
553 }
554
555 rt->family = AF_INET;
556 rt->in_addr.in = gateway;
557
558 link->dhcp_address = addr;
559 link->dhcp_route = rt;
560 addr = NULL;
561 rt = NULL;
562
563 link_enter_set_addresses(link);
564 }
565
566 return;
567 }
568
569 static int link_acquire_conf(Link *link) {
570 int r;
571
572 assert(link);
573 assert(link->network);
574 assert(link->network->dhcp);
575 assert(link->manager);
576 assert(link->manager->event);
577
578 if (!link->dhcp) {
579 link->dhcp = sd_dhcp_client_new(link->manager->event);
580 if (!link->dhcp)
581 return -ENOMEM;
582
583 r = sd_dhcp_client_set_index(link->dhcp, link->ifindex);
584 if (r < 0)
585 return r;
586
587 r = sd_dhcp_client_set_mac(link->dhcp, &link->mac);
588 if (r < 0)
589 return r;
590
591 r = sd_dhcp_client_set_callback(link->dhcp, dhcp_handler, link);
592 if (r < 0)
593 return r;
594 }
595
596 r = sd_dhcp_client_start(link->dhcp);
597 if (r < 0)
598 return r;
599
600 return 0;
601 }
602
603 int link_update(Link *link, sd_rtnl_message *m) {
604 unsigned flags;
605 int r;
606
607 assert(link);
608 assert(m);
609
610 r = sd_rtnl_message_link_get_flags(m, &flags);
611 if (r < 0) {
612 log_warning("Could not get link flags of '%s'", link->ifname);
613 return r;
614 }
615
616 if (link->flags & IFF_UP && !(flags & IFF_UP))
617 log_info("Interface '%s' is down", link->ifname);
618 else if (!(link->flags & IFF_UP) && flags & IFF_UP)
619 log_info("Interface '%s' is up", link->ifname);
620
621 if (link->flags & IFF_LOWER_UP && !(flags & IFF_LOWER_UP)) {
622 log_info("Interface '%s' is disconnected", link->ifname);
623
624 if (link->network->dhcp) {
625 r = sd_dhcp_client_stop(link->dhcp);
626 if (r < 0) {
627 link_enter_failed(link);
628 return r;
629 }
630 }
631 } else if (!(link->flags & IFF_LOWER_UP) && flags & IFF_LOWER_UP) {
632 log_info("Interface '%s' is connected", link->ifname);
633
634 if (link->network->dhcp) {
635 r = link_acquire_conf(link);
636 if (r < 0) {
637 link_enter_failed(link);
638 return r;
639 }
640 }
641 }
642
643 link->flags = flags;
644
645 return 0;
646 }