+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
Copyright 2013 Tom Gundersen <teg@jklm.no>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <net/if.h>
#include "network-internal.h"
#include "netdev/netdev.h"
#include "networkd-manager.h"
+#include "networkd-link.h"
#include "siphash24.h"
#include "stat-util.h"
#include "string-table.h"
#include "netdev/bridge.h"
#include "netdev/bond.h"
+#include "netdev/geneve.h"
#include "netdev/vlan.h"
#include "netdev/macvlan.h"
#include "netdev/ipvlan.h"
#include "netdev/dummy.h"
#include "netdev/vrf.h"
#include "netdev/vcan.h"
+#include "netdev/vxcan.h"
+#include "netdev/wireguard.h"
+#include "netdev/netdevsim.h"
const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
[NETDEV_KIND_BRIDGE] = &bridge_vtable,
[NETDEV_KIND_IP6TNL] = &ip6tnl_vtable,
[NETDEV_KIND_VRF] = &vrf_vtable,
[NETDEV_KIND_VCAN] = &vcan_vtable,
+ [NETDEV_KIND_GENEVE] = &geneve_vtable,
+ [NETDEV_KIND_VXCAN] = &vxcan_vtable,
+ [NETDEV_KIND_WIREGUARD] = &wireguard_vtable,
+ [NETDEV_KIND_NETDEVSIM] = &netdevsim_vtable,
};
static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
[NETDEV_KIND_IP6TNL] = "ip6tnl",
[NETDEV_KIND_VRF] = "vrf",
[NETDEV_KIND_VCAN] = "vcan",
+ [NETDEV_KIND_GENEVE] = "geneve",
+ [NETDEV_KIND_VXCAN] = "vxcan",
+ [NETDEV_KIND_WIREGUARD] = "wireguard",
+ [NETDEV_KIND_NETDEVSIM] = "netdevsim",
};
DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
netdev_join_callback *callback;
- if (!netdev)
+ if (!netdev || !netdev->manager)
return;
- rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
+ rtnl_message_new_synthetic_error(netdev->manager->rtnl, -ENODEV, 0, &m);
while ((callback = netdev->callbacks)) {
if (m) {
netdev_cancel_callbacks(netdev);
- if (netdev->ifname)
+ if (netdev->ifname && netdev->manager)
hashmap_remove(netdev->manager->netdevs, netdev->ifname);
free(netdev->filename);
condition_free_list(netdev->match_host);
condition_free_list(netdev->match_virt);
- condition_free_list(netdev->match_kernel);
+ condition_free_list(netdev->match_kernel_cmdline);
+ condition_free_list(netdev->match_kernel_version);
condition_free_list(netdev->match_arch);
- if (NETDEV_VTABLE(netdev) &&
+ /* Invoke the per-kind done() destructor, but only if the state field is initialized. We conditionalize that
+ * because we parse .netdev files twice: once to determine the kind (with a short, minimal NetDev structure
+ * allocation, with no room for per-kind fields), and once to read the kind's properties (with a full,
+ * comprehensive NetDev structure allocation with enough space for whatever the specific kind needs). Now, in
+ * the first case we shouldn't try to destruct the per-kind NetDev fields on destruction, in the second case we
+ * should. We use the state field to discern the two cases: it's _NETDEV_STATE_INVALID on the first "raw"
+ * call. */
+ if (netdev->state != _NETDEV_STATE_INVALID &&
+ NETDEV_VTABLE(netdev) &&
NETDEV_VTABLE(netdev)->done)
NETDEV_VTABLE(netdev)->done(netdev);
assert(link);
assert(callback);
+ if (link->flags & IFF_UP && netdev->kind == NETDEV_KIND_BOND) {
+ log_netdev_debug(netdev, "Link '%s' was up when attempting to enslave it. Bringing link down.", link->ifname);
+ r = link_down(link);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not bring link down: %m");
+ }
+
r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not allocate RTM_SETLINK message: %m");
/* callback for netdev's created without a backing Link */
static int netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
- _cleanup_netdev_unref_ NetDev *netdev = userdata;
+ _cleanup_(netdev_unrefp) NetDev *netdev = userdata;
int r;
assert(netdev->state != _NETDEV_STATE_INVALID);
} else if (IN_SET(netdev->state, NETDEV_STATE_LINGER, NETDEV_STATE_FAILED)) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
- r = rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
+ r = rtnl_message_new_synthetic_error(netdev->manager->rtnl, -ENODEV, 0, &m);
if (r >= 0)
callback(netdev->manager->rtnl, m, link);
} else {
mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
- *ret = mac;
- mac = NULL;
+ *ret = TAKE_PTR(mac);
return 0;
}
}
static int netdev_load_one(Manager *manager, const char *filename) {
- _cleanup_netdev_unref_ NetDev *netdev = NULL;
- _cleanup_free_ NetDev *netdev_raw = NULL;
+ _cleanup_(netdev_unrefp) NetDev *netdev_raw = NULL, *netdev = NULL;
_cleanup_fclose_ FILE *file = NULL;
const char *dropin_dirname;
+ bool independent = false;
int r;
assert(manager);
if (!file) {
if (errno == ENOENT)
return 0;
- else
- return -errno;
+
+ return -errno;
}
if (null_or_empty_fd(fileno(file))) {
if (!netdev_raw)
return log_oom();
+ netdev_raw->n_ref = 1;
netdev_raw->kind = _NETDEV_KIND_INVALID;
- dropin_dirname = strjoina(basename(filename), ".d");
+ netdev_raw->state = _NETDEV_STATE_INVALID; /* an invalid state means done() of the implementation won't be called on destruction */
+ dropin_dirname = strjoina(basename(filename), ".d");
r = config_parse_many(filename, network_dirs, dropin_dirname,
"Match\0NetDev\0",
config_item_perf_lookup, network_netdev_gperf_lookup,
- true, netdev_raw);
+ CONFIG_PARSE_WARN|CONFIG_PARSE_RELAXED, netdev_raw);
if (r < 0)
return r;
- r = fseek(file, 0, SEEK_SET);
- if (r < 0)
- return -errno;
-
/* skip out early if configuration does not match the environment */
if (net_match_config(NULL, NULL, NULL, NULL, NULL,
netdev_raw->match_host, netdev_raw->match_virt,
- netdev_raw->match_kernel, netdev_raw->match_arch,
+ netdev_raw->match_kernel_cmdline, netdev_raw->match_kernel_version,
+ netdev_raw->match_arch,
NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
return 0;
return 0;
}
+ r = fseek(file, 0, SEEK_SET);
+ if (r < 0)
+ return -errno;
+
netdev = malloc0(NETDEV_VTABLE(netdev_raw)->object_size);
if (!netdev)
return log_oom();
netdev->n_ref = 1;
netdev->manager = manager;
- netdev->state = _NETDEV_STATE_INVALID;
netdev->kind = netdev_raw->kind;
- netdev->ifname = netdev_raw->ifname;
+ netdev->state = NETDEV_STATE_LOADING; /* we initialize the state here for the first time, so that done() will be called on destruction */
if (NETDEV_VTABLE(netdev)->init)
NETDEV_VTABLE(netdev)->init(netdev);
r = config_parse(NULL, filename, file,
NETDEV_VTABLE(netdev)->sections,
config_item_perf_lookup, network_netdev_gperf_lookup,
- false, false, false, netdev);
+ CONFIG_PARSE_WARN, netdev);
if (r < 0)
return r;
case NETDEV_CREATE_INDEPENDENT:
r = netdev_create(netdev, NULL, NULL);
if (r < 0)
- return 0;
+ return r;
break;
default:
break;
}
+ switch (netdev->kind) {
+ case NETDEV_KIND_IPIP:
+ independent = IPIP(netdev)->independent;
+ break;
+ case NETDEV_KIND_GRE:
+ independent = GRE(netdev)->independent;
+ break;
+ case NETDEV_KIND_GRETAP:
+ independent = GRETAP(netdev)->independent;
+ break;
+ case NETDEV_KIND_IP6GRE:
+ independent = IP6GRE(netdev)->independent;
+ break;
+ case NETDEV_KIND_IP6GRETAP:
+ independent = IP6GRETAP(netdev)->independent;
+ break;
+ case NETDEV_KIND_SIT:
+ independent = SIT(netdev)->independent;
+ break;
+ case NETDEV_KIND_VTI:
+ independent = VTI(netdev)->independent;
+ break;
+ case NETDEV_KIND_VTI6:
+ independent = VTI6(netdev)->independent;
+ break;
+ case NETDEV_KIND_IP6TNL:
+ independent = IP6TNL(netdev)->independent;
+ break;
+ default:
+ break;
+ }
+
+ if (independent) {
+ r = netdev_create(netdev, NULL, NULL);
+ if (r < 0)
+ return r;
+ }
+
netdev = NULL;
return 0;
while ((netdev = hashmap_first(manager->netdevs)))
netdev_unref(netdev);
- r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
+ r = conf_files_list_strv(&files, ".netdev", NULL, 0, network_dirs);
if (r < 0)
return log_error_errno(r, "Failed to enumerate netdev files: %m");