summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlvin Šipraga <alsi@bang-olufsen.dk>2020-07-08 15:52:23 +0200
committerAlvin Šipraga <alsi@bang-olufsen.dk>2020-07-08 18:01:52 +0200
commit0d0de133f04d3870273970cfa4d61aac1ae06098 (patch)
tree911c536fc8cebdb40cb85b787641057c54e568f4
parent24e2494407cb5a88ee81fc238195687e5e0b8a09 (diff)
downloadsystemd-0d0de133f04d3870273970cfa4d61aac1ae06098.tar.gz
network: add support for MACVLAN source mode
Add support for creating a MACVLAN interface in "source" mode by specifying Mode=source in the [MACVLAN] section of a .netdev file. A list of allowed MAC addresses for the corresponding MACVLAN can also be specified with the SourceMACAddress= option of the [MACVLAN] section. An example .netdev file: [NetDev] Name=macvlan0 Kind=macvlan MACAddress=02:DE:AD:BE:EF:00 [MACVLAN] Mode=source SourceMACAddress=02:AB:AB:AB:AB:01 02:CD:CD:CD:CD:01 SourceMACAddress=02:EF:EF:EF:EF:01 The same keys can also be specified in [MACVTAP] for MACVTAP kinds of interfaces, with the same semantics.
-rw-r--r--man/systemd.netdev.xml15
-rw-r--r--src/libsystemd/sd-netlink/netlink-types.c11
-rw-r--r--src/network/netdev/macvlan.c40
-rw-r--r--src/network/netdev/macvlan.h2
-rw-r--r--src/network/netdev/netdev-gperf.gperf2
-rw-r--r--src/shared/macvlan-util.c1
-rw-r--r--src/shared/macvlan-util.h1
-rw-r--r--test/fuzz/fuzz-netdev-parser/directives.netdev2
8 files changed, 72 insertions, 2 deletions
diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml
index 37659326e3..80d1d20d30 100644
--- a/man/systemd.netdev.xml
+++ b/man/systemd.netdev.xml
@@ -499,11 +499,22 @@
<para>The MACVLAN mode to use. The supported options are
<literal>private</literal>,
<literal>vepa</literal>,
- <literal>bridge</literal>, and
- <literal>passthru</literal>.
+ <literal>bridge</literal>,
+ <literal>passthru</literal>, and
+ <literal>source</literal>.
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>SourceMACAddress=</varname></term>
+ <listitem>
+ <para>A whitespace-separated list of remote hardware addresses allowed on the MACVLAN. This
+ option only has an affect in source mode. Use full colon-, hyphen- or dot-delimited
+ hexadecimal. This option may appear more than once, in which case the lists are merged. If
+ the empty string is assigned to this option, the list of hardware addresses defined prior
+ to this is reset. Defaults to unset.</para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c
index a1e4ec9f27..060458a534 100644
--- a/src/libsystemd/sd-netlink/netlink-types.c
+++ b/src/libsystemd/sd-netlink/netlink-types.c
@@ -93,9 +93,20 @@ static const NLType rtnl_link_info_data_ipvlan_types[] = {
[IFLA_IPVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 },
};
+static const NLType rtnl_macvlan_macaddr_types[] = {
+ [IFLA_MACVLAN_MACADDR] = { .type = NETLINK_TYPE_ETHER_ADDR },
+};
+
+static const NLTypeSystem rtnl_macvlan_macaddr_type_system = {
+ .count = ELEMENTSOF(rtnl_macvlan_macaddr_types),
+ .types = rtnl_macvlan_macaddr_types,
+};
+
static const NLType rtnl_link_info_data_macvlan_types[] = {
[IFLA_MACVLAN_MODE] = { .type = NETLINK_TYPE_U32 },
[IFLA_MACVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_MACVLAN_MACADDR_MODE] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_MACVLAN_MACADDR_DATA] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_macvlan_macaddr_type_system },
};
static const NLType rtnl_link_info_data_bridge_types[] = {
diff --git a/src/network/netdev/macvlan.c b/src/network/netdev/macvlan.c
index e41ed9e6ed..41391788b0 100644
--- a/src/network/netdev/macvlan.c
+++ b/src/network/netdev/macvlan.c
@@ -23,6 +23,29 @@ static int netdev_macvlan_fill_message_create(NetDev *netdev, Link *link, sd_net
assert(m);
+ if (m->mode == NETDEV_MACVLAN_MODE_SOURCE && !set_isempty(m->match_source_mac)) {
+ Iterator i;
+ const struct ether_addr *mac_addr;
+
+ r = sd_netlink_message_append_u32(req, IFLA_MACVLAN_MACADDR_MODE, MACVLAN_MACADDR_SET);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_MACVLAN_MACADDR_MODE attribute: %m");
+
+ r = sd_netlink_message_open_container(req, IFLA_MACVLAN_MACADDR_DATA);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not open IFLA_MACVLAN_MACADDR_DATA container: %m");
+
+ SET_FOREACH(mac_addr, m->match_source_mac, i) {
+ r = sd_netlink_message_append_ether_addr(req, IFLA_MACVLAN_MACADDR, mac_addr);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_MACVLAN_MACADDR attribute: %m");
+ }
+
+ r = sd_netlink_message_close_container(req);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not close IFLA_MACVLAN_MACADDR_DATA container: %m");
+ }
+
if (m->mode != _NETDEV_MACVLAN_MODE_INVALID) {
r = sd_netlink_message_append_u32(req, IFLA_MACVLAN_MODE, m->mode);
if (r < 0)
@@ -32,6 +55,21 @@ static int netdev_macvlan_fill_message_create(NetDev *netdev, Link *link, sd_net
return 0;
}
+static void macvlan_done(NetDev *n) {
+ MacVlan *m;
+
+ assert(n);
+
+ if (n->kind == NETDEV_KIND_MACVLAN)
+ m = MACVLAN(n);
+ else
+ m = MACVTAP(n);
+
+ assert(m);
+
+ set_free_free(m->match_source_mac);
+}
+
static void macvlan_init(NetDev *n) {
MacVlan *m;
@@ -50,6 +88,7 @@ static void macvlan_init(NetDev *n) {
const NetDevVTable macvtap_vtable = {
.object_size = sizeof(MacVlan),
.init = macvlan_init,
+ .done = macvlan_done,
.sections = NETDEV_COMMON_SECTIONS "MACVTAP\0",
.fill_message_create = netdev_macvlan_fill_message_create,
.create_type = NETDEV_CREATE_STACKED,
@@ -59,6 +98,7 @@ const NetDevVTable macvtap_vtable = {
const NetDevVTable macvlan_vtable = {
.object_size = sizeof(MacVlan),
.init = macvlan_init,
+ .done = macvlan_done,
.sections = NETDEV_COMMON_SECTIONS "MACVLAN\0",
.fill_message_create = netdev_macvlan_fill_message_create,
.create_type = NETDEV_CREATE_STACKED,
diff --git a/src/network/netdev/macvlan.h b/src/network/netdev/macvlan.h
index 7e4d685bdb..7bc6eef12d 100644
--- a/src/network/netdev/macvlan.h
+++ b/src/network/netdev/macvlan.h
@@ -5,11 +5,13 @@ typedef struct MacVlan MacVlan;
#include "macvlan-util.h"
#include "netdev.h"
+#include "set.h"
struct MacVlan {
NetDev meta;
MacVlanMode mode;
+ Set *match_source_mac;
};
DEFINE_NETDEV_CAST(MACVLAN, MacVlan);
diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf
index b14835c313..0e2a9ce045 100644
--- a/src/network/netdev/netdev-gperf.gperf
+++ b/src/network/netdev/netdev-gperf.gperf
@@ -52,7 +52,9 @@ VLAN.MVRP, config_parse_tristate,
VLAN.LooseBinding, config_parse_tristate, 0, offsetof(VLan, loose_binding)
VLAN.ReorderHeader, config_parse_tristate, 0, offsetof(VLan, reorder_hdr)
MACVLAN.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode)
+MACVLAN.SourceMACAddress, config_parse_hwaddrs, 0, offsetof(MacVlan, match_source_mac)
MACVTAP.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode)
+MACVTAP.SourceMACAddress, config_parse_hwaddrs, 0, offsetof(MacVlan, match_source_mac)
IPVLAN.Mode, config_parse_ipvlan_mode, 0, offsetof(IPVlan, mode)
IPVLAN.Flags, config_parse_ipvlan_flags, 0, offsetof(IPVlan, flags)
IPVTAP.Mode, config_parse_ipvlan_mode, 0, offsetof(IPVlan, mode)
diff --git a/src/shared/macvlan-util.c b/src/shared/macvlan-util.c
index 90382acbd9..926b4d42a0 100644
--- a/src/shared/macvlan-util.c
+++ b/src/shared/macvlan-util.c
@@ -9,6 +9,7 @@ static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
[NETDEV_MACVLAN_MODE_VEPA] = "vepa",
[NETDEV_MACVLAN_MODE_BRIDGE] = "bridge",
[NETDEV_MACVLAN_MODE_PASSTHRU] = "passthru",
+ [NETDEV_MACVLAN_MODE_SOURCE] = "source",
};
DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
diff --git a/src/shared/macvlan-util.h b/src/shared/macvlan-util.h
index 24f864ac51..7670bbf402 100644
--- a/src/shared/macvlan-util.h
+++ b/src/shared/macvlan-util.h
@@ -8,6 +8,7 @@ typedef enum MacVlanMode {
NETDEV_MACVLAN_MODE_VEPA = MACVLAN_MODE_VEPA,
NETDEV_MACVLAN_MODE_BRIDGE = MACVLAN_MODE_BRIDGE,
NETDEV_MACVLAN_MODE_PASSTHRU = MACVLAN_MODE_PASSTHRU,
+ NETDEV_MACVLAN_MODE_SOURCE = MACVLAN_MODE_SOURCE,
_NETDEV_MACVLAN_MODE_MAX,
_NETDEV_MACVLAN_MODE_INVALID = -1
} MacVlanMode;
diff --git a/test/fuzz/fuzz-netdev-parser/directives.netdev b/test/fuzz/fuzz-netdev-parser/directives.netdev
index d69ac09f1f..ef1f18fa40 100644
--- a/test/fuzz/fuzz-netdev-parser/directives.netdev
+++ b/test/fuzz/fuzz-netdev-parser/directives.netdev
@@ -6,6 +6,7 @@ Id=
GVRP=
[MACVLAN]
Mode=
+SourceMACAddress=
[WireGuard]
ListenPort=
PrivateKey=
@@ -14,6 +15,7 @@ FwMark=
FirewallMark=
[MACVTAP]
Mode=
+SourceMACAddress=
[Match]
Architecture=
Host=