1 | /* |
2 | * This file is part of the Chelsio T4 Ethernet driver for Linux. |
3 | * |
4 | * Copyright (c) 2016 Chelsio Communications, Inc. All rights reserved. |
5 | * |
6 | * This software is available to you under a choice of one of two |
7 | * licenses. You may choose to be licensed under the terms of the GNU |
8 | * General Public License (GPL) Version 2, available from the file |
9 | * COPYING in the main directory of this source tree, or the |
10 | * OpenIB.org BSD license below: |
11 | * |
12 | * Redistribution and use in source and binary forms, with or |
13 | * without modification, are permitted provided that the following |
14 | * conditions are met: |
15 | * |
16 | * - Redistributions of source code must retain the above |
17 | * copyright notice, this list of conditions and the following |
18 | * disclaimer. |
19 | * |
20 | * - Redistributions in binary form must reproduce the above |
21 | * copyright notice, this list of conditions and the following |
22 | * disclaimer in the documentation and/or other materials |
23 | * provided with the distribution. |
24 | * |
25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
29 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
30 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
32 | * SOFTWARE. |
33 | */ |
34 | |
35 | #ifndef __CXGB4_TC_U32_PARSE_H |
36 | #define __CXGB4_TC_U32_PARSE_H |
37 | |
38 | struct cxgb4_match_field { |
39 | int off; /* Offset from the beginning of the header to match */ |
40 | /* Fill the value/mask pair in the spec if matched */ |
41 | int (*val)(struct ch_filter_specification *f, __be32 val, __be32 mask); |
42 | }; |
43 | |
44 | /* IPv4 match fields */ |
45 | static inline int cxgb4_fill_ipv4_tos(struct ch_filter_specification *f, |
46 | __be32 val, __be32 mask) |
47 | { |
48 | f->val.tos = (ntohl(val) >> 16) & 0x000000FF; |
49 | f->mask.tos = (ntohl(mask) >> 16) & 0x000000FF; |
50 | |
51 | return 0; |
52 | } |
53 | |
54 | static inline int cxgb4_fill_ipv4_frag(struct ch_filter_specification *f, |
55 | __be32 val, __be32 mask) |
56 | { |
57 | u32 mask_val; |
58 | u8 frag_val; |
59 | |
60 | frag_val = (ntohl(val) >> 13) & 0x00000007; |
61 | mask_val = ntohl(mask) & 0x0000FFFF; |
62 | |
63 | if (frag_val == 0x1 && mask_val != 0x3FFF) { /* MF set */ |
64 | f->val.frag = 1; |
65 | f->mask.frag = 1; |
66 | } else if (frag_val == 0x2 && mask_val != 0x3FFF) { /* DF set */ |
67 | f->val.frag = 0; |
68 | f->mask.frag = 1; |
69 | } else { |
70 | return -EINVAL; |
71 | } |
72 | |
73 | return 0; |
74 | } |
75 | |
76 | static inline int cxgb4_fill_ipv4_proto(struct ch_filter_specification *f, |
77 | __be32 val, __be32 mask) |
78 | { |
79 | f->val.proto = (ntohl(val) >> 16) & 0x000000FF; |
80 | f->mask.proto = (ntohl(mask) >> 16) & 0x000000FF; |
81 | |
82 | return 0; |
83 | } |
84 | |
85 | static inline int cxgb4_fill_ipv4_src_ip(struct ch_filter_specification *f, |
86 | __be32 val, __be32 mask) |
87 | { |
88 | memcpy(&f->val.fip[0], &val, sizeof(u32)); |
89 | memcpy(&f->mask.fip[0], &mask, sizeof(u32)); |
90 | |
91 | return 0; |
92 | } |
93 | |
94 | static inline int cxgb4_fill_ipv4_dst_ip(struct ch_filter_specification *f, |
95 | __be32 val, __be32 mask) |
96 | { |
97 | memcpy(&f->val.lip[0], &val, sizeof(u32)); |
98 | memcpy(&f->mask.lip[0], &mask, sizeof(u32)); |
99 | |
100 | return 0; |
101 | } |
102 | |
103 | static const struct cxgb4_match_field cxgb4_ipv4_fields[] = { |
104 | { .off = 0, .val = cxgb4_fill_ipv4_tos }, |
105 | { .off = 4, .val = cxgb4_fill_ipv4_frag }, |
106 | { .off = 8, .val = cxgb4_fill_ipv4_proto }, |
107 | { .off = 12, .val = cxgb4_fill_ipv4_src_ip }, |
108 | { .off = 16, .val = cxgb4_fill_ipv4_dst_ip }, |
109 | { .val = NULL } |
110 | }; |
111 | |
112 | /* IPv6 match fields */ |
113 | static inline int cxgb4_fill_ipv6_tos(struct ch_filter_specification *f, |
114 | __be32 val, __be32 mask) |
115 | { |
116 | f->val.tos = (ntohl(val) >> 20) & 0x000000FF; |
117 | f->mask.tos = (ntohl(mask) >> 20) & 0x000000FF; |
118 | |
119 | return 0; |
120 | } |
121 | |
122 | static inline int cxgb4_fill_ipv6_proto(struct ch_filter_specification *f, |
123 | __be32 val, __be32 mask) |
124 | { |
125 | f->val.proto = (ntohl(val) >> 8) & 0x000000FF; |
126 | f->mask.proto = (ntohl(mask) >> 8) & 0x000000FF; |
127 | |
128 | return 0; |
129 | } |
130 | |
131 | static inline int cxgb4_fill_ipv6_src_ip0(struct ch_filter_specification *f, |
132 | __be32 val, __be32 mask) |
133 | { |
134 | memcpy(&f->val.fip[0], &val, sizeof(u32)); |
135 | memcpy(&f->mask.fip[0], &mask, sizeof(u32)); |
136 | |
137 | return 0; |
138 | } |
139 | |
140 | static inline int cxgb4_fill_ipv6_src_ip1(struct ch_filter_specification *f, |
141 | __be32 val, __be32 mask) |
142 | { |
143 | memcpy(&f->val.fip[4], &val, sizeof(u32)); |
144 | memcpy(&f->mask.fip[4], &mask, sizeof(u32)); |
145 | |
146 | return 0; |
147 | } |
148 | |
149 | static inline int cxgb4_fill_ipv6_src_ip2(struct ch_filter_specification *f, |
150 | __be32 val, __be32 mask) |
151 | { |
152 | memcpy(&f->val.fip[8], &val, sizeof(u32)); |
153 | memcpy(&f->mask.fip[8], &mask, sizeof(u32)); |
154 | |
155 | return 0; |
156 | } |
157 | |
158 | static inline int cxgb4_fill_ipv6_src_ip3(struct ch_filter_specification *f, |
159 | __be32 val, __be32 mask) |
160 | { |
161 | memcpy(&f->val.fip[12], &val, sizeof(u32)); |
162 | memcpy(&f->mask.fip[12], &mask, sizeof(u32)); |
163 | |
164 | return 0; |
165 | } |
166 | |
167 | static inline int cxgb4_fill_ipv6_dst_ip0(struct ch_filter_specification *f, |
168 | __be32 val, __be32 mask) |
169 | { |
170 | memcpy(&f->val.lip[0], &val, sizeof(u32)); |
171 | memcpy(&f->mask.lip[0], &mask, sizeof(u32)); |
172 | |
173 | return 0; |
174 | } |
175 | |
176 | static inline int cxgb4_fill_ipv6_dst_ip1(struct ch_filter_specification *f, |
177 | __be32 val, __be32 mask) |
178 | { |
179 | memcpy(&f->val.lip[4], &val, sizeof(u32)); |
180 | memcpy(&f->mask.lip[4], &mask, sizeof(u32)); |
181 | |
182 | return 0; |
183 | } |
184 | |
185 | static inline int cxgb4_fill_ipv6_dst_ip2(struct ch_filter_specification *f, |
186 | __be32 val, __be32 mask) |
187 | { |
188 | memcpy(&f->val.lip[8], &val, sizeof(u32)); |
189 | memcpy(&f->mask.lip[8], &mask, sizeof(u32)); |
190 | |
191 | return 0; |
192 | } |
193 | |
194 | static inline int cxgb4_fill_ipv6_dst_ip3(struct ch_filter_specification *f, |
195 | __be32 val, __be32 mask) |
196 | { |
197 | memcpy(&f->val.lip[12], &val, sizeof(u32)); |
198 | memcpy(&f->mask.lip[12], &mask, sizeof(u32)); |
199 | |
200 | return 0; |
201 | } |
202 | |
203 | static const struct cxgb4_match_field cxgb4_ipv6_fields[] = { |
204 | { .off = 0, .val = cxgb4_fill_ipv6_tos }, |
205 | { .off = 4, .val = cxgb4_fill_ipv6_proto }, |
206 | { .off = 8, .val = cxgb4_fill_ipv6_src_ip0 }, |
207 | { .off = 12, .val = cxgb4_fill_ipv6_src_ip1 }, |
208 | { .off = 16, .val = cxgb4_fill_ipv6_src_ip2 }, |
209 | { .off = 20, .val = cxgb4_fill_ipv6_src_ip3 }, |
210 | { .off = 24, .val = cxgb4_fill_ipv6_dst_ip0 }, |
211 | { .off = 28, .val = cxgb4_fill_ipv6_dst_ip1 }, |
212 | { .off = 32, .val = cxgb4_fill_ipv6_dst_ip2 }, |
213 | { .off = 36, .val = cxgb4_fill_ipv6_dst_ip3 }, |
214 | { .val = NULL } |
215 | }; |
216 | |
217 | /* TCP/UDP match */ |
218 | static inline int cxgb4_fill_l4_ports(struct ch_filter_specification *f, |
219 | __be32 val, __be32 mask) |
220 | { |
221 | f->val.fport = ntohl(val) >> 16; |
222 | f->mask.fport = ntohl(mask) >> 16; |
223 | f->val.lport = ntohl(val) & 0x0000FFFF; |
224 | f->mask.lport = ntohl(mask) & 0x0000FFFF; |
225 | |
226 | return 0; |
227 | }; |
228 | |
229 | static const struct cxgb4_match_field cxgb4_tcp_fields[] = { |
230 | { .off = 0, .val = cxgb4_fill_l4_ports }, |
231 | { .val = NULL } |
232 | }; |
233 | |
234 | static const struct cxgb4_match_field cxgb4_udp_fields[] = { |
235 | { .off = 0, .val = cxgb4_fill_l4_ports }, |
236 | { .val = NULL } |
237 | }; |
238 | |
239 | struct { |
240 | /* Offset, shift, and mask added to beginning of the header |
241 | * to get to next header. Useful when using a header |
242 | * field's value to jump to next header such as IHL field |
243 | * in IPv4 header. |
244 | */ |
245 | struct tc_u32_sel ; |
246 | struct tc_u32_key ; |
247 | /* location of jump to make */ |
248 | const struct cxgb4_match_field *; |
249 | }; |
250 | |
251 | /* Accept a rule with a jump to transport layer header based on IHL field in |
252 | * IPv4 header. |
253 | */ |
254 | static const struct cxgb4_next_header cxgb4_ipv4_jumps[] = { |
255 | { |
256 | /* TCP Jump */ |
257 | .sel = { |
258 | .off = 0, |
259 | .offoff = 0, |
260 | .offshift = 6, |
261 | .offmask = cpu_to_be16(0x0f00), |
262 | }, |
263 | .key = { |
264 | .off = 8, |
265 | .val = cpu_to_be32(0x00060000), |
266 | .mask = cpu_to_be32(0x00ff0000), |
267 | }, |
268 | .jump = cxgb4_tcp_fields, |
269 | }, |
270 | { |
271 | /* UDP Jump */ |
272 | .sel = { |
273 | .off = 0, |
274 | .offoff = 0, |
275 | .offshift = 6, |
276 | .offmask = cpu_to_be16(0x0f00), |
277 | }, |
278 | .key = { |
279 | .off = 8, |
280 | .val = cpu_to_be32(0x00110000), |
281 | .mask = cpu_to_be32(0x00ff0000), |
282 | }, |
283 | .jump = cxgb4_udp_fields, |
284 | }, |
285 | { .jump = NULL }, |
286 | }; |
287 | |
288 | /* Accept a rule with a jump directly past the 40 Bytes of IPv6 fixed header |
289 | * to get to transport layer header. |
290 | */ |
291 | static const struct cxgb4_next_header cxgb4_ipv6_jumps[] = { |
292 | { |
293 | /* TCP Jump */ |
294 | .sel = { |
295 | .off = 40, |
296 | .offoff = 0, |
297 | .offshift = 0, |
298 | .offmask = 0, |
299 | }, |
300 | .key = { |
301 | .off = 4, |
302 | .val = cpu_to_be32(0x00000600), |
303 | .mask = cpu_to_be32(0x0000ff00), |
304 | }, |
305 | .jump = cxgb4_tcp_fields, |
306 | }, |
307 | { |
308 | /* UDP Jump */ |
309 | .sel = { |
310 | .off = 40, |
311 | .offoff = 0, |
312 | .offshift = 0, |
313 | .offmask = 0, |
314 | }, |
315 | .key = { |
316 | .off = 4, |
317 | .val = cpu_to_be32(0x00001100), |
318 | .mask = cpu_to_be32(0x0000ff00), |
319 | }, |
320 | .jump = cxgb4_udp_fields, |
321 | }, |
322 | { .jump = NULL }, |
323 | }; |
324 | |
325 | struct cxgb4_link { |
326 | const struct cxgb4_match_field *match_field; /* Next header */ |
327 | struct ch_filter_specification fs; /* Match spec associated with link */ |
328 | u32 link_handle; /* Knode handle associated with the link */ |
329 | unsigned long *tid_map; /* Bitmap for filter tids */ |
330 | }; |
331 | |
332 | struct cxgb4_tc_u32_table { |
333 | unsigned int size; /* number of entries in table */ |
334 | struct cxgb4_link table[] __counted_by(size); /* Jump table */ |
335 | }; |
336 | #endif /* __CXGB4_TC_U32_PARSE_H */ |
337 | |