1// SPDX-License-Identifier: GPL-2.0+
2/* Microchip VCAP TC
3 *
4 * Copyright (c) 2023 Microchip Technology Inc. and its subsidiaries.
5 */
6
7#include <net/flow_offload.h>
8#include <net/ipv6.h>
9#include <net/tcp.h>
10
11#include "vcap_api_client.h"
12#include "vcap_tc.h"
13
14enum vcap_is2_arp_opcode {
15 VCAP_IS2_ARP_REQUEST,
16 VCAP_IS2_ARP_REPLY,
17 VCAP_IS2_RARP_REQUEST,
18 VCAP_IS2_RARP_REPLY,
19};
20
21enum vcap_arp_opcode {
22 VCAP_ARP_OP_RESERVED,
23 VCAP_ARP_OP_REQUEST,
24 VCAP_ARP_OP_REPLY,
25};
26
27int vcap_tc_flower_handler_ethaddr_usage(struct vcap_tc_flower_parse_usage *st)
28{
29 enum vcap_key_field smac_key = VCAP_KF_L2_SMAC;
30 enum vcap_key_field dmac_key = VCAP_KF_L2_DMAC;
31 struct flow_match_eth_addrs match;
32 struct vcap_u48_key smac, dmac;
33 int err = 0;
34
35 flow_rule_match_eth_addrs(rule: st->frule, out: &match);
36
37 if (!is_zero_ether_addr(addr: match.mask->src)) {
38 vcap_netbytes_copy(dst: smac.value, src: match.key->src, ETH_ALEN);
39 vcap_netbytes_copy(dst: smac.mask, src: match.mask->src, ETH_ALEN);
40 err = vcap_rule_add_key_u48(rule: st->vrule, key: smac_key, fieldval: &smac);
41 if (err)
42 goto out;
43 }
44
45 if (!is_zero_ether_addr(addr: match.mask->dst)) {
46 vcap_netbytes_copy(dst: dmac.value, src: match.key->dst, ETH_ALEN);
47 vcap_netbytes_copy(dst: dmac.mask, src: match.mask->dst, ETH_ALEN);
48 err = vcap_rule_add_key_u48(rule: st->vrule, key: dmac_key, fieldval: &dmac);
49 if (err)
50 goto out;
51 }
52
53 st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS);
54
55 return err;
56
57out:
58 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "eth_addr parse error");
59 return err;
60}
61EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_ethaddr_usage);
62
63int vcap_tc_flower_handler_ipv4_usage(struct vcap_tc_flower_parse_usage *st)
64{
65 int err = 0;
66
67 if (st->l3_proto == ETH_P_IP) {
68 struct flow_match_ipv4_addrs mt;
69
70 flow_rule_match_ipv4_addrs(rule: st->frule, out: &mt);
71 if (mt.mask->src) {
72 err = vcap_rule_add_key_u32(rule: st->vrule,
73 key: VCAP_KF_L3_IP4_SIP,
74 be32_to_cpu(mt.key->src),
75 be32_to_cpu(mt.mask->src));
76 if (err)
77 goto out;
78 }
79 if (mt.mask->dst) {
80 err = vcap_rule_add_key_u32(rule: st->vrule,
81 key: VCAP_KF_L3_IP4_DIP,
82 be32_to_cpu(mt.key->dst),
83 be32_to_cpu(mt.mask->dst));
84 if (err)
85 goto out;
86 }
87 }
88
89 st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS);
90
91 return err;
92
93out:
94 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv4_addr parse error");
95 return err;
96}
97EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_ipv4_usage);
98
99int vcap_tc_flower_handler_ipv6_usage(struct vcap_tc_flower_parse_usage *st)
100{
101 int err = 0;
102
103 if (st->l3_proto == ETH_P_IPV6) {
104 struct flow_match_ipv6_addrs mt;
105 struct vcap_u128_key sip;
106 struct vcap_u128_key dip;
107
108 flow_rule_match_ipv6_addrs(rule: st->frule, out: &mt);
109 /* Check if address masks are non-zero */
110 if (!ipv6_addr_any(a: &mt.mask->src)) {
111 vcap_netbytes_copy(dst: sip.value, src: mt.key->src.s6_addr, count: 16);
112 vcap_netbytes_copy(dst: sip.mask, src: mt.mask->src.s6_addr, count: 16);
113 err = vcap_rule_add_key_u128(rule: st->vrule,
114 key: VCAP_KF_L3_IP6_SIP, fieldval: &sip);
115 if (err)
116 goto out;
117 }
118 if (!ipv6_addr_any(a: &mt.mask->dst)) {
119 vcap_netbytes_copy(dst: dip.value, src: mt.key->dst.s6_addr, count: 16);
120 vcap_netbytes_copy(dst: dip.mask, src: mt.mask->dst.s6_addr, count: 16);
121 err = vcap_rule_add_key_u128(rule: st->vrule,
122 key: VCAP_KF_L3_IP6_DIP, fieldval: &dip);
123 if (err)
124 goto out;
125 }
126 }
127 st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS);
128 return err;
129out:
130 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv6_addr parse error");
131 return err;
132}
133EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_ipv6_usage);
134
135int vcap_tc_flower_handler_portnum_usage(struct vcap_tc_flower_parse_usage *st)
136{
137 struct flow_match_ports mt;
138 u16 value, mask;
139 int err = 0;
140
141 flow_rule_match_ports(rule: st->frule, out: &mt);
142
143 if (mt.mask->src) {
144 value = be16_to_cpu(mt.key->src);
145 mask = be16_to_cpu(mt.mask->src);
146 err = vcap_rule_add_key_u32(rule: st->vrule, key: VCAP_KF_L4_SPORT, value,
147 mask);
148 if (err)
149 goto out;
150 }
151
152 if (mt.mask->dst) {
153 value = be16_to_cpu(mt.key->dst);
154 mask = be16_to_cpu(mt.mask->dst);
155 err = vcap_rule_add_key_u32(rule: st->vrule, key: VCAP_KF_L4_DPORT, value,
156 mask);
157 if (err)
158 goto out;
159 }
160
161 st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_PORTS);
162
163 return err;
164
165out:
166 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "port parse error");
167 return err;
168}
169EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_portnum_usage);
170
171int vcap_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage *st)
172{
173 enum vcap_key_field vid_key = VCAP_KF_8021Q_VID0;
174 enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP0;
175 struct flow_match_vlan mt;
176 u16 tpid;
177 int err;
178
179 flow_rule_match_cvlan(rule: st->frule, out: &mt);
180
181 tpid = be16_to_cpu(mt.key->vlan_tpid);
182
183 if (tpid == ETH_P_8021Q) {
184 vid_key = VCAP_KF_8021Q_VID1;
185 pcp_key = VCAP_KF_8021Q_PCP1;
186 }
187
188 if (mt.mask->vlan_id) {
189 err = vcap_rule_add_key_u32(rule: st->vrule, key: vid_key,
190 value: mt.key->vlan_id,
191 mask: mt.mask->vlan_id);
192 if (err)
193 goto out;
194 }
195
196 if (mt.mask->vlan_priority) {
197 err = vcap_rule_add_key_u32(rule: st->vrule, key: pcp_key,
198 value: mt.key->vlan_priority,
199 mask: mt.mask->vlan_priority);
200 if (err)
201 goto out;
202 }
203
204 st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_CVLAN);
205
206 return 0;
207out:
208 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "cvlan parse error");
209 return err;
210}
211EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_cvlan_usage);
212
213int vcap_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st,
214 enum vcap_key_field vid_key,
215 enum vcap_key_field pcp_key)
216{
217 struct flow_match_vlan mt;
218 int err;
219
220 flow_rule_match_vlan(rule: st->frule, out: &mt);
221
222 if (mt.mask->vlan_id) {
223 err = vcap_rule_add_key_u32(rule: st->vrule, key: vid_key,
224 value: mt.key->vlan_id,
225 mask: mt.mask->vlan_id);
226 if (err)
227 goto out;
228 }
229
230 if (mt.mask->vlan_priority) {
231 err = vcap_rule_add_key_u32(rule: st->vrule, key: pcp_key,
232 value: mt.key->vlan_priority,
233 mask: mt.mask->vlan_priority);
234 if (err)
235 goto out;
236 }
237
238 if (mt.mask->vlan_tpid)
239 st->tpid = be16_to_cpu(mt.key->vlan_tpid);
240
241 st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_VLAN);
242
243 return 0;
244out:
245 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "vlan parse error");
246 return err;
247}
248EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_vlan_usage);
249
250int vcap_tc_flower_handler_tcp_usage(struct vcap_tc_flower_parse_usage *st)
251{
252 struct flow_match_tcp mt;
253 u16 tcp_flags_mask;
254 u16 tcp_flags_key;
255 enum vcap_bit val;
256 int err = 0;
257
258 flow_rule_match_tcp(rule: st->frule, out: &mt);
259 tcp_flags_key = be16_to_cpu(mt.key->flags);
260 tcp_flags_mask = be16_to_cpu(mt.mask->flags);
261
262 if (tcp_flags_mask & TCPHDR_FIN) {
263 val = VCAP_BIT_0;
264 if (tcp_flags_key & TCPHDR_FIN)
265 val = VCAP_BIT_1;
266 err = vcap_rule_add_key_bit(rule: st->vrule, key: VCAP_KF_L4_FIN, val);
267 if (err)
268 goto out;
269 }
270
271 if (tcp_flags_mask & TCPHDR_SYN) {
272 val = VCAP_BIT_0;
273 if (tcp_flags_key & TCPHDR_SYN)
274 val = VCAP_BIT_1;
275 err = vcap_rule_add_key_bit(rule: st->vrule, key: VCAP_KF_L4_SYN, val);
276 if (err)
277 goto out;
278 }
279
280 if (tcp_flags_mask & TCPHDR_RST) {
281 val = VCAP_BIT_0;
282 if (tcp_flags_key & TCPHDR_RST)
283 val = VCAP_BIT_1;
284 err = vcap_rule_add_key_bit(rule: st->vrule, key: VCAP_KF_L4_RST, val);
285 if (err)
286 goto out;
287 }
288
289 if (tcp_flags_mask & TCPHDR_PSH) {
290 val = VCAP_BIT_0;
291 if (tcp_flags_key & TCPHDR_PSH)
292 val = VCAP_BIT_1;
293 err = vcap_rule_add_key_bit(rule: st->vrule, key: VCAP_KF_L4_PSH, val);
294 if (err)
295 goto out;
296 }
297
298 if (tcp_flags_mask & TCPHDR_ACK) {
299 val = VCAP_BIT_0;
300 if (tcp_flags_key & TCPHDR_ACK)
301 val = VCAP_BIT_1;
302 err = vcap_rule_add_key_bit(rule: st->vrule, key: VCAP_KF_L4_ACK, val);
303 if (err)
304 goto out;
305 }
306
307 if (tcp_flags_mask & TCPHDR_URG) {
308 val = VCAP_BIT_0;
309 if (tcp_flags_key & TCPHDR_URG)
310 val = VCAP_BIT_1;
311 err = vcap_rule_add_key_bit(rule: st->vrule, key: VCAP_KF_L4_URG, val);
312 if (err)
313 goto out;
314 }
315
316 st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_TCP);
317
318 return err;
319
320out:
321 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "tcp_flags parse error");
322 return err;
323}
324EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_tcp_usage);
325
326int vcap_tc_flower_handler_arp_usage(struct vcap_tc_flower_parse_usage *st)
327{
328 struct flow_match_arp mt;
329 u16 value, mask;
330 u32 ipval, ipmsk;
331 int err;
332
333 flow_rule_match_arp(rule: st->frule, out: &mt);
334
335 if (mt.mask->op) {
336 mask = 0x3;
337 if (st->l3_proto == ETH_P_ARP) {
338 value = mt.key->op == VCAP_ARP_OP_REQUEST ?
339 VCAP_IS2_ARP_REQUEST :
340 VCAP_IS2_ARP_REPLY;
341 } else { /* RARP */
342 value = mt.key->op == VCAP_ARP_OP_REQUEST ?
343 VCAP_IS2_RARP_REQUEST :
344 VCAP_IS2_RARP_REPLY;
345 }
346 err = vcap_rule_add_key_u32(rule: st->vrule, key: VCAP_KF_ARP_OPCODE,
347 value, mask);
348 if (err)
349 goto out;
350 }
351
352 /* The IS2 ARP keyset does not support ARP hardware addresses */
353 if (!is_zero_ether_addr(addr: mt.mask->sha) ||
354 !is_zero_ether_addr(addr: mt.mask->tha)) {
355 err = -EINVAL;
356 goto out;
357 }
358
359 if (mt.mask->sip) {
360 ipval = be32_to_cpu((__force __be32)mt.key->sip);
361 ipmsk = be32_to_cpu((__force __be32)mt.mask->sip);
362
363 err = vcap_rule_add_key_u32(rule: st->vrule, key: VCAP_KF_L3_IP4_SIP,
364 value: ipval, mask: ipmsk);
365 if (err)
366 goto out;
367 }
368
369 if (mt.mask->tip) {
370 ipval = be32_to_cpu((__force __be32)mt.key->tip);
371 ipmsk = be32_to_cpu((__force __be32)mt.mask->tip);
372
373 err = vcap_rule_add_key_u32(rule: st->vrule, key: VCAP_KF_L3_IP4_DIP,
374 value: ipval, mask: ipmsk);
375 if (err)
376 goto out;
377 }
378
379 st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_ARP);
380
381 return 0;
382
383out:
384 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "arp parse error");
385 return err;
386}
387EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_arp_usage);
388
389int vcap_tc_flower_handler_ip_usage(struct vcap_tc_flower_parse_usage *st)
390{
391 struct flow_match_ip mt;
392 int err = 0;
393
394 flow_rule_match_ip(rule: st->frule, out: &mt);
395
396 if (mt.mask->tos) {
397 err = vcap_rule_add_key_u32(rule: st->vrule, key: VCAP_KF_L3_TOS,
398 value: mt.key->tos,
399 mask: mt.mask->tos);
400 if (err)
401 goto out;
402 }
403
404 st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_IP);
405
406 return err;
407
408out:
409 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_tos parse error");
410 return err;
411}
412EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_ip_usage);
413

source code of linux/drivers/net/ethernet/microchip/vcap/vcap_tc.c