diff options
author | Neale Ranns <nranns@cisco.com> | 2016-11-22 08:29:51 +0000 |
---|---|---|
committer | Dave Barach <openvpp@barachs.net> | 2016-11-22 18:22:41 +0000 |
commit | 8817061c7337c936da2553a4881098e1646d05dc (patch) | |
tree | 6e167b33db7005c35782671ab1c7718782ecbcad | |
parent | fba8a9510283a1b7d8e047fe93a47612c4c1b7cd (diff) |
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 <nranns@cisco.com>
-rw-r--r-- | vlib/vlib/main.c | 36 |
1 files 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; |