summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuca Boccassi <luca.boccassi@microsoft.com>2022-01-19 23:38:00 +0100
committerGitHub <noreply@github.com>2022-01-19 23:38:00 +0100
commitde843f8582c15da075a3f5aa7e2af0b9cccad034 (patch)
treef445079d4fc364df0ece0ee9ee07fe40c25325c1
parentboot: Use -ffile-prefix-map when present (diff)
parenttest-network: add testcases for configuring SR-IOV by .link file (diff)
downloadsystemd-de843f8582c15da075a3f5aa7e2af0b9cccad034.tar.xz
systemd-de843f8582c15da075a3f5aa7e2af0b9cccad034.zip
Merge pull request #21865 from yuwata/network-sr-iov
udev/net: support configuring SR-IOV virtual functions through .link file
-rw-r--r--man/systemd.link.xml98
-rw-r--r--man/systemd.network.xml89
-rw-r--r--src/network/netdev/l2tp-tunnel.c10
-rw-r--r--src/network/netdev/l2tp-tunnel.h2
-rw-r--r--src/network/netdev/macsec.c30
-rw-r--r--src/network/netdev/macsec.h6
-rw-r--r--src/network/netdev/wireguard.c10
-rw-r--r--src/network/netdev/wireguard.h2
-rw-r--r--src/network/networkd-address-label.c10
-rw-r--r--src/network/networkd-address-label.h2
-rw-r--r--src/network/networkd-address.c8
-rw-r--r--src/network/networkd-address.h4
-rw-r--r--src/network/networkd-bridge-fdb.c10
-rw-r--r--src/network/networkd-bridge-fdb.h2
-rw-r--r--src/network/networkd-bridge-mdb.c10
-rw-r--r--src/network/networkd-bridge-mdb.h2
-rw-r--r--src/network/networkd-dhcp-server-static-lease.c10
-rw-r--r--src/network/networkd-dhcp-server-static-lease.h4
-rw-r--r--src/network/networkd-link.c2
-rw-r--r--src/network/networkd-neighbor.c10
-rw-r--r--src/network/networkd-neighbor.h2
-rw-r--r--src/network/networkd-network-gperf.gperf18
-rw-r--r--src/network/networkd-network.c4
-rw-r--r--src/network/networkd-nexthop.c10
-rw-r--r--src/network/networkd-nexthop.h2
-rw-r--r--src/network/networkd-radv.c20
-rw-r--r--src/network/networkd-radv.h4
-rw-r--r--src/network/networkd-route.c8
-rw-r--r--src/network/networkd-route.h4
-rw-r--r--src/network/networkd-routing-policy-rule.c10
-rw-r--r--src/network/networkd-routing-policy-rule.h2
-rw-r--r--src/network/networkd-sriov.c458
-rw-r--r--src/network/networkd-sriov.h41
-rw-r--r--src/network/networkd-util.c44
-rw-r--r--src/network/networkd-util.h37
-rw-r--r--src/network/tc/qdisc.c8
-rw-r--r--src/network/tc/qdisc.h4
-rw-r--r--src/network/tc/tclass.c8
-rw-r--r--src/network/tc/tclass.h4
-rw-r--r--src/shared/conf-parser.c44
-rw-r--r--src/shared/conf-parser.h37
-rw-r--r--src/shared/meson.build2
-rw-r--r--src/shared/netif-sriov.c631
-rw-r--r--src/shared/netif-sriov.h48
-rw-r--r--src/udev/net/link-config-gperf.gperf11
-rw-r--r--src/udev/net/link-config.c87
-rw-r--r--src/udev/net/link-config.h4
-rw-r--r--test/fuzz/fuzz-link-parser/directives.link11
-rw-r--r--test/test-network/conf/25-sriov-udev.network7
-rw-r--r--test/test-network/conf/25-sriov.link40
-rwxr-xr-xtest/test-network/systemd-networkd-tests.py156
51 files changed, 1281 insertions, 806 deletions
diff --git a/man/systemd.link.xml b/man/systemd.link.xml
index 45cabbccf7..700defeda6 100644
--- a/man/systemd.link.xml
+++ b/man/systemd.link.xml
@@ -946,6 +946,104 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>SR-IOVVirtualFunctions=</varname></term>
+ <listitem>
+ <para>Specifies the number of SR-IOV virtual functions. Takes an integer in the range
+ 0…2147483647. Defaults to unset, and automatically determined from the values specified in
+ the <varname>VirtualFunction=</varname> settings in the [SR-IOV] sections.</para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect1>
+
+ <refsect1 id='sr-iov'>
+ <title>[SR-IOV] Section Options</title>
+ <para>The [SR-IOV] section accepts the following keys. Specify several [SR-IOV] 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 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 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 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 one 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 one 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>
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 574cf599ec..4f41394682 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -300,94 +300,7 @@
</variablelist>
</refsect1>
- <refsect1>
- <title>[SR-IOV] Section Options</title>
- <para>The [SR-IOV] section accepts the following keys. Specify several [SR-IOV] 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 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 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 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 one 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 one 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>
+ <xi:include href="systemd.link.xml" xpointer="sr-iov" />
<refsect1>
<title>[Network] Section Options</title>
diff --git a/src/network/netdev/l2tp-tunnel.c b/src/network/netdev/l2tp-tunnel.c
index d870a11e00..419541ebdf 100644
--- a/src/network/netdev/l2tp-tunnel.c
+++ b/src/network/netdev/l2tp-tunnel.c
@@ -46,15 +46,15 @@ static L2tpSession* l2tp_session_free(L2tpSession *s) {
if (s->tunnel && s->section)
ordered_hashmap_remove(s->tunnel->sessions_by_section, s->section);
- network_config_section_free(s->section);
+ config_section_free(s->section);
free(s->name);
return mfree(s);
}
-DEFINE_NETWORK_SECTION_FUNCTIONS(L2tpSession, l2tp_session_free);
+DEFINE_SECTION_CLEANUP_FUNCTIONS(L2tpSession, l2tp_session_free);
static int l2tp_session_new_static(L2tpTunnel *t, const char *filename, unsigned section_line, L2tpSession **ret) {
- _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+ _cleanup_(config_section_freep) ConfigSection *n = NULL;
_cleanup_(l2tp_session_freep) L2tpSession *s = NULL;
int r;
@@ -63,7 +63,7 @@ static int l2tp_session_new_static(L2tpTunnel *t, const char *filename, unsigned
assert(filename);
assert(section_line > 0);
- r = network_config_section_new(filename, section_line, &n);
+ r = config_section_new(filename, section_line, &n);
if (r < 0)
return r;
@@ -83,7 +83,7 @@ static int l2tp_session_new_static(L2tpTunnel *t, const char *filename, unsigned
.section = TAKE_PTR(n),
};
- r = ordered_hashmap_ensure_put(&t->sessions_by_section, &network_config_hash_ops, s->section, s);
+ r = ordered_hashmap_ensure_put(&t->sessions_by_section, &config_section_hash_ops, s->section, s);
if (r < 0)
return r;
diff --git a/src/network/netdev/l2tp-tunnel.h b/src/network/netdev/l2tp-tunnel.h
index a884d2100f..236b78ce4b 100644
--- a/src/network/netdev/l2tp-tunnel.h
+++ b/src/network/netdev/l2tp-tunnel.h
@@ -34,7 +34,7 @@ typedef struct L2tpTunnel L2tpTunnel;
typedef struct L2tpSession {
L2tpTunnel *tunnel;
- NetworkConfigSection *section;
+ ConfigSection *section;
char *name;
diff --git a/src/network/netdev/macsec.c b/src/network/netdev/macsec.c
index ebb8c9c7dc..a049ade6ba 100644
--- a/src/network/netdev/macsec.c
+++ b/src/network/netdev/macsec.c
@@ -43,16 +43,16 @@ static ReceiveAssociation* macsec_receive_association_free(ReceiveAssociation *c
if (c->macsec && c->section)
ordered_hashmap_remove(c->macsec->receive_associations_by_section, c->section);
- network_config_section_free(c->section);
+ config_section_free(c->section);
security_association_clear(&c->sa);
return mfree(c);
}
-DEFINE_NETWORK_SECTION_FUNCTIONS(ReceiveAssociation, macsec_receive_association_free);
+DEFINE_SECTION_CLEANUP_FUNCTIONS(ReceiveAssociation, macsec_receive_association_free);
static int macsec_receive_association_new_static(MACsec *s, const char *filename, unsigned section_line, ReceiveAssociation **ret) {
- _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+ _cleanup_(config_section_freep) ConfigSection *n = NULL;
_cleanup_(macsec_receive_association_freep) ReceiveAssociation *c = NULL;
int r;
@@ -61,7 +61,7 @@ static int macsec_receive_association_new_static(MACsec *s, const char *filename
assert(filename);
assert(section_line > 0);
- r = network_config_section_new(filename, section_line, &n);
+ r = config_section_new(filename, section_line, &n);
if (r < 0)
return r;
@@ -82,7 +82,7 @@ static int macsec_receive_association_new_static(MACsec *s, const char *filename
security_association_init(&c->sa);
- r = ordered_hashmap_ensure_put(&s->receive_associations_by_section, &network_config_hash_ops, c->section, c);
+ r = ordered_hashmap_ensure_put(&s->receive_associations_by_section, &config_section_hash_ops, c->section, c);
if (r < 0)
return r;
@@ -103,12 +103,12 @@ static ReceiveChannel* macsec_receive_channel_free(ReceiveChannel *c) {
ordered_hashmap_remove(c->macsec->receive_channels_by_section, c->section);
}
- network_config_section_free(c->section);
+ config_section_free(c->section);
return mfree(c);
}
-DEFINE_NETWORK_SECTION_FUNCTIONS(ReceiveChannel, macsec_receive_channel_free);
+DEFINE_SECTION_CLEANUP_FUNCTIONS(ReceiveChannel, macsec_receive_channel_free);
static int macsec_receive_channel_new(MACsec *s, uint64_t sci, ReceiveChannel **ret) {
ReceiveChannel *c;
@@ -129,7 +129,7 @@ static int macsec_receive_channel_new(MACsec *s, uint64_t sci, ReceiveChannel **
}
static int macsec_receive_channel_new_static(MACsec *s, const char *filename, unsigned section_line, ReceiveChannel **ret) {
- _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+ _cleanup_(config_section_freep) ConfigSection *n = NULL;
_cleanup_(macsec_receive_channel_freep) ReceiveChannel *c = NULL;
int r;
@@ -138,7 +138,7 @@ static int macsec_receive_channel_new_static(MACsec *s, const char *filename, un
assert(filename);
assert(section_line > 0);
- r = network_config_section_new(filename, section_line, &n);
+ r = config_section_new(filename, section_line, &n);
if (r < 0)
return r;
@@ -154,7 +154,7 @@ static int macsec_receive_channel_new_static(MACsec *s, const char *filename, un
c->section = TAKE_PTR(n);
- r = ordered_hashmap_ensure_put(&s->receive_channels_by_section, &network_config_hash_ops, c->section, c);
+ r = ordered_hashmap_ensure_put(&s->receive_channels_by_section, &config_section_hash_ops, c->section, c);
if (r < 0)
return r;
@@ -170,16 +170,16 @@ static TransmitAssociation* macsec_transmit_association_free(TransmitAssociation
if (a->macsec && a->section)
ordered_hashmap_remove(a->macsec->transmit_associations_by_section, a->section);
- network_config_section_free(a->section);
+ config_section_free(a->section);
security_association_clear(&a->sa);
return mfree(a);
}
-DEFINE_NETWORK_SECTION_FUNCTIONS(TransmitAssociation, macsec_transmit_association_free);
+DEFINE_SECTION_CLEANUP_FUNCTIONS(TransmitAssociation, macsec_transmit_association_free);
static int macsec_transmit_association_new_static(MACsec *s, const char *filename, unsigned section_line, TransmitAssociation **ret) {
- _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+ _cleanup_(config_section_freep) ConfigSection *n = NULL;
_cleanup_(macsec_transmit_association_freep) TransmitAssociation *a = NULL;
int r;
@@ -188,7 +188,7 @@ static int macsec_transmit_association_new_static(MACsec *s, const char *filenam
assert(filename);
assert(section_line > 0);
- r = network_config_section_new(filename, section_line, &n);
+ r = config_section_new(filename, section_line, &n);
if (r < 0)
return r;
@@ -209,7 +209,7 @@ static int macsec_transmit_association_new_static(MACsec *s, const char *filenam
security_association_init(&a->sa);
- r = ordered_hashmap_ensure_put(&s->transmit_associations_by_section, &network_config_hash_ops, a->section, a);
+ r = ordered_hashmap_ensure_put(&s->transmit_associations_by_section, &config_section_hash_ops, a->section, a);
if (r < 0)
return r;
diff --git a/src/network/netdev/macsec.h b/src/network/netdev/macsec.h
index 4d88e49514..17bb1ca3fb 100644
--- a/src/network/netdev/macsec.h
+++ b/src/network/netdev/macsec.h
@@ -39,14 +39,14 @@ typedef struct SecurityAssociation {
typedef struct TransmitAssociation {
MACsec *macsec;
- NetworkConfigSection *section;
+ ConfigSection *section;
SecurityAssociation sa;
} TransmitAssociation;
typedef struct ReceiveAssociation {
MACsec *macsec;
- NetworkConfigSection *section;
+ ConfigSection *section;
MACsecSCI sci;
SecurityAssociation sa;
@@ -54,7 +54,7 @@ typedef struct ReceiveAssociation {
typedef struct ReceiveChannel {
MACsec *macsec;
- NetworkConfigSection *section;
+ ConfigSection *section;
MACsecSCI sci;
ReceiveAssociation *rxsa[MACSEC_MAX_ASSOCIATION_NUMBER];
diff --git a/src/network/netdev/wireguard.c b/src/network/netdev/wireguard.c
index 88f668753a..431b5ec045 100644
--- a/src/network/netdev/wireguard.c
+++ b/src/network/netdev/wireguard.c
@@ -47,7 +47,7 @@ static WireguardPeer* wireguard_peer_free(WireguardPeer *peer) {
hashmap_remove(peer->wireguard->peers_by_section, peer->section);
}
- network_config_section_free(peer->section);
+ config_section_free(peer->section);
while ((mask = peer->ipmasks)) {
LIST_REMOVE(ipmasks, peer->ipmasks, mask);
@@ -65,10 +65,10 @@ static WireguardPeer* wireguard_peer_free(WireguardPeer *peer) {
return mfree(peer);
}
-DEFINE_NETWORK_SECTION_FUNCTIONS(WireguardPeer, wireguard_peer_free);
+DEFINE_SECTION_CLEANUP_FUNCTIONS(WireguardPeer, wireguard_peer_free);
static int wireguard_peer_new_static(Wireguard *w, const char *filename, unsigned section_line, WireguardPeer **ret) {
- _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+ _cleanup_(config_section_freep) ConfigSection *n = NULL;
_cleanup_(wireguard_peer_freep) WireguardPeer *peer = NULL;
int r;
@@ -77,7 +77,7 @@ static int wireguard_peer_new_static(Wireguard *w, const char *filename, unsigne
assert(filename);
assert(section_line > 0);
- r = network_config_section_new(filename, section_line, &n);
+ r = config_section_new(filename, section_line, &n);
if (r < 0)
return r;
@@ -99,7 +99,7 @@ static int wireguard_peer_new_static(Wireguard *w, const char *filename, unsigne
LIST_PREPEND(peers, w->peers, peer);
- r = hashmap_ensure_put(&w->peers_by_section, &network_config_hash_ops, peer->section, peer);
+ r = hashmap_ensure_put(&w->peers_by_section, &config_section_hash_ops, peer->section, peer);
if (r < 0)
return r;
diff --git a/src/network/netdev/wireguard.h b/src/network/netdev/wireguard.h
index 29bacdc771..09dca88bbf 100644
--- a/src/network/netdev/wireguard.h
+++ b/src/network/netdev/wireguard.h
@@ -24,7 +24,7 @@ typedef struct WireguardIPmask {
typedef struct WireguardPeer {
Wireguard *wireguard;
- NetworkConfigSection *section;
+ ConfigSection *section;
uint8_t public_key[WG_KEY_LEN];
uint8_t preshared_key[WG_KEY_LEN];
diff --git a/src/network/networkd-address-label.c b/src/network/networkd-address-label.c
index 6f911b805f..506238f391 100644
--- a/src/network/networkd-address-label.c
+++ b/src/network/networkd-address-label.c
@@ -21,14 +21,14 @@ AddressLabel *address_label_free(AddressLabel *label) {
hashmap_remove(label->network->address_labels_by_section, label->section);
}
- network_config_section_free(label->section);
+ config_section_free(label->section);
return mfree(label);
}
-DEFINE_NETWORK_SECTION_FUNCTIONS(AddressLabel, address_label_free);
+DEFINE_SECTION_CLEANUP_FUNCTIONS(AddressLabel, address_label_free);
static int address_label_new_static(Network *network, const char *filename, unsigned section_line, AddressLabel **ret) {
- _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+ _cleanup_(config_section_freep) ConfigSection *n = NULL;
_cleanup_(address_label_freep) AddressLabel *label = NULL;
int r;
@@ -37,7 +37,7 @@ static int address_label_new_static(Network *network, const char *filename, unsi
assert(filename);
assert(section_line > 0);
- r = network_config_section_new(filename, section_line, &n);
+ r = config_section_new(filename, section_line, &n);
if (r < 0)
return r;
@@ -57,7 +57,7 @@ static int address_label_new_static(Network *network, const char *filename, unsi
.label = UINT32_MAX,
};
- r = hashmap_ensure_put(&network->address_labels_by_section, &network_config_hash_ops, label->section, label);
+ r = hashmap_ensure_put(&network->address_labels_by_section, &config_section_hash_ops, label->section, label);
if (r < 0)
return r;
diff --git a/src/network/networkd-address-label.h b/src/network/networkd-address-label.h
index 0f975454d9..582dd05b88 100644
--- a/src/network/networkd-address-label.h
+++ b/src/network/networkd-address-label.h
@@ -13,7 +13,7 @@ typedef struct Request Request;
typedef struct AddressLabel {
Network *network;
- NetworkConfigSection *section;
+ ConfigSection *section;
uint32_t label;
struct in6_addr prefix;
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index 7df743efb5..ff80f185ce 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -77,7 +77,7 @@ int address_new(Address **ret) {
}
static int address_new_static(Network *network, const char *filename, unsigned section_line, Address **ret) {
- _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+ _cleanup_(config_section_freep) ConfigSection *n = NULL;
_cleanup_(address_freep) Address *address = NULL;
int r;
@@ -86,7 +86,7 @@ static int address_new_static(Network *network, const char *filename, unsigned s
assert(filename);
assert(section_line > 0);
- r = network_config_section_new(filename, section_line, &n);
+ r = config_section_new(filename, section_line, &n);
if (r < 0)
return r;
@@ -107,7 +107,7 @@ static int address_new_static(Network *network, const char *filename, unsigned s
address->section = TAKE_PTR(n);
address->source = NETWORK_CONFIG_SOURCE_STATIC;
- r = ordered_hashmap_ensure_put(&network->addresses_by_section, &network_config_hash_ops, address->section, address);
+ r = ordered_hashmap_ensure_put(&network->addresses_by_section, &config_section_hash_ops, address->section, address);
if (r < 0)
return r;
@@ -134,7 +134,7 @@ Address *address_free(Address *address) {
sd_ipv4acd_unref(address->acd);
- network_config_section_free(address->section);
+ config_section_free(address->section);
free(address->label);
return mfree(address);
}
diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h
index 41c4ce6fa4..c1e5b3ce3a 100644
--- a/src/network/networkd-address.h
+++ b/src/network/networkd-address.h
@@ -22,7 +22,7 @@ typedef int (*address_ready_callback_t)(Address *address);
struct Address {
Link *link;
Network *network;
- NetworkConfigSection *section;
+ ConfigSection *section;
NetworkConfigSource source;
NetworkConfigState state;
union in_addr_union provider; /* DHCP server or router address */
@@ -72,7 +72,7 @@ int address_dup(const Address *src, Address **ret);
bool address_is_ready(const Address *a);
void address_set_broadcast(Address *a);
-DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free);
+DEFINE_SECTION_CLEANUP_FUNCTIONS(Address, address_free);
int link_drop_addresses(Link *link);
int link_drop_foreign_addresses(Link *link);
diff --git a/src/network/networkd-bridge-fdb.c b/src/network/networkd-bridge-fdb.c
index a0024f62d4..c1e2977d4d 100644
--- a/src/network/networkd-bridge-fdb.c
+++ b/src/network/networkd-bridge-fdb.c
@@ -32,13 +32,13 @@ BridgeFDB *bridge_fdb_free(BridgeFDB *fdb) {
hashmap_remove(fdb->network->bridge_fdb_entries_by_section, fdb->section);
}
- network_config_section_free(fdb->section);
+ config_section_free(fdb->section);
free(fdb->outgoing_ifname);
return mfree(fdb);
}
-DEFINE_NETWORK_SECTION_FUNCTIONS(BridgeFDB, bridge_fdb_free);
+DEFINE_SECTION_CLEANUP_FUNCTIONS(BridgeFDB, bridge_fdb_free);
/* create a new FDB entry or get an existing one. */
static int bridge_fdb_new_static(
@@ -47,7 +47,7 @@ static int bridge_fdb_new_static(
unsigned section_line,
BridgeFDB **ret) {
- _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+ _cleanup_(config_section_freep) ConfigSection *n = NULL;
_cleanup_(bridge_fdb_freep) BridgeFDB *fdb = NULL;
int r;
@@ -56,7 +56,7 @@ static int bridge_fdb_new_static(
assert(filename);
assert(section_line > 0);
- r = network_config_section_new(filename, section_line, &n);
+ r = config_section_new(filename, section_line, &n);
if (r < 0)
return r;
@@ -83,7 +83,7 @@ static int bridge_fdb_new_static(
.ntf_flags = NEIGHBOR_CACHE_ENTRY_FLAGS_SELF,
};
- r = hashmap_ensure_put(&network->bridge_fdb_entries_by_section, &network_config_hash_ops, fdb->section, fdb);
+ r = hashmap_ensure_put(&network->bridge_fdb_entries_by_section, &config_section_hash_ops, fdb->section, fdb);
if (r < 0)
return r;
diff --git a/src/network/networkd-bridge-fdb.h b/src/network/networkd-bridge-fdb.h
index fae7da5bbb..b1098760d2 100644
--- a/src/network/networkd-bridge-fdb.h
+++ b/src/network/networkd-bridge-fdb.h
@@ -27,7 +27,7 @@ typedef enum NeighborCacheEntryFlags {
typedef struct BridgeFDB {
Network *network;
- NetworkConfigSection *section;
+ ConfigSection *section;
uint32_t vni;
diff --git a/src/network/networkd-bridge-mdb.c b/src/network/networkd-bridge-mdb.c
index 10025a97ae..d155090ad1 100644
--- a/src/network/networkd-bridge-mdb.c
+++ b/src/network/networkd-bridge-mdb.c
@@ -24,12 +24,12 @@ BridgeMDB *bridge_mdb_free(BridgeMDB *mdb) {
hashmap_remove(mdb->network->bridge_mdb_entries_by_section, mdb->section);
}
- network_config_section_free(mdb->section);
+ config_section_free(mdb->section);
return mfree(mdb);
}
-DEFINE_NETWORK_SECTION_FUNCTIONS(BridgeMDB, bridge_mdb_free);
+DEFINE_SECTION_CLEANUP_FUNCTIONS(BridgeMDB, bridge_mdb_free);
/* create a new MDB entry or get an existing one. */
static int bridge_mdb_new_static(
@@ -38,7 +38,7 @@ static int bridge_mdb_new_static(
unsigned section_line,
BridgeMDB **ret) {
- _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+ _cleanup_(config_section_freep) ConfigSection *n = NULL;
_cleanup_(bridge_mdb_freep) BridgeMDB *mdb = NULL;
int r;
@@ -47,7 +47,7 @@ static int bridge_mdb_new_static(
assert(filename);
assert(section_line > 0);
- r = network_config_section_new(filename, section_line, &n);
+ r = config_section_new(filename, section_line, &n);
if (r < 0)
return r;
@@ -72,7 +72,7 @@ static int bridge_mdb_new_static(
.section = TAKE_PTR(n),
};
- r = hashmap_ensure_put(&network->bridge_mdb_entries_by_section, &network_config_hash_ops, mdb->section, mdb);
+ r = hashmap_ensure_put(&network->bridge_mdb_entries_by_section, &config_section_hash_ops, mdb->section, mdb);
if (r < 0)
return r;
diff --git a/src/network/networkd-bridge-mdb.h b/src/network/networkd-bridge-mdb.h
index 9ca262e0ce..ce91e3f572 100644
--- a/src/network/networkd-bridge-mdb.h
+++ b/src/network/networkd-bridge-mdb.h
@@ -13,7 +13,7 @@ typedef struct Request Request;
typedef struct BridgeMDB {
Network *network;
- NetworkConfigSection *section;
+ ConfigSection *section;
int family;
union in_addr_union group_addr;
diff --git a/src/network/networkd-dhcp-server-static-lease.c b/src/network/networkd-dhcp-server-static-lease.c
index 6acd838e2b..38e8c7e889 100644
--- a/src/network/networkd-dhcp-server-static-lease.c
+++ b/src/network/networkd-dhcp-server-static-lease.c
@@ -7,7 +7,7 @@
#include "networkd-network.h"
#include "networkd-util.h"
-DEFINE_NETWORK_SECTION_FUNCTIONS(DHCPStaticLease, dhcp_static_lease_free);
+DEFINE_SECTION_CLEANUP_FUNCTIONS(DHCPStaticLease, dhcp_static_lease_free);
DHCPStaticLease *dhcp_static_lease_free(DHCPStaticLease *static_lease) {
if (!static_lease)
@@ -16,7 +16,7 @@ DHCPStaticLease *dhcp_static_lease_free(DHCPStaticLease *static_lease) {
if (static_lease->network && static_lease->section)
hashmap_remove(static_lease->network->dhcp_static_leases_by_section, static_lease->section);
- network_config_section_free(static_lease->section);
+ config_section_free(static_lease->section);
free(static_lease->client_id);
return mfree(static_lease);
}
@@ -35,7 +35,7 @@ static int dhcp_static_lease_new(DHCPStaticLease **ret) {
}
static int lease_new_static(Network *network, const char *filename, unsigned section_line, DHCPStaticLease **ret) {
- _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+ _cleanup_(config_section_freep) ConfigSection *n = NULL;
_cleanup_(dhcp_static_lease_freep) DHCPStaticLease *static_lease = NULL;
int r;
@@ -44,7 +44,7 @@ static int lease_new_static(Network *network, const char *filename, unsigned sec
assert(section_line > 0);
assert(ret);
- r = network_config_section_new(filename, section_line, &n);
+ r = config_section_new(filename, section_line, &n);
if (r < 0)
return r;
@@ -60,7 +60,7 @@ static int lease_new_static(Network *network, const char *filename, unsigned sec
static_lease->network = network;
static_lease->section = TAKE_PTR(n);
- r = hashmap_ensure_put(&network->dhcp_static_leases_by_section, &network_config_hash_ops, static_lease->section, static_lease);
+ r = hashmap_ensure_put(&network->dhcp_static_leases_by_section, &config_section_hash_ops, static_lease->section, static_lease);
if (r < 0)
return r;
diff --git a/src/network/networkd-dhcp-server-static-lease.h b/src/network/networkd-dhcp-server-static-lease.h
index c2a9ad6bb1..9b8e78b90d 100644
--- a/src/network/networkd-dhcp-server-static-lease.h
+++ b/src/network/networkd-dhcp-server-static-lease.h
@@ -8,11 +8,11 @@
#include "in-addr-util.h"
typedef struct Network Network;
-typedef struct NetworkConfigSection NetworkConfigSection;
+typedef struct ConfigSection ConfigSection;
typedef struct DHCPStaticLease {
Network *network;
- NetworkConfigSection *section;
+ ConfigSection *section;
struct in_addr address;
uint8_t *client_id;
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index cea700bbb8..89ee8c8367 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -2549,6 +2549,8 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
r = ethtool_get_driver(&manager->ethtool_fd, link->ifname, &link->driver);
if (r < 0)
log_link_debug_errno(link, r, "Failed to get driver, continuing without: %m");
+ else
+ log_link_debug(link, "Found driver: %s", strna(link->driver));
if (streq_ptr(link->driver, "dsa")) {
uint32_t dsa_master_ifindex;
diff --git a/src/network/networkd-neighbor.c b/src/network/networkd-neighbor.c
index 26b7385497..4aab290bf8 100644
--- a/src/network/networkd-neighbor.c
+++ b/src/network/networkd-neighbor.c
@@ -19,7 +19,7 @@ Neighbor *neighbor_free(Neighbor *neighbor) {
hashmap_remove(neighbor->network->neighbors_by_section, neighbor->section);
}
- network_config_section_free(neighbor->section);
+ config_section_free(neighbor->section);
if (neighbor->link)
set_remove(neighbor->link->neighbors, neighbor);
@@ -27,10 +27,10 @@ Neighbor *neighbor_free(Neighbor *neighbor) {
return mfree(neighbor);
}
-DEFINE_NETWORK_SECTION_FUNCTIONS(Neighbor, neighbor_free);
+DEFINE_SECTION_CLEANUP_FUNCTIONS(Neighbor, neighbor_free);
static int neighbor_new_static(Network *network, const char *filename, unsigned section_line, Neighbor **ret) {
- _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+ _cleanup_(config_section_freep) ConfigSection *n = NULL;
_cleanup_(neighbor_freep) Neighbor *neighbor = NULL;
int r;
@@ -39,7 +39,7 @@ static int neighbor_new_static(Network *network, const char *filename, unsigned
assert(filename);
assert(section_line > 0);
- r = network_config_section_new(filename, section_line, &n);
+ r = config_section_new(filename, section_line, &n);
if (r < 0)
return r;
@@ -60,7 +60,7 @@ static int neighbor_new_static(Network *network, const char *filename, unsigned
.source = NETWORK_CONFIG_SOURCE_STATIC,
};
- r = hashmap_ensure_put(&network->neighbors_by_section, &network_config_hash_ops, neighbor->section, neighbor);
+ r = hashmap_ensure_put(&network->neighbors_by_section, &config_section_hash_ops, neighbor->section, neighbor);
if (r < 0)
return r;
diff --git a/src/network/networkd-neighbor.h b/src/network/networkd-neighbor.h
index e9e1854110..f31f58a4d4 100644
--- a/src/network/networkd-neighbor.h
+++ b/src/network/networkd-neighbor.h
@@ -18,7 +18,7 @@ typedef struct Request Request;
typedef struct Neighbor {
Network *network;
Link *link;
- NetworkConfigSection *section;
+ ConfigSection *section;
NetworkConfigSource source;
NetworkConfigState state;
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 4c3bf97311..08e3f13f5a 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -73,15 +73,15 @@ Link.Unmanaged, config_parse_bool,
Link.ActivationPolicy, config_parse_activation_policy, 0, offsetof(Network, activation_policy)
Link.RequiredForOnline, config_parse_required_for_online, 0, 0
Link.RequiredFamilyForOnline, config_parse_required_family_for_online, 0, offsetof(Network, required_family_for_online)
-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
+SR-IOV.VirtualFunction, config_parse_sr_iov_uint32, 0, offsetof(Network, sr_iov_by_section)
+SR-IOV.VLANId, config_parse_sr_iov_uint32, 0, offsetof(Network, sr_iov_by_section)
+SR-IOV.QualityOfService, config_parse_sr_iov_uint32, 0, offsetof(Network, sr_iov_by_section)
+SR-IOV.VLANProtocol, config_parse_sr_iov_vlan_proto, 0, offsetof(Network, sr_iov_by_section)
+SR-IOV.MACSpoofCheck, config_parse_sr_iov_boolean, 0, offsetof(Network, sr_iov_by_section)
+SR-IOV.QueryReceiveSideScaling, config_parse_sr_iov_boolean, 0, offsetof(Network, sr_iov_by_section)
+SR-IOV.Trust, config_parse_sr_iov_boolean, 0, offsetof(Network, sr_iov_by_section)
+SR-IOV.LinkState, config_parse_sr_iov_link_state, 0, offsetof(Network, sr_iov_by_section)
+SR-IOV.MACAddress, config_parse_sr_iov_mac, 0, offsetof(Network, sr_iov_by_section)
Network.Description, config_parse_string, 0, offsetof(Network, description)
Network.KeepMaster, config_parse_bool, 0, offsetof(Network, keep_master)
Network.BatmanAdvanced, config_parse_ifname, 0, offsetof(Network, batadv_name)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 873ad2e703..3142be471f 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -321,7 +321,9 @@ int network_verify(Network *network) {
network_drop_invalid_route_prefixes(network);
network_drop_invalid_routing_policy_rules(network);
network_drop_invalid_traffic_control(network);
- network_drop_invalid_sr_iov(network);
+ r = sr_iov_drop_invalid_sections(UINT32_MAX, network->sr_iov_by_section);
+ if (r < 0)
+ return r;
network_drop_invalid_static_leases(network);
network_adjust_dhcp_server(network);
diff --git a/src/network/networkd-nexthop.c b/src/network/networkd-nexthop.c
index b829aaab90..e9e5d08557 100644
--- a/src/network/networkd-nexthop.c
+++ b/src/network/networkd-nexthop.c
@@ -27,7 +27,7 @@ NextHop *nexthop_free(NextHop *nexthop) {
hashmap_remove(nexthop->network->nexthops_by_section, nexthop->section);
}
- network_config_section_free(nexthop->section);
+ config_section_free(nexthop->section);
if (nexthop->link) {
set_remove(nexthop->link->nexthops, nexthop);
@@ -48,7 +48,7 @@ NextHop *nexthop_free(NextHop *nexthop) {
return mfree(nexthop);
}
-DEFINE_NETWORK_SECTION_FUNCTIONS(NextHop, nexthop_free);
+DEFINE_SECTION_CLEANUP_FUNCTIONS(NextHop, nexthop_free);
static int nexthop_new(NextHop **ret) {
_cleanup_(nexthop_freep) NextHop *nexthop = NULL;
@@ -68,7 +68,7 @@ static int nexthop_new(NextHop **ret) {
}
static int nexthop_new_static(Network *network, const char *filename, unsigned section_line, NextHop **ret) {
- _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+ _cleanup_(config_section_freep) ConfigSection *n = NULL;
_cleanup_(nexthop_freep) NextHop *nexthop = NULL;
int r;
@@ -77,7 +77,7 @@ static int nexthop_new_static(Network *network, const char *filename, unsigned s
assert(filename);
assert(section_line > 0);
- r = network_config_section_new(filename, section_line, &n);
+ r = config_section_new(filename, section_line, &n);
if (r < 0)
return r;
@@ -96,7 +96,7 @@ static int nexthop_new_static(Network *network, const char *filename, unsigned s
nexthop->section = TAKE_PTR(n);
nexthop->source = NETWORK_CONFIG_SOURCE_STATIC;
- r = hashmap_ensure_put(&network->nexthops_by_section, &network_config_hash_ops, nexthop->section, nexthop);
+ r = hashmap_ensure_put(&network->nexthops_by_section, &config_section_hash_ops, nexthop->section, nexthop);
if (r < 0)
return r;
diff --git a/src/network/networkd-nexthop.h b/src/network/networkd-nexthop.h
index 7a8920238c..01b29ae560 100644
--- a/src/network/networkd-nexthop.h
+++ b/src/network/networkd-nexthop.h
@@ -22,7 +22,7 @@ typedef struct NextHop {
Network *network;
Manager *manager;
Link *link;
- NetworkConfigSection *section;
+ ConfigSection *section;
NetworkConfigSource source;
NetworkConfigState state;
diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c
index 59b0922a4c..0c5eebc815 100644
--- a/src/network/networkd-radv.c
+++ b/src/network/networkd-radv.c
@@ -69,16 +69,16 @@ Prefix *prefix_free(Prefix *prefix) {
hashmap_remove(prefix->network->prefixes_by_section, prefix->section);
}
- network_config_section_free(prefix->section);
+ config_section_free(prefix->section);
set_free(prefix->tokens);
return mfree(prefix);
}
-DEFINE_NETWORK_SECTION_FUNCTIONS(Prefix, prefix_free);
+DEFINE_SECTION_CLEANUP_FUNCTIONS(Prefix, prefix_free);
static int prefix_new_static(Network *network, const char *filename, unsigned section_line, Prefix **ret) {
- _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+ _cleanup_(config_section_freep) ConfigSection *n = NULL;
_cleanup_(prefix_freep) Prefix *prefix = NULL;
int r;
@@ -87,7 +87,7 @@ static int prefix_new_static(Network *network, const char *filename, unsigned se
assert(filename);
assert(section_line > 0);
- r = network_config_section_new(filename, section_line, &n);
+ r = config_section_new(filename, section_line, &n);
if (r < 0)
return r;
@@ -111,7 +111,7 @@ static int prefix_new_static(Network *network, const char *filename, unsigned se
.address_auto_configuration = true,
};
- r = hashmap_ensure_put(&network->prefixes_by_section, &network_config_hash_ops, prefix->section, prefix);
+ r = hashmap_ensure_put(&network->prefixes_by_section, &config_section_hash_ops, prefix->section, prefix);
if (r < 0)
return r;
@@ -128,15 +128,15 @@ RoutePrefix *route_prefix_free(RoutePrefix *prefix) {
hashmap_remove(prefix->network->route_prefixes_by_section, prefix->section);
}
- network_config_section_free(prefix->section);
+ config_section_free(prefix->section);
return mfree(prefix);
}
-DEFINE_NETWORK_SECTION_FUNCTIONS(RoutePrefix, route_prefix_free);
+DEFINE_SECTION_CLEANUP_FUNCTIONS(RoutePrefix, route_prefix_free);
static int route_prefix_new_static(Network *network, const char *filename, unsigned section_line, RoutePrefix **ret) {
- _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+ _cleanup_(config_section_freep) ConfigSection *n = NULL;
_cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL;
int r;
@@ -145,7 +145,7 @@ static int route_prefix_new_static(Network *network, const char *filename, unsig
assert(filename);
assert(section_line > 0);
- r = network_config_section_new(filename, section_line, &n);
+ r = config_section_new(filename, section_line, &n);
if (r < 0)
return r;
@@ -166,7 +166,7 @@ static int route_prefix_new_static(Network *network, const char *filename, unsig
.lifetime = RADV_DEFAULT_VALID_LIFETIME_USEC,
};
- r = hashmap_ensure_put(&network->route_prefixes_by_section, &network_config_hash_ops, prefix->section, prefix);
+ r = hashmap_ensure_put(&network->route_prefixes_by_section, &config_section_hash_ops, prefix->section, prefix);
if (r < 0)
return r;
diff --git a/src/network/networkd-radv.h b/src/network/networkd-radv.h
index 392c00b37d..952fa8ae58 100644
--- a/src/network/networkd-radv.h
+++ b/src/network/networkd-radv.h
@@ -29,7 +29,7 @@ typedef enum RADVPrefixDelegation {
typedef struct Prefix {
Network *network;
- NetworkConfigSection *section;
+ ConfigSection *section;
struct in6_addr prefix;
uint8_t prefixlen;
@@ -46,7 +46,7 @@ typedef struct Prefix {
typedef struct RoutePrefix {
Network *network;
- NetworkConfigSection *section;
+ ConfigSection *section;
struct in6_addr prefix;
uint8_t prefixlen;
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index 00e64978d4..03021362b6 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -47,7 +47,7 @@ int route_new(Route **ret) {
}
static int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) {
- _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+ _cleanup_(config_section_freep) ConfigSection *n = NULL;
_cleanup_(route_freep) Route *route = NULL;
int r;
@@ -56,7 +56,7 @@ static int route_new_static(Network *network, const char *filename, unsigned sec
assert(filename);
assert(section_line > 0);
- r = network_config_section_new(filename, section_line, &n);
+ r = config_section_new(filename, section_line, &n);
if (r < 0)
return r;
@@ -78,7 +78,7 @@ static int route_new_static(Network *network, const char *filename, unsigned sec
route->section = TAKE_PTR(n);
route->source = NETWORK_CONFIG_SOURCE_STATIC;
- r = hashmap_ensure_put(&network->routes_by_section, &network_config_hash_ops, route->section, route);
+ r = hashmap_ensure_put(&network->routes_by_section, &config_section_hash_ops, route->section, route);
if (r < 0)
return r;
@@ -95,7 +95,7 @@ Route *route_free(Route *route) {
hashmap_remove(route->network->routes_by_section, route->section);
}
- network_config_section_free(route->section);
+ config_section_free(route->section);
if (route->link)
set_remove(route->link->routes, route);
diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h
index e3e22a5985..3471008fee 100644
--- a/src/network/networkd-route.h
+++ b/src/network/networkd-route.h
@@ -19,7 +19,7 @@ typedef struct Route {
Link *link;
Manager *manager;
Network *network;
- NetworkConfigSection *section;
+ ConfigSection *section;
NetworkConfigSource source;
NetworkConfigState state;
union in_addr_union provider; /* DHCP server or router address */
@@ -74,7 +74,7 @@ extern const struct hash_ops route_hash_ops;
int route_new(Route **ret);
Route *route_free(Route *route);
-DEFINE_NETWORK_SECTION_FUNCTIONS(Route, route_free);
+DEFINE_SECTION_CLEANUP_FUNCTIONS(Route, route_free);
int route_dup(const Route *src, Route **ret);
int route_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg);
diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c
index a2e72a7d7c..1f3dfa53b0 100644
--- a/src/network/networkd-routing-policy-rule.c
+++ b/src/network/networkd-routing-policy-rule.c
@@ -54,14 +54,14 @@ RoutingPolicyRule *routing_policy_rule_free(RoutingPolicyRule *rule) {
if (rule->manager)
set_remove(rule->manager->rules, rule);
- network_config_section_free(rule->section);
+ config_section_free(rule->section);
free(rule->iif);
free(rule->oif);
return mfree(rule);
}
-DEFINE_NETWORK_SECTION_FUNCTIONS(RoutingPolicyRule, routing_policy_rule_free);
+DEFINE_SECTION_CLEANUP_FUNCTIONS(RoutingPolicyRule, routing_policy_rule_free);
static int routing_policy_rule_new(RoutingPolicyRule **ret) {
RoutingPolicyRule *rule;
@@ -86,7 +86,7 @@ static int routing_policy_rule_new(RoutingPolicyRule **ret) {
static int routing_policy_rule_new_static(Network *network, const char *filename, unsigned section_line, RoutingPolicyRule **ret) {
_cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
- _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+ _cleanup_(config_section_freep) ConfigSection *n = NULL;
int r;
assert(network);
@@ -94,7 +94,7 @@ static int routing_policy_rule_new_static(Network *network, const char *filename
assert(filename);
assert(section_line > 0);
- r = network_config_section_new(filename, section_line, &n);
+ r = config_section_new(filename, section_line, &n);
if (r < 0)
return r;
@@ -113,7 +113,7 @@ static int routing_policy_rule_new_static(Network *network, const char *filename
rule->source = NETWORK_CONFIG_SOURCE_STATIC;
rule->protocol = RTPROT_STATIC;
- r = hashmap_ensure_put(&network->rules_by_section, &network_config_hash_ops, rule->section, rule);
+ r = hashmap_ensure_put(&network->rules_by_section, &config_section_hash_ops, rule->section, rule);
if (r < 0)
return r;
diff --git a/src/network/networkd-routing-policy-rule.h b/src/network/networkd-routing-policy-rule.h
index f52943bd2e..1ab147caae 100644
--- a/src/network/networkd-routing-policy-rule.h
+++ b/src/network/networkd-routing-policy-rule.h
@@ -17,7 +17,7 @@ typedef struct Request Request;
typedef struct RoutingPolicyRule {
Manager *manager;
Network *network;
- NetworkConfigSection *section;
+ ConfigSection *section;
NetworkConfigSource source;
NetworkConfigState state;
diff --git a/src/network/networkd-sriov.c b/src/network/networkd-sriov.c
index 6da0f83521..cf138c7370 100644
--- a/src/network/networkd-sriov.c
+++ b/src/network/networkd-sriov.c
@@ -1,82 +1,10 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright © 2020 VMware, Inc. */
-#include "alloc-util.h"
#include "netlink-util.h"
+#include "networkd-link.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_MAX,
- .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_put(&network->sr_iov_by_section, &network_config_hash_ops, 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;
@@ -117,104 +45,16 @@ static int sr_iov_configure(Link *link, SRIOV *sr_iov) {
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");
+ return r;
- r = sd_netlink_message_close_container(req);
+ r = sr_iov_set_netlink_message(sr_iov, req);
if (r < 0)
- return log_link_error_errno(link, r, "Could not close IFLA_VFINFO_LIST container: %m");
+ return r;
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");
+ return r;
link_ref(link);
link->sr_iov_messages++;
@@ -239,7 +79,9 @@ int link_configure_sr_iov(Link *link) {
ORDERED_HASHMAP_FOREACH(sr_iov, link->network->sr_iov_by_section) {
r = sr_iov_configure(link, sr_iov);
if (r < 0)
- return r;
+ return log_link_warning_errno(link, r,
+ "Failed to configure SR-IOV virtual function %"PRIu32": %m",
+ sr_iov->vf);
}
if (link->sr_iov_messages == 0)
@@ -249,287 +91,3 @@ int link_configure_sr_iov(Link *link) {
return 0;
}
-
-static 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_MAX)
- 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;
-}
-
-void network_drop_invalid_sr_iov(Network *network) {
- SRIOV *sr_iov;
-
- assert(network);
-
- ORDERED_HASHMAP_FOREACH(sr_iov, network->sr_iov_by_section)
- if (sr_iov_section_verify(sr_iov) < 0)
- sr_iov_free(sr_iov);
-}
-
-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_MAX;
- else if (streq(lvalue, "VLANId"))
- sr_iov->vlan = 0;
- else if (streq(lvalue, "QualityOfService"))
- sr_iov->qos = 0;
- else
- assert_not_reached();
-
- TAKE_PTR(sr_iov);
- return 0;
- }
-
- r = safe_atou32(rvalue, &k);
- if (r < 0) {
- log_syntax(unit, LOG_WARNING, 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_WARNING, 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_WARNING, 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();
-
- 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_WARNING, 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_WARNING, 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();
-
- TAKE_PTR(sr_iov);
- return 0;
- }
-
- r = parse_boolean(rvalue);
- if (r < 0) {
- log_syntax(unit, LOG_WARNING, 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();
-
- 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 = parse_ether_addr(rvalue, &sr_iov->mac);
- if (r < 0) {
- log_syntax(unit, LOG_WARNING, filename, line, r,
- "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
index 950d1f9c59..4251fddf88 100644
--- a/src/network/networkd-sriov.h
+++ b/src/network/networkd-sriov.h
@@ -2,45 +2,8 @@
* Copyright © 2020 VMware, Inc. */
#pragma once
-#include <linux/if_link.h>
+#include "netif-sriov.h"
-#include "conf-parser.h"
-#include "ether-addr-util.h"
-#include "networkd-link.h"
-#include "networkd-network.h"
-#include "networkd-util.h"
+typedef struct Link Link;
-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 = -EINVAL,
-} 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 link_configure_sr_iov(Link *link);
-void network_drop_invalid_sr_iov(Network *network);
-
-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);
diff --git a/src/network/networkd-util.c b/src/network/networkd-util.c
index ac6f1680ca..1c0987bc33 100644
--- a/src/network/networkd-util.c
+++ b/src/network/networkd-util.c
@@ -243,50 +243,6 @@ int config_parse_mud_url(
return free_and_replace(*url, unescaped);
}
-static void network_config_hash_func(const NetworkConfigSection *c, struct siphash *state) {
- siphash24_compress_string(c->filename, state);
- siphash24_compress(&c->line, sizeof(c->line), state);
-}
-
-static int network_config_compare_func(const NetworkConfigSection *x, const NetworkConfigSection *y) {
- int r;
-
- r = strcmp(x->filename, y->filename);
- if (r != 0)
- return r;
-
- return CMP(x->line, y->line);
-}
-
-DEFINE_HASH_OPS(network_config_hash_ops, NetworkConfigSection, network_config_hash_func, network_config_compare_func);
-
-int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s) {
- NetworkConfigSection *cs;
-
- cs = malloc0(offsetof(NetworkConfigSection, filename) + strlen(filename) + 1);
- if (!cs)
- return -ENOMEM;
-
- strcpy(cs->filename, filename);
- cs->line = line;
-
- *s = TAKE_PTR(cs);
-
- return 0;
-}
-
-unsigned hashmap_find_free_section_line(Hashmap *hashmap) {
- NetworkConfigSection *cs;
- unsigned n = 0;
- void *entry;
-
- HASHMAP_FOREACH_KEY(entry, cs, hashmap)
- if (n < cs->line)
- n = cs->line;
-
- return n + 1;
-}
-
int log_link_message_full_errno(Link *link, sd_netlink_message *m, int level, int err, const char *msg) {
const char *err_msg = NULL;
diff --git a/src/network/networkd-util.h b/src/network/networkd-util.h
index d94243855e..0a627588aa 100644
--- a/src/network/networkd-util.h
+++ b/src/network/networkd-util.h
@@ -13,12 +13,6 @@
typedef struct Link Link;
-typedef struct NetworkConfigSection {
- unsigned line;
- bool invalid;
- char filename[];
-} NetworkConfigSection;
-
typedef enum NetworkConfigSource {
NETWORK_CONFIG_SOURCE_FOREIGN, /* configured by kernel */
NETWORK_CONFIG_SOURCE_STATIC,
@@ -141,37 +135,6 @@ AddressFamily dhcp_deprecated_address_family_from_string(const char *s) _pure_;
const char *dhcp_lease_server_type_to_string(sd_dhcp_lease_server_type_t t) _const_;
sd_dhcp_lease_server_type_t dhcp_lease_server_type_from_string(const char *s) _pure_;
-static inline NetworkConfigSection* network_config_section_free(NetworkConfigSection *cs) {
- return mfree(cs);
-}
-DEFINE_TRIVIAL_CLEANUP_FUNC(NetworkConfigSection*, network_config_section_free);
-
-int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s);
-extern const struct hash_ops network_config_hash_ops;
-unsigned hashmap_find_free_section_line(Hashmap *hashmap);
-
-static inline bool section_is_invalid(NetworkConfigSection *section) {
- /* If this returns false, then it does _not_ mean the section is valid. */
-
- if (!section)
- return false;
-
- return section->invalid;
-}
-
-#define DEFINE_NETWORK_SECTION_FUNCTIONS(type, free_func) \
- static inline type* free_func##_or_set_invalid(type *p) { \
- assert(p); \
- \
- if (p->section) \
- p->section->invalid = true; \
- else \
- free_func(p); \
- return NULL; \
- } \
- DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func); \
- DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func##_or_set_invalid);
-
int log_link_message_full_errno(Link *link, sd_netlink_message *m, int level, int err, const char *msg);
#define log_link_message_error_errno(link, m, err, msg) log_link_message_full_errno(link, m, LOG_ERR, err, msg)
#define log_link_message_warning_errno(link, m, err, msg) log_link_message_full_errno(link, m, LOG_WARNING, err, msg)
diff --git a/src/network/tc/qdisc.c b/src/network/tc/qdisc.c
index 995df2fc86..803c999855 100644
--- a/src/network/tc/qdisc.c
+++ b/src/network/tc/qdisc.c
@@ -77,7 +77,7 @@ static int qdisc_new(QDiscKind kind, QDisc **ret) {
}
int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, unsigned section_line, QDisc **ret) {
- _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+ _cleanup_(config_section_freep) ConfigSection *n = NULL;
_cleanup_(qdisc_freep) QDisc *qdisc = NULL;
TrafficControl *existing;
QDisc *q = NULL;
@@ -88,7 +88,7 @@ int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, uns
assert(filename);
assert(section_line > 0);
- r = network_config_section_new(filename, section_line, &n);
+ r = config_section_new(filename, section_line, &n);
if (r < 0)
return r;
@@ -126,7 +126,7 @@ int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, uns
qdisc->network = network;
qdisc->section = TAKE_PTR(n);
- r = ordered_hashmap_ensure_put(&network->tc_by_section, &network_config_hash_ops, qdisc->section, TC(qdisc));
+ r = ordered_hashmap_ensure_put(&network->tc_by_section, &config_section_hash_ops, qdisc->section, TC(qdisc));
if (r < 0)
return r;
@@ -141,7 +141,7 @@ QDisc* qdisc_free(QDisc *qdisc) {
if (qdisc->network && qdisc->section)
ordered_hashmap_remove(qdisc->network->tc_by_section, qdisc->section);
- network_config_section_free(qdisc->section);
+ config_section_free(qdisc->section);
free(qdisc->tca_kind);
return mfree(qdisc);
diff --git a/src/network/tc/qdisc.h b/src/network/tc/qdisc.h
index bf2df146a7..e37c4806e3 100644
--- a/src/network/tc/qdisc.h
+++ b/src/network/tc/qdisc.h
@@ -37,7 +37,7 @@ typedef enum QDiscKind {
typedef struct QDisc {
TrafficControl meta;
- NetworkConfigSection *section;
+ ConfigSection *section;
Network *network;
int family;
@@ -80,7 +80,7 @@ int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, uns
int qdisc_configure(Link *link, QDisc *qdisc);
int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact);
-DEFINE_NETWORK_SECTION_FUNCTIONS(QDisc, qdisc_free);
+DEFINE_SECTION_CLEANUP_FUNCTIONS(QDisc, qdisc_free);
DEFINE_TC_CAST(QDISC, QDisc);
diff --git a/src/network/tc/tclass.c b/src/network/tc/tclass.c
index 10bffd65c6..6a36ac1c1c 100644
--- a/src/network/tc/tclass.c
+++ b/src/network/tc/tclass.c
@@ -45,7 +45,7 @@ static int tclass_new(TClassKind kind, TClass **ret) {
}
int tclass_new_static(TClassKind kind, Network *network, const char *filename, unsigned section_line, TClass **ret) {
- _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+ _cleanup_(config_section_freep) ConfigSection *n = NULL;
_cleanup_(tclass_freep) TClass *tclass = NULL;
TrafficControl *existing;
int r;
@@ -55,7 +55,7 @@ int tclass_new_static(TClassKind kind, Network *network, const char *filename, u
assert(filename);
assert(section_line > 0);
- r = network_config_section_new(filename, section_line, &n);
+ r = config_section_new(filename, section_line, &n);
if (r < 0)
return r;
@@ -82,7 +82,7 @@ int tclass_new_static(TClassKind kind, Network *network, const char *filename, u
tclass->network = network;
tclass->section = TAKE_PTR(n);
- r = ordered_hashmap_ensure_put(&network->tc_by_section, &network_config_hash_ops, tclass->section, tclass);
+ r = ordered_hashmap_ensure_put(&network->tc_by_section, &config_section_hash_ops, tclass->section, tclass);
if (r < 0)
return r;
@@ -97,7 +97,7 @@ TClass* tclass_free(TClass *tclass) {
if (tclass->network && tclass->section)
ordered_hashmap_remove(tclass->network->tc_by_section, tclass->section);
- network_config_section_free(tclass->section);
+ config_section_free(tclass->section);
return mfree(tclass);
}
diff --git a/src/network/tc/tclass.h b/src/network/tc/tclass.h
index fc91789f30..5f8016c187 100644
--- a/src/network/tc/tclass.h
+++ b/src/network/tc/tclass.h
@@ -19,7 +19,7 @@ typedef enum TClassKind {
typedef struct TClass {
TrafficControl meta;
- NetworkConfigSection *section;
+ ConfigSection *section;
Network *network;
uint32_t classid;
@@ -59,7 +59,7 @@ int tclass_new_static(TClassKind kind, Network *network, const char *filename, u
int tclass_configure(Link *link, TClass *tclass);
int tclass_section_verify(TClass *tclass);
-DEFINE_NETWORK_SECTION_FUNCTIONS(TClass, tclass_free);
+DEFINE_SECTION_CLEANUP_FUNCTIONS(TClass, tclass_free);
DEFINE_TC_CAST(TCLASS, TClass);
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index 1e1967d7ea..64e67fb6f5 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -573,6 +573,50 @@ int config_parse_many(
return config_parse_many_files(conf_files, files, sections, lookup, table, flags, userdata, ret_stats_by_path);
}
+static void config_section_hash_func(const ConfigSection *c, struct siphash *state) {
+ siphash24_compress_string(c->filename, state);
+ siphash24_compress(&c->line, sizeof(c->line), state);
+}
+
+static int config_section_compare_func(const ConfigSection *x, const ConfigSection *y) {
+ int r;
+
+ r = strcmp(x->filename, y->filename);
+ if (r != 0)
+ return r;
+
+ return CMP(x->line, y->line);
+}
+
+DEFINE_HASH_OPS(config_section_hash_ops, ConfigSection, config_section_hash_func, config_section_compare_func);
+
+int config_section_new(const char *filename, unsigned line, ConfigSection **s) {
+ ConfigSection *cs;
+
+ cs = malloc0(offsetof(ConfigSection, filename) + strlen(filename) + 1);
+ if (!cs)
+ return -ENOMEM;
+
+ strcpy(cs->filename, filename);
+ cs->line = line;
+
+ *s = TAKE_PTR(cs);
+
+ return 0;
+}
+
+unsigned hashmap_find_free_section_line(Hashmap *hashmap) {
+ ConfigSection *cs;
+ unsigned n = 0;
+ void *entry;
+
+ HASHMAP_FOREACH_KEY(entry, cs, hashmap)
+ if (n < cs->line)
+ n = cs->line;
+
+ return n + 1;
+}
+
#define DEFINE_PARSER(type, vartype, conv_func) \
DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value")
diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h
index d686665532..1e03f93bce 100644
--- a/src/shared/conf-parser.h
+++ b/src/shared/conf-parser.h
@@ -114,6 +114,43 @@ int config_parse_many(
void *userdata,
Hashmap **ret_stats_by_path); /* possibly NULL */
+typedef struct ConfigSection {
+ unsigned line;
+ bool invalid;
+ char filename[];
+} ConfigSection;
+
+static inline ConfigSection* config_section_free(ConfigSection *cs) {
+ return mfree(cs);
+}
+DEFINE_TRIVIAL_CLEANUP_FUNC(ConfigSection*, config_section_free);
+
+int config_section_new(const char *filename, unsigned line, ConfigSection **s);
+extern const struct hash_ops config_section_hash_ops;
+unsigned hashmap_find_free_section_line(Hashmap *hashmap);
+
+static inline bool section_is_invalid(ConfigSection *section) {
+ /* If this returns false, then it does _not_ mean the section is valid. */
+
+ if (!section)
+ return false;
+
+ return section->invalid;
+}
+
+#define DEFINE_SECTION_CLEANUP_FUNCTIONS(type, free_func) \
+ static inline type* free_func##_or_set_invalid(type *p) { \
+ assert(p); \
+ \
+ if (p->section) \
+ p->section->invalid = true; \
+ else \
+ free_func(p); \
+ return NULL; \
+ } \
+ DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func); \
+ DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func##_or_set_invalid);
+
CONFIG_PARSER_PROTOTYPE(config_parse_int);
CONFIG_PARSER_PROTOTYPE(config_parse_unsigned);
CONFIG_PARSER_PROTOTYPE(config_parse_long);
diff --git a/src/shared/meson.build b/src/shared/meson.build
index f58d623f4a..66715e00c3 100644
--- a/src/shared/meson.build
+++ b/src/shared/meson.build
@@ -224,6 +224,8 @@ shared_sources = files('''
net-condition.h
netif-naming-scheme.c
netif-naming-scheme.h
+ netif-sriov.c
+ netif-sriov.h
netif-util.c
netif-util.h
nscd-flush.h
diff --git a/src/shared/netif-sriov.c b/src/shared/netif-sriov.c
new file mode 100644
index 0000000000..720aa65f4c
--- /dev/null
+++ b/src/shared/netif-sriov.c
@@ -0,0 +1,631 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "alloc-util.h"
+#include "device-util.h"
+#include "netlink-util.h"
+#include "netif-sriov.h"
+#include "parse-util.h"
+#include "set.h"
+#include "stdio-util.h"
+#include "string-util.h"
+
+static int sr_iov_new(SRIOV **ret) {
+ SRIOV *sr_iov;
+
+ assert(ret);
+
+ sr_iov = new(SRIOV, 1);
+ if (!sr_iov)
+ return -ENOMEM;
+
+ *sr_iov = (SRIOV) {
+ .vf = UINT32_MAX,
+ .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(OrderedHashmap **sr_iov_by_section, const char *filename, unsigned section_line, SRIOV **ret) {
+ _cleanup_(config_section_freep) ConfigSection *n = NULL;
+ _cleanup_(sr_iov_freep) SRIOV *sr_iov = NULL;
+ SRIOV *existing = NULL;
+ int r;
+
+ assert(sr_iov_by_section);
+ assert(filename);
+ assert(section_line > 0);
+ assert(ret);
+
+ r = config_section_new(filename, section_line, &n);
+ if (r < 0)
+ return r;
+
+ existing = ordered_hashmap_get(*sr_iov_by_section, n);
+ if (existing) {
+ *ret = existing;
+ return 0;
+ }
+
+ r = sr_iov_new(&sr_iov);
+ if (r < 0)
+ return r;
+
+ r = ordered_hashmap_ensure_put(sr_iov_by_section, &config_section_hash_ops, n, sr_iov);
+ if (r < 0)
+ return r;
+
+ sr_iov->section = TAKE_PTR(n);
+ sr_iov->sr_iov_by_section = *sr_iov_by_section;
+
+ *ret = TAKE_PTR(sr_iov);
+ return 0;
+}
+
+SRIOV *sr_iov_free(SRIOV *sr_iov) {
+ if (!sr_iov)
+ return NULL;
+
+ if (sr_iov->sr_iov_by_section && sr_iov->section)
+ ordered_hashmap_remove(sr_iov->sr_iov_by_section, sr_iov->section);
+
+ config_section_free(sr_iov->section);
+
+ return mfree(sr_iov);
+}
+
+int sr_iov_set_netlink_message(SRIOV *sr_iov, sd_netlink_message *req) {
+ int r;
+
+ assert(sr_iov);
+ assert(req);
+
+ r = sd_netlink_message_open_container(req, IFLA_VFINFO_LIST);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_open_container(req, IFLA_VF_INFO);
+ if (r < 0)
+ return r;
+
+ 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 r;
+ }
+
+ 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 r;
+ }
+
+ 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 r;
+ }
+
+ 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 r;
+ }
+
+ 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 r;
+ }
+
+ 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 r;
+
+ r = sd_netlink_message_append_data(req, IFLA_VF_VLAN_INFO, &ivvi, sizeof(struct ifla_vf_vlan_info));
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_close_container(req);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_netlink_message_close_container(req);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_close_container(req);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+int sr_iov_get_num_vfs(sd_device *device, uint32_t *ret) {
+ const char *str;
+ uint32_t n;
+ int r;
+
+ assert(device);
+ assert(ret);
+
+ r = sd_device_get_sysattr_value(device, "device/sriov_numvfs", &str);
+ if (r < 0)
+ return r;
+
+ r = safe_atou32(str, &n);
+ if (r < 0)
+ return r;
+
+ *ret = n;
+ return 0;
+}
+
+int sr_iov_set_num_vfs(sd_device *device, uint32_t num_vfs, OrderedHashmap *sr_iov_by_section) {
+ char val[DECIMAL_STR_MAX(uint32_t)];
+ const char *str;
+ int r;
+
+ assert(device);
+
+ if (num_vfs == UINT32_MAX) {
+ uint32_t current_num_vfs;
+ SRIOV *sr_iov;
+
+ /* If the number of virtual functions is not specified, then use the maximum number of VF + 1. */
+
+ num_vfs = 0;
+ ORDERED_HASHMAP_FOREACH(sr_iov, sr_iov_by_section)
+ num_vfs = MAX(num_vfs, sr_iov->vf + 1);
+
+ if (num_vfs == 0) /* No VF is configured. */
+ return 0;
+
+ r = sr_iov_get_num_vfs(device, &current_num_vfs);
+ if (r < 0)
+ return log_device_debug_errno(device, r, "Failed to get the current number of SR-IOV virtual functions: %m");
+
+ /* Enough VFs already exist. */
+ if (num_vfs <= current_num_vfs)
+ return 0;
+
+ } else if (num_vfs == 0) {
+ r = sd_device_set_sysattr_value(device, "device/sriov_numvfs", "0");
+ if (r < 0)
+ log_device_debug_errno(device, r, "Failed to write device/sriov_numvfs sysfs attribute, ignoring: %m");
+
+ /* Gracefully handle the error in disabling VFs when the interface does not support SR-IOV. */
+ return r == -ENOENT ? 0 : r;
+ }
+
+ /* So, the interface does not have enough VFs. Before increasing the number of VFs, check the
+ * maximum allowed number of VFs from the sriov_totalvfs sysattr. Note that the sysattr
+ * currently exists only for PCI drivers. Hence, ignore -ENOENT.
+ * TODO: netdevsim provides the information in debugfs. */
+ r = sd_device_get_sysattr_value(device, "device/sriov_totalvfs", &str);
+ if (r >= 0) {
+ uint32_t max_num_vfs;
+
+ r = safe_atou32(str, &max_num_vfs);
+ if (r < 0)
+ return log_device_debug_errno(device, r, "Failed to parse device/sriov_totalvfs sysfs attribute '%s': %m", str);
+
+ if (num_vfs > max_num_vfs)
+ return log_device_debug_errno(device, SYNTHETIC_ERRNO(ERANGE),
+ "Specified number of virtual functions is out of range. "
+ "The maximum allowed value is %"PRIu32".",
+ max_num_vfs);
+
+ } else if (r != -ENOENT) /* Currently, only PCI driver has the attribute. */
+ return log_device_debug_errno(device, r, "Failed to read device/sriov_totalvfs sysfs attribute: %m");
+
+ xsprintf(val, "%"PRIu32, num_vfs);
+ r = sd_device_set_sysattr_value(device, "device/sriov_numvfs", val);
+ if (r == -EBUSY) {
+ /* Some devices e.g. netdevsim refuse to set sriov_numvfs if it has non-zero value. */
+ r = sd_device_set_sysattr_value(device, "device/sriov_numvfs", "0");
+ if (r >= 0)
+ r = sd_device_set_sysattr_value(device, "device/sriov_numvfs", val);
+ }
+ if (r < 0)
+ return log_device_debug_errno(device, r, "Failed to write device/sriov_numvfs sysfs attribute: %m");
+
+ log_device_debug(device, "device/sriov_numvfs sysfs attribute set to '%s'.", val);
+ return 0;
+}
+
+static int sr_iov_section_verify(uint32_t num_vfs, SRIOV *sr_iov) {
+ assert(sr_iov);
+
+ if (section_is_invalid(sr_iov->section))
+ return -EINVAL;
+
+ if (sr_iov->vf == UINT32_MAX)
+ return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s: [SR-IOV] section without VirtualFunction= field configured. "
+ "Ignoring [SR-IOV] section from line %u.",
+ sr_iov->section->filename, sr_iov->section->line);
+
+ if (sr_iov->vf >= num_vfs)
+ return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s: VirtualFunction= must be smaller than the value specified in SR-IOVVirtualFunctions=. "
+ "Ignoring [SR-IOV] section from line %u.",
+ sr_iov->section->filename, sr_iov->section->line);
+
+ return 0;
+}
+
+int sr_iov_drop_invalid_sections(uint32_t num_vfs, OrderedHashmap *sr_iov_by_section) {
+ _cleanup_hashmap_free_ Hashmap *hashmap = NULL;
+ SRIOV *sr_iov;
+ int r;
+
+ ORDERED_HASHMAP_FOREACH(sr_iov, sr_iov_by_section) {
+ SRIOV *dup;
+
+ if (sr_iov_section_verify(num_vfs, sr_iov) < 0) {
+ sr_iov_free(sr_iov);
+ continue;
+ }
+
+ assert(sr_iov->vf < INT_MAX);
+
+ dup = hashmap_remove(hashmap, UINT32_TO_PTR(sr_iov->vf + 1));
+ if (dup) {
+ log_warning("%s: Conflicting [SR-IOV] section is specified at line %u and %u, "
+ "dropping the [SR-IOV] section specified at line %u.",
+ dup->section->filename, sr_iov->section->line,
+ dup->section->line, dup->section->line);
+ sr_iov_free(dup);
+ }
+
+ r = hashmap_ensure_put(&hashmap, NULL, UINT32_TO_PTR(sr_iov->vf + 1), sr_iov);
+ if (r < 0)
+ return log_oom();
+ assert(r > 0);
+ }
+
+ 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;
+ OrderedHashmap **sr_iov_by_section = data;
+ uint32_t k;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = sr_iov_new_static(sr_iov_by_section, filename, section_line, &sr_iov);
+ if (r < 0)
+ return r;
+
+ if (isempty(rvalue)) {
+ if (streq(lvalue, "VirtualFunction"))
+ sr_iov->vf = UINT32_MAX;
+ else if (streq(lvalue, "VLANId"))
+ sr_iov->vlan = 0;
+ else if (streq(lvalue, "QualityOfService"))
+ sr_iov->qos = 0;
+ else
+ assert_not_reached();
+
+ TAKE_PTR(sr_iov);
+ return 0;
+ }
+
+ r = safe_atou32(rvalue, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, 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_WARNING, 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_WARNING, 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();
+
+ 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;
+ OrderedHashmap **sr_iov_by_section = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = sr_iov_new_static(sr_iov_by_section, 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_WARNING, 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;
+ OrderedHashmap **sr_iov_by_section = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = sr_iov_new_static(sr_iov_by_section, 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_WARNING, 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;
+ OrderedHashmap **sr_iov_by_section = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = sr_iov_new_static(sr_iov_by_section, 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();
+
+ TAKE_PTR(sr_iov);
+ return 0;
+ }
+
+ r = parse_boolean(rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, 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();
+
+ 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;
+ OrderedHashmap **sr_iov_by_section = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = sr_iov_new_static(sr_iov_by_section, 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 = parse_ether_addr(rvalue, &sr_iov->mac);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to parse SR-IOV '%s=', ignoring assignment: %s", lvalue, rvalue);
+ return 0;
+ }
+
+ TAKE_PTR(sr_iov);
+ return 0;
+}
+
+int config_parse_sr_iov_num_vfs(
+ 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) {
+
+ uint32_t n, *num_vfs = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ *num_vfs = UINT32_MAX;
+ return 0;
+ }
+
+ r = safe_atou32(rvalue, &n);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
+ return 0;
+ }
+
+ if (n > INT_MAX) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "The number of SR-IOV virtual functions is too large. It must be equal to "
+ "or smaller than 2147483647. Ignoring assignment: %"PRIu32, n);
+ return 0;
+ }
+
+ *num_vfs = n;
+ return 0;
+}
diff --git a/src/shared/netif-sriov.h b/src/shared/netif-sriov.h
new file mode 100644
index 0000000000..4c85f101c7
--- /dev/null
+++ b/src/shared/netif-sriov.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <linux/if_link.h>
+
+#include "sd-device.h"
+
+#include "conf-parser.h"
+#include "ether-addr-util.h"
+#include "hashmap.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 = -EINVAL,
+} SRIOVLinkState;
+
+typedef struct SRIOV {
+ ConfigSection *section;
+ OrderedHashmap *sr_iov_by_section;
+
+ 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_set_netlink_message(SRIOV *sr_iov, sd_netlink_message *req);
+int sr_iov_get_num_vfs(sd_device *device, uint32_t *ret);
+int sr_iov_set_num_vfs(sd_device *device, uint32_t num_vfs, OrderedHashmap *sr_iov_by_section);
+int sr_iov_drop_invalid_sections(uint32_t num_vfs, OrderedHashmap *sr_iov_by_section);
+
+DEFINE_SECTION_CLEANUP_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);
+CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_num_vfs);
diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf
index ac7825b00f..7dde4ed59f 100644
--- a/src/udev/net/link-config-gperf.gperf
+++ b/src/udev/net/link-config-gperf.gperf
@@ -8,6 +8,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
#include "ethtool-util.h"
#include "link-config.h"
#include "net-condition.h"
+#include "netif-sriov.h"
#include "socket-util.h"
%}
struct ConfigPerfItem;
@@ -101,3 +102,13 @@ Link.RxMaxCoalescedHighFrames, config_parse_coalesce_u32,
Link.TxCoalesceHighSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.tx_coalesce_usecs_high)
Link.TxMaxCoalescedHighFrames, config_parse_coalesce_u32, 0, offsetof(LinkConfig, coalesce.tx_max_coalesced_frames_high)
Link.CoalescePacketRateSampleIntervalSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.rate_sample_interval)
+Link.SR-IOVVirtualFunctions, config_parse_sr_iov_num_vfs, 0, offsetof(LinkConfig, sr_iov_num_vfs)
+SR-IOV.VirtualFunction, config_parse_sr_iov_uint32, 0, offsetof(LinkConfig, sr_iov_by_section)
+SR-IOV.VLANId, config_parse_sr_iov_uint32, 0, offsetof(LinkConfig, sr_iov_by_section)
+SR-IOV.QualityOfService, config_parse_sr_iov_uint32, 0, offsetof(LinkConfig, sr_iov_by_section)
+SR-IOV.VLANProtocol, config_parse_sr_iov_vlan_proto, 0, offsetof(LinkConfig, sr_iov_by_section)
+SR-IOV.MACSpoofCheck, config_parse_sr_iov_boolean, 0, offsetof(LinkConfig, sr_iov_by_section)
+SR-IOV.QueryReceiveSideScaling, config_parse_sr_iov_boolean, 0, offsetof(LinkConfig, sr_iov_by_section)
+SR-IOV.Trust, config_parse_sr_iov_boolean, 0, offsetof(LinkConfig, sr_iov_by_section)
+SR-IOV.LinkState, config_parse_sr_iov_link_state, 0, offsetof(LinkConfig, sr_iov_by_section)
+SR-IOV.MACAddress, config_parse_sr_iov_mac, 0, offsetof(LinkConfig, sr_iov_by_section)
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index 05f0f2e0a6..7e2da6088c 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -22,6 +22,7 @@
#include "log-link.h"
#include "memory-util.h"
#include "net-condition.h"
+#include "netif-sriov.h"
#include "netif-util.h"
#include "netlink-util.h"
#include "parse-util.h"
@@ -60,6 +61,8 @@ static LinkConfig* link_config_free(LinkConfig *config) {
free(config->wol_password_file);
erase_and_free(config->wol_password);
+ ordered_hashmap_free_with_destructor(config->sr_iov_by_section, sr_iov_free);
+
return mfree(config);
}
@@ -247,6 +250,7 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) {
.txqueuelen = UINT32_MAX,
.coalesce.use_adaptive_rx_coalesce = -1,
.coalesce.use_adaptive_tx_coalesce = -1,
+ .sr_iov_num_vfs = UINT32_MAX,
};
for (i = 0; i < ELEMENTSOF(config->features); i++)
@@ -257,7 +261,9 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) {
STRV_MAKE_CONST(filename),
(const char* const*) CONF_PATHS_STRV("systemd/network"),
dropin_dirname,
- "Match\0Link\0",
+ "Match\0"
+ "Link\0"
+ "SR-IOV\0",
config_item_perf_lookup, link_config_gperf_lookup,
CONFIG_PARSE_WARN, config, NULL);
if (r < 0)
@@ -285,6 +291,10 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) {
if (r < 0)
return r;
+ r = sr_iov_drop_invalid_sections(config->sr_iov_num_vfs, config->sr_iov_by_section);
+ if (r < 0)
+ return r;
+
log_debug("Parsed configuration file %s", filename);
LIST_PREPEND(configs, ctx->configs, TAKE_PTR(config));
@@ -830,6 +840,77 @@ static int link_apply_alternative_names(Link *link, sd_netlink **rtnl) {
return 0;
}
+static int sr_iov_configure(Link *link, sd_netlink **rtnl, SRIOV *sr_iov) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
+ int r;
+
+ assert(link);
+ assert(rtnl);
+ assert(link->ifindex > 0);
+
+ if (!*rtnl) {
+ r = sd_netlink_open(rtnl);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_rtnl_message_new_link(*rtnl, &req, RTM_SETLINK, link->ifindex);
+ if (r < 0)
+ return r;
+
+ r = sr_iov_set_netlink_message(sr_iov, req);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_call(*rtnl, req, 0, NULL);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static int link_apply_sr_iov_config(Link *link, sd_netlink **rtnl) {
+ SRIOV *sr_iov;
+ uint32_t n;
+ int r;
+
+ assert(link);
+ assert(link->config);
+ assert(link->device);
+
+ r = sr_iov_set_num_vfs(link->device, link->config->sr_iov_num_vfs, link->config->sr_iov_by_section);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Failed to set the number of SR-IOV virtual functions, ignoring: %m");
+
+ if (ordered_hashmap_isempty(link->config->sr_iov_by_section))
+ return 0;
+
+ r = sr_iov_get_num_vfs(link->device, &n);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to get the number of SR-IOV virtual functions, ignoring [SR-IOV] sections: %m");
+ return 0;
+ }
+ if (n == 0) {
+ log_link_warning(link, "No SR-IOV virtual function exists, ignoring [SR-IOV] sections: %m");
+ return 0;
+ }
+
+ ORDERED_HASHMAP_FOREACH(sr_iov, link->config->sr_iov_by_section) {
+ if (sr_iov->vf >= n) {
+ log_link_warning(link, "SR-IOV virtual function %"PRIu32" does not exist, ignoring.", sr_iov->vf);
+ continue;
+ }
+
+ r = sr_iov_configure(link, rtnl, sr_iov);
+ if (r < 0)
+ log_link_warning_errno(link, r,
+ "Failed to configure SR-IOV virtual function %"PRIu32", ignoring: %m",
+ sr_iov->vf);
+ }
+
+ return 0;
+}
+
int link_apply_config(LinkConfigContext *ctx, sd_netlink **rtnl, Link *link) {
int r;
@@ -861,6 +942,10 @@ int link_apply_config(LinkConfigContext *ctx, sd_netlink **rtnl, Link *link) {
if (r < 0)
return r;
+ r = link_apply_sr_iov_config(link, rtnl);
+ if (r < 0)
+ return r;
+
return 0;
}
diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h
index 3b2cd69620..0d1d117f2e 100644
--- a/src/udev/net/link-config.h
+++ b/src/udev/net/link-config.h
@@ -7,6 +7,7 @@
#include "condition.h"
#include "conf-parser.h"
#include "ethtool-util.h"
+#include "hashmap.h"
#include "list.h"
#include "net-condition.h"
#include "netif-naming-scheme.h"
@@ -76,6 +77,9 @@ struct LinkConfig {
int autoneg_flow_control;
netdev_coalesce_param coalesce;
+ uint32_t sr_iov_num_vfs;
+ OrderedHashmap *sr_iov_by_section;
+
LIST_FIELDS(LinkConfig, configs);
};
diff --git a/test/fuzz/fuzz-link-parser/directives.link b/test/fuzz/fuzz-link-parser/directives.link
index 7586e35b49..a5773826c5 100644
--- a/test/fuzz/fuzz-link-parser/directives.link
+++ b/test/fuzz/fuzz-link-parser/directives.link
@@ -80,3 +80,14 @@ RxMaxCoalescedHighFrames=
TxCoalesceHighSec=
TxMaxCoalescedHighFrames=
CoalescePacketRateSampleIntervalSec=
+SR-IOVVirtualFunctions=
+[SR-IOV]
+VirtualFunction=
+MACSpoofCheck=
+VLANId=
+VLANProtocol=
+QualityOfService=
+QueryReceiveSideScaling=
+Trust=
+LinkState=
+MACAddress=
diff --git a/test/test-network/conf/25-sriov-udev.network b/test/test-network/conf/25-sriov-udev.network
new file mode 100644
index 0000000000..e9141310b7
--- /dev/null
+++ b/test/test-network/conf/25-sriov-udev.network
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Name=eni99np1
+
+[Network]
+Address=192.168.100.100/24
+IPv6AcceptRA=no
diff --git a/test/test-network/conf/25-sriov.link b/test/test-network/conf/25-sriov.link
new file mode 100644
index 0000000000..cc19561306
--- /dev/null
+++ b/test/test-network/conf/25-sriov.link
@@ -0,0 +1,40 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Match]
+Driver=netdevsim
+
+[Link]
+NamePolicy=keep kernel database onboard slot path
+AlternativeNamesPolicy=database onboard slot path mac
+MACAddressPolicy=persistent
+
+[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
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index 2207f36245..0233c4dd1f 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -176,7 +176,7 @@ def expectedFailureIfAlternativeNameIsNotAvailable():
call('ip link add dummy98 type dummy', stderr=subprocess.DEVNULL)
rc = call('ip link prop add dev dummy98 altname hogehogehogehogehoge', stderr=subprocess.DEVNULL)
if rc == 0:
- rc = call('ip link show dev hogehogehogehogehoge', stderr=subprocess.DEVNULL)
+ rc = call('ip link show dev hogehogehogehogehoge', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
if rc == 0:
supported = True
@@ -2065,7 +2065,6 @@ 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',
@@ -3450,32 +3449,6 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertRegex(output, 'qdisc fq_pie 3a: root')
self.assertRegex(output, 'limit 200000p')
- @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)
-
def test_wait_online_ipv4(self):
copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-with-ipv6-prefix.network', 'dhcp-client-ipv4-ipv6ra-prefix-client-with-delay.network')
start_networkd()
@@ -3999,6 +3972,133 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities):
print(output)
self.assertIn('from all to 8.8.8.8 lookup 100', output)
+class NetworkdSRIOVTests(unittest.TestCase, Utilities):
+ units = [
+ '25-sriov-udev.network',
+ '25-sriov.link',
+ '25-sriov.network',
+ ]
+
+ def setUp(self):
+ stop_networkd(show_logs=False)
+ call('rmmod netdevsim', stderr=subprocess.DEVNULL)
+
+ def tearDown(self):
+ remove_unit_from_networkd_path(self.units)
+ stop_networkd(show_logs=True)
+ call('rmmod netdevsim', stderr=subprocess.DEVNULL)
+
+ @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
+ def test_sriov(self):
+ 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'
+ )
+
+ @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable()
+ def test_sriov_udev(self):
+ call('modprobe netdevsim', stderr=subprocess.DEVNULL)
+
+ copy_unit_to_networkd_unit_path('25-sriov.link', '25-sriov-udev.network')
+ call('udevadm control --reload')
+
+ with open('/sys/bus/netdevsim/new_device', mode='w') as f:
+ f.write('99 1')
+
+ 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'
+ )
+ self.assertNotIn('vf 3', output)
+ self.assertNotIn('vf 4', output)
+
+ with open(os.path.join(network_unit_file_path, '25-sriov.link'), mode='a') as f:
+ f.write('[Link]\nSR-IOVVirtualFunctions=4\n')
+
+ call('udevadm control --reload')
+ call('udevadm trigger --action add --settle /sys/devices/netdevsim99/net/eni99np1')
+
+ 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\n *'
+ 'vf 3'
+ )
+ self.assertNotIn('vf 4', output)
+
+ with open(os.path.join(network_unit_file_path, '25-sriov.link'), mode='a') as f:
+ f.write('[Link]\nSR-IOVVirtualFunctions=\n')
+
+ call('udevadm control --reload')
+ call('udevadm trigger --action add --settle /sys/devices/netdevsim99/net/eni99np1')
+
+ 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\n *'
+ 'vf 3'
+ )
+ self.assertNotIn('vf 4', output)
+
+ with open(os.path.join(network_unit_file_path, '25-sriov.link'), mode='a') as f:
+ f.write('[Link]\nSR-IOVVirtualFunctions=2\n')
+
+ call('udevadm control --reload')
+ call('udevadm trigger --action add --settle /sys/devices/netdevsim99/net/eni99np1')
+
+ 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'
+ )
+ self.assertNotIn('vf 2', output)
+ self.assertNotIn('vf 3', output)
+ self.assertNotIn('vf 4', output)
+
+ with open(os.path.join(network_unit_file_path, '25-sriov.link'), mode='a') as f:
+ f.write('[Link]\nSR-IOVVirtualFunctions=\n')
+
+ call('udevadm control --reload')
+ call('udevadm trigger --action add --settle /sys/devices/netdevsim99/net/eni99np1')
+
+ 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'
+ )
+ self.assertNotIn('vf 3', output)
+ self.assertNotIn('vf 4', output)
+
class NetworkdLLDPTests(unittest.TestCase, Utilities):
links = ['veth99']