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 condition_free_list(netdev->match_host);
97 condition_free_list(netdev->match_virt);
98 condition_free_list(netdev->match_kernel);
99 condition_free_list(netdev->match_arch);
104 NetDev *netdev_unref(NetDev *netdev) {
105 if (netdev && (-- netdev->n_ref <= 0))
111 NetDev *netdev_ref(NetDev *netdev) {
113 assert_se(++ netdev->n_ref >= 2);
118 void netdev_drop(NetDev *netdev) {
119 if (!netdev || netdev->state == NETDEV_STATE_LINGER)
122 netdev->state = NETDEV_STATE_LINGER;
124 log_debug_netdev(netdev, "netdev removed");
126 netdev_cancel_callbacks(netdev);
128 netdev_unref(netdev);
133 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
140 netdev = hashmap_get(manager->netdevs, name);
151 static int netdev_enter_failed(NetDev *netdev) {
152 netdev->state = NETDEV_STATE_FAILED;
157 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
158 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
162 assert(netdev->state == NETDEV_STATE_READY);
163 assert(netdev->manager);
164 assert(netdev->manager->rtnl);
168 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
169 RTM_SETLINK, link->ifindex);
171 log_error_netdev(netdev,
172 "Could not allocate RTM_SETLINK message: %s",
177 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
179 log_error_netdev(netdev,
180 "Could not append IFLA_MASTER attribute: %s",
185 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
187 log_error_netdev(netdev,
188 "Could not send rtnetlink message: %s",
193 log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
198 static int netdev_enter_ready(NetDev *netdev) {
199 netdev_enslave_callback *callback;
202 assert(netdev->ifname);
204 if (netdev->state != NETDEV_STATE_CREATING)
207 netdev->state = NETDEV_STATE_READY;
209 log_info_netdev(netdev, "netdev ready");
211 LIST_FOREACH(callbacks, callback, netdev->callbacks) {
212 /* enslave the links that were attempted to be enslaved before the
214 netdev_enslave_ready(netdev, callback->link, callback->callback);
219 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
220 NetDev *netdev = userdata;
223 assert(netdev->state != _NETDEV_STATE_INVALID);
225 r = sd_rtnl_message_get_errno(m);
227 log_debug_netdev(netdev, "netdev exists, using existing");
229 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
238 int config_parse_tunnel_address(const char *unit,
239 const char *filename,
242 unsigned section_line,
249 unsigned char family = AF_INET;
257 r = net_parse_inaddr(rvalue, &family, n);
259 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
260 "Tunnel address is invalid, ignoring assignment: %s", rvalue);
266 static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
267 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
272 assert(!(netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN) ||
274 assert(netdev->ifname);
275 assert(netdev->manager);
276 assert(netdev->manager->rtnl);
278 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0);
280 log_error_netdev(netdev,
281 "Could not allocate RTM_NEWLINK message: %s",
287 r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
289 log_error_netdev(netdev,
290 "Could not append IFLA_LINK attribute: %s",
296 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->ifname);
298 log_error_netdev(netdev,
299 "Could not append IFLA_IFNAME attribute: %s",
305 r = sd_rtnl_message_append_u32(req, IFLA_MTU, netdev->mtu);
307 log_error_netdev(netdev,
308 "Could not append IFLA_MTU attribute: %s",
314 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
316 log_error_netdev(netdev,
317 "Could not open IFLA_LINKINFO container: %s",
322 kind = netdev_kind_to_string(netdev->kind);
324 log_error_netdev(netdev, "Invalid kind");
328 r = sd_rtnl_message_open_container_union(req, IFLA_INFO_DATA, kind);
330 log_error_netdev(netdev,
331 "Could not open IFLA_INFO_DATA container: %s",
336 if (netdev->vlanid <= VLANID_MAX) {
337 r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
339 log_error_netdev(netdev,
340 "Could not append IFLA_VLAN_ID attribute: %s",
346 if (netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
347 r = sd_rtnl_message_append_u32(req, IFLA_MACVLAN_MODE, netdev->macvlan_mode);
349 log_error_netdev(netdev,
350 "Could not append IFLA_MACVLAN_MODE attribute: %s",
356 r = sd_rtnl_message_close_container(req);
358 log_error_netdev(netdev,
359 "Could not close IFLA_INFO_DATA container %s",
364 r = sd_rtnl_message_close_container(req);
366 log_error_netdev(netdev,
367 "Could not close IFLA_LINKINFO container %s",
373 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
375 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
377 log_error_netdev(netdev,
378 "Could not send rtnetlink message: %s", strerror(-r));
382 log_debug_netdev(netdev, "creating netdev");
384 netdev->state = NETDEV_STATE_CREATING;
389 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
392 if (netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN)
393 return netdev_create(netdev, link, callback);
395 if(netdev->kind == NETDEV_KIND_IPIP ||
396 netdev->kind == NETDEV_KIND_GRE ||
397 netdev->kind == NETDEV_KIND_SIT ||
398 netdev->kind == NETDEV_KIND_VTI)
399 return netdev_create_tunnel(link, netdev_create_handler);
401 if (netdev->state == NETDEV_STATE_READY) {
402 r = netdev_enslave_ready(netdev, link, callback);
406 /* the netdev is not yet read, save this request for when it is*/
407 netdev_enslave_callback *cb;
409 cb = new0(netdev_enslave_callback, 1);
413 cb->callback = callback;
416 LIST_PREPEND(callbacks, netdev->callbacks, cb);
422 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
432 r = sd_rtnl_message_get_type(message, &type);
434 log_error_netdev(netdev, "Could not get rtnl message type");
438 if (type != RTM_NEWLINK) {
439 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
443 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
445 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
446 netdev_enter_failed(netdev);
448 } else if (ifindex <= 0) {
449 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
450 netdev_enter_failed(netdev);
454 if (netdev->ifindex > 0) {
455 if (netdev->ifindex != ifindex) {
456 log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
457 ifindex, netdev->ifindex);
458 netdev_enter_failed(netdev);
461 /* ifindex already set to the same for this netdev */
465 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
467 log_error_netdev(netdev, "Could not get IFNAME");
471 if (!streq(netdev->ifname, received_name)) {
472 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
474 netdev_enter_failed(netdev);
478 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
480 log_error_netdev(netdev, "Could not get LINKINFO");
484 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
486 log_error_netdev(netdev, "Could not get KIND");
490 r = sd_rtnl_message_exit_container(message);
492 log_error_netdev(netdev, "Could not exit container");
496 kind = netdev_kind_to_string(netdev->kind);
498 log_error_netdev(netdev, "Could not get kind");
499 netdev_enter_failed(netdev);
503 if (!streq(kind, received_kind)) {
504 log_error_netdev(netdev, "Received newlink with wrong KIND %s, "
505 "expected %s", received_kind, kind);
506 netdev_enter_failed(netdev);
510 netdev->ifindex = ifindex;
512 log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
514 netdev_enter_ready(netdev);
519 static int netdev_load_one(Manager *manager, const char *filename) {
520 _cleanup_netdev_unref_ NetDev *netdev = NULL;
521 _cleanup_fclose_ FILE *file = NULL;
527 if (null_or_empty_path(filename)) {
528 log_debug("skipping empty file: %s", filename);
532 file = fopen(filename, "re");
540 netdev = new0(NetDev, 1);
545 netdev->manager = manager;
546 netdev->state = _NETDEV_STATE_INVALID;
547 netdev->kind = _NETDEV_KIND_INVALID;
548 netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
549 netdev->vlanid = VLANID_MAX + 1;
550 netdev->tunnel_pmtudisc = true;
552 r = config_parse(NULL, filename, file, "Match\0NetDev\0VLAN\0MACVLAN\0Tunnel\0Peer\0",
553 config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
554 false, false, netdev);
556 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
560 if (netdev->kind == _NETDEV_KIND_INVALID) {
561 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
565 if (!netdev->ifname) {
566 log_warning("NetDev without Name configured in %s. Ignoring", filename);
570 if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid > VLANID_MAX) {
571 log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
575 if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
576 log_warning("VLAN Id configured for a %s in %s. Ignoring",
577 netdev_kind_to_string(netdev->kind), filename);
581 if (netdev->kind != NETDEV_KIND_MACVLAN &&
582 netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
583 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
584 netdev_kind_to_string(netdev->kind), filename);
588 netdev->filename = strdup(filename);
589 if (!netdev->filename)
592 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
593 netdev->match_host, netdev->match_virt,
594 netdev->match_kernel, netdev->match_arch,
595 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
598 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
602 LIST_HEAD_INIT(netdev->callbacks);
604 if(netdev->kind == NETDEV_KIND_VETH)
605 return netdev_create_veth(netdev, netdev_create_handler);
607 if (netdev->kind != NETDEV_KIND_VLAN &&
608 netdev->kind != NETDEV_KIND_MACVLAN &&
609 netdev->kind != NETDEV_KIND_IPIP &&
610 netdev->kind != NETDEV_KIND_GRE &&
611 netdev->kind != NETDEV_KIND_SIT &&
612 netdev->kind != NETDEV_KIND_VTI) {
613 r = netdev_create(netdev, NULL, NULL);
618 log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
625 int netdev_load(Manager *manager) {
632 while ((netdev = hashmap_first(manager->netdevs)))
633 netdev_unref(netdev);
635 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
637 log_error("Failed to enumerate netdev files: %s", strerror(-r));
641 STRV_FOREACH_BACKWARDS(f, files) {
642 r = netdev_load_one(manager, *f);