]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: add support for MACVLAN source mode 16405/head
authorAlvin Šipraga <alsi@bang-olufsen.dk>
Wed, 8 Jul 2020 13:52:23 +0000 (15:52 +0200)
committerAlvin Šipraga <alsi@bang-olufsen.dk>
Wed, 8 Jul 2020 16:01:52 +0000 (18:01 +0200)
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.

man/systemd.netdev.xml
src/libsystemd/sd-netlink/netlink-types.c
src/network/netdev/macvlan.c
src/network/netdev/macvlan.h
src/network/netdev/netdev-gperf.gperf
src/shared/macvlan-util.c
src/shared/macvlan-util.h
test/fuzz/fuzz-netdev-parser/directives.netdev

index 37659326e36f9070997bc617b813c81c0fc6561d..80d1d20d30822742ee84cf1ab9c3949f365bc044 100644 (file)
           <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>
 
index a1e4ec9f27f7f92c079265e9b30ee9209e038050..060458a534c0a161a053c58256105e1886e3f88e 100644 (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[] = {
index e41ed9e6ed7a062d0303dc8878f9ad8477c82e39..41391788b083f53bc3a81a168017d739e9fa9b17 100644 (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,
index 7e4d685bdbafaec5534329d8b806bcbf9a77436b..7bc6eef12df2b3a4e14bdf0a15eb1bf5ab33b61e 100644 (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);
index b14835c313eb74f05a1a5a0b6a66f035a4c28084..0e2a9ce045e3dd7db947c31c8b54b0890d3ae452 100644 (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)
index 90382acbd97f4b9454835cb89fd388a1dd870bb9..926b4d42a02996ef93a207a6610904a04fa4adf2 100644 (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);
index 24f864ac51c72bf3dbf15f3705b5f8b8aa8bc339..7670bbf4020e775ea0ff325573a78621728a1026 100644 (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;
index d69ac09f1fb81900e01c5fef97452a318370a43e..ef1f18fa402430c384c4bd14891ebe19f6d5ceaf 100644 (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=