1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
25 #include "network-internal.h"
26 #include "path-util.h"
27 #include "conf-files.h"
28 #include "conf-parser.h"
31 #define VLANID_MAX 4094
33 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
34 [NETDEV_KIND_BRIDGE] = "bridge",
35 [NETDEV_KIND_BOND] = "bond",
36 [NETDEV_KIND_VLAN] = "vlan",
37 [NETDEV_KIND_MACVLAN] = "macvlan",
38 [NETDEV_KIND_IPIP] = "ipip",
39 [NETDEV_KIND_GRE] = "gre",
40 [NETDEV_KIND_SIT] = "sit",
43 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
44 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
46 static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
47 [NETDEV_MACVLAN_MODE_PRIVATE] = "private",
48 [NETDEV_MACVLAN_MODE_VEPA] = "vepa",
49 [NETDEV_MACVLAN_MODE_BRIDGE] = "bridge",
50 [NETDEV_MACVLAN_MODE_PASSTHRU] = "passthru",
53 DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
54 DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode");
56 static void netdev_cancel_callbacks(NetDev *netdev) {
57 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
58 netdev_enslave_callback *callback;
63 rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
65 while ((callback = netdev->callbacks)) {
67 assert(callback->link);
68 assert(callback->callback);
69 assert(netdev->manager);
70 assert(netdev->manager->rtnl);
72 callback->callback(netdev->manager->rtnl, m, link);
75 LIST_REMOVE(callbacks, netdev->callbacks, callback);
80 static void netdev_free(NetDev *netdev) {
84 netdev_cancel_callbacks(netdev);
87 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
89 free(netdev->filename);
91 free(netdev->description);
94 condition_free_list(netdev->match_host);
95 condition_free_list(netdev->match_virt);
96 condition_free_list(netdev->match_kernel);
97 condition_free_list(netdev->match_arch);
102 NetDev *netdev_unref(NetDev *netdev) {
103 if (netdev && (-- netdev->n_ref <= 0))
109 NetDev *netdev_ref(NetDev *netdev) {
111 assert_se(++ netdev->n_ref >= 2);
116 void netdev_drop(NetDev *netdev) {
117 if (!netdev || netdev->state == NETDEV_STATE_LINGER)
120 netdev->state = NETDEV_STATE_LINGER;
122 log_debug_netdev(netdev, "netdev removed");
124 netdev_cancel_callbacks(netdev);
126 netdev_unref(netdev);
131 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
138 netdev = hashmap_get(manager->netdevs, name);
149 static int netdev_enter_failed(NetDev *netdev) {
150 netdev->state = NETDEV_STATE_FAILED;
155 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
156 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
160 assert(netdev->state == NETDEV_STATE_READY);
161 assert(netdev->manager);
162 assert(netdev->manager->rtnl);
166 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
167 RTM_SETLINK, link->ifindex);
169 log_error_netdev(netdev,
170 "Could not allocate RTM_SETLINK message: %s",
175 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
177 log_error_netdev(netdev,
178 "Could not append IFLA_MASTER attribute: %s",
183 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
185 log_error_netdev(netdev,
186 "Could not send rtnetlink message: %s",
191 log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
196 static int netdev_enter_ready(NetDev *netdev) {
197 netdev_enslave_callback *callback;
200 assert(netdev->ifname);
202 if (netdev->state != NETDEV_STATE_CREATING)
205 netdev->state = NETDEV_STATE_READY;
207 log_info_netdev(netdev, "netdev ready");
209 LIST_FOREACH(callbacks, callback, netdev->callbacks) {
210 /* enslave the links that were attempted to be enslaved before the
212 netdev_enslave_ready(netdev, callback->link, callback->callback);
217 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
218 NetDev *netdev = userdata;
221 assert(netdev->state != _NETDEV_STATE_INVALID);
223 r = sd_rtnl_message_get_errno(m);
225 log_debug_netdev(netdev, "netdev exists, using existing");
227 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
236 int config_parse_tunnel_address(const char *unit,
237 const char *filename,
240 unsigned section_line,
247 unsigned char family = AF_INET;
255 r = net_parse_inaddr(rvalue, &family, n);
257 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
258 "Tunnel address is invalid, ignoring assignment: %s", rvalue);
264 static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
265 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
270 assert(!(netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN) ||
272 assert(netdev->ifname);
273 assert(netdev->manager);
274 assert(netdev->manager->rtnl);
276 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0);
278 log_error_netdev(netdev,
279 "Could not allocate RTM_NEWLINK message: %s",
285 r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
287 log_error_netdev(netdev,
288 "Could not append IFLA_LINK attribute: %s",
294 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->ifname);
296 log_error_netdev(netdev,
297 "Could not append IFLA_IFNAME attribute: %s",
303 r = sd_rtnl_message_append_u32(req, IFLA_MTU, netdev->mtu);
305 log_error_netdev(netdev,
306 "Could not append IFLA_MTU attribute: %s",
312 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
314 log_error_netdev(netdev,
315 "Could not open IFLA_LINKINFO container: %s",
320 kind = netdev_kind_to_string(netdev->kind);
322 log_error_netdev(netdev, "Invalid kind");
326 r = sd_rtnl_message_open_container_union(req, IFLA_INFO_DATA, kind);
328 log_error_netdev(netdev,
329 "Could not open IFLA_INFO_DATA container: %s",
334 if (netdev->vlanid <= VLANID_MAX) {
335 r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
337 log_error_netdev(netdev,
338 "Could not append IFLA_VLAN_ID attribute: %s",
344 if (netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
345 r = sd_rtnl_message_append_u32(req, IFLA_MACVLAN_MODE, netdev->macvlan_mode);
347 log_error_netdev(netdev,
348 "Could not append IFLA_MACVLAN_MODE attribute: %s",
354 r = sd_rtnl_message_close_container(req);
356 log_error_netdev(netdev,
357 "Could not close IFLA_INFO_DATA container %s",
362 r = sd_rtnl_message_close_container(req);
364 log_error_netdev(netdev,
365 "Could not close IFLA_LINKINFO container %s",
371 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
373 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
375 log_error_netdev(netdev,
376 "Could not send rtnetlink message: %s", strerror(-r));
380 log_debug_netdev(netdev, "creating netdev");
382 netdev->state = NETDEV_STATE_CREATING;
387 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
390 if (netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN)
391 return netdev_create(netdev, link, callback);
393 if(netdev->kind == NETDEV_KIND_IPIP ||
394 netdev->kind == NETDEV_KIND_GRE ||
395 netdev->kind == NETDEV_KIND_SIT)
396 return netdev_create_tunnel(link, netdev_create_handler);
398 if (netdev->state == NETDEV_STATE_READY) {
399 r = netdev_enslave_ready(netdev, link, callback);
403 /* the netdev is not yet read, save this request for when it is*/
404 netdev_enslave_callback *cb;
406 cb = new0(netdev_enslave_callback, 1);
410 cb->callback = callback;
413 LIST_PREPEND(callbacks, netdev->callbacks, cb);
419 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
429 r = sd_rtnl_message_get_type(message, &type);
431 log_error_netdev(netdev, "Could not get rtnl message type");
435 if (type != RTM_NEWLINK) {
436 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
440 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
442 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
443 netdev_enter_failed(netdev);
445 } else if (ifindex <= 0) {
446 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
447 netdev_enter_failed(netdev);
452 if (netdev->ifindex > 0) {
453 if (netdev->ifindex != ifindex) {
454 log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
455 ifindex, netdev->ifindex);
456 netdev_enter_failed(netdev);
459 /* ifindex already set to the same for this netdev */
463 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
465 log_error_netdev(netdev, "Could not get IFNAME");
469 if (!streq(netdev->ifname, received_name)) {
470 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
472 netdev_enter_failed(netdev);
476 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
478 log_error_netdev(netdev, "Could not get LINKINFO");
482 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
484 log_error_netdev(netdev, "Could not get KIND");
488 r = sd_rtnl_message_exit_container(message);
490 log_error_netdev(netdev, "Could not exit container");
494 kind = netdev_kind_to_string(netdev->kind);
496 log_error_netdev(netdev, "Could not get kind");
497 netdev_enter_failed(netdev);
501 if (!streq(kind, received_kind)) {
502 log_error_netdev(netdev, "Received newlink with wrong KIND %s, "
503 "expected %s", received_kind, kind);
504 netdev_enter_failed(netdev);
508 netdev->ifindex = ifindex;
510 log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
512 netdev_enter_ready(netdev);
517 static int netdev_load_one(Manager *manager, const char *filename) {
518 _cleanup_netdev_unref_ NetDev *netdev = NULL;
519 _cleanup_fclose_ FILE *file = NULL;
525 if (null_or_empty_path(filename)) {
526 log_debug("skipping empty file: %s", filename);
530 file = fopen(filename, "re");
538 netdev = new0(NetDev, 1);
543 netdev->manager = manager;
544 netdev->state = _NETDEV_STATE_INVALID;
545 netdev->kind = _NETDEV_KIND_INVALID;
546 netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
547 netdev->vlanid = VLANID_MAX + 1;
549 r = config_parse(NULL, filename, file, "Match\0NetDev\0VLAN\0MACVLAN\0Tunnel\0",
550 config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
551 false, false, netdev);
553 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
557 if (netdev->kind == _NETDEV_KIND_INVALID) {
558 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
562 if (!netdev->ifname) {
563 log_warning("NetDev without Name configured in %s. Ignoring", filename);
567 if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid > VLANID_MAX) {
568 log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
572 if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
573 log_warning("VLAN Id configured for a %s in %s. Ignoring",
574 netdev_kind_to_string(netdev->kind), filename);
578 if (netdev->kind != NETDEV_KIND_MACVLAN &&
579 netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
580 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
581 netdev_kind_to_string(netdev->kind), filename);
585 netdev->filename = strdup(filename);
586 if (!netdev->filename)
589 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
590 netdev->match_host, netdev->match_virt,
591 netdev->match_kernel, netdev->match_arch,
592 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
595 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
599 LIST_HEAD_INIT(netdev->callbacks);
601 if (netdev->kind != NETDEV_KIND_VLAN &&
602 netdev->kind != NETDEV_KIND_MACVLAN &&
603 netdev->kind != NETDEV_KIND_IPIP &&
604 netdev->kind != NETDEV_KIND_GRE &&
605 netdev->kind != NETDEV_KIND_SIT) {
606 r = netdev_create(netdev, NULL, NULL);
611 log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
618 int netdev_load(Manager *manager) {
625 while ((netdev = hashmap_first(manager->netdevs)))
626 netdev_unref(netdev);
628 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
630 log_error("Failed to enumerate netdev files: %s", strerror(-r));
634 STRV_FOREACH_BACKWARDS(f, files) {
635 r = netdev_load_one(manager, *f);