vlib: deprecate i2c and cj
[vpp.git] / src / plugins / dpdk / device / flow.c
1 /*
2  * Copyright (c) 2019 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <vnet/vnet.h>
17 #include <vppinfra/vec.h>
18 #include <vppinfra/format.h>
19 #include <assert.h>
20
21 #include <vnet/ip/ip.h>
22 #include <vnet/ethernet/ethernet.h>
23 #include <vnet/ethernet/arp_packet.h>
24 #include <vnet/vxlan/vxlan.h>
25 #include <dpdk/device/dpdk.h>
26
27 #include <dpdk/device/dpdk_priv.h>
28 #include <vppinfra/error.h>
29
30 /* check if flow is L2 flow */
31 #define FLOW_IS_L2_LAYER(f) \
32   (f->type == VNET_FLOW_TYPE_ETHERNET)
33
34 /* check if flow is VLAN sensitive */
35 #define FLOW_IS_VLAN_TAGGED(f) \
36   ((f->type == VNET_FLOW_TYPE_IP4_N_TUPLE_TAGGED) || \
37    (f->type == VNET_FLOW_TYPE_IP6_N_TUPLE_TAGGED))
38
39 /* check if flow is L4 type */
40 #define FLOW_IS_L4_LAYER(f) \
41   ((f->type == VNET_FLOW_TYPE_IP4_N_TUPLE) || \
42    (f->type == VNET_FLOW_TYPE_IP6_N_TUPLE))
43
44 /* check if flow is L4 tunnel type */
45 #define FLOW_IS_L4_TUNNEL_LAYER(f) \
46   ((f->type >= VNET_FLOW_TYPE_IP4_VXLAN) || \
47    (f->type <= VNET_FLOW_TYPE_IP6_GTPU_IP6))
48
49 /* constant structs */
50 static const struct rte_flow_attr ingress = {.ingress = 1 };
51
52 static inline bool
53 mac_address_is_all_zero (const u8 addr[6])
54 {
55   int i = 0;
56
57   for (i = 0; i < 6; i++)
58     if (addr[i] != 0)
59       return false;
60
61   return true;
62 }
63
64 static int
65 dpdk_flow_add (dpdk_device_t * xd, vnet_flow_t * f, dpdk_flow_entry_t * fe)
66 {
67   struct rte_flow_item_eth eth[2] = { };
68   struct rte_flow_item_ipv4 ip4[2] = { };
69   struct rte_flow_item_ipv4 inner_ip4[2] = { };
70   struct rte_flow_item_ipv6 ip6[2] = { };
71   struct rte_flow_item_ipv6 inner_ip6[2] = { };
72   struct rte_flow_item_udp udp[2] = { };
73   struct rte_flow_item_tcp tcp[2] = { };
74   struct rte_flow_item_gtp gtp[2] = { };
75   struct rte_flow_action_mark mark = { 0 };
76   struct rte_flow_action_queue queue = { 0 };
77   struct rte_flow_item *item, *items = 0;
78   struct rte_flow_action *action, *actions = 0;
79   bool fate = false;
80
81   enum
82   {
83     vxlan_hdr_sz = sizeof (vxlan_header_t),
84     raw_sz = sizeof (struct rte_flow_item_raw)
85   };
86
87   union
88   {
89     struct rte_flow_item_raw item;
90     u8 val[raw_sz + vxlan_hdr_sz];
91   } raw[2];
92
93   u16 src_port, dst_port, src_port_mask, dst_port_mask;
94   u8 protocol;
95   int rv = 0;
96
97   if (f->actions & (~xd->supported_flow_actions))
98     return VNET_FLOW_ERROR_NOT_SUPPORTED;
99
100   /* Match items */
101   /* Ethernet */
102   vec_add2 (items, item, 1);
103   item->type = RTE_FLOW_ITEM_TYPE_ETH;
104   if (f->type == VNET_FLOW_TYPE_ETHERNET)
105     {
106       vnet_flow_ethernet_t *te = &f->ethernet;
107
108       clib_memset (&eth[0], 0, sizeof (eth[0]));
109       clib_memset (&eth[1], 0, sizeof (eth[1]));
110
111       /* check if SMAC/DMAC/Ether_type assigned */
112       if (!mac_address_is_all_zero (te->eth_hdr.dst_address))
113         {
114           clib_memcpy_fast (&eth[0].dst, &te->eth_hdr.dst_address,
115                             sizeof (eth[0].dst));
116           clib_memset (&eth[1].dst, 0xFF, sizeof (eth[1].dst));
117         }
118
119       if (!mac_address_is_all_zero (te->eth_hdr.src_address))
120         {
121           clib_memcpy_fast (&eth[0].src, &te->eth_hdr.src_address,
122                             sizeof (eth[0].src));
123           clib_memset (&eth[1].src, 0xFF, sizeof (eth[1].src));
124         }
125
126       if (te->eth_hdr.type)
127         {
128           eth[0].type = clib_host_to_net_u16 (te->eth_hdr.type);
129           eth[1].type = clib_host_to_net_u16 (0xFFFF);
130         }
131
132       item->spec = eth;
133       item->mask = eth + 1;
134     }
135   else
136     {
137       item->spec = NULL;
138       item->mask = NULL;
139     }
140
141   if (FLOW_IS_VLAN_TAGGED (f))
142     {
143       vec_add2 (items, item, 1);
144       item->type = RTE_FLOW_ITEM_TYPE_VLAN;
145       item->spec = NULL;
146       item->mask = NULL;
147     }
148
149   if (FLOW_IS_L2_LAYER (f))
150     goto pattern_end;
151
152   /* IP */
153   vec_add2 (items, item, 1);
154   if ((f->type == VNET_FLOW_TYPE_IP6_N_TUPLE) ||
155       (f->type == VNET_FLOW_TYPE_IP6_GTPC) ||
156       (f->type == VNET_FLOW_TYPE_IP6_GTPU) ||
157       (f->type == VNET_FLOW_TYPE_IP6_GTPU_IP4) ||
158       (f->type == VNET_FLOW_TYPE_IP6_GTPU_IP6))
159     {
160       vnet_flow_ip6_n_tuple_t *t6 = &f->ip6_n_tuple;
161       item->type = RTE_FLOW_ITEM_TYPE_IPV6;
162
163       if (!clib_memcmp (&t6->src_addr.mask, &zero_addr, 16) &&
164           !clib_memcmp (&t6->dst_addr.mask, &zero_addr, 16))
165         {
166           item->spec = NULL;
167           item->mask = NULL;
168         }
169       else
170         {
171           clib_memcpy_fast (ip6[0].hdr.src_addr, &t6->src_addr.addr, 16);
172           clib_memcpy_fast (ip6[1].hdr.src_addr, &t6->src_addr.mask, 16);
173           clib_memcpy_fast (ip6[0].hdr.dst_addr, &t6->dst_addr.addr, 16);
174           clib_memcpy_fast (ip6[1].hdr.dst_addr, &t6->dst_addr.mask, 16);
175           item->spec = ip6;
176           item->mask = ip6 + 1;
177         }
178
179       src_port = t6->src_port.port;
180       dst_port = t6->dst_port.port;
181       src_port_mask = t6->src_port.mask;
182       dst_port_mask = t6->dst_port.mask;
183       protocol = t6->protocol;
184     }
185   else if ((f->type == VNET_FLOW_TYPE_IP4_N_TUPLE) ||
186            (f->type == VNET_FLOW_TYPE_IP4_GTPC) ||
187            (f->type == VNET_FLOW_TYPE_IP4_GTPU) ||
188            (f->type == VNET_FLOW_TYPE_IP4_GTPU_IP4) ||
189            (f->type == VNET_FLOW_TYPE_IP4_GTPU_IP6))
190     {
191       vnet_flow_ip4_n_tuple_t *t4 = &f->ip4_n_tuple;
192       item->type = RTE_FLOW_ITEM_TYPE_IPV4;
193
194       if (!t4->src_addr.mask.as_u32 && !t4->dst_addr.mask.as_u32)
195         {
196           item->spec = NULL;
197           item->mask = NULL;
198         }
199       else
200         {
201           ip4[0].hdr.src_addr = t4->src_addr.addr.as_u32;
202           ip4[1].hdr.src_addr = t4->src_addr.mask.as_u32;
203           ip4[0].hdr.dst_addr = t4->dst_addr.addr.as_u32;
204           ip4[1].hdr.dst_addr = t4->dst_addr.mask.as_u32;
205           item->spec = ip4;
206           item->mask = ip4 + 1;
207         }
208
209       src_port = t4->src_port.port;
210       dst_port = t4->dst_port.port;
211       src_port_mask = t4->src_port.mask;
212       dst_port_mask = t4->dst_port.mask;
213       protocol = t4->protocol;
214     }
215   else if (f->type == VNET_FLOW_TYPE_IP4_VXLAN)
216     {
217       vnet_flow_ip4_vxlan_t *v4 = &f->ip4_vxlan;
218       ip4[0].hdr.src_addr = v4->src_addr.as_u32;
219       ip4[1].hdr.src_addr = -1;
220       ip4[0].hdr.dst_addr = v4->dst_addr.as_u32;
221       ip4[1].hdr.dst_addr = -1;
222       item->type = RTE_FLOW_ITEM_TYPE_IPV4;
223       item->spec = ip4;
224       item->mask = ip4 + 1;
225
226       dst_port = v4->dst_port;
227       dst_port_mask = -1;
228       src_port = 0;
229       src_port_mask = 0;
230       protocol = IP_PROTOCOL_UDP;
231     }
232   else
233     {
234       rv = VNET_FLOW_ERROR_NOT_SUPPORTED;
235       goto done;
236     }
237
238   /* Layer 4 */
239   vec_add2 (items, item, 1);
240   if (protocol == IP_PROTOCOL_UDP)
241     {
242       item->type = RTE_FLOW_ITEM_TYPE_UDP;
243
244       if ((src_port_mask == 0) && (dst_port_mask == 0))
245         {
246           item->spec = NULL;
247           item->mask = NULL;
248         }
249       else
250         {
251           udp[0].hdr.src_port = clib_host_to_net_u16 (src_port);
252           udp[1].hdr.src_port = clib_host_to_net_u16 (src_port_mask);
253           udp[0].hdr.dst_port = clib_host_to_net_u16 (dst_port);
254           udp[1].hdr.dst_port = clib_host_to_net_u16 (dst_port_mask);
255           item->spec = udp;
256           item->mask = udp + 1;
257         }
258     }
259   else if (protocol == IP_PROTOCOL_TCP)
260     {
261       item->type = RTE_FLOW_ITEM_TYPE_TCP;
262
263       if ((src_port_mask == 0) && (dst_port_mask == 0))
264         {
265           item->spec = NULL;
266           item->mask = NULL;
267         }
268
269       tcp[0].hdr.src_port = clib_host_to_net_u16 (src_port);
270       tcp[1].hdr.src_port = clib_host_to_net_u16 (src_port_mask);
271       tcp[0].hdr.dst_port = clib_host_to_net_u16 (dst_port);
272       tcp[1].hdr.dst_port = clib_host_to_net_u16 (dst_port_mask);
273       item->spec = tcp;
274       item->mask = tcp + 1;
275     }
276   else
277     {
278       rv = VNET_FLOW_ERROR_NOT_SUPPORTED;
279       goto done;
280     }
281
282   /* Tunnel header match */
283   if (f->type == VNET_FLOW_TYPE_IP4_VXLAN)
284     {
285       u32 vni = f->ip4_vxlan.vni;
286       vxlan_header_t spec_hdr = {
287         .flags = VXLAN_FLAGS_I,
288         .vni_reserved = clib_host_to_net_u32 (vni << 8)
289       };
290       vxlan_header_t mask_hdr = {
291         .flags = 0xff,
292         .vni_reserved = clib_host_to_net_u32 (((u32) - 1) << 8)
293       };
294
295       clib_memset (raw, 0, sizeof raw);
296       raw[0].item.relative = 1;
297       raw[0].item.length = vxlan_hdr_sz;
298
299       clib_memcpy_fast (raw[0].val + raw_sz, &spec_hdr, vxlan_hdr_sz);
300       raw[0].item.pattern = raw[0].val + raw_sz;
301       clib_memcpy_fast (raw[1].val + raw_sz, &mask_hdr, vxlan_hdr_sz);
302       raw[1].item.pattern = raw[1].val + raw_sz;
303
304       vec_add2 (items, item, 1);
305       item->type = RTE_FLOW_ITEM_TYPE_RAW;
306       item->spec = raw;
307       item->mask = raw + 1;
308     }
309   else if (f->type == VNET_FLOW_TYPE_IP4_GTPC)
310     {
311       vnet_flow_ip4_gtpc_t *gc = &f->ip4_gtpc;
312       gtp[0].teid = clib_host_to_net_u32 (gc->teid);
313       gtp[1].teid = ~0;
314
315       vec_add2 (items, item, 1);
316       item->type = RTE_FLOW_ITEM_TYPE_GTPC;
317       item->spec = gtp;
318       item->mask = gtp + 1;
319     }
320   else if (f->type == VNET_FLOW_TYPE_IP4_GTPU)
321     {
322       vnet_flow_ip4_gtpu_t *gu = &f->ip4_gtpu;
323       gtp[0].teid = clib_host_to_net_u32 (gu->teid);
324       gtp[1].teid = ~0;
325
326       vec_add2 (items, item, 1);
327       item->type = RTE_FLOW_ITEM_TYPE_GTPU;
328       item->spec = gtp;
329       item->mask = gtp + 1;
330     }
331   else if ((f->type == VNET_FLOW_TYPE_IP4_GTPU_IP4) ||
332            (f->type == VNET_FLOW_TYPE_IP4_GTPU_IP6))
333     {
334       vnet_flow_ip4_gtpu_t *gu = &f->ip4_gtpu;
335       gtp[0].teid = clib_host_to_net_u32 (gu->teid);
336       gtp[1].teid = ~0;
337
338       vec_add2 (items, item, 1);
339       item->type = RTE_FLOW_ITEM_TYPE_GTPU;
340       item->spec = gtp;
341       item->mask = gtp + 1;
342
343       /* inner IP4 header */
344       if (f->type == VNET_FLOW_TYPE_IP4_GTPU_IP4)
345         {
346           vec_add2 (items, item, 1);
347           item->type = RTE_FLOW_ITEM_TYPE_IPV4;
348
349           vnet_flow_ip4_gtpu_ip4_t *gu4 = &f->ip4_gtpu_ip4;
350           if (!gu4->inner_src_addr.mask.as_u32 &&
351               !gu4->inner_dst_addr.mask.as_u32)
352             {
353               item->spec = NULL;
354               item->mask = NULL;
355             }
356           else
357             {
358               inner_ip4[0].hdr.src_addr = gu4->inner_src_addr.addr.as_u32;
359               inner_ip4[1].hdr.src_addr = gu4->inner_src_addr.mask.as_u32;
360               inner_ip4[0].hdr.dst_addr = gu4->inner_dst_addr.addr.as_u32;
361               inner_ip4[1].hdr.dst_addr = gu4->inner_dst_addr.mask.as_u32;
362               item->spec = inner_ip4;
363               item->mask = inner_ip4 + 1;
364             }
365         }
366       else if (f->type == VNET_FLOW_TYPE_IP4_GTPU_IP6)
367         {
368           ip6_address_t zero_addr;
369           vnet_flow_ip4_gtpu_ip6_t *gu6 = &f->ip4_gtpu_ip6;
370
371           clib_memset (&zero_addr, 0, sizeof (ip6_address_t));
372
373           vec_add2 (items, item, 1);
374           item->type = RTE_FLOW_ITEM_TYPE_IPV6;
375
376           if (!clib_memcmp (&gu6->inner_src_addr.mask, &zero_addr, 16) &&
377               !clib_memcmp (&gu6->inner_dst_addr.mask, &zero_addr, 16))
378             {
379               item->spec = NULL;
380               item->mask = NULL;
381             }
382           else
383             {
384               clib_memcpy_fast (inner_ip6[0].hdr.src_addr,
385                                 &gu6->inner_src_addr.addr, 16);
386               clib_memcpy_fast (inner_ip6[1].hdr.src_addr,
387                                 &gu6->inner_src_addr.mask, 16);
388               clib_memcpy_fast (inner_ip6[0].hdr.dst_addr,
389                                 &gu6->inner_dst_addr.addr, 16);
390               clib_memcpy_fast (inner_ip6[1].hdr.dst_addr,
391                                 &gu6->inner_dst_addr.mask, 16);
392               item->spec = inner_ip6;
393               item->mask = inner_ip6 + 1;
394             }
395         }
396     }
397   else if (f->type == VNET_FLOW_TYPE_IP6_GTPC)
398     {
399       vnet_flow_ip6_gtpc_t *gc = &f->ip6_gtpc;
400       gtp[0].teid = clib_host_to_net_u32 (gc->teid);
401       gtp[1].teid = ~0;
402
403       vec_add2 (items, item, 1);
404       item->type = RTE_FLOW_ITEM_TYPE_GTPC;
405       item->spec = gtp;
406       item->mask = gtp + 1;
407     }
408   else if (f->type == VNET_FLOW_TYPE_IP6_GTPU)
409     {
410       vnet_flow_ip6_gtpu_t *gu = &f->ip6_gtpu;
411       gtp[0].teid = clib_host_to_net_u32 (gu->teid);
412       gtp[1].teid = ~0;
413
414       vec_add2 (items, item, 1);
415       item->type = RTE_FLOW_ITEM_TYPE_GTPU;
416       item->spec = gtp;
417       item->mask = gtp + 1;
418     }
419   else if ((f->type == VNET_FLOW_TYPE_IP6_GTPU_IP4) ||
420            (f->type == VNET_FLOW_TYPE_IP6_GTPU_IP6))
421     {
422       vnet_flow_ip6_gtpu_t *gu = &f->ip6_gtpu;
423       gtp[0].teid = clib_host_to_net_u32 (gu->teid);
424       gtp[1].teid = ~0;
425
426       vec_add2 (items, item, 1);
427       item->type = RTE_FLOW_ITEM_TYPE_GTPU;
428       item->spec = gtp;
429       item->mask = gtp + 1;
430
431       /* inner IP4 header */
432       if (f->type == VNET_FLOW_TYPE_IP6_GTPU_IP4)
433         {
434           vec_add2 (items, item, 1);
435           item->type = RTE_FLOW_ITEM_TYPE_IPV4;
436
437           vnet_flow_ip6_gtpu_ip4_t *gu4 = &f->ip6_gtpu_ip4;
438
439           if (!gu4->inner_src_addr.mask.as_u32 &&
440               !gu4->inner_dst_addr.mask.as_u32)
441             {
442               item->spec = NULL;
443               item->mask = NULL;
444             }
445           else
446             {
447               inner_ip4[0].hdr.src_addr = gu4->inner_src_addr.addr.as_u32;
448               inner_ip4[1].hdr.src_addr = gu4->inner_src_addr.mask.as_u32;
449               inner_ip4[0].hdr.dst_addr = gu4->inner_dst_addr.addr.as_u32;
450               inner_ip4[1].hdr.dst_addr = gu4->inner_dst_addr.mask.as_u32;
451               item->spec = inner_ip4;
452               item->mask = inner_ip4 + 1;
453             }
454         }
455
456       if (f->type == VNET_FLOW_TYPE_IP6_GTPU_IP6)
457         {
458           ip6_address_t zero_addr;
459           vnet_flow_ip6_gtpu_ip6_t *gu6 = &f->ip6_gtpu_ip6;
460
461           clib_memset (&zero_addr, 0, sizeof (ip6_address_t));
462
463           vec_add2 (items, item, 1);
464           item->type = RTE_FLOW_ITEM_TYPE_IPV6;
465
466           if (!clib_memcmp (&gu6->inner_src_addr.mask, &zero_addr, 16) &&
467               !clib_memcmp (&gu6->inner_dst_addr.mask, &zero_addr, 16))
468             {
469               item->spec = NULL;
470               item->mask = NULL;
471             }
472           else
473             {
474               clib_memcpy_fast (inner_ip6[0].hdr.src_addr,
475                                 &gu6->inner_src_addr.addr, 16);
476               clib_memcpy_fast (inner_ip6[1].hdr.src_addr,
477                                 &gu6->inner_src_addr.mask, 16);
478               clib_memcpy_fast (inner_ip6[0].hdr.dst_addr,
479                                 &gu6->inner_dst_addr.addr, 16);
480               clib_memcpy_fast (inner_ip6[1].hdr.dst_addr,
481                                 &gu6->inner_dst_addr.mask, 16);
482               item->spec = inner_ip6;
483               item->mask = inner_ip6 + 1;
484             }
485
486         }
487     }
488
489 pattern_end:
490   vec_add2 (items, item, 1);
491   item->type = RTE_FLOW_ITEM_TYPE_END;
492
493   /* Actions */
494   /* Only one 'fate' can be assigned */
495   if (f->actions & VNET_FLOW_ACTION_REDIRECT_TO_QUEUE)
496     {
497       vec_add2 (actions, action, 1);
498       queue.index = f->redirect_queue;
499       action->type = RTE_FLOW_ACTION_TYPE_QUEUE;
500       action->conf = &queue;
501       fate = true;
502     }
503   if (f->actions & VNET_FLOW_ACTION_DROP)
504     {
505       vec_add2 (actions, action, 1);
506       action->type = RTE_FLOW_ACTION_TYPE_DROP;
507       if (fate == true)
508         {
509           rv = VNET_FLOW_ERROR_INTERNAL;
510           goto done;
511         }
512       else
513         fate = true;
514     }
515   if (fate == false)
516     {
517       vec_add2 (actions, action, 1);
518       action->type = RTE_FLOW_ACTION_TYPE_PASSTHRU;
519     }
520
521   if (f->actions & VNET_FLOW_ACTION_MARK)
522     {
523       vec_add2 (actions, action, 1);
524       mark.id = fe->mark;
525       action->type = RTE_FLOW_ACTION_TYPE_MARK;
526       action->conf = &mark;
527     }
528
529   vec_add2 (actions, action, 1);
530   action->type = RTE_FLOW_ACTION_TYPE_END;
531
532   rv = rte_flow_validate (xd->device_index, &ingress, items, actions,
533                           &xd->last_flow_error);
534
535   if (rv)
536     {
537       if (rv == -EINVAL)
538         rv = VNET_FLOW_ERROR_NOT_SUPPORTED;
539       else if (rv == -EEXIST)
540         rv = VNET_FLOW_ERROR_ALREADY_EXISTS;
541       else
542         rv = VNET_FLOW_ERROR_INTERNAL;
543       goto done;
544     }
545
546   fe->handle = rte_flow_create (xd->device_index, &ingress, items, actions,
547                                 &xd->last_flow_error);
548
549   if (!fe->handle)
550     rv = VNET_FLOW_ERROR_NOT_SUPPORTED;
551
552 done:
553   vec_free (items);
554   vec_free (actions);
555   return rv;
556 }
557
558 int
559 dpdk_flow_ops_fn (vnet_main_t * vnm, vnet_flow_dev_op_t op, u32 dev_instance,
560                   u32 flow_index, uword * private_data)
561 {
562   dpdk_main_t *dm = &dpdk_main;
563   vnet_flow_t *flow = vnet_get_flow (flow_index);
564   dpdk_device_t *xd = vec_elt_at_index (dm->devices, dev_instance);
565   dpdk_flow_entry_t *fe;
566   dpdk_flow_lookup_entry_t *fle = 0;
567   int rv;
568
569   /* recycle old flow lookup entries only after the main loop counter
570      increases - i.e. previously DMA'ed packets were handled */
571   if (vec_len (xd->parked_lookup_indexes) > 0 &&
572       xd->parked_loop_count != dm->vlib_main->main_loop_count)
573     {
574       u32 *fl_index;
575
576       vec_foreach (fl_index, xd->parked_lookup_indexes)
577         pool_put_index (xd->flow_lookup_entries, *fl_index);
578       vec_reset_length (xd->parked_lookup_indexes);
579     }
580
581   if (op == VNET_FLOW_DEV_OP_DEL_FLOW)
582     {
583       fe = vec_elt_at_index (xd->flow_entries, *private_data);
584
585       if ((rv = rte_flow_destroy (xd->device_index, fe->handle,
586                                   &xd->last_flow_error)))
587         return VNET_FLOW_ERROR_INTERNAL;
588
589       if (fe->mark)
590         {
591           /* make sure no action is taken for in-flight (marked) packets */
592           fle = pool_elt_at_index (xd->flow_lookup_entries, fe->mark);
593           clib_memset (fle, -1, sizeof (*fle));
594           vec_add1 (xd->parked_lookup_indexes, fe->mark);
595           xd->parked_loop_count = dm->vlib_main->main_loop_count;
596         }
597
598       clib_memset (fe, 0, sizeof (*fe));
599       pool_put (xd->flow_entries, fe);
600
601       goto disable_rx_offload;
602     }
603
604   if (op != VNET_FLOW_DEV_OP_ADD_FLOW)
605     return VNET_FLOW_ERROR_NOT_SUPPORTED;
606
607   pool_get (xd->flow_entries, fe);
608   fe->flow_index = flow->index;
609
610   if (flow->actions == 0)
611     {
612       rv = VNET_FLOW_ERROR_NOT_SUPPORTED;
613       goto done;
614     }
615
616   /* if we need to mark packets, assign one mark */
617   if (flow->actions & (VNET_FLOW_ACTION_MARK |
618                        VNET_FLOW_ACTION_REDIRECT_TO_NODE |
619                        VNET_FLOW_ACTION_BUFFER_ADVANCE))
620     {
621       /* reserve slot 0 */
622       if (xd->flow_lookup_entries == 0)
623         pool_get_aligned (xd->flow_lookup_entries, fle,
624                           CLIB_CACHE_LINE_BYTES);
625       pool_get_aligned (xd->flow_lookup_entries, fle, CLIB_CACHE_LINE_BYTES);
626       fe->mark = fle - xd->flow_lookup_entries;
627
628       /* install entry in the lookup table */
629       clib_memset (fle, -1, sizeof (*fle));
630       if (flow->actions & VNET_FLOW_ACTION_MARK)
631         fle->flow_id = flow->mark_flow_id;
632       if (flow->actions & VNET_FLOW_ACTION_REDIRECT_TO_NODE)
633         fle->next_index = flow->redirect_device_input_next_index;
634       if (flow->actions & VNET_FLOW_ACTION_BUFFER_ADVANCE)
635         fle->buffer_advance = flow->buffer_advance;
636     }
637   else
638     fe->mark = 0;
639
640   if ((xd->flags & DPDK_DEVICE_FLAG_RX_FLOW_OFFLOAD) == 0)
641     {
642       xd->flags |= DPDK_DEVICE_FLAG_RX_FLOW_OFFLOAD;
643       dpdk_device_setup (xd);
644     }
645
646   switch (flow->type)
647     {
648     case VNET_FLOW_TYPE_ETHERNET:
649     case VNET_FLOW_TYPE_IP4_N_TUPLE:
650     case VNET_FLOW_TYPE_IP6_N_TUPLE:
651     case VNET_FLOW_TYPE_IP4_VXLAN:
652     case VNET_FLOW_TYPE_IP4_GTPC:
653     case VNET_FLOW_TYPE_IP4_GTPU:
654     case VNET_FLOW_TYPE_IP4_GTPU_IP4:
655     case VNET_FLOW_TYPE_IP4_GTPU_IP6:
656     case VNET_FLOW_TYPE_IP6_GTPC:
657     case VNET_FLOW_TYPE_IP6_GTPU:
658     case VNET_FLOW_TYPE_IP6_GTPU_IP4:
659     case VNET_FLOW_TYPE_IP6_GTPU_IP6:
660       if ((rv = dpdk_flow_add (xd, flow, fe)))
661         goto done;
662       break;
663     default:
664       rv = VNET_FLOW_ERROR_NOT_SUPPORTED;
665       goto done;
666     }
667
668   *private_data = fe - xd->flow_entries;
669
670 done:
671   if (rv)
672     {
673       clib_memset (fe, 0, sizeof (*fe));
674       pool_put (xd->flow_entries, fe);
675       if (fle)
676         {
677           clib_memset (fle, -1, sizeof (*fle));
678           pool_put (xd->flow_lookup_entries, fle);
679         }
680     }
681 disable_rx_offload:
682   if ((xd->flags & DPDK_DEVICE_FLAG_RX_FLOW_OFFLOAD) != 0
683       && pool_elts (xd->flow_entries) == 0)
684     {
685       xd->flags &= ~DPDK_DEVICE_FLAG_RX_FLOW_OFFLOAD;
686       dpdk_device_setup (xd);
687     }
688
689   return rv;
690 }
691
692 u8 *
693 format_dpdk_flow (u8 * s, va_list * args)
694 {
695   u32 dev_instance = va_arg (*args, u32);
696   u32 flow_index = va_arg (*args, u32);
697   uword private_data = va_arg (*args, uword);
698   dpdk_main_t *dm = &dpdk_main;
699   dpdk_device_t *xd = vec_elt_at_index (dm->devices, dev_instance);
700   dpdk_flow_entry_t *fe;
701
702   if (flow_index == ~0)
703     {
704       s = format (s, "%-25s: %U\n", "supported flow actions",
705                   format_flow_actions, xd->supported_flow_actions);
706       s = format (s, "%-25s: %d\n", "last DPDK error type",
707                   xd->last_flow_error.type);
708       s = format (s, "%-25s: %s\n", "last DPDK error message",
709                   xd->last_flow_error.message ? xd->last_flow_error.message :
710                   "n/a");
711       return s;
712     }
713
714   if (private_data >= vec_len (xd->flow_entries))
715     return format (s, "unknown flow");
716
717   fe = vec_elt_at_index (xd->flow_entries, private_data);
718   s = format (s, "mark %u", fe->mark);
719   return s;
720 }
721
722 /*
723  * fd.io coding-style-patch-verification: ON
724  *
725  * Local Variables:
726  * eval: (c-set-style "gnu")
727  * End:
728  */