summaryrefslogtreecommitdiffstats
path: root/src/vnet/pipeline.h
blob: a4aa5cf5277df684e26bca7d6da6f5011a22bb49 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

@media only all and (prefers-color-scheme: dark) {
.highlight .hll { background-color: #49483e }
.highlight .c { color: #75715e } /* Comment */
.highlight .err { color: #960050; background-color: #1e0010 } /* Error */
.highlight .k { color: #66d9ef } /* Keyword */
.highlight .l { color: #ae81ff } /* Literal */
.highlight .n { color: #f8f8f2 } /* Name */
.highlight .o { color: #f92672 } /* Operator */
.highlight .p { color: #f8f8f2 } /* Punctuation */
.highlight .ch { color: #75715e } /* Comment.Hashbang */
.highlight .cm { color: #75715e } /* Comment.Multiline */
.highlight .cp { color: #75715e } /* Comment.Preproc */
.highlight .cpf { color: #75715e } /* Comment.PreprocFile */
.highlight .c1 { color: #75715e } /* Comment.Single */
.highlight .cs { color: #75715e } /* Comment.Special */
.highlight .gd { color: #f92672 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gi { color: #a6e22e } /* Generic.Inserted */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #75715e } /* Generic.Subheading */
.highlight .kc { color: #66d9ef } /* Keyword.Constant */
.highlight .kd { color: #66d9ef } /* Keyword.Declaration */
.highlight .kn { color: #f92672 } /* Keyword.Namespace */
.highlight .kp { color: #66d9ef } /* Keyword.Pseudo */
.highlight .kr { color: #66d9ef } /* Keyword.Reserved */
.highlight .kt { color: #66d9ef } /* Keyword.Type */
.highlight .ld { color: #e6db74 } /* Literal.Date */
.highlight .m { color: #ae81ff } /* Literal.Number */
.highlight .s { color: #e6db74 } /* Literal.String */
.highlight .na { color: #a6e22e } /* Name.Attribute */
.highlight .nb { color: #f8f8f2 } /* Name.Builtin */
.highlight .nc { color: #a6e22e } /* Name.Class */
.highlight .no { color: #66d9ef } /* Name.Constant */
.highlight .nd { color: #a6e22e } /* Name.Decorator */
.highlight .ni { color: #f8f8f2 } /* Name.Entity */
.highlight .ne { color: #a6e22e } /* Name.Exception */
.highlight .nf { color: #a6e22e } /* Name.Function */
.highlight .nl { color: #f8f8f2 } /* Name.Label */
.highlight .nn { color: #f8f8f2 } /* Name.Namespace */
.highlight .nx { color: #a6e22e } /* Name.Other */
.highlight .py { color: #f8f8f2 } /* Name.Property */
.highlight .nt { color: #f92672 } /* Name.Tag */
.highlight .nv { color: #f8f8f2 } /* Name.Variable */
.highlight .ow { color: #f92672 } /* Operator.Word */
.highlight .w { color: #f8f8f2 } /* Text.Whitespace */
.highlight .mb { color: #ae81ff } /* Literal.Number.Bin */
.highlight .mf { color: #ae81ff } /* Literal.Number.Float */
.highlight .mh { color: #ae81ff } /* Literal.Number.Hex */
.highlight .mi { color: #ae81ff } /* Literal.Number.Integer */
.highlight .mo { color: #ae81ff } /* Literal.Number.Oct */
.highlight .sa { color: #e6db74 } /* Literal.String.Affix */
.highlight .sb { color: #e6db74 } /* Literal.String.Backtick */
.highlight .sc { color: #e6db74 } /* Literal.String.Char */
.highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */
.highlight .sd { color: #e6db74 } /* Literal.String.Doc */
.highlight .s2 { color: #e6db74 } /* Literal.String.Double */
.highlight .se { color: #ae81ff } /* Literal.String.Escape */
.highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */
.highlight .si { color: #e6db74 } /* Literal.String.Interpol */
.highlight .sx { color: #e6db74 } /* Literal.String.Other */
.highlight .sr { color: #e6db74 } /* Literal.String.Regex */
.highlight .s1 { color: #e6db74 } /* Literal.String.Single */
.highlight .ss { color: #e6db74 } /* Literal.String.Symbol */
.highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #a6e22e } /* Name.Function.Magic */
.highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */
.highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */
.highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}
@media (prefers-color-scheme: light) {
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
}
/*
 * Copyright (c) 2016 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * @brief The IPv4 Multicast-FIB
 *
 * FIXME
 *
 * This IPv4 FIB is used by the protocol independent FIB. So directly using
 * this APIs in client code is not encouraged. However, this IPv4 FIB can be
 * used if all the client wants is an IPv4 prefix data-base
 */

#ifndef __IP6_MFIB_H__
#define __IP6_MFIB_H__

#include <vlib/vlib.h>
#include <vnet/ip/ip.h>

#include <vnet/mfib/mfib_table.h>

extern fib_node_index_t ip6_mfib_table_lookup(const ip6_mfib_t *fib<
/*
 * vnet/pipeline.h: software pipeline
 *
 * Copyright (c) 2012 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Usage example.
 *
 * #define NSTAGES 3 or whatever
 *
 * <Define pipeline stages>
 *
 * #include <vnet/pipeline.h>
 *
 * static uword my_node_fn (vlib_main_t * vm,
 *                               vlib_node_runtime_t * node,
 *                               vlib_frame_t * frame)
 * {
 *     return dispatch_pipeline (vm, node, frame);
 * }
 *
 */

#ifndef NSTAGES
#error files which #include <vnet/pipeline.h> must define NSTAGES
#endif

#ifndef STAGE_INLINE
#define STAGE_INLINE inline
#endif

/*
 * A prefetch stride of 2 is quasi-equivalent to doubling the number
 * of stages with every other pipeline stage empty.
 */

/*
 * This is a typical first pipeline stage, which prefetches
 * buffer metadata and the first line of pkt data.
 * To use it:
 *  #define stage0 generic_stage0
 */
static STAGE_INLINE void
generic_stage0 (vlib_main_t * vm,
		vlib_node_runtime_t * node, u32 buffer_index)
{
  /* generic default stage 0 here */
  vlib_buffer_t *b = vlib_get_buffer (vm, buffer_index);
  vlib_prefetch_buffer_header (b, STORE);
  CLIB_PREFETCH (b->data, CLIB_CACHE_LINE_BYTES, STORE);
}

#if NSTAGES == 2

static STAGE_INLINE uword
dispatch_pipeline (vlib_main_t * vm,
		   vlib_node_runtime_t * node, vlib_frame_t * frame)
{
  u32 *from = vlib_frame_vector_args (frame);
  u32 n_left_from, n_left_to_next, *to_next, next_index, next0;
  int pi, pi_limit;

  n_left_from = frame->n_vectors;
  next_index = node->cached_next_index;

  while (n_left_from > 0)
    {
      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);

      pi_limit = clib_min (n_left_from, n_left_to_next);

      for (pi = 0; pi < NSTAGES - 1; pi++)
	{
	  if (pi == pi_limit)
	    break;
	  stage0 (vm, node, from[pi]);
	}

      for (; pi < pi_limit; pi++)
	{
	  stage0 (vm, node, from[pi]);
	  to_next[0] = from[pi - 1];
	  to_next++;
	  n_left_to_next--;
	  next0 = last_stage (vm, node, from[pi - 1]);
	  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
					   to_next, n_left_to_next,
					   from[pi - 1], next0);
	  n_left_from--;
	  if ((int) n_left_to_next < 0 && n_left_from > 0)
	    vlib_get_next_frame (vm, node, next_index, to_next,
				 n_left_to_next);
	}

      for (; pi < (pi_limit + (NSTAGES - 1)); pi++)
	{
	  if (((pi - 1) >= 0) && ((pi - 1) < pi_limit))
	    {
	      to_next[0] = from[pi - 1];
	      to_next++;
	      n_left_to_next--;
	      next0 = last_stage (vm, node, from[pi - 1]);
	      vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
					       to_next, n_left_to_next,
					       from[pi - 1], next0);
	      n_left_from--;
	      if ((int) n_left_to_next < 0 && n_left_from > 0)
		vlib_get_next_frame (vm, node, next_index, to_next,
				     n_left_to_next);
	    }
	}
      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
      from += pi_limit;
    }
  return frame->n_vectors;
}
#endif

#if NSTAGES == 3
static STAGE_INLINE uword
dispatch_pipeline (vlib_main_t * vm,
		   vlib_node_runtime_t * node, vlib_frame_t * frame)
{
  u32 *from = vlib_frame_vector_args (frame);
  u32 n_left_from, n_left_to_next, *to_next, next_index, next0;
  int pi, pi_limit;

  n_left_from = frame->n_vectors;
  next_index = node->cached_next_index;

  while (n_left_from > 0)
    {
      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);

      pi_limit = clib_min (n_left_from, n_left_to_next);

      for (pi = 0; pi < NSTAGES - 1; pi++)
	{
	  if (pi == pi_limit)
	    break;
	  stage0 (vm, node, from[pi]);
	  if (pi - 1 >= 0)
	    stage1 (vm, node, from[pi - 1]);
	}

      for (; pi < pi_limit; pi++)
	{
	  stage0 (vm, node, from[pi]);
	  stage1 (vm, node, from[pi - 1]);
	  to_next[0] = from[pi - 2];
	  to_next++;
	  n_left_to_next--;
	  next0 = last_stage (vm, node, from[pi - 2]);
	  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
					   to_next, n_left_to_next,
					   from[pi - 2], next0);
	  n_left_from--;
	  if ((int) n_left_to_next < 0 && n_left_from > 0)
	    vlib_get_next_frame (vm, node, next_index, to_next,
				 n_left_to_next);
	}


      for (; pi < (pi_limit + (NSTAGES - 1)); pi++)
	{
	  if (((pi - 1) >= 0) && ((pi - 1) < pi_limit))
	    stage1 (vm, node, from[pi - 1]);
	  if (((pi - 2) >= 0) && ((pi - 2) < pi_limit))
	    {
	      to_next[0] = from[pi - 2];
	      to_next++;
	      n_left_to_next--;
	      next0 = last_stage (vm, node, from[pi - 2]);
	      vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
					       to_next, n_left_to_next,
					       from[pi - 2], next0);
	      n_left_from--;
	      if ((int) n_left_to_next < 0 && n_left_from > 0)
		vlib_get_next_frame (vm, node, next_index, to_next,
				     n_left_to_next);
	    }
	}

      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
      from += pi_limit;
    }
  return frame->n_vectors;
}
#endif

#if NSTAGES == 4
static STAGE_INLINE uword
dispatch_pipeline (vlib_main_t * vm,
		   vlib_node_runtime_t * node, vlib_frame_t * frame)
{
  u32 *from = vlib_frame_vector_args (frame);
  u32 n_left_from, n_left_to_next, *to_next, next_index, next0;
  int pi, pi_limit;

  n_left_from = frame->n_vectors;
  next_index = node->cached_next_index;

  while (n_left_from > 0)
    {
      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);

      pi_limit = clib_min (n_left_from, n_left_to_next);

      for (pi = 0; pi < NSTAGES - 1; pi++)
	{
	  if (pi == pi_limit)
	    break;
	  stage0 (vm, node, from[pi]);
	  if (pi - 1 >= 0)
	    stage1 (vm, node, from[pi - 1]);
	  if (pi - 2 >= 0)
	    stage2 (vm, node, from[pi - 2]);
	}

      for (; pi < pi_limit; pi++)
	{
	  stage0 (vm, node, from[pi]);
	  stage1 (vm, node, from[pi - 1]);
	  stage2 (vm, node, from[pi - 2]);
	  to_next[0] = from[pi - 3];
	  to_next++;
	  n_left_to_next--;
	  next0 = last_stage (vm, node, from[pi - 3]);
	  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
					   to_next, n_left_to_next,
					   from[pi - 3], next0);
	  n_left_from--;
	  if ((int) n_left_to_next < 0 && n_left_from > 0)
	    vlib_get_next_frame (vm, node, next_index, to_next,
				 n_left_to_next);
	}


      for (; pi < (pi_limit + (NSTAGES - 1)); pi++)
	{
	  if (((pi - 1) >= 0) && ((pi - 1) < pi_limit))
	    stage1 (vm, node, from[pi - 1]);
	  if (((pi - 2) >= 0) && ((pi - 2) < pi_limit))
	    stage2 (vm, node, from[pi - 2]);
	  if (((pi - 3) >= 0) && ((pi - 3) < pi_limit))
	    {
	      to_next[0] = from[pi - 3];
	      to_next++;
	      n_left_to_next--;
	      next0 = last_stage (vm, node, from[pi - 3]);
	      vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
					       to_next, n_left_to_next,
					       from[pi - 3], next0);
	      n_left_from--;
	      if ((int) n_left_to_next < 0 && n_left_from > 0)
		vlib_get_next_frame (vm, node, next_index, to_next,
				     n_left_to_next);
	    }
	}

      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
      from += pi_limit;
    }
  return frame->n_vectors;
}
#endif


#if NSTAGES == 5
static STAGE_INLINE uword
dispatch_pipeline (vlib_main_t * vm,
		   vlib_node_runtime_t * node, vlib_frame_t * frame)
{
  u32 *from = vlib_frame_vector_args (frame);
  u32 n_left_from, n_left_to_next, *to_next, next_index, next0;
  int pi, pi_limit;

  n_left_from = frame->n_vectors;
  next_index = node->cached_next_index;

  while (n_left_from > 0)
    {
      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);

      pi_limit = clib_min (n_left_from, n_left_to_next);

      for (pi = 0; pi < NSTAGES - 1; pi++)
	{
	  if (pi == pi_limit)
	    break;
	  stage0 (vm, node, from[pi]);
	  if (pi - 1 >= 0)
	    stage1 (vm, node, from[pi - 1]);
	  if (pi - 2 >= 0)
	    stage2 (vm, node, from[pi - 2]);
	  if (pi - 3 >= 0)
	    stage3 (vm, node, from[pi - 3]);
	}

      for (; pi < pi_limit; pi++)
	{
	  stage0 (vm, node, from[pi]);
	  stage1 (vm, node, from[pi - 1]);
	  stage2 (vm, node, from[pi - 2]);
	  stage3 (vm, node, from[pi - 3]);
	  to_next[0] = from[pi - 4];
	  to_next++;
	  n_left_to_next--;
	  next0 = last_stage (vm, node, from[pi - 4]);
	  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
					   to_next, n_left_to_next,
					   from[pi - 4], next0);
	  n_left_from--;
	  if ((int) n_left_to_next < 0 && n_left_from > 0)
	    vlib_get_next_frame (vm, node, next_index, to_next,
				 n_left_to_next);
	}


      for (; pi < (pi_limit + (NSTAGES - 1)); pi++)
	{
	  if (((pi - 1) >= 0) && ((pi - 1) < pi_limit))
	    stage1 (vm, node, from[pi - 1]);
	  if (((pi - 2) >= 0) && ((pi - 2) < pi_limit))
	    stage2 (vm, node, from[pi - 2]);
	  if (((pi - 3) >= 0) && ((pi - 3) < pi_limit))
	    stage3 (vm, node, from[pi - 3]);
	  if (((pi - 4) >= 0) && ((pi - 4) < pi_limit))
	    {
	      to_next[0] = from[pi - 4];
	      to_next++;
	      n_left_to_next--;
	      next0 = last_stage (vm, node, from[pi - 4]);
	      vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
					       to_next, n_left_to_next,
					       from[pi - 4], next0);
	      n_left_from--;
	      if ((int) n_left_to_next < 0 && n_left_from > 0)
		vlib_get_next_frame (vm, node, next_index, to_next,
				     n_left_to_next);
	    }
	}

      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
      from += pi_limit;
    }
  return frame->n_vectors;
}
#endif

#if NSTAGES == 6
static STAGE_INLINE uword
dispatch_pipeline (vlib_main_t * vm,
		   vlib_node_runtime_t * node, vlib_frame_t * frame)
{
  u32 *from = vlib_frame_vector_args (frame);
  u32 n_left_from, n_left_to_next, *to_next, next_index, next0;
  int pi, pi_limit;

  n_left_from = frame->n_vectors;
  next_index = node->cached_next_index;

  while (n_left_from > 0)
    {
      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);

      pi_limit = clib_min (n_left_from, n_left_to_next);

      for (pi = 0; pi < NSTAGES - 1; pi++)
	{
	  if (pi == pi_limit)
	    break;
	  stage0 (vm, node, from[pi]);
	  if (pi - 1 >= 0)
	    stage1 (vm, node, from[pi - 1]);
	  if (pi - 2 >= 0)
	    stage2 (vm, node, from[pi - 2]);
	  if (pi - 3 >= 0)
	    stage3 (vm, node, from[pi - 3]);
	  if (pi - 4 >= 0)
	    stage4 (vm, node, from[pi - 4]);
	}

      for (; pi < pi_limit; pi++)
	{
	  stage0 (vm, node, from[pi]);
	  stage1 (vm, node, from[pi - 1]);
	  stage2 (vm, node, from[pi - 2]);
	  stage3 (vm, node, from[pi - 3]);
	  stage4 (vm, node, from[pi - 4]);
	  to_next[0] = from[pi - 5];
	  to_next++;
	  n_left_to_next--;
	  next0 = last_stage (vm, node, from[pi - 5]);
	  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
					   to_next, n_left_to_next,
					   from[pi - 5], next0);
	  n_left_from--;
	  if ((int) n_left_to_next < 0 && n_left_from > 0)
	    vlib_get_next_frame (vm, node, next_index, to_next,
				 n_left_to_next);
	}


      for (; pi < (pi_limit + (NSTAGES - 1)); pi++)
	{
	  if (((pi - 1) >= 0) && ((pi - 1) < pi_limit))
	    stage1 (vm, node, from[pi - 1]);
	  if (((pi - 2) >= 0) && ((pi - 2) < pi_limit))
	    stage2 (vm, node, from[pi - 2]);
	  if (((pi - 3) >= 0) && ((pi - 3) < pi_limit))
	    stage3 (vm, node, from[pi - 3]);
	  if (((pi - 4) >= 0) && ((pi - 4) < pi_limit))
	    stage4 (vm, node, from[pi - 4]);
	  if (((pi - 5) >= 0) && ((pi - 5) < pi_limit))
	    {
	      to_next[0] = from[pi - 5];
	      to_next++;
	      n_left_to_next--;
	      next0 = last_stage (vm, node, from[pi - 5]);
	      vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
					       to_next, n_left_to_next,
					       from[pi - 5], next0);
	      n_left_from--;
	      if ((int) n_left_to_next < 0 && n_left_from > 0)
		vlib_get_next_frame (vm, node, next_index, to_next,
				     n_left_to_next);
	    }
	}

      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
      from += pi_limit;
    }
  return frame->n_vectors;
}
#endif

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */