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",
38 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
39 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
41 static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
42 [NETDEV_MACVLAN_MODE_PRIVATE] = "private",
43 [NETDEV_MACVLAN_MODE_VEPA] = "vepa",
44 [NETDEV_MACVLAN_MODE_BRIDGE] = "bridge",
45 [NETDEV_MACVLAN_MODE_PASSTHRU] = "passthru",
48 DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
49 DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode");
51 void netdev_free(NetDev *netdev) {
52 netdev_enslave_callback *callback;
57 while ((callback = netdev->callbacks)) {
58 LIST_REMOVE(callbacks, netdev->callbacks, callback);
63 hashmap_remove(netdev->manager->netdevs, netdev->name);
65 free(netdev->filename);
67 free(netdev->description);
73 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
80 netdev = hashmap_get(manager->netdevs, name);
91 static int netdev_enter_failed(NetDev *netdev) {
92 netdev->state = NETDEV_STATE_FAILED;
97 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
98 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
102 assert(netdev->state == NETDEV_STATE_READY);
103 assert(netdev->manager);
104 assert(netdev->manager->rtnl);
108 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
109 RTM_SETLINK, link->ifindex);
111 log_error_netdev(netdev,
112 "Could not allocate RTM_SETLINK message: %s",
117 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
119 log_error_netdev(netdev,
120 "Could not append IFLA_MASTER attribute: %s",
125 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
127 log_error_netdev(netdev,
128 "Could not send rtnetlink message: %s",
133 log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
138 static int netdev_enter_ready(NetDev *netdev) {
139 netdev_enslave_callback *callback;
142 assert(netdev->name);
144 netdev->state = NETDEV_STATE_READY;
146 log_info_netdev(netdev, "netdev ready");
148 LIST_FOREACH(callbacks, callback, netdev->callbacks) {
149 /* enslave the links that were attempted to be enslaved befor the
151 netdev_enslave_ready(netdev, callback->link, callback->callback);
157 static int netdev_getlink_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
159 NetDev *netdev = userdata;
164 if (netdev->state == NETDEV_STATE_FAILED)
167 r = sd_rtnl_message_get_errno(m);
169 log_struct_netdev(LOG_ERR, netdev,
170 "MESSAGE=%s: could not get link: %s",
171 netdev->name, strerror(-r),
177 netdev_set_ifindex(netdev, m);
182 static int netdev_getlink(NetDev *netdev) {
183 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
186 assert(netdev->manager);
187 assert(netdev->manager->rtnl);
188 assert(netdev->name);
190 log_debug_netdev(netdev, "requesting netdev status");
192 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
195 log_error_netdev(netdev, "Could not allocate RTM_GETLINK message");
199 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->name);
201 log_error_netdev(netdev, "Colud not append ifname to message: %s",
206 r = sd_rtnl_call_async(netdev->manager->rtnl, req, netdev_getlink_handler,
209 log_error_netdev(netdev,
210 "Could not send rtnetlink message: %s", strerror(-r));
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 r = netdev_getlink(netdev);
228 log_warning_netdev(netdev, "netdev failed: %s", strerror(-r));
229 netdev_enter_failed(netdev);
237 static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
238 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
243 assert(!(netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN) ||
245 assert(netdev->name);
246 assert(netdev->manager);
247 assert(netdev->manager->rtnl);
249 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0);
251 log_error_netdev(netdev,
252 "Could not allocate RTM_NEWLINK message: %s",
258 r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
260 log_error_netdev(netdev,
261 "Could not append IFLA_LINK attribute: %s",
267 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->name);
269 log_error_netdev(netdev,
270 "Could not append IFLA_IFNAME attribute: %s",
275 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
277 log_error_netdev(netdev,
278 "Could not open IFLA_LINKINFO container: %s",
283 kind = netdev_kind_to_string(netdev->kind);
285 log_error_netdev(netdev, "Invalid kind");
289 r = sd_rtnl_message_append_string(req, IFLA_INFO_KIND, kind);
291 log_error_netdev(netdev,
292 "Could not append IFLA_INFO_KIND attribute: %s",
297 if (netdev->vlanid <= VLANID_MAX || netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
298 r = sd_rtnl_message_open_container(req, IFLA_INFO_DATA);
300 log_error_netdev(netdev,
301 "Could not open IFLA_INFO_DATA container: %s",
306 if (netdev->vlanid <= VLANID_MAX) {
307 r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
309 log_error_netdev(netdev,
310 "Could not append IFLA_VLAN_ID attribute: %s",
316 if (netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
317 r = sd_rtnl_message_append_u32(req, IFLA_MACVLAN_MODE, netdev->macvlan_mode);
319 log_error_netdev(netdev,
320 "Could not append IFLA_MACVLAN_MODE attribute: %s",
326 r = sd_rtnl_message_close_container(req);
328 log_error_netdev(netdev,
329 "Could not close IFLA_INFO_DATA container %s",
335 r = sd_rtnl_message_close_container(req);
337 log_error_netdev(netdev,
338 "Could not close IFLA_LINKINFO container %s",
344 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
346 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
348 log_error_netdev(netdev,
349 "Could not send rtnetlink message: %s", strerror(-r));
353 log_debug_netdev(netdev, "creating netdev");
355 netdev->state = NETDEV_STATE_CREATING;
360 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
361 if (netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN)
362 return netdev_create(netdev, link, callback);
364 if (netdev->state == NETDEV_STATE_READY) {
365 netdev_enslave_ready(netdev, link, callback);
367 /* the netdev is not yet read, save this request for when it is*/
368 netdev_enslave_callback *cb;
370 cb = new0(netdev_enslave_callback, 1);
374 cb->callback = callback;
377 LIST_PREPEND(callbacks, netdev->callbacks, cb);
383 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
391 kind = netdev_kind_to_string(netdev->kind);
393 log_error_netdev(netdev, "Could not get kind");
395 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
397 log_error_netdev(netdev, "Could not get LINKINFO");
401 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
403 log_error_netdev(netdev, "Could not get KIND");
407 if (!streq(kind, received_kind)) {
408 log_error_netdev(netdev, "Received newlink with wrong KIND");
409 netdev_enter_failed(netdev);
413 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
415 log_struct_netdev(LOG_ERR, netdev,
416 "MESSAGE=%s: could not get ifindex: %s",
417 netdev->name, strerror(-r),
423 if (netdev->ifindex > 0) {
424 if (netdev->ifindex == ifindex)
430 netdev->ifindex = ifindex;
432 netdev_enter_ready(netdev);
437 static int netdev_load_one(Manager *manager, const char *filename) {
438 _cleanup_netdev_free_ NetDev *netdev = NULL;
439 _cleanup_fclose_ FILE *file = NULL;
445 file = fopen(filename, "re");
453 netdev = new0(NetDev, 1);
457 netdev->manager = manager;
458 netdev->state = _NETDEV_STATE_INVALID;
459 netdev->kind = _NETDEV_KIND_INVALID;
460 netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
461 netdev->vlanid = VLANID_MAX + 1;
463 r = config_parse(NULL, filename, file, "Match\0NetDev\0VLAN\0MACVLAN\0",
464 config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
465 false, false, netdev);
467 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
471 if (netdev->kind == _NETDEV_KIND_INVALID) {
472 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
477 log_warning("NetDev without Name configured in %s. Ignoring", filename);
481 if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid > VLANID_MAX) {
482 log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
486 if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
487 log_warning("VLAN Id configured for a %s in %s. Ignoring",
488 netdev_kind_to_string(netdev->kind), filename);
492 if (netdev->kind != NETDEV_KIND_MACVLAN &&
493 netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
494 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
495 netdev_kind_to_string(netdev->kind), filename);
499 netdev->filename = strdup(filename);
500 if (!netdev->filename)
503 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
504 netdev->match_host, netdev->match_virt,
505 netdev->match_kernel, netdev->match_arch,
506 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
509 r = hashmap_put(netdev->manager->netdevs, netdev->name, netdev);
513 LIST_HEAD_INIT(netdev->callbacks);
515 if (netdev->kind != NETDEV_KIND_VLAN &&
516 netdev->kind != NETDEV_KIND_MACVLAN) {
517 r = netdev_create(netdev, NULL, NULL);
527 int netdev_load(Manager *manager) {
534 while ((netdev = hashmap_first(manager->netdevs)))
537 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
539 log_error("Failed to enumerate netdev files: %s", strerror(-r));
543 STRV_FOREACH_BACKWARDS(f, files) {
544 r = netdev_load_one(manager, *f);