flow: add rte_flow check before creating by rte_flow_validate
[vpp.git] / src / plugins / dpdk / device / flow.c
index a9ba1d0..3f95531 100644 (file)
@@ -84,10 +84,10 @@ dpdk_flow_add (dpdk_device_t * xd, vnet_flow_t * f, dpdk_flow_entry_t * fe)
   if (f->type == VNET_FLOW_TYPE_IP6_N_TUPLE)
     {
       vnet_flow_ip6_n_tuple_t *t6 = &f->ip6_n_tuple;
-      clib_memcpy (ip6[0].hdr.src_addr, &t6->src_addr.addr, 16);
-      clib_memcpy (ip6[1].hdr.src_addr, &t6->src_addr.mask, 16);
-      clib_memcpy (ip6[0].hdr.dst_addr, &t6->dst_addr.addr, 16);
-      clib_memcpy (ip6[1].hdr.dst_addr, &t6->dst_addr.mask, 16);
+      clib_memcpy_fast (ip6[0].hdr.src_addr, &t6->src_addr.addr, 16);
+      clib_memcpy_fast (ip6[1].hdr.src_addr, &t6->src_addr.mask, 16);
+      clib_memcpy_fast (ip6[0].hdr.dst_addr, &t6->dst_addr.addr, 16);
+      clib_memcpy_fast (ip6[1].hdr.dst_addr, &t6->dst_addr.mask, 16);
       item->type = RTE_FLOW_ITEM_TYPE_IPV6;
       item->spec = ip6;
       item->mask = ip6 + 1;
@@ -179,12 +179,14 @@ dpdk_flow_add (dpdk_device_t * xd, vnet_flow_t * f, dpdk_flow_entry_t * fe)
        .vni_reserved = clib_host_to_net_u32 (((u32) - 1) << 8)
       };
 
-      memset (raw, 0, sizeof raw);
+      clib_memset (raw, 0, sizeof raw);
       raw[0].item.relative = 1;
       raw[0].item.length = vxlan_hdr_sz;
 
-      clib_memcpy (raw[0].val + raw_sz, &spec_hdr, vxlan_hdr_sz);
-      clib_memcpy (raw[1].val + raw_sz, &mask_hdr, vxlan_hdr_sz);;
+      clib_memcpy_fast (raw[0].val + raw_sz, &spec_hdr, vxlan_hdr_sz);
+      raw[0].item.pattern = raw[0].val + raw_sz;
+      clib_memcpy_fast (raw[1].val + raw_sz, &mask_hdr, vxlan_hdr_sz);
+      raw[1].item.pattern = raw[1].val + raw_sz;
 
       vec_add2 (items, item, 1);
       item->type = RTE_FLOW_ITEM_TYPE_RAW;
@@ -207,6 +209,20 @@ dpdk_flow_add (dpdk_device_t * xd, vnet_flow_t * f, dpdk_flow_entry_t * fe)
   vec_add2 (actions, action, 1);
   action->type = RTE_FLOW_ACTION_TYPE_END;
 
+  rv = rte_flow_validate (xd->device_index, &ingress, items, actions,
+                         &xd->last_flow_error);
+
+  if (rv)
+    {
+      if (rv == -EINVAL)
+       rv = VNET_FLOW_ERROR_NOT_SUPPORTED;
+      else if (rv == -EEXIST)
+       rv = VNET_FLOW_ERROR_ALREADY_EXISTS;
+      else
+       rv = VNET_FLOW_ERROR_INTERNAL;
+      goto done;
+    }
+
   fe->handle = rte_flow_create (xd->device_index, &ingress, items, actions,
                                &xd->last_flow_error);
 
@@ -230,6 +246,18 @@ dpdk_flow_ops_fn (vnet_main_t * vnm, vnet_flow_dev_op_t op, u32 dev_instance,
   dpdk_flow_lookup_entry_t *fle = 0;
   int rv;
 
+  /* recycle old flow lookup entries only after the main loop counter
+     increases - i.e. previously DMA'ed packets were handled */
+  if (vec_len (xd->parked_lookup_indexes) > 0 &&
+      xd->parked_loop_count != dm->vlib_main->main_loop_count)
+    {
+      u32 *fl_index;
+
+      vec_foreach (fl_index, xd->parked_lookup_indexes)
+       pool_put_index (xd->flow_lookup_entries, *fl_index);
+      vec_reset_length (xd->flow_lookup_entries);
+    }
+
   if (op == VNET_FLOW_DEV_OP_DEL_FLOW)
     {
       ASSERT (*private_data >= vec_len (xd->flow_entries));
@@ -240,7 +268,16 @@ dpdk_flow_ops_fn (vnet_main_t * vnm, vnet_flow_dev_op_t op, u32 dev_instance,
                                  &xd->last_flow_error)))
        return VNET_FLOW_ERROR_INTERNAL;
 
-      memset (fe, 0, sizeof (*fe));
+      if (fe->mark)
+       {
+         /* make sure no action is taken for in-flight (marked) packets */
+         fle = pool_elt_at_index (xd->flow_lookup_entries, fe->mark);
+         clib_memset (fle, -1, sizeof (*fle));
+         vec_add1 (xd->parked_lookup_indexes, fe->mark);
+         xd->parked_loop_count = dm->vlib_main->main_loop_count;
+       }
+
+      clib_memset (fe, 0, sizeof (*fe));
       pool_put (xd->flow_entries, fe);
 
       goto disable_rx_offload;
@@ -269,6 +306,15 @@ dpdk_flow_ops_fn (vnet_main_t * vnm, vnet_flow_dev_op_t op, u32 dev_instance,
                          CLIB_CACHE_LINE_BYTES);
       pool_get_aligned (xd->flow_lookup_entries, fle, CLIB_CACHE_LINE_BYTES);
       fe->mark = fle - xd->flow_lookup_entries;
+
+      /* install entry in the lookup table */
+      clib_memset (fle, -1, sizeof (*fle));
+      if (flow->actions & VNET_FLOW_ACTION_MARK)
+       fle->flow_id = flow->mark_flow_id;
+      if (flow->actions & VNET_FLOW_ACTION_REDIRECT_TO_NODE)
+       fle->next_index = flow->redirect_device_input_next_index;
+      if (flow->actions & VNET_FLOW_ACTION_BUFFER_ADVANCE)
+       fle->buffer_advance = flow->buffer_advance;
     }
   else
     fe->mark = 0;
@@ -294,23 +340,14 @@ dpdk_flow_ops_fn (vnet_main_t * vnm, vnet_flow_dev_op_t op, u32 dev_instance,
 
   *private_data = fe - xd->flow_entries;
 
-  /* install entry in the lookup table */
-  memset (fle, -1, sizeof (*fle));
-  if (flow->actions & VNET_FLOW_ACTION_MARK)
-    fle->flow_id = flow->mark_flow_id;
-  if (flow->actions & VNET_FLOW_ACTION_REDIRECT_TO_NODE)
-    fle->next_index = flow->redirect_device_input_next_index;
-  if (flow->actions & VNET_FLOW_ACTION_BUFFER_ADVANCE)
-    fle->buffer_advance = flow->buffer_advance;
-
 done:
   if (rv)
     {
-      memset (fe, 0, sizeof (*fe));
+      clib_memset (fe, 0, sizeof (*fe));
       pool_put (xd->flow_entries, fe);
       if (fle)
        {
-         memset (fle, 0, sizeof (*fle));
+         clib_memset (fle, -1, sizeof (*fle));
          pool_put (xd->flow_lookup_entries, fle);
        }
     }
@@ -347,11 +384,10 @@ format_dpdk_flow (u8 * s, va_list * args)
       return s;
     }
 
-  fe = vec_elt_at_index (xd->flow_entries, private_data);
-
-  if (!fe)
+  if (private_data >= vec_len (xd->flow_entries))
     return format (s, "unknown flow");
 
+  fe = vec_elt_at_index (xd->flow_entries, private_data);
   s = format (s, "mark %u", fe->mark);
   return s;
 }