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",
41 [NETDEV_KIND_VETH] = "veth",
42 [NETDEV_KIND_VTI] = "vti"
45 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
46 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
48 static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
49 [NETDEV_MACVLAN_MODE_PRIVATE] = "private",
50 [NETDEV_MACVLAN_MODE_VEPA] = "vepa",
51 [NETDEV_MACVLAN_MODE_BRIDGE] = "bridge",
52 [NETDEV_MACVLAN_MODE_PASSTHRU] = "passthru",
55 DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
56 DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode");
58 static void netdev_cancel_callbacks(NetDev *netdev) {
59 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
60 netdev_enslave_callback *callback;
65 rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
67 while ((callback = netdev->callbacks)) {
69 assert(callback->link);
70 assert(callback->callback);
71 assert(netdev->manager);
72 assert(netdev->manager->rtnl);
74 callback->callback(netdev->manager->rtnl, m, link);
77 LIST_REMOVE(callbacks, netdev->callbacks, callback);
82 static void netdev_free(NetDev *netdev) {
86 netdev_cancel_callbacks(netdev);
89 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
91 free(netdev->filename);
93 free(netdev->description);
96 free(netdev->mac_peer);
98 condition_free_list(netdev->match_host);
99 condition_free_list(netdev->match_virt);
100 condition_free_list(netdev->match_kernel);
101 condition_free_list(netdev->match_arch);
106 NetDev *netdev_unref(NetDev *netdev) {
107 if (netdev && (-- netdev->n_ref <= 0))
113 NetDev *netdev_ref(NetDev *netdev) {
115 assert_se(++ netdev->n_ref >= 2);
120 void netdev_drop(NetDev *netdev) {
121 if (!netdev || netdev->state == NETDEV_STATE_LINGER)
124 netdev->state = NETDEV_STATE_LINGER;
126 log_debug_netdev(netdev, "netdev removed");
128 netdev_cancel_callbacks(netdev);
130 netdev_unref(netdev);
135 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
142 netdev = hashmap_get(manager->netdevs, name);
153 static int netdev_enter_failed(NetDev *netdev) {
154 netdev->state = NETDEV_STATE_FAILED;
159 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
160 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
164 assert(netdev->state == NETDEV_STATE_READY);
165 assert(netdev->manager);
166 assert(netdev->manager->rtnl);
170 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
171 RTM_SETLINK, link->ifindex);
173 log_error_netdev(netdev,
174 "Could not allocate RTM_SETLINK message: %s",
179 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
181 log_error_netdev(netdev,
182 "Could not append IFLA_MASTER attribute: %s",
187 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
189 log_error_netdev(netdev,
190 "Could not send rtnetlink message: %s",
195 log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
200 static int netdev_enter_ready(NetDev *netdev) {
201 netdev_enslave_callback *callback;
204 assert(netdev->ifname);
206 if (netdev->state != NETDEV_STATE_CREATING)
209 netdev->state = NETDEV_STATE_READY;
211 log_info_netdev(netdev, "netdev ready");
213 LIST_FOREACH(callbacks, callback, netdev->callbacks) {
214 /* enslave the links that were attempted to be enslaved before the
216 netdev_enslave_ready(netdev, callback->link, callback->callback);
221 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
222 NetDev *netdev = userdata;
225 assert(netdev->state != _NETDEV_STATE_INVALID);
227 r = sd_rtnl_message_get_errno(m);
229 log_debug_netdev(netdev, "netdev exists, using existing");
231 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
240 int config_parse_tunnel_address(const char *unit,
241 const char *filename,
244 unsigned section_line,
251 unsigned char family = AF_INET;
259 r = net_parse_inaddr(rvalue, &family, n);
261 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
262 "Tunnel address is invalid, ignoring assignment: %s", rvalue);
268 static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
269 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
274 assert(!(netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN) ||
276 assert(netdev->ifname);
277 assert(netdev->manager);
278 assert(netdev->manager->rtnl);
280 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0);
282 log_error_netdev(netdev,
283 "Could not allocate RTM_NEWLINK message: %s",
289 r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
291 log_error_netdev(netdev,
292 "Could not append IFLA_LINK attribute: %s",
298 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->ifname);
300 log_error_netdev(netdev,
301 "Could not append IFLA_IFNAME attribute: %s",
307 r = sd_rtnl_message_append_u32(req, IFLA_MTU, netdev->mtu);
309 log_error_netdev(netdev,
310 "Could not append IFLA_MTU attribute: %s",
317 r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, netdev->mac);
319 log_error_netdev(netdev,
320 "Colud not append IFLA_ADDRESS attribute: %s",
326 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
328 log_error_netdev(netdev,
329 "Could not open IFLA_LINKINFO container: %s",
334 kind = netdev_kind_to_string(netdev->kind);
336 log_error_netdev(netdev, "Invalid kind");
340 r = sd_rtnl_message_open_container_union(req, IFLA_INFO_DATA, kind);
342 log_error_netdev(netdev,
343 "Could not open IFLA_INFO_DATA container: %s",
348 if (netdev->vlanid <= VLANID_MAX) {
349 r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
351 log_error_netdev(netdev,
352 "Could not append IFLA_VLAN_ID attribute: %s",
358 if (netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
359 r = sd_rtnl_message_append_u32(req, IFLA_MACVLAN_MODE, netdev->macvlan_mode);
361 log_error_netdev(netdev,
362 "Could not append IFLA_MACVLAN_MODE attribute: %s",
368 r = sd_rtnl_message_close_container(req);
370 log_error_netdev(netdev,
371 "Could not close IFLA_INFO_DATA container %s",
376 r = sd_rtnl_message_close_container(req);
378 log_error_netdev(netdev,
379 "Could not close IFLA_LINKINFO container %s",
385 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
387 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
389 log_error_netdev(netdev,
390 "Could not send rtnetlink message: %s", strerror(-r));
394 log_debug_netdev(netdev, "creating netdev");
396 netdev->state = NETDEV_STATE_CREATING;
401 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
404 if (netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN)
405 return netdev_create(netdev, link, callback);
407 if(netdev->kind == NETDEV_KIND_IPIP ||
408 netdev->kind == NETDEV_KIND_GRE ||
409 netdev->kind == NETDEV_KIND_SIT ||
410 netdev->kind == NETDEV_KIND_VTI)
411 return netdev_create_tunnel(link, netdev_create_handler);
413 if (netdev->state == NETDEV_STATE_READY) {
414 r = netdev_enslave_ready(netdev, link, callback);
418 /* the netdev is not yet read, save this request for when it is*/
419 netdev_enslave_callback *cb;
421 cb = new0(netdev_enslave_callback, 1);
425 cb->callback = callback;
428 LIST_PREPEND(callbacks, netdev->callbacks, cb);
434 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
444 r = sd_rtnl_message_get_type(message, &type);
446 log_error_netdev(netdev, "Could not get rtnl message type");
450 if (type != RTM_NEWLINK) {
451 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
455 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
457 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
458 netdev_enter_failed(netdev);
460 } else if (ifindex <= 0) {
461 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
462 netdev_enter_failed(netdev);
466 if (netdev->ifindex > 0) {
467 if (netdev->ifindex != ifindex) {
468 log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
469 ifindex, netdev->ifindex);
470 netdev_enter_failed(netdev);
473 /* ifindex already set to the same for this netdev */
477 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
479 log_error_netdev(netdev, "Could not get IFNAME");
483 if (!streq(netdev->ifname, received_name)) {
484 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
486 netdev_enter_failed(netdev);
490 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
492 log_error_netdev(netdev, "Could not get LINKINFO");
496 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
498 log_error_netdev(netdev, "Could not get KIND");
502 r = sd_rtnl_message_exit_container(message);
504 log_error_netdev(netdev, "Could not exit container");
508 kind = netdev_kind_to_string(netdev->kind);
510 log_error_netdev(netdev, "Could not get kind");
511 netdev_enter_failed(netdev);
515 if (!streq(kind, received_kind)) {
516 log_error_netdev(netdev, "Received newlink with wrong KIND %s, "
517 "expected %s", received_kind, kind);
518 netdev_enter_failed(netdev);
522 netdev->ifindex = ifindex;
524 log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
526 netdev_enter_ready(netdev);
531 static int netdev_load_one(Manager *manager, const char *filename) {
532 _cleanup_netdev_unref_ NetDev *netdev = NULL;
533 _cleanup_fclose_ FILE *file = NULL;
539 if (null_or_empty_path(filename)) {
540 log_debug("skipping empty file: %s", filename);
544 file = fopen(filename, "re");
552 netdev = new0(NetDev, 1);
557 netdev->manager = manager;
558 netdev->state = _NETDEV_STATE_INVALID;
559 netdev->kind = _NETDEV_KIND_INVALID;
560 netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
561 netdev->vlanid = VLANID_MAX + 1;
562 netdev->tunnel_pmtudisc = true;
564 r = config_parse(NULL, filename, file, "Match\0NetDev\0VLAN\0MACVLAN\0Tunnel\0Peer\0",
565 config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
566 false, false, netdev);
568 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
572 if (netdev->kind == _NETDEV_KIND_INVALID) {
573 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
577 if (!netdev->ifname) {
578 log_warning("NetDev without Name configured in %s. Ignoring", filename);
582 if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid > VLANID_MAX) {
583 log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
587 if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
588 log_warning("VLAN Id configured for a %s in %s. Ignoring",
589 netdev_kind_to_string(netdev->kind), filename);
593 if (netdev->kind != NETDEV_KIND_MACVLAN &&
594 netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
595 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
596 netdev_kind_to_string(netdev->kind), filename);
600 netdev->filename = strdup(filename);
601 if (!netdev->filename)
604 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
605 netdev->match_host, netdev->match_virt,
606 netdev->match_kernel, netdev->match_arch,
607 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
610 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
614 LIST_HEAD_INIT(netdev->callbacks);
616 if(netdev->kind == NETDEV_KIND_VETH)
617 return netdev_create_veth(netdev, netdev_create_handler);
619 if (netdev->kind != NETDEV_KIND_VLAN &&
620 netdev->kind != NETDEV_KIND_MACVLAN &&
621 netdev->kind != NETDEV_KIND_IPIP &&
622 netdev->kind != NETDEV_KIND_GRE &&
623 netdev->kind != NETDEV_KIND_SIT &&
624 netdev->kind != NETDEV_KIND_VTI) {
625 r = netdev_create(netdev, NULL, NULL);
630 log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
637 int netdev_load(Manager *manager) {
644 while ((netdev = hashmap_first(manager->netdevs)))
645 netdev_unref(netdev);
647 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
649 log_error("Failed to enumerate netdev files: %s", strerror(-r));
653 STRV_FOREACH_BACKWARDS(f, files) {
654 r = netdev_load_one(manager, *f);