1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-23 21:35:11 +03:00

networkd: add basic support for MACVLANs

This commit is contained in:
Tom Gundersen 2014-02-25 21:16:17 +01:00
parent e3ab0c0e19
commit fe6b2d55bc
8 changed files with 170 additions and 18 deletions

View File

@ -142,8 +142,9 @@
<term><varname>Kind=</varname></term> <term><varname>Kind=</varname></term>
<listitem> <listitem>
<para>The netdev kind. Currently, <literal>bridge</literal>, <para>The netdev kind. Currently, <literal>bridge</literal>,
<literal>bond</literal> and <literal>vlan</literal> <literal>bond</literal>, <literal>vlan</literal> and
are supported. This option is compulsory.</para> <literal>macvlan</literal> are supported. This option
is compulsory.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>
@ -161,6 +162,21 @@
</varlistentry> </varlistentry>
</variablelist> </variablelist>
<para>The <literal>[MACVLAN]</literal> section only applies for netdevs of kind
<literal>macvlan</literal>, and accepts the following key:</para>
<variablelist class='network-directives'>
<varlistentry>
<term><varname>Mode=</varname></term>
<listitem>
<para>The MACVLAN mode to use. The supported options are
<literal>private</literal>, <literal>vepa</literal>,
<literal>bridge</literal> and <literal>passthru</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1> </refsect1>
<refsect1> <refsect1>

View File

@ -235,6 +235,13 @@
may be specified more than once.</para> may be specified more than once.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>MACVLAN=</varname></term>
<listitem>
<para>The name of a MACVLAN to create on the link. This option
may be specified more than once.</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
<para>An <literal>[Address]</literal> section accepts the following keys. <para>An <literal>[Address]</literal> section accepts the following keys.

View File

@ -890,7 +890,7 @@ static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
} }
static int link_enter_enslave(Link *link) { static int link_enter_enslave(Link *link) {
NetDev *vlan; NetDev *vlan, *macvlan;
Iterator i; Iterator i;
int r; int r;
@ -901,7 +901,8 @@ static int link_enter_enslave(Link *link) {
link->state = LINK_STATE_ENSLAVING; link->state = LINK_STATE_ENSLAVING;
if (!link->network->bridge && !link->network->bond && if (!link->network->bridge && !link->network->bond &&
hashmap_isempty(link->network->vlans)) hashmap_isempty(link->network->vlans) &&
hashmap_isempty(link->network->macvlans))
return link_enslaved(link); return link_enslaved(link);
if (link->network->bridge) { if (link->network->bridge) {
@ -943,6 +944,24 @@ static int link_enter_enslave(Link *link) {
link->enslaving ++; link->enslaving ++;
} }
HASHMAP_FOREACH(macvlan, link->network->macvlans, i) {
log_struct_link(LOG_DEBUG, link,
"MESSAGE=%s: enslaving by '%s'",
link->ifname, macvlan->name, NETDEV(macvlan), NULL);
r = netdev_enslave(macvlan, link, &enslave_handler);
if (r < 0) {
log_struct_link(LOG_WARNING, link,
"MESSAGE=%s: could not enslave by '%s': %s",
link->ifname, macvlan->name, strerror(-r),
NETDEV(macvlan), NULL);
link_enter_failed(link);
return r;
}
link->enslaving ++;
}
return 0; return 0;
} }

View File

@ -23,3 +23,4 @@ NetDev.Description, config_parse_string, 0,
NetDev.Name, config_parse_ifname, 0, offsetof(NetDev, name) NetDev.Name, config_parse_ifname, 0, offsetof(NetDev, name)
NetDev.Kind, config_parse_netdev_kind, 0, offsetof(NetDev, kind) NetDev.Kind, config_parse_netdev_kind, 0, offsetof(NetDev, kind)
VLAN.Id, config_parse_uint64, 0, offsetof(NetDev, vlanid) VLAN.Id, config_parse_uint64, 0, offsetof(NetDev, vlanid)
MACVLAN.Mode, config_parse_macvlan_mode, 0, offsetof(NetDev, macvlan_mode)

View File

@ -32,11 +32,22 @@ static const char* const netdev_kind_table[] = {
[NETDEV_KIND_BRIDGE] = "bridge", [NETDEV_KIND_BRIDGE] = "bridge",
[NETDEV_KIND_BOND] = "bond", [NETDEV_KIND_BOND] = "bond",
[NETDEV_KIND_VLAN] = "vlan", [NETDEV_KIND_VLAN] = "vlan",
[NETDEV_KIND_MACVLAN] = "macvlan",
}; };
DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind); DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind"); 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_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");
void netdev_free(NetDev *netdev) { void netdev_free(NetDev *netdev) {
netdev_enslave_callback *callback; netdev_enslave_callback *callback;
@ -166,8 +177,8 @@ static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t c
int r; int r;
assert(netdev); assert(netdev);
assert(!(netdev->kind == NETDEV_KIND_VLAN) || assert(!(netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN) ||
(link && callback && netdev->vlanid <= VLANID_MAX)); (link && callback));
assert(netdev->name); assert(netdev->name);
assert(netdev->manager); assert(netdev->manager);
assert(netdev->manager->rtnl); assert(netdev->manager->rtnl);
@ -220,7 +231,7 @@ static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t c
return r; return r;
} }
if (netdev->vlanid <= VLANID_MAX) { if (netdev->vlanid <= VLANID_MAX || netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
r = sd_rtnl_message_open_container(req, IFLA_INFO_DATA); r = sd_rtnl_message_open_container(req, IFLA_INFO_DATA);
if (r < 0) { if (r < 0) {
log_error_netdev(netdev, log_error_netdev(netdev,
@ -229,12 +240,24 @@ static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t c
return r; return r;
} }
r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid); if (netdev->vlanid <= VLANID_MAX) {
if (r < 0) { r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
log_error_netdev(netdev, if (r < 0) {
"Could not append IFLA_VLAN_ID attribute: %s", log_error_netdev(netdev,
strerror(-r)); "Could not append IFLA_VLAN_ID attribute: %s",
return r; 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); r = sd_rtnl_message_close_container(req);
@ -272,7 +295,7 @@ static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t c
} }
int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) { int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
if (netdev->kind == NETDEV_KIND_VLAN) if (netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN)
return netdev_create(netdev, link, callback); return netdev_create(netdev, link, callback);
if (netdev->state == NETDEV_STATE_READY) { if (netdev->state == NETDEV_STATE_READY) {
@ -335,10 +358,12 @@ static int netdev_load_one(Manager *manager, const char *filename) {
netdev->manager = manager; netdev->manager = manager;
netdev->state = _NETDEV_STATE_INVALID; netdev->state = _NETDEV_STATE_INVALID;
netdev->kind = _NETDEV_KIND_INVALID; netdev->kind = _NETDEV_KIND_INVALID;
netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
netdev->vlanid = VLANID_MAX + 1; netdev->vlanid = VLANID_MAX + 1;
r = config_parse(NULL, filename, file, "Match\0NetDev\0VLAN\0", config_item_perf_lookup, r = config_parse(NULL, filename, file, "Match\0NetDev\0VLAN\0MACVLAN\0",
(void*) network_netdev_gperf_lookup, false, false, netdev); config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
false, false, netdev);
if (r < 0) { if (r < 0) {
log_warning("Could not parse config file %s: %s", filename, strerror(-r)); log_warning("Could not parse config file %s: %s", filename, strerror(-r));
return r; return r;
@ -359,6 +384,19 @@ static int netdev_load_one(Manager *manager, const char *filename) {
return 0; 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);
return 0;
}
if (netdev->kind != NETDEV_KIND_MACVLAN &&
netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
netdev_kind_to_string(netdev->kind), filename);
return 0;
}
netdev->filename = strdup(filename); netdev->filename = strdup(filename);
if (!netdev->filename) if (!netdev->filename)
return log_oom(); return log_oom();
@ -375,7 +413,8 @@ static int netdev_load_one(Manager *manager, const char *filename) {
LIST_HEAD_INIT(netdev->callbacks); LIST_HEAD_INIT(netdev->callbacks);
if (netdev->kind != NETDEV_KIND_VLAN) { if (netdev->kind != NETDEV_KIND_VLAN &&
netdev->kind != NETDEV_KIND_MACVLAN) {
r = netdev_create(netdev, NULL, NULL); r = netdev_create(netdev, NULL, NULL);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -28,6 +28,7 @@ Network.Description, config_parse_string, 0,
Network.Bridge, config_parse_bridge, 0, offsetof(Network, bridge) Network.Bridge, config_parse_bridge, 0, offsetof(Network, bridge)
Network.Bond, config_parse_bond, 0, offsetof(Network, bond) Network.Bond, config_parse_bond, 0, offsetof(Network, bond)
Network.VLAN, config_parse_vlan, 0, offsetof(Network, vlans) Network.VLAN, config_parse_vlan, 0, offsetof(Network, vlans)
Network.MACVLAN, config_parse_macvlan, 0, offsetof(Network, macvlans)
Network.DHCP, config_parse_bool, 0, offsetof(Network, dhcp) Network.DHCP, config_parse_bool, 0, offsetof(Network, dhcp)
Network.Address, config_parse_address, 0, 0 Network.Address, config_parse_address, 0, 0
Network.Gateway, config_parse_gateway, 0, 0 Network.Gateway, config_parse_gateway, 0, 0

View File

@ -53,10 +53,14 @@ static int network_load_one(Manager *manager, const char *filename) {
LIST_HEAD_INIT(network->static_addresses); LIST_HEAD_INIT(network->static_addresses);
LIST_HEAD_INIT(network->static_routes); LIST_HEAD_INIT(network->static_routes);
network->vlans = hashmap_new(uint64_hash_func, uint64_compare_func); network->vlans = hashmap_new(string_hash_func, string_compare_func);
if (!network->vlans) if (!network->vlans)
return log_oom(); return log_oom();
network->macvlans = hashmap_new(uint64_hash_func, uint64_compare_func);
if (!network->macvlans)
return log_oom();
network->addresses_by_section = hashmap_new(uint64_hash_func, uint64_compare_func); network->addresses_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
if (!network->addresses_by_section) if (!network->addresses_by_section)
return log_oom(); return log_oom();
@ -150,6 +154,8 @@ void network_free(Network *network) {
hashmap_free(network->vlans); hashmap_free(network->vlans);
hashmap_free(network->macvlans);
while ((route = network->static_routes)) while ((route = network->static_routes))
route_free(route); route_free(route);
@ -330,3 +336,45 @@ int config_parse_vlan(const char *unit,
return 0; return 0;
} }
int config_parse_macvlan(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) {
Network *network = userdata;
NetDev *netdev;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
r = netdev_get(network->manager, rvalue, &netdev);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"MACVLAN is invalid, ignoring assignment: %s", rvalue);
return 0;
}
if (netdev->kind != NETDEV_KIND_MACVLAN) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"NetDev is not a MACVLAN, ignoring assignment: %s", rvalue);
return 0;
}
r = hashmap_put(network->macvlans, netdev->name, netdev);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"Can not add MACVLAN to network: %s", rvalue);
return 0;
}
return 0;
}

View File

@ -50,10 +50,20 @@ struct netdev_enslave_callback {
LIST_FIELDS(netdev_enslave_callback, callbacks); LIST_FIELDS(netdev_enslave_callback, callbacks);
}; };
typedef enum MacVlanMode {
NETDEV_MACVLAN_MODE_PRIVATE = MACVLAN_MODE_PRIVATE,
NETDEV_MACVLAN_MODE_VEPA = MACVLAN_MODE_VEPA,
NETDEV_MACVLAN_MODE_BRIDGE = MACVLAN_MODE_BRIDGE,
NETDEV_MACVLAN_MODE_PASSTHRU = MACVLAN_MODE_PASSTHRU,
_NETDEV_MACVLAN_MODE_MAX,
_NETDEV_MACVLAN_MODE_INVALID = -1
} MacVlanMode;
typedef enum NetDevKind { typedef enum NetDevKind {
NETDEV_KIND_BRIDGE, NETDEV_KIND_BRIDGE,
NETDEV_KIND_BOND, NETDEV_KIND_BOND,
NETDEV_KIND_VLAN, NETDEV_KIND_VLAN,
NETDEV_KIND_MACVLAN,
_NETDEV_KIND_MAX, _NETDEV_KIND_MAX,
_NETDEV_KIND_INVALID = -1 _NETDEV_KIND_INVALID = -1
} NetDevKind; } NetDevKind;
@ -81,6 +91,7 @@ struct NetDev {
NetDevKind kind; NetDevKind kind;
uint64_t vlanid; uint64_t vlanid;
int32_t macvlan_mode;
int ifindex; int ifindex;
NetDevState state; NetDevState state;
@ -107,6 +118,7 @@ struct Network {
NetDev *bridge; NetDev *bridge;
NetDev *bond; NetDev *bond;
Hashmap *vlans; Hashmap *vlans;
Hashmap *macvlans;
bool dhcp; bool dhcp;
bool dhcp_dns; bool dhcp_dns;
bool dhcp_mtu; bool dhcp_mtu;
@ -248,8 +260,13 @@ int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t cb);
const char *netdev_kind_to_string(NetDevKind d) _const_; const char *netdev_kind_to_string(NetDevKind d) _const_;
NetDevKind netdev_kind_from_string(const char *d) _pure_; NetDevKind netdev_kind_from_string(const char *d) _pure_;
const char *macvlan_mode_to_string(MacVlanMode d) _const_;
MacVlanMode macvlan_mode_from_string(const char *d) _pure_;
int config_parse_netdev_kind(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); int config_parse_netdev_kind(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);
int config_parse_macvlan_mode(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);
/* gperf */ /* gperf */
const struct ConfigPerfItem* network_netdev_gperf_lookup(const char *key, unsigned length); const struct ConfigPerfItem* network_netdev_gperf_lookup(const char *key, unsigned length);
@ -277,6 +294,10 @@ int config_parse_vlan(const char *unit, const char *filename, unsigned line,
const char *section, unsigned section_line, const char *lvalue, const char *section, unsigned section_line, const char *lvalue,
int ltype, const char *rvalue, void *data, void *userdata); int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_macvlan(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);
/* gperf */ /* gperf */
const struct ConfigPerfItem* network_network_gperf_lookup(const char *key, unsigned length); const struct ConfigPerfItem* network_network_gperf_lookup(const char *key, unsigned length);