#include "list.h"
#include "siphash24.h"
-#define VLANID_MAX 4094
-
static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
[NETDEV_KIND_BRIDGE] = "bridge",
[NETDEV_KIND_BOND] = "bond",
[NETDEV_KIND_GRE] = "gre",
[NETDEV_KIND_SIT] = "sit",
[NETDEV_KIND_VETH] = "veth",
- [NETDEV_KIND_VTI] = "vti"
+ [NETDEV_KIND_VTI] = "vti",
+ [NETDEV_KIND_DUMMY] = "dummy",
+ [NETDEV_KIND_TUN] = "tun",
+ [NETDEV_KIND_TAP] = "tap",
};
DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
-static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
- [NETDEV_MACVLAN_MODE_PRIVATE] = "private",
- [NETDEV_MACVLAN_MODE_VEPA] = "vepa",
- [NETDEV_MACVLAN_MODE_BRIDGE] = "bridge",
- [NETDEV_MACVLAN_MODE_PASSTHRU] = "passthru",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
-DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode");
static void netdev_cancel_callbacks(NetDev *netdev) {
_cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
- netdev_enslave_callback *callback;
+ netdev_join_callback *callback;
if (!netdev)
return;
free(netdev->ifname_peer);
free(netdev->mac);
free(netdev->mac_peer);
+ free(netdev->user_name);
+ free(netdev->group_name);
condition_free_list(netdev->match_host);
condition_free_list(netdev->match_virt);
assert(netdev->state == NETDEV_STATE_READY);
assert(netdev->manager);
assert(netdev->manager->rtnl);
+ assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
assert(link);
assert(callback);
return r;
}
+ link_ref(link);
+
log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
return 0;
}
static int netdev_enter_ready(NetDev *netdev) {
- netdev_enslave_callback *callback;
+ netdev_join_callback *callback, *callback_next;
+ int r;
assert(netdev);
assert(netdev->ifname);
log_info_netdev(netdev, "netdev ready");
- LIST_FOREACH(callbacks, callback, netdev->callbacks) {
+ LIST_FOREACH_SAFE(callbacks, callback, callback_next, netdev->callbacks) {
/* enslave the links that were attempted to be enslaved before the
* link was ready */
- netdev_enslave_ready(netdev, callback->link, callback->callback);
+ r = netdev_enslave_ready(netdev, callback->link, callback->callback);
+ if (r < 0)
+ return r;
+
+ LIST_REMOVE(callbacks, netdev->callbacks, callback);
+ link_unref(callback->link);
+ free(callback);
}
return 0;
}
+/* callback for netdev's created without a backing Link */
static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
- NetDev *netdev = userdata;
+ _cleanup_netdev_unref_ NetDev *netdev = userdata;
int r;
assert(netdev->state != _NETDEV_STATE_INVALID);
return 1;
}
-int config_parse_tunnel_address(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
- NetDev *n = data;
- unsigned char family = AF_INET;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- r = net_parse_inaddr(rvalue, &family, n);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Tunnel address is invalid, ignoring assignment: %s", rvalue);
- return 0;
- }
- return 0;
-}
-
-static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
+static int netdev_create(NetDev *netdev) {
_cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
const char *kind;
int r;
assert(netdev);
- assert(!(netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN) ||
- (link && callback));
assert(netdev->ifname);
assert(netdev->manager);
assert(netdev->manager->rtnl);
return r;
}
- if (link) {
- r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
- if (r < 0) {
- log_error_netdev(netdev,
- "Could not append IFLA_LINK attribute: %s",
- strerror(-r));
- return r;
- }
- }
-
r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->ifname);
if (r < 0) {
log_error_netdev(netdev,
return r;
}
- if (netdev->vlanid <= VLANID_MAX) {
- r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
- if (r < 0) {
- log_error_netdev(netdev,
- "Could not append IFLA_VLAN_ID attribute: %s",
- strerror(-r));
- return r;
- }
- }
-
- if (netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
- r = sd_rtnl_message_append_u32(req, IFLA_MACVLAN_MODE, netdev->macvlan_mode);
- if (r < 0) {
- log_error_netdev(netdev,
- "Could not append IFLA_MACVLAN_MODE attribute: %s",
- strerror(-r));
- return r;
- }
- }
-
r = sd_rtnl_message_close_container(req);
if (r < 0) {
log_error_netdev(netdev,
return r;
}
- if (link)
- r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
- else
- r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
+ r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
if (r < 0) {
log_error_netdev(netdev,
"Could not send rtnetlink message: %s", strerror(-r));
return r;
}
+ netdev_ref(netdev);
+
log_debug_netdev(netdev, "creating netdev");
netdev->state = NETDEV_STATE_CREATING;
return 0;
}
-int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
+static int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
int r;
- switch(netdev->kind) {
- case NETDEV_KIND_VLAN:
- case NETDEV_KIND_MACVLAN:
- return netdev_create(netdev, link, callback);
- case NETDEV_KIND_VXLAN:
- return netdev_create_vxlan(netdev, link, callback);
- case NETDEV_KIND_IPIP:
- case NETDEV_KIND_GRE:
- case NETDEV_KIND_SIT:
- case NETDEV_KIND_VTI:
- return netdev_create_tunnel(link, netdev_create_handler);
- default:
- break;
- }
+ assert(netdev);
+ assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
if (netdev->state == NETDEV_STATE_READY) {
r = netdev_enslave_ready(netdev, link, callback);
return r;
} else {
/* the netdev is not yet read, save this request for when it is*/
- netdev_enslave_callback *cb;
+ netdev_join_callback *cb;
- cb = new0(netdev_enslave_callback, 1);
+ cb = new0(netdev_join_callback, 1);
if (!cb)
return log_oom();
cb->callback = callback;
cb->link = link;
+ link_ref(link);
LIST_PREPEND(callbacks, netdev->callbacks, cb);
}
return 0;
}
+/* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
+int netdev_join(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
+
+ assert(netdev);
+
+ switch(netdev->kind) {
+ case NETDEV_KIND_VLAN:
+ return netdev_create_vlan(netdev, link, callback);
+ case NETDEV_KIND_MACVLAN:
+ return netdev_create_macvlan(netdev, link, callback);
+ case NETDEV_KIND_VXLAN:
+ return netdev_create_vxlan(netdev, link, callback);
+ case NETDEV_KIND_IPIP:
+ case NETDEV_KIND_GRE:
+ case NETDEV_KIND_SIT:
+ case NETDEV_KIND_VTI:
+ return netdev_create_tunnel(netdev, link, callback);
+ case NETDEV_KIND_BRIDGE:
+ case NETDEV_KIND_BOND:
+ return netdev_enslave(netdev, link, callback);
+ default:
+ assert_not_reached("Enslaving by invalid netdev kind");
+ }
+
+ return 0;
+}
+
int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
uint16_t type;
const char *kind;
return r;
}
- kind = netdev_kind_to_string(netdev->kind);
- if (!kind) {
- log_error_netdev(netdev, "Could not get kind");
- netdev_enter_failed(netdev);
- return -EINVAL;
+ if (netdev->kind == NETDEV_KIND_TAP)
+ /* the kernel does not distinguish between tun and tap */
+ kind = "tun";
+ else {
+ kind = netdev_kind_to_string(netdev->kind);
+ if (!kind) {
+ log_error_netdev(netdev, "Could not get kind");
+ netdev_enter_failed(netdev);
+ return -EINVAL;
+ }
}
if (!streq(kind, received_kind)) {
- log_error_netdev(netdev, "Received newlink with wrong KIND %s, "
+ log_error_netdev(netdev,
+ "Received newlink with wrong KIND %s, "
"expected %s", received_kind, kind);
netdev_enter_failed(netdev);
return r;
netdev->state = _NETDEV_STATE_INVALID;
netdev->kind = _NETDEV_KIND_INVALID;
netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
+ netdev->bond_mode = _NETDEV_BOND_MODE_INVALID;
netdev->vlanid = VLANID_MAX + 1;
netdev->vxlanid = VXLAN_VID_MAX + 1;
netdev->tunnel_pmtudisc = true;
netdev->learning = true;
r = config_parse(NULL, filename, file,
- "Match\0NetDev\0VLAN\0MACVLAN\0VXLAN\0Tunnel\0Peer\0",
+ "Match\0NetDev\0VLAN\0MACVLAN\0VXLAN\0Tunnel\0Peer\0Tun\0Tap\0Bond\0",
config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
false, false, netdev);
if (r < 0) {
return r;
}
- if (netdev->kind == _NETDEV_KIND_INVALID) {
+ switch (netdev->kind) {
+ case _NETDEV_KIND_INVALID:
log_warning("NetDev without Kind configured in %s. Ignoring", filename);
return 0;
+ case NETDEV_KIND_VLAN:
+ if (netdev->vlanid > VLANID_MAX) {
+ log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
+ return 0;
+ }
+ break;
+ case NETDEV_KIND_VXLAN:
+ if (netdev->vxlanid > VXLAN_VID_MAX) {
+ log_warning("VXLAN without valid Id configured in %s. Ignoring", filename);
+ return 0;
+ }
+ break;
+ case NETDEV_KIND_IPIP:
+ case NETDEV_KIND_GRE:
+ case NETDEV_KIND_SIT:
+ case NETDEV_KIND_VTI:
+ if (netdev->local.in.s_addr == INADDR_ANY) {
+ log_warning("Tunnel without local address configured in %s. Ignoring", filename);
+ return 0;
+ }
+ if (netdev->remote.in.s_addr == INADDR_ANY) {
+ log_warning("Tunnel without remote address configured in %s. Ignoring", filename);
+ return 0;
+ }
+ if (netdev->family != AF_INET) {
+ log_warning("Tunnel with invalid address family configured in %s. Ignoring", filename);
+ return 0;
+ }
+ break;
+ default:
+ break;
}
if (!netdev->ifname) {
return 0;
}
- if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid > VLANID_MAX) {
- log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
- return 0;
- }
-
- if (netdev->kind == NETDEV_KIND_VXLAN && netdev->vxlanid > VXLAN_VID_MAX) {
- log_warning("VXLAN without valid Id configured in %s. Ignoring", filename);
- return 0;
- }
-
if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
log_warning("VLAN Id configured for a %s in %s. Ignoring",
netdev_kind_to_string(netdev->kind), filename);
if (r < 0)
return r;
+ break;
+ case NETDEV_KIND_DUMMY:
+ r = netdev_create_dummy(netdev, netdev_create_handler);
+ if (r < 0)
+ return r;
+
break;
case NETDEV_KIND_BRIDGE:
+ r = netdev_create(netdev);
+ if (r < 0)
+ return r;
+ break;
case NETDEV_KIND_BOND:
- r = netdev_create(netdev, NULL, NULL);
+ r = netdev_create_bond(netdev, netdev_create_handler);
if (r < 0)
return r;
break;