vnet: export header files to build the plugins
[vpp.git] / src / plugins / unittest / punt_test.c
1 /*
2  * Copyright (c) 2018 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <vnet/vnet.h>
17 #include <vnet/adj/rewrite.h>
18 #include <vnet/ethernet/ethernet.h>
19 #include <vnet/adj/adj.h>
20 #include <vnet/ip/ip.h>
21 #include <vnet/ip/punt.h>
22
23 typedef enum punt_next_t_
24 {
25   PUNT_NEXT_DROP,
26   PUNT_N_NEXT,
27 } punt_next_t;
28
29 typedef struct punt_trace_t_
30 {
31   vlib_punt_reason_t pt_reason;
32 } punt_trace_t;
33
34 #define SW_IF_INDEX_PG0 1
35 #define SW_IF_INDEX_PG1 2
36
37 index_t *adjs[FIB_PROTOCOL_IP_MAX];
38
39 static vlib_punt_reason_t punt_reason_v4, punt_reason_v6;
40 static vlib_punt_hdl_t punt_hdl;
41
42 static u8 *
43 format_punt_trace (u8 * s, va_list * args)
44 {
45   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
46   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
47   punt_trace_t *t = va_arg (*args, punt_trace_t *);
48
49   s = format (s, "punt: %U", format_vlib_punt_reason, t->pt_reason);
50
51   return s;
52 }
53
54 always_inline uword
55 punt_test_fwd (vlib_main_t * vm,
56                vlib_node_runtime_t * node,
57                vlib_frame_t * frame, fib_protocol_t fproto, u32 sw_if_index)
58 {
59   u32 n_left_from, *from, *to_next, next_index;
60
61   from = vlib_frame_vector_args (frame);
62   n_left_from = frame->n_vectors;
63   next_index = node->cached_next_index;
64
65   while (n_left_from > 0)
66     {
67       u32 n_left_to_next;
68
69       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
70
71       while (n_left_from > 0 && n_left_to_next > 0)
72         {
73           ip_adjacency_t *adj0;
74           vlib_buffer_t *b0;
75           void *ip0;
76           index_t ai0;
77           u32 bi0;
78
79           bi0 = to_next[0] = from[0];
80           from += 1;
81           to_next += 1;
82           n_left_to_next -= 1;
83           n_left_from -= 1;
84
85           b0 = vlib_get_buffer (vm, bi0);
86           vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index;
87           ai0 = adjs[fproto][sw_if_index];
88
89           adj0 = adj_get (ai0);
90           ip0 = vlib_buffer_get_current (b0);
91
92           vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
93           vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
94
95           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
96                                            to_next, n_left_to_next, bi0, 0);
97         }
98       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
99     }
100
101   return frame->n_vectors;
102 }
103
104 always_inline uword
105 punt_test_pg0_ip4 (vlib_main_t * vm,
106                    vlib_node_runtime_t * node, vlib_frame_t * frame)
107 {
108   return (punt_test_fwd (vm, node, frame, FIB_PROTOCOL_IP4, SW_IF_INDEX_PG0));
109 }
110
111 always_inline uword
112 punt_test_pg1_ip4 (vlib_main_t * vm,
113                    vlib_node_runtime_t * node, vlib_frame_t * frame)
114 {
115   return (punt_test_fwd (vm, node, frame, FIB_PROTOCOL_IP4, SW_IF_INDEX_PG1));
116 }
117
118 always_inline uword
119 punt_test_pg0_ip6 (vlib_main_t * vm,
120                    vlib_node_runtime_t * node, vlib_frame_t * frame)
121 {
122   return (punt_test_fwd (vm, node, frame, FIB_PROTOCOL_IP6, SW_IF_INDEX_PG0));
123 }
124
125 always_inline uword
126 punt_test_pg1_ip6 (vlib_main_t * vm,
127                    vlib_node_runtime_t * node, vlib_frame_t * frame)
128 {
129   return (punt_test_fwd (vm, node, frame, FIB_PROTOCOL_IP6, SW_IF_INDEX_PG1));
130 }
131
132 VLIB_REGISTER_NODE (punt_test_pg0_ip4_node) = {
133   .function = punt_test_pg0_ip4,
134   .name = "punt-test-pg0-ip4",
135   .vector_size = sizeof (u32),
136   .format_trace = format_punt_trace,
137 };
138 VLIB_REGISTER_NODE (punt_test_pg1_ip4_node) = {
139   .function = punt_test_pg1_ip4,
140   .name = "punt-test-pg1-ip4",
141   .vector_size = sizeof (u32),
142   .format_trace = format_punt_trace,
143 };
144 VLIB_REGISTER_NODE (punt_test_pg0_ip6_node) = {
145   .function = punt_test_pg0_ip6,
146   .name = "punt-test-pg0-ip6",
147   .vector_size = sizeof (u32),
148   .format_trace = format_punt_trace,
149 };
150 VLIB_REGISTER_NODE (punt_test_pg1_ip6_node) = {
151   .function = punt_test_pg1_ip6,
152   .name = "punt-test-pg1-ip6",
153   .vector_size = sizeof (u32),
154   .format_trace = format_punt_trace,
155 };
156
157 typedef struct punt_feat_trace_t_
158 {
159   vlib_punt_reason_t pt_reason;
160 } punt_feat_trace_t;
161
162 always_inline uword
163 punt_test_feat_inline (vlib_main_t * vm,
164                        vlib_node_runtime_t * node,
165                        vlib_frame_t * frame, u8 is_ip4)
166 {
167   u32 n_left_from, *from, *to_next, next_index;
168
169   from = vlib_frame_vector_args (frame);
170   n_left_from = frame->n_vectors;
171   next_index = node->cached_next_index;
172
173   while (n_left_from > 0)
174     {
175       u32 n_left_to_next;
176
177       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
178
179       while (n_left_from > 0 && n_left_to_next > 0)
180         {
181           vlib_buffer_t *b0;
182           u32 bi0, next0;
183
184           bi0 = to_next[0] = from[0];
185           from += 1;
186           to_next += 1;
187           n_left_to_next -= 1;
188           n_left_from -= 1;
189           next0 = 0;
190
191           b0 = vlib_get_buffer (vm, bi0);
192
193           if (is_ip4)
194             b0->punt_reason = punt_reason_v4;
195           else
196             b0->punt_reason = punt_reason_v6;
197
198           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
199             {
200               punt_feat_trace_t *t;
201
202               b0 = vlib_get_buffer (vm, bi0);
203
204               t = vlib_add_trace (vm, node, b0, sizeof (*t));
205               t->pt_reason = b0->punt_reason;
206             }
207           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
208                                            to_next, n_left_to_next,
209                                            bi0, next0);
210         }
211       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
212     }
213
214   return frame->n_vectors;
215 }
216
217 static u8 *
218 format_punt_feat_trace (u8 * s, va_list * args)
219 {
220   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
221   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
222   punt_feat_trace_t *t = va_arg (*args, punt_feat_trace_t *);
223
224   s = format (s, "reason: %U", format_vlib_punt_reason, t->pt_reason);
225
226   return s;
227 }
228
229 always_inline uword
230 punt_test_feat_ip4 (vlib_main_t * vm,
231                     vlib_node_runtime_t * node, vlib_frame_t * frame)
232 {
233   return (punt_test_feat_inline (vm, node, frame, 1));
234 }
235
236 always_inline uword
237 punt_test_feat_ip6 (vlib_main_t * vm,
238                     vlib_node_runtime_t * node, vlib_frame_t * frame)
239 {
240   return (punt_test_feat_inline (vm, node, frame, 0));
241 }
242
243 VLIB_REGISTER_NODE (punt_test_feat_ip6_node) = {
244   .function = punt_test_feat_ip6,
245   .name = "punt-test-feat-ip6",
246   .vector_size = sizeof (u32),
247   .format_trace = format_punt_feat_trace,
248   .n_next_nodes = 1,
249   .next_nodes = {
250     [0] = "punt-dispatch"
251   }
252 };
253 VLIB_REGISTER_NODE (punt_test_feat_ip4_node) = {
254   .function = punt_test_feat_ip4,
255   .name = "punt-test-feat-ip4",
256   .vector_size = sizeof (u32),
257   .format_trace = format_punt_feat_trace,
258   .n_next_nodes = 1,
259   .next_nodes = {
260     [0] = "punt-dispatch"
261   }
262 };
263 VNET_FEATURE_INIT (punt_test_feat_ip6_feature, static) =
264 {
265   .arc_name = "ip6-unicast",
266   .node_name = "punt-test-feat-ip6",
267 };
268 VNET_FEATURE_INIT (punt_test_feat_ip4_feature, static) =
269 {
270   .arc_name = "ip4-unicast",
271   .node_name = "punt-test-feat-ip4",
272 };
273
274 static clib_error_t *
275 punt_test (vlib_main_t * vm,
276            unformat_input_t * input, vlib_cli_command_t * cmd_arg)
277 {
278   ip46_address_t ip46 = ip46_address_initializer;
279   fib_protocol_t fproto;
280   vnet_main_t *vnm;
281   u32 sw_if_index;
282   int rc;
283
284   vnm = vnet_get_main ();
285   fproto = FIB_PROTOCOL_IP4;
286
287   if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
288     {
289       vlib_node_t *from;
290
291       if (unformat (input, "%U", unformat_ip4_address, &ip46.ip4))
292         {
293           fproto = FIB_PROTOCOL_IP4;
294         }
295       else if (unformat (input, "%U", unformat_ip6_address, &ip46.ip6))
296         {
297           fproto = FIB_PROTOCOL_IP6;
298         }
299       else if (unformat (input, "clear"))
300         {
301           vnet_feature_enable_disable ("ip4-unicast",
302                                        "punt-test-feat-ip4",
303                                        sw_if_index, 0, NULL, 0);
304           vnet_feature_enable_disable ("ip6-unicast",
305                                        "punt-test-feat-ip6",
306                                        sw_if_index, 0, NULL, 0);
307           return NULL;
308         }
309       else
310         {
311           /*
312            * allocate a client and a reason
313            */
314           punt_hdl = vlib_punt_client_register ("test");
315
316           rc = vlib_punt_reason_alloc (
317             punt_hdl, "reason-v4", NULL, NULL, &punt_reason_v4,
318             VNET_PUNT_REASON_F_IP4_PACKET, format_vnet_punt_reason_flags);
319           rc |= vlib_punt_reason_alloc (
320             punt_hdl, "reason-v6", NULL, NULL, &punt_reason_v6,
321             VNET_PUNT_REASON_F_IP6_PACKET, format_vnet_punt_reason_flags);
322           ASSERT (!rc);
323
324           vnet_feature_enable_disable ("ip4-unicast",
325                                        "punt-test-feat-ip4",
326                                        sw_if_index, 1, NULL, 0);
327           vnet_feature_enable_disable ("ip6-unicast",
328                                        "punt-test-feat-ip6",
329                                        sw_if_index, 1, NULL, 0);
330           return NULL;
331         }
332
333       if (SW_IF_INDEX_PG0 == sw_if_index)
334         {
335           if (FIB_PROTOCOL_IP4 == fproto)
336             {
337               /*
338                * register the node that will forward the punted packet
339                */
340               vlib_punt_register (punt_hdl, punt_reason_v4,
341                                   "punt-test-pg0-ip4");
342               from = vlib_get_node_by_name (vm, (u8 *) "punt-test-pg0-ip4");
343             }
344           else
345             {
346               vlib_punt_register (punt_hdl, punt_reason_v6,
347                                   "punt-test-pg0-ip6");
348               from = vlib_get_node_by_name (vm, (u8 *) "punt-test-pg0-ip6");
349             }
350         }
351       else
352         {
353           if (FIB_PROTOCOL_IP4 == fproto)
354             {
355               vlib_punt_register (punt_hdl, punt_reason_v4,
356                                   "punt-test-pg1-ip4");
357               from = vlib_get_node_by_name (vm, (u8 *) "punt-test-pg1-ip4");
358             }
359           else
360             {
361               vlib_punt_register (punt_hdl, punt_reason_v6,
362                                   "punt-test-pg1-ip6");
363               from = vlib_get_node_by_name (vm, (u8 *) "punt-test-pg1-ip6");
364             }
365         }
366
367       vlib_node_add_next (vm, from->index,
368                           vnet_tx_node_index_for_sw_interface
369                           (vnm, sw_if_index));
370
371       vec_validate (adjs[fproto], sw_if_index);
372
373       adjs[fproto][sw_if_index] = adj_nbr_find (fproto,
374                                                 fib_proto_to_link (fproto),
375                                                 &ip46, sw_if_index);
376     }
377
378   return (NULL);
379 }
380
381 VLIB_CLI_COMMAND (test_fib_command, static) =
382 {
383   .path = "test punt",
384   .short_help = "punt unit tests - DO NOT RUN ON A LIVE SYSTEM",
385   .function = punt_test,
386 };
387
388 /*
389  * fd.io coding-style-patch-verification: ON
390  *
391  * Local Variables:
392  * eval: (c-set-style "gnu")
393  * End:
394  */