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 | |
14 | enum 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 | |
21 | enum vcap_arp_opcode { |
22 | VCAP_ARP_OP_RESERVED, |
23 | VCAP_ARP_OP_REQUEST, |
24 | VCAP_ARP_OP_REPLY, |
25 | }; |
26 | |
27 | int 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 | |
57 | out: |
58 | NL_SET_ERR_MSG_MOD(st->fco->common.extack, "eth_addr parse error" ); |
59 | return err; |
60 | } |
61 | EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_ethaddr_usage); |
62 | |
63 | int 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 | |
93 | out: |
94 | NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv4_addr parse error" ); |
95 | return err; |
96 | } |
97 | EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_ipv4_usage); |
98 | |
99 | int 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; |
129 | out: |
130 | NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ipv6_addr parse error" ); |
131 | return err; |
132 | } |
133 | EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_ipv6_usage); |
134 | |
135 | int 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 | |
165 | out: |
166 | NL_SET_ERR_MSG_MOD(st->fco->common.extack, "port parse error" ); |
167 | return err; |
168 | } |
169 | EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_portnum_usage); |
170 | |
171 | int 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; |
207 | out: |
208 | NL_SET_ERR_MSG_MOD(st->fco->common.extack, "cvlan parse error" ); |
209 | return err; |
210 | } |
211 | EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_cvlan_usage); |
212 | |
213 | int 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; |
244 | out: |
245 | NL_SET_ERR_MSG_MOD(st->fco->common.extack, "vlan parse error" ); |
246 | return err; |
247 | } |
248 | EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_vlan_usage); |
249 | |
250 | int 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 | |
320 | out: |
321 | NL_SET_ERR_MSG_MOD(st->fco->common.extack, "tcp_flags parse error" ); |
322 | return err; |
323 | } |
324 | EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_tcp_usage); |
325 | |
326 | int 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 | |
383 | out: |
384 | NL_SET_ERR_MSG_MOD(st->fco->common.extack, "arp parse error" ); |
385 | return err; |
386 | } |
387 | EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_arp_usage); |
388 | |
389 | int 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 | |
408 | out: |
409 | NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_tos parse error" ); |
410 | return err; |
411 | } |
412 | EXPORT_SYMBOL_GPL(vcap_tc_flower_handler_ip_usage); |
413 | |