summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Gundersen <teg@jklm.no>2014-02-25 21:16:17 +0100
committerTom Gundersen <teg@jklm.no>2014-02-25 21:19:08 +0100
commitfe6b2d55bcb379d01664ed28cea40634cb6b52e3 (patch)
tree330da49ab0f895c7c1618a36b4439f41a04d9472
parente3ab0c0e19227efdf15237dd9136fc6fc7f3839d (diff)
networkd: add basic support for MACVLANs
-rw-r--r--man/systemd.netdev.xml20
-rw-r--r--man/systemd.network.xml7
-rw-r--r--src/network/networkd-link.c23
-rw-r--r--src/network/networkd-netdev-gperf.gperf1
-rw-r--r--src/network/networkd-netdev.c65
-rw-r--r--src/network/networkd-network-gperf.gperf1
-rw-r--r--src/network/networkd-network.c50
-rw-r--r--src/network/networkd.h21
8 files changed, 170 insertions, 18 deletions
diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml
index 26cc6158c..5d8b41a3b 100644
--- a/man/systemd.netdev.xml
+++ b/man/systemd.netdev.xml
@@ -142,8 +142,9 @@
<term><varname>Kind=</varname></term>
<listitem>
<para>The netdev kind. Currently, <literal>bridge</literal>,
- <literal>bond</literal> and <literal>vlan</literal>
- are supported. This option is compulsory.</para>
+ <literal>bond</literal>, <literal>vlan</literal> and
+ <literal>macvlan</literal> are supported. This option
+ is compulsory.</para>
</listitem>
</varlistentry>
</variablelist>
@@ -161,6 +162,21 @@
</varlistentry>
</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>
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 1ba4f4a97..fcf48c6d4 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -235,6 +235,13 @@
may be specified more than once.</para>
</listitem>
</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>
<para>An <literal>[Address]</literal> section accepts the following keys.
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 1f495b38b..b217123ec 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -890,7 +890,7 @@ static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
}
static int link_enter_enslave(Link *link) {
- NetDev *vlan;
+ NetDev *vlan, *macvlan;
Iterator i;
int r;
@@ -901,7 +901,8 @@ static int link_enter_enslave(Link *link) {
link->state = LINK_STATE_ENSLAVING;
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);
if (link->network->bridge) {
@@ -943,6 +944,24 @@ static int link_enter_enslave(Link *link) {
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;
}
diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf
index 7dd47f971..2793d77a7 100644
--- a/src/network/networkd-netdev-gperf.gperf
+++ b/src/network/networkd-netdev-gperf.gperf
@@ -23,3 +23,4 @@ NetDev.Description, config_parse_string, 0,
NetDev.Name, config_parse_ifname, 0, offsetof(NetDev, name)
NetDev.Kind, config_parse_netdev_kind, 0, offsetof(NetDev, kind)
VLAN.Id, config_parse_uint64, 0, offsetof(NetDev, vlanid)
+MACVLAN.Mode, config_parse_macvlan_mode, 0, offsetof(NetDev, macvlan_mode)
diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index 05f21fa87..9f580aeab 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -32,11 +32,22 @@ static const char* const netdev_kind_table[] = {
[NETDEV_KIND_BRIDGE] = "bridge",
[NETDEV_KIND_BOND] = "bond",
[NETDEV_KIND_VLAN] = "vlan",
+ [NETDEV_KIND_MACVLAN] = "macvlan",
};
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_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) {
netdev_enslave_callback *callback;
@@ -166,8 +177,8 @@ static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t c
int r;
assert(netdev);
- assert(!(netdev->kind == NETDEV_KIND_VLAN) ||
- (link && callback && netdev->vlanid <= VLANID_MAX));
+ assert(!(netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN) ||
+ (link && callback));
assert(netdev->name);
assert(netdev->manager);
assert(netdev->manager->rtnl);
@@ -220,7 +231,7 @@ static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t c
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);
if (r < 0) {
log_error_netdev(netdev,
@@ -229,12 +240,24 @@ static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t c
return r;
}
- 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->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);
@@ -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) {
- if (netdev->kind == NETDEV_KIND_VLAN)
+ if (netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN)
return netdev_create(netdev, link, callback);
if (netdev->state == NETDEV_STATE_READY) {
@@ -335,10 +358,12 @@ static int netdev_load_one(Manager *manager, const char *filename) {
netdev->manager = manager;
netdev->state = _NETDEV_STATE_INVALID;
netdev->kind = _NETDEV_KIND_INVALID;
+ netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
netdev->vlanid = VLANID_MAX + 1;
- r = config_parse(NULL, filename, file, "Match\0NetDev\0VLAN\0", config_item_perf_lookup,
- (void*) network_netdev_gperf_lookup, false, false, netdev);
+ r = config_parse(NULL, filename, file, "Match\0NetDev\0VLAN\0MACVLAN\0",
+ config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
+ false, false, netdev);
if (r < 0) {
log_warning("Could not parse config file %s: %s", filename, strerror(-r));
return r;
@@ -359,6 +384,19 @@ static int netdev_load_one(Manager *manager, const char *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);
+ 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);
if (!netdev->filename)
return log_oom();
@@ -375,7 +413,8 @@ static int netdev_load_one(Manager *manager, const char *filename) {
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);
if (r < 0)
return r;
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 44aeb9c3a..6cc186f2a 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -28,6 +28,7 @@ Network.Description, config_parse_string, 0,
Network.Bridge, config_parse_bridge, 0, offsetof(Network, bridge)
Network.Bond, config_parse_bond, 0, offsetof(Network, bond)
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.Address, config_parse_address, 0, 0
Network.Gateway, config_parse_gateway, 0, 0
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 14fa92aea..ca79d4ff6 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -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_routes);
- network->vlans = hashmap_new(uint64_hash_func, uint64_compare_func);
+ network->vlans = hashmap_new(string_hash_func, string_compare_func);
if (!network->vlans)
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);
if (!network->addresses_by_section)
return log_oom();
@@ -150,6 +154,8 @@ void network_free(Network *network) {
hashmap_free(network->vlans);
+ hashmap_free(network->macvlans);
+
while ((route = network->static_routes))
route_free(route);
@@ -330,3 +336,45 @@ int config_parse_vlan(const char *unit,
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;
+}
diff --git a/src/network/networkd.h b/src/network/networkd.h
index 8307bb5b1..85c300982 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -50,10 +50,20 @@ struct netdev_enslave_callback {
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 {
NETDEV_KIND_BRIDGE,
NETDEV_KIND_BOND,
NETDEV_KIND_VLAN,
+ NETDEV_KIND_MACVLAN,
_NETDEV_KIND_MAX,
_NETDEV_KIND_INVALID = -1
} NetDevKind;
@@ -81,6 +91,7 @@ struct NetDev {
NetDevKind kind;
uint64_t vlanid;
+ int32_t macvlan_mode;
int ifindex;
NetDevState state;
@@ -107,6 +118,7 @@ struct Network {
NetDev *bridge;
NetDev *bond;
Hashmap *vlans;
+ Hashmap *macvlans;
bool dhcp;
bool dhcp_dns;
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_;
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_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 */
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,
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 */
const struct ConfigPerfItem* network_network_gperf_lookup(const char *key, unsigned length);