_ (DST_LOOKUP_MISS, "icmp6 dst address lookup misses") \
_ (DEST_UNREACH_SENT, "destination unreachable response sent") \
_ (TTL_EXPIRE_SENT, "hop limit exceeded response sent") \
- _ (PARAM_PROBLEM_SENT, "parameter Pproblem response sent") \
+ _ (PARAM_PROBLEM_SENT, "parameter problem response sent") \
_ (DROP, "error message dropped")
typedef enum {
typedef enum {
IP4_REWRITE_NEXT_DROP,
IP4_REWRITE_NEXT_ARP,
+ IP4_REWRITE_NEXT_ICMP_ERROR,
} ip4_rewrite_next_t;
always_inline uword
ip1 = vlib_buffer_get_current (p1);
error0 = error1 = IP4_ERROR_NONE;
+ next0 = next1 = IP4_REWRITE_NEXT_DROP;
/* Decrement TTL & update checksum.
Works either endian, so no need for byte swap. */
ip0->ttl = ttl0;
ip1->ttl = ttl1;
- error0 = ttl0 <= 0 ? IP4_ERROR_TIME_EXPIRED : error0;
- error1 = ttl1 <= 0 ? IP4_ERROR_TIME_EXPIRED : error1;
+ /*
+ * If the ttl drops below 1 when forwarding, generate
+ * an ICMP response.
+ */
+ if (PREDICT_FALSE(ttl0 <= 0))
+ {
+ error0 = IP4_ERROR_TIME_EXPIRED;
+ vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32)~0;
+ icmp4_error_set_vnet_buffer(p0, ICMP4_time_exceeded,
+ ICMP4_time_exceeded_ttl_exceeded_in_transit, 0);
+ next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
+ }
+ if (PREDICT_FALSE(ttl1 <= 0))
+ {
+ error1 = IP4_ERROR_TIME_EXPIRED;
+ vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32)~0;
+ icmp4_error_set_vnet_buffer(p1, ICMP4_time_exceeded,
+ ICMP4_time_exceeded_ttl_exceeded_in_transit, 0);
+ next1 = IP4_REWRITE_NEXT_ICMP_ERROR;
+ }
/* Verify checksum. */
ASSERT (ip0->checksum == ip4_header_checksum (ip0));
? IP4_ERROR_MTU_EXCEEDED
: error1);
- next0 = (error0 == IP4_ERROR_NONE)
- ? adj0[0].rewrite_header.next_index : 0;
+ next0 = (error0 == IP4_ERROR_NONE)
+ ? adj0[0].rewrite_header.next_index : next0;
if (rewrite_for_locally_received_packets)
next0 = next0 && next0_override ? next0_override : next0;
- next1 = (error1 == IP4_ERROR_NONE)
- ? adj1[0].rewrite_header.next_index : 0;
+ next1 = (error1 == IP4_ERROR_NONE)
+ ? adj1[0].rewrite_header.next_index : next1;
if (rewrite_for_locally_received_packets)
next1 = next1 && next1_override ? next1_override : next1;
/* packet increment */ 0,
/* byte increment */ rw_len1-sizeof(ethernet_header_t));
- p0->current_data -= rw_len0;
- p1->current_data -= rw_len1;
-
- p0->current_length += rw_len0;
- p1->current_length += rw_len1;
-
- vnet_buffer (p0)->sw_if_index[VLIB_TX] = adj0[0].rewrite_header.sw_if_index;
- vnet_buffer (p1)->sw_if_index[VLIB_TX] = adj1[0].rewrite_header.sw_if_index;
-
- p0->error = error_node->errors[error0];
- p1->error = error_node->errors[error1];
+ /* Don't adjust the buffer for ttl issue; icmp-error node wants
+ * to see the IP headerr */
+ if (PREDICT_TRUE(error0 == IP4_ERROR_NONE))
+ {
+ p0->current_data -= rw_len0;
+ p0->current_length += rw_len0;
+ p0->error = error_node->errors[error0];
+ vnet_buffer (p0)->sw_if_index[VLIB_TX] =
+ adj0[0].rewrite_header.sw_if_index;
+ }
+ if (PREDICT_TRUE(error1 == IP4_ERROR_NONE))
+ {
+ p1->current_data -= rw_len1;
+ p1->current_length += rw_len1;
+ p1->error = error_node->errors[error1];
+ vnet_buffer (p1)->sw_if_index[VLIB_TX] =
+ adj1[0].rewrite_header.sw_if_index;
+ }
/* Guess we are only writing on simple Ethernet header. */
vnet_rewrite_two_headers (adj0[0], adj1[0],
ip0 = vlib_buffer_get_current (p0);
error0 = IP4_ERROR_NONE;
- next0 = 0; /* drop on error */
+ next0 = IP4_REWRITE_NEXT_DROP; /* drop on error */
/* Decrement TTL & update checksum. */
if (! rewrite_for_locally_received_packets)
ASSERT (ip0->checksum == ip4_header_checksum (ip0));
- error0 = ttl0 <= 0 ? IP4_ERROR_TIME_EXPIRED : error0;
+ if (PREDICT_FALSE(ttl0 <= 0))
+ {
+ /*
+ * If the ttl drops below 1 when forwarding, generate
+ * an ICMP response.
+ */
+ error0 = IP4_ERROR_TIME_EXPIRED;
+ next0 = IP4_REWRITE_NEXT_ICMP_ERROR;
+ vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32)~0;
+ icmp4_error_set_vnet_buffer(p0, ICMP4_time_exceeded,
+ ICMP4_time_exceeded_ttl_exceeded_in_transit, 0);
+ }
}
if (rewrite_for_locally_received_packets)
> adj0[0].rewrite_header.max_l3_packet_bytes
? IP4_ERROR_MTU_EXCEEDED
: error0);
-
+
p0->error = error_node->errors[error0];
- p0->current_data -= rw_len0;
- p0->current_length += rw_len0;
- vnet_buffer (p0)->sw_if_index[VLIB_TX] =
- adj0[0].rewrite_header.sw_if_index;
-
- next0 = (error0 == IP4_ERROR_NONE)
- ? adj0[0].rewrite_header.next_index : 0;
+
+ /* Don't adjust the buffer for ttl issue; icmp-error node wants
+ * to see the IP headerr */
+ if (PREDICT_TRUE(error0 == IP4_ERROR_NONE))
+ {
+ p0->current_data -= rw_len0;
+ p0->current_length += rw_len0;
+
+ vnet_buffer (p0)->sw_if_index[VLIB_TX] =
+ adj0[0].rewrite_header.sw_if_index;
+ next0 = adj0[0].rewrite_header.next_index;
+ }
if (rewrite_for_locally_received_packets)
next0 = next0 && next0_override ? next0_override : next0;
.format_trace = format_ip4_rewrite_trace,
- .n_next_nodes = 2,
+ .n_next_nodes = 3,
.next_nodes = {
[IP4_REWRITE_NEXT_DROP] = "error-drop",
[IP4_REWRITE_NEXT_ARP] = "ip4-arp",
+ [IP4_REWRITE_NEXT_ICMP_ERROR] = "ip4-icmp-error",
},
};
error0 = ip4_get_fragment_offset (ip0) == 1 ? IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
error1 = ip4_get_fragment_offset (ip1) == 1 ? IP4_ERROR_FRAGMENT_OFFSET_ONE : error1;
- /* TTL <= 1? Drop it. */
- error0 = (ip0->ttl <= 1 && cast0 == VNET_UNICAST) ? IP4_ERROR_TIME_EXPIRED : error0;
- error1 = (ip1->ttl <= 1 && cast1 == VNET_UNICAST) ? IP4_ERROR_TIME_EXPIRED : error1;
+ /* TTL < 1? Drop it. */
+ error0 = (ip0->ttl < 1 && cast0 == VNET_UNICAST) ? IP4_ERROR_TIME_EXPIRED : error0;
+ error1 = (ip1->ttl < 1 && cast1 == VNET_UNICAST) ? IP4_ERROR_TIME_EXPIRED : error1;
/* Verify lengths. */
ip_len0 = clib_net_to_host_u16 (ip0->length);
/* Drop fragmentation offset 1 packets. */
error0 = ip4_get_fragment_offset (ip0) == 1 ? IP4_ERROR_FRAGMENT_OFFSET_ONE : error0;
- /* TTL <= 1? Drop it. */
- error0 = (ip0->ttl <= 1 && cast0 == VNET_UNICAST) ? IP4_ERROR_TIME_EXPIRED : error0;
+ /* TTL < 1? Drop it. */
+ error0 = (ip0->ttl < 1 && cast0 == VNET_UNICAST) ? IP4_ERROR_TIME_EXPIRED : error0;
/* Verify lengths. */
ip_len0 = clib_net_to_host_u16 (ip0->length);
typedef enum {
IP6_REWRITE_NEXT_DROP,
+ IP6_REWRITE_NEXT_ICMP_ERROR,
} ip6_rewrite_next_t;
always_inline uword
ip1 = vlib_buffer_get_current (p1);
error0 = error1 = IP6_ERROR_NONE;
+ next0 = next1 = IP6_REWRITE_NEXT_DROP;
if (! rewrite_for_locally_received_packets)
{
ip0->hop_limit = hop_limit0;
ip1->hop_limit = hop_limit1;
- error0 = hop_limit0 <= 0 ? IP6_ERROR_TIME_EXPIRED : error0;
- error1 = hop_limit1 <= 0 ? IP6_ERROR_TIME_EXPIRED : error1;
+ /*
+ * If the hop count drops below 1 when forwarding, generate
+ * an ICMP response.
+ */
+ if (PREDICT_FALSE(hop_limit0 <= 0))
+ {
+ error0 = IP6_ERROR_TIME_EXPIRED;
+ next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
+ vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32)~0;
+ icmp6_error_set_vnet_buffer(p0, ICMP6_time_exceeded,
+ ICMP6_time_exceeded_ttl_exceeded_in_transit, 0);
+ }
+ if (PREDICT_FALSE(hop_limit1 <= 0))
+ {
+ error1 = IP6_ERROR_TIME_EXPIRED;
+ next1 = IP6_REWRITE_NEXT_ICMP_ERROR;
+ vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32)~0;
+ icmp6_error_set_vnet_buffer(p1, ICMP6_time_exceeded,
+ ICMP6_time_exceeded_ttl_exceeded_in_transit, 0);
+ }
}
adj0 = ip_get_adjacency (lm, adj_index0);
? IP6_ERROR_MTU_EXCEEDED
: error1);
- p0->current_data -= rw_len0;
- p1->current_data -= rw_len1;
+ /* Don't adjust the buffer for hop count issue; icmp-error node
+ * wants to see the IP headerr */
+ if (PREDICT_TRUE(error0 == IP6_ERROR_NONE))
+ {
+ p0->current_data -= rw_len0;
+ p0->current_length += rw_len0;
- p0->current_length += rw_len0;
- p1->current_length += rw_len1;
+ vnet_buffer (p0)->sw_if_index[VLIB_TX] =
+ adj0[0].rewrite_header.sw_if_index;
+ next0 = adj0[0].rewrite_header.next_index;
+ }
+ if (PREDICT_TRUE(error1 == IP6_ERROR_NONE))
+ {
+ p1->current_data -= rw_len1;
+ p1->current_length += rw_len1;
- vnet_buffer (p0)->sw_if_index[VLIB_TX] = adj0[0].rewrite_header.sw_if_index;
- vnet_buffer (p1)->sw_if_index[VLIB_TX] = adj1[0].rewrite_header.sw_if_index;
-
- next0 = (error0 == IP6_ERROR_NONE) ?
- adj0[0].rewrite_header.next_index : IP6_REWRITE_NEXT_DROP;
- next1 = (error1 == IP6_ERROR_NONE) ?
- adj1[0].rewrite_header.next_index : IP6_REWRITE_NEXT_DROP;
+ vnet_buffer (p1)->sw_if_index[VLIB_TX] =
+ adj1[0].rewrite_header.sw_if_index;
+ next1 = adj1[0].rewrite_header.next_index;
+ }
/* Guess we are only writing on simple Ethernet header. */
vnet_rewrite_two_headers (adj0[0], adj1[0],
ip0 = vlib_buffer_get_current (p0);
error0 = IP6_ERROR_NONE;
+ next0 = IP6_REWRITE_NEXT_DROP;
/* Check hop limit */
if (! rewrite_for_locally_received_packets)
ip0->hop_limit = hop_limit0;
- error0 = hop_limit0 <= 0 ? IP6_ERROR_TIME_EXPIRED : error0;
+ if (PREDICT_FALSE(hop_limit0 <= 0))
+ {
+ /*
+ * If the hop count drops below 1 when forwarding, generate
+ * an ICMP response.
+ */
+ error0 = IP6_ERROR_TIME_EXPIRED;
+ next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
+ vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32)~0;
+ icmp6_error_set_vnet_buffer(p0, ICMP6_time_exceeded,
+ ICMP6_time_exceeded_ttl_exceeded_in_transit, 0);
+ }
}
if (rewrite_for_locally_received_packets)
? IP6_ERROR_MTU_EXCEEDED
: error0);
- p0->current_data -= rw_len0;
- p0->current_length += rw_len0;
- vnet_buffer (p0)->sw_if_index[VLIB_TX] = adj0[0].rewrite_header.sw_if_index;
-
- next0 = (error0 == IP6_ERROR_NONE) ?
- adj0[0].rewrite_header.next_index : IP6_REWRITE_NEXT_DROP;
+ /* Don't adjust the buffer for hop count issue; icmp-error node
+ * wants to see the IP headerr */
+ if (PREDICT_TRUE(error0 == IP6_ERROR_NONE))
+ {
+ p0->current_data -= rw_len0;
+ p0->current_length += rw_len0;
+
+ vnet_buffer (p0)->sw_if_index[VLIB_TX] =
+ adj0[0].rewrite_header.sw_if_index;
+ next0 = adj0[0].rewrite_header.next_index;
+ }
p0->error = error_node->errors[error0];
.format_trace = format_ip6_rewrite_trace,
- .n_next_nodes = 1,
+ .n_next_nodes = 2,
.next_nodes = {
[IP6_REWRITE_NEXT_DROP] = "error-drop",
+ [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
},
};
* like dhcpv6 packets from client has hop-limit 1, which should not
* be dropped.
*/
- error0 = ip0->hop_limit <= 1 ? IP6_ERROR_TIME_EXPIRED : error0;
- error1 = ip1->hop_limit <= 1 ? IP6_ERROR_TIME_EXPIRED : error1;
+ error0 = ip0->hop_limit < 1 ? IP6_ERROR_TIME_EXPIRED : error0;
+ error1 = ip1->hop_limit < 1 ? IP6_ERROR_TIME_EXPIRED : error1;
/* L2 length must be at least minimal IP header. */
error0 = p0->current_length < sizeof (ip0[0]) ? IP6_ERROR_TOO_SHORT : error0;
* like dhcpv6 packets from client has hop-limit 1, which should not
* be dropped.
*/
- error0 = ip0->hop_limit <= 1 ? IP6_ERROR_TIME_EXPIRED : error0;
+ error0 = ip0->hop_limit < 1 ? IP6_ERROR_TIME_EXPIRED : error0;
/* L2 length must be at least minimal IP header. */
error0 = p0->current_length < sizeof (ip0[0]) ? IP6_ERROR_TOO_SHORT : error0;
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;
next0 = (error0 == 0) ? vec_elt(rt->next_by_dst_port, i0) : next0;
next1 = (error1 == 0) ? vec_elt(rt->next_by_dst_port, i1) : next1;
- b0->error = node->errors[next0 == SPARSE_VEC_INVALID_INDEX ?
- UDP_ERROR_NO_LISTENER : error0];
- b1->error = node->errors[next1 == SPARSE_VEC_INVALID_INDEX ?
- UDP_ERROR_NO_LISTENER : error1];
+ 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);
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;
}