xref: /linux/drivers/net/ethernet/intel/iavf/iavf_adv_rss.c (revision d30c1683aaecb93d2ab95685dc4300a33d3cea7a)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2021, Intel Corporation. */
3 
4 /* advanced RSS configuration ethtool support for iavf */
5 
6 #include "iavf.h"
7 
8 /**
9  * iavf_fill_adv_rss_ip4_hdr - fill the IPv4 RSS protocol header
10  * @hdr: the virtchnl message protocol header data structure
11  * @hash_flds: the RSS configuration protocol hash fields
12  */
13 static void
14 iavf_fill_adv_rss_ip4_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
15 {
16 	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV4);
17 
18 	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_IPV4_SA)
19 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, SRC);
20 
21 	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_IPV4_DA)
22 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, DST);
23 }
24 
25 /**
26  * iavf_fill_adv_rss_ip6_hdr - fill the IPv6 RSS protocol header
27  * @hdr: the virtchnl message protocol header data structure
28  * @hash_flds: the RSS configuration protocol hash fields
29  */
30 static void
31 iavf_fill_adv_rss_ip6_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
32 {
33 	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV6);
34 
35 	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_IPV6_SA)
36 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, SRC);
37 
38 	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_IPV6_DA)
39 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, DST);
40 }
41 
42 /**
43  * iavf_fill_adv_rss_tcp_hdr - fill the TCP RSS protocol header
44  * @hdr: the virtchnl message protocol header data structure
45  * @hash_flds: the RSS configuration protocol hash fields
46  */
47 static void
48 iavf_fill_adv_rss_tcp_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
49 {
50 	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, TCP);
51 
52 	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_TCP_SRC_PORT)
53 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, SRC_PORT);
54 
55 	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_TCP_DST_PORT)
56 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, DST_PORT);
57 }
58 
59 /**
60  * iavf_fill_adv_rss_udp_hdr - fill the UDP RSS protocol header
61  * @hdr: the virtchnl message protocol header data structure
62  * @hash_flds: the RSS configuration protocol hash fields
63  */
64 static void
65 iavf_fill_adv_rss_udp_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
66 {
67 	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, UDP);
68 
69 	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_UDP_SRC_PORT)
70 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, SRC_PORT);
71 
72 	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_UDP_DST_PORT)
73 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, DST_PORT);
74 }
75 
76 /**
77  * iavf_fill_adv_rss_sctp_hdr - fill the SCTP RSS protocol header
78  * @hdr: the virtchnl message protocol header data structure
79  * @hash_flds: the RSS configuration protocol hash fields
80  */
81 static void
82 iavf_fill_adv_rss_sctp_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
83 {
84 	VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, SCTP);
85 
86 	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_SCTP_SRC_PORT)
87 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, SRC_PORT);
88 
89 	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_SCTP_DST_PORT)
90 		VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, DST_PORT);
91 }
92 
93 /**
94  * iavf_fill_adv_rss_gtp_hdr - Fill GTP-related RSS protocol headers
95  * @proto_hdrs: pointer to the virtchnl protocol headers structure to populate
96  * @packet_hdrs: bitmask of packet header types to configure
97  * @hash_flds: RSS hash field configuration
98  *
99  * This function populates the virtchnl protocol header structure with
100  * appropriate GTP-related header types based on the specified packet_hdrs.
101  * It supports GTPC, GTPU with extension headers, and uplink/downlink PDU
102  * types. For certain GTPU types, it also appends an IPv4 header to enable
103  * hashing on the destination IP address.
104  *
105  * Return: 0 on success or -EOPNOTSUPP if the packet_hdrs value is unsupported.
106  */
107 static int
108 iavf_fill_adv_rss_gtp_hdr(struct virtchnl_proto_hdrs *proto_hdrs,
109 			  u32 packet_hdrs, u64 hash_flds)
110 {
111 	struct virtchnl_proto_hdr *hdr;
112 
113 	hdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1];
114 
115 	switch (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_GTP) {
116 	case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPC_TEID:
117 	case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPC:
118 		VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, GTPC);
119 		break;
120 	case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_EH:
121 		VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, GTPU_EH);
122 		break;
123 	case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_UP:
124 		VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, GTPU_EH_PDU_UP);
125 		hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
126 		iavf_fill_adv_rss_ip4_hdr(hdr, IAVF_ADV_RSS_HASH_FLD_IPV4_DA);
127 		break;
128 	case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_DWN:
129 		VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, GTPU_EH_PDU_DWN);
130 		fallthrough;
131 	case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_IP:
132 		hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
133 		iavf_fill_adv_rss_ip4_hdr(hdr, IAVF_ADV_RSS_HASH_FLD_IPV4_DA);
134 		break;
135 	default:
136 		return -EOPNOTSUPP;
137 	}
138 
139 	return 0;
140 }
141 
142 /**
143  * iavf_fill_adv_rss_cfg_msg - fill the RSS configuration into virtchnl message
144  * @rss_cfg: the virtchnl message to be filled with RSS configuration setting
145  * @packet_hdrs: the RSS configuration protocol header types
146  * @hash_flds: the RSS configuration protocol hash fields
147  * @symm: if true, symmetric hash is required
148  *
149  * Returns 0 if the RSS configuration virtchnl message is filled successfully
150  */
151 int
152 iavf_fill_adv_rss_cfg_msg(struct virtchnl_rss_cfg *rss_cfg,
153 			  u32 packet_hdrs, u64 hash_flds, bool symm)
154 {
155 	const u32 packet_l3_hdrs = packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_L3;
156 	const u32 packet_l4_hdrs = packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_L4;
157 	struct virtchnl_proto_hdrs *proto_hdrs = &rss_cfg->proto_hdrs;
158 	struct virtchnl_proto_hdr *hdr;
159 
160 	if (symm)
161 		rss_cfg->rss_algorithm = VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC;
162 	else
163 		rss_cfg->rss_algorithm = VIRTCHNL_RSS_ALG_TOEPLITZ_ASYMMETRIC;
164 
165 	proto_hdrs->tunnel_level = 0;	/* always outer layer */
166 
167 	if (packet_l3_hdrs) {
168 		hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
169 		switch (packet_l3_hdrs) {
170 		case IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4:
171 			iavf_fill_adv_rss_ip4_hdr(hdr, hash_flds);
172 			break;
173 		case IAVF_ADV_RSS_FLOW_SEG_HDR_IPV6:
174 			iavf_fill_adv_rss_ip6_hdr(hdr, hash_flds);
175 			break;
176 		default:
177 			return -EINVAL;
178 		}
179 	}
180 
181 	if (packet_l4_hdrs) {
182 		hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
183 		switch (packet_l4_hdrs) {
184 		case IAVF_ADV_RSS_FLOW_SEG_HDR_TCP:
185 			iavf_fill_adv_rss_tcp_hdr(hdr, hash_flds);
186 			break;
187 		case IAVF_ADV_RSS_FLOW_SEG_HDR_UDP:
188 			iavf_fill_adv_rss_udp_hdr(hdr, hash_flds);
189 			break;
190 		case IAVF_ADV_RSS_FLOW_SEG_HDR_SCTP:
191 			iavf_fill_adv_rss_sctp_hdr(hdr, hash_flds);
192 			break;
193 		default:
194 			return -EINVAL;
195 		}
196 	}
197 
198 	if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_GTP) {
199 		hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
200 		if (iavf_fill_adv_rss_gtp_hdr(proto_hdrs, packet_hdrs, hash_flds))
201 			return -EINVAL;
202 	}
203 
204 	return 0;
205 }
206 
207 /**
208  * iavf_find_adv_rss_cfg_by_hdrs - find RSS configuration with header type
209  * @adapter: pointer to the VF adapter structure
210  * @packet_hdrs: protocol header type to find.
211  *
212  * Returns pointer to advance RSS configuration if found or null
213  */
214 struct iavf_adv_rss *
215 iavf_find_adv_rss_cfg_by_hdrs(struct iavf_adapter *adapter, u32 packet_hdrs)
216 {
217 	struct iavf_adv_rss *rss;
218 
219 	list_for_each_entry(rss, &adapter->adv_rss_list_head, list)
220 		if (rss->packet_hdrs == packet_hdrs)
221 			return rss;
222 
223 	return NULL;
224 }
225 
226 /**
227  * iavf_print_adv_rss_cfg
228  * @adapter: pointer to the VF adapter structure
229  * @rss: pointer to the advance RSS configuration to print
230  * @action: the string description about how to handle the RSS
231  * @result: the string description about the virtchnl result
232  *
233  * Print the advance RSS configuration
234  **/
235 void
236 iavf_print_adv_rss_cfg(struct iavf_adapter *adapter, struct iavf_adv_rss *rss,
237 		       const char *action, const char *result)
238 {
239 	u32 packet_hdrs = rss->packet_hdrs;
240 	u64 hash_flds = rss->hash_flds;
241 	static char hash_opt[300];
242 	const char *proto;
243 
244 	if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_TCP)
245 		proto = "TCP";
246 	else if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_UDP)
247 		proto = "UDP";
248 	else if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_SCTP)
249 		proto = "SCTP";
250 	else if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_GTP)
251 		proto = "GTP";
252 	else
253 		return;
254 
255 	memset(hash_opt, 0, sizeof(hash_opt));
256 
257 	strcat(hash_opt, proto);
258 	if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4)
259 		strcat(hash_opt, "v4 ");
260 	else
261 		strcat(hash_opt, "v6 ");
262 
263 	if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_IPV4_SA |
264 			 IAVF_ADV_RSS_HASH_FLD_IPV6_SA))
265 		strcat(hash_opt, "IP SA,");
266 	if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_IPV4_DA |
267 			 IAVF_ADV_RSS_HASH_FLD_IPV6_DA))
268 		strcat(hash_opt, "IP DA,");
269 	if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_TCP_SRC_PORT |
270 			 IAVF_ADV_RSS_HASH_FLD_UDP_SRC_PORT |
271 			 IAVF_ADV_RSS_HASH_FLD_SCTP_SRC_PORT))
272 		strcat(hash_opt, "src port,");
273 	if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_TCP_DST_PORT |
274 			 IAVF_ADV_RSS_HASH_FLD_UDP_DST_PORT |
275 			 IAVF_ADV_RSS_HASH_FLD_SCTP_DST_PORT))
276 		strcat(hash_opt, "dst port,");
277 	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_GTPC_TEID)
278 		strcat(hash_opt, "gtp-c,");
279 	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_GTPU_IP_TEID)
280 		strcat(hash_opt, "gtp-u ip,");
281 	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_GTPU_EH_TEID)
282 		strcat(hash_opt, "gtp-u ext,");
283 	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_GTPU_UP_TEID)
284 		strcat(hash_opt, "gtp-u ul,");
285 	if (hash_flds & IAVF_ADV_RSS_HASH_FLD_GTPU_DWN_TEID)
286 		strcat(hash_opt, "gtp-u dl,");
287 
288 	if (!action)
289 		action = "";
290 
291 	if (!result)
292 		result = "";
293 
294 	dev_info(&adapter->pdev->dev, "%s %s %s\n", action, hash_opt, result);
295 }
296