Line data Source code
1 : /*
2 : * Copyright (c) 2016 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 : * @file
17 : * @brief L2 LISP-GPE decap code.
18 : *
19 : */
20 : #include <vlib/vlib.h>
21 : #include <lisp/lisp-gpe/lisp_gpe.h>
22 :
23 : typedef struct
24 : {
25 : u32 next_index;
26 : u32 tunnel_index;
27 : u32 error;
28 : lisp_gpe_header_t h;
29 : } lisp_gpe_rx_trace_t;
30 :
31 : static u8 *
32 0 : format_lisp_gpe_rx_trace (u8 * s, va_list * args)
33 : {
34 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
35 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
36 0 : lisp_gpe_rx_trace_t *t = va_arg (*args, lisp_gpe_rx_trace_t *);
37 :
38 0 : if (t->tunnel_index != ~0)
39 : {
40 0 : s = format (s, "LISP-GPE: tunnel %d next %d error %d", t->tunnel_index,
41 : t->next_index, t->error);
42 : }
43 : else
44 : {
45 0 : s = format (s, "LISP-GPE: no tunnel next %d error %d\n", t->next_index,
46 : t->error);
47 : }
48 0 : s = format (s, "\n %U", format_lisp_gpe_header_with_length, &t->h,
49 : (u32) sizeof (t->h) /* max size */ );
50 0 : return s;
51 : }
52 :
53 : static u32 next_proto_to_next_index[LISP_GPE_NEXT_PROTOS] = {
54 : LISP_GPE_INPUT_NEXT_DROP,
55 : LISP_GPE_INPUT_NEXT_IP4_INPUT,
56 : LISP_GPE_INPUT_NEXT_IP6_INPUT,
57 : LISP_GPE_INPUT_NEXT_L2_INPUT,
58 : LISP_GPE_INPUT_NEXT_DROP
59 : };
60 :
61 : always_inline u32
62 0 : next_protocol_to_next_index (lisp_gpe_header_t * lgh, u8 * next_header)
63 : {
64 0 : lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
65 :
66 : /* lisp-gpe router */
67 0 : if (PREDICT_TRUE ((lgh->flags & LISP_GPE_FLAGS_P)
68 : || GPE_ENCAP_VXLAN == lgm->encap_mode))
69 : {
70 0 : if (PREDICT_FALSE (lgh->next_protocol >= LISP_GPE_NEXT_PROTOS))
71 0 : return LISP_GPE_INPUT_NEXT_DROP;
72 :
73 0 : return next_proto_to_next_index[lgh->next_protocol];
74 : }
75 : /* legacy lisp router */
76 0 : else if ((lgh->flags & LISP_GPE_FLAGS_P) == 0)
77 : {
78 0 : ip4_header_t *iph = (ip4_header_t *) next_header;
79 0 : if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
80 0 : return LISP_GPE_INPUT_NEXT_IP4_INPUT;
81 0 : else if ((iph->ip_version_and_header_length & 0xF0) == 0x60)
82 0 : return LISP_GPE_INPUT_NEXT_IP6_INPUT;
83 : else
84 0 : return LISP_GPE_INPUT_NEXT_DROP;
85 : }
86 : else
87 0 : return LISP_GPE_INPUT_NEXT_DROP;
88 : }
89 :
90 : always_inline tunnel_lookup_t *
91 0 : next_index_to_iface (lisp_gpe_main_t * lgm, u32 next_index)
92 : {
93 0 : if (LISP_GPE_INPUT_NEXT_IP4_INPUT == next_index
94 0 : || LISP_GPE_INPUT_NEXT_IP6_INPUT == next_index)
95 0 : return &lgm->l3_ifaces;
96 0 : else if (LISP_GPE_INPUT_NEXT_L2_INPUT == next_index)
97 0 : return &lgm->l2_ifaces;
98 0 : else if (LISP_GPE_INPUT_NEXT_NSH_INPUT == next_index)
99 0 : return &lgm->nsh_ifaces;
100 0 : clib_warning ("next_index not associated to an interface!");
101 0 : return 0;
102 : }
103 :
104 : static_always_inline void
105 0 : incr_decap_stats (vnet_main_t * vnm, u32 thread_index, u32 length,
106 : u32 sw_if_index, u32 * last_sw_if_index, u32 * n_packets,
107 : u32 * n_bytes)
108 : {
109 : vnet_interface_main_t *im;
110 :
111 0 : if (PREDICT_TRUE (sw_if_index == *last_sw_if_index))
112 : {
113 0 : *n_packets += 1;
114 0 : *n_bytes += length;
115 : }
116 : else
117 : {
118 0 : if (PREDICT_TRUE (*last_sw_if_index != ~0))
119 : {
120 0 : im = &vnm->interface_main;
121 :
122 0 : vlib_increment_combined_counter (im->combined_sw_if_counters +
123 : VNET_INTERFACE_COUNTER_RX,
124 : thread_index, *last_sw_if_index,
125 0 : *n_packets, *n_bytes);
126 : }
127 0 : *last_sw_if_index = sw_if_index;
128 0 : *n_packets = 1;
129 0 : *n_bytes = length;
130 : }
131 0 : }
132 :
133 : /**
134 : * @brief LISP-GPE decap dispatcher.
135 : * @node lisp_gpe_input_inline
136 : *
137 : * LISP-GPE decap dispatcher.
138 : *
139 : * Decaps IP-UDP-LISP-GPE header and based on the next protocol and in the
140 : * GPE header and the vni decides the next node to forward the packet to.
141 : *
142 : * @param[in] vm vlib_main_t corresponding to current thread.
143 : * @param[in] node vlib_node_runtime_t data for this node.
144 : * @param[in] frame vlib_frame_t whose contents should be dispatched.
145 : *
146 : * @return number of vectors in frame.
147 : */
148 : static uword
149 0 : lisp_gpe_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
150 : vlib_frame_t * from_frame, u8 is_v4)
151 : {
152 : u32 n_left_from, next_index, *from, *to_next, thread_index;
153 0 : u32 n_bytes = 0, n_packets = 0, last_sw_if_index = ~0, drops = 0;
154 0 : lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
155 :
156 0 : thread_index = vm->thread_index;
157 0 : from = vlib_frame_vector_args (from_frame);
158 0 : n_left_from = from_frame->n_vectors;
159 :
160 0 : next_index = node->cached_next_index;
161 :
162 0 : while (n_left_from > 0)
163 : {
164 : u32 n_left_to_next;
165 :
166 0 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
167 :
168 0 : while (n_left_from >= 4 && n_left_to_next >= 2)
169 : {
170 : u32 bi0, bi1;
171 : vlib_buffer_t *b0, *b1;
172 : ip4_udp_lisp_gpe_header_t *iul4_0, *iul4_1;
173 : ip6_udp_lisp_gpe_header_t *iul6_0, *iul6_1;
174 : lisp_gpe_header_t *lh0, *lh1;
175 : u32 next0, next1, error0, error1;
176 : uword *si0, *si1;
177 : tunnel_lookup_t *tl0, *tl1;
178 :
179 : /* Prefetch next iteration. */
180 : {
181 : vlib_buffer_t *p2, *p3;
182 :
183 0 : p2 = vlib_get_buffer (vm, from[2]);
184 0 : p3 = vlib_get_buffer (vm, from[3]);
185 :
186 0 : vlib_prefetch_buffer_header (p2, LOAD);
187 0 : vlib_prefetch_buffer_header (p3, LOAD);
188 :
189 0 : CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
190 0 : CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
191 : }
192 :
193 0 : bi0 = from[0];
194 0 : bi1 = from[1];
195 0 : to_next[0] = bi0;
196 0 : to_next[1] = bi1;
197 0 : from += 2;
198 0 : to_next += 2;
199 0 : n_left_to_next -= 2;
200 0 : n_left_from -= 2;
201 :
202 0 : b0 = vlib_get_buffer (vm, bi0);
203 0 : b1 = vlib_get_buffer (vm, bi1);
204 :
205 : /* udp leaves current_data pointing at the lisp header */
206 0 : if (is_v4)
207 : {
208 0 : vlib_buffer_advance (b0,
209 : -(word) (sizeof (udp_header_t) +
210 : sizeof (ip4_header_t)));
211 0 : vlib_buffer_advance (b1,
212 : -(word) (sizeof (udp_header_t) +
213 : sizeof (ip4_header_t)));
214 :
215 0 : iul4_0 = vlib_buffer_get_current (b0);
216 0 : iul4_1 = vlib_buffer_get_current (b1);
217 :
218 : /* pop (ip, udp, lisp-gpe) */
219 0 : vlib_buffer_advance (b0, sizeof (*iul4_0));
220 0 : vlib_buffer_advance (b1, sizeof (*iul4_1));
221 :
222 0 : lh0 = &iul4_0->lisp;
223 0 : lh1 = &iul4_1->lisp;
224 : }
225 : else
226 : {
227 0 : vlib_buffer_advance (b0,
228 : -(word) (sizeof (udp_header_t) +
229 : sizeof (ip6_header_t)));
230 0 : vlib_buffer_advance (b1,
231 : -(word) (sizeof (udp_header_t) +
232 : sizeof (ip6_header_t)));
233 :
234 0 : iul6_0 = vlib_buffer_get_current (b0);
235 0 : iul6_1 = vlib_buffer_get_current (b1);
236 :
237 : /* pop (ip, udp, lisp-gpe) */
238 0 : vlib_buffer_advance (b0, sizeof (*iul6_0));
239 0 : vlib_buffer_advance (b1, sizeof (*iul6_1));
240 :
241 0 : lh0 = &iul6_0->lisp;
242 0 : lh1 = &iul6_1->lisp;
243 : }
244 :
245 : /* determine next_index from lisp-gpe header */
246 0 : next0 = next_protocol_to_next_index (lh0,
247 0 : vlib_buffer_get_current (b0));
248 0 : next1 = next_protocol_to_next_index (lh1,
249 0 : vlib_buffer_get_current (b1));
250 :
251 : /* determine if tunnel is l2 or l3 */
252 0 : tl0 = next_index_to_iface (lgm, next0);
253 0 : tl1 = next_index_to_iface (lgm, next1);
254 :
255 : /* map iid/vni to lisp-gpe sw_if_index which is used by ipx_input to
256 : * decide the rx vrf and the input features to be applied */
257 0 : si0 = hash_get (tl0->sw_if_index_by_vni,
258 : clib_net_to_host_u32 (lh0->iid << 8));
259 0 : si1 = hash_get (tl1->sw_if_index_by_vni,
260 : clib_net_to_host_u32 (lh1->iid << 8));
261 :
262 :
263 : /* Required to make the l2 tag push / pop code work on l2 subifs */
264 0 : vnet_update_l2_len (b0);
265 0 : vnet_update_l2_len (b1);
266 :
267 0 : if (si0)
268 : {
269 0 : incr_decap_stats (lgm->vnet_main, thread_index,
270 0 : vlib_buffer_length_in_chain (vm, b0), si0[0],
271 : &last_sw_if_index, &n_packets, &n_bytes);
272 0 : vnet_buffer (b0)->sw_if_index[VLIB_RX] = si0[0];
273 0 : error0 = 0;
274 : }
275 : else
276 : {
277 0 : next0 = LISP_GPE_INPUT_NEXT_DROP;
278 0 : error0 = LISP_GPE_ERROR_NO_TUNNEL;
279 0 : drops++;
280 : }
281 :
282 0 : if (si1)
283 : {
284 0 : incr_decap_stats (lgm->vnet_main, thread_index,
285 0 : vlib_buffer_length_in_chain (vm, b1), si1[0],
286 : &last_sw_if_index, &n_packets, &n_bytes);
287 0 : vnet_buffer (b1)->sw_if_index[VLIB_RX] = si1[0];
288 0 : error1 = 0;
289 : }
290 : else
291 : {
292 0 : next1 = LISP_GPE_INPUT_NEXT_DROP;
293 0 : error1 = LISP_GPE_ERROR_NO_TUNNEL;
294 0 : drops++;
295 : }
296 :
297 0 : b0->error = error0 ? node->errors[error0] : 0;
298 0 : b1->error = error1 ? node->errors[error1] : 0;
299 :
300 0 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
301 : {
302 0 : lisp_gpe_rx_trace_t *tr = vlib_add_trace (vm, node, b0,
303 : sizeof (*tr));
304 0 : tr->next_index = next0;
305 0 : tr->error = error0;
306 0 : tr->h = lh0[0];
307 : }
308 :
309 0 : if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
310 : {
311 0 : lisp_gpe_rx_trace_t *tr = vlib_add_trace (vm, node, b1,
312 : sizeof (*tr));
313 0 : tr->next_index = next1;
314 0 : tr->error = error1;
315 0 : tr->h = lh1[0];
316 : }
317 :
318 0 : vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
319 : n_left_to_next, bi0, bi1, next0,
320 : next1);
321 : }
322 :
323 0 : while (n_left_from > 0 && n_left_to_next > 0)
324 : {
325 : u32 bi0;
326 : vlib_buffer_t *b0;
327 : u32 next0;
328 : ip4_udp_lisp_gpe_header_t *iul4_0;
329 : ip6_udp_lisp_gpe_header_t *iul6_0;
330 : lisp_gpe_header_t *lh0;
331 : u32 error0;
332 : uword *si0;
333 : tunnel_lookup_t *tl0;
334 :
335 0 : bi0 = from[0];
336 0 : to_next[0] = bi0;
337 0 : from += 1;
338 0 : to_next += 1;
339 0 : n_left_from -= 1;
340 0 : n_left_to_next -= 1;
341 :
342 0 : b0 = vlib_get_buffer (vm, bi0);
343 :
344 : /* udp leaves current_data pointing at the lisp header
345 : * TODO: there's no difference in processing between v4 and v6
346 : * encapsulated packets so the code should be simplified if ip header
347 : * info is not going to be used for dp smrs/dpsec */
348 0 : if (is_v4)
349 : {
350 0 : vlib_buffer_advance (b0,
351 : -(word) (sizeof (udp_header_t) +
352 : sizeof (ip4_header_t)));
353 :
354 0 : iul4_0 = vlib_buffer_get_current (b0);
355 :
356 : /* pop (ip, udp, lisp-gpe) */
357 0 : vlib_buffer_advance (b0, sizeof (*iul4_0));
358 :
359 0 : lh0 = &iul4_0->lisp;
360 : }
361 : else
362 : {
363 0 : vlib_buffer_advance (b0,
364 : -(word) (sizeof (udp_header_t) +
365 : sizeof (ip6_header_t)));
366 :
367 0 : iul6_0 = vlib_buffer_get_current (b0);
368 :
369 : /* pop (ip, udp, lisp-gpe) */
370 0 : vlib_buffer_advance (b0, sizeof (*iul6_0));
371 :
372 0 : lh0 = &iul6_0->lisp;
373 : }
374 :
375 : /* TODO if security is to be implemented, something similar to RPF,
376 : * probably we'd like to check that the peer is allowed to send us
377 : * packets. For this, we should use the tunnel table OR check that
378 : * we have a mapping for the source eid and that the outer source of
379 : * the packet is one of its locators */
380 :
381 : /* determine next_index from lisp-gpe header */
382 0 : next0 = next_protocol_to_next_index (lh0,
383 0 : vlib_buffer_get_current (b0));
384 :
385 : /* determine if tunnel is l2 or l3 */
386 0 : tl0 = next_index_to_iface (lgm, next0);
387 :
388 : /* map iid/vni to lisp-gpe sw_if_index which is used by ipx_input to
389 : * decide the rx vrf and the input features to be applied.
390 : * NOTE: vni uses only the first 24 bits */
391 0 : si0 = hash_get (tl0->sw_if_index_by_vni,
392 : clib_net_to_host_u32 (lh0->iid << 8));
393 :
394 : /* Required to make the l2 tag push / pop code work on l2 subifs */
395 0 : vnet_update_l2_len (b0);
396 :
397 0 : if (si0)
398 : {
399 0 : incr_decap_stats (lgm->vnet_main, thread_index,
400 0 : vlib_buffer_length_in_chain (vm, b0), si0[0],
401 : &last_sw_if_index, &n_packets, &n_bytes);
402 0 : vnet_buffer (b0)->sw_if_index[VLIB_RX] = si0[0];
403 0 : error0 = 0;
404 : }
405 : else
406 : {
407 0 : next0 = LISP_GPE_INPUT_NEXT_DROP;
408 0 : error0 = LISP_GPE_ERROR_NO_TUNNEL;
409 0 : drops++;
410 : }
411 :
412 : /* TODO error handling if security is implemented */
413 0 : b0->error = error0 ? node->errors[error0] : 0;
414 :
415 0 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
416 : {
417 0 : lisp_gpe_rx_trace_t *tr = vlib_add_trace (vm, node, b0,
418 : sizeof (*tr));
419 0 : tr->next_index = next0;
420 0 : tr->error = error0;
421 0 : tr->h = lh0[0];
422 : }
423 :
424 0 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
425 : n_left_to_next, bi0, next0);
426 : }
427 :
428 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
429 : }
430 :
431 : /* flush iface stats */
432 0 : incr_decap_stats (lgm->vnet_main, thread_index, 0, ~0, &last_sw_if_index,
433 : &n_packets, &n_bytes);
434 0 : vlib_node_increment_counter (vm, lisp_gpe_ip4_input_node.index,
435 : LISP_GPE_ERROR_NO_TUNNEL, drops);
436 0 : return from_frame->n_vectors;
437 : }
438 :
439 : static uword
440 0 : lisp_gpe_ip4_input (vlib_main_t * vm, vlib_node_runtime_t * node,
441 : vlib_frame_t * from_frame)
442 : {
443 0 : return lisp_gpe_input_inline (vm, node, from_frame, 1);
444 : }
445 :
446 : static uword
447 0 : lisp_gpe_ip6_input (vlib_main_t * vm, vlib_node_runtime_t * node,
448 : vlib_frame_t * from_frame)
449 : {
450 0 : return lisp_gpe_input_inline (vm, node, from_frame, 0);
451 : }
452 :
453 : static char *lisp_gpe_ip4_input_error_strings[] = {
454 : #define lisp_gpe_error(n,s) s,
455 : #include <lisp/lisp-gpe/lisp_gpe_error.def>
456 : #undef lisp_gpe_error
457 : };
458 :
459 : /* *INDENT-OFF* */
460 96218 : VLIB_REGISTER_NODE (lisp_gpe_ip4_input_node) = {
461 : .function = lisp_gpe_ip4_input,
462 : .name = "lisp-gpe-ip4-input",
463 : /* Takes a vector of packets. */
464 : .vector_size = sizeof (u32),
465 : .n_next_nodes = LISP_GPE_INPUT_N_NEXT,
466 : .next_nodes = {
467 : #define _(s,n) [LISP_GPE_INPUT_NEXT_##s] = n,
468 : foreach_lisp_gpe_ip_input_next
469 : #undef _
470 : },
471 :
472 : .n_errors = ARRAY_LEN (lisp_gpe_ip4_input_error_strings),
473 : .error_strings = lisp_gpe_ip4_input_error_strings,
474 :
475 : .format_buffer = format_lisp_gpe_header_with_length,
476 : .format_trace = format_lisp_gpe_rx_trace,
477 : // $$$$ .unformat_buffer = unformat_lisp_gpe_header,
478 : };
479 : /* *INDENT-ON* */
480 :
481 : /* *INDENT-OFF* */
482 96218 : VLIB_REGISTER_NODE (lisp_gpe_ip6_input_node) = {
483 : .function = lisp_gpe_ip6_input,
484 : .name = "lisp-gpe-ip6-input",
485 : /* Takes a vector of packets. */
486 : .vector_size = sizeof (u32),
487 : .n_next_nodes = LISP_GPE_INPUT_N_NEXT,
488 : .next_nodes = {
489 : #define _(s,n) [LISP_GPE_INPUT_NEXT_##s] = n,
490 : foreach_lisp_gpe_ip_input_next
491 : #undef _
492 : },
493 :
494 : .n_errors = ARRAY_LEN (lisp_gpe_ip4_input_error_strings),
495 : .error_strings = lisp_gpe_ip4_input_error_strings,
496 :
497 : .format_buffer = format_lisp_gpe_header_with_length,
498 : .format_trace = format_lisp_gpe_rx_trace,
499 : // $$$$ .unformat_buffer = unformat_lisp_gpe_header,
500 : };
501 : /* *INDENT-ON* */
502 :
503 : /**
504 : * Adds arc from lisp-gpe-input to nsh-input if nsh-input is available
505 : */
506 : static void
507 575 : gpe_add_arc_from_input_to_nsh ()
508 : {
509 575 : lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
510 575 : vlib_main_t *vm = lgm->vlib_main;
511 : vlib_node_t *nsh_input;
512 :
513 : /* Arc already exists */
514 575 : if (next_proto_to_next_index[LISP_GPE_NEXT_PROTO_NSH]
515 : != LISP_GPE_INPUT_NEXT_DROP)
516 0 : return;
517 :
518 : /* Check if nsh-input is available */
519 575 : if ((nsh_input = vlib_get_node_by_name (vm, (u8 *) "nsh-input")))
520 : {
521 : u32 slot4, slot6;
522 1150 : slot4 = vlib_node_add_next_with_slot (vm, lisp_gpe_ip4_input_node.index,
523 575 : nsh_input->index,
524 : LISP_GPE_NEXT_PROTO_NSH);
525 1150 : slot6 = vlib_node_add_next_with_slot (vm, lisp_gpe_ip6_input_node.index,
526 575 : nsh_input->index,
527 : LISP_GPE_NEXT_PROTO_NSH);
528 575 : ASSERT (slot4 == slot6 && slot4 == LISP_GPE_INPUT_NEXT_NSH_INPUT);
529 :
530 575 : next_proto_to_next_index[LISP_GPE_NEXT_PROTO_NSH] = slot4;
531 : }
532 : }
533 :
534 : /** GPE decap init function. */
535 : clib_error_t *
536 575 : gpe_decap_init (vlib_main_t * vm)
537 : {
538 575 : clib_error_t *error = 0;
539 :
540 575 : if ((error = vlib_call_init_function (vm, lisp_gpe_init)))
541 0 : return error;
542 :
543 575 : gpe_add_arc_from_input_to_nsh ();
544 575 : return 0;
545 : }
546 :
547 : static uword
548 0 : lisp_gpe_nsh_placeholder_input (vlib_main_t * vm, vlib_node_runtime_t * node,
549 : vlib_frame_t * from_frame)
550 : {
551 0 : vlib_node_increment_counter (vm, node->node_index, 0, 1);
552 0 : return from_frame->n_vectors;
553 : }
554 :
555 : static char *lisp_gpe_nsh_placeholder_error_strings[] = {
556 : "lisp gpe placeholder nsh decap",
557 : };
558 :
559 : /* *INDENT-OFF* */
560 96218 : VLIB_REGISTER_NODE (lisp_gpe_nsh_placeholder_input_node) = {
561 : .function = lisp_gpe_nsh_placeholder_input,
562 : .name = "lisp-gpe-nsh-placeholder-input",
563 : .vector_size = sizeof (u32),
564 : .type = VLIB_NODE_TYPE_INTERNAL,
565 : .n_next_nodes = 1,
566 :
567 : .n_errors = 1,
568 : .error_strings = lisp_gpe_nsh_placeholder_error_strings,
569 :
570 : .next_nodes = {
571 : [0] = "error-drop",
572 : },
573 : };
574 : /* *INDENT-ON* */
575 :
576 : static clib_error_t *
577 0 : lisp_add_placeholder_nsh_node_command_fn (vlib_main_t * vm,
578 : unformat_input_t * input,
579 : vlib_cli_command_t * cmd)
580 : {
581 0 : lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
582 0 : vlib_node_add_next (lgm->vlib_main, lisp_gpe_ip4_input_node.index,
583 0 : lisp_gpe_nsh_placeholder_input_node.index);
584 0 : next_proto_to_next_index[LISP_GPE_NEXT_PROTO_NSH] =
585 : LISP_GPE_INPUT_NEXT_NSH_INPUT;
586 0 : return 0;
587 : }
588 :
589 : /* *INDENT-OFF* */
590 123991 : VLIB_CLI_COMMAND (lisp_add_placeholder_nsh_node_command, static) = {
591 : .path = "test one nsh add-placeholder-decap-node",
592 : .function = lisp_add_placeholder_nsh_node_command_fn,
593 : };
594 : /* *INDENT-ON* */
595 :
596 4607 : VLIB_INIT_FUNCTION (gpe_decap_init);
597 :
598 : /*
599 : * fd.io coding-style-patch-verification: ON
600 : *
601 : * Local Variables:
602 : * eval: (c-set-style "gnu")
603 : * End:
604 : */
|