a86bfbd1a42d6be29d46d1092fc705176c2404c7
[dpdk.git] / lib / librte_ether / rte_flow.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright 2016 6WIND S.A.
5  *   Copyright 2016 Mellanox.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of 6WIND S.A. nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <errno.h>
35 #include <stddef.h>
36 #include <stdint.h>
37 #include <string.h>
38
39 #include <rte_common.h>
40 #include <rte_errno.h>
41 #include <rte_branch_prediction.h>
42 #include "rte_ethdev.h"
43 #include "rte_flow_driver.h"
44 #include "rte_flow.h"
45
46 /**
47  * Flow elements description tables.
48  */
49 struct rte_flow_desc_data {
50         const char *name;
51         size_t size;
52 };
53
54 /** Generate flow_item[] entry. */
55 #define MK_FLOW_ITEM(t, s) \
56         [RTE_FLOW_ITEM_TYPE_ ## t] = { \
57                 .name = # t, \
58                 .size = s, \
59         }
60
61 /** Information about known flow pattern items. */
62 static const struct rte_flow_desc_data rte_flow_desc_item[] = {
63         MK_FLOW_ITEM(END, 0),
64         MK_FLOW_ITEM(VOID, 0),
65         MK_FLOW_ITEM(INVERT, 0),
66         MK_FLOW_ITEM(ANY, sizeof(struct rte_flow_item_any)),
67         MK_FLOW_ITEM(PF, 0),
68         MK_FLOW_ITEM(VF, sizeof(struct rte_flow_item_vf)),
69         MK_FLOW_ITEM(PORT, sizeof(struct rte_flow_item_port)),
70         MK_FLOW_ITEM(RAW, sizeof(struct rte_flow_item_raw)), /* +pattern[] */
71         MK_FLOW_ITEM(ETH, sizeof(struct rte_flow_item_eth)),
72         MK_FLOW_ITEM(VLAN, sizeof(struct rte_flow_item_vlan)),
73         MK_FLOW_ITEM(IPV4, sizeof(struct rte_flow_item_ipv4)),
74         MK_FLOW_ITEM(IPV6, sizeof(struct rte_flow_item_ipv6)),
75         MK_FLOW_ITEM(ICMP, sizeof(struct rte_flow_item_icmp)),
76         MK_FLOW_ITEM(UDP, sizeof(struct rte_flow_item_udp)),
77         MK_FLOW_ITEM(TCP, sizeof(struct rte_flow_item_tcp)),
78         MK_FLOW_ITEM(SCTP, sizeof(struct rte_flow_item_sctp)),
79         MK_FLOW_ITEM(VXLAN, sizeof(struct rte_flow_item_vxlan)),
80         MK_FLOW_ITEM(MPLS, sizeof(struct rte_flow_item_mpls)),
81         MK_FLOW_ITEM(GRE, sizeof(struct rte_flow_item_gre)),
82         MK_FLOW_ITEM(E_TAG, sizeof(struct rte_flow_item_e_tag)),
83         MK_FLOW_ITEM(NVGRE, sizeof(struct rte_flow_item_nvgre)),
84         MK_FLOW_ITEM(GENEVE, sizeof(struct rte_flow_item_geneve)),
85 };
86
87 /** Generate flow_action[] entry. */
88 #define MK_FLOW_ACTION(t, s) \
89         [RTE_FLOW_ACTION_TYPE_ ## t] = { \
90                 .name = # t, \
91                 .size = s, \
92         }
93
94 /** Information about known flow actions. */
95 static const struct rte_flow_desc_data rte_flow_desc_action[] = {
96         MK_FLOW_ACTION(END, 0),
97         MK_FLOW_ACTION(VOID, 0),
98         MK_FLOW_ACTION(PASSTHRU, 0),
99         MK_FLOW_ACTION(MARK, sizeof(struct rte_flow_action_mark)),
100         MK_FLOW_ACTION(FLAG, 0),
101         MK_FLOW_ACTION(QUEUE, sizeof(struct rte_flow_action_queue)),
102         MK_FLOW_ACTION(DROP, 0),
103         MK_FLOW_ACTION(COUNT, 0),
104         MK_FLOW_ACTION(DUP, sizeof(struct rte_flow_action_dup)),
105         MK_FLOW_ACTION(RSS, sizeof(struct rte_flow_action_rss)), /* +queue[] */
106         MK_FLOW_ACTION(PF, 0),
107         MK_FLOW_ACTION(VF, sizeof(struct rte_flow_action_vf)),
108 };
109
110 static int
111 flow_err(uint16_t port_id, int ret, struct rte_flow_error *error)
112 {
113         if (ret == 0)
114                 return 0;
115         if (rte_eth_dev_is_removed(port_id))
116                 return rte_flow_error_set(error, EIO,
117                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
118                                           NULL, rte_strerror(EIO));
119         return ret;
120 }
121
122 /* Get generic flow operations structure from a port. */
123 const struct rte_flow_ops *
124 rte_flow_ops_get(uint16_t port_id, struct rte_flow_error *error)
125 {
126         struct rte_eth_dev *dev = &rte_eth_devices[port_id];
127         const struct rte_flow_ops *ops;
128         int code;
129
130         if (unlikely(!rte_eth_dev_is_valid_port(port_id)))
131                 code = ENODEV;
132         else if (unlikely(!dev->dev_ops->filter_ctrl ||
133                           dev->dev_ops->filter_ctrl(dev,
134                                                     RTE_ETH_FILTER_GENERIC,
135                                                     RTE_ETH_FILTER_GET,
136                                                     &ops) ||
137                           !ops))
138                 code = ENOSYS;
139         else
140                 return ops;
141         rte_flow_error_set(error, code, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
142                            NULL, rte_strerror(code));
143         return NULL;
144 }
145
146 /* Check whether a flow rule can be created on a given port. */
147 int
148 rte_flow_validate(uint16_t port_id,
149                   const struct rte_flow_attr *attr,
150                   const struct rte_flow_item pattern[],
151                   const struct rte_flow_action actions[],
152                   struct rte_flow_error *error)
153 {
154         const struct rte_flow_ops *ops = rte_flow_ops_get(port_id, error);
155         struct rte_eth_dev *dev = &rte_eth_devices[port_id];
156
157         if (unlikely(!ops))
158                 return -rte_errno;
159         if (likely(!!ops->validate))
160                 return flow_err(port_id, ops->validate(dev, attr, pattern,
161                                                        actions, error), error);
162         return rte_flow_error_set(error, ENOSYS,
163                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
164                                   NULL, rte_strerror(ENOSYS));
165 }
166
167 /* Create a flow rule on a given port. */
168 struct rte_flow *
169 rte_flow_create(uint16_t port_id,
170                 const struct rte_flow_attr *attr,
171                 const struct rte_flow_item pattern[],
172                 const struct rte_flow_action actions[],
173                 struct rte_flow_error *error)
174 {
175         struct rte_eth_dev *dev = &rte_eth_devices[port_id];
176         struct rte_flow *flow;
177         const struct rte_flow_ops *ops = rte_flow_ops_get(port_id, error);
178
179         if (unlikely(!ops))
180                 return NULL;
181         if (likely(!!ops->create)) {
182                 flow = ops->create(dev, attr, pattern, actions, error);
183                 if (flow == NULL)
184                         flow_err(port_id, -rte_errno, error);
185                 return flow;
186         }
187         rte_flow_error_set(error, ENOSYS, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
188                            NULL, rte_strerror(ENOSYS));
189         return NULL;
190 }
191
192 /* Destroy a flow rule on a given port. */
193 int
194 rte_flow_destroy(uint16_t port_id,
195                  struct rte_flow *flow,
196                  struct rte_flow_error *error)
197 {
198         struct rte_eth_dev *dev = &rte_eth_devices[port_id];
199         const struct rte_flow_ops *ops = rte_flow_ops_get(port_id, error);
200
201         if (unlikely(!ops))
202                 return -rte_errno;
203         if (likely(!!ops->destroy))
204                 return flow_err(port_id, ops->destroy(dev, flow, error),
205                                 error);
206         return rte_flow_error_set(error, ENOSYS,
207                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
208                                   NULL, rte_strerror(ENOSYS));
209 }
210
211 /* Destroy all flow rules associated with a port. */
212 int
213 rte_flow_flush(uint16_t port_id,
214                struct rte_flow_error *error)
215 {
216         struct rte_eth_dev *dev = &rte_eth_devices[port_id];
217         const struct rte_flow_ops *ops = rte_flow_ops_get(port_id, error);
218
219         if (unlikely(!ops))
220                 return -rte_errno;
221         if (likely(!!ops->flush))
222                 return flow_err(port_id, ops->flush(dev, error), error);
223         return rte_flow_error_set(error, ENOSYS,
224                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
225                                   NULL, rte_strerror(ENOSYS));
226 }
227
228 /* Query an existing flow rule. */
229 int
230 rte_flow_query(uint16_t port_id,
231                struct rte_flow *flow,
232                enum rte_flow_action_type action,
233                void *data,
234                struct rte_flow_error *error)
235 {
236         struct rte_eth_dev *dev = &rte_eth_devices[port_id];
237         const struct rte_flow_ops *ops = rte_flow_ops_get(port_id, error);
238
239         if (!ops)
240                 return -rte_errno;
241         if (likely(!!ops->query))
242                 return flow_err(port_id, ops->query(dev, flow, action, data,
243                                                     error), error);
244         return rte_flow_error_set(error, ENOSYS,
245                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
246                                   NULL, rte_strerror(ENOSYS));
247 }
248
249 /* Restrict ingress traffic to the defined flow rules. */
250 int
251 rte_flow_isolate(uint16_t port_id,
252                  int set,
253                  struct rte_flow_error *error)
254 {
255         struct rte_eth_dev *dev = &rte_eth_devices[port_id];
256         const struct rte_flow_ops *ops = rte_flow_ops_get(port_id, error);
257
258         if (!ops)
259                 return -rte_errno;
260         if (likely(!!ops->isolate))
261                 return flow_err(port_id, ops->isolate(dev, set, error), error);
262         return rte_flow_error_set(error, ENOSYS,
263                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
264                                   NULL, rte_strerror(ENOSYS));
265 }
266
267 /* Initialize flow error structure. */
268 int
269 rte_flow_error_set(struct rte_flow_error *error,
270                    int code,
271                    enum rte_flow_error_type type,
272                    const void *cause,
273                    const char *message)
274 {
275         if (error) {
276                 *error = (struct rte_flow_error){
277                         .type = type,
278                         .cause = cause,
279                         .message = message,
280                 };
281         }
282         rte_errno = code;
283         return -code;
284 }
285
286 /** Compute storage space needed by item specification. */
287 static void
288 flow_item_spec_size(const struct rte_flow_item *item,
289                     size_t *size, size_t *pad)
290 {
291         if (!item->spec) {
292                 *size = 0;
293                 goto empty;
294         }
295         switch (item->type) {
296                 union {
297                         const struct rte_flow_item_raw *raw;
298                 } spec;
299
300         /* Not a fall-through */
301         case RTE_FLOW_ITEM_TYPE_RAW:
302                 spec.raw = item->spec;
303                 *size = offsetof(struct rte_flow_item_raw, pattern) +
304                         spec.raw->length * sizeof(*spec.raw->pattern);
305                 break;
306         default:
307                 *size = rte_flow_desc_item[item->type].size;
308                 break;
309         }
310 empty:
311         *pad = RTE_ALIGN_CEIL(*size, sizeof(double)) - *size;
312 }
313
314 /** Compute storage space needed by action configuration. */
315 static void
316 flow_action_conf_size(const struct rte_flow_action *action,
317                       size_t *size, size_t *pad)
318 {
319         if (!action->conf) {
320                 *size = 0;
321                 goto empty;
322         }
323         switch (action->type) {
324                 union {
325                         const struct rte_flow_action_rss *rss;
326                 } conf;
327
328         /* Not a fall-through. */
329         case RTE_FLOW_ACTION_TYPE_RSS:
330                 conf.rss = action->conf;
331                 *size = offsetof(struct rte_flow_action_rss, queue) +
332                         conf.rss->num * sizeof(*conf.rss->queue);
333                 break;
334         default:
335                 *size = rte_flow_desc_action[action->type].size;
336                 break;
337         }
338 empty:
339         *pad = RTE_ALIGN_CEIL(*size, sizeof(double)) - *size;
340 }
341
342 /** Store a full rte_flow description. */
343 size_t
344 rte_flow_copy(struct rte_flow_desc *desc, size_t len,
345               const struct rte_flow_attr *attr,
346               const struct rte_flow_item *items,
347               const struct rte_flow_action *actions)
348 {
349         struct rte_flow_desc *fd = NULL;
350         size_t tmp;
351         size_t pad;
352         size_t off1 = 0;
353         size_t off2 = 0;
354         size_t size = 0;
355
356 store:
357         if (items) {
358                 const struct rte_flow_item *item;
359
360                 item = items;
361                 if (fd)
362                         fd->items = (void *)&fd->data[off1];
363                 do {
364                         struct rte_flow_item *dst = NULL;
365
366                         if ((size_t)item->type >=
367                                 RTE_DIM(rte_flow_desc_item) ||
368                             !rte_flow_desc_item[item->type].name) {
369                                 rte_errno = ENOTSUP;
370                                 return 0;
371                         }
372                         if (fd)
373                                 dst = memcpy(fd->data + off1, item,
374                                              sizeof(*item));
375                         off1 += sizeof(*item);
376                         flow_item_spec_size(item, &tmp, &pad);
377                         if (item->spec) {
378                                 if (fd)
379                                         dst->spec = memcpy(fd->data + off2,
380                                                            item->spec, tmp);
381                                 off2 += tmp + pad;
382                         }
383                         if (item->last) {
384                                 if (fd)
385                                         dst->last = memcpy(fd->data + off2,
386                                                            item->last, tmp);
387                                 off2 += tmp + pad;
388                         }
389                         if (item->mask) {
390                                 if (fd)
391                                         dst->mask = memcpy(fd->data + off2,
392                                                            item->mask, tmp);
393                                 off2 += tmp + pad;
394                         }
395                         off2 = RTE_ALIGN_CEIL(off2, sizeof(double));
396                 } while ((item++)->type != RTE_FLOW_ITEM_TYPE_END);
397                 off1 = RTE_ALIGN_CEIL(off1, sizeof(double));
398         }
399         if (actions) {
400                 const struct rte_flow_action *action;
401
402                 action = actions;
403                 if (fd)
404                         fd->actions = (void *)&fd->data[off1];
405                 do {
406                         struct rte_flow_action *dst = NULL;
407
408                         if ((size_t)action->type >=
409                                 RTE_DIM(rte_flow_desc_action) ||
410                             !rte_flow_desc_action[action->type].name) {
411                                 rte_errno = ENOTSUP;
412                                 return 0;
413                         }
414                         if (fd)
415                                 dst = memcpy(fd->data + off1, action,
416                                              sizeof(*action));
417                         off1 += sizeof(*action);
418                         flow_action_conf_size(action, &tmp, &pad);
419                         if (action->conf) {
420                                 if (fd)
421                                         dst->conf = memcpy(fd->data + off2,
422                                                            action->conf, tmp);
423                                 off2 += tmp + pad;
424                         }
425                         off2 = RTE_ALIGN_CEIL(off2, sizeof(double));
426                 } while ((action++)->type != RTE_FLOW_ACTION_TYPE_END);
427         }
428         if (fd != NULL)
429                 return size;
430         off1 = RTE_ALIGN_CEIL(off1, sizeof(double));
431         tmp = RTE_ALIGN_CEIL(offsetof(struct rte_flow_desc, data),
432                              sizeof(double));
433         size = tmp + off1 + off2;
434         if (size > len)
435                 return size;
436         fd = desc;
437         if (fd != NULL) {
438                 *fd = (const struct rte_flow_desc) {
439                         .size = size,
440                         .attr = *attr,
441                 };
442                 tmp -= offsetof(struct rte_flow_desc, data);
443                 off2 = tmp + off1;
444                 off1 = tmp;
445                 goto store;
446         }
447         return 0;
448 }