2 * Copyright (c) 2015 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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 * interface_output.c: interface output node
18 * Copyright (c) 2008 Eliot Dresselhaus
20 * Permission is hereby granted, free of charge, to any person obtaining
21 * a copy of this software and associated documentation files (the
22 * "Software"), to deal in the Software without restriction, including
23 * without limitation the rights to use, copy, modify, merge, publish,
24 * distribute, sublicense, and/or sell copies of the Software, and to
25 * permit persons to whom the Software is furnished to do so, subject to
26 * the following conditions:
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 #include <vnet/vnet.h>
41 #include <vnet/feature/feature.h>
46 u8 data[128 - sizeof (u32)];
48 interface_output_trace_t;
51 format_vnet_interface_output_trace (u8 * s, va_list * va)
53 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
54 vlib_node_t *node = va_arg (*va, vlib_node_t *);
55 interface_output_trace_t *t = va_arg (*va, interface_output_trace_t *);
56 vnet_main_t *vnm = vnet_get_main ();
57 vnet_sw_interface_t *si;
60 if (t->sw_if_index != (u32) ~ 0)
62 indent = format_get_indent (s);
64 if (pool_is_free_index
65 (vnm->interface_main.sw_interfaces, t->sw_if_index))
67 /* the interface may have been deleted by the time the trace is printed */
68 s = format (s, "sw_if_index: %d\n%U%U",
70 format_white_space, indent,
71 node->format_buffer ? node->
72 format_buffer : format_hex_bytes, t->data,
77 si = vnet_get_sw_interface (vnm, t->sw_if_index);
79 s = format (s, "%U\n%U%U",
80 format_vnet_sw_interface_name, vnm, si,
81 format_white_space, indent,
82 node->format_buffer ? node->
83 format_buffer : format_hex_bytes, t->data,
91 vnet_interface_output_trace (vlib_main_t * vm,
92 vlib_node_runtime_t * node,
93 vlib_frame_t * frame, uword n_buffers)
98 from = vlib_frame_args (frame);
103 vlib_buffer_t *b0, *b1;
104 interface_output_trace_t *t0, *t1;
106 /* Prefetch next iteration. */
107 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
108 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
113 b0 = vlib_get_buffer (vm, bi0);
114 b1 = vlib_get_buffer (vm, bi1);
116 if (b0->flags & VLIB_BUFFER_IS_TRACED)
118 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
119 t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
120 clib_memcpy (t0->data, vlib_buffer_get_current (b0),
123 if (b1->flags & VLIB_BUFFER_IS_TRACED)
125 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
126 t1->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_TX];
127 clib_memcpy (t1->data, vlib_buffer_get_current (b1),
138 interface_output_trace_t *t0;
142 b0 = vlib_get_buffer (vm, bi0);
144 if (b0->flags & VLIB_BUFFER_IS_TRACED)
146 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
147 t0->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
148 clib_memcpy (t0->data, vlib_buffer_get_current (b0),
157 vnet_interface_output_node (vlib_main_t * vm,
158 vlib_node_runtime_t * node, vlib_frame_t * frame)
160 vnet_main_t *vnm = vnet_get_main ();
161 vnet_interface_output_runtime_t *rt = (void *) node->runtime_data;
162 vnet_sw_interface_t *si;
163 vnet_hw_interface_t *hi;
164 u32 n_left_to_tx, *from, *from_end, *to_tx;
165 u32 n_bytes, n_buffers, n_packets;
166 u32 n_bytes_b0, n_bytes_b1, n_bytes_b2, n_bytes_b3;
167 u32 thread_index = vm->thread_index;
168 vnet_interface_main_t *im = &vnm->interface_main;
169 u32 next_index = VNET_INTERFACE_OUTPUT_NEXT_TX;
170 u32 current_config_index = ~0;
171 u8 arc = im->output_feature_arc_index;
173 n_buffers = frame->n_vectors;
175 if (node->flags & VLIB_NODE_FLAG_TRACE)
176 vnet_interface_output_trace (vm, node, frame, n_buffers);
178 from = vlib_frame_args (frame);
181 return vlib_error_drop_buffers (vm, node, from,
182 /* buffer stride */ 1,
184 VNET_INTERFACE_OUTPUT_NEXT_DROP,
186 VNET_INTERFACE_OUTPUT_ERROR_INTERFACE_DELETED);
188 si = vnet_get_sw_interface (vnm, rt->sw_if_index);
189 hi = vnet_get_sup_hw_interface (vnm, rt->sw_if_index);
190 if (!(si->flags & (VNET_SW_INTERFACE_FLAG_ADMIN_UP |
191 VNET_SW_INTERFACE_FLAG_BOND_SLAVE)) ||
192 !(hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
194 vlib_simple_counter_main_t *cm;
196 cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
197 VNET_INTERFACE_COUNTER_TX_ERROR);
198 vlib_increment_simple_counter (cm, thread_index,
199 rt->sw_if_index, n_buffers);
201 return vlib_error_drop_buffers (vm, node, from,
202 /* buffer stride */ 1,
204 VNET_INTERFACE_OUTPUT_NEXT_DROP,
206 VNET_INTERFACE_OUTPUT_ERROR_INTERFACE_DOWN);
209 from_end = from + n_buffers;
211 /* Total byte count of all buffers. */
215 /* interface-output feature arc handling */
216 if (PREDICT_FALSE (vnet_have_features (arc, rt->sw_if_index)))
218 vnet_feature_config_main_t *fcm;
219 fcm = vnet_feature_get_config_main (arc);
220 current_config_index = vnet_get_feature_config_index (arc,
222 vnet_get_config_data (&fcm->config_main, ¤t_config_index,
226 while (from < from_end)
228 /* Get new next frame since previous incomplete frame may have less
229 than VNET_FRAME_SIZE vectors in it. */
230 vlib_get_new_next_frame (vm, node, next_index, to_tx, n_left_to_tx);
232 while (from + 8 <= from_end && n_left_to_tx >= 4)
234 u32 bi0, bi1, bi2, bi3;
235 vlib_buffer_t *b0, *b1, *b2, *b3;
236 u32 tx_swif0, tx_swif1, tx_swif2, tx_swif3;
238 /* Prefetch next iteration. */
239 vlib_prefetch_buffer_with_index (vm, from[4], LOAD);
240 vlib_prefetch_buffer_with_index (vm, from[5], LOAD);
241 vlib_prefetch_buffer_with_index (vm, from[6], LOAD);
242 vlib_prefetch_buffer_with_index (vm, from[7], LOAD);
256 b0 = vlib_get_buffer (vm, bi0);
257 b1 = vlib_get_buffer (vm, bi1);
258 b2 = vlib_get_buffer (vm, bi2);
259 b3 = vlib_get_buffer (vm, bi3);
261 /* Be grumpy about zero length buffers for benefit of
262 driver tx function. */
263 ASSERT (b0->current_length > 0);
264 ASSERT (b1->current_length > 0);
265 ASSERT (b2->current_length > 0);
266 ASSERT (b3->current_length > 0);
268 n_bytes_b0 = vlib_buffer_length_in_chain (vm, b0);
269 n_bytes_b1 = vlib_buffer_length_in_chain (vm, b1);
270 n_bytes_b2 = vlib_buffer_length_in_chain (vm, b2);
271 n_bytes_b3 = vlib_buffer_length_in_chain (vm, b3);
272 tx_swif0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
273 tx_swif1 = vnet_buffer (b1)->sw_if_index[VLIB_TX];
274 tx_swif2 = vnet_buffer (b2)->sw_if_index[VLIB_TX];
275 tx_swif3 = vnet_buffer (b3)->sw_if_index[VLIB_TX];
277 n_bytes += n_bytes_b0 + n_bytes_b1;
278 n_bytes += n_bytes_b2 + n_bytes_b3;
281 if (PREDICT_FALSE (current_config_index != ~0))
283 b0->feature_arc_index = arc;
284 b1->feature_arc_index = arc;
285 b2->feature_arc_index = arc;
286 b3->feature_arc_index = arc;
287 b0->current_config_index = current_config_index;
288 b1->current_config_index = current_config_index;
289 b2->current_config_index = current_config_index;
290 b3->current_config_index = current_config_index;
293 /* update vlan subif tx counts, if required */
294 if (PREDICT_FALSE (tx_swif0 != rt->sw_if_index))
296 vlib_increment_combined_counter (im->combined_sw_if_counters +
297 VNET_INTERFACE_COUNTER_TX,
298 thread_index, tx_swif0, 1,
302 if (PREDICT_FALSE (tx_swif1 != rt->sw_if_index))
305 vlib_increment_combined_counter (im->combined_sw_if_counters +
306 VNET_INTERFACE_COUNTER_TX,
307 thread_index, tx_swif1, 1,
311 if (PREDICT_FALSE (tx_swif2 != rt->sw_if_index))
314 vlib_increment_combined_counter (im->combined_sw_if_counters +
315 VNET_INTERFACE_COUNTER_TX,
316 thread_index, tx_swif2, 1,
319 if (PREDICT_FALSE (tx_swif3 != rt->sw_if_index))
322 vlib_increment_combined_counter (im->combined_sw_if_counters +
323 VNET_INTERFACE_COUNTER_TX,
324 thread_index, tx_swif3, 1,
329 while (from + 1 <= from_end && n_left_to_tx >= 1)
341 b0 = vlib_get_buffer (vm, bi0);
343 /* Be grumpy about zero length buffers for benefit of
344 driver tx function. */
345 ASSERT (b0->current_length > 0);
347 n_bytes_b0 = vlib_buffer_length_in_chain (vm, b0);
348 tx_swif0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
349 n_bytes += n_bytes_b0;
352 if (PREDICT_FALSE (current_config_index != ~0))
354 b0->feature_arc_index = arc;
355 b0->current_config_index = current_config_index;
358 if (PREDICT_FALSE (tx_swif0 != rt->sw_if_index))
361 vlib_increment_combined_counter (im->combined_sw_if_counters +
362 VNET_INTERFACE_COUNTER_TX,
363 thread_index, tx_swif0, 1,
368 vlib_put_next_frame (vm, node, next_index, n_left_to_tx);
371 /* Update main interface stats. */
372 vlib_increment_combined_counter (im->combined_sw_if_counters
373 + VNET_INTERFACE_COUNTER_TX,
375 rt->sw_if_index, n_packets, n_bytes);
379 VLIB_NODE_FUNCTION_MULTIARCH_CLONE (vnet_interface_output_node);
380 CLIB_MULTIARCH_SELECT_FN (vnet_interface_output_node);
382 /* Use buffer's sw_if_index[VNET_TX] to choose output interface. */
384 vnet_per_buffer_interface_output (vlib_main_t * vm,
385 vlib_node_runtime_t * node,
386 vlib_frame_t * frame)
388 vnet_main_t *vnm = vnet_get_main ();
389 u32 n_left_to_next, *from, *to_next;
390 u32 n_left_from, next_index;
392 n_left_from = frame->n_vectors;
394 from = vlib_frame_args (frame);
395 next_index = node->cached_next_index;
397 while (n_left_from > 0)
399 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
401 while (n_left_from >= 4 && n_left_to_next >= 2)
403 u32 bi0, bi1, next0, next1;
404 vlib_buffer_t *b0, *b1;
405 vnet_hw_interface_t *hi0, *hi1;
407 /* Prefetch next iteration. */
408 vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
409 vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
420 b0 = vlib_get_buffer (vm, bi0);
421 b1 = vlib_get_buffer (vm, bi1);
424 vnet_get_sup_hw_interface (vnm,
425 vnet_buffer (b0)->sw_if_index
428 vnet_get_sup_hw_interface (vnm,
429 vnet_buffer (b1)->sw_if_index
432 next0 = hi0->hw_if_index;
433 next1 = hi1->hw_if_index;
435 vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
436 n_left_to_next, bi0, bi1, next0,
440 while (n_left_from > 0 && n_left_to_next > 0)
444 vnet_hw_interface_t *hi0;
453 b0 = vlib_get_buffer (vm, bi0);
456 vnet_get_sup_hw_interface (vnm,
457 vnet_buffer (b0)->sw_if_index
460 next0 = hi0->hw_if_index;
462 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
463 n_left_to_next, bi0, next0);
466 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
469 return frame->n_vectors;
473 counter_index (vlib_main_t * vm, vlib_error_t e)
478 ni = vlib_error_get_node (e);
479 n = vlib_get_node (vm, ni);
481 ci = vlib_error_get_code (e);
482 ASSERT (ci < n->n_errors);
484 ci += n->error_heap_index;
490 format_vnet_error_trace (u8 * s, va_list * va)
492 vlib_main_t *vm = va_arg (*va, vlib_main_t *);
493 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
494 vlib_error_t *e = va_arg (*va, vlib_error_t *);
495 vlib_node_t *error_node;
496 vlib_error_main_t *em = &vm->error_main;
499 error_node = vlib_get_node (vm, vlib_error_get_node (e[0]));
500 i = counter_index (vm, e[0]);
501 s = format (s, "%v: %s", error_node->name, em->error_strings_heap[i]);
507 trace_errors_with_buffers (vlib_main_t * vm,
508 vlib_node_runtime_t * node, vlib_frame_t * frame)
510 u32 n_left, *buffers;
512 buffers = vlib_frame_vector_args (frame);
513 n_left = frame->n_vectors;
518 vlib_buffer_t *b0, *b1;
519 vlib_error_t *t0, *t1;
521 /* Prefetch next iteration. */
522 vlib_prefetch_buffer_with_index (vm, buffers[2], LOAD);
523 vlib_prefetch_buffer_with_index (vm, buffers[3], LOAD);
528 b0 = vlib_get_buffer (vm, bi0);
529 b1 = vlib_get_buffer (vm, bi1);
531 if (b0->flags & VLIB_BUFFER_IS_TRACED)
533 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
536 if (b1->flags & VLIB_BUFFER_IS_TRACED)
538 t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
553 b0 = vlib_get_buffer (vm, bi0);
555 if (b0->flags & VLIB_BUFFER_IS_TRACED)
557 t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
566 validate_error (vlib_main_t * vm, vlib_error_t * e, u32 index)
568 uword node_index = vlib_error_get_node (e[0]);
569 uword code = vlib_error_get_code (e[0]);
572 if (node_index >= vec_len (vm->node_main.nodes))
573 return format (0, "[%d], node index out of range 0x%x, error 0x%x",
574 index, node_index, e[0]);
576 n = vlib_get_node (vm, node_index);
577 if (code >= n->n_errors)
578 return format (0, "[%d], code %d out of range for node %v",
579 index, code, n->name);
585 validate_error_frame (vlib_main_t * vm,
586 vlib_node_runtime_t * node, vlib_frame_t * f)
588 u32 *buffers = vlib_frame_args (f);
593 for (i = 0; i < f->n_vectors; i++)
595 b = vlib_get_buffer (vm, buffers[i]);
596 msg = validate_error (vm, &b->error, i);
606 VNET_ERROR_DISPOSITION_DROP,
607 VNET_ERROR_DISPOSITION_PUNT,
608 VNET_ERROR_N_DISPOSITION,
609 } vnet_error_disposition_t;
612 do_packet (vlib_main_t * vm, vlib_error_t a)
614 vlib_error_main_t *em = &vm->error_main;
615 u32 i = counter_index (vm, a);
616 em->counters[i] += 1;
617 vlib_error_elog_count (vm, i, 1);
620 static_always_inline uword
621 process_drop_punt (vlib_main_t * vm,
622 vlib_node_runtime_t * node,
623 vlib_frame_t * frame, vnet_error_disposition_t disposition)
625 vnet_main_t *vnm = vnet_get_main ();
626 vlib_error_main_t *em = &vm->error_main;
627 u32 *buffers, *first_buffer;
628 vlib_error_t current_error;
629 u32 current_counter_index, n_errors_left;
630 u32 current_sw_if_index, n_errors_current_sw_if_index;
632 vlib_simple_counter_main_t *cm;
633 u32 thread_index = vm->thread_index;
635 static vlib_error_t memory[VNET_ERROR_N_DISPOSITION];
636 static char memory_init[VNET_ERROR_N_DISPOSITION];
638 buffers = vlib_frame_args (frame);
639 first_buffer = buffers;
642 vlib_buffer_t *b = vlib_get_buffer (vm, first_buffer[0]);
644 if (!memory_init[disposition])
646 memory_init[disposition] = 1;
647 memory[disposition] = b->error;
650 current_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
651 n_errors_current_sw_if_index = 0;
654 current_error = memory[disposition];
655 current_counter_index = counter_index (vm, memory[disposition]);
656 current_counter = em->counters[current_counter_index];
658 if (node->flags & VLIB_NODE_FLAG_TRACE)
659 trace_errors_with_buffers (vm, node, frame);
661 n_errors_left = frame->n_vectors;
662 cm = vec_elt_at_index (vnm->interface_main.sw_if_counters,
663 (disposition == VNET_ERROR_DISPOSITION_PUNT
664 ? VNET_INTERFACE_COUNTER_PUNT
665 : VNET_INTERFACE_COUNTER_DROP));
667 while (n_errors_left >= 2)
669 vlib_buffer_t *b0, *b1;
670 vnet_sw_interface_t *sw_if0, *sw_if1;
673 u32 sw_if_index0, sw_if_index1;
681 b0 = vlib_get_buffer (vm, bi0);
682 b1 = vlib_get_buffer (vm, bi1);
687 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
688 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
690 /* Speculate that sw_if_index == sw_if_index[01]. */
691 n_errors_current_sw_if_index += 2;
693 /* Speculatively assume all 2 (node, code) pairs are equal
694 to current (node, code). */
695 current_counter += 2;
697 if (PREDICT_FALSE (e0 != current_error
698 || e1 != current_error
699 || sw_if_index0 != current_sw_if_index
700 || sw_if_index1 != current_sw_if_index))
702 current_counter -= 2;
703 n_errors_current_sw_if_index -= 2;
705 vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1);
706 vlib_increment_simple_counter (cm, thread_index, sw_if_index1, 1);
708 /* Increment super-interface drop/punt counters for
710 sw_if0 = vnet_get_sw_interface (vnm, sw_if_index0);
711 vlib_increment_simple_counter
712 (cm, thread_index, sw_if0->sup_sw_if_index,
713 sw_if0->sup_sw_if_index != sw_if_index0);
715 sw_if1 = vnet_get_sw_interface (vnm, sw_if_index1);
716 vlib_increment_simple_counter
717 (cm, thread_index, sw_if1->sup_sw_if_index,
718 sw_if1->sup_sw_if_index != sw_if_index1);
720 em->counters[current_counter_index] = current_counter;
724 /* For 2 repeated errors, change current error. */
725 if (e0 == e1 && e1 != current_error)
728 current_counter_index = counter_index (vm, e0);
730 current_counter = em->counters[current_counter_index];
734 while (n_errors_left >= 1)
737 vnet_sw_interface_t *sw_if0;
739 u32 bi0, sw_if_index0;
745 current_counter += 1;
747 b0 = vlib_get_buffer (vm, bi0);
750 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
752 /* Increment drop/punt counters. */
753 vlib_increment_simple_counter (cm, thread_index, sw_if_index0, 1);
755 /* Increment super-interface drop/punt counters for sub-interfaces. */
756 sw_if0 = vnet_get_sw_interface (vnm, sw_if_index0);
757 vlib_increment_simple_counter (cm, thread_index,
758 sw_if0->sup_sw_if_index,
759 sw_if0->sup_sw_if_index != sw_if_index0);
761 if (PREDICT_FALSE (e0 != current_error))
763 current_counter -= 1;
765 vlib_error_elog_count (vm, current_counter_index,
767 - em->counters[current_counter_index]));
769 em->counters[current_counter_index] = current_counter;
773 current_counter_index = counter_index (vm, e0);
774 current_counter = em->counters[current_counter_index];
778 if (n_errors_current_sw_if_index > 0)
780 vnet_sw_interface_t *si;
782 vlib_increment_simple_counter (cm, thread_index, current_sw_if_index,
783 n_errors_current_sw_if_index);
785 si = vnet_get_sw_interface (vnm, current_sw_if_index);
786 if (si->sup_sw_if_index != current_sw_if_index)
787 vlib_increment_simple_counter (cm, thread_index, si->sup_sw_if_index,
788 n_errors_current_sw_if_index);
791 vlib_error_elog_count (vm, current_counter_index,
793 - em->counters[current_counter_index]));
795 /* Return cached counter. */
796 em->counters[current_counter_index] = current_counter;
798 /* Save memory for next iteration. */
799 memory[disposition] = current_error;
801 if (disposition == VNET_ERROR_DISPOSITION_DROP || !vm->os_punt_frame)
803 vlib_buffer_free (vm, first_buffer, frame->n_vectors);
805 /* If there is no punt function, free the frame as well. */
806 if (disposition == VNET_ERROR_DISPOSITION_PUNT && !vm->os_punt_frame)
807 vlib_frame_free (vm, node, frame);
810 vm->os_punt_frame (vm, node, frame);
812 return frame->n_vectors;
816 pcap_drop_trace (vlib_main_t * vm,
817 vnet_interface_main_t * im, vlib_frame_t * f)
820 u32 n_left = f->n_vectors;
821 vlib_buffer_t *b0, *p1;
823 i16 save_current_data;
824 u16 save_current_length;
826 from = vlib_frame_vector_args (f);
830 if (PREDICT_TRUE (n_left > 1))
832 p1 = vlib_get_buffer (vm, from[1]);
833 vlib_prefetch_buffer_header (p1, LOAD);
837 b0 = vlib_get_buffer (vm, bi0);
841 /* See if we're pointedly ignoring this specific error */
842 if (im->pcap_drop_filter_hash
843 && hash_get (im->pcap_drop_filter_hash, b0->error))
846 /* Trace all drops, or drops received on a specific interface */
847 if (im->pcap_sw_if_index == 0 ||
848 im->pcap_sw_if_index == vnet_buffer (b0)->sw_if_index[VLIB_RX])
850 save_current_data = b0->current_data;
851 save_current_length = b0->current_length;
854 * Typically, we'll need to rewind the buffer
856 if (b0->current_data > 0)
857 vlib_buffer_advance (b0, (word) - b0->current_data);
859 pcap_add_buffer (&im->pcap_main, vm, bi0, 512);
861 b0->current_data = save_current_data;
862 b0->current_length = save_current_length;
868 vnet_pcap_drop_trace_filter_add_del (u32 error_index, int is_add)
870 vnet_interface_main_t *im = &vnet_get_main ()->interface_main;
872 if (im->pcap_drop_filter_hash == 0)
873 im->pcap_drop_filter_hash = hash_create (0, sizeof (uword));
876 hash_set (im->pcap_drop_filter_hash, error_index, 1);
878 hash_unset (im->pcap_drop_filter_hash, error_index);
882 process_drop (vlib_main_t * vm,
883 vlib_node_runtime_t * node, vlib_frame_t * frame)
885 vnet_interface_main_t *im = &vnet_get_main ()->interface_main;
887 if (PREDICT_FALSE (im->drop_pcap_enable))
888 pcap_drop_trace (vm, im, frame);
890 return process_drop_punt (vm, node, frame, VNET_ERROR_DISPOSITION_DROP);
894 process_punt (vlib_main_t * vm,
895 vlib_node_runtime_t * node, vlib_frame_t * frame)
897 return process_drop_punt (vm, node, frame, VNET_ERROR_DISPOSITION_PUNT);
901 VLIB_REGISTER_NODE (drop_buffers,static) = {
902 .function = process_drop,
903 .name = "error-drop",
904 .flags = VLIB_NODE_FLAG_IS_DROP,
905 .vector_size = sizeof (u32),
906 .format_trace = format_vnet_error_trace,
907 .validate_frame = validate_error_frame,
911 VLIB_NODE_FUNCTION_MULTIARCH (drop_buffers, process_drop);
914 VLIB_REGISTER_NODE (punt_buffers,static) = {
915 .function = process_punt,
916 .flags = (VLIB_NODE_FLAG_FRAME_NO_FREE_AFTER_DISPATCH
917 | VLIB_NODE_FLAG_IS_PUNT),
918 .name = "error-punt",
919 .vector_size = sizeof (u32),
920 .format_trace = format_vnet_error_trace,
921 .validate_frame = validate_error_frame,
925 VLIB_NODE_FUNCTION_MULTIARCH (punt_buffers, process_punt);
928 VLIB_REGISTER_NODE (vnet_per_buffer_interface_output_node,static) = {
929 .function = vnet_per_buffer_interface_output,
930 .name = "interface-output",
931 .vector_size = sizeof (u32),
935 VLIB_NODE_FUNCTION_MULTIARCH (vnet_per_buffer_interface_output_node,
936 vnet_per_buffer_interface_output);
939 interface_tx_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
940 vlib_frame_t * from_frame)
942 vnet_main_t *vnm = vnet_get_main ();
943 u32 last_sw_if_index = ~0;
944 vlib_frame_t *to_frame = 0;
945 vnet_hw_interface_t *hw = 0;
946 u32 *from, *to_next = 0;
949 from = vlib_frame_vector_args (from_frame);
950 n_left_from = from_frame->n_vectors;
951 while (n_left_from > 0)
960 b0 = vlib_get_buffer (vm, bi0);
961 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
963 if (PREDICT_FALSE ((last_sw_if_index != sw_if_index0) || to_frame == 0))
967 hw = vnet_get_sup_hw_interface (vnm, last_sw_if_index);
968 vlib_put_frame_to_node (vm, hw->tx_node_index, to_frame);
970 last_sw_if_index = sw_if_index0;
971 hw = vnet_get_sup_hw_interface (vnm, sw_if_index0);
972 to_frame = vlib_get_frame_to_node (vm, hw->tx_node_index);
973 to_next = vlib_frame_vector_args (to_frame);
978 to_frame->n_vectors++;
980 vlib_put_frame_to_node (vm, hw->tx_node_index, to_frame);
981 return from_frame->n_vectors;
985 VLIB_REGISTER_NODE (interface_tx, static) = {
986 .function = interface_tx_node_fn,
987 .name = "interface-tx",
988 .vector_size = sizeof (u32),
995 VNET_FEATURE_ARC_INIT (interface_output, static) =
997 .arc_name = "interface-output",
998 .start_nodes = VNET_FEATURES (0),
999 .arc_index_ptr = &vnet_main.interface_main.output_feature_arc_index,
1002 VNET_FEATURE_INIT (span_tx, static) = {
1003 .arc_name = "interface-output",
1004 .node_name = "span-output",
1005 .runs_before = VNET_FEATURES ("interface-tx"),
1008 VNET_FEATURE_INIT (interface_tx, static) = {
1009 .arc_name = "interface-output",
1010 .node_name = "interface-tx",
1016 vnet_per_buffer_interface_output_hw_interface_add_del (vnet_main_t * vnm,
1020 vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
1023 next_index = vlib_node_add_next_with_slot
1024 (vnm->vlib_main, vnet_per_buffer_interface_output_node.index,
1025 hi->output_node_index,
1026 /* next_index */ hw_if_index);
1028 ASSERT (next_index == hw_if_index);
1033 VNET_HW_INTERFACE_ADD_DEL_FUNCTION
1034 (vnet_per_buffer_interface_output_hw_interface_add_del);
1036 static clib_error_t *
1037 pcap_drop_trace_command_fn (vlib_main_t * vm,
1038 unformat_input_t * input,
1039 vlib_cli_command_t * cmd)
1041 vnet_main_t *vnm = vnet_get_main ();
1042 vnet_interface_main_t *im = &vnm->interface_main;
1046 clib_error_t *error = 0;
1048 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1050 if (unformat (input, "on"))
1052 if (im->drop_pcap_enable == 0)
1054 if (im->pcap_filename == 0)
1055 im->pcap_filename = format (0, "/tmp/drop.pcap%c", 0);
1057 memset (&im->pcap_main, 0, sizeof (im->pcap_main));
1058 im->pcap_main.file_name = (char *) im->pcap_filename;
1059 im->pcap_main.n_packets_to_capture = 100;
1060 if (im->pcap_pkts_to_capture)
1061 im->pcap_main.n_packets_to_capture = im->pcap_pkts_to_capture;
1063 im->pcap_main.packet_type = PCAP_PACKET_TYPE_ethernet;
1064 im->drop_pcap_enable = 1;
1066 vlib_cli_output (vm, "pcap drop capture on...");
1070 vlib_cli_output (vm, "pcap drop capture already on...");
1074 else if (unformat (input, "off"))
1078 if (im->drop_pcap_enable)
1080 vlib_cli_output (vm, "captured %d pkts...",
1081 im->pcap_main.n_packets_captured);
1082 if (im->pcap_main.n_packets_captured)
1084 im->pcap_main.n_packets_to_capture =
1085 im->pcap_main.n_packets_captured;
1086 error = pcap_write (&im->pcap_main);
1088 clib_error_report (error);
1090 vlib_cli_output (vm, "saved to %s...", im->pcap_filename);
1095 vlib_cli_output (vm, "pcap drop capture already off...");
1098 im->drop_pcap_enable = 0;
1100 else if (unformat (input, "max %d", &max))
1102 im->pcap_pkts_to_capture = max;
1106 else if (unformat (input, "intfc %U",
1107 unformat_vnet_sw_interface, vnm,
1108 &im->pcap_sw_if_index))
1110 else if (unformat (input, "intfc any"))
1112 im->pcap_sw_if_index = 0;
1115 else if (unformat (input, "file %s", &filename))
1117 u8 *chroot_filename;
1118 /* Brain-police user path input */
1119 if (strstr ((char *) filename, "..")
1120 || index ((char *) filename, '/'))
1122 vlib_cli_output (vm, "illegal characters in filename '%s'",
1127 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
1128 vec_free (filename);
1130 if (im->pcap_filename)
1131 vec_free (im->pcap_filename);
1132 im->pcap_filename = chroot_filename;
1133 im->pcap_main.file_name = (char *) im->pcap_filename;
1136 else if (unformat (input, "status"))
1138 if (im->drop_pcap_enable == 0)
1140 vlib_cli_output (vm, "pcap drop capture is off...");
1144 vlib_cli_output (vm, "pcap drop capture: %d of %d pkts...",
1145 im->pcap_main.n_packets_captured,
1146 im->pcap_main.n_packets_to_capture);
1155 return clib_error_return (0, "unknown input `%U'",
1156 format_unformat_error, input);
1162 VLIB_CLI_COMMAND (pcap_trace_command, static) = {
1163 .path = "pcap drop trace",
1165 "pcap drop trace on off max <nn> intfc <intfc> file <name> status",
1166 .function = pcap_drop_trace_command_fn,
1171 * fd.io coding-style-patch-verification: ON
1174 * eval: (c-set-style "gnu")