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:
commit
de843f8582
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
||||
|
@ -34,7 +34,7 @@ typedef struct L2tpTunnel L2tpTunnel;
|
||||
|
||||
typedef struct L2tpSession {
|
||||
L2tpTunnel *tunnel;
|
||||
NetworkConfigSection *section;
|
||||
ConfigSection *section;
|
||||
|
||||
char *name;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
|
||||
|
@ -13,7 +13,7 @@ typedef struct Request Request;
|
||||
|
||||
typedef struct AddressLabel {
|
||||
Network *network;
|
||||
NetworkConfigSection *section;
|
||||
ConfigSection *section;
|
||||
|
||||
uint32_t label;
|
||||
struct in6_addr prefix;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -27,7 +27,7 @@ typedef enum NeighborCacheEntryFlags {
|
||||
|
||||
typedef struct BridgeFDB {
|
||||
Network *network;
|
||||
NetworkConfigSection *section;
|
||||
ConfigSection *section;
|
||||
|
||||
uint32_t vni;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -18,7 +18,7 @@ typedef struct Request Request;
|
||||
typedef struct Neighbor {
|
||||
Network *network;
|
||||
Link *link;
|
||||
NetworkConfigSection *section;
|
||||
ConfigSection *section;
|
||||
NetworkConfigSource source;
|
||||
NetworkConfigState state;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -22,7 +22,7 @@ typedef struct NextHop {
|
||||
Network *network;
|
||||
Manager *manager;
|
||||
Link *link;
|
||||
NetworkConfigSection *section;
|
||||
ConfigSection *section;
|
||||
NetworkConfigSource source;
|
||||
NetworkConfigState state;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -17,7 +17,7 @@ typedef struct Request Request;
|
||||
typedef struct RoutingPolicyRule {
|
||||
Manager *manager;
|
||||
Network *network;
|
||||
NetworkConfigSection *section;
|
||||
ConfigSection *section;
|
||||
NetworkConfigSource source;
|
||||
NetworkConfigState state;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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")
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
631
src/shared/netif-sriov.c
Normal 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, ¤t_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
48
src/shared/netif-sriov.h
Normal 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);
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -80,3 +80,14 @@ RxMaxCoalescedHighFrames=
|
||||
TxCoalesceHighSec=
|
||||
TxMaxCoalescedHighFrames=
|
||||
CoalescePacketRateSampleIntervalSec=
|
||||
SR-IOVVirtualFunctions=
|
||||
[SR-IOV]
|
||||
VirtualFunction=
|
||||
MACSpoofCheck=
|
||||
VLANId=
|
||||
VLANProtocol=
|
||||
QualityOfService=
|
||||
QueryReceiveSideScaling=
|
||||
Trust=
|
||||
LinkState=
|
||||
MACAddress=
|
||||
|
7
test/test-network/conf/25-sriov-udev.network
Normal file
7
test/test-network/conf/25-sriov-udev.network
Normal 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
|
40
test/test-network/conf/25-sriov.link
Normal file
40
test/test-network/conf/25-sriov.link
Normal 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
|
@ -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']
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user