diff options
author | Luca Boccassi <luca.boccassi@microsoft.com> | 2022-01-19 23:38:00 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-19 23:38:00 +0100 |
commit | de843f8582c15da075a3f5aa7e2af0b9cccad034 (patch) | |
tree | f445079d4fc364df0ece0ee9ee07fe40c25325c1 | |
parent | boot: Use -ffile-prefix-map when present (diff) | |
parent | test-network: add testcases for configuring SR-IOV by .link file (diff) | |
download | systemd-de843f8582c15da075a3f5aa7e2af0b9cccad034.tar.xz systemd-de843f8582c15da075a3f5aa7e2af0b9cccad034.zip |
Merge pull request #21865 from yuwata/network-sr-iov
udev/net: support configuring SR-IOV virtual functions through .link file
51 files changed, 1281 insertions, 806 deletions
diff --git a/man/systemd.link.xml b/man/systemd.link.xml index 45cabbccf7..700defeda6 100644 --- a/man/systemd.link.xml +++ b/man/systemd.link.xml @@ -946,6 +946,104 @@ </listitem> </varlistentry> + <varlistentry> + <term><varname>SR-IOVVirtualFunctions=</varname></term> + <listitem> + <para>Specifies the number of SR-IOV virtual functions. Takes an integer in the range + 0…2147483647. Defaults to unset, and automatically determined from the values specified in + the <varname>VirtualFunction=</varname> settings in the [SR-IOV] sections.</para> + </listitem> + </varlistentry> + + </variablelist> + </refsect1> + + <refsect1 id='sr-iov'> + <title>[SR-IOV] Section Options</title> + <para>The [SR-IOV] section accepts the following keys. Specify several [SR-IOV] sections to + configure several SR-IOVs. SR-IOV provides the ability to partition a single physical PCI resource + into virtual PCI functions which can then be injected into a VM. In the case of network VFs, SR-IOV + improves north-south network performance (that is, traffic with endpoints outside the host machine) + by allowing traffic to bypass the host machine’s network stack.</para> + + <variablelist class='network-directives'> + <varlistentry> + <term><varname>VirtualFunction=</varname></term> + <listitem> + <para>Specifies a Virtual Function (VF), lightweight PCIe function designed solely to move + data in and out. Takes an integer in the range 0…2147483646. This option is compulsory. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>VLANId=</varname></term> + <listitem> + <para>Specifies VLAN ID of the virtual function. Takes an integer in the range 1…4095.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>QualityOfService=</varname></term> + <listitem> + <para>Specifies quality of service of the virtual function. Takes an integer in the range + 1…4294967294.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>VLANProtocol=</varname></term> + <listitem> + <para>Specifies VLAN protocol of the virtual function. Takes <literal>802.1Q</literal> or + <literal>802.1ad</literal>.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>MACSpoofCheck=</varname></term> + <listitem> + <para>Takes a boolean. Controls the MAC spoof checking. When unset, the kernel's default will + be used.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>QueryReceiveSideScaling=</varname></term> + <listitem> + <para>Takes a boolean. Toggle the ability of querying the receive side scaling (RSS) + configuration of the virtual function (VF). The VF RSS information like RSS hash key may be + considered sensitive on some devices where this information is shared between VF and the + physical function (PF). When unset, the kernel's default will be used.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>Trust=</varname></term> + <listitem> + <para>Takes a boolean. Allows one to set trust mode of the virtual function (VF). When set, + VF users can set a specific feature which may impact security and/or performance. When unset, + the kernel's default will be used.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>LinkState=</varname></term> + <listitem> + <para>Allows one to set the link state of the virtual function (VF). Takes a boolean or a + special value <literal>auto</literal>. Setting to <literal>auto</literal> means a + reflection of the physical function (PF) link state, <literal>yes</literal> lets the VF to + communicate with other VFs on this host even if the PF link state is down, + <literal>no</literal> causes the hardware to drop any packets sent by the VF. When unset, + the kernel's default will be used.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>MACAddress=</varname></term> + <listitem> + <para>Specifies the MAC address for the virtual function.</para> + </listitem> + </varlistentry> </variablelist> </refsect1> diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 574cf599ec..4f41394682 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -300,94 +300,7 @@ </variablelist> </refsect1> - <refsect1> - <title>[SR-IOV] Section Options</title> - <para>The [SR-IOV] section accepts the following keys. Specify several [SR-IOV] sections to - configure several SR-IOVs. SR-IOV provides the ability to partition a single physical PCI resource - into virtual PCI functions which can then be injected into a VM. In the case of network VFs, SR-IOV - improves north-south network performance (that is, traffic with endpoints outside the host machine) - by allowing traffic to bypass the host machine’s network stack.</para> - - <variablelist class='network-directives'> - <varlistentry> - <term><varname>VirtualFunction=</varname></term> - <listitem> - <para>Specifies a Virtual Function (VF), lightweight PCIe function designed solely to move - data in and out. Takes an integer in the range 0…2147483646. This option is compulsory. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>VLANId=</varname></term> - <listitem> - <para>Specifies VLAN ID of the virtual function. Takes an integer in the range 1…4095.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>QualityOfService=</varname></term> - <listitem> - <para>Specifies quality of service of the virtual function. Takes an integer in the range - 1…4294967294.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>VLANProtocol=</varname></term> - <listitem> - <para>Specifies VLAN protocol of the virtual function. Takes <literal>802.1Q</literal> or - <literal>802.1ad</literal>.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>MACSpoofCheck=</varname></term> - <listitem> - <para>Takes a boolean. Controls the MAC spoof checking. When unset, the kernel's default will - be used.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>QueryReceiveSideScaling=</varname></term> - <listitem> - <para>Takes a boolean. Toggle the ability of querying the receive side scaling (RSS) - configuration of the virtual function (VF). The VF RSS information like RSS hash key may be - considered sensitive on some devices where this information is shared between VF and the - physical function (PF). When unset, the kernel's default will be used.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>Trust=</varname></term> - <listitem> - <para>Takes a boolean. Allows one to set trust mode of the virtual function (VF). When set, VF - users can set a specific feature which may impact security and/or performance. When unset, - the kernel's default will be used.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>LinkState=</varname></term> - <listitem> - <para>Allows one to set the link state of the virtual function (VF). Takes a boolean or a - special value <literal>auto</literal>. Setting to <literal>auto</literal> means a - reflection of the physical function (PF) link state, <literal>yes</literal> lets the VF to - communicate with other VFs on this host even if the PF link state is down, - <literal>no</literal> causes the hardware to drop any packets sent by the VF. When unset, - the kernel's default will be used.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>MACAddress=</varname></term> - <listitem> - <para>Specifies the MAC address for the virtual function.</para> - </listitem> - </varlistentry> - </variablelist> - </refsect1> + <xi:include href="systemd.link.xml" xpointer="sr-iov" /> <refsect1> <title>[Network] Section Options</title> diff --git a/src/network/netdev/l2tp-tunnel.c b/src/network/netdev/l2tp-tunnel.c index d870a11e00..419541ebdf 100644 --- a/src/network/netdev/l2tp-tunnel.c +++ b/src/network/netdev/l2tp-tunnel.c @@ -46,15 +46,15 @@ static L2tpSession* l2tp_session_free(L2tpSession *s) { if (s->tunnel && s->section) ordered_hashmap_remove(s->tunnel->sessions_by_section, s->section); - network_config_section_free(s->section); + config_section_free(s->section); free(s->name); return mfree(s); } -DEFINE_NETWORK_SECTION_FUNCTIONS(L2tpSession, l2tp_session_free); +DEFINE_SECTION_CLEANUP_FUNCTIONS(L2tpSession, l2tp_session_free); static int l2tp_session_new_static(L2tpTunnel *t, const char *filename, unsigned section_line, L2tpSession **ret) { - _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; + _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(l2tp_session_freep) L2tpSession *s = NULL; int r; @@ -63,7 +63,7 @@ static int l2tp_session_new_static(L2tpTunnel *t, const char *filename, unsigned assert(filename); assert(section_line > 0); - r = network_config_section_new(filename, section_line, &n); + r = config_section_new(filename, section_line, &n); if (r < 0) return r; @@ -83,7 +83,7 @@ static int l2tp_session_new_static(L2tpTunnel *t, const char *filename, unsigned .section = TAKE_PTR(n), }; - r = ordered_hashmap_ensure_put(&t->sessions_by_section, &network_config_hash_ops, s->section, s); + r = ordered_hashmap_ensure_put(&t->sessions_by_section, &config_section_hash_ops, s->section, s); if (r < 0) return r; diff --git a/src/network/netdev/l2tp-tunnel.h b/src/network/netdev/l2tp-tunnel.h index a884d2100f..236b78ce4b 100644 --- a/src/network/netdev/l2tp-tunnel.h +++ b/src/network/netdev/l2tp-tunnel.h @@ -34,7 +34,7 @@ typedef struct L2tpTunnel L2tpTunnel; typedef struct L2tpSession { L2tpTunnel *tunnel; - NetworkConfigSection *section; + ConfigSection *section; char *name; diff --git a/src/network/netdev/macsec.c b/src/network/netdev/macsec.c index ebb8c9c7dc..a049ade6ba 100644 --- a/src/network/netdev/macsec.c +++ b/src/network/netdev/macsec.c @@ -43,16 +43,16 @@ static ReceiveAssociation* macsec_receive_association_free(ReceiveAssociation *c if (c->macsec && c->section) ordered_hashmap_remove(c->macsec->receive_associations_by_section, c->section); - network_config_section_free(c->section); + config_section_free(c->section); security_association_clear(&c->sa); return mfree(c); } -DEFINE_NETWORK_SECTION_FUNCTIONS(ReceiveAssociation, macsec_receive_association_free); +DEFINE_SECTION_CLEANUP_FUNCTIONS(ReceiveAssociation, macsec_receive_association_free); static int macsec_receive_association_new_static(MACsec *s, const char *filename, unsigned section_line, ReceiveAssociation **ret) { - _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; + _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(macsec_receive_association_freep) ReceiveAssociation *c = NULL; int r; @@ -61,7 +61,7 @@ static int macsec_receive_association_new_static(MACsec *s, const char *filename assert(filename); assert(section_line > 0); - r = network_config_section_new(filename, section_line, &n); + r = config_section_new(filename, section_line, &n); if (r < 0) return r; @@ -82,7 +82,7 @@ static int macsec_receive_association_new_static(MACsec *s, const char *filename security_association_init(&c->sa); - r = ordered_hashmap_ensure_put(&s->receive_associations_by_section, &network_config_hash_ops, c->section, c); + r = ordered_hashmap_ensure_put(&s->receive_associations_by_section, &config_section_hash_ops, c->section, c); if (r < 0) return r; @@ -103,12 +103,12 @@ static ReceiveChannel* macsec_receive_channel_free(ReceiveChannel *c) { ordered_hashmap_remove(c->macsec->receive_channels_by_section, c->section); } - network_config_section_free(c->section); + config_section_free(c->section); return mfree(c); } -DEFINE_NETWORK_SECTION_FUNCTIONS(ReceiveChannel, macsec_receive_channel_free); +DEFINE_SECTION_CLEANUP_FUNCTIONS(ReceiveChannel, macsec_receive_channel_free); static int macsec_receive_channel_new(MACsec *s, uint64_t sci, ReceiveChannel **ret) { ReceiveChannel *c; @@ -129,7 +129,7 @@ static int macsec_receive_channel_new(MACsec *s, uint64_t sci, ReceiveChannel ** } static int macsec_receive_channel_new_static(MACsec *s, const char *filename, unsigned section_line, ReceiveChannel **ret) { - _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; + _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(macsec_receive_channel_freep) ReceiveChannel *c = NULL; int r; @@ -138,7 +138,7 @@ static int macsec_receive_channel_new_static(MACsec *s, const char *filename, un assert(filename); assert(section_line > 0); - r = network_config_section_new(filename, section_line, &n); + r = config_section_new(filename, section_line, &n); if (r < 0) return r; @@ -154,7 +154,7 @@ static int macsec_receive_channel_new_static(MACsec *s, const char *filename, un c->section = TAKE_PTR(n); - r = ordered_hashmap_ensure_put(&s->receive_channels_by_section, &network_config_hash_ops, c->section, c); + r = ordered_hashmap_ensure_put(&s->receive_channels_by_section, &config_section_hash_ops, c->section, c); if (r < 0) return r; @@ -170,16 +170,16 @@ static TransmitAssociation* macsec_transmit_association_free(TransmitAssociation if (a->macsec && a->section) ordered_hashmap_remove(a->macsec->transmit_associations_by_section, a->section); - network_config_section_free(a->section); + config_section_free(a->section); security_association_clear(&a->sa); return mfree(a); } -DEFINE_NETWORK_SECTION_FUNCTIONS(TransmitAssociation, macsec_transmit_association_free); +DEFINE_SECTION_CLEANUP_FUNCTIONS(TransmitAssociation, macsec_transmit_association_free); static int macsec_transmit_association_new_static(MACsec *s, const char *filename, unsigned section_line, TransmitAssociation **ret) { - _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; + _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(macsec_transmit_association_freep) TransmitAssociation *a = NULL; int r; @@ -188,7 +188,7 @@ static int macsec_transmit_association_new_static(MACsec *s, const char *filenam assert(filename); assert(section_line > 0); - r = network_config_section_new(filename, section_line, &n); + r = config_section_new(filename, section_line, &n); if (r < 0) return r; @@ -209,7 +209,7 @@ static int macsec_transmit_association_new_static(MACsec *s, const char *filenam security_association_init(&a->sa); - r = ordered_hashmap_ensure_put(&s->transmit_associations_by_section, &network_config_hash_ops, a->section, a); + r = ordered_hashmap_ensure_put(&s->transmit_associations_by_section, &config_section_hash_ops, a->section, a); if (r < 0) return r; diff --git a/src/network/netdev/macsec.h b/src/network/netdev/macsec.h index 4d88e49514..17bb1ca3fb 100644 --- a/src/network/netdev/macsec.h +++ b/src/network/netdev/macsec.h @@ -39,14 +39,14 @@ typedef struct SecurityAssociation { typedef struct TransmitAssociation { MACsec *macsec; - NetworkConfigSection *section; + ConfigSection *section; SecurityAssociation sa; } TransmitAssociation; typedef struct ReceiveAssociation { MACsec *macsec; - NetworkConfigSection *section; + ConfigSection *section; MACsecSCI sci; SecurityAssociation sa; @@ -54,7 +54,7 @@ typedef struct ReceiveAssociation { typedef struct ReceiveChannel { MACsec *macsec; - NetworkConfigSection *section; + ConfigSection *section; MACsecSCI sci; ReceiveAssociation *rxsa[MACSEC_MAX_ASSOCIATION_NUMBER]; diff --git a/src/network/netdev/wireguard.c b/src/network/netdev/wireguard.c index 88f668753a..431b5ec045 100644 --- a/src/network/netdev/wireguard.c +++ b/src/network/netdev/wireguard.c @@ -47,7 +47,7 @@ static WireguardPeer* wireguard_peer_free(WireguardPeer *peer) { hashmap_remove(peer->wireguard->peers_by_section, peer->section); } - network_config_section_free(peer->section); + config_section_free(peer->section); while ((mask = peer->ipmasks)) { LIST_REMOVE(ipmasks, peer->ipmasks, mask); @@ -65,10 +65,10 @@ static WireguardPeer* wireguard_peer_free(WireguardPeer *peer) { return mfree(peer); } -DEFINE_NETWORK_SECTION_FUNCTIONS(WireguardPeer, wireguard_peer_free); +DEFINE_SECTION_CLEANUP_FUNCTIONS(WireguardPeer, wireguard_peer_free); static int wireguard_peer_new_static(Wireguard *w, const char *filename, unsigned section_line, WireguardPeer **ret) { - _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; + _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(wireguard_peer_freep) WireguardPeer *peer = NULL; int r; @@ -77,7 +77,7 @@ static int wireguard_peer_new_static(Wireguard *w, const char *filename, unsigne assert(filename); assert(section_line > 0); - r = network_config_section_new(filename, section_line, &n); + r = config_section_new(filename, section_line, &n); if (r < 0) return r; @@ -99,7 +99,7 @@ static int wireguard_peer_new_static(Wireguard *w, const char *filename, unsigne LIST_PREPEND(peers, w->peers, peer); - r = hashmap_ensure_put(&w->peers_by_section, &network_config_hash_ops, peer->section, peer); + r = hashmap_ensure_put(&w->peers_by_section, &config_section_hash_ops, peer->section, peer); if (r < 0) return r; diff --git a/src/network/netdev/wireguard.h b/src/network/netdev/wireguard.h index 29bacdc771..09dca88bbf 100644 --- a/src/network/netdev/wireguard.h +++ b/src/network/netdev/wireguard.h @@ -24,7 +24,7 @@ typedef struct WireguardIPmask { typedef struct WireguardPeer { Wireguard *wireguard; - NetworkConfigSection *section; + ConfigSection *section; uint8_t public_key[WG_KEY_LEN]; uint8_t preshared_key[WG_KEY_LEN]; diff --git a/src/network/networkd-address-label.c b/src/network/networkd-address-label.c index 6f911b805f..506238f391 100644 --- a/src/network/networkd-address-label.c +++ b/src/network/networkd-address-label.c @@ -21,14 +21,14 @@ AddressLabel *address_label_free(AddressLabel *label) { hashmap_remove(label->network->address_labels_by_section, label->section); } - network_config_section_free(label->section); + config_section_free(label->section); return mfree(label); } -DEFINE_NETWORK_SECTION_FUNCTIONS(AddressLabel, address_label_free); +DEFINE_SECTION_CLEANUP_FUNCTIONS(AddressLabel, address_label_free); static int address_label_new_static(Network *network, const char *filename, unsigned section_line, AddressLabel **ret) { - _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; + _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(address_label_freep) AddressLabel *label = NULL; int r; @@ -37,7 +37,7 @@ static int address_label_new_static(Network *network, const char *filename, unsi assert(filename); assert(section_line > 0); - r = network_config_section_new(filename, section_line, &n); + r = config_section_new(filename, section_line, &n); if (r < 0) return r; @@ -57,7 +57,7 @@ static int address_label_new_static(Network *network, const char *filename, unsi .label = UINT32_MAX, }; - r = hashmap_ensure_put(&network->address_labels_by_section, &network_config_hash_ops, label->section, label); + r = hashmap_ensure_put(&network->address_labels_by_section, &config_section_hash_ops, label->section, label); if (r < 0) return r; diff --git a/src/network/networkd-address-label.h b/src/network/networkd-address-label.h index 0f975454d9..582dd05b88 100644 --- a/src/network/networkd-address-label.h +++ b/src/network/networkd-address-label.h @@ -13,7 +13,7 @@ typedef struct Request Request; typedef struct AddressLabel { Network *network; - NetworkConfigSection *section; + ConfigSection *section; uint32_t label; struct in6_addr prefix; diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 7df743efb5..ff80f185ce 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -77,7 +77,7 @@ int address_new(Address **ret) { } static int address_new_static(Network *network, const char *filename, unsigned section_line, Address **ret) { - _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; + _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(address_freep) Address *address = NULL; int r; @@ -86,7 +86,7 @@ static int address_new_static(Network *network, const char *filename, unsigned s assert(filename); assert(section_line > 0); - r = network_config_section_new(filename, section_line, &n); + r = config_section_new(filename, section_line, &n); if (r < 0) return r; @@ -107,7 +107,7 @@ static int address_new_static(Network *network, const char *filename, unsigned s address->section = TAKE_PTR(n); address->source = NETWORK_CONFIG_SOURCE_STATIC; - r = ordered_hashmap_ensure_put(&network->addresses_by_section, &network_config_hash_ops, address->section, address); + r = ordered_hashmap_ensure_put(&network->addresses_by_section, &config_section_hash_ops, address->section, address); if (r < 0) return r; @@ -134,7 +134,7 @@ Address *address_free(Address *address) { sd_ipv4acd_unref(address->acd); - network_config_section_free(address->section); + config_section_free(address->section); free(address->label); return mfree(address); } diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h index 41c4ce6fa4..c1e5b3ce3a 100644 --- a/src/network/networkd-address.h +++ b/src/network/networkd-address.h @@ -22,7 +22,7 @@ typedef int (*address_ready_callback_t)(Address *address); struct Address { Link *link; Network *network; - NetworkConfigSection *section; + ConfigSection *section; NetworkConfigSource source; NetworkConfigState state; union in_addr_union provider; /* DHCP server or router address */ @@ -72,7 +72,7 @@ int address_dup(const Address *src, Address **ret); bool address_is_ready(const Address *a); void address_set_broadcast(Address *a); -DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free); +DEFINE_SECTION_CLEANUP_FUNCTIONS(Address, address_free); int link_drop_addresses(Link *link); int link_drop_foreign_addresses(Link *link); diff --git a/src/network/networkd-bridge-fdb.c b/src/network/networkd-bridge-fdb.c index a0024f62d4..c1e2977d4d 100644 --- a/src/network/networkd-bridge-fdb.c +++ b/src/network/networkd-bridge-fdb.c @@ -32,13 +32,13 @@ BridgeFDB *bridge_fdb_free(BridgeFDB *fdb) { hashmap_remove(fdb->network->bridge_fdb_entries_by_section, fdb->section); } - network_config_section_free(fdb->section); + config_section_free(fdb->section); free(fdb->outgoing_ifname); return mfree(fdb); } -DEFINE_NETWORK_SECTION_FUNCTIONS(BridgeFDB, bridge_fdb_free); +DEFINE_SECTION_CLEANUP_FUNCTIONS(BridgeFDB, bridge_fdb_free); /* create a new FDB entry or get an existing one. */ static int bridge_fdb_new_static( @@ -47,7 +47,7 @@ static int bridge_fdb_new_static( unsigned section_line, BridgeFDB **ret) { - _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; + _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(bridge_fdb_freep) BridgeFDB *fdb = NULL; int r; @@ -56,7 +56,7 @@ static int bridge_fdb_new_static( assert(filename); assert(section_line > 0); - r = network_config_section_new(filename, section_line, &n); + r = config_section_new(filename, section_line, &n); if (r < 0) return r; @@ -83,7 +83,7 @@ static int bridge_fdb_new_static( .ntf_flags = NEIGHBOR_CACHE_ENTRY_FLAGS_SELF, }; - r = hashmap_ensure_put(&network->bridge_fdb_entries_by_section, &network_config_hash_ops, fdb->section, fdb); + r = hashmap_ensure_put(&network->bridge_fdb_entries_by_section, &config_section_hash_ops, fdb->section, fdb); if (r < 0) return r; diff --git a/src/network/networkd-bridge-fdb.h b/src/network/networkd-bridge-fdb.h index fae7da5bbb..b1098760d2 100644 --- a/src/network/networkd-bridge-fdb.h +++ b/src/network/networkd-bridge-fdb.h @@ -27,7 +27,7 @@ typedef enum NeighborCacheEntryFlags { typedef struct BridgeFDB { Network *network; - NetworkConfigSection *section; + ConfigSection *section; uint32_t vni; diff --git a/src/network/networkd-bridge-mdb.c b/src/network/networkd-bridge-mdb.c index 10025a97ae..d155090ad1 100644 --- a/src/network/networkd-bridge-mdb.c +++ b/src/network/networkd-bridge-mdb.c @@ -24,12 +24,12 @@ BridgeMDB *bridge_mdb_free(BridgeMDB *mdb) { hashmap_remove(mdb->network->bridge_mdb_entries_by_section, mdb->section); } - network_config_section_free(mdb->section); + config_section_free(mdb->section); return mfree(mdb); } -DEFINE_NETWORK_SECTION_FUNCTIONS(BridgeMDB, bridge_mdb_free); +DEFINE_SECTION_CLEANUP_FUNCTIONS(BridgeMDB, bridge_mdb_free); /* create a new MDB entry or get an existing one. */ static int bridge_mdb_new_static( @@ -38,7 +38,7 @@ static int bridge_mdb_new_static( unsigned section_line, BridgeMDB **ret) { - _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; + _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(bridge_mdb_freep) BridgeMDB *mdb = NULL; int r; @@ -47,7 +47,7 @@ static int bridge_mdb_new_static( assert(filename); assert(section_line > 0); - r = network_config_section_new(filename, section_line, &n); + r = config_section_new(filename, section_line, &n); if (r < 0) return r; @@ -72,7 +72,7 @@ static int bridge_mdb_new_static( .section = TAKE_PTR(n), }; - r = hashmap_ensure_put(&network->bridge_mdb_entries_by_section, &network_config_hash_ops, mdb->section, mdb); + r = hashmap_ensure_put(&network->bridge_mdb_entries_by_section, &config_section_hash_ops, mdb->section, mdb); if (r < 0) return r; diff --git a/src/network/networkd-bridge-mdb.h b/src/network/networkd-bridge-mdb.h index 9ca262e0ce..ce91e3f572 100644 --- a/src/network/networkd-bridge-mdb.h +++ b/src/network/networkd-bridge-mdb.h @@ -13,7 +13,7 @@ typedef struct Request Request; typedef struct BridgeMDB { Network *network; - NetworkConfigSection *section; + ConfigSection *section; int family; union in_addr_union group_addr; diff --git a/src/network/networkd-dhcp-server-static-lease.c b/src/network/networkd-dhcp-server-static-lease.c index 6acd838e2b..38e8c7e889 100644 --- a/src/network/networkd-dhcp-server-static-lease.c +++ b/src/network/networkd-dhcp-server-static-lease.c @@ -7,7 +7,7 @@ #include "networkd-network.h" #include "networkd-util.h" -DEFINE_NETWORK_SECTION_FUNCTIONS(DHCPStaticLease, dhcp_static_lease_free); +DEFINE_SECTION_CLEANUP_FUNCTIONS(DHCPStaticLease, dhcp_static_lease_free); DHCPStaticLease *dhcp_static_lease_free(DHCPStaticLease *static_lease) { if (!static_lease) @@ -16,7 +16,7 @@ DHCPStaticLease *dhcp_static_lease_free(DHCPStaticLease *static_lease) { if (static_lease->network && static_lease->section) hashmap_remove(static_lease->network->dhcp_static_leases_by_section, static_lease->section); - network_config_section_free(static_lease->section); + config_section_free(static_lease->section); free(static_lease->client_id); return mfree(static_lease); } @@ -35,7 +35,7 @@ static int dhcp_static_lease_new(DHCPStaticLease **ret) { } static int lease_new_static(Network *network, const char *filename, unsigned section_line, DHCPStaticLease **ret) { - _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; + _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(dhcp_static_lease_freep) DHCPStaticLease *static_lease = NULL; int r; @@ -44,7 +44,7 @@ static int lease_new_static(Network *network, const char *filename, unsigned sec assert(section_line > 0); assert(ret); - r = network_config_section_new(filename, section_line, &n); + r = config_section_new(filename, section_line, &n); if (r < 0) return r; @@ -60,7 +60,7 @@ static int lease_new_static(Network *network, const char *filename, unsigned sec static_lease->network = network; static_lease->section = TAKE_PTR(n); - r = hashmap_ensure_put(&network->dhcp_static_leases_by_section, &network_config_hash_ops, static_lease->section, static_lease); + r = hashmap_ensure_put(&network->dhcp_static_leases_by_section, &config_section_hash_ops, static_lease->section, static_lease); if (r < 0) return r; diff --git a/src/network/networkd-dhcp-server-static-lease.h b/src/network/networkd-dhcp-server-static-lease.h index c2a9ad6bb1..9b8e78b90d 100644 --- a/src/network/networkd-dhcp-server-static-lease.h +++ b/src/network/networkd-dhcp-server-static-lease.h @@ -8,11 +8,11 @@ #include "in-addr-util.h" typedef struct Network Network; -typedef struct NetworkConfigSection NetworkConfigSection; +typedef struct ConfigSection ConfigSection; typedef struct DHCPStaticLease { Network *network; - NetworkConfigSection *section; + ConfigSection *section; struct in_addr address; uint8_t *client_id; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index cea700bbb8..89ee8c8367 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2549,6 +2549,8 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { r = ethtool_get_driver(&manager->ethtool_fd, link->ifname, &link->driver); if (r < 0) log_link_debug_errno(link, r, "Failed to get driver, continuing without: %m"); + else + log_link_debug(link, "Found driver: %s", strna(link->driver)); if (streq_ptr(link->driver, "dsa")) { uint32_t dsa_master_ifindex; diff --git a/src/network/networkd-neighbor.c b/src/network/networkd-neighbor.c index 26b7385497..4aab290bf8 100644 --- a/src/network/networkd-neighbor.c +++ b/src/network/networkd-neighbor.c @@ -19,7 +19,7 @@ Neighbor *neighbor_free(Neighbor *neighbor) { hashmap_remove(neighbor->network->neighbors_by_section, neighbor->section); } - network_config_section_free(neighbor->section); + config_section_free(neighbor->section); if (neighbor->link) set_remove(neighbor->link->neighbors, neighbor); @@ -27,10 +27,10 @@ Neighbor *neighbor_free(Neighbor *neighbor) { return mfree(neighbor); } -DEFINE_NETWORK_SECTION_FUNCTIONS(Neighbor, neighbor_free); +DEFINE_SECTION_CLEANUP_FUNCTIONS(Neighbor, neighbor_free); static int neighbor_new_static(Network *network, const char *filename, unsigned section_line, Neighbor **ret) { - _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; + _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(neighbor_freep) Neighbor *neighbor = NULL; int r; @@ -39,7 +39,7 @@ static int neighbor_new_static(Network *network, const char *filename, unsigned assert(filename); assert(section_line > 0); - r = network_config_section_new(filename, section_line, &n); + r = config_section_new(filename, section_line, &n); if (r < 0) return r; @@ -60,7 +60,7 @@ static int neighbor_new_static(Network *network, const char *filename, unsigned .source = NETWORK_CONFIG_SOURCE_STATIC, }; - r = hashmap_ensure_put(&network->neighbors_by_section, &network_config_hash_ops, neighbor->section, neighbor); + r = hashmap_ensure_put(&network->neighbors_by_section, &config_section_hash_ops, neighbor->section, neighbor); if (r < 0) return r; diff --git a/src/network/networkd-neighbor.h b/src/network/networkd-neighbor.h index e9e1854110..f31f58a4d4 100644 --- a/src/network/networkd-neighbor.h +++ b/src/network/networkd-neighbor.h @@ -18,7 +18,7 @@ typedef struct Request Request; typedef struct Neighbor { Network *network; Link *link; - NetworkConfigSection *section; + ConfigSection *section; NetworkConfigSource source; NetworkConfigState state; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 4c3bf97311..08e3f13f5a 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -73,15 +73,15 @@ Link.Unmanaged, config_parse_bool, Link.ActivationPolicy, config_parse_activation_policy, 0, offsetof(Network, activation_policy) Link.RequiredForOnline, config_parse_required_for_online, 0, 0 Link.RequiredFamilyForOnline, config_parse_required_family_for_online, 0, offsetof(Network, required_family_for_online) -SR-IOV.VirtualFunction, config_parse_sr_iov_uint32, 0, 0 -SR-IOV.VLANId, config_parse_sr_iov_uint32, 0, 0 -SR-IOV.QualityOfService, config_parse_sr_iov_uint32, 0, 0 -SR-IOV.VLANProtocol, config_parse_sr_iov_vlan_proto, 0, 0 -SR-IOV.MACSpoofCheck, config_parse_sr_iov_boolean, 0, 0 -SR-IOV.QueryReceiveSideScaling, config_parse_sr_iov_boolean, 0, 0 -SR-IOV.Trust, config_parse_sr_iov_boolean, 0, 0 -SR-IOV.LinkState, config_parse_sr_iov_link_state, 0, 0 -SR-IOV.MACAddress, config_parse_sr_iov_mac, 0, 0 +SR-IOV.VirtualFunction, config_parse_sr_iov_uint32, 0, offsetof(Network, sr_iov_by_section) +SR-IOV.VLANId, config_parse_sr_iov_uint32, 0, offsetof(Network, sr_iov_by_section) +SR-IOV.QualityOfService, config_parse_sr_iov_uint32, 0, offsetof(Network, sr_iov_by_section) +SR-IOV.VLANProtocol, config_parse_sr_iov_vlan_proto, 0, offsetof(Network, sr_iov_by_section) +SR-IOV.MACSpoofCheck, config_parse_sr_iov_boolean, 0, offsetof(Network, sr_iov_by_section) +SR-IOV.QueryReceiveSideScaling, config_parse_sr_iov_boolean, 0, offsetof(Network, sr_iov_by_section) +SR-IOV.Trust, config_parse_sr_iov_boolean, 0, offsetof(Network, sr_iov_by_section) +SR-IOV.LinkState, config_parse_sr_iov_link_state, 0, offsetof(Network, sr_iov_by_section) +SR-IOV.MACAddress, config_parse_sr_iov_mac, 0, offsetof(Network, sr_iov_by_section) Network.Description, config_parse_string, 0, offsetof(Network, description) Network.KeepMaster, config_parse_bool, 0, offsetof(Network, keep_master) Network.BatmanAdvanced, config_parse_ifname, 0, offsetof(Network, batadv_name) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 873ad2e703..3142be471f 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -321,7 +321,9 @@ int network_verify(Network *network) { network_drop_invalid_route_prefixes(network); network_drop_invalid_routing_policy_rules(network); network_drop_invalid_traffic_control(network); - network_drop_invalid_sr_iov(network); + r = sr_iov_drop_invalid_sections(UINT32_MAX, network->sr_iov_by_section); + if (r < 0) + return r; network_drop_invalid_static_leases(network); network_adjust_dhcp_server(network); diff --git a/src/network/networkd-nexthop.c b/src/network/networkd-nexthop.c index b829aaab90..e9e5d08557 100644 --- a/src/network/networkd-nexthop.c +++ b/src/network/networkd-nexthop.c @@ -27,7 +27,7 @@ NextHop *nexthop_free(NextHop *nexthop) { hashmap_remove(nexthop->network->nexthops_by_section, nexthop->section); } - network_config_section_free(nexthop->section); + config_section_free(nexthop->section); if (nexthop->link) { set_remove(nexthop->link->nexthops, nexthop); @@ -48,7 +48,7 @@ NextHop *nexthop_free(NextHop *nexthop) { return mfree(nexthop); } -DEFINE_NETWORK_SECTION_FUNCTIONS(NextHop, nexthop_free); +DEFINE_SECTION_CLEANUP_FUNCTIONS(NextHop, nexthop_free); static int nexthop_new(NextHop **ret) { _cleanup_(nexthop_freep) NextHop *nexthop = NULL; @@ -68,7 +68,7 @@ static int nexthop_new(NextHop **ret) { } static int nexthop_new_static(Network *network, const char *filename, unsigned section_line, NextHop **ret) { - _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; + _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(nexthop_freep) NextHop *nexthop = NULL; int r; @@ -77,7 +77,7 @@ static int nexthop_new_static(Network *network, const char *filename, unsigned s assert(filename); assert(section_line > 0); - r = network_config_section_new(filename, section_line, &n); + r = config_section_new(filename, section_line, &n); if (r < 0) return r; @@ -96,7 +96,7 @@ static int nexthop_new_static(Network *network, const char *filename, unsigned s nexthop->section = TAKE_PTR(n); nexthop->source = NETWORK_CONFIG_SOURCE_STATIC; - r = hashmap_ensure_put(&network->nexthops_by_section, &network_config_hash_ops, nexthop->section, nexthop); + r = hashmap_ensure_put(&network->nexthops_by_section, &config_section_hash_ops, nexthop->section, nexthop); if (r < 0) return r; diff --git a/src/network/networkd-nexthop.h b/src/network/networkd-nexthop.h index 7a8920238c..01b29ae560 100644 --- a/src/network/networkd-nexthop.h +++ b/src/network/networkd-nexthop.h @@ -22,7 +22,7 @@ typedef struct NextHop { Network *network; Manager *manager; Link *link; - NetworkConfigSection *section; + ConfigSection *section; NetworkConfigSource source; NetworkConfigState state; diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c index 59b0922a4c..0c5eebc815 100644 --- a/src/network/networkd-radv.c +++ b/src/network/networkd-radv.c @@ -69,16 +69,16 @@ Prefix *prefix_free(Prefix *prefix) { hashmap_remove(prefix->network->prefixes_by_section, prefix->section); } - network_config_section_free(prefix->section); + config_section_free(prefix->section); set_free(prefix->tokens); return mfree(prefix); } -DEFINE_NETWORK_SECTION_FUNCTIONS(Prefix, prefix_free); +DEFINE_SECTION_CLEANUP_FUNCTIONS(Prefix, prefix_free); static int prefix_new_static(Network *network, const char *filename, unsigned section_line, Prefix **ret) { - _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; + _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(prefix_freep) Prefix *prefix = NULL; int r; @@ -87,7 +87,7 @@ static int prefix_new_static(Network *network, const char *filename, unsigned se assert(filename); assert(section_line > 0); - r = network_config_section_new(filename, section_line, &n); + r = config_section_new(filename, section_line, &n); if (r < 0) return r; @@ -111,7 +111,7 @@ static int prefix_new_static(Network *network, const char *filename, unsigned se .address_auto_configuration = true, }; - r = hashmap_ensure_put(&network->prefixes_by_section, &network_config_hash_ops, prefix->section, prefix); + r = hashmap_ensure_put(&network->prefixes_by_section, &config_section_hash_ops, prefix->section, prefix); if (r < 0) return r; @@ -128,15 +128,15 @@ RoutePrefix *route_prefix_free(RoutePrefix *prefix) { hashmap_remove(prefix->network->route_prefixes_by_section, prefix->section); } - network_config_section_free(prefix->section); + config_section_free(prefix->section); return mfree(prefix); } -DEFINE_NETWORK_SECTION_FUNCTIONS(RoutePrefix, route_prefix_free); +DEFINE_SECTION_CLEANUP_FUNCTIONS(RoutePrefix, route_prefix_free); static int route_prefix_new_static(Network *network, const char *filename, unsigned section_line, RoutePrefix **ret) { - _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; + _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(route_prefix_freep) RoutePrefix *prefix = NULL; int r; @@ -145,7 +145,7 @@ static int route_prefix_new_static(Network *network, const char *filename, unsig assert(filename); assert(section_line > 0); - r = network_config_section_new(filename, section_line, &n); + r = config_section_new(filename, section_line, &n); if (r < 0) return r; @@ -166,7 +166,7 @@ static int route_prefix_new_static(Network *network, const char *filename, unsig .lifetime = RADV_DEFAULT_VALID_LIFETIME_USEC, }; - r = hashmap_ensure_put(&network->route_prefixes_by_section, &network_config_hash_ops, prefix->section, prefix); + r = hashmap_ensure_put(&network->route_prefixes_by_section, &config_section_hash_ops, prefix->section, prefix); if (r < 0) return r; diff --git a/src/network/networkd-radv.h b/src/network/networkd-radv.h index 392c00b37d..952fa8ae58 100644 --- a/src/network/networkd-radv.h +++ b/src/network/networkd-radv.h @@ -29,7 +29,7 @@ typedef enum RADVPrefixDelegation { typedef struct Prefix { Network *network; - NetworkConfigSection *section; + ConfigSection *section; struct in6_addr prefix; uint8_t prefixlen; @@ -46,7 +46,7 @@ typedef struct Prefix { typedef struct RoutePrefix { Network *network; - NetworkConfigSection *section; + ConfigSection *section; struct in6_addr prefix; uint8_t prefixlen; diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 00e64978d4..03021362b6 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -47,7 +47,7 @@ int route_new(Route **ret) { } static int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) { - _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; + _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(route_freep) Route *route = NULL; int r; @@ -56,7 +56,7 @@ static int route_new_static(Network *network, const char *filename, unsigned sec assert(filename); assert(section_line > 0); - r = network_config_section_new(filename, section_line, &n); + r = config_section_new(filename, section_line, &n); if (r < 0) return r; @@ -78,7 +78,7 @@ static int route_new_static(Network *network, const char *filename, unsigned sec route->section = TAKE_PTR(n); route->source = NETWORK_CONFIG_SOURCE_STATIC; - r = hashmap_ensure_put(&network->routes_by_section, &network_config_hash_ops, route->section, route); + r = hashmap_ensure_put(&network->routes_by_section, &config_section_hash_ops, route->section, route); if (r < 0) return r; @@ -95,7 +95,7 @@ Route *route_free(Route *route) { hashmap_remove(route->network->routes_by_section, route->section); } - network_config_section_free(route->section); + config_section_free(route->section); if (route->link) set_remove(route->link->routes, route); diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index e3e22a5985..3471008fee 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -19,7 +19,7 @@ typedef struct Route { Link *link; Manager *manager; Network *network; - NetworkConfigSection *section; + ConfigSection *section; NetworkConfigSource source; NetworkConfigState state; union in_addr_union provider; /* DHCP server or router address */ @@ -74,7 +74,7 @@ extern const struct hash_ops route_hash_ops; int route_new(Route **ret); Route *route_free(Route *route); -DEFINE_NETWORK_SECTION_FUNCTIONS(Route, route_free); +DEFINE_SECTION_CLEANUP_FUNCTIONS(Route, route_free); int route_dup(const Route *src, Route **ret); int route_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg); diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c index a2e72a7d7c..1f3dfa53b0 100644 --- a/src/network/networkd-routing-policy-rule.c +++ b/src/network/networkd-routing-policy-rule.c @@ -54,14 +54,14 @@ RoutingPolicyRule *routing_policy_rule_free(RoutingPolicyRule *rule) { if (rule->manager) set_remove(rule->manager->rules, rule); - network_config_section_free(rule->section); + config_section_free(rule->section); free(rule->iif); free(rule->oif); return mfree(rule); } -DEFINE_NETWORK_SECTION_FUNCTIONS(RoutingPolicyRule, routing_policy_rule_free); +DEFINE_SECTION_CLEANUP_FUNCTIONS(RoutingPolicyRule, routing_policy_rule_free); static int routing_policy_rule_new(RoutingPolicyRule **ret) { RoutingPolicyRule *rule; @@ -86,7 +86,7 @@ static int routing_policy_rule_new(RoutingPolicyRule **ret) { static int routing_policy_rule_new_static(Network *network, const char *filename, unsigned section_line, RoutingPolicyRule **ret) { _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL; - _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; + _cleanup_(config_section_freep) ConfigSection *n = NULL; int r; assert(network); @@ -94,7 +94,7 @@ static int routing_policy_rule_new_static(Network *network, const char *filename assert(filename); assert(section_line > 0); - r = network_config_section_new(filename, section_line, &n); + r = config_section_new(filename, section_line, &n); if (r < 0) return r; @@ -113,7 +113,7 @@ static int routing_policy_rule_new_static(Network *network, const char *filename rule->source = NETWORK_CONFIG_SOURCE_STATIC; rule->protocol = RTPROT_STATIC; - r = hashmap_ensure_put(&network->rules_by_section, &network_config_hash_ops, rule->section, rule); + r = hashmap_ensure_put(&network->rules_by_section, &config_section_hash_ops, rule->section, rule); if (r < 0) return r; diff --git a/src/network/networkd-routing-policy-rule.h b/src/network/networkd-routing-policy-rule.h index f52943bd2e..1ab147caae 100644 --- a/src/network/networkd-routing-policy-rule.h +++ b/src/network/networkd-routing-policy-rule.h @@ -17,7 +17,7 @@ typedef struct Request Request; typedef struct RoutingPolicyRule { Manager *manager; Network *network; - NetworkConfigSection *section; + ConfigSection *section; NetworkConfigSource source; NetworkConfigState state; diff --git a/src/network/networkd-sriov.c b/src/network/networkd-sriov.c index 6da0f83521..cf138c7370 100644 --- a/src/network/networkd-sriov.c +++ b/src/network/networkd-sriov.c @@ -1,82 +1,10 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later * Copyright © 2020 VMware, Inc. */ -#include "alloc-util.h" #include "netlink-util.h" +#include "networkd-link.h" #include "networkd-manager.h" #include "networkd-sriov.h" -#include "parse-util.h" -#include "set.h" -#include "string-util.h" - -static int sr_iov_new(SRIOV **ret) { - SRIOV *sr_iov; - - sr_iov = new(SRIOV, 1); - if (!sr_iov) - return -ENOMEM; - - *sr_iov = (SRIOV) { - .vf = UINT32_MAX, - .vlan_proto = ETH_P_8021Q, - .vf_spoof_check_setting = -1, - .trust = -1, - .query_rss = -1, - .link_state = _SR_IOV_LINK_STATE_INVALID, - }; - - *ret = TAKE_PTR(sr_iov); - - return 0; -} - -static int sr_iov_new_static(Network *network, const char *filename, unsigned section_line, SRIOV **ret) { - _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; - _cleanup_(sr_iov_freep) SRIOV *sr_iov = NULL; - SRIOV *existing = NULL; - int r; - - assert(network); - assert(ret); - assert(filename); - assert(section_line > 0); - - r = network_config_section_new(filename, section_line, &n); - if (r < 0) - return r; - - existing = ordered_hashmap_get(network->sr_iov_by_section, n); - if (existing) { - *ret = existing; - return 0; - } - - r = sr_iov_new(&sr_iov); - if (r < 0) - return r; - - sr_iov->network = network; - sr_iov->section = TAKE_PTR(n); - - r = ordered_hashmap_ensure_put(&network->sr_iov_by_section, &network_config_hash_ops, sr_iov->section, sr_iov); - if (r < 0) - return r; - - *ret = TAKE_PTR(sr_iov); - return 0; -} - -SRIOV *sr_iov_free(SRIOV *sr_iov) { - if (!sr_iov) - return NULL; - - if (sr_iov->network && sr_iov->section) - ordered_hashmap_remove(sr_iov->network->sr_iov_by_section, sr_iov->section); - - network_config_section_free(sr_iov->section); - - return mfree(sr_iov); -} static int sr_iov_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { int r; @@ -117,104 +45,16 @@ static int sr_iov_configure(Link *link, SRIOV *sr_iov) { r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex); if (r < 0) - return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m"); - - r = sd_netlink_message_open_container(req, IFLA_VFINFO_LIST); - if (r < 0) - return log_link_error_errno(link, r, "Could not open IFLA_VFINFO_LIST container: %m"); - - r = sd_netlink_message_open_container(req, IFLA_VF_INFO); - if (r < 0) - return log_link_error_errno(link, r, "Could not open IFLA_VF_INFO container: %m"); - - if (!ether_addr_is_null(&sr_iov->mac)) { - struct ifla_vf_mac ivm = { - .vf = sr_iov->vf, - }; - - memcpy(ivm.mac, &sr_iov->mac, ETH_ALEN); - r = sd_netlink_message_append_data(req, IFLA_VF_MAC, &ivm, sizeof(struct ifla_vf_mac)); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_VF_MAC: %m"); - } - - if (sr_iov->vf_spoof_check_setting >= 0) { - struct ifla_vf_spoofchk ivs = { - .vf = sr_iov->vf, - .setting = sr_iov->vf_spoof_check_setting, - }; - - r = sd_netlink_message_append_data(req, IFLA_VF_SPOOFCHK, &ivs, sizeof(struct ifla_vf_spoofchk)); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_VF_SPOOFCHK: %m"); - } - - if (sr_iov->query_rss >= 0) { - struct ifla_vf_rss_query_en ivs = { - .vf = sr_iov->vf, - .setting = sr_iov->query_rss, - }; - - r = sd_netlink_message_append_data(req, IFLA_VF_RSS_QUERY_EN, &ivs, sizeof(struct ifla_vf_rss_query_en)); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_VF_RSS_QUERY_EN: %m"); - } - - if (sr_iov->trust >= 0) { - struct ifla_vf_trust ivt = { - .vf = sr_iov->vf, - .setting = sr_iov->trust, - }; - - r = sd_netlink_message_append_data(req, IFLA_VF_TRUST, &ivt, sizeof(struct ifla_vf_trust)); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_VF_TRUST: %m"); - } - - if (sr_iov->link_state >= 0) { - struct ifla_vf_link_state ivl = { - .vf = sr_iov->vf, - .link_state = sr_iov->link_state, - }; - - r = sd_netlink_message_append_data(req, IFLA_VF_LINK_STATE, &ivl, sizeof(struct ifla_vf_link_state)); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_VF_LINK_STATE: %m"); - } - - if (sr_iov->vlan > 0) { - /* Because of padding, first the buffer must be initialized with 0. */ - struct ifla_vf_vlan_info ivvi = {}; - ivvi.vf = sr_iov->vf; - ivvi.vlan = sr_iov->vlan; - ivvi.qos = sr_iov->qos; - ivvi.vlan_proto = htobe16(sr_iov->vlan_proto); - - r = sd_netlink_message_open_container(req, IFLA_VF_VLAN_LIST); - if (r < 0) - return log_link_error_errno(link, r, "Could not open IFLA_VF_VLAN_LIST container: %m"); - - r = sd_netlink_message_append_data(req, IFLA_VF_VLAN_INFO, &ivvi, sizeof(struct ifla_vf_vlan_info)); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFLA_VF_VLAN_INFO: %m"); - - r = sd_netlink_message_close_container(req); - if (r < 0) - return log_link_error_errno(link, r, "Could not close IFLA_VF_VLAN_LIST container: %m"); - } - - r = sd_netlink_message_close_container(req); - if (r < 0) - return log_link_error_errno(link, r, "Could not close IFLA_VF_INFO container: %m"); + return r; - r = sd_netlink_message_close_container(req); + r = sr_iov_set_netlink_message(sr_iov, req); if (r < 0) - return log_link_error_errno(link, r, "Could not close IFLA_VFINFO_LIST container: %m"); + return r; r = netlink_call_async(link->manager->rtnl, NULL, req, sr_iov_handler, link_netlink_destroy_callback, link); if (r < 0) - return log_link_error_errno(link, r, "Could not send rtnetlink message: %m"); + return r; link_ref(link); link->sr_iov_messages++; @@ -239,7 +79,9 @@ int link_configure_sr_iov(Link *link) { ORDERED_HASHMAP_FOREACH(sr_iov, link->network->sr_iov_by_section) { r = sr_iov_configure(link, sr_iov); if (r < 0) - return r; + return log_link_warning_errno(link, r, + "Failed to configure SR-IOV virtual function %"PRIu32": %m", + sr_iov->vf); } if (link->sr_iov_messages == 0) @@ -249,287 +91,3 @@ int link_configure_sr_iov(Link *link) { return 0; } - -static int sr_iov_section_verify(SRIOV *sr_iov) { - assert(sr_iov); - - if (section_is_invalid(sr_iov->section)) - return -EINVAL; - - if (sr_iov->vf == UINT32_MAX) - return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), - "%s: [SRIOV] section without VirtualFunction= field configured. " - "Ignoring [SRIOV] section from line %u.", - sr_iov->section->filename, sr_iov->section->line); - - return 0; -} - -void network_drop_invalid_sr_iov(Network *network) { - SRIOV *sr_iov; - - assert(network); - - ORDERED_HASHMAP_FOREACH(sr_iov, network->sr_iov_by_section) - if (sr_iov_section_verify(sr_iov) < 0) - sr_iov_free(sr_iov); -} - -int config_parse_sr_iov_uint32( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL; - Network *network = data; - uint32_t k; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - r = sr_iov_new_static(network, filename, section_line, &sr_iov); - if (r < 0) - return r; - - if (isempty(rvalue)) { - if (streq(lvalue, "VirtualFunction")) - sr_iov->vf = UINT32_MAX; - else if (streq(lvalue, "VLANId")) - sr_iov->vlan = 0; - else if (streq(lvalue, "QualityOfService")) - sr_iov->qos = 0; - else - assert_not_reached(); - - TAKE_PTR(sr_iov); - return 0; - } - - r = safe_atou32(rvalue, &k); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to parse SR-IOV '%s=', ignoring assignment: %s", lvalue, rvalue); - return 0; - } - - if (streq(lvalue, "VLANId")) { - if (k == 0 || k > 4095) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid SR-IOV VLANId: %d", k); - return 0; - } - sr_iov->vlan = k; - } else if (streq(lvalue, "VirtualFunction")) { - if (k >= INT_MAX) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid SR-IOV virtual function: %d", k); - return 0; - } - sr_iov->vf = k; - } else if (streq(lvalue, "QualityOfService")) - sr_iov->qos = k; - else - assert_not_reached(); - - TAKE_PTR(sr_iov); - return 0; -} - -int config_parse_sr_iov_vlan_proto( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL; - Network *network = data; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - r = sr_iov_new_static(network, filename, section_line, &sr_iov); - if (r < 0) - return r; - - if (isempty(rvalue) || streq(rvalue, "802.1Q")) - sr_iov->vlan_proto = ETH_P_8021Q; - else if (streq(rvalue, "802.1ad")) - sr_iov->vlan_proto = ETH_P_8021AD; - else { - log_syntax(unit, LOG_WARNING, filename, line, 0, - "Invalid SR-IOV '%s=', ignoring assignment: %s", lvalue, rvalue); - return 0; - } - - TAKE_PTR(sr_iov); - return 0; -} - -int config_parse_sr_iov_link_state( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL; - Network *network = data; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - r = sr_iov_new_static(network, filename, section_line, &sr_iov); - if (r < 0) - return r; - - /* Unfortunately, SR_IOV_LINK_STATE_DISABLE is 2, not 0. So, we cannot use - * DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN() macro. */ - - if (isempty(rvalue)) { - sr_iov->link_state = _SR_IOV_LINK_STATE_INVALID; - TAKE_PTR(sr_iov); - return 0; - } - - if (streq(rvalue, "auto")) { - sr_iov->link_state = SR_IOV_LINK_STATE_AUTO; - TAKE_PTR(sr_iov); - return 0; - } - - r = parse_boolean(rvalue); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to parse SR-IOV '%s=', ignoring assignment: %s", lvalue, rvalue); - return 0; - } - - sr_iov->link_state = r ? SR_IOV_LINK_STATE_ENABLE : SR_IOV_LINK_STATE_DISABLE; - TAKE_PTR(sr_iov); - return 0; -} - -int config_parse_sr_iov_boolean( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL; - Network *network = data; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - r = sr_iov_new_static(network, filename, section_line, &sr_iov); - if (r < 0) - return r; - - if (isempty(rvalue)) { - if (streq(lvalue, "MACSpoofCheck")) - sr_iov->vf_spoof_check_setting = -1; - else if (streq(lvalue, "QueryReceiveSideScaling")) - sr_iov->query_rss = -1; - else if (streq(lvalue, "Trust")) - sr_iov->trust = -1; - else - assert_not_reached(); - - TAKE_PTR(sr_iov); - return 0; - } - - r = parse_boolean(rvalue); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse '%s=', ignoring: %s", lvalue, rvalue); - return 0; - } - - if (streq(lvalue, "MACSpoofCheck")) - sr_iov->vf_spoof_check_setting = r; - else if (streq(lvalue, "QueryReceiveSideScaling")) - sr_iov->query_rss = r; - else if (streq(lvalue, "Trust")) - sr_iov->trust = r; - else - assert_not_reached(); - - TAKE_PTR(sr_iov); - return 0; -} - -int config_parse_sr_iov_mac( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - _cleanup_(sr_iov_free_or_set_invalidp) SRIOV *sr_iov = NULL; - Network *network = data; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - r = sr_iov_new_static(network, filename, section_line, &sr_iov); - if (r < 0) - return r; - - if (isempty(rvalue)) { - sr_iov->mac = ETHER_ADDR_NULL; - TAKE_PTR(sr_iov); - return 0; - } - - r = parse_ether_addr(rvalue, &sr_iov->mac); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to parse SR-IOV '%s=', ignoring assignment: %s", lvalue, rvalue); - return 0; - } - - TAKE_PTR(sr_iov); - return 0; -} diff --git a/src/network/networkd-sriov.h b/src/network/networkd-sriov.h index 950d1f9c59..4251fddf88 100644 --- a/src/network/networkd-sriov.h +++ b/src/network/networkd-sriov.h @@ -2,45 +2,8 @@ * Copyright © 2020 VMware, Inc. */ #pragma once -#include <linux/if_link.h> +#include "netif-sriov.h" -#include "conf-parser.h" -#include "ether-addr-util.h" -#include "networkd-link.h" -#include "networkd-network.h" -#include "networkd-util.h" +typedef struct Link Link; -typedef enum SRIOVLinkState { - SR_IOV_LINK_STATE_AUTO = IFLA_VF_LINK_STATE_AUTO, - SR_IOV_LINK_STATE_ENABLE = IFLA_VF_LINK_STATE_ENABLE, - SR_IOV_LINK_STATE_DISABLE = IFLA_VF_LINK_STATE_DISABLE, - _SR_IOV_LINK_STATE_MAX, - _SR_IOV_LINK_STATE_INVALID = -EINVAL, -} SRIOVLinkState; - -typedef struct SRIOV { - NetworkConfigSection *section; - Network *network; - - uint32_t vf; /* 0 - 2147483646 */ - uint32_t vlan; /* 0 - 4095, 0 disables VLAN filter */ - uint32_t qos; - uint16_t vlan_proto; /* ETH_P_8021Q or ETH_P_8021AD */ - int vf_spoof_check_setting; - int query_rss; - int trust; - SRIOVLinkState link_state; - struct ether_addr mac; -} SRIOV; - -SRIOV *sr_iov_free(SRIOV *sr_iov); int link_configure_sr_iov(Link *link); -void network_drop_invalid_sr_iov(Network *network); - -DEFINE_NETWORK_SECTION_FUNCTIONS(SRIOV, sr_iov_free); - -CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_uint32); -CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_boolean); -CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_link_state); -CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_vlan_proto); -CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_mac); diff --git a/src/network/networkd-util.c b/src/network/networkd-util.c index ac6f1680ca..1c0987bc33 100644 --- a/src/network/networkd-util.c +++ b/src/network/networkd-util.c @@ -243,50 +243,6 @@ int config_parse_mud_url( return free_and_replace(*url, unescaped); } -static void network_config_hash_func(const NetworkConfigSection *c, struct siphash *state) { - siphash24_compress_string(c->filename, state); - siphash24_compress(&c->line, sizeof(c->line), state); -} - -static int network_config_compare_func(const NetworkConfigSection *x, const NetworkConfigSection *y) { - int r; - - r = strcmp(x->filename, y->filename); - if (r != 0) - return r; - - return CMP(x->line, y->line); -} - -DEFINE_HASH_OPS(network_config_hash_ops, NetworkConfigSection, network_config_hash_func, network_config_compare_func); - -int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s) { - NetworkConfigSection *cs; - - cs = malloc0(offsetof(NetworkConfigSection, filename) + strlen(filename) + 1); - if (!cs) - return -ENOMEM; - - strcpy(cs->filename, filename); - cs->line = line; - - *s = TAKE_PTR(cs); - - return 0; -} - -unsigned hashmap_find_free_section_line(Hashmap *hashmap) { - NetworkConfigSection *cs; - unsigned n = 0; - void *entry; - - HASHMAP_FOREACH_KEY(entry, cs, hashmap) - if (n < cs->line) - n = cs->line; - - return n + 1; -} - int log_link_message_full_errno(Link *link, sd_netlink_message *m, int level, int err, const char *msg) { const char *err_msg = NULL; diff --git a/src/network/networkd-util.h b/src/network/networkd-util.h index d94243855e..0a627588aa 100644 --- a/src/network/networkd-util.h +++ b/src/network/networkd-util.h @@ -13,12 +13,6 @@ typedef struct Link Link; -typedef struct NetworkConfigSection { - unsigned line; - bool invalid; - char filename[]; -} NetworkConfigSection; - typedef enum NetworkConfigSource { NETWORK_CONFIG_SOURCE_FOREIGN, /* configured by kernel */ NETWORK_CONFIG_SOURCE_STATIC, @@ -141,37 +135,6 @@ AddressFamily dhcp_deprecated_address_family_from_string(const char *s) _pure_; const char *dhcp_lease_server_type_to_string(sd_dhcp_lease_server_type_t t) _const_; sd_dhcp_lease_server_type_t dhcp_lease_server_type_from_string(const char *s) _pure_; -static inline NetworkConfigSection* network_config_section_free(NetworkConfigSection *cs) { - return mfree(cs); -} -DEFINE_TRIVIAL_CLEANUP_FUNC(NetworkConfigSection*, network_config_section_free); - -int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s); -extern const struct hash_ops network_config_hash_ops; -unsigned hashmap_find_free_section_line(Hashmap *hashmap); - -static inline bool section_is_invalid(NetworkConfigSection *section) { - /* If this returns false, then it does _not_ mean the section is valid. */ - - if (!section) - return false; - - return section->invalid; -} - -#define DEFINE_NETWORK_SECTION_FUNCTIONS(type, free_func) \ - static inline type* free_func##_or_set_invalid(type *p) { \ - assert(p); \ - \ - if (p->section) \ - p->section->invalid = true; \ - else \ - free_func(p); \ - return NULL; \ - } \ - DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func); \ - DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func##_or_set_invalid); - int log_link_message_full_errno(Link *link, sd_netlink_message *m, int level, int err, const char *msg); #define log_link_message_error_errno(link, m, err, msg) log_link_message_full_errno(link, m, LOG_ERR, err, msg) #define log_link_message_warning_errno(link, m, err, msg) log_link_message_full_errno(link, m, LOG_WARNING, err, msg) diff --git a/src/network/tc/qdisc.c b/src/network/tc/qdisc.c index 995df2fc86..803c999855 100644 --- a/src/network/tc/qdisc.c +++ b/src/network/tc/qdisc.c @@ -77,7 +77,7 @@ static int qdisc_new(QDiscKind kind, QDisc **ret) { } int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, unsigned section_line, QDisc **ret) { - _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; + _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(qdisc_freep) QDisc *qdisc = NULL; TrafficControl *existing; QDisc *q = NULL; @@ -88,7 +88,7 @@ int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, uns assert(filename); assert(section_line > 0); - r = network_config_section_new(filename, section_line, &n); + r = config_section_new(filename, section_line, &n); if (r < 0) return r; @@ -126,7 +126,7 @@ int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, uns qdisc->network = network; qdisc->section = TAKE_PTR(n); - r = ordered_hashmap_ensure_put(&network->tc_by_section, &network_config_hash_ops, qdisc->section, TC(qdisc)); + r = ordered_hashmap_ensure_put(&network->tc_by_section, &config_section_hash_ops, qdisc->section, TC(qdisc)); if (r < 0) return r; @@ -141,7 +141,7 @@ QDisc* qdisc_free(QDisc *qdisc) { if (qdisc->network && qdisc->section) ordered_hashmap_remove(qdisc->network->tc_by_section, qdisc->section); - network_config_section_free(qdisc->section); + config_section_free(qdisc->section); free(qdisc->tca_kind); return mfree(qdisc); diff --git a/src/network/tc/qdisc.h b/src/network/tc/qdisc.h index bf2df146a7..e37c4806e3 100644 --- a/src/network/tc/qdisc.h +++ b/src/network/tc/qdisc.h @@ -37,7 +37,7 @@ typedef enum QDiscKind { typedef struct QDisc { TrafficControl meta; - NetworkConfigSection *section; + ConfigSection *section; Network *network; int family; @@ -80,7 +80,7 @@ int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, uns int qdisc_configure(Link *link, QDisc *qdisc); int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact); -DEFINE_NETWORK_SECTION_FUNCTIONS(QDisc, qdisc_free); +DEFINE_SECTION_CLEANUP_FUNCTIONS(QDisc, qdisc_free); DEFINE_TC_CAST(QDISC, QDisc); diff --git a/src/network/tc/tclass.c b/src/network/tc/tclass.c index 10bffd65c6..6a36ac1c1c 100644 --- a/src/network/tc/tclass.c +++ b/src/network/tc/tclass.c @@ -45,7 +45,7 @@ static int tclass_new(TClassKind kind, TClass **ret) { } int tclass_new_static(TClassKind kind, Network *network, const char *filename, unsigned section_line, TClass **ret) { - _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; + _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(tclass_freep) TClass *tclass = NULL; TrafficControl *existing; int r; @@ -55,7 +55,7 @@ int tclass_new_static(TClassKind kind, Network *network, const char *filename, u assert(filename); assert(section_line > 0); - r = network_config_section_new(filename, section_line, &n); + r = config_section_new(filename, section_line, &n); if (r < 0) return r; @@ -82,7 +82,7 @@ int tclass_new_static(TClassKind kind, Network *network, const char *filename, u tclass->network = network; tclass->section = TAKE_PTR(n); - r = ordered_hashmap_ensure_put(&network->tc_by_section, &network_config_hash_ops, tclass->section, tclass); + r = ordered_hashmap_ensure_put(&network->tc_by_section, &config_section_hash_ops, tclass->section, tclass); if (r < 0) return r; @@ -97,7 +97,7 @@ TClass* tclass_free(TClass *tclass) { if (tclass->network && tclass->section) ordered_hashmap_remove(tclass->network->tc_by_section, tclass->section); - network_config_section_free(tclass->section); + config_section_free(tclass->section); return mfree(tclass); } diff --git a/src/network/tc/tclass.h b/src/network/tc/tclass.h index fc91789f30..5f8016c187 100644 --- a/src/network/tc/tclass.h +++ b/src/network/tc/tclass.h @@ -19,7 +19,7 @@ typedef enum TClassKind { typedef struct TClass { TrafficControl meta; - NetworkConfigSection *section; + ConfigSection *section; Network *network; uint32_t classid; @@ -59,7 +59,7 @@ int tclass_new_static(TClassKind kind, Network *network, const char *filename, u int tclass_configure(Link *link, TClass *tclass); int tclass_section_verify(TClass *tclass); -DEFINE_NETWORK_SECTION_FUNCTIONS(TClass, tclass_free); +DEFINE_SECTION_CLEANUP_FUNCTIONS(TClass, tclass_free); DEFINE_TC_CAST(TCLASS, TClass); diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index 1e1967d7ea..64e67fb6f5 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -573,6 +573,50 @@ int config_parse_many( return config_parse_many_files(conf_files, files, sections, lookup, table, flags, userdata, ret_stats_by_path); } +static void config_section_hash_func(const ConfigSection *c, struct siphash *state) { + siphash24_compress_string(c->filename, state); + siphash24_compress(&c->line, sizeof(c->line), state); +} + +static int config_section_compare_func(const ConfigSection *x, const ConfigSection *y) { + int r; + + r = strcmp(x->filename, y->filename); + if (r != 0) + return r; + + return CMP(x->line, y->line); +} + +DEFINE_HASH_OPS(config_section_hash_ops, ConfigSection, config_section_hash_func, config_section_compare_func); + +int config_section_new(const char *filename, unsigned line, ConfigSection **s) { + ConfigSection *cs; + + cs = malloc0(offsetof(ConfigSection, filename) + strlen(filename) + 1); + if (!cs) + return -ENOMEM; + + strcpy(cs->filename, filename); + cs->line = line; + + *s = TAKE_PTR(cs); + + return 0; +} + +unsigned hashmap_find_free_section_line(Hashmap *hashmap) { + ConfigSection *cs; + unsigned n = 0; + void *entry; + + HASHMAP_FOREACH_KEY(entry, cs, hashmap) + if (n < cs->line) + n = cs->line; + + return n + 1; +} + #define DEFINE_PARSER(type, vartype, conv_func) \ DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value") diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index d686665532..1e03f93bce 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -114,6 +114,43 @@ int config_parse_many( void *userdata, Hashmap **ret_stats_by_path); /* possibly NULL */ +typedef struct ConfigSection { + unsigned line; + bool invalid; + char filename[]; +} ConfigSection; + +static inline ConfigSection* config_section_free(ConfigSection *cs) { + return mfree(cs); +} +DEFINE_TRIVIAL_CLEANUP_FUNC(ConfigSection*, config_section_free); + +int config_section_new(const char *filename, unsigned line, ConfigSection **s); +extern const struct hash_ops config_section_hash_ops; +unsigned hashmap_find_free_section_line(Hashmap *hashmap); + +static inline bool section_is_invalid(ConfigSection *section) { + /* If this returns false, then it does _not_ mean the section is valid. */ + + if (!section) + return false; + + return section->invalid; +} + +#define DEFINE_SECTION_CLEANUP_FUNCTIONS(type, free_func) \ + static inline type* free_func##_or_set_invalid(type *p) { \ + assert(p); \ + \ + if (p->section) \ + p->section->invalid = true; \ + else \ + free_func(p); \ + return NULL; \ + } \ + DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func); \ + DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func##_or_set_invalid); + CONFIG_PARSER_PROTOTYPE(config_parse_int); CONFIG_PARSER_PROTOTYPE(config_parse_unsigned); CONFIG_PARSER_PROTOTYPE(config_parse_long); diff --git a/src/shared/meson.build b/src/shared/meson.build index f58d623f4a..66715e00c3 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -224,6 +224,8 @@ shared_sources = files(''' net-condition.h netif-naming-scheme.c netif-naming-scheme.h + netif-sriov.c + netif-sriov.h netif-util.c netif-util.h nscd-flush.h diff --git a/src/shared/netif-sriov.c b/src/shared/netif-sriov.c new file mode 100644 index 0000000000..720aa65f4c --- /dev/null +++ b/src/shared/netif-sriov.c @@ -0,0 +1,631 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "alloc-util.h" +#include "device-util.h" +#include "netlink-util.h" +#include "netif-sriov.h" +#include "parse-util.h" +#include "set.h" +#include "stdio-util.h" +#include "string-util.h" + +static int sr_iov_new(SRIOV **ret) { + SRIOV *sr_iov; + + assert(ret); + + sr_iov = new(SRIOV, 1); + if (!sr_iov) + return -ENOMEM; + + *sr_iov = (SRIOV) { + .vf = UINT32_MAX, + .vlan_proto = ETH_P_8021Q, + .vf_spoof_check_setting = -1, + .trust = -1, + .query_rss = -1, + .link_state = _SR_IOV_LINK_STATE_INVALID, + }; + + *ret = TAKE_PTR(sr_iov); + + return 0; +} + +static int sr_iov_new_static(OrderedHashmap **sr_iov_by_section, const char *filename, unsigned section_line, SRIOV **ret) { + _cleanup_(config_section_freep) ConfigSection *n = NULL; + _cleanup_(sr_iov_freep) SRIOV *sr_iov = NULL; + SRIOV *existing = NULL; + int r; + + assert(sr_iov_by_section); + assert(filename); + assert(section_line > 0); + assert(ret); + + r = config_section_new(filename, section_line, &n); + if (r < 0) + return r; + + existing = ordered_hashmap_get(*sr_iov_by_section, n); + if (existing) { + *ret = existing; + return 0; + } + + r = sr_iov_new(&sr_iov); + if (r < 0) + return r; + + r = ordered_hashmap_ensure_put(sr_iov_by_section, &config_section_hash_ops, n, sr_iov); + if (r < 0) + return r; + + sr_iov->section = TAKE_PTR(n); + sr_iov->sr_iov_by_section = *sr_iov_by_section; + + *ret = TAKE_PTR(sr_iov); + return 0; +} + +SRIOV *sr_iov_free(SRIOV *sr_iov) { + if (!sr_iov) + return NULL; + + if (sr_iov->sr_iov_by_section && sr_iov->section) + ordered_hashmap_remove(sr_iov->sr_iov_by_section, sr_iov->section); + + config_section_free(sr_iov->section); + + return mfree(sr_iov); +} + +int sr_iov_set_netlink_message(SRIOV *sr_iov, sd_netlink_message *req) { + int r; + + assert(sr_iov); + assert(req); + + r = sd_netlink_message_open_container(req, IFLA_VFINFO_LIST); + if (r < 0) + return r; + + r = sd_netlink_message_open_container(req, IFLA_VF_INFO); + if (r < 0) + return r; + + if (!ether_addr_is_null(&sr_iov->mac)) { + struct ifla_vf_mac ivm = { + .vf = sr_iov->vf, + }; + + memcpy(ivm.mac, &sr_iov->mac, ETH_ALEN); + r = sd_netlink_message_append_data(req, IFLA_VF_MAC, &ivm, sizeof(struct ifla_vf_mac)); + if (r < 0) + return r; + } + + if (sr_iov->vf_spoof_check_setting >= 0) { + struct ifla_vf_spoofchk ivs = { + .vf = sr_iov->vf, + .setting = sr_iov->vf_spoof_check_setting, + }; + + r = sd_netlink_message_append_data(req, IFLA_VF_SPOOFCHK, &ivs, sizeof(struct ifla_vf_spoofchk)); + if (r < 0) + return r; + } + + if (sr_iov->query_rss >= 0) { + struct ifla_vf_rss_query_en ivs = { + .vf = sr_iov->vf, + .setting = sr_iov->query_rss, + }; + + r = sd_netlink_message_append_data(req, IFLA_VF_RSS_QUERY_EN, &ivs, sizeof(struct ifla_vf_rss_query_en)); + if (r < 0) + return r; + } + + if (sr_iov->trust >= 0) { + struct ifla_vf_trust ivt = { + .vf = sr_iov->vf, + .setting = sr_iov->trust, + }; + + r = sd_netlink_message_append_data(req, IFLA_VF_TRUST, &ivt, sizeof(struct ifla_vf_trust)); + if (r < 0) + return r; + } + + if (sr_iov->link_state >= 0) { + struct ifla_vf_link_state ivl = { + .vf = sr_iov->vf, + .link_state = sr_iov->link_state, + }; + + r = sd_netlink_message_append_data(req, IFLA_VF_LINK_STATE, &ivl, sizeof(struct ifla_vf_link_state)); + if (r < 0) + return r; + } + + if (sr_iov->vlan > 0) { + /* Because of padding, first the buffer must be initialized with 0. */ + struct ifla_vf_vlan_info ivvi = {}; + ivvi.vf = sr_iov->vf; + ivvi.vlan = sr_iov->vlan; + ivvi.qos = sr_iov->qos; + ivvi.vlan_proto = htobe16(sr_iov->vlan_proto); + + r = sd_netlink_message_open_container(req, IFLA_VF_VLAN_LIST); + if (r < 0) + return r; + + r = sd_netlink_message_append_data(req, IFLA_VF_VLAN_INFO, &ivvi, sizeof(struct ifla_vf_vlan_info)); + if (r < 0) + return r; + + r = sd_netlink_message_close_container(req); + if (r < 0) + return r; + } + + r = sd_netlink_message_close_container(req); + if (r < 0) + return r; + + r = sd_netlink_message_close_container(req); + if (r < 0) + return r; + + return 0; +} + +int sr_iov_get_num_vfs(sd_device *device, uint32_t *ret) { + const char *str; + uint32_t n; + int r; + + assert(device); + assert(ret); + + r = sd_device_get_sysattr_value(device, "device/sriov_numvfs", &str); + if (r < 0) + return r; + + r = safe_atou32(str, &n); + if (r < 0) + return r; + + *ret = n; + return 0; +} + +int sr_iov_set_num_vfs(sd_device *device, uint32_t num_vfs, OrderedHashmap *sr_iov_by_section) { + char val[DECIMAL_STR_MAX(uint32_t)]; + const char *str; + int r; + + assert(device); + + if (num_vfs == UINT32_MAX) { + uint32_t current_num_vfs; + SRIOV *sr_iov; + + /* If the number of virtual functions is not specified, then use the maximum number of VF + 1. */ + + num_vfs = 0; + ORDERED_HASHMAP_FOREACH(sr_iov, sr_iov_by_section) + num_vfs = MAX(num_vfs, sr_iov->vf + 1); + + if (num_vfs == 0) /* No VF is configured. */ + return 0; + + r = sr_iov_get_num_vfs(device, ¤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; +} diff --git a/src/shared/netif-sriov.h b/src/shared/netif-sriov.h new file mode 100644 index 0000000000..4c85f101c7 --- /dev/null +++ b/src/shared/netif-sriov.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include <linux/if_link.h> + +#include "sd-device.h" + +#include "conf-parser.h" +#include "ether-addr-util.h" +#include "hashmap.h" + +typedef enum SRIOVLinkState { + SR_IOV_LINK_STATE_AUTO = IFLA_VF_LINK_STATE_AUTO, + SR_IOV_LINK_STATE_ENABLE = IFLA_VF_LINK_STATE_ENABLE, + SR_IOV_LINK_STATE_DISABLE = IFLA_VF_LINK_STATE_DISABLE, + _SR_IOV_LINK_STATE_MAX, + _SR_IOV_LINK_STATE_INVALID = -EINVAL, +} SRIOVLinkState; + +typedef struct SRIOV { + ConfigSection *section; + OrderedHashmap *sr_iov_by_section; + + uint32_t vf; /* 0 - 2147483646 */ + uint32_t vlan; /* 0 - 4095, 0 disables VLAN filter */ + uint32_t qos; + uint16_t vlan_proto; /* ETH_P_8021Q or ETH_P_8021AD */ + int vf_spoof_check_setting; + int query_rss; + int trust; + SRIOVLinkState link_state; + struct ether_addr mac; +} SRIOV; + +SRIOV *sr_iov_free(SRIOV *sr_iov); +int sr_iov_set_netlink_message(SRIOV *sr_iov, sd_netlink_message *req); +int sr_iov_get_num_vfs(sd_device *device, uint32_t *ret); +int sr_iov_set_num_vfs(sd_device *device, uint32_t num_vfs, OrderedHashmap *sr_iov_by_section); +int sr_iov_drop_invalid_sections(uint32_t num_vfs, OrderedHashmap *sr_iov_by_section); + +DEFINE_SECTION_CLEANUP_FUNCTIONS(SRIOV, sr_iov_free); + +CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_uint32); +CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_boolean); +CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_link_state); +CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_vlan_proto); +CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_mac); +CONFIG_PARSER_PROTOTYPE(config_parse_sr_iov_num_vfs); diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf index ac7825b00f..7dde4ed59f 100644 --- a/src/udev/net/link-config-gperf.gperf +++ b/src/udev/net/link-config-gperf.gperf @@ -8,6 +8,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") #include "ethtool-util.h" #include "link-config.h" #include "net-condition.h" +#include "netif-sriov.h" #include "socket-util.h" %} struct ConfigPerfItem; @@ -101,3 +102,13 @@ Link.RxMaxCoalescedHighFrames, config_parse_coalesce_u32, Link.TxCoalesceHighSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.tx_coalesce_usecs_high) Link.TxMaxCoalescedHighFrames, config_parse_coalesce_u32, 0, offsetof(LinkConfig, coalesce.tx_max_coalesced_frames_high) Link.CoalescePacketRateSampleIntervalSec, config_parse_coalesce_sec, 0, offsetof(LinkConfig, coalesce.rate_sample_interval) +Link.SR-IOVVirtualFunctions, config_parse_sr_iov_num_vfs, 0, offsetof(LinkConfig, sr_iov_num_vfs) +SR-IOV.VirtualFunction, config_parse_sr_iov_uint32, 0, offsetof(LinkConfig, sr_iov_by_section) +SR-IOV.VLANId, config_parse_sr_iov_uint32, 0, offsetof(LinkConfig, sr_iov_by_section) +SR-IOV.QualityOfService, config_parse_sr_iov_uint32, 0, offsetof(LinkConfig, sr_iov_by_section) +SR-IOV.VLANProtocol, config_parse_sr_iov_vlan_proto, 0, offsetof(LinkConfig, sr_iov_by_section) +SR-IOV.MACSpoofCheck, config_parse_sr_iov_boolean, 0, offsetof(LinkConfig, sr_iov_by_section) +SR-IOV.QueryReceiveSideScaling, config_parse_sr_iov_boolean, 0, offsetof(LinkConfig, sr_iov_by_section) +SR-IOV.Trust, config_parse_sr_iov_boolean, 0, offsetof(LinkConfig, sr_iov_by_section) +SR-IOV.LinkState, config_parse_sr_iov_link_state, 0, offsetof(LinkConfig, sr_iov_by_section) +SR-IOV.MACAddress, config_parse_sr_iov_mac, 0, offsetof(LinkConfig, sr_iov_by_section) diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index 05f0f2e0a6..7e2da6088c 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -22,6 +22,7 @@ #include "log-link.h" #include "memory-util.h" #include "net-condition.h" +#include "netif-sriov.h" #include "netif-util.h" #include "netlink-util.h" #include "parse-util.h" @@ -60,6 +61,8 @@ static LinkConfig* link_config_free(LinkConfig *config) { free(config->wol_password_file); erase_and_free(config->wol_password); + ordered_hashmap_free_with_destructor(config->sr_iov_by_section, sr_iov_free); + return mfree(config); } @@ -247,6 +250,7 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) { .txqueuelen = UINT32_MAX, .coalesce.use_adaptive_rx_coalesce = -1, .coalesce.use_adaptive_tx_coalesce = -1, + .sr_iov_num_vfs = UINT32_MAX, }; for (i = 0; i < ELEMENTSOF(config->features); i++) @@ -257,7 +261,9 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) { STRV_MAKE_CONST(filename), (const char* const*) CONF_PATHS_STRV("systemd/network"), dropin_dirname, - "Match\0Link\0", + "Match\0" + "Link\0" + "SR-IOV\0", config_item_perf_lookup, link_config_gperf_lookup, CONFIG_PARSE_WARN, config, NULL); if (r < 0) @@ -285,6 +291,10 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) { if (r < 0) return r; + r = sr_iov_drop_invalid_sections(config->sr_iov_num_vfs, config->sr_iov_by_section); + if (r < 0) + return r; + log_debug("Parsed configuration file %s", filename); LIST_PREPEND(configs, ctx->configs, TAKE_PTR(config)); @@ -830,6 +840,77 @@ static int link_apply_alternative_names(Link *link, sd_netlink **rtnl) { return 0; } +static int sr_iov_configure(Link *link, sd_netlink **rtnl, SRIOV *sr_iov) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; + int r; + + assert(link); + assert(rtnl); + assert(link->ifindex > 0); + + if (!*rtnl) { + r = sd_netlink_open(rtnl); + if (r < 0) + return r; + } + + r = sd_rtnl_message_new_link(*rtnl, &req, RTM_SETLINK, link->ifindex); + if (r < 0) + return r; + + r = sr_iov_set_netlink_message(sr_iov, req); + if (r < 0) + return r; + + r = sd_netlink_call(*rtnl, req, 0, NULL); + if (r < 0) + return r; + + return 0; +} + +static int link_apply_sr_iov_config(Link *link, sd_netlink **rtnl) { + SRIOV *sr_iov; + uint32_t n; + int r; + + assert(link); + assert(link->config); + assert(link->device); + + r = sr_iov_set_num_vfs(link->device, link->config->sr_iov_num_vfs, link->config->sr_iov_by_section); + if (r < 0) + log_link_warning_errno(link, r, "Failed to set the number of SR-IOV virtual functions, ignoring: %m"); + + if (ordered_hashmap_isempty(link->config->sr_iov_by_section)) + return 0; + + r = sr_iov_get_num_vfs(link->device, &n); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get the number of SR-IOV virtual functions, ignoring [SR-IOV] sections: %m"); + return 0; + } + if (n == 0) { + log_link_warning(link, "No SR-IOV virtual function exists, ignoring [SR-IOV] sections: %m"); + return 0; + } + + ORDERED_HASHMAP_FOREACH(sr_iov, link->config->sr_iov_by_section) { + if (sr_iov->vf >= n) { + log_link_warning(link, "SR-IOV virtual function %"PRIu32" does not exist, ignoring.", sr_iov->vf); + continue; + } + + r = sr_iov_configure(link, rtnl, sr_iov); + if (r < 0) + log_link_warning_errno(link, r, + "Failed to configure SR-IOV virtual function %"PRIu32", ignoring: %m", + sr_iov->vf); + } + + return 0; +} + int link_apply_config(LinkConfigContext *ctx, sd_netlink **rtnl, Link *link) { int r; @@ -861,6 +942,10 @@ int link_apply_config(LinkConfigContext *ctx, sd_netlink **rtnl, Link *link) { if (r < 0) return r; + r = link_apply_sr_iov_config(link, rtnl); + if (r < 0) + return r; + return 0; } diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h index 3b2cd69620..0d1d117f2e 100644 --- a/src/udev/net/link-config.h +++ b/src/udev/net/link-config.h @@ -7,6 +7,7 @@ #include "condition.h" #include "conf-parser.h" #include "ethtool-util.h" +#include "hashmap.h" #include "list.h" #include "net-condition.h" #include "netif-naming-scheme.h" @@ -76,6 +77,9 @@ struct LinkConfig { int autoneg_flow_control; netdev_coalesce_param coalesce; + uint32_t sr_iov_num_vfs; + OrderedHashmap *sr_iov_by_section; + LIST_FIELDS(LinkConfig, configs); }; diff --git a/test/fuzz/fuzz-link-parser/directives.link b/test/fuzz/fuzz-link-parser/directives.link index 7586e35b49..a5773826c5 100644 --- a/test/fuzz/fuzz-link-parser/directives.link +++ b/test/fuzz/fuzz-link-parser/directives.link @@ -80,3 +80,14 @@ RxMaxCoalescedHighFrames= TxCoalesceHighSec= TxMaxCoalescedHighFrames= CoalescePacketRateSampleIntervalSec= +SR-IOVVirtualFunctions= +[SR-IOV] +VirtualFunction= +MACSpoofCheck= +VLANId= +VLANProtocol= +QualityOfService= +QueryReceiveSideScaling= +Trust= +LinkState= +MACAddress= diff --git a/test/test-network/conf/25-sriov-udev.network b/test/test-network/conf/25-sriov-udev.network new file mode 100644 index 0000000000..e9141310b7 --- /dev/null +++ b/test/test-network/conf/25-sriov-udev.network @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Match] +Name=eni99np1 + +[Network] +Address=192.168.100.100/24 +IPv6AcceptRA=no diff --git a/test/test-network/conf/25-sriov.link b/test/test-network/conf/25-sriov.link new file mode 100644 index 0000000000..cc19561306 --- /dev/null +++ b/test/test-network/conf/25-sriov.link @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Match] +Driver=netdevsim + +[Link] +NamePolicy=keep kernel database onboard slot path +AlternativeNamesPolicy=database onboard slot path mac +MACAddressPolicy=persistent + +[SR-IOV] +VirtualFunction=0 +VLANId=5 +VLANProtocol=802.1ad +QualityOfService=1 +MACSpoofCheck=yes +QueryReceiveSideScaling=yes +Trust=yes +LinkState=yes +MACAddress=00:11:22:33:44:55 + +[SR-IOV] +VirtualFunction=1 +VLANId=6 +VLANProtocol=802.1Q +QualityOfService=2 +MACSpoofCheck=no +QueryReceiveSideScaling=no +Trust=no +LinkState=no +MACAddress=00:11:22:33:44:56 + +[SR-IOV] +VirtualFunction=2 +VLANId=7 +QualityOfService=3 +MACSpoofCheck=no +QueryReceiveSideScaling=no +Trust=no +LinkState=auto +MACAddress=00:11:22:33:44:57 diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 2207f36245..0233c4dd1f 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -176,7 +176,7 @@ def expectedFailureIfAlternativeNameIsNotAvailable(): call('ip link add dummy98 type dummy', stderr=subprocess.DEVNULL) rc = call('ip link prop add dev dummy98 altname hogehogehogehogehoge', stderr=subprocess.DEVNULL) if rc == 0: - rc = call('ip link show dev hogehogehogehogehoge', stderr=subprocess.DEVNULL) + rc = call('ip link show dev hogehogehogehogehoge', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) if rc == 0: supported = True @@ -2065,7 +2065,6 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): '25-route-vrf.network', '25-gateway-static.network', '25-gateway-next-static.network', - '25-sriov.network', '25-sysctl-disable-ipv6.network', '25-sysctl.network', '25-test1.network', @@ -3450,32 +3449,6 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): self.assertRegex(output, 'qdisc fq_pie 3a: root') self.assertRegex(output, 'limit 200000p') - @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable() - def test_sriov(self): - call('rmmod netdevsim', stderr=subprocess.DEVNULL) - call('modprobe netdevsim', stderr=subprocess.DEVNULL) - with open('/sys/bus/netdevsim/new_device', mode='w') as f: - f.write('99 1') - - call('udevadm settle') - call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr=subprocess.DEVNULL) - with open('/sys/class/net/eni99np1/device/sriov_numvfs', mode='w') as f: - f.write('3') - - copy_unit_to_networkd_unit_path('25-sriov.network') - start_networkd() - self.wait_online(['eni99np1:routable']) - - output = check_output('ip link show dev eni99np1') - print(output) - self.assertRegex(output, - 'vf 0 .*00:11:22:33:44:55.*vlan 5, qos 1, vlan protocol 802.1ad, spoof checking on, link-state enable, trust on, query_rss on\n *' - 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *' - 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off' - ) - - call('rmmod netdevsim', stderr=subprocess.DEVNULL) - def test_wait_online_ipv4(self): copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-with-ipv6-prefix.network', 'dhcp-client-ipv4-ipv6ra-prefix-client-with-delay.network') start_networkd() @@ -3999,6 +3972,133 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities): print(output) self.assertIn('from all to 8.8.8.8 lookup 100', output) +class NetworkdSRIOVTests(unittest.TestCase, Utilities): + units = [ + '25-sriov-udev.network', + '25-sriov.link', + '25-sriov.network', + ] + + def setUp(self): + stop_networkd(show_logs=False) + call('rmmod netdevsim', stderr=subprocess.DEVNULL) + + def tearDown(self): + remove_unit_from_networkd_path(self.units) + stop_networkd(show_logs=True) + call('rmmod netdevsim', stderr=subprocess.DEVNULL) + + @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable() + def test_sriov(self): + call('modprobe netdevsim', stderr=subprocess.DEVNULL) + + with open('/sys/bus/netdevsim/new_device', mode='w') as f: + f.write('99 1') + + call('udevadm settle') + call('udevadm info -w10s /sys/devices/netdevsim99/net/eni99np1', stderr=subprocess.DEVNULL) + with open('/sys/class/net/eni99np1/device/sriov_numvfs', mode='w') as f: + f.write('3') + + copy_unit_to_networkd_unit_path('25-sriov.network') + start_networkd() + self.wait_online(['eni99np1:routable']) + + output = check_output('ip link show dev eni99np1') + print(output) + self.assertRegex(output, + 'vf 0 .*00:11:22:33:44:55.*vlan 5, qos 1, vlan protocol 802.1ad, spoof checking on, link-state enable, trust on, query_rss on\n *' + 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *' + 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off' + ) + + @expectedFailureIfNetdevsimWithSRIOVIsNotAvailable() + def test_sriov_udev(self): + call('modprobe netdevsim', stderr=subprocess.DEVNULL) + + copy_unit_to_networkd_unit_path('25-sriov.link', '25-sriov-udev.network') + call('udevadm control --reload') + + with open('/sys/bus/netdevsim/new_device', mode='w') as f: + f.write('99 1') + + start_networkd() + self.wait_online(['eni99np1:routable']) + + output = check_output('ip link show dev eni99np1') + print(output) + self.assertRegex(output, + 'vf 0 .*00:11:22:33:44:55.*vlan 5, qos 1, vlan protocol 802.1ad, spoof checking on, link-state enable, trust on, query_rss on\n *' + 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *' + 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off' + ) + self.assertNotIn('vf 3', output) + self.assertNotIn('vf 4', output) + + with open(os.path.join(network_unit_file_path, '25-sriov.link'), mode='a') as f: + f.write('[Link]\nSR-IOVVirtualFunctions=4\n') + + call('udevadm control --reload') + call('udevadm trigger --action add --settle /sys/devices/netdevsim99/net/eni99np1') + + output = check_output('ip link show dev eni99np1') + print(output) + self.assertRegex(output, + 'vf 0 .*00:11:22:33:44:55.*vlan 5, qos 1, vlan protocol 802.1ad, spoof checking on, link-state enable, trust on, query_rss on\n *' + 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *' + 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off\n *' + 'vf 3' + ) + self.assertNotIn('vf 4', output) + + with open(os.path.join(network_unit_file_path, '25-sriov.link'), mode='a') as f: + f.write('[Link]\nSR-IOVVirtualFunctions=\n') + + call('udevadm control --reload') + call('udevadm trigger --action add --settle /sys/devices/netdevsim99/net/eni99np1') + + output = check_output('ip link show dev eni99np1') + print(output) + self.assertRegex(output, + 'vf 0 .*00:11:22:33:44:55.*vlan 5, qos 1, vlan protocol 802.1ad, spoof checking on, link-state enable, trust on, query_rss on\n *' + 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *' + 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off\n *' + 'vf 3' + ) + self.assertNotIn('vf 4', output) + + with open(os.path.join(network_unit_file_path, '25-sriov.link'), mode='a') as f: + f.write('[Link]\nSR-IOVVirtualFunctions=2\n') + + call('udevadm control --reload') + call('udevadm trigger --action add --settle /sys/devices/netdevsim99/net/eni99np1') + + output = check_output('ip link show dev eni99np1') + print(output) + self.assertRegex(output, + 'vf 0 .*00:11:22:33:44:55.*vlan 5, qos 1, vlan protocol 802.1ad, spoof checking on, link-state enable, trust on, query_rss on\n *' + 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off' + ) + self.assertNotIn('vf 2', output) + self.assertNotIn('vf 3', output) + self.assertNotIn('vf 4', output) + + with open(os.path.join(network_unit_file_path, '25-sriov.link'), mode='a') as f: + f.write('[Link]\nSR-IOVVirtualFunctions=\n') + + call('udevadm control --reload') + call('udevadm trigger --action add --settle /sys/devices/netdevsim99/net/eni99np1') + + output = check_output('ip link show dev eni99np1') + print(output) + self.assertRegex(output, + 'vf 0 .*00:11:22:33:44:55.*vlan 5, qos 1, vlan protocol 802.1ad, spoof checking on, link-state enable, trust on, query_rss on\n *' + 'vf 1 .*00:11:22:33:44:56.*vlan 6, qos 2, spoof checking off, link-state disable, trust off, query_rss off\n *' + 'vf 2 .*00:11:22:33:44:57.*vlan 7, qos 3, spoof checking off, link-state auto, trust off, query_rss off' + ) + self.assertNotIn('vf 3', output) + self.assertNotIn('vf 4', output) + class NetworkdLLDPTests(unittest.TestCase, Utilities): links = ['veth99'] |