Line data Source code
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 0 : format_punt_trace (u8 * s, va_list * args)
44 : {
45 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
46 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
47 0 : punt_trace_t *t = va_arg (*args, punt_trace_t *);
48 :
49 0 : s = format (s, "punt: %U", format_vlib_punt_reason, t->pt_reason);
50 :
51 0 : return s;
52 : }
53 :
54 : always_inline uword
55 6 : 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 6 : from = vlib_frame_vector_args (frame);
62 6 : n_left_from = frame->n_vectors;
63 6 : next_index = node->cached_next_index;
64 :
65 12 : while (n_left_from > 0)
66 : {
67 : u32 n_left_to_next;
68 :
69 6 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
70 :
71 408 : 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 402 : bi0 = to_next[0] = from[0];
80 402 : from += 1;
81 402 : to_next += 1;
82 402 : n_left_to_next -= 1;
83 402 : n_left_from -= 1;
84 :
85 402 : b0 = vlib_get_buffer (vm, bi0);
86 402 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index;
87 402 : ai0 = adjs[fproto][sw_if_index];
88 :
89 402 : adj0 = adj_get (ai0);
90 402 : ip0 = vlib_buffer_get_current (b0);
91 :
92 402 : vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
93 402 : vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
94 :
95 402 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
96 : to_next, n_left_to_next, bi0, 0);
97 : }
98 6 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
99 : }
100 :
101 6 : return frame->n_vectors;
102 : }
103 :
104 : always_inline uword
105 2 : punt_test_pg0_ip4 (vlib_main_t * vm,
106 : vlib_node_runtime_t * node, vlib_frame_t * frame)
107 : {
108 2 : return (punt_test_fwd (vm, node, frame, FIB_PROTOCOL_IP4, SW_IF_INDEX_PG0));
109 : }
110 :
111 : always_inline uword
112 1 : punt_test_pg1_ip4 (vlib_main_t * vm,
113 : vlib_node_runtime_t * node, vlib_frame_t * frame)
114 : {
115 1 : return (punt_test_fwd (vm, node, frame, FIB_PROTOCOL_IP4, SW_IF_INDEX_PG1));
116 : }
117 :
118 : always_inline uword
119 2 : punt_test_pg0_ip6 (vlib_main_t * vm,
120 : vlib_node_runtime_t * node, vlib_frame_t * frame)
121 : {
122 2 : return (punt_test_fwd (vm, node, frame, FIB_PROTOCOL_IP6, SW_IF_INDEX_PG0));
123 : }
124 :
125 : always_inline uword
126 1 : punt_test_pg1_ip6 (vlib_main_t * vm,
127 : vlib_node_runtime_t * node, vlib_frame_t * frame)
128 : {
129 1 : return (punt_test_fwd (vm, node, frame, FIB_PROTOCOL_IP6, SW_IF_INDEX_PG1));
130 : }
131 :
132 : /* *INDENT-OFF* */
133 23519 : VLIB_REGISTER_NODE (punt_test_pg0_ip4_node) = {
134 : .function = punt_test_pg0_ip4,
135 : .name = "punt-test-pg0-ip4",
136 : .vector_size = sizeof (u32),
137 : .format_trace = format_punt_trace,
138 : };
139 23519 : VLIB_REGISTER_NODE (punt_test_pg1_ip4_node) = {
140 : .function = punt_test_pg1_ip4,
141 : .name = "punt-test-pg1-ip4",
142 : .vector_size = sizeof (u32),
143 : .format_trace = format_punt_trace,
144 : };
145 23519 : VLIB_REGISTER_NODE (punt_test_pg0_ip6_node) = {
146 : .function = punt_test_pg0_ip6,
147 : .name = "punt-test-pg0-ip6",
148 : .vector_size = sizeof (u32),
149 : .format_trace = format_punt_trace,
150 : };
151 23519 : VLIB_REGISTER_NODE (punt_test_pg1_ip6_node) = {
152 : .function = punt_test_pg1_ip6,
153 : .name = "punt-test-pg1-ip6",
154 : .vector_size = sizeof (u32),
155 : .format_trace = format_punt_trace,
156 : };
157 : /* *INDENT-ON* */
158 :
159 : typedef struct punt_feat_trace_t_
160 : {
161 : vlib_punt_reason_t pt_reason;
162 : } punt_feat_trace_t;
163 :
164 : always_inline uword
165 6 : punt_test_feat_inline (vlib_main_t * vm,
166 : vlib_node_runtime_t * node,
167 : vlib_frame_t * frame, u8 is_ip4)
168 : {
169 : u32 n_left_from, *from, *to_next, next_index;
170 :
171 6 : from = vlib_frame_vector_args (frame);
172 6 : n_left_from = frame->n_vectors;
173 6 : next_index = node->cached_next_index;
174 :
175 12 : while (n_left_from > 0)
176 : {
177 : u32 n_left_to_next;
178 :
179 6 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
180 :
181 408 : while (n_left_from > 0 && n_left_to_next > 0)
182 : {
183 : vlib_buffer_t *b0;
184 : u32 bi0, next0;
185 :
186 402 : bi0 = to_next[0] = from[0];
187 402 : from += 1;
188 402 : to_next += 1;
189 402 : n_left_to_next -= 1;
190 402 : n_left_from -= 1;
191 402 : next0 = 0;
192 :
193 402 : b0 = vlib_get_buffer (vm, bi0);
194 :
195 402 : if (is_ip4)
196 201 : b0->punt_reason = punt_reason_v4;
197 : else
198 201 : b0->punt_reason = punt_reason_v6;
199 :
200 402 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
201 : {
202 : punt_feat_trace_t *t;
203 :
204 402 : b0 = vlib_get_buffer (vm, bi0);
205 :
206 402 : t = vlib_add_trace (vm, node, b0, sizeof (*t));
207 402 : t->pt_reason = b0->punt_reason;
208 : }
209 402 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
210 : to_next, n_left_to_next,
211 : bi0, next0);
212 : }
213 6 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
214 : }
215 :
216 6 : return frame->n_vectors;
217 : }
218 :
219 : static u8 *
220 267 : format_punt_feat_trace (u8 * s, va_list * args)
221 : {
222 267 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
223 267 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
224 267 : punt_feat_trace_t *t = va_arg (*args, punt_feat_trace_t *);
225 :
226 267 : s = format (s, "reason: %U", format_vlib_punt_reason, t->pt_reason);
227 :
228 267 : return s;
229 : }
230 :
231 : always_inline uword
232 3 : punt_test_feat_ip4 (vlib_main_t * vm,
233 : vlib_node_runtime_t * node, vlib_frame_t * frame)
234 : {
235 3 : return (punt_test_feat_inline (vm, node, frame, 1));
236 : }
237 :
238 : always_inline uword
239 3 : punt_test_feat_ip6 (vlib_main_t * vm,
240 : vlib_node_runtime_t * node, vlib_frame_t * frame)
241 : {
242 3 : return (punt_test_feat_inline (vm, node, frame, 0));
243 : }
244 :
245 : /* *INDENT-OFF* */
246 23519 : VLIB_REGISTER_NODE (punt_test_feat_ip6_node) = {
247 : .function = punt_test_feat_ip6,
248 : .name = "punt-test-feat-ip6",
249 : .vector_size = sizeof (u32),
250 : .format_trace = format_punt_feat_trace,
251 : .n_next_nodes = 1,
252 : .next_nodes = {
253 : [0] = "punt-dispatch"
254 : }
255 : };
256 23519 : VLIB_REGISTER_NODE (punt_test_feat_ip4_node) = {
257 : .function = punt_test_feat_ip4,
258 : .name = "punt-test-feat-ip4",
259 : .vector_size = sizeof (u32),
260 : .format_trace = format_punt_feat_trace,
261 : .n_next_nodes = 1,
262 : .next_nodes = {
263 : [0] = "punt-dispatch"
264 : }
265 : };
266 8399 : VNET_FEATURE_INIT (punt_test_feat_ip6_feature, static) =
267 : {
268 : .arc_name = "ip6-unicast",
269 : .node_name = "punt-test-feat-ip6",
270 : };
271 8399 : VNET_FEATURE_INIT (punt_test_feat_ip4_feature, static) =
272 : {
273 : .arc_name = "ip4-unicast",
274 : .node_name = "punt-test-feat-ip4",
275 : };
276 : /* *INDENT-ON* */
277 :
278 : static clib_error_t *
279 5 : punt_test (vlib_main_t * vm,
280 : unformat_input_t * input, vlib_cli_command_t * cmd_arg)
281 : {
282 5 : ip46_address_t ip46 = ip46_address_initializer;
283 : fib_protocol_t fproto;
284 : vnet_main_t *vnm;
285 : u32 sw_if_index;
286 : int rc;
287 :
288 5 : vnm = vnet_get_main ();
289 5 : fproto = FIB_PROTOCOL_IP4;
290 :
291 5 : if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
292 : {
293 : vlib_node_t *from;
294 :
295 5 : if (unformat (input, "%U", unformat_ip4_address, &ip46.ip4))
296 : {
297 2 : fproto = FIB_PROTOCOL_IP4;
298 : }
299 3 : else if (unformat (input, "%U", unformat_ip6_address, &ip46.ip6))
300 : {
301 2 : fproto = FIB_PROTOCOL_IP6;
302 : }
303 1 : else if (unformat (input, "clear"))
304 : {
305 0 : vnet_feature_enable_disable ("ip4-unicast",
306 : "punt-test-feat-ip4",
307 : sw_if_index, 0, NULL, 0);
308 0 : vnet_feature_enable_disable ("ip6-unicast",
309 : "punt-test-feat-ip6",
310 : sw_if_index, 0, NULL, 0);
311 0 : return NULL;
312 : }
313 : else
314 : {
315 : /*
316 : * allocate a client and a reason
317 : */
318 1 : punt_hdl = vlib_punt_client_register ("test");
319 :
320 1 : rc = vlib_punt_reason_alloc (
321 : punt_hdl, "reason-v4", NULL, NULL, &punt_reason_v4,
322 : VNET_PUNT_REASON_F_IP4_PACKET, format_vnet_punt_reason_flags);
323 1 : rc |= vlib_punt_reason_alloc (
324 : punt_hdl, "reason-v6", NULL, NULL, &punt_reason_v6,
325 : VNET_PUNT_REASON_F_IP6_PACKET, format_vnet_punt_reason_flags);
326 1 : ASSERT (!rc);
327 :
328 1 : vnet_feature_enable_disable ("ip4-unicast",
329 : "punt-test-feat-ip4",
330 : sw_if_index, 1, NULL, 0);
331 1 : vnet_feature_enable_disable ("ip6-unicast",
332 : "punt-test-feat-ip6",
333 : sw_if_index, 1, NULL, 0);
334 1 : return NULL;
335 : }
336 :
337 4 : if (SW_IF_INDEX_PG0 == sw_if_index)
338 : {
339 2 : if (FIB_PROTOCOL_IP4 == fproto)
340 : {
341 : /*
342 : * register the node that will forward the punted packet
343 : */
344 1 : vlib_punt_register (punt_hdl, punt_reason_v4,
345 : "punt-test-pg0-ip4");
346 1 : from = vlib_get_node_by_name (vm, (u8 *) "punt-test-pg0-ip4");
347 : }
348 : else
349 : {
350 1 : vlib_punt_register (punt_hdl, punt_reason_v6,
351 : "punt-test-pg0-ip6");
352 1 : from = vlib_get_node_by_name (vm, (u8 *) "punt-test-pg0-ip6");
353 : }
354 : }
355 : else
356 : {
357 2 : if (FIB_PROTOCOL_IP4 == fproto)
358 : {
359 1 : vlib_punt_register (punt_hdl, punt_reason_v4,
360 : "punt-test-pg1-ip4");
361 1 : from = vlib_get_node_by_name (vm, (u8 *) "punt-test-pg1-ip4");
362 : }
363 : else
364 : {
365 1 : vlib_punt_register (punt_hdl, punt_reason_v6,
366 : "punt-test-pg1-ip6");
367 1 : from = vlib_get_node_by_name (vm, (u8 *) "punt-test-pg1-ip6");
368 : }
369 : }
370 :
371 4 : vlib_node_add_next (vm, from->index,
372 4 : vnet_tx_node_index_for_sw_interface
373 : (vnm, sw_if_index));
374 :
375 4 : vec_validate (adjs[fproto], sw_if_index);
376 :
377 4 : adjs[fproto][sw_if_index] = adj_nbr_find (fproto,
378 4 : fib_proto_to_link (fproto),
379 : &ip46, sw_if_index);
380 : }
381 :
382 4 : return (NULL);
383 : }
384 :
385 : /* *INDENT-OFF* */
386 16239 : VLIB_CLI_COMMAND (test_fib_command, static) =
387 : {
388 : .path = "test punt",
389 : .short_help = "punt unit tests - DO NOT RUN ON A LIVE SYSTEM",
390 : .function = punt_test,
391 : };
392 : /* *INDENT-ON* */
393 :
394 : /*
395 : * fd.io coding-style-patch-verification: ON
396 : *
397 : * Local Variables:
398 : * eval: (c-set-style "gnu")
399 : * End:
400 : */
|