1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 /* Google virtual Ethernet (gve) driver
3 *
4 * Copyright (C) 2015-2024 Google LLC
5 */
6
7 #include "gve.h"
8 #include "gve_adminq.h"
9
10 static
gve_fill_ethtool_flow_spec(struct ethtool_rx_flow_spec * fsp,struct gve_adminq_queried_flow_rule * rule)11 int gve_fill_ethtool_flow_spec(struct ethtool_rx_flow_spec *fsp,
12 struct gve_adminq_queried_flow_rule *rule)
13 {
14 struct gve_adminq_flow_rule *flow_rule = &rule->flow_rule;
15 static const u16 flow_type_lut[] = {
16 [GVE_FLOW_TYPE_TCPV4] = TCP_V4_FLOW,
17 [GVE_FLOW_TYPE_UDPV4] = UDP_V4_FLOW,
18 [GVE_FLOW_TYPE_SCTPV4] = SCTP_V4_FLOW,
19 [GVE_FLOW_TYPE_AHV4] = AH_V4_FLOW,
20 [GVE_FLOW_TYPE_ESPV4] = ESP_V4_FLOW,
21 [GVE_FLOW_TYPE_TCPV6] = TCP_V6_FLOW,
22 [GVE_FLOW_TYPE_UDPV6] = UDP_V6_FLOW,
23 [GVE_FLOW_TYPE_SCTPV6] = SCTP_V6_FLOW,
24 [GVE_FLOW_TYPE_AHV6] = AH_V6_FLOW,
25 [GVE_FLOW_TYPE_ESPV6] = ESP_V6_FLOW,
26 };
27
28 if (be16_to_cpu(flow_rule->flow_type) >= ARRAY_SIZE(flow_type_lut))
29 return -EINVAL;
30
31 fsp->flow_type = flow_type_lut[be16_to_cpu(flow_rule->flow_type)];
32
33 memset(&fsp->h_u, 0, sizeof(fsp->h_u));
34 memset(&fsp->h_ext, 0, sizeof(fsp->h_ext));
35 memset(&fsp->m_u, 0, sizeof(fsp->m_u));
36 memset(&fsp->m_ext, 0, sizeof(fsp->m_ext));
37
38 switch (fsp->flow_type) {
39 case TCP_V4_FLOW:
40 case UDP_V4_FLOW:
41 case SCTP_V4_FLOW:
42 fsp->h_u.tcp_ip4_spec.ip4src = flow_rule->key.src_ip[0];
43 fsp->h_u.tcp_ip4_spec.ip4dst = flow_rule->key.dst_ip[0];
44 fsp->h_u.tcp_ip4_spec.psrc = flow_rule->key.src_port;
45 fsp->h_u.tcp_ip4_spec.pdst = flow_rule->key.dst_port;
46 fsp->h_u.tcp_ip4_spec.tos = flow_rule->key.tos;
47 fsp->m_u.tcp_ip4_spec.ip4src = flow_rule->mask.src_ip[0];
48 fsp->m_u.tcp_ip4_spec.ip4dst = flow_rule->mask.dst_ip[0];
49 fsp->m_u.tcp_ip4_spec.psrc = flow_rule->mask.src_port;
50 fsp->m_u.tcp_ip4_spec.pdst = flow_rule->mask.dst_port;
51 fsp->m_u.tcp_ip4_spec.tos = flow_rule->mask.tos;
52 break;
53 case AH_V4_FLOW:
54 case ESP_V4_FLOW:
55 fsp->h_u.ah_ip4_spec.ip4src = flow_rule->key.src_ip[0];
56 fsp->h_u.ah_ip4_spec.ip4dst = flow_rule->key.dst_ip[0];
57 fsp->h_u.ah_ip4_spec.spi = flow_rule->key.spi;
58 fsp->h_u.ah_ip4_spec.tos = flow_rule->key.tos;
59 fsp->m_u.ah_ip4_spec.ip4src = flow_rule->mask.src_ip[0];
60 fsp->m_u.ah_ip4_spec.ip4dst = flow_rule->mask.dst_ip[0];
61 fsp->m_u.ah_ip4_spec.spi = flow_rule->mask.spi;
62 fsp->m_u.ah_ip4_spec.tos = flow_rule->mask.tos;
63 break;
64 case TCP_V6_FLOW:
65 case UDP_V6_FLOW:
66 case SCTP_V6_FLOW:
67 memcpy(fsp->h_u.tcp_ip6_spec.ip6src, &flow_rule->key.src_ip,
68 sizeof(struct in6_addr));
69 memcpy(fsp->h_u.tcp_ip6_spec.ip6dst, &flow_rule->key.dst_ip,
70 sizeof(struct in6_addr));
71 fsp->h_u.tcp_ip6_spec.psrc = flow_rule->key.src_port;
72 fsp->h_u.tcp_ip6_spec.pdst = flow_rule->key.dst_port;
73 fsp->h_u.tcp_ip6_spec.tclass = flow_rule->key.tclass;
74 memcpy(fsp->m_u.tcp_ip6_spec.ip6src, &flow_rule->mask.src_ip,
75 sizeof(struct in6_addr));
76 memcpy(fsp->m_u.tcp_ip6_spec.ip6dst, &flow_rule->mask.dst_ip,
77 sizeof(struct in6_addr));
78 fsp->m_u.tcp_ip6_spec.psrc = flow_rule->mask.src_port;
79 fsp->m_u.tcp_ip6_spec.pdst = flow_rule->mask.dst_port;
80 fsp->m_u.tcp_ip6_spec.tclass = flow_rule->mask.tclass;
81 break;
82 case AH_V6_FLOW:
83 case ESP_V6_FLOW:
84 memcpy(fsp->h_u.ah_ip6_spec.ip6src, &flow_rule->key.src_ip,
85 sizeof(struct in6_addr));
86 memcpy(fsp->h_u.ah_ip6_spec.ip6dst, &flow_rule->key.dst_ip,
87 sizeof(struct in6_addr));
88 fsp->h_u.ah_ip6_spec.spi = flow_rule->key.spi;
89 fsp->h_u.ah_ip6_spec.tclass = flow_rule->key.tclass;
90 memcpy(fsp->m_u.ah_ip6_spec.ip6src, &flow_rule->mask.src_ip,
91 sizeof(struct in6_addr));
92 memcpy(fsp->m_u.ah_ip6_spec.ip6dst, &flow_rule->mask.dst_ip,
93 sizeof(struct in6_addr));
94 fsp->m_u.ah_ip6_spec.spi = flow_rule->mask.spi;
95 fsp->m_u.ah_ip6_spec.tclass = flow_rule->mask.tclass;
96 break;
97 default:
98 return -EINVAL;
99 }
100
101 fsp->ring_cookie = be16_to_cpu(flow_rule->action);
102
103 return 0;
104 }
105
gve_generate_flow_rule(struct gve_priv * priv,struct ethtool_rx_flow_spec * fsp,struct gve_adminq_flow_rule * rule)106 static int gve_generate_flow_rule(struct gve_priv *priv, struct ethtool_rx_flow_spec *fsp,
107 struct gve_adminq_flow_rule *rule)
108 {
109 static const u16 flow_type_lut[] = {
110 [TCP_V4_FLOW] = GVE_FLOW_TYPE_TCPV4,
111 [UDP_V4_FLOW] = GVE_FLOW_TYPE_UDPV4,
112 [SCTP_V4_FLOW] = GVE_FLOW_TYPE_SCTPV4,
113 [AH_V4_FLOW] = GVE_FLOW_TYPE_AHV4,
114 [ESP_V4_FLOW] = GVE_FLOW_TYPE_ESPV4,
115 [TCP_V6_FLOW] = GVE_FLOW_TYPE_TCPV6,
116 [UDP_V6_FLOW] = GVE_FLOW_TYPE_UDPV6,
117 [SCTP_V6_FLOW] = GVE_FLOW_TYPE_SCTPV6,
118 [AH_V6_FLOW] = GVE_FLOW_TYPE_AHV6,
119 [ESP_V6_FLOW] = GVE_FLOW_TYPE_ESPV6,
120 };
121 u32 flow_type;
122
123 if (fsp->ring_cookie == RX_CLS_FLOW_DISC)
124 return -EOPNOTSUPP;
125
126 if (fsp->ring_cookie >= priv->rx_cfg.num_queues)
127 return -EINVAL;
128
129 rule->action = cpu_to_be16(fsp->ring_cookie);
130
131 flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
132 if (!flow_type || flow_type >= ARRAY_SIZE(flow_type_lut))
133 return -EINVAL;
134
135 rule->flow_type = cpu_to_be16(flow_type_lut[flow_type]);
136
137 switch (flow_type) {
138 case TCP_V4_FLOW:
139 case UDP_V4_FLOW:
140 case SCTP_V4_FLOW:
141 rule->key.src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src;
142 rule->key.dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst;
143 rule->key.src_port = fsp->h_u.tcp_ip4_spec.psrc;
144 rule->key.dst_port = fsp->h_u.tcp_ip4_spec.pdst;
145 rule->mask.src_ip[0] = fsp->m_u.tcp_ip4_spec.ip4src;
146 rule->mask.dst_ip[0] = fsp->m_u.tcp_ip4_spec.ip4dst;
147 rule->mask.src_port = fsp->m_u.tcp_ip4_spec.psrc;
148 rule->mask.dst_port = fsp->m_u.tcp_ip4_spec.pdst;
149 break;
150 case AH_V4_FLOW:
151 case ESP_V4_FLOW:
152 rule->key.src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src;
153 rule->key.dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst;
154 rule->key.spi = fsp->h_u.ah_ip4_spec.spi;
155 rule->mask.src_ip[0] = fsp->m_u.tcp_ip4_spec.ip4src;
156 rule->mask.dst_ip[0] = fsp->m_u.tcp_ip4_spec.ip4dst;
157 rule->mask.spi = fsp->m_u.ah_ip4_spec.spi;
158 break;
159 case TCP_V6_FLOW:
160 case UDP_V6_FLOW:
161 case SCTP_V6_FLOW:
162 memcpy(&rule->key.src_ip, fsp->h_u.tcp_ip6_spec.ip6src,
163 sizeof(struct in6_addr));
164 memcpy(&rule->key.dst_ip, fsp->h_u.tcp_ip6_spec.ip6dst,
165 sizeof(struct in6_addr));
166 rule->key.src_port = fsp->h_u.tcp_ip6_spec.psrc;
167 rule->key.dst_port = fsp->h_u.tcp_ip6_spec.pdst;
168 memcpy(&rule->mask.src_ip, fsp->m_u.tcp_ip6_spec.ip6src,
169 sizeof(struct in6_addr));
170 memcpy(&rule->mask.dst_ip, fsp->m_u.tcp_ip6_spec.ip6dst,
171 sizeof(struct in6_addr));
172 rule->mask.src_port = fsp->m_u.tcp_ip6_spec.psrc;
173 rule->mask.dst_port = fsp->m_u.tcp_ip6_spec.pdst;
174 break;
175 case AH_V6_FLOW:
176 case ESP_V6_FLOW:
177 memcpy(&rule->key.src_ip, fsp->h_u.usr_ip6_spec.ip6src,
178 sizeof(struct in6_addr));
179 memcpy(&rule->key.dst_ip, fsp->h_u.usr_ip6_spec.ip6dst,
180 sizeof(struct in6_addr));
181 rule->key.spi = fsp->h_u.ah_ip6_spec.spi;
182 memcpy(&rule->mask.src_ip, fsp->m_u.usr_ip6_spec.ip6src,
183 sizeof(struct in6_addr));
184 memcpy(&rule->mask.dst_ip, fsp->m_u.usr_ip6_spec.ip6dst,
185 sizeof(struct in6_addr));
186 rule->key.spi = fsp->h_u.ah_ip6_spec.spi;
187 break;
188 default:
189 /* not doing un-parsed flow types */
190 return -EINVAL;
191 }
192
193 return 0;
194 }
195
gve_get_flow_rule_entry(struct gve_priv * priv,struct ethtool_rxnfc * cmd)196 int gve_get_flow_rule_entry(struct gve_priv *priv, struct ethtool_rxnfc *cmd)
197 {
198 struct gve_adminq_queried_flow_rule *rules_cache = priv->flow_rules_cache.rules_cache;
199 struct ethtool_rx_flow_spec *fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
200 u32 *cache_num = &priv->flow_rules_cache.rules_cache_num;
201 struct gve_adminq_queried_flow_rule *rule = NULL;
202 int err = 0;
203 u32 i;
204
205 if (!priv->max_flow_rules)
206 return -EOPNOTSUPP;
207
208 if (!priv->flow_rules_cache.rules_cache_synced ||
209 fsp->location < be32_to_cpu(rules_cache[0].location) ||
210 fsp->location > be32_to_cpu(rules_cache[*cache_num - 1].location)) {
211 err = gve_adminq_query_flow_rules(priv, GVE_FLOW_RULE_QUERY_RULES, fsp->location);
212 if (err)
213 return err;
214
215 priv->flow_rules_cache.rules_cache_synced = true;
216 }
217
218 for (i = 0; i < *cache_num; i++) {
219 if (fsp->location == be32_to_cpu(rules_cache[i].location)) {
220 rule = &rules_cache[i];
221 break;
222 }
223 }
224
225 if (!rule)
226 return -EINVAL;
227
228 err = gve_fill_ethtool_flow_spec(fsp, rule);
229
230 return err;
231 }
232
gve_get_flow_rule_ids(struct gve_priv * priv,struct ethtool_rxnfc * cmd,u32 * rule_locs)233 int gve_get_flow_rule_ids(struct gve_priv *priv, struct ethtool_rxnfc *cmd, u32 *rule_locs)
234 {
235 __be32 *rule_ids_cache = priv->flow_rules_cache.rule_ids_cache;
236 u32 *cache_num = &priv->flow_rules_cache.rule_ids_cache_num;
237 u32 starting_rule_id = 0;
238 u32 i = 0, j = 0;
239 int err = 0;
240
241 if (!priv->max_flow_rules)
242 return -EOPNOTSUPP;
243
244 do {
245 err = gve_adminq_query_flow_rules(priv, GVE_FLOW_RULE_QUERY_IDS,
246 starting_rule_id);
247 if (err)
248 return err;
249
250 for (i = 0; i < *cache_num; i++) {
251 if (j >= cmd->rule_cnt)
252 return -EMSGSIZE;
253
254 rule_locs[j++] = be32_to_cpu(rule_ids_cache[i]);
255 starting_rule_id = be32_to_cpu(rule_ids_cache[i]) + 1;
256 }
257 } while (*cache_num != 0);
258 cmd->data = priv->max_flow_rules;
259
260 return err;
261 }
262
gve_add_flow_rule(struct gve_priv * priv,struct ethtool_rxnfc * cmd)263 int gve_add_flow_rule(struct gve_priv *priv, struct ethtool_rxnfc *cmd)
264 {
265 struct ethtool_rx_flow_spec *fsp = &cmd->fs;
266 struct gve_adminq_flow_rule *rule = NULL;
267 int err;
268
269 if (!priv->max_flow_rules)
270 return -EOPNOTSUPP;
271
272 rule = kvzalloc(sizeof(*rule), GFP_KERNEL);
273 if (!rule)
274 return -ENOMEM;
275
276 err = gve_generate_flow_rule(priv, fsp, rule);
277 if (err)
278 goto out;
279
280 err = gve_adminq_add_flow_rule(priv, rule, fsp->location);
281
282 out:
283 kvfree(rule);
284 if (err)
285 dev_err(&priv->pdev->dev, "Failed to add the flow rule: %u", fsp->location);
286
287 return err;
288 }
289
gve_del_flow_rule(struct gve_priv * priv,struct ethtool_rxnfc * cmd)290 int gve_del_flow_rule(struct gve_priv *priv, struct ethtool_rxnfc *cmd)
291 {
292 struct ethtool_rx_flow_spec *fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
293
294 if (!priv->max_flow_rules)
295 return -EOPNOTSUPP;
296
297 return gve_adminq_del_flow_rule(priv, fsp->location);
298 }
299