]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #16338 from keszybz/spelling2
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 2 Jul 2020 13:10:27 +0000 (15:10 +0200)
committerGitHub <noreply@github.com>
Thu, 2 Jul 2020 13:10:27 +0000 (15:10 +0200)
Tree-wide spelling fixes

27 files changed:
NEWS
man/systemd.network.xml
src/basic/socket-util.c
src/libsystemd-network/dhcp6-internal.h
src/libsystemd-network/dhcp6-network.c
src/libsystemd-network/icmp6-util.c
src/libsystemd-network/icmp6-util.h
src/libsystemd-network/sd-dhcp6-client.c
src/libsystemd-network/sd-radv.c
src/libsystemd-network/test-dhcp-client.c
src/libsystemd-network/test-dhcp6-client.c
src/libsystemd-network/test-ipv4ll.c
src/libsystemd-network/test-ndisc-ra.c
src/libsystemd-network/test-ndisc-rs.c
src/libsystemd/sd-netlink/netlink-types.c
src/network/meson.build
src/network/networkd-link.c
src/network/networkd-link.h
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/network/networkd-sriov.c [new file with mode: 0644]
src/network/networkd-sriov.h [new file with mode: 0644]
src/resolve/resolved-dns-stream.c
test/fuzz/fuzz-network-parser/directives.network
test/test-network/conf/25-sriov.network [new file with mode: 0644]
test/test-network/systemd-networkd-tests.py

diff --git a/NEWS b/NEWS
index 5d79200cf1109b3a04fc58e70ee0151fcea88d52..e1754231c72fc025b2b303aa7b2361a34c5f32d3 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -178,12 +178,12 @@ CHANGES WITH 246 in spe:
           traffic). DataBitRate=, DataSamplePoint=, FDMode=, FDNonISO= have
           been added to configure various CAN-FD aspects.
 
-        * systemd-networkd's [DHCPv6] section gained a new WithoutRA= boolean
-          setting. If enabled, DHCPv6 will be attempted right-away without
-          requiring an Router Advertisement packet suggesting it
-          first. Conversely, the [IPv6AcceptRA] gained a boolean option
-          DHCPv6Client= that may be used to turn off the DHCPv6 client even if
-          the RA packets suggest it.
+        * systemd-networkd's [DHCPv6] section gained a new WithoutRA= setting.
+          If enabled, DHCPv6 will be attempted right-away without requiring an
+          Router Advertisement packet suggesting it first. Conversely, the
+          [IPv6AcceptRA] section gained a boolean option DHCPv6Client= that may
+          be used to turn off the DHCPv6 client even if the RA packets suggest
+          it.
 
         * systemd-networkd's [DHCPv4] section gained a new setting UseGateway=
           which may be used to turn off use of the gateway information provided
index a4fe1b4ddea136bb8b1e77ad063e2187ed3e4493..c48955da338e2ef44f0219f836e89cabb351c6f6 100644 (file)
     </variablelist>
   </refsect1>
 
+  <refsect1>
+      <title>[SR-IOV] Section Options</title>
+      <para>The <literal>[SR-IOV]</literal> section accepts the
+      following keys. Specify several <literal>[SR-IOV]</literal>
+      sections to configure several SR-IOVs. SR-IOV provides the ability to partition a single physical PCI resource
+      into virtual PCI functions which can then be injected into a VM. In the case of network VFs, SR-IOV improves
+      north-south network performance (that is, traffic with endpoints outside the host machine) by allowing traffic to
+      bypass the host machine’s network stack.</para>
+
+      <variablelist class='network-directives'>
+        <varlistentry>
+          <term><varname>VirtualFunction=</varname></term>
+          <listitem>
+            <para>Specifies a Virtual Function (VF), lightweight PCIe function designed solely to move data
+            in and out. Takes an unsigned integer in the range 0..2147483646. This option is compulsory.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>VLANId=</varname></term>
+          <listitem>
+            <para>Specifies VLAN ID of the virtual function. Takes an unsigned integer in the range 1..4095.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>QualityOfService=</varname></term>
+          <listitem>
+            <para>Specifies quality of service of the virtual function. Takes an unsigned integer in the range 1..4294967294.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>VLANProtocol=</varname></term>
+          <listitem>
+            <para>Specifies VLAN protocol of the virtual function. Takes <literal>802.1Q</literal> or
+            <literal>802.1ad</literal>.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>MACSpoofCheck=</varname></term>
+          <listitem>
+            <para>Takes a boolean. Controls the MAC spoof checking. When unset, the kernel's default will be used.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>QueryReceiveSideScaling=</varname></term>
+          <listitem>
+            <para>Takes a boolean. Toggle the ability of querying the receive side scaling (RSS)
+            configuration of the virtual function (VF). The VF RSS information like RSS hash key may be
+            considered sensitive on some devices where this information is shared between VF and the
+            physical function (PF). When unset, the kernel's default will be used.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>Trust=</varname></term>
+          <listitem>
+            <para>Takes a boolean. Allows to set trust mode of the virtual function (VF). When set, VF
+            users can set a specific feature which may impact security and/or performance. When unset,
+            the kernel's default will be used.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>LinkState=</varname></term>
+          <listitem>
+            <para>Allows to set the link state of the virtual function (VF). Takes a boolean or a
+            special value <literal>auto</literal>. Setting to <literal>auto</literal> means a
+            reflection of the physical function (PF) link state, <literal>yes</literal> lets the VF to
+            communicate with other VFs on this host even if the PF link state is down,
+            <literal>no</literal> causes the hardware to drop any packets sent by the VF. When unset,
+            the kernel's default will be used.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>MACAddress=</varname></term>
+          <listitem>
+            <para>Specifies the MAC address for the virtual function.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+  </refsect1>
+
   <refsect1>
     <title>[Network] Section Options</title>
 
index 07f534f34d1f174972087c79f5df48887683eeb2..5218374b2b393355e79cb896ccd309ddc7e8b954 100644 (file)
@@ -1130,6 +1130,7 @@ int socket_bind_to_ifname(int fd, const char *ifname) {
 
 int socket_bind_to_ifindex(int fd, int ifindex) {
         char ifname[IF_NAMESIZE + 1];
+        int r;
 
         assert(fd >= 0);
 
@@ -1141,10 +1142,9 @@ int socket_bind_to_ifindex(int fd, int ifindex) {
                 return 0;
         }
 
-        if (setsockopt(fd, SOL_SOCKET, SO_BINDTOIFINDEX, &ifindex, sizeof(ifindex)) >= 0)
-                return 0;
-        if (errno != ENOPROTOOPT)
-                return -errno;
+        r = setsockopt_int(fd, SOL_SOCKET, SO_BINDTOIFINDEX, ifindex);
+        if (r != -ENOPROTOOPT)
+                return r;
 
         /* Fall back to SO_BINDTODEVICE on kernels < 5.0 which didn't have SO_BINDTOIFINDEX */
         if (!format_ifname(ifindex, ifname))
index b0d1216eed847fbd80424f2fc66dc99c96376d43..baf7bb2ef4ad79714fd01f624fdf486b1dc40f1b 100644 (file)
@@ -112,7 +112,7 @@ int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen,
 int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen,
                                   char ***str_arr);
 
-int dhcp6_network_bind_udp_socket(int index, struct in6_addr *address);
+int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *address);
 int dhcp6_network_send_udp_socket(int s, struct in6_addr *address,
                                   const void *packet, size_t len);
 
index f82afe6a0915258fb7fec47dc720694ee541c43d..e2efa8bbe347b12da0400688f1ec64ed284e3244 100644 (file)
 #include "fd-util.h"
 #include "socket-util.h"
 
-int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
+int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *local_address) {
         union sockaddr_union src = {
                 .in6.sin6_family = AF_INET6,
                 .in6.sin6_port = htobe16(DHCP6_PORT_CLIENT),
-                .in6.sin6_scope_id = index,
+                .in6.sin6_scope_id = ifindex,
         };
         _cleanup_close_ int s = -1;
         int r;
 
-        assert(index > 0);
+        assert(ifindex > 0);
         assert(local_address);
 
         src.in6.sin6_addr = *local_address;
index bdd94867ac33b88c79e0622eaefa151605e26021..d9690293f13e16786ea0331d9e0309d15799a154 100644 (file)
@@ -81,11 +81,11 @@ static int icmp6_bind_router_message(const struct icmp6_filter *filter,
         return TAKE_FD(s);
 }
 
-int icmp6_bind_router_solicitation(int index) {
+int icmp6_bind_router_solicitation(int ifindex) {
         struct icmp6_filter filter = {};
         struct ipv6_mreq mreq = {
                 .ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
-                .ipv6mr_interface = index,
+                .ipv6mr_interface = ifindex,
         };
 
         ICMP6_FILTER_SETBLOCKALL(&filter);
@@ -94,11 +94,11 @@ int icmp6_bind_router_solicitation(int index) {
         return icmp6_bind_router_message(&filter, &mreq);
 }
 
-int icmp6_bind_router_advertisement(int index) {
+int icmp6_bind_router_advertisement(int ifindex) {
         struct icmp6_filter filter = {};
         struct ipv6_mreq mreq = {
                 .ipv6mr_multiaddr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT,
-                .ipv6mr_interface = index,
+                .ipv6mr_interface = ifindex,
         };
 
         ICMP6_FILTER_SETBLOCKALL(&filter);
index 725a68086bc462bf8878f7447eacf3b08bb874c8..ac68ded1fe9653d6b8485a4b990c612a3d86bb95 100644 (file)
@@ -17,8 +17,8 @@
         { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }
 
-int icmp6_bind_router_solicitation(int index);
-int icmp6_bind_router_advertisement(int index);
+int icmp6_bind_router_solicitation(int ifindex);
+int icmp6_bind_router_advertisement(int ifindex);
 int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr);
 int icmp6_receive(int fd, void *buffer, size_t size, struct in6_addr *dst,
                   triple_timestamp *timestamp);
index e1572703e2becc713bcb9a715c775508cd334116..7a8823cce93e45fa0161fa8a5e2eac3e82960841 100644 (file)
@@ -159,7 +159,7 @@ int sd_dhcp6_client_set_callback(
 int sd_dhcp6_client_set_ifindex(sd_dhcp6_client *client, int ifindex) {
 
         assert_return(client, -EINVAL);
-        assert_return(ifindex >= -1, -EINVAL);
+        assert_return(ifindex > 0, -EINVAL);
         assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
 
         client->ifindex = ifindex;
index 7ea6f0d5612d7c3070f5e804e485a296e5506d2b..cc5c0223b5cee459785ec68f94e1176e3747a3b0 100644 (file)
@@ -415,7 +415,7 @@ _public_ int sd_radv_start(sd_radv *ra) {
 
 _public_ int sd_radv_set_ifindex(sd_radv *ra, int ifindex) {
         assert_return(ra, -EINVAL);
-        assert_return(ifindex >= -1, -EINVAL);
+        assert_return(ifindex > 0, -EINVAL);
 
         if (ra->state != SD_RADV_STATE_IDLE)
                 return -EBUSY;
index 80a85661942ea9ea1c55c94de29abef6dd43505c..8f2f4462be3513f9a0ad34c7f3c9cf2010c293b6 100644 (file)
@@ -258,7 +258,7 @@ int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, const
 }
 
 int dhcp_network_bind_raw_socket(
-                int index,
+                int ifindex,
                 union sockaddr_union *link,
                 uint32_t id,
                 const uint8_t *addr, size_t addr_len,
index 56c8c978e5817f2ca207de2906ea138a66237b82..7af7d670b5917ca2879d52c17855839f733391ae 100644 (file)
@@ -30,7 +30,7 @@ static struct ether_addr mac_addr = {
 
 static sd_event_source *hangcheck;
 static int test_dhcp_fd[2];
-static int test_index = 42;
+static int test_ifindex = 42;
 static int test_client_message_num;
 static be32_t test_iaid = 0;
 static uint8_t test_duid[14] = { };
@@ -48,7 +48,7 @@ static int test_client_basic(sd_event *e) {
 
         assert_se(sd_dhcp6_client_set_ifindex(client, 15) == 0);
         assert_se(sd_dhcp6_client_set_ifindex(client, -42) == -EINVAL);
-        assert_se(sd_dhcp6_client_set_ifindex(client, -1) == 0);
+        assert_se(sd_dhcp6_client_set_ifindex(client, -1) == -EINVAL);
         assert_se(sd_dhcp6_client_set_ifindex(client, 42) >= 0);
 
         assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr,
@@ -877,8 +877,8 @@ int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address,
         return len;
 }
 
-int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
-        assert_se(index == test_index);
+int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *local_address) {
+        assert_se(ifindex == test_ifindex);
 
         if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_dhcp_fd) < 0)
                 return -errno;
@@ -899,7 +899,7 @@ static int test_client_solicit(sd_event *e) {
 
         assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
 
-        assert_se(sd_dhcp6_client_set_ifindex(client, test_index) == 0);
+        assert_se(sd_dhcp6_client_set_ifindex(client, test_ifindex) == 0);
         assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr,
                                           sizeof (mac_addr),
                                           ARPHRD_ETHER) >= 0);
index 6051e65820455a759ca9e41fb5f1484028238dc9..310b658e188a0eb203041ac7f8c6d97e017feed5 100644 (file)
@@ -78,7 +78,7 @@ int arp_send_announcement(int fd, int ifindex,
         return arp_network_send_raw_socket(fd, ifindex, &ea);
 }
 
-int arp_network_bind_raw_socket(int index, be32_t address, const struct ether_addr *eth_mac) {
+int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_addr *eth_mac) {
         if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
                 return -errno;
 
index 7c6c4663f3b7836d519b0ab24dc859b67b428836..d759ec03a8ad9efbda2a28cfb66855bfc4a7372a 100644 (file)
@@ -159,8 +159,8 @@ static void test_radv(void) {
         assert_se(ra);
 
         assert_se(sd_radv_set_ifindex(NULL, 0) < 0);
-        assert_se(sd_radv_set_ifindex(ra, 0) >= 0);
-        assert_se(sd_radv_set_ifindex(ra, -1) >= 0);
+        assert_se(sd_radv_set_ifindex(ra, 0) < 0);
+        assert_se(sd_radv_set_ifindex(ra, -1) < 0);
         assert_se(sd_radv_set_ifindex(ra, -2) < 0);
         assert_se(sd_radv_set_ifindex(ra, 42) >= 0);
 
@@ -219,12 +219,12 @@ static void test_radv(void) {
         assert_se(!ra);
 }
 
-int icmp6_bind_router_solicitation(int index) {
+int icmp6_bind_router_solicitation(int ifindex) {
         return -ENOSYS;
 }
 
-int icmp6_bind_router_advertisement(int index) {
-        assert_se(index == 42);
+int icmp6_bind_router_advertisement(int ifindex) {
+        assert_se(ifindex == 42);
 
         return test_fd[1];
 }
index 9fc902645c8a9aedb77208de61e874f7beb36940..5d1e66fcdc96900772d66866f71edc8461c9d64e 100644 (file)
@@ -174,8 +174,8 @@ static int test_rs_hangcheck(sd_event_source *s, uint64_t usec,
         return 0;
 }
 
-int icmp6_bind_router_solicitation(int index) {
-        assert_se(index == 42);
+int icmp6_bind_router_solicitation(int ifindex) {
+        assert_se(ifindex == 42);
 
         if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
                 return -errno;
@@ -183,8 +183,7 @@ int icmp6_bind_router_solicitation(int index) {
         return test_fd[0];
 }
 
-int icmp6_bind_router_advertisement(int index) {
-
+int icmp6_bind_router_advertisement(int ifindex) {
         return -ENOSYS;
 }
 
index 488bfb5f4fed49eaefdcf6032bff90c2c93fc531..a1e4ec9f27f7f92c079265e9b30ee9209e038050 100644 (file)
@@ -537,6 +537,43 @@ static const NLTypeSystem rtnl_prop_list_type_system = {
         .types = rtnl_prop_list_types,
 };
 
+static const NLType rtnl_vf_vlan_list_types[] = {
+        [IFLA_VF_VLAN_INFO]  = { .size = sizeof(struct ifla_vf_vlan_info) },
+};
+
+static const NLTypeSystem rtnl_vf_vlan_type_system = {
+        .count = ELEMENTSOF(rtnl_vf_vlan_list_types),
+        .types = rtnl_vf_vlan_list_types,
+};
+
+static const NLType rtnl_vf_vlan_info_types[] = {
+        [IFLA_VF_MAC]           = { .size = sizeof(struct ifla_vf_mac) },
+        [IFLA_VF_VLAN]          = { .size = sizeof(struct ifla_vf_vlan) },
+        [IFLA_VF_VLAN_LIST]     = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_vf_vlan_type_system},
+        [IFLA_VF_TX_RATE]       = { .size = sizeof(struct ifla_vf_tx_rate) },
+        [IFLA_VF_SPOOFCHK]      = { .size = sizeof(struct ifla_vf_spoofchk) },
+        [IFLA_VF_RATE]          = { .size = sizeof(struct ifla_vf_rate) },
+        [IFLA_VF_LINK_STATE]    = { .size = sizeof(struct ifla_vf_link_state) },
+        [IFLA_VF_RSS_QUERY_EN]  = { .size = sizeof(struct ifla_vf_rss_query_en) },
+        [IFLA_VF_TRUST]         = { .size = sizeof(struct ifla_vf_trust) },
+        [IFLA_VF_IB_NODE_GUID]  = { .size = sizeof(struct ifla_vf_guid) },
+        [IFLA_VF_IB_PORT_GUID]  = { .size = sizeof(struct ifla_vf_guid) },
+};
+
+static const NLTypeSystem rtnl_vf_vlan_info_type_system = {
+        .count = ELEMENTSOF(rtnl_vf_vlan_info_types),
+        .types = rtnl_vf_vlan_info_types,
+};
+
+static const NLType rtnl_link_io_srv_types[] = {
+        [IFLA_VF_INFO] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_vf_vlan_info_type_system },
+};
+
+static const NLTypeSystem rtnl_io_srv_type_system = {
+        .count = ELEMENTSOF(rtnl_link_io_srv_types),
+        .types = rtnl_link_io_srv_types,
+};
+
 static const NLType rtnl_link_types[] = {
         [IFLA_ADDRESS]          = { .type = NETLINK_TYPE_ETHER_ADDR },
         [IFLA_BROADCAST]        = { .type = NETLINK_TYPE_ETHER_ADDR },
@@ -564,10 +601,8 @@ static const NLType rtnl_link_types[] = {
         [IFLA_LINKINFO]         = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_info_type_system },
         [IFLA_NET_NS_PID]       = { .type = NETLINK_TYPE_U32 },
         [IFLA_IFALIAS]          = { .type = NETLINK_TYPE_STRING, .size = IFALIASZ - 1 },
-/*
-        [IFLA_NUM_VF],
-        [IFLA_VFINFO_LIST]      = {. type = NETLINK_TYPE_NESTED, },
-*/
+        [IFLA_NUM_VF]           = { .type = NETLINK_TYPE_U32 },
+        [IFLA_VFINFO_LIST]      = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_io_srv_type_system },
         [IFLA_STATS64]          = { .size = sizeof(struct rtnl_link_stats64) },
 /*
         [IFLA_VF_PORTS]         = { .type = NETLINK_TYPE_NESTED },
index 97a164091a7f1bd126bfa92fe62490a3c4a3ec2b..b3a88d991035677fbfc9d364b566f10e2edf908d 100644 (file)
@@ -105,6 +105,8 @@ sources = files('''
         networkd-routing-policy-rule.h
         networkd-speed-meter.c
         networkd-speed-meter.h
+        networkd-sriov.c
+        networkd-sriov.h
         networkd-util.c
         networkd-util.h
         networkd-wifi.c
index bc26cd2c3ed622a04c664842809c276c3bc26799..4df56087198368c7c8142acb28dc1f6ad3b6196d 100644 (file)
@@ -3,6 +3,7 @@
 #include <netinet/in.h>
 #include <linux/if.h>
 #include <linux/if_arp.h>
+#include <linux/if_link.h>
 #include <unistd.h>
 
 #include "alloc-util.h"
@@ -31,6 +32,7 @@
 #include "networkd-manager.h"
 #include "networkd-ndisc.h"
 #include "networkd-neighbor.h"
+#include "networkd-sriov.h"
 #include "networkd-radv.h"
 #include "networkd-routing-policy-rule.h"
 #include "networkd-wifi.h"
@@ -1127,6 +1129,9 @@ void link_check_ready(Link *link) {
         if (!link->tc_configured)
                 return;
 
+        if (!link->sr_iov_configured)
+                return;
+
         if (link_has_carrier(link) || !link->network->configure_without_carrier) {
 
                 if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4) && !link->ipv4ll_address)
@@ -2838,6 +2843,28 @@ static int link_configure_traffic_control(Link *link) {
         return 0;
 }
 
+static int link_configure_sr_iov(Link *link) {
+        SRIOV *sr_iov;
+        Iterator i;
+        int r;
+
+        link->sr_iov_configured = false;
+        link->sr_iov_messages = 0;
+
+        ORDERED_HASHMAP_FOREACH(sr_iov, link->network->sr_iov_by_section, i) {
+                r = sr_iov_configure(link, sr_iov);
+                if (r < 0)
+                        return r;
+        }
+
+        if (link->sr_iov_messages == 0)
+                link->sr_iov_configured = true;
+        else
+                log_link_debug(link, "Configuring SR-IOV");
+
+        return 0;
+}
+
 static int link_configure(Link *link) {
         int r;
 
@@ -2849,6 +2876,10 @@ static int link_configure(Link *link) {
         if (r < 0)
                 return r;
 
+        r = link_configure_sr_iov(link);
+        if (r < 0)
+                return r;
+
         if (link->iftype == ARPHRD_CAN)
                 return link_configure_can(link);
 
index 5a81805a04d11235738e212a05465e088c779aa2..f53b9da2e3603089c62039df34345ed5b6076f16 100644 (file)
@@ -82,6 +82,7 @@ typedef struct Link {
         unsigned routing_policy_rule_messages;
         unsigned routing_policy_rule_remove_messages;
         unsigned tc_messages;
+        unsigned sr_iov_messages;
         unsigned enslaving;
 
         Set *addresses;
@@ -118,6 +119,7 @@ typedef struct Link {
         bool static_nexthops_configured:1;
         bool routing_policy_rules_configured:1;
         bool tc_configured:1;
+        bool sr_iov_configured:1;
         bool setting_mtu:1;
         bool setting_genmode:1;
         bool ipv6_mtu_set:1;
index d6f23fe5f0c676bcd91c2e92089a8213677a872c..43935e07b69d5658b153d2153de92a73c2a0394a 100644 (file)
@@ -15,6 +15,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
 #include "networkd-ipv4ll.h"
 #include "networkd-ndisc.h"
 #include "networkd-network.h"
+#include "networkd-sriov.h"
 #include "qdisc.h"
 #include "tclass.h"
 #include "vlan-util.h"
@@ -53,6 +54,15 @@ Link.Multicast,                              config_parse_tristate,
 Link.AllMulticast,                           config_parse_tristate,                                    0,                             offsetof(Network, allmulticast)
 Link.Unmanaged,                              config_parse_bool,                                        0,                             offsetof(Network, unmanaged)
 Link.RequiredForOnline,                      config_parse_required_for_online,                         0,                             0
+SR-IOV.VirtualFunction,                      config_parse_sr_iov_uint32,                               0,                             0
+SR-IOV.VLANId,                               config_parse_sr_iov_uint32,                               0,                             0
+SR-IOV.QualityOfService,                     config_parse_sr_iov_uint32,                               0,                             0
+SR-IOV.VLANProtocol,                         config_parse_sr_iov_vlan_proto,                           0,                             0
+SR-IOV.MACSpoofCheck,                        config_parse_sr_iov_boolean,                              0,                             0
+SR-IOV.QueryReceiveSideScaling,              config_parse_sr_iov_boolean,                              0,                             0
+SR-IOV.Trust,                                config_parse_sr_iov_boolean,                              0,                             0
+SR-IOV.LinkState,                            config_parse_sr_iov_link_state,                           0,                             0
+SR-IOV.MACAddress,                           config_parse_sr_iov_mac,                                  0,                             0
 Network.Description,                         config_parse_string,                                      0,                             offsetof(Network, description)
 Network.Bridge,                              config_parse_ifname,                                      0,                             offsetof(Network, bridge_name)
 Network.Bond,                                config_parse_ifname,                                      0,                             offsetof(Network, bond_name)
index e3012b476993aa2eb67cf1564dd8ac1e566ae778..5316faeedb27e5d44d17f52428a6d91c637ef753 100644 (file)
@@ -16,6 +16,7 @@
 #include "network-internal.h"
 #include "networkd-manager.h"
 #include "networkd-network.h"
+#include "networkd-sriov.h"
 #include "parse-util.h"
 #include "path-lookup.h"
 #include "set.h"
@@ -158,6 +159,7 @@ int network_verify(Network *network) {
         Route *route, *route_next;
         FdbEntry *fdb, *fdb_next;
         TrafficControl *tc;
+        SRIOV *sr_iov;
         Iterator i;
 
         assert(network);
@@ -330,6 +332,10 @@ int network_verify(Network *network) {
                 if (traffic_control_section_verify(tc, &has_root, &has_clsact) < 0)
                         traffic_control_free(tc);
 
+        ORDERED_HASHMAP_FOREACH(sr_iov, network->sr_iov_by_section, i)
+                if (sr_iov_section_verify(sr_iov) < 0)
+                        sr_iov_free(sr_iov);
+
         return 0;
 }
 
@@ -484,6 +490,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
                         filename, NETWORK_DIRS, dropin_dirname,
                         "Match\0"
                         "Link\0"
+                        "SR-IOV\0"
                         "Network\0"
                         "Address\0"
                         "Neighbor\0"
@@ -731,6 +738,7 @@ static Network *network_free(Network *network) {
         hashmap_free(network->prefixes_by_section);
         hashmap_free(network->route_prefixes_by_section);
         hashmap_free(network->rules_by_section);
+        ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free);
         ordered_hashmap_free_with_destructor(network->tc_by_section, traffic_control_free);
 
         if (network->manager &&
index 47fceee0b87901417a737c47d50b35e663be1afe..2ce555bfc557f7686b5027fa9090b4f9a1f6b352 100644 (file)
@@ -312,6 +312,7 @@ struct Network {
         Hashmap *route_prefixes_by_section;
         Hashmap *rules_by_section;
         OrderedHashmap *tc_by_section;
+        OrderedHashmap *sr_iov_by_section;
 
         /* All kinds of DNS configuration */
         struct in_addr_data *dns;
diff --git a/src/network/networkd-sriov.c b/src/network/networkd-sriov.c
new file mode 100644 (file)
index 0000000..5ae751e
--- /dev/null
@@ -0,0 +1,501 @@
+/* SPDX-License-Identifier: LGPL-2.1+
+ * Copyright © 2020 VMware, Inc. */
+
+#include "alloc-util.h"
+#include "netlink-util.h"
+#include "networkd-manager.h"
+#include "networkd-sriov.h"
+#include "parse-util.h"
+#include "set.h"
+#include "string-util.h"
+
+static int sr_iov_new(SRIOV **ret) {
+        SRIOV *sr_iov;
+
+        sr_iov = new(SRIOV, 1);
+        if (!sr_iov)
+                return -ENOMEM;
+
+        *sr_iov = (SRIOV) {
+                  .vf = (uint32_t) -1,
+                  .vlan_proto = ETH_P_8021Q,
+                  .vf_spoof_check_setting = -1,
+                  .trust = -1,
+                  .query_rss = -1,
+                  .link_state = _SR_IOV_LINK_STATE_INVALID,
+        };
+
+        *ret = TAKE_PTR(sr_iov);
+
+        return 0;
+}
+
+static int sr_iov_new_static(Network *network, const char *filename, unsigned section_line, SRIOV **ret) {
+        _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+        _cleanup_(sr_iov_freep) SRIOV *sr_iov = NULL;
+        SRIOV *existing = NULL;
+        int r;
+
+        assert(network);
+        assert(ret);
+        assert(filename);
+        assert(section_line > 0);
+
+        r = network_config_section_new(filename, section_line, &n);
+        if (r < 0)
+                return r;
+
+        existing = ordered_hashmap_get(network->sr_iov_by_section, n);
+        if (existing) {
+                *ret = existing;
+                return 0;
+        }
+
+        r = sr_iov_new(&sr_iov);
+        if (r < 0)
+                return r;
+
+        sr_iov->network = network;
+        sr_iov->section = TAKE_PTR(n);
+
+        r = ordered_hashmap_ensure_allocated(&network->sr_iov_by_section, &network_config_hash_ops);
+        if (r < 0)
+                return r;
+
+        r = ordered_hashmap_put(network->sr_iov_by_section, sr_iov->section, sr_iov);
+        if (r < 0)
+                return r;
+
+        *ret = TAKE_PTR(sr_iov);
+        return 0;
+}
+
+SRIOV *sr_iov_free(SRIOV *sr_iov) {
+        if (!sr_iov)
+                return NULL;
+
+        if (sr_iov->network && sr_iov->section)
+                ordered_hashmap_remove(sr_iov->network->sr_iov_by_section, sr_iov->section);
+
+        network_config_section_free(sr_iov->section);
+
+        return mfree(sr_iov);
+}
+
+static int sr_iov_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+        int r;
+
+        assert(link);
+        assert(link->sr_iov_messages > 0);
+        link->sr_iov_messages--;
+
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+                return 1;
+
+        r = sd_netlink_message_get_errno(m);
+        if (r < 0 && r != -EEXIST) {
+                log_link_message_error_errno(link, m, r, "Could not set up SR-IOV");
+                link_enter_failed(link);
+                return 1;
+        }
+
+        if (link->sr_iov_messages == 0) {
+                log_link_debug(link, "SR-IOV configured");
+                link->sr_iov_configured = true;
+                link_check_ready(link);
+        }
+
+        return 1;
+}
+
+int sr_iov_configure(Link *link, SRIOV *sr_iov) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
+        int r;
+
+        assert(link);
+        assert(link->manager);
+        assert(link->manager->rtnl);
+        assert(link->ifindex > 0);
+
+        log_link_debug(link, "Setting SR-IOV virtual function %"PRIu32, sr_iov->vf);
+
+        r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
+
+        r = sd_netlink_message_open_container(req, IFLA_VFINFO_LIST);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not open IFLA_VFINFO_LIST container: %m");
+
+        r = sd_netlink_message_open_container(req, IFLA_VF_INFO);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not open IFLA_VF_INFO container: %m");
+
+        if (!ether_addr_is_null(&sr_iov->mac)) {
+                struct ifla_vf_mac ivm = {
+                        .vf = sr_iov->vf,
+                };
+
+                memcpy(ivm.mac, &sr_iov->mac, ETH_ALEN);
+                r = sd_netlink_message_append_data(req, IFLA_VF_MAC, &ivm, sizeof(struct ifla_vf_mac));
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append IFLA_VF_MAC: %m");
+        }
+
+        if (sr_iov->vf_spoof_check_setting >= 0) {
+                struct ifla_vf_spoofchk ivs = {
+                        .vf = sr_iov->vf,
+                        .setting = sr_iov->vf_spoof_check_setting,
+                };
+
+                r = sd_netlink_message_append_data(req, IFLA_VF_SPOOFCHK, &ivs, sizeof(struct ifla_vf_spoofchk));
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append IFLA_VF_SPOOFCHK: %m");
+        }
+
+        if (sr_iov->query_rss >= 0) {
+                struct ifla_vf_rss_query_en ivs = {
+                        .vf = sr_iov->vf,
+                        .setting = sr_iov->query_rss,
+                };
+
+                r = sd_netlink_message_append_data(req, IFLA_VF_RSS_QUERY_EN, &ivs, sizeof(struct ifla_vf_rss_query_en));
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append IFLA_VF_RSS_QUERY_EN: %m");
+        }
+
+        if (sr_iov->trust >= 0) {
+                struct ifla_vf_trust ivt = {
+                        .vf = sr_iov->vf,
+                        .setting = sr_iov->trust,
+                };
+
+                r = sd_netlink_message_append_data(req, IFLA_VF_TRUST, &ivt, sizeof(struct ifla_vf_trust));
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append IFLA_VF_TRUST: %m");
+        }
+
+        if (sr_iov->link_state >= 0) {
+                struct ifla_vf_link_state ivl = {
+                        .vf = sr_iov->vf,
+                        .link_state = sr_iov->link_state,
+                };
+
+                r = sd_netlink_message_append_data(req, IFLA_VF_LINK_STATE, &ivl, sizeof(struct ifla_vf_link_state));
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append IFLA_VF_LINK_STATE: %m");
+        }
+
+        if (sr_iov->vlan > 0) {
+                /* Because of padding, first the buffer must be initialized with 0. */
+                struct ifla_vf_vlan_info ivvi = {};
+                ivvi.vf = sr_iov->vf;
+                ivvi.vlan = sr_iov->vlan;
+                ivvi.qos = sr_iov->qos;
+                ivvi.vlan_proto = htobe16(sr_iov->vlan_proto);
+
+                r = sd_netlink_message_open_container(req, IFLA_VF_VLAN_LIST);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not open IFLA_VF_VLAN_LIST container: %m");
+
+                r = sd_netlink_message_append_data(req, IFLA_VF_VLAN_INFO, &ivvi, sizeof(struct ifla_vf_vlan_info));
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append IFLA_VF_VLAN_INFO: %m");
+
+                r = sd_netlink_message_close_container(req);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not close IFLA_VF_VLAN_LIST container: %m");
+        }
+
+        r = sd_netlink_message_close_container(req);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not close IFLA_VF_INFO container: %m");
+
+        r = sd_netlink_message_close_container(req);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not close IFLA_VFINFO_LIST container: %m");
+
+        r = netlink_call_async(link->manager->rtnl, NULL, req, sr_iov_handler,
+                               link_netlink_destroy_callback, link);
+        if (r < 0)
+                return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
+
+        link_ref(link);
+        link->sr_iov_messages++;
+
+        return 0;
+}
+
+int sr_iov_section_verify(SRIOV *sr_iov) {
+        assert(sr_iov);
+
+        if (section_is_invalid(sr_iov->section))
+                return -EINVAL;
+
+        if (sr_iov->vf == (uint32_t) -1)
+                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+                                         "%s: [SRIOV] section without VirtualFunction= field configured. "
+                                         "Ignoring [SRIOV] section from line %u.",
+                                         sr_iov->section->filename, sr_iov->section->line);
+
+        return 0;
+}
+
+int config_parse_sr_iov_uint32(
+                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) {
+
+        _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL;
+        Network *network = data;
+        uint32_t k;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = sr_iov_new_static(network, filename, section_line, &sr_iov);
+        if (r < 0)
+                return r;
+
+        if (isempty(rvalue)) {
+                if (streq(lvalue, "VirtualFunction"))
+                        sr_iov->vf = (uint32_t) -1;
+                else if (streq(lvalue, "VLANId"))
+                        sr_iov->vlan = 0;
+                else if (streq(lvalue, "QualityOfService"))
+                        sr_iov->qos = 0;
+                else
+                        assert_not_reached("Invalid lvalue");
+
+                TAKE_PTR(sr_iov);
+                return 0;
+        }
+
+        r = safe_atou32(rvalue, &k);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Failed to parse SR-IOV '%s=', ignoring assignment: %s", lvalue, rvalue);
+                return 0;
+        }
+
+        if (streq(lvalue, "VLANId")) {
+                if (k == 0 || k > 4095) {
+                        log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid SR-IOV VLANId: %d", k);
+                        return 0;
+                }
+                sr_iov->vlan = k;
+        } else if (streq(lvalue, "VirtualFunction")) {
+                if (k >= INT_MAX) {
+                        log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid SR-IOV virtual function: %d", k);
+                        return 0;
+                }
+                sr_iov->vf = k;
+        } else if (streq(lvalue, "QualityOfService"))
+                sr_iov->qos = k;
+        else
+                assert_not_reached("Invalid lvalue");
+
+        TAKE_PTR(sr_iov);
+        return 0;
+}
+
+int config_parse_sr_iov_vlan_proto(
+                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) {
+
+        _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL;
+        Network *network = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = sr_iov_new_static(network, filename, section_line, &sr_iov);
+        if (r < 0)
+                return r;
+
+        if (isempty(rvalue) || streq(rvalue, "802.1Q"))
+                sr_iov->vlan_proto = ETH_P_8021Q;
+        else if (streq(rvalue, "802.1ad"))
+                sr_iov->vlan_proto = ETH_P_8021AD;
+        else {
+                log_syntax(unit, LOG_ERR, filename, line, 0,
+                           "Invalid SR-IOV '%s=', ignoring assignment: %s", lvalue, rvalue);
+                return 0;
+        }
+
+        TAKE_PTR(sr_iov);
+        return 0;
+}
+
+int config_parse_sr_iov_link_state(
+                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) {
+
+        _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL;
+        Network *network = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = sr_iov_new_static(network, filename, section_line, &sr_iov);
+        if (r < 0)
+                return r;
+
+        /* Unfortunately, SR_IOV_LINK_STATE_DISABLE is 2, not 0. So, we cannot use
+         * DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN() macro. */
+
+        if (isempty(rvalue)) {
+                sr_iov->link_state = _SR_IOV_LINK_STATE_INVALID;
+                TAKE_PTR(sr_iov);
+                return 0;
+        }
+
+        if (streq(rvalue, "auto")) {
+                sr_iov->link_state = SR_IOV_LINK_STATE_AUTO;
+                TAKE_PTR(sr_iov);
+                return 0;
+        }
+
+        r = parse_boolean(rvalue);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Failed to parse SR-IOV '%s=', ignoring assignment: %s", lvalue, rvalue);
+                return 0;
+        }
+
+        sr_iov->link_state = r ? SR_IOV_LINK_STATE_ENABLE : SR_IOV_LINK_STATE_DISABLE;
+        TAKE_PTR(sr_iov);
+        return 0;
+}
+
+int config_parse_sr_iov_boolean(
+                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) {
+
+        _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL;
+        Network *network = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = sr_iov_new_static(network, filename, section_line, &sr_iov);
+        if (r < 0)
+                return r;
+
+        if (isempty(rvalue)) {
+                if (streq(lvalue, "MACSpoofCheck"))
+                        sr_iov->vf_spoof_check_setting = -1;
+                else if (streq(lvalue, "QueryReceiveSideScaling"))
+                        sr_iov->query_rss = -1;
+                else if (streq(lvalue, "Trust"))
+                        sr_iov->trust = -1;
+                else
+                        assert_not_reached("Invalid lvalue");
+
+                TAKE_PTR(sr_iov);
+                return 0;
+        }
+
+        r = parse_boolean(rvalue);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse '%s=', ignoring: %s", lvalue, rvalue);
+                return 0;
+        }
+
+        if (streq(lvalue, "MACSpoofCheck"))
+                sr_iov->vf_spoof_check_setting = r;
+        else if (streq(lvalue, "QueryReceiveSideScaling"))
+                sr_iov->query_rss = r;
+        else if (streq(lvalue, "Trust"))
+                sr_iov->trust = r;
+        else
+                assert_not_reached("Invalid lvalue");
+
+        TAKE_PTR(sr_iov);
+        return 0;
+}
+
+int config_parse_sr_iov_mac(
+                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) {
+
+        _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL;
+        Network *network = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = sr_iov_new_static(network, filename, section_line, &sr_iov);
+        if (r < 0)
+                return r;
+
+        if (isempty(rvalue)) {
+                sr_iov->mac = ETHER_ADDR_NULL;
+                TAKE_PTR(sr_iov);
+                return 0;
+        }
+
+        r = ether_addr_from_string(rvalue, &sr_iov->mac);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, 0,
+                           "Failed to parse SR-IOV '%s=', ignoring assignment: %s", lvalue, rvalue);
+                return 0;
+        }
+
+        TAKE_PTR(sr_iov);
+        return 0;
+}
diff --git a/src/network/networkd-sriov.h b/src/network/networkd-sriov.h
new file mode 100644 (file)
index 0000000..a545d12
--- /dev/null
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: LGPL-2.1+
+ * Copyright © 2020 VMware, Inc. */
+#pragma once
+
+#include <linux/if_link.h>
+
+#include "conf-parser.h"
+#include "networkd-link.h"
+#include "networkd-network.h"
+#include "networkd-util.h"
+
+typedef enum SRIOVLinkState {
+        SR_IOV_LINK_STATE_AUTO = IFLA_VF_LINK_STATE_AUTO,
+        SR_IOV_LINK_STATE_ENABLE = IFLA_VF_LINK_STATE_ENABLE,
+        SR_IOV_LINK_STATE_DISABLE = IFLA_VF_LINK_STATE_DISABLE,
+        _SR_IOV_LINK_STATE_MAX,
+        _SR_IOV_LINK_STATE_INVALID = -1,
+} SRIOVLinkState;
+
+typedef struct SRIOV {
+        NetworkConfigSection *section;
+        Network *network;
+
+        uint32_t vf;   /* 0 - 2147483646 */
+        uint32_t vlan; /* 0 - 4095, 0 disables VLAN filter */
+        uint32_t qos;
+        uint16_t vlan_proto; /* ETH_P_8021Q or ETH_P_8021AD */
+        int vf_spoof_check_setting;
+        int query_rss;
+        int trust;
+        SRIOVLinkState link_state;
+        struct ether_addr mac;
+} SRIOV;
+
+SRIOV *sr_iov_free(SRIOV *sr_iov);
+
+int sr_iov_configure(Link *link, SRIOV *sr_iov);
+int sr_iov_section_verify(SRIOV *sr_iov);
+
+DEFINE_NETWORK_SECTION_FUNCTIONS(SRIOV, sr_iov_free);
+
+CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_uint32);
+CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_boolean);
+CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_link_state);
+CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_vlan_proto);
+CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_mac);
index 1e2ff05c3e527285b21542d1876230974cc95fb5..d4c49e673ef8a65dbca4df91e3968b7870a24fec 100644 (file)
@@ -190,7 +190,7 @@ static int dns_stream_identify(DnsStream *s) {
                 s->ifindex = manager_find_ifindex(s->manager, s->local.sa.sa_family, s->local.sa.sa_family == AF_INET ? (union in_addr_union*) &s->local.in.sin_addr : (union in_addr_union*)  &s->local.in6.sin6_addr);
 
         if (s->protocol == DNS_PROTOCOL_LLMNR && s->ifindex > 0) {
-                uint32_t ifindex = htobe32(s->ifindex);
+                be32_t ifindex = htobe32(s->ifindex);
 
                 /* Make sure all packets for this connection are sent on the same interface */
                 if (s->local.sa.sa_family == AF_INET) {
index 703da475b6ddf54bb62b8b412c0136d87ace5016..da4a9647ab30b6bec9078d7927e4adcf15a5f094 100644 (file)
@@ -38,6 +38,16 @@ MTUBytes=
 Multicast=
 MACAddress=
 Group=
+[SR-IOV]
+VirtualFunction=
+MACSpoofCheck=
+VLANId=
+VLANProtocol=
+QualityOfService=
+QueryReceiveSideScaling=
+Trust=
+LinkState=
+MACAddress=
 [BridgeFDB]
 VLANId=
 MACAddress=
diff --git a/test/test-network/conf/25-sriov.network b/test/test-network/conf/25-sriov.network
new file mode 100644 (file)
index 0000000..c962c3d
--- /dev/null
@@ -0,0 +1,37 @@
+[Match]
+Name=eni99np1
+
+[Network]
+Address=192.168.100.100/24
+
+[SR-IOV]
+VirtualFunction=0
+VLANId=5
+VLANProtocol=802.1ad
+QualityOfService=1
+MACSpoofCheck=yes
+QueryReceiveSideScaling=yes
+Trust=yes
+LinkState=yes
+MACAddress=00:11:22:33:44:55
+
+[SR-IOV]
+VirtualFunction=1
+VLANId=6
+VLANProtocol=802.1Q
+QualityOfService=2
+MACSpoofCheck=no
+QueryReceiveSideScaling=no
+Trust=no
+LinkState=no
+MACAddress=00:11:22:33:44:56
+
+[SR-IOV]
+VirtualFunction=2
+VLANId=7
+QualityOfService=3
+MACSpoofCheck=no
+QueryReceiveSideScaling=no
+Trust=no
+LinkState=auto
+MACAddress=00:11:22:33:44:57
index c48163b055a5604b6d4051a5835f8e7825849802..caf077c8365958ed3cccc9ea09eb89a223bde107 100755 (executable)
@@ -158,6 +158,33 @@ def expectedFailureIfAlternativeNameIsNotAvailable():
 
     return f
 
+def expectedFailureIfNetdevsimWithSRIOVIsNotAvailable():
+    def f(func):
+        call('rmmod netdevsim', stderr=subprocess.DEVNULL)
+        rc = call('modprobe netdevsim', stderr=subprocess.DEVNULL)
+        if rc != 0:
+            return unittest.expectedFailure(func)
+
+        try:
+            with open('/sys/bus/netdevsim/new_device', mode='w') as f:
+                f.write('99 1')
+        except Exception as error:
+            return unittest.expectedFailure(func)
+
+        call('udevadm settle')
+        call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr=subprocess.DEVNULL)
+        try:
+            with open('/sys/class/net/eni99np1/device/sriov_numvfs', mode='w') as f:
+                f.write('3')
+        except Exception as error:
+            call('rmmod netdevsim', stderr=subprocess.DEVNULL)
+            return unittest.expectedFailure(func)
+
+        call('rmmod netdevsim', stderr=subprocess.DEVNULL)
+        return func
+
+    return f
+
 def expectedFailureIfCAKEIsNotAvailable():
     def f(func):
         call('ip link add dummy98 type dummy', stderr=subprocess.DEVNULL)
@@ -1695,6 +1722,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
         '25-route-vrf.network',
         '25-gateway-static.network',
         '25-gateway-next-static.network',
+        '25-sriov.network',
         '25-sysctl-disable-ipv6.network',
         '25-sysctl.network',
         '25-test1.network',
@@ -2237,7 +2265,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
         self.assertRegex(output, 'inet6 .* scope link')
         output = check_output('ip -4 route show dev dummy98')
         print(output)
-        self.assertEqual(output, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
+        self.assertRegex(output, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
         output = check_output('ip -6 route show dev dummy98')
         print(output)
         self.assertRegex(output, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
@@ -2260,7 +2288,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
         self.assertRegex(output, 'inet6 .* scope link')
         output = check_output('ip -4 route show dev dummy98')
         print(output)
-        self.assertEqual(output, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
+        self.assertRegex(output, '10.2.0.0/16 proto kernel scope link src 10.2.3.4')
         output = check_output('ip -6 route show dev dummy98')
         print(output)
         self.assertRegex(output, 'default via 2607:5300:203:39ff:ff:ff:ff:ff proto static')
@@ -2508,6 +2536,32 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
         self.assertRegex(output, 'quanta 1 2 3 4 5')
         self.assertRegex(output, 'priomap 3 4 5 6 7')
 
+    @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
+    def test_sriov(self):
+        call('rmmod netdevsim', stderr=subprocess.DEVNULL)
+        call('modprobe netdevsim', stderr=subprocess.DEVNULL)
+        with open('/sys/bus/netdevsim/new_device', mode='w') as f:
+            f.write('99 1')
+
+        call('udevadm settle')
+        call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr=subprocess.DEVNULL)
+        with open('/sys/class/net/eni99np1/device/sriov_numvfs', mode='w') as f:
+            f.write('3')
+
+        copy_unit_to_networkd_unit_path('25-sriov.network')
+        start_networkd()
+        self.wait_online(['eni99np1:routable'])
+
+        output = check_output('ip link show dev eni99np1')
+        print(output)
+        self.assertRegex(output,
+                         'vf 0 .*00:11:22:33:44:55.*vlan 5, qos 1, vlan protocol 802.1ad, spoof checking on, link-state enable, trust on, query_rss on\n *'
+                         'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *'
+                         'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off'
+        )
+
+        call('rmmod netdevsim', stderr=subprocess.DEVNULL)
+
 class NetworkdStateFileTests(unittest.TestCase, Utilities):
     links = [
         'dummy98',