udp_main_t udp_main;
-#define foreach_udp_input_next \
- _ (PUNT, "error-punt") \
- _ (DROP, "error-drop")
+#define foreach_udp_input_next \
+ _ (PUNT, "error-punt") \
+ _ (DROP, "error-drop") \
+ _ (ICMP4_ERROR, "ip4-icmp-error") \
+ _ (ICMP6_ERROR, "ip6-icmp-error")
typedef enum {
#define _(s,n) UDP_INPUT_NEXT_##s,
typedef struct {
u16 src_port;
u16 dst_port;
+ u8 bound;
} udp_rx_trace_t;
u8 * format_udp_rx_trace (u8 * s, va_list * args)
CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
udp_rx_trace_t * t = va_arg (*args, udp_rx_trace_t *);
- s = format (s, "UDP: src-port %d dst-port %d",
+ s = format (s, "UDP: src-port %d dst-port %d%s",
clib_net_to_host_u16(t->src_port),
- clib_net_to_host_u16(t->dst_port));
+ clib_net_to_host_u16(t->dst_port),
+ t->bound ? "" : " (no listener)");
return s;
}
(void *) vlib_node_get_runtime_data (vm, udp4_input_node.index)
: (void *) vlib_node_get_runtime_data (vm, udp6_input_node.index);
__attribute__((unused)) u32 n_left_from, next_index, i_next, * from, * to_next;
+ word n_no_listener = 0;
from = vlib_frame_vector_args (from_frame);
n_left_from = from_frame->n_vectors;
advance1 = sizeof(ip6_header_t);
}
- if (PREDICT_FALSE(b0->current_length < advance0 + sizeof (h0)))
+ if (PREDICT_FALSE(b0->current_length < advance0 + sizeof (*h0)))
{
error0 = UDP_ERROR_LENGTH_ERROR;
next0 = UDP_INPUT_NEXT_DROP;
vlib_buffer_advance (b0, advance0);
h0 = vlib_buffer_get_current (b0);
error0 = next0 = 0;
+ if (PREDICT_FALSE(clib_net_to_host_u16(h0->length) >
+ vlib_buffer_length_in_chain(vm, b0)))
+ {
+ error0 = UDP_ERROR_LENGTH_ERROR;
+ next0 = UDP_INPUT_NEXT_DROP;
+ }
}
- if (PREDICT_FALSE(b1->current_length < advance1 + sizeof (h1)))
+ if (PREDICT_FALSE(b1->current_length < advance1 + sizeof (*h1)))
{
error1 = UDP_ERROR_LENGTH_ERROR;
next1 = UDP_INPUT_NEXT_DROP;
vlib_buffer_advance (b1, advance1);
h1 = vlib_buffer_get_current (b1);
error1 = next1 = 0;
+ if (PREDICT_FALSE(clib_net_to_host_u16(h1->length) >
+ vlib_buffer_length_in_chain(vm, b1)))
+ {
+ error1 = UDP_ERROR_LENGTH_ERROR;
+ next1 = UDP_INPUT_NEXT_DROP;
+ }
}
-
/* Index sparse array with network byte order. */
dst_port0 = (error0 == 0) ? h0->dst_port : 0;
dst_port1 = (error1 == 0) ? h1->dst_port : 0;
next0 = (error0 == 0) ? vec_elt(rt->next_by_dst_port, i0) : next0;
next1 = (error1 == 0) ? vec_elt(rt->next_by_dst_port, i1) : next1;
- if (PREDICT_TRUE (error0 == 0))
- b0->error = node->errors[next0 == SPARSE_VEC_INVALID_INDEX ? UDP_ERROR_NO_LISTENER : UDP_ERROR_NONE];
- if (PREDICT_TRUE (error1 == 0))
- b1->error = node->errors[next1 == SPARSE_VEC_INVALID_INDEX ? UDP_ERROR_NO_LISTENER : UDP_ERROR_NONE];
+ if (PREDICT_FALSE(next0 == SPARSE_VEC_INVALID_INDEX))
+ {
+ // move the pointer back so icmp-error can find the
+ // ip packet header
+ vlib_buffer_advance (b0, - (word)advance0);
+
+ if (is_ip4)
+ {
+ icmp4_error_set_vnet_buffer(b0, ICMP4_destination_unreachable,
+ ICMP4_destination_unreachable_port_unreachable, 0);
+ next0 = UDP_INPUT_NEXT_ICMP4_ERROR;
+ }
+ else
+ {
+ icmp6_error_set_vnet_buffer(b0, ICMP6_destination_unreachable,
+ ICMP6_destination_unreachable_port_unreachable, 0);
+ next0 = UDP_INPUT_NEXT_ICMP6_ERROR;
+ }
+ n_no_listener ++;
+ }
+ else
+ {
+ b0->error = node->errors[UDP_ERROR_NONE];
+ // advance to the payload
+ vlib_buffer_advance (b0, sizeof (*h0));
+ }
+
+ if (PREDICT_FALSE(next1 == SPARSE_VEC_INVALID_INDEX))
+ {
+ // move the pointer back so icmp-error can find the
+ // ip packet header
+ vlib_buffer_advance (b1, - (word)advance1);
+
+ if (is_ip4)
+ {
+ icmp4_error_set_vnet_buffer(b1, ICMP4_destination_unreachable,
+ ICMP4_destination_unreachable_port_unreachable, 0);
+ next1 = UDP_INPUT_NEXT_ICMP4_ERROR;
+ }
+ else
+ {
+ icmp6_error_set_vnet_buffer(b1, ICMP6_destination_unreachable,
+ ICMP6_destination_unreachable_port_unreachable, 0);
+ next1 = UDP_INPUT_NEXT_ICMP6_ERROR;
+ }
+ n_no_listener ++;
+ }
+ else
+ {
+ b1->error = node->errors[UDP_ERROR_NONE];
+ // advance to the payload
+ vlib_buffer_advance (b1, sizeof (*h1));
+ }
if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
{
{
tr->src_port = h0->src_port;
tr->dst_port = h0->dst_port;
+ tr->bound = (next0 != UDP_INPUT_NEXT_ICMP4_ERROR &&
+ next0 != UDP_INPUT_NEXT_ICMP6_ERROR);
}
}
if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
{
tr->src_port = h1->src_port;
tr->dst_port = h1->dst_port;
+ tr->bound = (next1 != UDP_INPUT_NEXT_ICMP4_ERROR &&
+ next1 != UDP_INPUT_NEXT_ICMP6_ERROR);
}
}
- vlib_buffer_advance (b0, sizeof (*h0));
- vlib_buffer_advance (b1, sizeof (*h1));
-
vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
to_next, n_left_to_next,
bi0, bi1, next0, next1);
else
advance0 = sizeof(ip6_header_t);
- if (PREDICT_FALSE(b0->current_length < advance0 + sizeof (h0)))
+ if (PREDICT_FALSE(b0->current_length < advance0 + sizeof (*h0)))
{
b0->error = node->errors[UDP_ERROR_LENGTH_ERROR];
next0 = UDP_INPUT_NEXT_DROP;
h0 = vlib_buffer_get_current (b0);
- if (PREDICT_TRUE
- (clib_net_to_host_u16(h0->length) <= b0->current_length))
+ if (PREDICT_TRUE(clib_net_to_host_u16(h0->length) <=
+ vlib_buffer_length_in_chain(vm, b0)))
{
i0 = sparse_vec_index (rt->next_by_dst_port, h0->dst_port);
next0 = vec_elt(rt->next_by_dst_port, i0);
- b0->error = node->errors [next0 == SPARSE_VEC_INVALID_INDEX ? UDP_ERROR_NO_LISTENER : UDP_ERROR_NONE];
+ if (PREDICT_FALSE(next0 == SPARSE_VEC_INVALID_INDEX))
+ {
+ // move the pointer back so icmp-error can find the
+ // ip packet header
+ vlib_buffer_advance (b0, - (word)advance0);
+
+ if (is_ip4)
+ {
+ icmp4_error_set_vnet_buffer(b0, ICMP4_destination_unreachable,
+ ICMP4_destination_unreachable_port_unreachable, 0);
+ next0 = UDP_INPUT_NEXT_ICMP4_ERROR;
+ }
+ else
+ {
+ icmp6_error_set_vnet_buffer(b0, ICMP6_destination_unreachable,
+ ICMP6_destination_unreachable_port_unreachable, 0);
+ next0 = UDP_INPUT_NEXT_ICMP6_ERROR;
+ }
+ n_no_listener ++;
+ }
+ else
+ {
+ b0->error = node->errors[UDP_ERROR_NONE];
+ // advance to the payload
+ vlib_buffer_advance (b0, sizeof (*h0));
+ }
}
else
{
{
tr->src_port = h0->src_port;
tr->dst_port = h0->dst_port;
+ tr->bound = (next0 != UDP_INPUT_NEXT_ICMP4_ERROR &&
+ next0 != UDP_INPUT_NEXT_ICMP6_ERROR);
}
}
- vlib_buffer_advance (b0, sizeof (*h0));
+
vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
to_next, n_left_to_next,
bi0, next0);
vlib_put_next_frame (vm, node, next_index, n_left_to_next);
}
+ vlib_error_count(vm, node->node_index, UDP_ERROR_NO_LISTENER, n_no_listener);
return from_frame->n_vectors;
}
.unformat_buffer = unformat_udp_header,
};
+VLIB_NODE_FUNCTION_MULTIARCH (udp4_input_node, udp4_input)
+
VLIB_REGISTER_NODE (udp6_input_node) = {
.function = udp6_input,
.name = "ip6-udp-lookup",
.unformat_buffer = unformat_udp_header,
};
+VLIB_NODE_FUNCTION_MULTIARCH (udp6_input_node, udp6_input)
+
static void add_dst_port (udp_main_t * um,
udp_dst_port_t dst_port,
char * dst_port_name, u8 is_ip4)