2177ccb9d14a27a981d3378c8e088ae905e817ca
[vpp.git] / src / examples / handoffdemo / node.c
1 /*
2  * node.c - skeleton vpp engine plug-in dual-loop node skeleton
3  *
4  * Copyright (c) <current-year> <your-organization>
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #include <vlib/vlib.h>
18 #include <vnet/vnet.h>
19 #include <vnet/pg/pg.h>
20 #include <vppinfra/error.h>
21 #include <handoffdemo/handoffdemo.h>
22
23 typedef struct
24 {
25   int current_thread;
26 } handoffdemo_trace_t;
27
28 /* packet trace format function */
29 static u8 *
30 format_handoffdemo_trace (u8 * s, va_list * args)
31 {
32   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
33   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
34   handoffdemo_trace_t *t = va_arg (*args, handoffdemo_trace_t *);
35
36   s = format (s, "HANDOFFDEMO: current thread %d", t->current_thread);
37
38   return s;
39 }
40
41 vlib_node_registration_t handoffdemo_node;
42
43 #define foreach_handoffdemo_error                       \
44 _(HANDED_OFF, "packets handed off processed")           \
45 _(CONGESTION_DROP, "handoff queue congestion drops")    \
46 _(COMPLETE, "completed packets")
47
48 typedef enum
49 {
50 #define _(sym,str) HANDOFFDEMO_ERROR_##sym,
51   foreach_handoffdemo_error
52 #undef _
53     HANDOFFDEMO_N_ERROR,
54 } handoffdemo_error_t;
55
56 static char *handoffdemo_error_strings[] = {
57 #define _(sym,string) string,
58   foreach_handoffdemo_error
59 #undef _
60 };
61
62 typedef enum
63 {
64   HANDOFFDEMO_NEXT_DROP,
65   HANDOFFDEMO_N_NEXT,
66 } handoffdemo_next_t;
67
68 always_inline uword
69 handoffdemo_inline (vlib_main_t * vm,
70                     vlib_node_runtime_t * node, vlib_frame_t * frame,
71                     int which, int is_trace)
72 {
73   handoffdemo_main_t *hmp = &handoffdemo_main;
74   u32 n_left_from, *from;
75   u32 error0 = node->errors[HANDOFFDEMO_ERROR_COMPLETE];
76   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
77   u16 thread_indices[VLIB_FRAME_SIZE];
78   u16 nexts[VLIB_FRAME_SIZE], *next;
79   u32 n_enq;
80   int i;
81
82   from = vlib_frame_vector_args (frame);
83   n_left_from = frame->n_vectors;
84
85   vlib_get_buffers (vm, from, bufs, n_left_from);
86   next = nexts;
87   b = bufs;
88
89   /* First thread */
90   if (which == 1)
91     {
92       for (i = 0; i < frame->n_vectors; i++)
93         {
94           /* Pick a thread to handle this packet */
95           thread_indices[i] = 2;
96
97           if (is_trace && (b[0]->flags & VLIB_BUFFER_IS_TRACED))
98             {
99               handoffdemo_trace_t *t = vlib_add_trace (vm, node, b[0],
100                                                        sizeof (*t));
101               t->current_thread = vm->thread_index;
102             }
103
104           b += 1;
105           next += 1;
106           n_left_from -= 1;
107         }
108
109       /* Enqueue buffers to threads */
110       n_enq =
111         vlib_buffer_enqueue_to_thread (vm, hmp->frame_queue_index,
112                                        from, thread_indices, frame->n_vectors,
113                                        1 /* drop on congestion */ );
114       if (n_enq < frame->n_vectors)
115         vlib_node_increment_counter (vm, node->node_index,
116                                      HANDOFFDEMO_ERROR_CONGESTION_DROP,
117                                      frame->n_vectors - n_enq);
118       vlib_node_increment_counter (vm, node->node_index,
119                                    HANDOFFDEMO_ERROR_HANDED_OFF, n_enq);
120       return frame->n_vectors;
121     }
122   else                          /* Second thread */
123     {
124       u32 *from;
125
126       from = vlib_frame_vector_args (frame);
127       n_left_from = frame->n_vectors;
128
129       vlib_get_buffers (vm, from, bufs, n_left_from);
130       next = nexts;
131       b = bufs;
132
133       while (n_left_from > 0)
134         {
135           if (is_trace && (b[0]->flags & VLIB_BUFFER_IS_TRACED))
136             {
137               handoffdemo_trace_t *t = vlib_add_trace (vm, node, b[0],
138                                                        sizeof (*t));
139               t->current_thread = vm->thread_index;
140             }
141
142           next[0] = HANDOFFDEMO_NEXT_DROP;
143           b[0]->error = error0;
144           next++;
145           b++;
146           n_left_from--;
147         }
148
149       vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
150                                    frame->n_vectors);
151     }
152
153   return frame->n_vectors;
154 }
155
156 static uword
157 handoffdemo_node_1_fn (vlib_main_t * vm,
158                        vlib_node_runtime_t * node, vlib_frame_t * frame)
159 {
160   if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
161     return handoffdemo_inline (vm, node, frame, 1 /* which */ ,
162                                1 /* is_trace */ );
163   else
164     return handoffdemo_inline (vm, node, frame, 1 /* which */ ,
165                                0 /* is_trace */ );
166 }
167
168 /* *INDENT-OFF* */
169 VLIB_REGISTER_NODE (handoffdemo_node_1) =
170 {
171   .name = "handoffdemo-1",
172   .function = handoffdemo_node_1_fn,
173   .vector_size = sizeof (u32),
174   .format_trace = format_handoffdemo_trace,
175   .type = VLIB_NODE_TYPE_INTERNAL,
176
177   .n_errors = ARRAY_LEN(handoffdemo_error_strings),
178   .error_strings = handoffdemo_error_strings,
179
180   .n_next_nodes = HANDOFFDEMO_N_NEXT,
181
182   /* edit / add dispositions here */
183   .next_nodes = {
184         [HANDOFFDEMO_NEXT_DROP] = "error-drop",
185   },
186 };
187 /* *INDENT-ON* */
188
189 uword
190 handoffdemo_node_2_fn (vlib_main_t * vm,
191                        vlib_node_runtime_t * node, vlib_frame_t * frame)
192 {
193   if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
194     return handoffdemo_inline (vm, node, frame, 2 /* which */ ,
195                                1 /* is_trace */ );
196   else
197     return handoffdemo_inline (vm, node, frame, 2 /* which */ ,
198                                0 /* is_trace */ );
199 }
200
201 /* *INDENT-OFF* */
202 VLIB_REGISTER_NODE (handoffdemo_node_2) =
203 {
204   .name = "handoffdemo-2",
205   .function = handoffdemo_node_2_fn,
206   .vector_size = sizeof (u32),
207   .format_trace = format_handoffdemo_trace,
208   .type = VLIB_NODE_TYPE_INTERNAL,
209
210   .n_errors = ARRAY_LEN(handoffdemo_error_strings),
211   .error_strings = handoffdemo_error_strings,
212
213   .n_next_nodes = HANDOFFDEMO_N_NEXT,
214
215   /* edit / add dispositions here */
216   .next_nodes = {
217         [HANDOFFDEMO_NEXT_DROP] = "error-drop",
218   },
219 };
220 /* *INDENT-ON* */
221
222 static clib_error_t *
223 handoffdemo_node_init (vlib_main_t * vm)
224 {
225   handoffdemo_main_t *hmp = &handoffdemo_main;
226
227   hmp->frame_queue_index = vlib_frame_queue_main_init
228     (handoffdemo_node_2.index, 16);
229
230   return 0;
231 }
232
233 VLIB_INIT_FUNCTION (handoffdemo_node_init);
234
235 /*
236  * fd.io coding-style-patch-verification: ON
237  *
238  * Local Variables:
239  * eval: (c-set-style "gnu")
240  * End:
241  */