diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 37659326e36..c8ebd45c7f8 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -499,11 +499,22 @@ The MACVLAN mode to use. The supported options are private, vepa, - bridge, and - passthru. + bridge, + passthru, and + source. + + SourceMACAddress= + + A whitespace-separated list of remote hardware addresses allowed on the MACVLAN. This + option only has an effect 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. + + diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index a1e4ec9f27f..060458a534c 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 e41ed9e6ed7..41391788b08 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 7e4d685bdba..7bc6eef12df 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 b14835c313e..0e2a9ce045e 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 90382acbd97..926b4d42a02 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 24f864ac51c..7670bbf4020 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 d69ac09f1fb..ef1f18fa402 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=