[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20231008052101.144422-5-akihiko.odaki@daynix.com>
Date: Sun, 8 Oct 2023 14:20:48 +0900
From: Akihiko Odaki <akihiko.odaki@...nix.com>
To:
Cc: Willem de Bruijn <willemdebruijn.kernel@...il.com>,
Jason Wang <jasowang@...hat.com>,
"Michael S. Tsirkin" <mst@...hat.com>,
Xuan Zhuo Shuah Khan <"xuanzhuo@...ux.alibaba.comshuah"@kernel.org>,
netdev@...r.kernel.org, linux-kernel@...r.kernel.org,
kvm@...r.kernel.org, virtualization@...ts.linux-foundation.org,
linux-kselftest@...r.kernel.org, bpf@...r.kernel.org,
davem@...emloft.net, kuba@...nel.org, ast@...nel.org,
daniel@...earbox.net, andrii@...nel.org, kafai@...com,
songliubraving@...com, yhs@...com, john.fastabend@...il.com,
kpsingh@...nel.org, rdunlap@...radead.org, willemb@...gle.com,
gustavoars@...nel.org, herbert@...dor.apana.org.au,
steffen.klassert@...unet.com, nogikh@...gle.com, pablo@...filter.org,
decui@...rosoft.com, cai@....pw, jakub@...udflare.com,
elver@...gle.com, pabeni@...hat.com,
Yuri Benditovich <yuri.benditovich@...nix.com>,
Akihiko Odaki <akihiko.odaki@...nix.com>
Subject: [RFC PATCH 4/7] virtio_net: Add functions for hashing
They are useful to implement VIRTIO_NET_F_RSS and
VIRTIO_NET_F_HASH_REPORT.
Signed-off-by: Akihiko Odaki <akihiko.odaki@...nix.com>
---
include/linux/virtio_net.h | 157 +++++++++++++++++++++++++++++++++++++
1 file changed, 157 insertions(+)
diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
index 7b4dd69555e4..f05781ddc261 100644
--- a/include/linux/virtio_net.h
+++ b/include/linux/virtio_net.h
@@ -7,6 +7,143 @@
#include <uapi/linux/udp.h>
#include <uapi/linux/virtio_net.h>
+struct virtio_net_hash {
+ u32 value;
+ u16 report;
+};
+
+struct virtio_net_toeplitz_state {
+ u32 hash;
+ u32 key_buffer;
+ const u32 *key;
+};
+
+#define VIRTIO_NET_SUPPORTED_HASH_TYPES (VIRTIO_NET_RSS_HASH_TYPE_IPv4 | \
+ VIRTIO_NET_RSS_HASH_TYPE_TCPv4 | \
+ VIRTIO_NET_RSS_HASH_TYPE_UDPv4 | \
+ VIRTIO_NET_RSS_HASH_TYPE_IPv6 | \
+ VIRTIO_NET_RSS_HASH_TYPE_TCPv6 | \
+ VIRTIO_NET_RSS_HASH_TYPE_UDPv6)
+
+static inline void virtio_net_toeplitz(struct virtio_net_toeplitz_state *state,
+ const u32 *input, size_t len)
+{
+ u32 key;
+
+ while (len) {
+ state->key++;
+ key = ntohl(*state->key);
+
+ for (u32 bit = BIT(31); bit; bit >>= 1) {
+ if (*input & bit)
+ state->hash ^= state->key_buffer;
+
+ state->key_buffer =
+ (state->key_buffer << 1) | !!(key & bit);
+ }
+
+ input++;
+ len--;
+ }
+}
+
+static inline u8 virtio_net_hash_key_length(u32 types)
+{
+ size_t len = 0;
+
+ if (types & VIRTIO_NET_HASH_REPORT_IPv4)
+ len = max(len,
+ sizeof(struct flow_dissector_key_ipv4_addrs));
+
+ if (types &
+ (VIRTIO_NET_HASH_REPORT_TCPv4 | VIRTIO_NET_HASH_REPORT_UDPv4))
+ len = max(len,
+ sizeof(struct flow_dissector_key_ipv4_addrs) +
+ sizeof(struct flow_dissector_key_ports));
+
+ if (types & VIRTIO_NET_HASH_REPORT_IPv6)
+ len = max(len,
+ sizeof(struct flow_dissector_key_ipv6_addrs));
+
+ if (types &
+ (VIRTIO_NET_HASH_REPORT_TCPv6 | VIRTIO_NET_HASH_REPORT_UDPv6))
+ len = max(len,
+ sizeof(struct flow_dissector_key_ipv6_addrs) +
+ sizeof(struct flow_dissector_key_ports));
+
+ return 4 + len;
+}
+
+static inline void virtio_net_hash(const struct sk_buff *skb,
+ u32 types, const u32 *key,
+ struct virtio_net_hash *hash)
+{
+ u16 report = VIRTIO_NET_HASH_REPORT_NONE;
+ struct virtio_net_toeplitz_state toeplitz_state = {
+ .key_buffer = ntohl(*key),
+ .key = key
+ };
+ struct flow_keys flow;
+
+ if (!skb_flow_dissect_flow_keys(skb, &flow, 0))
+ return;
+
+ switch (flow.basic.n_proto) {
+ case htons(ETH_P_IP):
+ if (flow.basic.ip_proto == IPPROTO_TCP &&
+ (types & VIRTIO_NET_RSS_HASH_TYPE_TCPv4)) {
+ report = VIRTIO_NET_HASH_REPORT_TCPv4;
+ virtio_net_toeplitz(&toeplitz_state,
+ (u32 *)&flow.addrs.v4addrs,
+ sizeof(flow.addrs.v4addrs) / 4);
+ virtio_net_toeplitz(&toeplitz_state, &flow.ports.ports,
+ 1);
+ } else if (flow.basic.ip_proto == IPPROTO_UDP &&
+ (types & VIRTIO_NET_RSS_HASH_TYPE_UDPv4)) {
+ report = VIRTIO_NET_HASH_REPORT_UDPv4;
+ virtio_net_toeplitz(&toeplitz_state,
+ (u32 *)&flow.addrs.v4addrs,
+ sizeof(flow.addrs.v4addrs) / 4);
+ virtio_net_toeplitz(&toeplitz_state, &flow.ports.ports,
+ 1);
+ } else if (types & VIRTIO_NET_RSS_HASH_TYPE_IPv4) {
+ report = VIRTIO_NET_HASH_REPORT_IPv4;
+ virtio_net_toeplitz(&toeplitz_state,
+ (u32 *)&flow.addrs.v4addrs,
+ sizeof(flow.addrs.v4addrs) / 4);
+ }
+ break;
+
+ case htons(ETH_P_IPV6):
+ if (flow.basic.ip_proto == IPPROTO_TCP &&
+ (types & VIRTIO_NET_RSS_HASH_TYPE_TCPv6)) {
+ report = VIRTIO_NET_HASH_REPORT_TCPv6;
+ virtio_net_toeplitz(&toeplitz_state,
+ (u32 *)&flow.addrs.v6addrs,
+ sizeof(flow.addrs.v6addrs) / 4);
+ virtio_net_toeplitz(&toeplitz_state, &flow.ports.ports,
+ 1);
+ } else if (flow.basic.ip_proto == IPPROTO_UDP &&
+ (types & VIRTIO_NET_RSS_HASH_TYPE_UDPv6)) {
+ report = VIRTIO_NET_HASH_REPORT_UDPv6;
+ virtio_net_toeplitz(&toeplitz_state,
+ (u32 *)&flow.addrs.v6addrs,
+ sizeof(flow.addrs.v6addrs) / 4);
+ virtio_net_toeplitz(&toeplitz_state, &flow.ports.ports,
+ 1);
+ } else if (types & VIRTIO_NET_RSS_HASH_TYPE_IPv6) {
+ report = VIRTIO_NET_HASH_REPORT_IPv6;
+ virtio_net_toeplitz(&toeplitz_state,
+ (u32 *)&flow.addrs.v6addrs,
+ sizeof(flow.addrs.v6addrs) / 4);
+ }
+ break;
+ }
+
+ hash->value = toeplitz_state.hash;
+ hash->report = report;
+}
+
static inline bool virtio_net_hdr_match_proto(__be16 protocol, __u8 gso_type)
{
switch (gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
@@ -216,4 +353,24 @@ static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
return 0;
}
+static inline int virtio_net_hdr_v1_hash_from_skb(const struct sk_buff *skb,
+ struct virtio_net_hdr_v1_hash *hdr,
+ bool has_data_valid,
+ int vlan_hlen,
+ const struct virtio_net_hash *hash)
+{
+ int ret;
+
+ memset(hdr, 0, sizeof(*hdr));
+
+ ret = virtio_net_hdr_from_skb(skb, (struct virtio_net_hdr *)hdr,
+ true, has_data_valid, vlan_hlen);
+ if (!ret) {
+ hdr->hash_value = cpu_to_le32(hash->value);
+ hdr->hash_report = cpu_to_le16(hash->report);
+ }
+
+ return ret;
+}
+
#endif /* _LINUX_VIRTIO_NET_H */
--
2.42.0
Powered by blists - more mailing lists