From 8817061c7337c936da2553a4881098e1646d05dc Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Tue, 22 Nov 2016 08:29:51 +0000 Subject: Prevent a frame leak when a pending node dispatches packets to itself. this patch recognises the case where the pending frame has packets dispatched to the same to-node, i.e. when restoring the frame there now exists a new to-node frame, and then frees the frame in hand. Change-Id: If166bf56970b7b3412fa6097cd90bf22f72abe4d Signed-off-by: Neale Ranns --- vlib/vlib/main.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/vlib/vlib/main.c b/vlib/vlib/main.c index eba2d4535e8..fc294a72621 100644 --- a/vlib/vlib/main.c +++ b/vlib/vlib/main.c @@ -1141,18 +1141,42 @@ dispatch_pending_node (vlib_main_t * vm, /* Frame is ready to be used again, so restore it. */ if (restore_frame_index != ~0) { + /* we musn't restore a frame that is flagged to be freed. This shouldn't + happen since frames to be freed post dispatch are those used + when the to-node frame becomes full i.e. they form a sort of queue of + frames to a single node. If we get here then the to-node frame and the + pending frame *were* the same, and so we removed the to-node frame. + Therefore this frame is no longer part of the queue for that node + and hence it cannot be it's overspill. + */ + ASSERT (!(f->flags & VLIB_FRAME_FREE_AFTER_DISPATCH)); + /* p->next_frame_index can change during node dispatch if node function decides to change graph hook up. */ nf = vec_elt_at_index (nm->next_frames, p->next_frame_index); - nf->frame_index = restore_frame_index; nf->flags |= VLIB_FRAME_IS_ALLOCATED; - f->n_vectors = 0; - } - if (f->flags & VLIB_FRAME_FREE_AFTER_DISPATCH) + if (~0 == nf->frame_index) + { + /* no new frame has been assigned to this node, use the saved one */ + nf->frame_index = restore_frame_index; + f->n_vectors = 0; + } + else + { + /* 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); + } + } + else { - ASSERT (!(n->flags & VLIB_NODE_FLAG_FRAME_NO_FREE_AFTER_DISPATCH)); - vlib_frame_free (vm, n, f); + if (f->flags & VLIB_FRAME_FREE_AFTER_DISPATCH) + { + ASSERT (!(n->flags & VLIB_NODE_FLAG_FRAME_NO_FREE_AFTER_DISPATCH)); + vlib_frame_free (vm, n, f); + } } return last_time_stamp; -- cgit 1.2.3-korg