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/>.
23 #include "network-internal.h"
24 #include "path-util.h"
25 #include "conf-files.h"
26 #include "conf-parser.h"
29 #define VLANID_MAX 4094
31 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
32 [NETDEV_KIND_BRIDGE] = "bridge",
33 [NETDEV_KIND_BOND] = "bond",
34 [NETDEV_KIND_VLAN] = "vlan",
35 [NETDEV_KIND_MACVLAN] = "macvlan",
36 [NETDEV_KIND_IPIP] = "ipip",
37 [NETDEV_KIND_GRE] = "gre",
38 [NETDEV_KIND_SIT] = "sit",
41 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
42 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
44 static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
45 [NETDEV_MACVLAN_MODE_PRIVATE] = "private",
46 [NETDEV_MACVLAN_MODE_VEPA] = "vepa",
47 [NETDEV_MACVLAN_MODE_BRIDGE] = "bridge",
48 [NETDEV_MACVLAN_MODE_PASSTHRU] = "passthru",
51 DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
52 DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode");
54 static void netdev_cancel_callbacks(NetDev *netdev) {
55 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
56 netdev_enslave_callback *callback;
61 rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
63 while ((callback = netdev->callbacks)) {
65 assert(callback->link);
66 assert(callback->callback);
67 assert(netdev->manager);
68 assert(netdev->manager->rtnl);
70 callback->callback(netdev->manager->rtnl, m, link);
73 LIST_REMOVE(callbacks, netdev->callbacks, callback);
78 static void netdev_free(NetDev *netdev) {
82 netdev_cancel_callbacks(netdev);
85 hashmap_remove(netdev->manager->netdevs, netdev->name);
87 free(netdev->filename);
89 free(netdev->description);
92 condition_free_list(netdev->match_host);
93 condition_free_list(netdev->match_virt);
94 condition_free_list(netdev->match_kernel);
95 condition_free_list(netdev->match_arch);
100 NetDev *netdev_unref(NetDev *netdev) {
101 if (netdev && (-- netdev->n_ref <= 0))
107 NetDev *netdev_ref(NetDev *netdev) {
109 assert_se(++ netdev->n_ref >= 2);
114 void netdev_drop(NetDev *netdev) {
115 if (!netdev || netdev->state == NETDEV_STATE_LINGER)
118 netdev->state = NETDEV_STATE_LINGER;
120 log_debug_netdev(netdev, "netdev removed");
122 netdev_cancel_callbacks(netdev);
124 netdev_unref(netdev);
129 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
136 netdev = hashmap_get(manager->netdevs, name);
147 static int netdev_enter_failed(NetDev *netdev) {
148 netdev->state = NETDEV_STATE_FAILED;
153 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
154 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
158 assert(netdev->state == NETDEV_STATE_READY);
159 assert(netdev->manager);
160 assert(netdev->manager->rtnl);
164 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
165 RTM_SETLINK, link->ifindex);
167 log_error_netdev(netdev,
168 "Could not allocate RTM_SETLINK message: %s",
173 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
175 log_error_netdev(netdev,
176 "Could not append IFLA_MASTER attribute: %s",
181 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
183 log_error_netdev(netdev,
184 "Could not send rtnetlink message: %s",
189 log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
194 static int netdev_enter_ready(NetDev *netdev) {
195 netdev_enslave_callback *callback;
198 assert(netdev->name);
200 if (netdev->state != NETDEV_STATE_CREATING)
203 netdev->state = NETDEV_STATE_READY;
205 log_info_netdev(netdev, "netdev ready");
207 LIST_FOREACH(callbacks, callback, netdev->callbacks) {
208 /* enslave the links that were attempted to be enslaved before the
210 netdev_enslave_ready(netdev, callback->link, callback->callback);
215 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
216 NetDev *netdev = userdata;
219 assert(netdev->state != _NETDEV_STATE_INVALID);
221 r = sd_rtnl_message_get_errno(m);
223 log_debug_netdev(netdev, "netdev exists, using existing");
225 log_warning_netdev(netdev, "netdev could not be greated: %s", strerror(-r));
234 int config_parse_tunnel_address(const char *unit,
235 const char *filename,
238 unsigned section_line,
245 unsigned char family = AF_INET;
253 r = net_parse_inaddr(rvalue, &family, n);
255 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
256 "Tunnel address is invalid, ignoring assignment: %s", rvalue);
262 static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
263 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
268 assert(!(netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN) ||
270 assert(netdev->name);
271 assert(netdev->manager);
272 assert(netdev->manager->rtnl);
274 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0);
276 log_error_netdev(netdev,
277 "Could not allocate RTM_NEWLINK message: %s",
283 r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
285 log_error_netdev(netdev,
286 "Could not append IFLA_LINK attribute: %s",
292 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->name);
294 log_error_netdev(netdev,
295 "Could not append IFLA_IFNAME attribute: %s",
301 r = sd_rtnl_message_append_u32(req, IFLA_MTU, netdev->mtu);
303 log_error_netdev(netdev,
304 "Could not append IFLA_MTU attribute: %s",
310 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
312 log_error_netdev(netdev,
313 "Could not open IFLA_LINKINFO container: %s",
318 kind = netdev_kind_to_string(netdev->kind);
320 log_error_netdev(netdev, "Invalid kind");
324 r = sd_rtnl_message_open_container_union(req, IFLA_INFO_DATA, kind);
326 log_error_netdev(netdev,
327 "Could not open IFLA_INFO_DATA container: %s",
332 if (netdev->vlanid <= VLANID_MAX) {
333 r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
335 log_error_netdev(netdev,
336 "Could not append IFLA_VLAN_ID attribute: %s",
342 if (netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
343 r = sd_rtnl_message_append_u32(req, IFLA_MACVLAN_MODE, netdev->macvlan_mode);
345 log_error_netdev(netdev,
346 "Could not append IFLA_MACVLAN_MODE attribute: %s",
352 r = sd_rtnl_message_close_container(req);
354 log_error_netdev(netdev,
355 "Could not close IFLA_INFO_DATA container %s",
360 r = sd_rtnl_message_close_container(req);
362 log_error_netdev(netdev,
363 "Could not close IFLA_LINKINFO container %s",
369 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
371 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
373 log_error_netdev(netdev,
374 "Could not send rtnetlink message: %s", strerror(-r));
378 log_debug_netdev(netdev, "creating netdev");
380 netdev->state = NETDEV_STATE_CREATING;
385 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
388 if (netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN)
389 return netdev_create(netdev, link, callback);
391 if(netdev->kind == NETDEV_KIND_IPIP ||
392 netdev->kind == NETDEV_KIND_GRE ||
393 netdev->kind == NETDEV_KIND_SIT)
394 return netdev_create_tunnel(link, netdev_create_handler);
396 if (netdev->state == NETDEV_STATE_READY) {
397 r = netdev_enslave_ready(netdev, link, callback);
401 /* the netdev is not yet read, save this request for when it is*/
402 netdev_enslave_callback *cb;
404 cb = new0(netdev_enslave_callback, 1);
408 cb->callback = callback;
411 LIST_PREPEND(callbacks, netdev->callbacks, cb);
417 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
427 r = sd_rtnl_message_get_type(message, &type);
429 log_error_netdev(netdev, "Could not get rtnl message type");
433 if (type != RTM_NEWLINK) {
434 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
438 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
440 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
441 netdev_enter_failed(netdev);
443 } else if (ifindex <= 0) {
444 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
445 netdev_enter_failed(netdev);
450 if (netdev->ifindex > 0) {
451 if (netdev->ifindex != ifindex) {
452 log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
453 ifindex, netdev->ifindex);
454 netdev_enter_failed(netdev);
457 /* ifindex already set to the same for this netdev */
461 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
463 log_error_netdev(netdev, "Could not get IFNAME");
467 if (!streq(netdev->name, received_name)) {
468 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
470 netdev_enter_failed(netdev);
474 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
476 log_error_netdev(netdev, "Could not get LINKINFO");
480 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
482 log_error_netdev(netdev, "Could not get KIND");
486 r = sd_rtnl_message_exit_container(message);
488 log_error_netdev(netdev, "Could not exit container");
492 kind = netdev_kind_to_string(netdev->kind);
494 log_error_netdev(netdev, "Could not get kind");
495 netdev_enter_failed(netdev);
499 if (!streq(kind, received_kind)) {
500 log_error_netdev(netdev, "Received newlink with wrong KIND %s, "
501 "expected %s", received_kind, kind);
502 netdev_enter_failed(netdev);
506 netdev->ifindex = ifindex;
508 netdev_enter_ready(netdev);
513 static int netdev_load_one(Manager *manager, const char *filename) {
514 _cleanup_netdev_unref_ NetDev *netdev = NULL;
515 _cleanup_fclose_ FILE *file = NULL;
521 if (null_or_empty_path(filename)) {
522 log_debug("skipping empty file: %s", filename);
526 file = fopen(filename, "re");
534 netdev = new0(NetDev, 1);
539 netdev->manager = manager;
540 netdev->state = _NETDEV_STATE_INVALID;
541 netdev->kind = _NETDEV_KIND_INVALID;
542 netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
543 netdev->vlanid = VLANID_MAX + 1;
545 r = config_parse(NULL, filename, file, "Match\0NetDev\0VLAN\0MACVLAN\0Tunnel\0",
546 config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
547 false, false, netdev);
549 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
553 if (netdev->kind == _NETDEV_KIND_INVALID) {
554 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
559 log_warning("NetDev without Name configured in %s. Ignoring", filename);
563 if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid > VLANID_MAX) {
564 log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
568 if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
569 log_warning("VLAN Id configured for a %s in %s. Ignoring",
570 netdev_kind_to_string(netdev->kind), filename);
574 if (netdev->kind != NETDEV_KIND_MACVLAN &&
575 netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
576 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
577 netdev_kind_to_string(netdev->kind), filename);
581 netdev->filename = strdup(filename);
582 if (!netdev->filename)
585 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
586 netdev->match_host, netdev->match_virt,
587 netdev->match_kernel, netdev->match_arch,
588 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
591 r = hashmap_put(netdev->manager->netdevs, netdev->name, netdev);
595 LIST_HEAD_INIT(netdev->callbacks);
597 if (netdev->kind != NETDEV_KIND_VLAN &&
598 netdev->kind != NETDEV_KIND_MACVLAN &&
599 netdev->kind != NETDEV_KIND_IPIP &&
600 netdev->kind != NETDEV_KIND_GRE &&
601 netdev->kind != NETDEV_KIND_SIT) {
602 r = netdev_create(netdev, NULL, NULL);
607 log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
614 int netdev_load(Manager *manager) {
621 while ((netdev = hashmap_first(manager->netdevs)))
622 netdev_unref(netdev);
624 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
626 log_error("Failed to enumerate netdev files: %s", strerror(-r));
630 STRV_FOREACH_BACKWARDS(f, files) {
631 r = netdev_load_one(manager, *f);