1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-19 22:50:17 +03:00

Merge pull request #21865 from yuwata/network-sr-iov

udev/net: support configuring SR-IOV virtual functions through .link file
This commit is contained in:
Luca Boccassi 2022-01-19 22:38:00 +00:00 committed by GitHub
commit de843f8582
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 1281 additions and 806 deletions

View File

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

View File

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

View File

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

View File

@ -34,7 +34,7 @@ typedef struct L2tpTunnel L2tpTunnel;
typedef struct L2tpSession {
L2tpTunnel *tunnel;
NetworkConfigSection *section;
ConfigSection *section;
char *name;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -13,7 +13,7 @@ typedef struct Request Request;
typedef struct AddressLabel {
Network *network;
NetworkConfigSection *section;
ConfigSection *section;
uint32_t label;
struct in6_addr prefix;

View File

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

View File

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

View File

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

View File

@ -27,7 +27,7 @@ typedef enum NeighborCacheEntryFlags {
typedef struct BridgeFDB {
Network *network;
NetworkConfigSection *section;
ConfigSection *section;
uint32_t vni;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -18,7 +18,7 @@ typedef struct Request Request;
typedef struct Neighbor {
Network *network;
Link *link;
NetworkConfigSection *section;
ConfigSection *section;
NetworkConfigSource source;
NetworkConfigState state;

View File

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

View File

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

View File

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

View File

@ -22,7 +22,7 @@ typedef struct NextHop {
Network *network;
Manager *manager;
Link *link;
NetworkConfigSection *section;
ConfigSection *section;
NetworkConfigSource source;
NetworkConfigState state;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -17,7 +17,7 @@ typedef struct Request Request;
typedef struct RoutingPolicyRule {
Manager *manager;
Network *network;
NetworkConfigSection *section;
ConfigSection *section;
NetworkConfigSource source;
NetworkConfigState state;

View File

@ -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");
return r;
r = sd_netlink_message_open_container(req, IFLA_VFINFO_LIST);
r = sr_iov_set_netlink_message(sr_iov, req);
if (r < 0)
return log_link_error_errno(link, r, "Could not open IFLA_VFINFO_LIST container: %m");
r = sd_netlink_message_open_container(req, IFLA_VF_INFO);
if (r < 0)
return log_link_error_errno(link, r, "Could not open IFLA_VF_INFO container: %m");
if (!ether_addr_is_null(&sr_iov->mac)) {
struct ifla_vf_mac ivm = {
.vf = sr_iov->vf,
};
memcpy(ivm.mac, &sr_iov->mac, ETH_ALEN);
r = sd_netlink_message_append_data(req, IFLA_VF_MAC, &ivm, sizeof(struct ifla_vf_mac));
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_VF_MAC: %m");
}
if (sr_iov->vf_spoof_check_setting >= 0) {
struct ifla_vf_spoofchk ivs = {
.vf = sr_iov->vf,
.setting = sr_iov->vf_spoof_check_setting,
};
r = sd_netlink_message_append_data(req, IFLA_VF_SPOOFCHK, &ivs, sizeof(struct ifla_vf_spoofchk));
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_VF_SPOOFCHK: %m");
}
if (sr_iov->query_rss >= 0) {
struct ifla_vf_rss_query_en ivs = {
.vf = sr_iov->vf,
.setting = sr_iov->query_rss,
};
r = sd_netlink_message_append_data(req, IFLA_VF_RSS_QUERY_EN, &ivs, sizeof(struct ifla_vf_rss_query_en));
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_VF_RSS_QUERY_EN: %m");
}
if (sr_iov->trust >= 0) {
struct ifla_vf_trust ivt = {
.vf = sr_iov->vf,
.setting = sr_iov->trust,
};
r = sd_netlink_message_append_data(req, IFLA_VF_TRUST, &ivt, sizeof(struct ifla_vf_trust));
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_VF_TRUST: %m");
}
if (sr_iov->link_state >= 0) {
struct ifla_vf_link_state ivl = {
.vf = sr_iov->vf,
.link_state = sr_iov->link_state,
};
r = sd_netlink_message_append_data(req, IFLA_VF_LINK_STATE, &ivl, sizeof(struct ifla_vf_link_state));
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_VF_LINK_STATE: %m");
}
if (sr_iov->vlan > 0) {
/* Because of padding, first the buffer must be initialized with 0. */
struct ifla_vf_vlan_info ivvi = {};
ivvi.vf = sr_iov->vf;
ivvi.vlan = sr_iov->vlan;
ivvi.qos = sr_iov->qos;
ivvi.vlan_proto = htobe16(sr_iov->vlan_proto);
r = sd_netlink_message_open_container(req, IFLA_VF_VLAN_LIST);
if (r < 0)
return log_link_error_errno(link, r, "Could not open IFLA_VF_VLAN_LIST container: %m");
r = sd_netlink_message_append_data(req, IFLA_VF_VLAN_INFO, &ivvi, sizeof(struct ifla_vf_vlan_info));
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_VF_VLAN_INFO: %m");
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_link_error_errno(link, r, "Could not close IFLA_VF_VLAN_LIST container: %m");
}
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_link_error_errno(link, r, "Could not close IFLA_VF_INFO container: %m");
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_link_error_errno(link, r, "Could not close IFLA_VFINFO_LIST container: %m");
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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

631
src/shared/netif-sriov.c Normal file
View File

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

48
src/shared/netif-sriov.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

@ -80,3 +80,14 @@ RxMaxCoalescedHighFrames=
TxCoalesceHighSec=
TxMaxCoalescedHighFrames=
CoalescePacketRateSampleIntervalSec=
SR-IOVVirtualFunctions=
[SR-IOV]
VirtualFunction=
MACSpoofCheck=
VLANId=
VLANProtocol=
QualityOfService=
QueryReceiveSideScaling=
Trust=
LinkState=
MACAddress=

View File

@ -0,0 +1,7 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Name=eni99np1
[Network]
Address=192.168.100.100/24
IPv6AcceptRA=no

View File

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

View File

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