next0 = im->ip4_input_next_index_by_type[type0];
p0->error = node->errors[ICMP4_ERROR_UNKNOWN_TYPE];
- if (PREDICT_FALSE (next0 != next))
- {
- vlib_put_next_frame (vm, node, next, n_left_to_next + 1);
- next = next0;
- vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
- to_next[0] = bi0;
- to_next += 1;
- n_left_to_next -= 1;
- }
+
+ /* Verify speculative enqueue, maybe switch current next frame */
+ vlib_validate_buffer_enqueue_x1 (vm, node, next, to_next,
+ n_left_to_next, bi0, next0);
}
vlib_put_next_frame (vm, node, next, n_left_to_next);
while (n_left_from > 0 && n_left_to_next > 0)
{
- u32 pi0 = from[0];
+ /*
+ * Duplicate first buffer and free the original chain. Keep
+ * as much of the original packet as possible, within the
+ * minimum MTU. We chat "a little" here by keeping whatever
+ * is available in the first buffer.
+ */
+
+ u32 pi0 = ~0;
+ u32 org_pi0 = from[0];
u32 next0 = IP4_ICMP_ERROR_NEXT_LOOKUP;
u8 error0 = ICMP4_ERROR_NONE;
- vlib_buffer_t *p0;
+ vlib_buffer_t *p0, *org_p0;
ip4_header_t *ip0, *out_ip0;
icmp46_header_t *icmp0;
u32 sw_if_index0, if_add_index0;
ip_csum_t sum;
+ org_p0 = vlib_get_buffer (vm, org_pi0);
+ p0 = vlib_buffer_copy_no_chain (vm, org_p0, &pi0);
+ if (!p0 || pi0 == ~0) /* Out of buffers */
+ continue;
+
/* Speculatively enqueue p0 to the current next frame */
to_next[0] = pi0;
from += 1;
n_left_from -= 1;
n_left_to_next -= 1;
- p0 = vlib_get_buffer (vm, pi0);
ip0 = vlib_buffer_get_current (p0);
sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
- /*
- * RFC1812 says to keep as much of the original packet as
- * possible within the minimum MTU (576). We cheat "a little"
- * here by keeping whatever fits in the first buffer, to be more
- * efficient
- */
- if (PREDICT_FALSE (p0->total_length_not_including_first_buffer))
- {
- /* clear current_length of all other buffers in chain */
- vlib_buffer_t *b = p0;
- p0->total_length_not_including_first_buffer = 0;
- while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
- {
- b = vlib_get_buffer (vm, b->next_buffer);
- b->current_length = 0;
- }
- }
- p0->current_length =
- p0->current_length > 576 ? 576 : p0->current_length;
-
/* Add IP header and ICMPv4 header including a 4 byte data field */
vlib_buffer_advance (p0,
-sizeof (ip4_header_t) -
sizeof (icmp46_header_t) - 4);
+
+ p0->current_length =
+ p0->current_length > 576 ? 576 : p0->current_length;
out_ip0 = vlib_buffer_get_current (p0);
icmp0 = (icmp46_header_t *) & out_ip0[1];
/* Update error status */
if (error0 == ICMP4_ERROR_NONE)
error0 = icmp4_icmp_type_to_error (icmp0->type);
+
vlib_error_count (vm, node->node_index, error0, 1);
/* Verify speculative enqueue, maybe switch current next frame */
vlib_put_next_frame (vm, node, next_index, n_left_to_next);
}
+ /*
+ * push the original buffers to error-drop, so that
+ * they can get the error counters handled, then freed
+ */
+ vlib_buffer_enqueue_to_single_next (vm, node,
+ vlib_frame_vector_args (frame),
+ IP4_ICMP_ERROR_NEXT_DROP,
+ frame->n_vectors);
+
return frame->n_vectors;
}
ASSERT (p0->current_data == 0);
ip0 = (void *) (p0->data + ip_offset);
icmp0 = (void *) (p0->data + icmp_offset);
- len0 = clib_net_to_host_u16 (ip0->length) - ip4_header_bytes (ip0);
+
+ /* if IP length has been specified, then calculate the length based on buffer */
+ if (ip0->length == 0)
+ len0 = vlib_buffer_length_in_chain (vm, p0) - icmp_offset;
+ else
+ len0 = clib_net_to_host_u16 (ip0->length) - icmp_offset;
+
icmp0->checksum =
~ip_csum_fold (ip_incremental_checksum (0, icmp0, len0));
}
ip4_icmp_register_type (vlib_main_t * vm, icmp4_type_t type, u32 node_index)
{
icmp4_main_t *im = &icmp4_main;
+ u32 old_next_index;
ASSERT ((int) type < ARRAY_LEN (im->ip4_input_next_index_by_type));
+ old_next_index = im->ip4_input_next_index_by_type[type];
+
im->ip4_input_next_index_by_type[type]
= vlib_node_add_next (vm, ip4_icmp_input_node.index, node_index);
+
+ if (old_next_index &&
+ (old_next_index != im->ip4_input_next_index_by_type[type]))
+ clib_warning ("WARNING: changed next_by_type[%d]", (int) type);
}
static clib_error_t *
foreach_icmp4_code;
#undef _
- memset (cm->ip4_input_next_index_by_type,
- ICMP_INPUT_NEXT_ERROR, sizeof (cm->ip4_input_next_index_by_type));
+ clib_memset (cm->ip4_input_next_index_by_type,
+ ICMP_INPUT_NEXT_ERROR,
+ sizeof (cm->ip4_input_next_index_by_type));
ip4_icmp_register_type (vm, ICMP4_echo_request,
ip4_icmp_echo_request_node.index);