vlib: don't leak node frames on refork

Free node frames in worker mains on refork. Otherwise these frames are
never returned to free pool and it causes massive memory leaks if
performed under traffic load

Type: fix
Signed-off-by: Dmitry Valter <d-valter@yandex-team.ru>
Change-Id: I15cbf024a3f4b4082445fd5e5aaa10bfcf77f363
diff --git a/src/vlib/drop.c b/src/vlib/drop.c
index d353d72..2a10225 100644
--- a/src/vlib/drop.c
+++ b/src/vlib/drop.c
@@ -236,7 +236,7 @@
 
       /* If there is no punt function, free the frame as well. */
       if (disposition == ERROR_DISPOSITION_PUNT && !vm->os_punt_frame)
-	vlib_frame_free (vm, node, frame);
+	vlib_frame_free (vm, frame);
     }
   else
     vm->os_punt_frame (vm, node, frame);
diff --git a/src/vlib/main.c b/src/vlib/main.c
index 9c7d6f5..964bc4a 100644
--- a/src/vlib/main.c
+++ b/src/vlib/main.c
@@ -106,6 +106,7 @@
   f->vector_offset = to_node->vector_offset;
   f->aux_offset = to_node->aux_offset;
   f->flags = 0;
+  f->frame_size_index = to_node->frame_size_index;
 
   fs->n_alloc_frames += 1;
 
@@ -186,17 +187,15 @@
 
 /* Free given frame. */
 void
-vlib_frame_free (vlib_main_t * vm, vlib_node_runtime_t * r, vlib_frame_t * f)
+vlib_frame_free (vlib_main_t *vm, vlib_frame_t *f)
 {
   vlib_node_main_t *nm = &vm->node_main;
-  vlib_node_t *node;
   vlib_frame_size_t *fs;
 
   ASSERT (vm == vlib_get_main ());
   ASSERT (f->frame_flags & VLIB_FRAME_IS_ALLOCATED);
 
-  node = vlib_get_node (vm, r->node_index);
-  fs = vec_elt_at_index (nm->frame_sizes, node->frame_size_index);
+  fs = vec_elt_at_index (nm->frame_sizes, f->frame_size_index);
 
   ASSERT (f->frame_flags & VLIB_FRAME_IS_ALLOCATED);
 
@@ -1171,7 +1170,7 @@
 	  /* The node has gained a frame, implying packets from the current frame
 	     were re-queued to this same node. we don't need the saved one
 	     anymore */
-	  vlib_frame_free (vm, n, f);
+	  vlib_frame_free (vm, f);
 	}
     }
   else
@@ -1179,7 +1178,7 @@
       if (f->frame_flags & VLIB_FRAME_FREE_AFTER_DISPATCH)
 	{
 	  ASSERT (!(n->flags & VLIB_NODE_FLAG_FRAME_NO_FREE_AFTER_DISPATCH));
-	  vlib_frame_free (vm, n, f);
+	  vlib_frame_free (vm, f);
 	}
     }
 
diff --git a/src/vlib/node.c b/src/vlib/node.c
index c6a13fb..4d1ef98 100644
--- a/src/vlib/node.c
+++ b/src/vlib/node.c
@@ -577,7 +577,7 @@
 
   vlib_node_increment_counter (vm, node->node_index, 0, n_vectors);
   vlib_buffer_free (vm, vlib_frame_vector_args (frame), n_vectors);
-  vlib_frame_free (vm, node, frame);
+  vlib_frame_free (vm, frame);
 
   return n_vectors;
 }
diff --git a/src/vlib/node.h b/src/vlib/node.h
index 1492326..dbff6c1 100644
--- a/src/vlib/node.h
+++ b/src/vlib/node.h
@@ -389,6 +389,9 @@
   /* Number of vector elements currently in frame. */
   u16 n_vectors;
 
+  /* Index of frame size corresponding to allocated node. */
+  u16 frame_size_index;
+
   /* Scalar and vector arguments to next node. */
   u8 arguments[0];
 } vlib_frame_t;
diff --git a/src/vlib/node_funcs.h b/src/vlib/node_funcs.h
index 0f9f30a..8672270 100644
--- a/src/vlib/node_funcs.h
+++ b/src/vlib/node_funcs.h
@@ -1256,8 +1256,7 @@
   return v >> VLIB_LOG2_MAIN_LOOPS_PER_STATS_UPDATE;
 }
 
-void
-vlib_frame_free (vlib_main_t * vm, vlib_node_runtime_t * r, vlib_frame_t * f);
+void vlib_frame_free (vlib_main_t *vm, vlib_frame_t *f);
 
 /* Return the edge index if present, ~0 otherwise */
 uword vlib_node_get_next (vlib_main_t * vm, uword node, uword next_node);
diff --git a/src/vlib/threads.c b/src/vlib/threads.c
index 5599c5b..adf225b 100644
--- a/src/vlib/threads.c
+++ b/src/vlib/threads.c
@@ -913,6 +913,17 @@
   vec_validate_aligned (old_counters_all_clear, j, CLIB_CACHE_LINE_BYTES);
   vm_clone->error_main.counters_last_clear = old_counters_all_clear;
 
+  for (j = 0; j < vec_len (nm_clone->next_frames); j++)
+    {
+      vlib_next_frame_t *nf = &nm_clone->next_frames[j];
+      if ((nf->flags & VLIB_FRAME_IS_ALLOCATED) && nf->frame != NULL)
+	{
+	  vlib_frame_t *f = nf->frame;
+	  nf->frame = NULL;
+	  vlib_frame_free (vm_clone, f);
+	}
+    }
+
   vec_free (nm_clone->next_frames);
   nm_clone->next_frames = vec_dup_aligned (nm->next_frames,
 					   CLIB_CACHE_LINE_BYTES);