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.
This commit is contained in:
Alvin Šipraga 2020-07-08 15:52:23 +02:00
parent 24e2494407
commit 0d0de133f0
8 changed files with 72 additions and 2 deletions

View File

@ -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>

View File

@ -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[] = {

View File

@ -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,

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -6,6 +6,7 @@ Id=
GVRP=
[MACVLAN]
Mode=
SourceMACAddress=
[WireGuard]
ListenPort=
PrivateKey=
@ -14,6 +15,7 @@ FwMark=
FirewallMark=
[MACVTAP]
Mode=
SourceMACAddress=
[Match]
Architecture=
Host=