blob: 6dd58108091112193cbc9e0ae96f7fc7e7eaec69 [file] [log] [blame]
Neale Rannsf068c3e2018-01-03 04:18:48 -08001/*
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#include <vnet/dpo/dvr_dpo.h>
17#include <vnet/fib/fib_node.h>
18#include <vnet/ip/ip.h>
19#include <vnet/ethernet/ethernet.h>
Neale Rannsa342da22019-06-06 10:35:07 +000020#include <vnet/l2/l2_input.h>
Neale Rannsf068c3e2018-01-03 04:18:48 -080021
Filip Tehlareb9a27f2019-03-07 01:42:11 -080022#ifndef CLIB_MARCH_VARIANT
BenoƮt Ganne47727c02019-02-12 13:35:08 +010023dvr_dpo_t *dvr_dpo_pool;
24
Neale Rannsf068c3e2018-01-03 04:18:48 -080025/**
26 * The 'DB' of DVR DPOs.
27 * There is one per-interface per-L3 proto, so this is a per-interface vector
28 */
29static index_t *dvr_dpo_db[DPO_PROTO_NUM];
30
31static dvr_dpo_t *
32dvr_dpo_alloc (void)
33{
34 dvr_dpo_t *dd;
35
36 pool_get(dvr_dpo_pool, dd);
37
38 return (dd);
39}
40
41static inline dvr_dpo_t *
42dvr_dpo_get_from_dpo (const dpo_id_t *dpo)
43{
44 ASSERT(DPO_DVR == dpo->dpoi_type);
45
46 return (dvr_dpo_get(dpo->dpoi_index));
47}
48
49static inline index_t
50dvr_dpo_get_index (dvr_dpo_t *dd)
51{
52 return (dd - dvr_dpo_pool);
53}
54
55static void
56dvr_dpo_lock (dpo_id_t *dpo)
57{
58 dvr_dpo_t *dd;
59
60 dd = dvr_dpo_get_from_dpo(dpo);
61 dd->dd_locks++;
62}
63
64static void
65dvr_dpo_unlock (dpo_id_t *dpo)
66{
67 dvr_dpo_t *dd;
68
69 dd = dvr_dpo_get_from_dpo(dpo);
70 dd->dd_locks--;
71
72 if (0 == dd->dd_locks)
73 {
74 if (DPO_PROTO_IP4 == dd->dd_proto)
75 {
76 vnet_feature_enable_disable ("ip4-output", "ip4-dvr-reinject",
77 dd->dd_sw_if_index, 0, 0, 0);
78 }
79 else
80 {
81 vnet_feature_enable_disable ("ip6-output", "ip6-dvr-reinject",
82 dd->dd_sw_if_index, 0, 0, 0);
83 }
84
85 dvr_dpo_db[dd->dd_proto][dd->dd_sw_if_index] = INDEX_INVALID;
86 pool_put(dvr_dpo_pool, dd);
87 }
88}
89
90void
91dvr_dpo_add_or_lock (u32 sw_if_index,
92 dpo_proto_t dproto,
93 dpo_id_t *dpo)
94{
Neale Rannsa342da22019-06-06 10:35:07 +000095 l2_input_config_t *config;
Neale Rannsf068c3e2018-01-03 04:18:48 -080096 dvr_dpo_t *dd;
97
98 vec_validate_init_empty(dvr_dpo_db[dproto],
99 sw_if_index,
100 INDEX_INVALID);
101
102 if (INDEX_INVALID == dvr_dpo_db[dproto][sw_if_index])
103 {
104 dd = dvr_dpo_alloc();
105
106 dd->dd_sw_if_index = sw_if_index;
107 dd->dd_proto = dproto;
108
109 dvr_dpo_db[dproto][sw_if_index] = dvr_dpo_get_index(dd);
110
Neale Rannsa342da22019-06-06 10:35:07 +0000111 config = l2input_intf_config (sw_if_index);
112
113 if (config->bridge || config->xconnect)
114 {
115 dd->dd_reinject = DVR_REINJECT_L2;
116 }
117 else
118 {
119 dd->dd_reinject = DVR_REINJECT_L3;
120 }
121
Neale Rannsf068c3e2018-01-03 04:18:48 -0800122 /*
123 * enable the reinject into L2 path feature on the interface
124 */
125 if (DPO_PROTO_IP4 == dproto)
126 vnet_feature_enable_disable ("ip4-output", "ip4-dvr-reinject",
127 dd->dd_sw_if_index, 1, 0, 0);
128 else if (DPO_PROTO_IP6 == dproto)
129 vnet_feature_enable_disable ("ip6-output", "ip6-dvr-reinject",
130 dd->dd_sw_if_index, 1, 0, 0);
131 else
132 ASSERT(0);
133 }
134 else
135 {
136 dd = dvr_dpo_get(dvr_dpo_db[dproto][sw_if_index]);
137 }
138
139 dpo_set(dpo, DPO_DVR, dproto, dvr_dpo_get_index(dd));
140}
Filip Tehlareb9a27f2019-03-07 01:42:11 -0800141#endif /* CLIB_MARCH_VARIANT */
Neale Rannsf068c3e2018-01-03 04:18:48 -0800142
143
144static clib_error_t *
145dvr_dpo_interface_state_change (vnet_main_t * vnm,
146 u32 sw_if_index,
147 u32 flags)
148{
149 /*
150 */
151 return (NULL);
152}
153
154VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(
155 dvr_dpo_interface_state_change);
156
157/**
158 * @brief Registered callback for HW interface state changes
159 */
160static clib_error_t *
161dvr_dpo_hw_interface_state_change (vnet_main_t * vnm,
162 u32 hw_if_index,
163 u32 flags)
164{
165 return (NULL);
166}
167
168VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION(
169 dvr_dpo_hw_interface_state_change);
170
171static clib_error_t *
172dvr_dpo_interface_delete (vnet_main_t * vnm,
173 u32 sw_if_index,
174 u32 is_add)
175{
176 return (NULL);
177}
178
179VNET_SW_INTERFACE_ADD_DEL_FUNCTION(
180 dvr_dpo_interface_delete);
181
Filip Tehlareb9a27f2019-03-07 01:42:11 -0800182#ifndef CLIB_MARCH_VARIANT
183static u8*
Neale Rannsa342da22019-06-06 10:35:07 +0000184format_dvr_reinject (u8* s, va_list *ap)
185{
186 dvr_dpo_reinject_t ddr = va_arg(*ap, int);
187
188 switch (ddr)
189 {
190 case DVR_REINJECT_L2:
191 s = format (s, "l2");
192 break;
193 case DVR_REINJECT_L3:
194 s = format (s, "l3");
195 break;
196 }
197 return (s);
198}
199
200static u8*
Neale Rannsf068c3e2018-01-03 04:18:48 -0800201format_dvr_dpo (u8* s, va_list *ap)
202{
203 index_t index = va_arg(*ap, index_t);
204 CLIB_UNUSED(u32 indent) = va_arg(*ap, u32);
205 vnet_main_t * vnm = vnet_get_main();
206 dvr_dpo_t *dd = dvr_dpo_get(index);
207
Neale Rannsa342da22019-06-06 10:35:07 +0000208 return (format(s, "%U-dvr-%U-dpo %U",
209 format_dpo_proto, dd->dd_proto,
Neale Rannsf068c3e2018-01-03 04:18:48 -0800210 format_vnet_sw_interface_name,
211 vnm,
Neale Rannsa342da22019-06-06 10:35:07 +0000212 vnet_get_sw_interface(vnm, dd->dd_sw_if_index),
213 format_dvr_reinject, dd->dd_reinject));
Neale Rannsf068c3e2018-01-03 04:18:48 -0800214}
215
216static void
217dvr_dpo_mem_show (void)
218{
219 fib_show_memory_usage("DVR",
220 pool_elts(dvr_dpo_pool),
221 pool_len(dvr_dpo_pool),
222 sizeof(dvr_dpo_t));
223}
224
225
226const static dpo_vft_t dvr_dpo_vft = {
227 .dv_lock = dvr_dpo_lock,
228 .dv_unlock = dvr_dpo_unlock,
229 .dv_format = format_dvr_dpo,
230 .dv_mem_show = dvr_dpo_mem_show,
231};
232
233/**
234 * @brief The per-protocol VLIB graph nodes that are assigned to a glean
235 * object.
236 *
237 * this means that these graph nodes are ones from which a glean is the
238 * parent object in the DPO-graph.
239 */
240const static char* const dvr_dpo_ip4_nodes[] =
241{
242 "ip4-dvr-dpo",
243 NULL,
244};
245const static char* const dvr_dpo_ip6_nodes[] =
246{
247 "ip6-dvr-dpo",
248 NULL,
249};
250
251const static char* const * const dvr_dpo_nodes[DPO_PROTO_NUM] =
252{
253 [DPO_PROTO_IP4] = dvr_dpo_ip4_nodes,
254 [DPO_PROTO_IP6] = dvr_dpo_ip6_nodes,
255};
256
257void
258dvr_dpo_module_init (void)
259{
260 dpo_register(DPO_DVR,
261 &dvr_dpo_vft,
262 dvr_dpo_nodes);
263}
Filip Tehlareb9a27f2019-03-07 01:42:11 -0800264#endif /* CLIB_MARCH_VARIANT */
Neale Rannsf068c3e2018-01-03 04:18:48 -0800265
266/**
267 * @brief Interface DPO trace data
268 */
269typedef struct dvr_dpo_trace_t_
270{
271 u32 sw_if_index;
272} dvr_dpo_trace_t;
273
274always_inline uword
275dvr_dpo_inline (vlib_main_t * vm,
276 vlib_node_runtime_t * node,
277 vlib_frame_t * from_frame,
278 u8 is_ip6)
279{
280 u32 n_left_from, next_index, * from, * to_next;
281 ip_lookup_main_t *lm = (is_ip6?
282 &ip6_main.lookup_main:
283 &ip4_main.lookup_main);
284
285 from = vlib_frame_vector_args (from_frame);
286 n_left_from = from_frame->n_vectors;
287
288 next_index = node->cached_next_index;
289
290 while (n_left_from > 0)
291 {
292 u32 n_left_to_next;
293
294 vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
295
296 while (n_left_from >= 4 && n_left_to_next > 2)
297 {
298 const dvr_dpo_t *dd0, *dd1;
299 u32 bi0, ddi0, bi1, ddi1;
300 vlib_buffer_t *b0, *b1;
301 u32 next0, next1;
302 u8 len0, len1;
303
304 bi0 = from[0];
305 to_next[0] = bi0;
306 bi1 = from[1];
307 to_next[1] = bi1;
308 from += 2;
309 to_next += 2;
310 n_left_from -= 2;
311 n_left_to_next -= 2;
312 next0 = next1 = 0;
313
314 b0 = vlib_get_buffer (vm, bi0);
315 b1 = vlib_get_buffer (vm, bi1);
316
317 ddi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
318 ddi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
319 dd0 = dvr_dpo_get(ddi0);
320 dd1 = dvr_dpo_get(ddi1);
321
322 vnet_buffer(b0)->sw_if_index[VLIB_TX] = dd0->dd_sw_if_index;
323 vnet_buffer(b1)->sw_if_index[VLIB_TX] = dd1->dd_sw_if_index;
324
325 len0 = ((u8*)vlib_buffer_get_current(b0) -
326 (u8*)ethernet_buffer_get_header(b0));
327 len1 = ((u8*)vlib_buffer_get_current(b1) -
328 (u8*)ethernet_buffer_get_header(b1));
Neale Ranns7bf3f9f2018-04-09 02:25:27 -0700329 vnet_buffer(b0)->l2.l2_len =
330 vnet_buffer(b0)->ip.save_rewrite_length =
331 len0;
332 vnet_buffer(b1)->l2.l2_len =
333 vnet_buffer(b1)->ip.save_rewrite_length =
334 len1;
Neale Rannsa342da22019-06-06 10:35:07 +0000335
Damjan Mariondac03522018-02-01 15:30:13 +0100336 b0->flags |= VNET_BUFFER_F_IS_DVR;
337 b1->flags |= VNET_BUFFER_F_IS_DVR;
Neale Rannsf068c3e2018-01-03 04:18:48 -0800338
339 vlib_buffer_advance(b0, -len0);
340 vlib_buffer_advance(b1, -len1);
341
342 vnet_feature_arc_start (lm->output_feature_arc_index,
343 dd0->dd_sw_if_index, &next0, b0);
344 vnet_feature_arc_start (lm->output_feature_arc_index,
345 dd1->dd_sw_if_index, &next1, b1);
346
347 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
348 {
349 dvr_dpo_trace_t *tr0;
350
351 tr0 = vlib_add_trace (vm, node, b0, sizeof (*tr0));
352 tr0->sw_if_index = dd0->dd_sw_if_index;
353 }
354 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
355 {
356 dvr_dpo_trace_t *tr1;
357
358 tr1 = vlib_add_trace (vm, node, b1, sizeof (*tr1));
359 tr1->sw_if_index = dd1->dd_sw_if_index;
360 }
361
362 vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
363 n_left_to_next, bi0, bi1,
364 next0, next1);
365 }
366
367 while (n_left_from > 0 && n_left_to_next > 0)
368 {
369 const dvr_dpo_t * dd0;
370 vlib_buffer_t * b0;
371 u32 bi0, ddi0;
372 u32 next0;
373 u8 len0;
374
375 bi0 = from[0];
376 to_next[0] = bi0;
377 from += 1;
378 to_next += 1;
379 n_left_from -= 1;
380 n_left_to_next -= 1;
381 next0 = 0;
382
383 b0 = vlib_get_buffer (vm, bi0);
384
385 ddi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
386 dd0 = dvr_dpo_get(ddi0);
387
388 vnet_buffer(b0)->sw_if_index[VLIB_TX] = dd0->dd_sw_if_index;
389
390 /*
391 * take that, rewind it back...
392 */
393 len0 = ((u8*)vlib_buffer_get_current(b0) -
394 (u8*)ethernet_buffer_get_header(b0));
Neale Ranns7bf3f9f2018-04-09 02:25:27 -0700395 vnet_buffer(b0)->l2.l2_len =
396 vnet_buffer(b0)->ip.save_rewrite_length =
397 len0;
Damjan Mariondac03522018-02-01 15:30:13 +0100398 b0->flags |= VNET_BUFFER_F_IS_DVR;
Neale Rannsf068c3e2018-01-03 04:18:48 -0800399 vlib_buffer_advance(b0, -len0);
400
401 /*
402 * start processing the ipX output features
403 */
404 vnet_feature_arc_start(lm->output_feature_arc_index,
405 dd0->dd_sw_if_index, &next0, b0);
406
407 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
408 {
409 dvr_dpo_trace_t *tr;
410
411 tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
412 tr->sw_if_index = dd0->dd_sw_if_index;
413 }
414
415 vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
416 n_left_to_next, bi0,
417 next0);
418 }
419 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
420 }
421 return from_frame->n_vectors;
422}
423
424static u8 *
425format_dvr_dpo_trace (u8 * s, va_list * args)
426{
427 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
428 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
429 dvr_dpo_trace_t * t = va_arg (*args, dvr_dpo_trace_t *);
430 u32 indent = format_get_indent (s);
431 s = format (s, "%U sw_if_index:%d",
432 format_white_space, indent,
433 t->sw_if_index);
434 return s;
435}
436
Filip Tehlareb9a27f2019-03-07 01:42:11 -0800437VLIB_NODE_FN (ip4_dvr_dpo_node) (vlib_main_t * vm,
Neale Rannsf068c3e2018-01-03 04:18:48 -0800438 vlib_node_runtime_t * node,
439 vlib_frame_t * from_frame)
440{
441 return (dvr_dpo_inline(vm, node, from_frame, 0));
442}
443
Filip Tehlareb9a27f2019-03-07 01:42:11 -0800444VLIB_NODE_FN (ip6_dvr_dpo_node) (vlib_main_t * vm,
Neale Rannsf068c3e2018-01-03 04:18:48 -0800445 vlib_node_runtime_t * node,
446 vlib_frame_t * from_frame)
447{
448 return (dvr_dpo_inline(vm, node, from_frame, 1));
449}
450
451VLIB_REGISTER_NODE (ip4_dvr_dpo_node) = {
Neale Rannsf068c3e2018-01-03 04:18:48 -0800452 .name = "ip4-dvr-dpo",
453 .vector_size = sizeof (u32),
454 .format_trace = format_dvr_dpo_trace,
455 .sibling_of = "ip4-rewrite",
456};
457VLIB_REGISTER_NODE (ip6_dvr_dpo_node) = {
Neale Rannsf068c3e2018-01-03 04:18:48 -0800458 .name = "ip6-dvr-dpo",
459 .vector_size = sizeof (u32),
460 .format_trace = format_dvr_dpo_trace,
461 .sibling_of = "ip6-rewrite",
462};
463
Neale Rannsf068c3e2018-01-03 04:18:48 -0800464typedef enum dvr_reinject_next_t_
465{
Neale Rannsa342da22019-06-06 10:35:07 +0000466 DVR_REINJECT_NEXT_L2,
467 DVR_REINJECT_NEXT_L3,
Neale Rannsf068c3e2018-01-03 04:18:48 -0800468} dvr_reinject_next_t;
469
470always_inline uword
471dvr_reinject_inline (vlib_main_t * vm,
472 vlib_node_runtime_t * node,
473 vlib_frame_t * from_frame)
474{
475 u32 n_left_from, next_index, * from, * to_next;
476
477 from = vlib_frame_vector_args (from_frame);
478 n_left_from = from_frame->n_vectors;
479
480 next_index = node->cached_next_index;
481
482 while (n_left_from > 0)
483 {
484 u32 n_left_to_next;
485
486 vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
487
488 while (n_left_from >= 4 && n_left_to_next > 2)
489 {
490 dvr_reinject_next_t next0, next1;
Neale Rannsa342da22019-06-06 10:35:07 +0000491 const dvr_dpo_t *dd0, *dd1;
492 u32 bi0, bi1, ddi0, ddi1;
Neale Rannsf068c3e2018-01-03 04:18:48 -0800493 vlib_buffer_t *b0, *b1;
Neale Rannsf068c3e2018-01-03 04:18:48 -0800494
495 bi0 = from[0];
496 to_next[0] = bi0;
497 bi1 = from[1];
498 to_next[1] = bi1;
499 from += 2;
500 to_next += 2;
501 n_left_from -= 2;
502 n_left_to_next -= 2;
503
504 b0 = vlib_get_buffer (vm, bi0);
505 b1 = vlib_get_buffer (vm, bi1);
506
Damjan Mariondac03522018-02-01 15:30:13 +0100507 if (b0->flags & VNET_BUFFER_F_IS_DVR)
Neale Rannsa342da22019-06-06 10:35:07 +0000508 {
509 ddi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
510 dd0 = dvr_dpo_get(ddi0);
511 next0 = (dd0->dd_reinject == DVR_REINJECT_L2 ?
512 DVR_REINJECT_NEXT_L2 :
513 DVR_REINJECT_NEXT_L3);
514 }
Neale Rannsf068c3e2018-01-03 04:18:48 -0800515 else
Damjan Marion7d98a122018-07-19 20:42:08 +0200516 vnet_feature_next( &next0, b0);
Neale Rannsf068c3e2018-01-03 04:18:48 -0800517
Damjan Mariondac03522018-02-01 15:30:13 +0100518 if (b1->flags & VNET_BUFFER_F_IS_DVR)
Neale Rannsa342da22019-06-06 10:35:07 +0000519 {
520 ddi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
521 dd1 = dvr_dpo_get(ddi1);
522 next1 = (dd1->dd_reinject == DVR_REINJECT_L2 ?
523 DVR_REINJECT_NEXT_L2 :
524 DVR_REINJECT_NEXT_L3);
525 }
Neale Rannsf068c3e2018-01-03 04:18:48 -0800526 else
Damjan Marion7d98a122018-07-19 20:42:08 +0200527 vnet_feature_next( &next1, b1);
Neale Rannsf068c3e2018-01-03 04:18:48 -0800528
529 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
530 {
531 dvr_dpo_trace_t *tr0;
532
533 tr0 = vlib_add_trace (vm, node, b0, sizeof (*tr0));
534 tr0->sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_TX];
535 }
536 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
537 {
538 dvr_dpo_trace_t *tr1;
539
540 tr1 = vlib_add_trace (vm, node, b1, sizeof (*tr1));
541 tr1->sw_if_index = vnet_buffer(b1)->sw_if_index[VLIB_TX];
542 }
543
544 vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
545 n_left_to_next, bi0, bi1,
546 next0, next1);
547 }
548
549 while (n_left_from > 0 && n_left_to_next > 0)
550 {
551 dvr_reinject_next_t next0;
Neale Rannsa342da22019-06-06 10:35:07 +0000552 const dvr_dpo_t *dd0;
Neale Rannsf068c3e2018-01-03 04:18:48 -0800553 vlib_buffer_t * b0;
Neale Rannsa342da22019-06-06 10:35:07 +0000554 u32 bi0, ddi0;
Neale Rannsf068c3e2018-01-03 04:18:48 -0800555
556 bi0 = from[0];
557 to_next[0] = bi0;
558 from += 1;
559 to_next += 1;
560 n_left_from -= 1;
561 n_left_to_next -= 1;
562
563 b0 = vlib_get_buffer (vm, bi0);
564
Damjan Mariondac03522018-02-01 15:30:13 +0100565 if (b0->flags & VNET_BUFFER_F_IS_DVR)
Neale Rannsa342da22019-06-06 10:35:07 +0000566 {
567 ddi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
568 dd0 = dvr_dpo_get(ddi0);
569 next0 = (dd0->dd_reinject == DVR_REINJECT_L2 ?
570 DVR_REINJECT_NEXT_L2 :
571 DVR_REINJECT_NEXT_L3);
572 }
Neale Rannsf068c3e2018-01-03 04:18:48 -0800573 else
Damjan Marion7d98a122018-07-19 20:42:08 +0200574 vnet_feature_next( &next0, b0);
Neale Rannsf068c3e2018-01-03 04:18:48 -0800575
576 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
577 {
578 dvr_dpo_trace_t *tr;
579
580 tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
581 tr->sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_TX];
582 }
583
584 vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
585 n_left_to_next, bi0, next0);
586 }
587 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
588 }
589 return from_frame->n_vectors;
590}
591
Filip Tehlareb9a27f2019-03-07 01:42:11 -0800592VLIB_NODE_FN (ip4_dvr_reinject_node) (vlib_main_t * vm,
Neale Rannsf068c3e2018-01-03 04:18:48 -0800593 vlib_node_runtime_t * node,
594 vlib_frame_t * from_frame)
595{
596 return (dvr_reinject_inline(vm, node, from_frame));
597}
598
Filip Tehlareb9a27f2019-03-07 01:42:11 -0800599VLIB_NODE_FN (ip6_dvr_reinject_node) (vlib_main_t * vm,
Neale Rannsf068c3e2018-01-03 04:18:48 -0800600 vlib_node_runtime_t * node,
601 vlib_frame_t * from_frame)
602{
603 return (dvr_reinject_inline(vm, node, from_frame));
604}
605
606VLIB_REGISTER_NODE (ip4_dvr_reinject_node) = {
Neale Rannsf068c3e2018-01-03 04:18:48 -0800607 .name = "ip4-dvr-reinject",
608 .vector_size = sizeof (u32),
609 .format_trace = format_dvr_dpo_trace,
610
611 .n_next_nodes = 1,
612 .next_nodes = {
Neale Rannsa342da22019-06-06 10:35:07 +0000613 [DVR_REINJECT_NEXT_L2] = "l2-output",
614 [DVR_REINJECT_NEXT_L3] = "interface-output",
Neale Rannsf068c3e2018-01-03 04:18:48 -0800615 },
616};
617
618VLIB_REGISTER_NODE (ip6_dvr_reinject_node) = {
Neale Rannsf068c3e2018-01-03 04:18:48 -0800619 .name = "ip6-dvr-reinject",
620 .vector_size = sizeof (u32),
621 .format_trace = format_dvr_dpo_trace,
622
623 .n_next_nodes = 1,
624 .next_nodes = {
Neale Rannsa342da22019-06-06 10:35:07 +0000625 [DVR_REINJECT_NEXT_L2] = "l2-output",
626 [DVR_REINJECT_NEXT_L3] = "interface-output",
Neale Rannsf068c3e2018-01-03 04:18:48 -0800627 },
628};
629
630VNET_FEATURE_INIT (ip4_dvr_reinject_feat_node, static) =
631{
632 .arc_name = "ip4-output",
633 .node_name = "ip4-dvr-reinject",
634 .runs_after = VNET_FEATURES ("nat44-in2out-output",
635 "acl-plugin-out-ip4-fa"),
636};
637VNET_FEATURE_INIT (ip6_dvr_reinject_feat_node, static) =
638{
639 .arc_name = "ip6-output",
640 .node_name = "ip6-dvr-reinject",
641 .runs_after = VNET_FEATURES ("acl-plugin-out-ip6-fa"),
642};
643