From: Chris Luke Date: Tue, 14 Jun 2016 20:24:47 +0000 (-0400) Subject: VPP-48 Fixes for ip4/6 ttl checks and icmp responses X-Git-Tag: v16.09-rc1~230 X-Git-Url: https://gerrit.fd.io/r/gitweb?a=commitdiff_plain;h=816f3e1b879b43802ea8035d6a3f1cbf5db76825;p=vpp.git VPP-48 Fixes for ip4/6 ttl checks and icmp responses This patch fixes a few minor things: - Previously ip[46]_input was rejecting packets with an input TTL (hop limit) of one; this was not correct behavior. Packets that are bound for this device can validly have a TTL of one. - ip[46]_forward was not generating an ICMP TTL expired message if the act of decrementing the TTL caused it to become zero. This was not previously an issue because ip[46]_input was filtering packets where this could happen. - udp_local was not generating ICMP Port Unreachable messages if UDP packets arrived for a port that is not listened to. This is typically the signal that "traceroute" uses to terminate its search. Together these fixes mean that traceroute probes transiting a VPP node, or are targetted toward a VPP node, now work as expected. Change-Id: I84bb940883f7a18435f29f4518fb0445b989a3e3 Signed-off-by: Chris Luke --- diff --git a/vnet/vnet/ip/icmp4.h b/vnet/vnet/ip/icmp4.h index f99bf2dafc3..07fe52d11ea 100644 --- a/vnet/vnet/ip/icmp4.h +++ b/vnet/vnet/ip/icmp4.h @@ -28,7 +28,7 @@ _ (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 { diff --git a/vnet/vnet/ip/ip4_forward.c b/vnet/vnet/ip/ip4_forward.c index 96036dc0ec6..6008ec222c5 100644 --- a/vnet/vnet/ip/ip4_forward.c +++ b/vnet/vnet/ip/ip4_forward.c @@ -2516,6 +2516,7 @@ ip4_probe_neighbor (vlib_main_t * vm, ip4_address_t * dst, u32 sw_if_index) typedef enum { IP4_REWRITE_NEXT_DROP, IP4_REWRITE_NEXT_ARP, + IP4_REWRITE_NEXT_ICMP_ERROR, } ip4_rewrite_next_t; always_inline uword @@ -2585,6 +2586,7 @@ ip4_rewrite_inline (vlib_main_t * vm, 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. */ @@ -2611,8 +2613,26 @@ ip4_rewrite_inline (vlib_main_t * vm, 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)); @@ -2657,14 +2677,14 @@ ip4_rewrite_inline (vlib_main_t * vm, ? 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; @@ -2686,17 +2706,24 @@ ip4_rewrite_inline (vlib_main_t * vm, /* 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], @@ -2733,7 +2760,7 @@ ip4_rewrite_inline (vlib_main_t * vm, 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) @@ -2754,7 +2781,18 @@ ip4_rewrite_inline (vlib_main_t * vm, 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) @@ -2796,15 +2834,20 @@ ip4_rewrite_inline (vlib_main_t * vm, > 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; @@ -2854,10 +2897,11 @@ VLIB_REGISTER_NODE (ip4_rewrite_node) = { .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", }, }; diff --git a/vnet/vnet/ip/ip4_input.c b/vnet/vnet/ip/ip4_input.c index 5b2b42ded13..c5281c4eb1d 100644 --- a/vnet/vnet/ip/ip4_input.c +++ b/vnet/vnet/ip/ip4_input.c @@ -194,9 +194,9 @@ ip4_input_inline (vlib_main_t * vm, 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); @@ -293,8 +293,8 @@ ip4_input_inline (vlib_main_t * vm, /* 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); diff --git a/vnet/vnet/ip/ip6_forward.c b/vnet/vnet/ip/ip6_forward.c index afb23f1bf6c..eabaa89802b 100644 --- a/vnet/vnet/ip/ip6_forward.c +++ b/vnet/vnet/ip/ip6_forward.c @@ -2277,6 +2277,7 @@ ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index) typedef enum { IP6_REWRITE_NEXT_DROP, + IP6_REWRITE_NEXT_ICMP_ERROR, } ip6_rewrite_next_t; always_inline uword @@ -2345,6 +2346,7 @@ ip6_rewrite_inline (vlib_main_t * vm, ip1 = vlib_buffer_get_current (p1); error0 = error1 = IP6_ERROR_NONE; + next0 = next1 = IP6_REWRITE_NEXT_DROP; if (! rewrite_for_locally_received_packets) { @@ -2360,8 +2362,26 @@ ip6_rewrite_inline (vlib_main_t * vm, 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); @@ -2403,19 +2423,26 @@ ip6_rewrite_inline (vlib_main_t * vm, ? 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], @@ -2449,6 +2476,7 @@ ip6_rewrite_inline (vlib_main_t * vm, ip0 = vlib_buffer_get_current (p0); error0 = IP6_ERROR_NONE; + next0 = IP6_REWRITE_NEXT_DROP; /* Check hop limit */ if (! rewrite_for_locally_received_packets) @@ -2461,7 +2489,18 @@ ip6_rewrite_inline (vlib_main_t * vm, 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) @@ -2488,12 +2527,17 @@ ip6_rewrite_inline (vlib_main_t * vm, ? 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]; @@ -2542,9 +2586,10 @@ VLIB_REGISTER_NODE (ip6_rewrite_node) = { .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", }, }; diff --git a/vnet/vnet/ip/ip6_input.c b/vnet/vnet/ip/ip6_input.c index 7b5470dc553..05929c55884 100644 --- a/vnet/vnet/ip/ip6_input.c +++ b/vnet/vnet/ip/ip6_input.c @@ -177,8 +177,8 @@ ip6_input (vlib_main_t * vm, * 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; @@ -252,7 +252,7 @@ ip6_input (vlib_main_t * vm, * 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; diff --git a/vnet/vnet/ip/udp_local.c b/vnet/vnet/ip/udp_local.c index 354dd4e8c91..9b701470934 100644 --- a/vnet/vnet/ip/udp_local.c +++ b/vnet/vnet/ip/udp_local.c @@ -23,9 +23,11 @@ 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, @@ -37,6 +39,7 @@ typedef enum { typedef struct { u16 src_port; u16 dst_port; + u8 bound; } udp_rx_trace_t; u8 * format_udp_rx_trace (u8 * s, va_list * args) @@ -45,9 +48,10 @@ 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; } @@ -72,6 +76,7 @@ udp46_input_inline (vlib_main_t * vm, (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; @@ -177,10 +182,59 @@ udp46_input_inline (vlib_main_t * vm, 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)) { @@ -190,6 +244,8 @@ udp46_input_inline (vlib_main_t * vm, { 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)) @@ -200,12 +256,11 @@ udp46_input_inline (vlib_main_t * vm, { 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); @@ -251,7 +306,32 @@ udp46_input_inline (vlib_main_t * vm, 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 { @@ -268,9 +348,11 @@ udp46_input_inline (vlib_main_t * vm, { 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); @@ -278,6 +360,7 @@ udp46_input_inline (vlib_main_t * vm, 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; }