FD.io VPP  v21.10.1-2-g0a485f517
Vector Packet Processing
flow.c
Go to the documentation of this file.
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>
24 #include <vnet/vxlan/vxlan.h>
25 #include <dpdk/device/dpdk.h>
26 #include <dpdk/device/dpdk_priv.h>
27 #include <vppinfra/error.h>
28 
29 #define FLOW_IS_ETHERNET_CLASS(f) \
30  (f->type == VNET_FLOW_TYPE_ETHERNET)
31 
32 #define FLOW_IS_IPV4_CLASS(f) \
33  ((f->type == VNET_FLOW_TYPE_IP4) || \
34  (f->type == VNET_FLOW_TYPE_IP4_N_TUPLE) || \
35  (f->type == VNET_FLOW_TYPE_IP4_N_TUPLE_TAGGED) || \
36  (f->type == VNET_FLOW_TYPE_IP4_VXLAN) || \
37  (f->type == VNET_FLOW_TYPE_IP4_GTPC) || \
38  (f->type == VNET_FLOW_TYPE_IP4_GTPU) || \
39  (f->type == VNET_FLOW_TYPE_IP4_L2TPV3OIP) || \
40  (f->type == VNET_FLOW_TYPE_IP4_IPSEC_ESP) || \
41  (f->type == VNET_FLOW_TYPE_IP4_IPSEC_AH))
42 
43 #define FLOW_IS_IPV6_CLASS(f) \
44  ((f->type == VNET_FLOW_TYPE_IP6) || \
45  (f->type == VNET_FLOW_TYPE_IP6_N_TUPLE) || \
46  (f->type == VNET_FLOW_TYPE_IP6_N_TUPLE_TAGGED) || \
47  (f->type == VNET_FLOW_TYPE_IP6_VXLAN))
48 
49 /* check if flow is VLAN sensitive */
50 #define FLOW_HAS_VLAN_TAG(f) \
51  ((f->type == VNET_FLOW_TYPE_IP4_N_TUPLE_TAGGED) || \
52  (f->type == VNET_FLOW_TYPE_IP6_N_TUPLE_TAGGED))
53 
54 /* check if flow is L3 type */
55 #define FLOW_IS_L3_TYPE(f) \
56  ((f->type == VNET_FLOW_TYPE_IP4) || \
57  (f->type == VNET_FLOW_TYPE_IP6))
58 
59 /* check if flow is L4 type */
60 #define FLOW_IS_L4_TYPE(f) \
61  ((f->type == VNET_FLOW_TYPE_IP4_N_TUPLE) || \
62  (f->type == VNET_FLOW_TYPE_IP6_N_TUPLE) || \
63  (f->type == VNET_FLOW_TYPE_IP4_N_TUPLE_TAGGED) || \
64  (f->type == VNET_FLOW_TYPE_IP6_N_TUPLE_TAGGED))
65 
66 /* check if flow is L4 tunnel type */
67 #define FLOW_IS_L4_TUNNEL_TYPE(f) \
68  ((f->type == VNET_FLOW_TYPE_IP4_VXLAN) || \
69  (f->type == VNET_FLOW_TYPE_IP6_VXLAN) || \
70  (f->type == VNET_FLOW_TYPE_IP4_GTPC) || \
71  (f->type == VNET_FLOW_TYPE_IP4_GTPU))
72 
73 /* constant structs */
74 static const struct rte_flow_attr ingress = {.ingress = 1 };
75 
76 static inline bool
78 {
79  int i = 0;
80 
81  for (i = 0; i < 6; i++)
82  if (addr[i] != 0)
83  return false;
84 
85  return true;
86 }
87 
88 static inline void
90 {
91 #define BIT_IS_SET(v, b) \
92  ((v) & (u64)1<<(b))
93 
94  *dpdk_rss_type = 0;
95 
96 #undef _
97 #define _(n, f, s) \
98  if (n != -1 && BIT_IS_SET(type, n)) \
99  *dpdk_rss_type |= f;
100 
102 #undef _
103  return;
104 }
105 
106 static inline enum rte_eth_hash_function
108 {
109  enum rte_eth_hash_function rss_func;
110 
111  switch (func)
112  {
113  case VNET_RSS_FUNC_DEFAULT:
114  rss_func = RTE_ETH_HASH_FUNCTION_DEFAULT;
115  break;
116  case VNET_RSS_FUNC_TOEPLITZ:
117  rss_func = RTE_ETH_HASH_FUNCTION_TOEPLITZ;
118  break;
119  case VNET_RSS_FUNC_SIMPLE_XOR:
120  rss_func = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
121  break;
122  case VNET_RSS_FUNC_SYMMETRIC_TOEPLITZ:
123  rss_func = RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ;
124  break;
125  default:
126  rss_func = RTE_ETH_HASH_FUNCTION_MAX;
127  break;
128  }
129 
130  return rss_func;
131 }
132 
133 static int
135 {
136  struct rte_flow_item_eth eth[2] = { };
137  struct rte_flow_item_ipv4 ip4[2] = { };
138  struct rte_flow_item_ipv6 ip6[2] = { };
139  struct rte_flow_item_udp udp[2] = { };
140  struct rte_flow_item_tcp tcp[2] = { };
141  struct rte_flow_item_gtp gtp[2] = { };
142  struct rte_flow_item_l2tpv3oip l2tp[2] = { };
143  struct rte_flow_item_esp esp[2] = { };
144  struct rte_flow_item_ah ah[2] = { };
145  struct rte_flow_action_mark mark = { 0 };
146  struct rte_flow_action_queue queue = { 0 };
147  struct rte_flow_action_rss rss = { 0 };
148  struct rte_flow_item *item, *items = 0;
149  struct rte_flow_action *action, *actions = 0;
150  bool fate = false;
151 
152  enum
153  {
154  vxlan_hdr_sz = sizeof (vxlan_header_t),
155  raw_sz = sizeof (struct rte_flow_item_raw)
156  };
157 
158  union
159  {
160  struct rte_flow_item_raw item;
161  u8 val[raw_sz + vxlan_hdr_sz];
162  } raw[2];
163 
164  u16 src_port = 0, dst_port = 0, src_port_mask = 0, dst_port_mask = 0;
165  u8 protocol = IP_PROTOCOL_RESERVED;
166  int rv = 0;
167 
168  enum
169  {
170  FLOW_UNKNOWN_CLASS,
171  FLOW_ETHERNET_CLASS,
172  FLOW_IPV4_CLASS,
173  FLOW_IPV6_CLASS,
174  } flow_class = FLOW_UNKNOWN_CLASS;
175 
177  flow_class = FLOW_ETHERNET_CLASS;
178  else if (FLOW_IS_IPV4_CLASS (f))
179  flow_class = FLOW_IPV4_CLASS;
180  else if (FLOW_IS_IPV6_CLASS (f))
181  flow_class = FLOW_IPV6_CLASS;
182  else
183  return VNET_FLOW_ERROR_NOT_SUPPORTED;
184 
185  if (f->actions & (~xd->supported_flow_actions))
186  return VNET_FLOW_ERROR_NOT_SUPPORTED;
187 
188  /* Match items */
189  /* Layer 2, Ethernet */
190  vec_add2 (items, item, 1);
191  item->type = RTE_FLOW_ITEM_TYPE_ETH;
192 
193  if (flow_class == FLOW_ETHERNET_CLASS)
194  {
195  vnet_flow_ethernet_t *te = &f->ethernet;
196 
197  clib_memset (&eth[0], 0, sizeof (eth[0]));
198  clib_memset (&eth[1], 0, sizeof (eth[1]));
199 
200  /* check if SMAC/DMAC/Ether_type assigned */
201  if (!mac_address_is_all_zero (te->eth_hdr.dst_address))
202  {
203  clib_memcpy_fast (&eth[0].dst, &te->eth_hdr.dst_address,
204  sizeof (eth[0].dst));
205  clib_memset (&eth[1].dst, 0xFF, sizeof (eth[1].dst));
206  }
207 
208  if (!mac_address_is_all_zero (te->eth_hdr.src_address))
209  {
210  clib_memcpy_fast (&eth[0].src, &te->eth_hdr.src_address,
211  sizeof (eth[0].src));
212  clib_memset (&eth[1].src, 0xFF, sizeof (eth[1].src));
213  }
214 
215  if (te->eth_hdr.type)
216  {
217  eth[0].type = clib_host_to_net_u16 (te->eth_hdr.type);
218  eth[1].type = clib_host_to_net_u16 (0xFFFF);
219  }
220 
221  item->spec = eth;
222  item->mask = eth + 1;
223  }
224  else
225  {
226  item->spec = NULL;
227  item->mask = NULL;
228  }
229 
230  /* currently only single empty vlan tag is supported */
231  if (FLOW_HAS_VLAN_TAG (f))
232  {
233  vec_add2 (items, item, 1);
234  item->type = RTE_FLOW_ITEM_TYPE_VLAN;
235  item->spec = NULL;
236  item->mask = NULL;
237  }
238 
240  goto pattern_end;
241 
242  /* Layer 3, IP */
243  vec_add2 (items, item, 1);
244  if (flow_class == FLOW_IPV4_CLASS)
245  {
246  vnet_flow_ip4_t *ip4_ptr = &f->ip4;
247 
248  item->type = RTE_FLOW_ITEM_TYPE_IPV4;
249  if ((!ip4_ptr->src_addr.mask.as_u32) &&
250  (!ip4_ptr->dst_addr.mask.as_u32) && (!ip4_ptr->protocol.mask))
251  {
252  item->spec = NULL;
253  item->mask = NULL;
254  }
255  else
256  {
257  ip4[0].hdr.src_addr = ip4_ptr->src_addr.addr.as_u32;
258  ip4[1].hdr.src_addr = ip4_ptr->src_addr.mask.as_u32;
259  ip4[0].hdr.dst_addr = ip4_ptr->dst_addr.addr.as_u32;
260  ip4[1].hdr.dst_addr = ip4_ptr->dst_addr.mask.as_u32;
261  ip4[0].hdr.next_proto_id = ip4_ptr->protocol.prot;
262  ip4[1].hdr.next_proto_id = ip4_ptr->protocol.mask;
263 
264  item->spec = ip4;
265  item->mask = ip4 + 1;
266  }
267 
269  {
270  vnet_flow_ip4_n_tuple_t *ip4_n_ptr = &f->ip4_n_tuple;
271 
272  src_port = ip4_n_ptr->src_port.port;
273  dst_port = ip4_n_ptr->dst_port.port;
274  src_port_mask = ip4_n_ptr->src_port.mask;
275  dst_port_mask = ip4_n_ptr->dst_port.mask;
276  }
277 
278  protocol = ip4_ptr->protocol.prot;
279  }
280  else if (flow_class == FLOW_IPV6_CLASS)
281  {
282  vnet_flow_ip6_t *ip6_ptr = &f->ip6;
283 
284  item->type = RTE_FLOW_ITEM_TYPE_IPV6;
285 
286  if ((ip6_ptr->src_addr.mask.as_u64[0] == 0) &&
287  (ip6_ptr->src_addr.mask.as_u64[1] == 0) &&
288  (!ip6_ptr->protocol.mask))
289  {
290  item->spec = NULL;
291  item->mask = NULL;
292  }
293  else
294  {
295  clib_memcpy (ip6[0].hdr.src_addr, &ip6_ptr->src_addr.addr,
296  ARRAY_LEN (ip6_ptr->src_addr.addr.as_u8));
297  clib_memcpy (ip6[1].hdr.src_addr, &ip6_ptr->src_addr.mask,
298  ARRAY_LEN (ip6_ptr->src_addr.mask.as_u8));
299  clib_memcpy (ip6[0].hdr.dst_addr, &ip6_ptr->dst_addr.addr,
300  ARRAY_LEN (ip6_ptr->dst_addr.addr.as_u8));
301  clib_memcpy (ip6[1].hdr.dst_addr, &ip6_ptr->dst_addr.mask,
302  ARRAY_LEN (ip6_ptr->dst_addr.mask.as_u8));
303  ip6[0].hdr.proto = ip6_ptr->protocol.prot;
304  ip6[1].hdr.proto = ip6_ptr->protocol.mask;
305 
306  item->spec = ip6;
307  item->mask = ip6 + 1;
308  }
309 
311  {
312  vnet_flow_ip6_n_tuple_t *ip6_n_ptr = &f->ip6_n_tuple;
313 
314  src_port = ip6_n_ptr->src_port.port;
315  dst_port = ip6_n_ptr->dst_port.port;
316  src_port_mask = ip6_n_ptr->src_port.mask;
317  dst_port_mask = ip6_n_ptr->dst_port.mask;
318  }
319 
320  protocol = ip6_ptr->protocol.prot;
321  }
322 
323  if (FLOW_IS_L3_TYPE (f))
324  goto pattern_end;
325 
326  /* Layer 3, IP */
327  vec_add2 (items, item, 1);
328  switch (protocol)
329  {
330  case IP_PROTOCOL_L2TP:
331  item->type = RTE_FLOW_ITEM_TYPE_L2TPV3OIP;
332  l2tp[0].session_id = clib_host_to_net_u32 (f->ip4_l2tpv3oip.session_id);
333  l2tp[1].session_id = ~0;
334 
335  item->spec = l2tp;
336  item->mask = l2tp + 1;
337  break;
338 
339  case IP_PROTOCOL_IPSEC_ESP:
340  item->type = RTE_FLOW_ITEM_TYPE_ESP;
341  esp[0].hdr.spi = clib_host_to_net_u32 (f->ip4_ipsec_esp.spi);
342  esp[1].hdr.spi = ~0;
343 
344  item->spec = esp;
345  item->mask = esp + 1;
346  break;
347 
348  case IP_PROTOCOL_IPSEC_AH:
349  item->type = RTE_FLOW_ITEM_TYPE_AH;
350  ah[0].spi = clib_host_to_net_u32 (f->ip4_ipsec_ah.spi);
351  ah[1].spi = ~0;
352 
353  item->spec = ah;
354  item->mask = ah + 1;
355  break;
356  case IP_PROTOCOL_TCP:
357  item->type = RTE_FLOW_ITEM_TYPE_TCP;
358  if ((src_port_mask == 0) && (dst_port_mask == 0))
359  {
360  item->spec = NULL;
361  item->mask = NULL;
362  }
363  else
364  {
365  tcp[0].hdr.src_port = clib_host_to_net_u16 (src_port);
366  tcp[1].hdr.src_port = clib_host_to_net_u16 (src_port_mask);
367  tcp[0].hdr.dst_port = clib_host_to_net_u16 (dst_port);
368  tcp[1].hdr.dst_port = clib_host_to_net_u16 (dst_port_mask);
369  item->spec = tcp;
370  item->mask = tcp + 1;
371  }
372  break;
373 
374  case IP_PROTOCOL_UDP:
375  item->type = RTE_FLOW_ITEM_TYPE_UDP;
376  if ((src_port_mask == 0) && (dst_port_mask == 0))
377  {
378  item->spec = NULL;
379  item->mask = NULL;
380  }
381  else
382  {
383  udp[0].hdr.src_port = clib_host_to_net_u16 (src_port);
384  udp[1].hdr.src_port = clib_host_to_net_u16 (src_port_mask);
385  udp[0].hdr.dst_port = clib_host_to_net_u16 (dst_port);
386  udp[1].hdr.dst_port = clib_host_to_net_u16 (dst_port_mask);
387  item->spec = udp;
388  item->mask = udp + 1;
389  }
390 
391  /* handle the UDP tunnels */
392  if (f->type == VNET_FLOW_TYPE_IP4_GTPC)
393  {
394  gtp[0].teid = clib_host_to_net_u32 (f->ip4_gtpc.teid);
395  gtp[1].teid = ~0;
396 
397  vec_add2 (items, item, 1);
398  item->type = RTE_FLOW_ITEM_TYPE_GTPC;
399  item->spec = gtp;
400  item->mask = gtp + 1;
401  }
402  else if (f->type == VNET_FLOW_TYPE_IP4_GTPU)
403  {
404  gtp[0].teid = clib_host_to_net_u32 (f->ip4_gtpu.teid);
405  gtp[1].teid = ~0;
406 
407  vec_add2 (items, item, 1);
408  item->type = RTE_FLOW_ITEM_TYPE_GTPU;
409  item->spec = gtp;
410  item->mask = gtp + 1;
411  }
412  else if (f->type == VNET_FLOW_TYPE_IP4_VXLAN)
413  {
414  u32 vni = f->ip4_vxlan.vni;
415 
416  vxlan_header_t spec_hdr = {
417  .flags = VXLAN_FLAGS_I,
418  .vni_reserved = clib_host_to_net_u32 (vni << 8)
419  };
420  vxlan_header_t mask_hdr = {
421  .flags = 0xff,
422  .vni_reserved = clib_host_to_net_u32 (((u32) - 1) << 8)
423  };
424 
425  clib_memset (raw, 0, sizeof raw);
426  raw[0].item.relative = 1;
427  raw[0].item.length = vxlan_hdr_sz;
428 
429  clib_memcpy_fast (raw[0].val + raw_sz, &spec_hdr, vxlan_hdr_sz);
430  raw[0].item.pattern = raw[0].val + raw_sz;
431  clib_memcpy_fast (raw[1].val + raw_sz, &mask_hdr, vxlan_hdr_sz);
432  raw[1].item.pattern = raw[1].val + raw_sz;
433 
434  vec_add2 (items, item, 1);
435  item->type = RTE_FLOW_ITEM_TYPE_RAW;
436  item->spec = raw;
437  item->mask = raw + 1;
438  }
439  break;
440 
441  default:
442  rv = VNET_FLOW_ERROR_NOT_SUPPORTED;
443  goto done;
444  }
445 
446 pattern_end:
447  if ((f->actions & VNET_FLOW_ACTION_RSS) &&
448  (f->rss_types & (1ULL << VNET_FLOW_RSS_TYPES_ESP)))
449  {
450 
451  vec_add2 (items, item, 1);
452  item->type = RTE_FLOW_ITEM_TYPE_ESP;
453  }
454 
455  vec_add2 (items, item, 1);
456  item->type = RTE_FLOW_ITEM_TYPE_END;
457 
458  /* Actions */
459  /* Only one 'fate' can be assigned */
460  if (f->actions & VNET_FLOW_ACTION_REDIRECT_TO_QUEUE)
461  {
462  vec_add2 (actions, action, 1);
463  queue.index = f->redirect_queue;
464  action->type = RTE_FLOW_ACTION_TYPE_QUEUE;
465  action->conf = &queue;
466  fate = true;
467  }
468 
469  if (f->actions & VNET_FLOW_ACTION_DROP)
470  {
471  vec_add2 (actions, action, 1);
472  action->type = RTE_FLOW_ACTION_TYPE_DROP;
473  if (fate == true)
474  {
475  rv = VNET_FLOW_ERROR_INTERNAL;
476  goto done;
477  }
478  else
479  fate = true;
480  }
481 
482  if (f->actions & VNET_FLOW_ACTION_RSS)
483  {
484  u64 rss_type = 0;
485 
486  vec_add2 (actions, action, 1);
487  action->type = RTE_FLOW_ACTION_TYPE_RSS;
488  action->conf = &rss;
489 
490  /* convert types to DPDK rss bitmask */
491  dpdk_flow_convert_rss_types (f->rss_types, &rss_type);
492 
493  rss.types = rss_type;
494  if ((rss.func = dpdk_flow_convert_rss_func (f->rss_fun)) ==
495  RTE_ETH_HASH_FUNCTION_MAX)
496  {
497  rv = VNET_FLOW_ERROR_NOT_SUPPORTED;
498  goto done;
499  }
500 
501  if (fate == true)
502  {
503  rv = VNET_FLOW_ERROR_INTERNAL;
504  goto done;
505  }
506  else
507  fate = true;
508  }
509 
510  if (fate == false)
511  {
512  vec_add2 (actions, action, 1);
513  action->type = RTE_FLOW_ACTION_TYPE_PASSTHRU;
514  }
515 
516  if (f->actions & VNET_FLOW_ACTION_MARK)
517  {
518  vec_add2 (actions, action, 1);
519  mark.id = fe->mark;
520  action->type = RTE_FLOW_ACTION_TYPE_MARK;
521  action->conf = &mark;
522  }
523 
524  vec_add2 (actions, action, 1);
525  action->type = RTE_FLOW_ACTION_TYPE_END;
526 
527  rv = rte_flow_validate (xd->device_index, &ingress, items, actions,
528  &xd->last_flow_error);
529 
530  if (rv)
531  {
532  if (rv == -EINVAL)
533  rv = VNET_FLOW_ERROR_NOT_SUPPORTED;
534  else if (rv == -EEXIST)
535  rv = VNET_FLOW_ERROR_ALREADY_EXISTS;
536  else
537  rv = VNET_FLOW_ERROR_INTERNAL;
538 
539  goto done;
540  }
541 
542  fe->handle = rte_flow_create (xd->device_index, &ingress, items, actions,
543  &xd->last_flow_error);
544 
545  if (!fe->handle)
546  rv = VNET_FLOW_ERROR_NOT_SUPPORTED;
547 
548 done:
549  vec_free (items);
550  vec_free (actions);
551  return rv;
552 }
553 
554 int
556  u32 flow_index, uword * private_data)
557 {
558  dpdk_main_t *dm = &dpdk_main;
559  vnet_flow_t *flow = vnet_get_flow (flow_index);
560  dpdk_device_t *xd = vec_elt_at_index (dm->devices, dev_instance);
561  dpdk_flow_entry_t *fe;
562  dpdk_flow_lookup_entry_t *fle = 0;
563  int rv;
564 
565  /* recycle old flow lookup entries only after the main loop counter
566  increases - i.e. previously DMA'ed packets were handled */
567  if (vec_len (xd->parked_lookup_indexes) > 0 &&
569  {
570  u32 *fl_index;
571 
572  vec_foreach (fl_index, xd->parked_lookup_indexes)
573  pool_put_index (xd->flow_lookup_entries, *fl_index);
575  }
576 
577  if (op == VNET_FLOW_DEV_OP_DEL_FLOW)
578  {
579  fe = vec_elt_at_index (xd->flow_entries, *private_data);
580 
581  if ((rv = rte_flow_destroy (xd->device_index, fe->handle,
582  &xd->last_flow_error)))
583  return VNET_FLOW_ERROR_INTERNAL;
584 
585  if (fe->mark)
586  {
587  /* make sure no action is taken for in-flight (marked) packets */
588  fle = pool_elt_at_index (xd->flow_lookup_entries, fe->mark);
589  clib_memset (fle, -1, sizeof (*fle));
592  }
593 
594  clib_memset (fe, 0, sizeof (*fe));
595  pool_put (xd->flow_entries, fe);
596 
597  goto disable_rx_offload;
598  }
599 
600  if (op != VNET_FLOW_DEV_OP_ADD_FLOW)
601  return VNET_FLOW_ERROR_NOT_SUPPORTED;
602 
603  pool_get (xd->flow_entries, fe);
604  fe->flow_index = flow->index;
605 
606  if (flow->actions == 0)
607  {
608  rv = VNET_FLOW_ERROR_NOT_SUPPORTED;
609  goto done;
610  }
611 
612  /* if we need to mark packets, assign one mark */
613  if (flow->actions & (VNET_FLOW_ACTION_MARK |
614  VNET_FLOW_ACTION_REDIRECT_TO_NODE |
615  VNET_FLOW_ACTION_BUFFER_ADVANCE))
616  {
617  /* reserve slot 0 */
618  if (xd->flow_lookup_entries == 0)
622  fe->mark = fle - xd->flow_lookup_entries;
623 
624  /* install entry in the lookup table */
625  clib_memset (fle, -1, sizeof (*fle));
626  if (flow->actions & VNET_FLOW_ACTION_MARK)
627  fle->flow_id = flow->mark_flow_id;
628  if (flow->actions & VNET_FLOW_ACTION_REDIRECT_TO_NODE)
629  fle->next_index = flow->redirect_device_input_next_index;
630  if (flow->actions & VNET_FLOW_ACTION_BUFFER_ADVANCE)
631  fle->buffer_advance = flow->buffer_advance;
632  }
633  else
634  fe->mark = 0;
635 
636  if ((xd->flags & DPDK_DEVICE_FLAG_RX_FLOW_OFFLOAD) == 0)
637  {
638  xd->flags |= DPDK_DEVICE_FLAG_RX_FLOW_OFFLOAD;
639  dpdk_device_setup (xd);
640  }
641 
642  switch (flow->type)
643  {
644  case VNET_FLOW_TYPE_ETHERNET:
645  case VNET_FLOW_TYPE_IP4:
646  case VNET_FLOW_TYPE_IP6:
647  case VNET_FLOW_TYPE_IP4_N_TUPLE:
648  case VNET_FLOW_TYPE_IP6_N_TUPLE:
649  case VNET_FLOW_TYPE_IP4_VXLAN:
650  case VNET_FLOW_TYPE_IP4_GTPC:
651  case VNET_FLOW_TYPE_IP4_GTPU:
652  case VNET_FLOW_TYPE_IP4_L2TPV3OIP:
653  case VNET_FLOW_TYPE_IP4_IPSEC_ESP:
654  case VNET_FLOW_TYPE_IP4_IPSEC_AH:
655  if ((rv = dpdk_flow_add (xd, flow, fe)))
656  goto done;
657  break;
658  default:
659  rv = VNET_FLOW_ERROR_NOT_SUPPORTED;
660  goto done;
661  }
662 
663  *private_data = fe - xd->flow_entries;
664 
665 done:
666  if (rv)
667  {
668  clib_memset (fe, 0, sizeof (*fe));
669  pool_put (xd->flow_entries, fe);
670  if (fle)
671  {
672  clib_memset (fle, -1, sizeof (*fle));
673  pool_put (xd->flow_lookup_entries, fle);
674  }
675  }
676 disable_rx_offload:
677  if ((xd->flags & DPDK_DEVICE_FLAG_RX_FLOW_OFFLOAD) != 0
678  && pool_elts (xd->flow_entries) == 0)
679  {
680  xd->flags &= ~DPDK_DEVICE_FLAG_RX_FLOW_OFFLOAD;
681  dpdk_device_setup (xd);
682  }
683 
684  return rv;
685 }
686 
687 u8 *
688 format_dpdk_flow (u8 * s, va_list * args)
689 {
690  u32 dev_instance = va_arg (*args, u32);
691  u32 flow_index = va_arg (*args, u32);
692  uword private_data = va_arg (*args, uword);
693  dpdk_main_t *dm = &dpdk_main;
694  dpdk_device_t *xd = vec_elt_at_index (dm->devices, dev_instance);
695  dpdk_flow_entry_t *fe;
696 
697  if (flow_index == ~0)
698  {
699  s = format (s, "%-25s: %U\n", "supported flow actions",
701  s = format (s, "%-25s: %d\n", "last DPDK error type",
702  xd->last_flow_error.type);
703  s = format (s, "%-25s: %s\n", "last DPDK error message",
704  xd->last_flow_error.message ? xd->last_flow_error.message :
705  "n/a");
706  return s;
707  }
708 
709  if (private_data >= vec_len (xd->flow_entries))
710  return format (s, "unknown flow");
711 
712  fe = vec_elt_at_index (xd->flow_entries, private_data);
713  s = format (s, "mark %u", fe->mark);
714  return s;
715 }
716 
717 /*
718  * fd.io coding-style-patch-verification: ON
719  *
720  * Local Variables:
721  * eval: (c-set-style "gnu")
722  * End:
723  */
vec_reset_length
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
Definition: vec_bootstrap.h:194
dpdk_flow_convert_rss_func
static enum rte_eth_hash_function dpdk_flow_convert_rss_func(vnet_rss_function_t func)
Definition: flow.c:107
dpdk_flow_lookup_entry_t::flow_id
u32 flow_id
Definition: dpdk.h:162
dpdk.h
dpdk_device_t::last_flow_error
struct rte_flow_error last_flow_error
Definition: dpdk.h:227
dpdk_device_t::supported_flow_actions
u32 supported_flow_actions
Definition: dpdk.h:222
vxlan.h
raw
const char *const const char *const raw
Definition: cJSON.h:270
dst_port
vl_api_ip_port_and_mask_t dst_port
Definition: flow_types.api:92
vlib_main_t::main_loop_count
volatile u32 main_loop_count
Definition: main.h:118
dpdk_device_t::flags
u16 flags
Definition: dpdk.h:200
clib_memcpy
#define clib_memcpy(d, s, n)
Definition: string.h:197
ip4
vl_api_ip4_address_t ip4
Definition: one.api:376
dpdk_main_t::devices
dpdk_device_t * devices
Definition: dpdk.h:361
dpdk_flow_convert_rss_types
static void dpdk_flow_convert_rss_types(u64 type, u64 *dpdk_rss_type)
Definition: flow.c:89
vnet_get_flow
vnet_flow_t * vnet_get_flow(u32 flow_index)
Definition: flow.c:57
f
vlib_frame_t * f
Definition: interface_output.c:1098
pool_elt_at_index
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:549
pool_get_aligned
#define pool_get_aligned(P, E, A)
Allocate an object E from a pool P with alignment A.
Definition: pool.h:249
vxlan_header_t
Definition: vxlan_packet.h:44
vni
u32 vni
Definition: flow_types.api:160
vnet_rss_function_t
vnet_rss_function_t
Definition: flow.h:201
u16
unsigned short u16
Definition: types.h:57
pool_put
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:305
flow
Definition: flow_types.api:196
dpdk_device_setup
void dpdk_device_setup(dpdk_device_t *xd)
Definition: common.c:42
FLOW_IS_L3_TYPE
#define FLOW_IS_L3_TYPE(f)
Definition: flow.c:55
addr
vhost_vring_addr_t addr
Definition: vhost_user.h:130
format_dpdk_flow
u8 * format_dpdk_flow(u8 *s, va_list *args)
Definition: flow.c:688
clib_memcpy_fast
static_always_inline void * clib_memcpy_fast(void *restrict dst, const void *restrict src, size_t n)
Definition: string.h:92
pool_put_index
#define pool_put_index(p, i)
Free pool element with given index.
Definition: pool.h:337
ethernet.h
dpdk_device_t::parked_loop_count
u32 parked_loop_count
Definition: dpdk.h:226
FLOW_HAS_VLAN_TAG
#define FLOW_HAS_VLAN_TAG(f)
Definition: flow.c:50
VXLAN_FLAGS_I
#define VXLAN_FLAGS_I
Definition: vxlan_packet.h:53
mac_address_is_all_zero
static bool mac_address_is_all_zero(const u8 addr[6])
Definition: flow.c:77
vec_len
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
Definition: vec_bootstrap.h:142
error.h
vec_add2
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:644
vec_add1
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:606
vec_elt_at_index
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
Definition: vec_bootstrap.h:203
dpdk_flow_entry_t::handle
struct rte_flow * handle
Definition: dpdk.h:157
dpdk_flow_lookup_entry_t::buffer_advance
i16 buffer_advance
Definition: dpdk.h:164
ARRAY_LEN
#define ARRAY_LEN(x)
Definition: clib.h:70
dpdk_device_t::device_index
u32 device_index
Definition: dpdk.h:190
dpdk_main
dpdk_main_t dpdk_main
Definition: init.c:48
dpdk_main_t
Definition: dpdk.h:357
vxlan_header_t::flags
u8 flags
Definition: vxlan_packet.h:46
uword
u64 uword
Definition: types.h:112
vnet_flow_dev_op_t
vnet_flow_dev_op_t
Definition: interface.h:96
src_port
vl_api_ip_port_and_mask_t src_port
Definition: flow_types.api:91
pool_get
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:255
format.h
VNET_FLOW_DEV_OP_DEL_FLOW
@ VNET_FLOW_DEV_OP_DEL_FLOW
Definition: interface.h:99
src
vl_api_address_t src
Definition: gre.api:54
vnet_flow_t
Definition: flow.h:223
CLIB_CACHE_LINE_BYTES
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:58
VNET_FLOW_DEV_OP_ADD_FLOW
@ VNET_FLOW_DEV_OP_ADD_FLOW
Definition: interface.h:98
dpdk_flow_entry_t::flow_index
u32 flow_index
Definition: dpdk.h:155
dpdk_flow_entry_t
Definition: dpdk.h:153
FLOW_IS_IPV4_CLASS
#define FLOW_IS_IPV4_CLASS(f)
Definition: flow.c:32
vnet_main_t
Definition: vnet.h:76
vec_free
#define vec_free(V)
Free vector's memory (no header).
Definition: vec.h:395
dpdk_device_t::parked_lookup_indexes
u32 * parked_lookup_indexes
Definition: dpdk.h:225
dpdk_device_t::flow_lookup_entries
dpdk_flow_lookup_entry_t * flow_lookup_entries
Definition: dpdk.h:224
FLOW_IS_ETHERNET_CLASS
#define FLOW_IS_ETHERNET_CLASS(f)
Definition: flow.c:29
u64
unsigned long u64
Definition: types.h:89
format
description fragment has unexpected format
Definition: map.api:433
ip.h
u32
unsigned int u32
Definition: types.h:88
ip6
vl_api_ip6_address_t ip6
Definition: one.api:424
protocol
vl_api_ip_proto_t protocol
Definition: lb_types.api:72
FLOW_IS_L4_TUNNEL_TYPE
#define FLOW_IS_L4_TUNNEL_TYPE(f)
Definition: flow.c:67
dst
vl_api_ip4_address_t dst
Definition: pnat.api:41
dpdk_flow_entry_t::mark
u32 mark
Definition: dpdk.h:156
vec_foreach
#define vec_foreach(var, vec)
Vector iterator.
Definition: vec_bootstrap.h:213
pool_elts
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:127
actions
vl_api_flow_action_t actions
Definition: flow_types.api:224
vec.h
dpdk_flow_add
static int dpdk_flow_add(dpdk_device_t *xd, vnet_flow_t *f, dpdk_flow_entry_t *fe)
Definition: flow.c:134
dpdk_main_t::vlib_main
vlib_main_t * vlib_main
Definition: dpdk.h:378
clib_memset
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
item
cJSON * item
Definition: cJSON.h:222
dpdk_flow_lookup_entry_t::next_index
u16 next_index
Definition: dpdk.h:163
u8
unsigned char u8
Definition: types.h:56
arp_packet.h
dpdk_device_t::flow_entries
dpdk_flow_entry_t * flow_entries
Definition: dpdk.h:223
i
int i
Definition: flowhash_template.h:376
rv
int __clib_unused rv
Definition: application.c:491
vnet.h
format_flow_actions
format_function_t format_flow_actions
Definition: flow.h:295
action
vl_api_mac_event_action_t action
Definition: l2.api:211
cJSON::type
int type
Definition: cJSON.h:112
dpdk_flow_ops_fn
int dpdk_flow_ops_fn(vnet_main_t *vnm, vnet_flow_dev_op_t op, u32 dev_instance, u32 flow_index, uword *private_data)
Definition: flow.c:555
foreach_dpdk_rss_hf
#define foreach_dpdk_rss_hf
Definition: dpdk.h:449
type
vl_api_fib_path_type_t type
Definition: fib_types.api:123
FLOW_IS_IPV6_CLASS
#define FLOW_IS_IPV6_CLASS(f)
Definition: flow.c:43
FLOW_IS_L4_TYPE
#define FLOW_IS_L4_TYPE(f)
Definition: flow.c:60
ingress
static const struct rte_flow_attr ingress
Definition: flow.c:74
dpdk_priv.h
dpdk_flow_lookup_entry_t
Definition: dpdk.h:160
dpdk_device_t
Definition: dpdk.h:182