ip: SVR fix race condition
[vpp.git] / src / vnet / ip / reass / ip4_sv_reass.c
index 3117780..9971daf 100644 (file)
@@ -321,6 +321,8 @@ ip4_sv_reass_find_or_create (vlib_main_t * vm, ip4_sv_reass_main_t * rm,
   ip4_sv_reass_t *reass = NULL;
   f64 now = vlib_time_now (vm);
 
+again:
+
   if (!clib_bihash_search_16_8 (&rm->hash, &kv->kv, &kv->kv))
     {
       if (vm->thread_index != kv->v.thread_index)
@@ -375,10 +377,14 @@ ip4_sv_reass_find_or_create (vlib_main_t * vm, ip4_sv_reass_main_t * rm,
   kv->v.thread_index = vm->thread_index;
   reass->last_heard = now;
 
-  if (clib_bihash_add_del_16_8 (&rm->hash, &kv->kv, 1))
+  int rv = clib_bihash_add_del_16_8 (&rm->hash, &kv->kv, 2);
+  if (rv)
     {
       ip4_sv_reass_free (vm, rm, rt, reass);
       reass = NULL;
+      // if other worker created a context already work with the other copy
+      if (-2 == rv)
+       goto again;
     }
 
   return reass;
@@ -846,24 +852,24 @@ slow_path:
 
          ip4_sv_reass_rc_t rc =
            ip4_sv_reass_update (vm, node, rm, ip0, reass, bi0);
+         u32 counter = ~0;
          switch (rc)
            {
            case IP4_SV_REASS_RC_OK:
              /* nothing to do here */
              break;
            case IP4_SV_REASS_RC_TOO_MANY_FRAGMENTS:
-             vlib_node_increment_counter (vm, node->node_index,
-                                          IP4_ERROR_REASS_FRAGMENT_CHAIN_TOO_LONG,
-                                          1);
-             ip4_sv_reass_free (vm, rm, rt, reass);
-             goto next_packet;
+             counter = IP4_ERROR_REASS_FRAGMENT_CHAIN_TOO_LONG;
              break;
            case IP4_SV_REASS_RC_UNSUPP_IP_PROTO:
-             vlib_node_increment_counter (vm, node->node_index,
-                                          IP4_ERROR_REASS_UNSUPP_IP_PROT, 1);
+             counter = IP4_ERROR_REASS_UNSUPP_IP_PROT;
+             break;
+           }
+         if (~0 != counter)
+           {
+             vlib_node_increment_counter (vm, node->node_index, counter, 1);
              ip4_sv_reass_free (vm, rm, rt, reass);
              goto next_packet;
-             break;
            }
          if (reass->is_complete)
            {