network/netdev: follow-ups for reloading .netdev files (#34979)
Follow-ups for #34909.
This commit is contained in:
@@ -72,4 +72,5 @@ const NetDevVTable bare_udp_vtable = {
|
||||
.fill_message_create = netdev_bare_udp_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
.iftype = ARPHRD_NONE,
|
||||
.keep_existing = true,
|
||||
};
|
||||
|
||||
@@ -56,13 +56,23 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_all_targets, bond_arp_all_targets
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_primary_reselect, bond_primary_reselect, BondPrimaryReselect);
|
||||
|
||||
static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||
assert(!link);
|
||||
assert(m);
|
||||
|
||||
Bond *b = BOND(netdev);
|
||||
int r;
|
||||
|
||||
if (b->mode != _NETDEV_BOND_MODE_INVALID) {
|
||||
assert(netdev->manager);
|
||||
assert(!link);
|
||||
assert(m);
|
||||
|
||||
if (netdev->ifindex > 0) {
|
||||
r = link_get_by_index(netdev->manager, netdev->ifindex, &link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
bool up = link && FLAGS_SET(link->flags, IFF_UP);
|
||||
bool has_slaves = link && !set_isempty(link->slaves);
|
||||
|
||||
if (b->mode != _NETDEV_BOND_MODE_INVALID && !up && !has_slaves) {
|
||||
r = sd_netlink_message_append_u8(m, IFLA_BOND_MODE, b->mode);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -75,7 +85,8 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlin
|
||||
}
|
||||
|
||||
if (b->lacp_rate != _NETDEV_BOND_LACP_RATE_INVALID &&
|
||||
b->mode == NETDEV_BOND_MODE_802_3AD) {
|
||||
b->mode == NETDEV_BOND_MODE_802_3AD &&
|
||||
!up) {
|
||||
r = sd_netlink_message_append_u8(m, IFLA_BOND_AD_LACP_RATE, b->lacp_rate);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -119,14 +130,16 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlin
|
||||
}
|
||||
|
||||
if (b->ad_select != _NETDEV_BOND_AD_SELECT_INVALID &&
|
||||
b->mode == NETDEV_BOND_MODE_802_3AD) {
|
||||
b->mode == NETDEV_BOND_MODE_802_3AD &&
|
||||
!up) {
|
||||
r = sd_netlink_message_append_u8(m, IFLA_BOND_AD_SELECT, b->ad_select);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (b->fail_over_mac != _NETDEV_BOND_FAIL_OVER_MAC_INVALID &&
|
||||
b->mode == NETDEV_BOND_MODE_ACTIVE_BACKUP) {
|
||||
b->mode == NETDEV_BOND_MODE_ACTIVE_BACKUP &&
|
||||
!has_slaves) {
|
||||
r = sd_netlink_message_append_u8(m, IFLA_BOND_FAIL_OVER_MAC, b->fail_over_mac);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -181,7 +194,7 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlin
|
||||
return r;
|
||||
}
|
||||
|
||||
if (b->ad_user_port_key != 0) {
|
||||
if (b->ad_user_port_key != 0 && !up) {
|
||||
r = sd_netlink_message_append_u16(m, IFLA_BOND_AD_USER_PORT_KEY, b->ad_user_port_key);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -197,7 +210,7 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlin
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (b->tlb_dynamic_lb >= 0) {
|
||||
if (b->tlb_dynamic_lb >= 0 && !up) {
|
||||
r = sd_netlink_message_append_u8(m, IFLA_BOND_TLB_DYNAMIC_LB, b->tlb_dynamic_lb);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -281,12 +281,17 @@ static void bridge_init(NetDev *netdev) {
|
||||
b->ageing_time = USEC_INFINITY;
|
||||
}
|
||||
|
||||
static bool bridge_can_set_mac(NetDev *netdev, const struct hw_addr_data *hw_addr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const NetDevVTable bridge_vtable = {
|
||||
.object_size = sizeof(Bridge),
|
||||
.init = bridge_init,
|
||||
.sections = NETDEV_COMMON_SECTIONS "Bridge\0",
|
||||
.post_create = netdev_bridge_post_create,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
.can_set_mac = bridge_can_set_mac,
|
||||
.iftype = ARPHRD_ETHER,
|
||||
.generate_mac = true,
|
||||
};
|
||||
|
||||
@@ -4,10 +4,15 @@
|
||||
|
||||
#include "dummy.h"
|
||||
|
||||
static bool dummy_can_set_mac(NetDev *netdev, const struct hw_addr_data *hw_addr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const NetDevVTable dummy_vtable = {
|
||||
.object_size = sizeof(Dummy),
|
||||
.sections = NETDEV_COMMON_SECTIONS,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
.can_set_mac = dummy_can_set_mac,
|
||||
.iftype = ARPHRD_ETHER,
|
||||
.generate_mac = true,
|
||||
};
|
||||
|
||||
@@ -254,6 +254,10 @@ static int netdev_geneve_verify(NetDev *netdev, const char *filename) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool geneve_can_set_mac(NetDev *netdev, const struct hw_addr_data *hw_addr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void geneve_init(NetDev *netdev) {
|
||||
Geneve *v = GENEVE(netdev);
|
||||
|
||||
@@ -272,6 +276,7 @@ const NetDevVTable geneve_vtable = {
|
||||
.fill_message_create = netdev_geneve_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
.config_verify = netdev_geneve_verify,
|
||||
.can_set_mac = geneve_can_set_mac,
|
||||
.iftype = ARPHRD_ETHER,
|
||||
.generate_mac = true,
|
||||
};
|
||||
|
||||
@@ -60,6 +60,7 @@ const NetDevVTable ipvlan_vtable = {
|
||||
.can_set_mac = ipvlan_can_set_mac,
|
||||
.iftype = ARPHRD_ETHER,
|
||||
.generate_mac = true,
|
||||
.keep_existing = true,
|
||||
};
|
||||
|
||||
const NetDevVTable ipvtap_vtable = {
|
||||
@@ -71,6 +72,7 @@ const NetDevVTable ipvtap_vtable = {
|
||||
.can_set_mac = ipvlan_can_set_mac,
|
||||
.iftype = ARPHRD_ETHER,
|
||||
.generate_mac = true,
|
||||
.keep_existing = true,
|
||||
};
|
||||
|
||||
IPVlanMode link_get_ipvlan_mode(Link *link) {
|
||||
|
||||
@@ -178,6 +178,7 @@ const NetDevVTable macvtap_vtable = {
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.iftype = ARPHRD_ETHER,
|
||||
.generate_mac = true,
|
||||
.keep_existing = true,
|
||||
};
|
||||
|
||||
const NetDevVTable macvlan_vtable = {
|
||||
@@ -189,4 +190,5 @@ const NetDevVTable macvlan_vtable = {
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.iftype = ARPHRD_ETHER,
|
||||
.generate_mac = true,
|
||||
.keep_existing = true,
|
||||
};
|
||||
|
||||
+96
-43
@@ -400,7 +400,7 @@ int netdev_enter_ready(NetDev *netdev) {
|
||||
assert(netdev);
|
||||
assert(netdev->ifname);
|
||||
|
||||
if (netdev->state != NETDEV_STATE_CREATING)
|
||||
if (!IN_SET(netdev->state, NETDEV_STATE_LOADING, NETDEV_STATE_CREATING))
|
||||
return 0;
|
||||
|
||||
netdev->state = NETDEV_STATE_READY;
|
||||
@@ -432,18 +432,17 @@ static int netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev
|
||||
assert(netdev->state != _NETDEV_STATE_INVALID);
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r == -EEXIST)
|
||||
log_netdev_info(netdev, "netdev exists, using existing without changing its parameters");
|
||||
else if (r < 0) {
|
||||
log_netdev_warning_errno(netdev, r, "netdev could not be created: %m");
|
||||
if (r >= 0)
|
||||
log_netdev_debug(netdev, "Created.");
|
||||
else if (r == -EEXIST && netdev->ifindex > 0)
|
||||
log_netdev_debug(netdev, "Already exists.");
|
||||
else {
|
||||
log_netdev_warning_errno(netdev, r, "Failed to create netdev: %m");
|
||||
netdev_enter_failed(netdev);
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_netdev_debug(netdev, "Created");
|
||||
|
||||
return 1;
|
||||
return netdev_enter_ready(netdev);
|
||||
}
|
||||
|
||||
int netdev_set_ifindex_internal(NetDev *netdev, int ifindex) {
|
||||
@@ -464,8 +463,6 @@ int netdev_set_ifindex_internal(NetDev *netdev, int ifindex) {
|
||||
}
|
||||
|
||||
static int netdev_set_ifindex_impl(NetDev *netdev, const char *name, int ifindex) {
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(name);
|
||||
assert(ifindex > 0);
|
||||
@@ -478,11 +475,7 @@ static int netdev_set_ifindex_impl(NetDev *netdev, const char *name, int ifindex
|
||||
"Received netlink message with unexpected interface name %s (ifindex=%i).",
|
||||
name, ifindex);
|
||||
|
||||
r = netdev_set_ifindex_internal(netdev, ifindex);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
return netdev_enter_ready(netdev);
|
||||
return netdev_set_ifindex_internal(netdev, ifindex);
|
||||
}
|
||||
|
||||
int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *message) {
|
||||
@@ -636,15 +629,32 @@ finalize:
|
||||
|
||||
static bool netdev_can_set_mac(NetDev *netdev, const struct hw_addr_data *hw_addr) {
|
||||
assert(netdev);
|
||||
assert(netdev->manager);
|
||||
assert(hw_addr);
|
||||
|
||||
if (hw_addr->length <= 0)
|
||||
return false;
|
||||
|
||||
if (!NETDEV_VTABLE(netdev)->can_set_mac)
|
||||
return true;
|
||||
Link *link;
|
||||
if (link_get_by_index(netdev->manager, netdev->ifindex, &link) < 0)
|
||||
return true; /* The netdev does not exist yet. We can set MAC address. */
|
||||
|
||||
return NETDEV_VTABLE(netdev)->can_set_mac(netdev, hw_addr);
|
||||
if (hw_addr_equal(&link->hw_addr, hw_addr))
|
||||
return false; /* Unchanged, not necessary to set. */
|
||||
|
||||
/* Soem netdevs refuse to update MAC address even if the interface is not running, e.g. ipvlan.
|
||||
* Some other netdevs have the IFF_LIVE_ADDR_CHANGE flag and can update update MAC address even if
|
||||
* the interface is running, e.g. dummy. For those cases, use custom checkers. */
|
||||
if (NETDEV_VTABLE(netdev)->can_set_mac)
|
||||
return NETDEV_VTABLE(netdev)->can_set_mac(netdev, hw_addr);
|
||||
|
||||
/* Before ad72c4a06acc6762e84994ac2f722da7a07df34e and 0ec92a8f56ff07237dbe8af7c7a72aba7f957baf
|
||||
* (both in v6.5), the kernel refuse to set MAC address for existing netdevs even if it is unchanged.
|
||||
* So, by default, do not update MAC address if the it is running. See eth_prepare_mac_addr_change(),
|
||||
* which is called by eth_mac_addr(). Note, the result of netif_running() is mapped to operstate
|
||||
* and flags. See rtnl_fill_ifinfo() and dev_get_flags(). */
|
||||
return link->kernel_operstate == IF_OPER_DOWN &&
|
||||
(link->flags & (IFF_RUNNING | IFF_LOWER_UP | IFF_DORMANT)) == 0;
|
||||
}
|
||||
|
||||
static bool netdev_can_set_mtu(NetDev *netdev, uint32_t mtu) {
|
||||
@@ -653,18 +663,35 @@ static bool netdev_can_set_mtu(NetDev *netdev, uint32_t mtu) {
|
||||
if (mtu <= 0)
|
||||
return false;
|
||||
|
||||
if (!NETDEV_VTABLE(netdev)->can_set_mtu)
|
||||
return true;
|
||||
Link *link;
|
||||
if (link_get_by_index(netdev->manager, netdev->ifindex, &link) < 0)
|
||||
return true; /* The netdev does not exist yet. We can set MTU. */
|
||||
|
||||
return NETDEV_VTABLE(netdev)->can_set_mtu(netdev, mtu);
|
||||
if (mtu < link->min_mtu || link->max_mtu < mtu)
|
||||
return false; /* The MTU is out of range. */
|
||||
|
||||
if (link->mtu == mtu)
|
||||
return false; /* Unchanged, not necessary to set. */
|
||||
|
||||
/* Some netdevs cannot change MTU, e.g. vxlan. Let's use the custom checkers in such cases. */
|
||||
if (NETDEV_VTABLE(netdev)->can_set_mtu)
|
||||
return NETDEV_VTABLE(netdev)->can_set_mtu(netdev, mtu);
|
||||
|
||||
/* By default, allow to update the MTU. */
|
||||
return true;
|
||||
}
|
||||
|
||||
static int netdev_create_message(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||
int r;
|
||||
|
||||
r = sd_netlink_message_append_string(m, IFLA_IFNAME, netdev->ifname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (netdev->ifindex <= 0) {
|
||||
/* Set interface name when it is newly created. Otherwise, the kernel older than
|
||||
* bd039b5ea2a91ea707ee8539df26456bd5be80af (v6.2) will refuse the netlink message even if
|
||||
* the name is unchanged. */
|
||||
r = sd_netlink_message_append_string(m, IFLA_IFNAME, netdev->ifname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
struct hw_addr_data hw_addr;
|
||||
r = netdev_generate_hw_addr(netdev, link, netdev->ifname, &netdev->hw_addr, &hw_addr);
|
||||
@@ -827,7 +854,16 @@ static int stacked_netdev_process_request(Request *req, Link *link, void *userda
|
||||
assert(link);
|
||||
|
||||
if (!netdev_is_managed(netdev))
|
||||
return 1; /* Already detached, due to e.g. reloading .netdev files, cancelling the request. */
|
||||
goto cancelled; /* Already detached, due to e.g. reloading .netdev files, cancelling the request. */
|
||||
|
||||
if (NETDEV_VTABLE(netdev)->keep_existing && netdev->ifindex > 0) {
|
||||
/* Already exists, and the netdev does not support updating, entering the ready state. */
|
||||
r = netdev_enter_ready(netdev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
goto cancelled;
|
||||
}
|
||||
|
||||
r = netdev_is_ready_to_create(netdev, link);
|
||||
if (r <= 0)
|
||||
@@ -838,21 +874,41 @@ static int stacked_netdev_process_request(Request *req, Link *link, void *userda
|
||||
return log_netdev_warning_errno(netdev, r, "Failed to create netdev: %m");
|
||||
|
||||
return 1;
|
||||
|
||||
cancelled:
|
||||
assert_se(TAKE_PTR(req->counter) == &link->create_stacked_netdev_messages);
|
||||
link->create_stacked_netdev_messages--;
|
||||
|
||||
if (link->create_stacked_netdev_messages == 0) {
|
||||
link->stacked_netdevs_created = true;
|
||||
log_link_debug(link, "Stacked netdevs created.");
|
||||
link_check_ready(link);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int create_stacked_netdev_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
|
||||
NetDev *netdev = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(link);
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
log_link_message_warning_errno(link, m, r, "Could not create stacked netdev");
|
||||
if (r >= 0)
|
||||
log_netdev_debug(netdev, "Created.");
|
||||
else if (r == -EEXIST && netdev->ifindex > 0)
|
||||
log_netdev_debug(netdev, "Already exists.");
|
||||
else {
|
||||
log_netdev_warning_errno(netdev, r, "Failed to create netdev: %m");
|
||||
netdev_enter_failed(netdev);
|
||||
link_enter_failed(link);
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void) netdev_enter_ready(netdev);
|
||||
|
||||
if (link->create_stacked_netdev_messages == 0) {
|
||||
link->stacked_netdevs_created = true;
|
||||
log_link_debug(link, "Stacked netdevs created.");
|
||||
@@ -901,6 +957,15 @@ static int independent_netdev_process_request(Request *req, Link *link, void *us
|
||||
if (!netdev_is_managed(netdev))
|
||||
return 1; /* Already detached, due to e.g. reloading .netdev files, cancelling the request. */
|
||||
|
||||
if (NETDEV_VTABLE(netdev)->keep_existing && netdev->ifindex > 0) {
|
||||
/* Already exists, and the netdev does not support updating, entering the ready state. */
|
||||
r = netdev_enter_ready(netdev);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1; /* Skip this request. */
|
||||
}
|
||||
|
||||
r = netdev_is_ready_to_create(netdev, NULL);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
@@ -930,21 +995,9 @@ static int netdev_request_to_create(NetDev *netdev) {
|
||||
if (netdev->state != NETDEV_STATE_LOADING)
|
||||
return 0; /* Already configured (at least tried previously). Not necessary to reconfigure. */
|
||||
|
||||
r = netdev_is_ready_to_create(netdev, NULL);
|
||||
r = netdev_queue_request(netdev, independent_netdev_process_request, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0) {
|
||||
/* If the netdev has no dependency, then create it now. */
|
||||
r = independent_netdev_create(netdev);
|
||||
if (r < 0)
|
||||
return log_netdev_warning_errno(netdev, r, "Failed to create netdev: %m");
|
||||
|
||||
} else {
|
||||
/* Otherwise, wait for the dependencies being resolved. */
|
||||
r = netdev_queue_request(netdev, independent_netdev_process_request, NULL);
|
||||
if (r < 0)
|
||||
return log_netdev_warning_errno(netdev, r, "Failed to request to create netdev: %m");
|
||||
}
|
||||
return log_netdev_warning_errno(netdev, r, "Failed to request to create netdev: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -199,6 +199,10 @@ typedef struct NetDevVTable {
|
||||
|
||||
/* When assigning ifindex to the netdev, skip to check if the netdev kind matches. */
|
||||
bool skip_netdev_kind_check;
|
||||
|
||||
/* Provides if the netdev can be updated, that is, whether RTM_NEWLINK with existing ifindex is supported or not.
|
||||
* If this is true, the netdev does not support updating. */
|
||||
bool keep_existing;
|
||||
} NetDevVTable;
|
||||
|
||||
extern const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX];
|
||||
|
||||
@@ -4,10 +4,15 @@
|
||||
|
||||
#include "netdevsim.h"
|
||||
|
||||
static bool netdevsim_can_set_mac(NetDev *netdev, const struct hw_addr_data *hw_addr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const NetDevVTable netdevsim_vtable = {
|
||||
.object_size = sizeof(NetDevSim),
|
||||
.sections = NETDEV_COMMON_SECTIONS,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
.can_set_mac = netdevsim_can_set_mac,
|
||||
.iftype = ARPHRD_ETHER,
|
||||
.generate_mac = true,
|
||||
};
|
||||
|
||||
@@ -1119,6 +1119,11 @@ static void netdev_tunnel_init(NetDev *netdev) {
|
||||
t->ttl = DEFAULT_IPV6_TTL;
|
||||
}
|
||||
|
||||
static bool tunnel_can_set_mac(NetDev *netdev, const struct hw_addr_data *hw_addr) {
|
||||
assert(IN_SET(netdev->kind, NETDEV_KIND_GRETAP, NETDEV_KIND_IP6GRETAP, NETDEV_KIND_ERSPAN));
|
||||
return true;
|
||||
}
|
||||
|
||||
const NetDevVTable ipip_vtable = {
|
||||
.object_size = sizeof(Tunnel),
|
||||
.init = netdev_tunnel_init,
|
||||
@@ -1188,6 +1193,7 @@ const NetDevVTable gretap_vtable = {
|
||||
.is_ready_to_create = netdev_tunnel_is_ready_to_create,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
.needs_reconfigure = tunnel_needs_reconfigure,
|
||||
.can_set_mac = tunnel_can_set_mac,
|
||||
.iftype = ARPHRD_ETHER,
|
||||
.generate_mac = true,
|
||||
};
|
||||
@@ -1213,6 +1219,7 @@ const NetDevVTable ip6gretap_vtable = {
|
||||
.is_ready_to_create = netdev_tunnel_is_ready_to_create,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
.needs_reconfigure = tunnel_needs_reconfigure,
|
||||
.can_set_mac = tunnel_can_set_mac,
|
||||
.iftype = ARPHRD_ETHER,
|
||||
.generate_mac = true,
|
||||
};
|
||||
@@ -1238,6 +1245,7 @@ const NetDevVTable erspan_vtable = {
|
||||
.is_ready_to_create = netdev_tunnel_is_ready_to_create,
|
||||
.config_verify = netdev_tunnel_verify,
|
||||
.needs_reconfigure = tunnel_needs_reconfigure,
|
||||
.can_set_mac = tunnel_can_set_mac,
|
||||
.iftype = ARPHRD_ETHER,
|
||||
.generate_mac = true,
|
||||
};
|
||||
|
||||
+78
-69
@@ -36,15 +36,33 @@ static TunTap* TUNTAP(NetDev *netdev) {
|
||||
|
||||
DEFINE_PRIVATE_HASH_OPS_FULL(named_fd_hash_ops, char, string_hash_func, string_compare_func, free, void, close_fd_ptr);
|
||||
|
||||
int manager_add_tuntap_fd(Manager *m, int fd, const char *name) {
|
||||
static int manager_add_tuntap_fd_impl(Manager *m, int fd, const char *name) {
|
||||
_cleanup_free_ char *tuntap_name = NULL;
|
||||
const char *p;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(fd >= 0);
|
||||
assert(name);
|
||||
|
||||
tuntap_name = strdup(name);
|
||||
if (!tuntap_name)
|
||||
return log_oom_debug();
|
||||
|
||||
r = hashmap_ensure_put(&m->tuntap_fds_by_name, &named_fd_hash_ops, tuntap_name, FD_TO_PTR(fd));
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to store tuntap fd: %m");
|
||||
|
||||
TAKE_PTR(tuntap_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int manager_add_tuntap_fd(Manager *m, int fd, const char *name) {
|
||||
const char *p;
|
||||
|
||||
assert(m);
|
||||
assert(fd >= 0);
|
||||
assert(name);
|
||||
|
||||
p = startswith(name, "tuntap-");
|
||||
if (!p)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Received unknown fd (%s).", name);
|
||||
@@ -52,66 +70,76 @@ int manager_add_tuntap_fd(Manager *m, int fd, const char *name) {
|
||||
if (!ifname_valid(p))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Received tuntap fd with invalid name (%s).", p);
|
||||
|
||||
tuntap_name = strdup(p);
|
||||
if (!tuntap_name)
|
||||
return log_oom_debug();
|
||||
return manager_add_tuntap_fd_impl(m, fd, p);
|
||||
}
|
||||
|
||||
r = hashmap_ensure_put(&m->tuntap_fds_by_name, &named_fd_hash_ops, tuntap_name, FD_TO_PTR(fd));
|
||||
static int netdev_take_tuntap_fd(Manager *m, const char *ifname) {
|
||||
_unused_ _cleanup_free_ char *name = NULL;
|
||||
void *p;
|
||||
|
||||
assert(m);
|
||||
assert(ifname);
|
||||
|
||||
p = hashmap_remove2(m->tuntap_fds_by_name, ifname, (void**) &name);
|
||||
if (!p)
|
||||
return -EBADF;
|
||||
|
||||
return PTR_TO_FD(p);
|
||||
}
|
||||
|
||||
static int netdev_push_tuntap_fd(NetDev *netdev, int fd) {
|
||||
_unused_ _cleanup_close_ int fd_old = -EBADF;
|
||||
int r;
|
||||
|
||||
assert(netdev->manager);
|
||||
|
||||
fd_old = netdev_take_tuntap_fd(netdev->manager, netdev->ifname);
|
||||
|
||||
if (!TUNTAP(netdev)->keep_fd)
|
||||
return 0;
|
||||
|
||||
r = manager_add_tuntap_fd_impl(netdev->manager, fd, netdev->ifname);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to store tuntap fd: %m");
|
||||
return r;
|
||||
|
||||
TAKE_PTR(tuntap_name);
|
||||
return 0;
|
||||
(void) notify_push_fdf(fd, "tuntap-%s", netdev->ifname);
|
||||
return 1; /* saved */
|
||||
}
|
||||
|
||||
static void manager_close_and_notify_tuntap_fd(Manager *m, const char *ifname) {
|
||||
assert(m);
|
||||
assert(ifname);
|
||||
|
||||
/* netdev_take_tuntap_fd() may invalidate ifname. Hence, need to create fdname earlier. */
|
||||
const char *fdname = strjoina("tuntap-", ifname);
|
||||
close_and_notify_warn(netdev_take_tuntap_fd(m, ifname), fdname);
|
||||
}
|
||||
|
||||
void manager_clear_unmanaged_tuntap_fds(Manager *m) {
|
||||
char *name;
|
||||
const char *name;
|
||||
void *p;
|
||||
|
||||
assert(m);
|
||||
|
||||
while ((p = hashmap_steal_first_key_and_value(m->tuntap_fds_by_name, (void**) &name))) {
|
||||
close_and_notify_warn(PTR_TO_FD(p), name);
|
||||
name = mfree(name);
|
||||
HASHMAP_FOREACH_KEY(p, name, m->tuntap_fds_by_name) {
|
||||
NetDev *netdev;
|
||||
|
||||
if (netdev_get(m, name, &netdev) < 0 ||
|
||||
!IN_SET(netdev->kind, NETDEV_KIND_TAP, NETDEV_KIND_TUN) ||
|
||||
!TUNTAP(netdev)->keep_fd)
|
||||
manager_close_and_notify_tuntap_fd(m, name);
|
||||
}
|
||||
}
|
||||
|
||||
static int tuntap_take_fd(NetDev *netdev) {
|
||||
_cleanup_free_ char *name = NULL;
|
||||
void *p;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(netdev->manager);
|
||||
|
||||
r = link_get_by_name(netdev->manager, netdev->ifname, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
p = hashmap_remove2(netdev->manager->tuntap_fds_by_name, netdev->ifname, (void**) &name);
|
||||
if (!p)
|
||||
return -ENOENT;
|
||||
|
||||
log_netdev_debug(netdev, "Found file descriptor in fd store.");
|
||||
return PTR_TO_FD(p);
|
||||
}
|
||||
|
||||
static int netdev_create_tuntap(NetDev *netdev) {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
struct ifreq ifr = {};
|
||||
TunTap *t;
|
||||
TunTap *t = TUNTAP(netdev);
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(netdev->manager);
|
||||
t = TUNTAP(netdev);
|
||||
assert(t);
|
||||
|
||||
fd = TAKE_FD(t->fd);
|
||||
if (fd < 0)
|
||||
fd = tuntap_take_fd(netdev);
|
||||
if (fd < 0)
|
||||
fd = open(TUN_DEV, O_RDWR|O_CLOEXEC);
|
||||
fd = open(TUN_DEV, O_RDWR|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return log_netdev_error_errno(netdev, errno, "Failed to open " TUN_DEV ": %m");
|
||||
|
||||
@@ -175,42 +203,25 @@ static int netdev_create_tuntap(NetDev *netdev) {
|
||||
if (ioctl(fd, TUNSETPERSIST, 1) < 0)
|
||||
return log_netdev_error_errno(netdev, errno, "TUNSETPERSIST failed: %m");
|
||||
|
||||
if (t->keep_fd) {
|
||||
t->fd = TAKE_FD(fd);
|
||||
(void) notify_push_fdf(t->fd, "tuntap-%s", netdev->ifname);
|
||||
}
|
||||
r = netdev_push_tuntap_fd(netdev, fd);
|
||||
if (r < 0)
|
||||
return log_netdev_warning_errno(netdev, r, "Failed to save TUN/TAP fd: %m");
|
||||
if (r > 0)
|
||||
TAKE_FD(fd);
|
||||
|
||||
netdev_enter_ready(netdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tuntap_init(NetDev *netdev) {
|
||||
TunTap *t;
|
||||
|
||||
assert(netdev);
|
||||
t = TUNTAP(netdev);
|
||||
assert(t);
|
||||
|
||||
t->fd = -EBADF;
|
||||
}
|
||||
|
||||
static void tuntap_drop(NetDev *netdev) {
|
||||
TunTap *t;
|
||||
|
||||
assert(netdev);
|
||||
t = TUNTAP(netdev);
|
||||
assert(t);
|
||||
|
||||
t->fd = close_and_notify_warn(t->fd, netdev->ifname);
|
||||
manager_close_and_notify_tuntap_fd(netdev->manager, netdev->ifname);
|
||||
}
|
||||
|
||||
static void tuntap_done(NetDev *netdev) {
|
||||
TunTap *t;
|
||||
TunTap *t = TUNTAP(netdev);
|
||||
|
||||
assert(netdev);
|
||||
t = TUNTAP(netdev);
|
||||
assert(t);
|
||||
|
||||
t->fd = safe_close(t->fd);
|
||||
t->user_name = mfree(t->user_name);
|
||||
t->group_name = mfree(t->group_name);
|
||||
}
|
||||
@@ -237,7 +248,6 @@ const NetDevVTable tun_vtable = {
|
||||
.object_size = sizeof(TunTap),
|
||||
.sections = NETDEV_COMMON_SECTIONS "Tun\0",
|
||||
.config_verify = tuntap_verify,
|
||||
.init = tuntap_init,
|
||||
.drop = tuntap_drop,
|
||||
.done = tuntap_done,
|
||||
.create = netdev_create_tuntap,
|
||||
@@ -249,7 +259,6 @@ const NetDevVTable tap_vtable = {
|
||||
.object_size = sizeof(TunTap),
|
||||
.sections = NETDEV_COMMON_SECTIONS "Tap\0",
|
||||
.config_verify = tuntap_verify,
|
||||
.init = tuntap_init,
|
||||
.drop = tuntap_drop,
|
||||
.done = tuntap_done,
|
||||
.create = netdev_create_tuntap,
|
||||
|
||||
@@ -8,7 +8,6 @@ typedef struct TunTap TunTap;
|
||||
struct TunTap {
|
||||
NetDev meta;
|
||||
|
||||
int fd;
|
||||
char *user_name;
|
||||
char *group_name;
|
||||
bool multi_queue;
|
||||
|
||||
@@ -150,4 +150,5 @@ const NetDevVTable veth_vtable = {
|
||||
.get_ifindex = netdev_veth_get_ifindex,
|
||||
.iftype = ARPHRD_ETHER,
|
||||
.generate_mac = true,
|
||||
.keep_existing = true,
|
||||
};
|
||||
|
||||
@@ -21,11 +21,17 @@ static int netdev_vrf_fill_message_create(NetDev *netdev, Link *link, sd_netlink
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool vrf_can_set_mac(NetDev *netdev, const struct hw_addr_data *hw_addr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const NetDevVTable vrf_vtable = {
|
||||
.object_size = sizeof(Vrf),
|
||||
.sections = NETDEV_COMMON_SECTIONS "VRF\0",
|
||||
.fill_message_create = netdev_vrf_fill_message_create,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
.can_set_mac = vrf_can_set_mac,
|
||||
.iftype = ARPHRD_ETHER,
|
||||
.generate_mac = true,
|
||||
.keep_existing = true,
|
||||
};
|
||||
|
||||
@@ -124,4 +124,5 @@ const NetDevVTable vxcan_vtable = {
|
||||
.set_ifindex = netdev_vxcan_set_ifindex,
|
||||
.get_ifindex = netdev_vxcan_get_ifindex,
|
||||
.iftype = ARPHRD_CAN,
|
||||
.keep_existing = true,
|
||||
};
|
||||
|
||||
@@ -197,6 +197,10 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool vxlan_can_set_mac(NetDev *netdev, const struct hw_addr_data *hw_addr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool vxlan_can_set_mtu(NetDev *netdev, uint32_t mtu) {
|
||||
assert(netdev);
|
||||
|
||||
@@ -452,6 +456,7 @@ const NetDevVTable vxlan_vtable = {
|
||||
.create_type = NETDEV_CREATE_STACKED,
|
||||
.is_ready_to_create = netdev_vxlan_is_ready_to_create,
|
||||
.config_verify = netdev_vxlan_verify,
|
||||
.can_set_mac = vxlan_can_set_mac,
|
||||
.can_set_mtu = vxlan_can_set_mtu,
|
||||
.needs_reconfigure = vxlan_needs_reconfigure,
|
||||
.iftype = ARPHRD_ETHER,
|
||||
|
||||
@@ -1265,4 +1265,5 @@ const NetDevVTable wireguard_vtable = {
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
.config_verify = wireguard_verify,
|
||||
.iftype = ARPHRD_NONE,
|
||||
.keep_existing = true,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user