udp: add option to disable icmp unreachables

Type: improvement

Signed-off-by: Florin Coras <fcoras@cisco.com>
Change-Id: I90c2a191ab34a2a7df3fb0a951e5fc78f40ccfe2
diff --git a/src/vnet/udp/udp.h b/src/vnet/udp/udp.h
index dc3f8f5..89539e5 100644
--- a/src/vnet/udp/udp.h
+++ b/src/vnet/udp/udp.h
@@ -122,6 +122,8 @@
 
   u16 default_mtu;
   u16 msg_id_base;
+
+  u8 icmp_send_unreachable_disabled;
 } udp_main_t;
 
 extern udp_main_t udp_main;
diff --git a/src/vnet/udp/udp_cli.c b/src/vnet/udp/udp_cli.c
index 09e3a8a..97760f4 100644
--- a/src/vnet/udp/udp_cli.c
+++ b/src/vnet/udp/udp_cli.c
@@ -100,6 +100,8 @@
     {
       if (unformat (input, "mtu %u", &tmp))
 	um->default_mtu = tmp;
+      else if (unformat (input, "icmp-unreachable-disabled"))
+	um->icmp_send_unreachable_disabled = 1;
       else
 	return clib_error_return (0, "unknown input `%U'",
 				  format_unformat_error, input);
diff --git a/src/vnet/udp/udp_local.c b/src/vnet/udp/udp_local.c
index 61aafaf..edfec33 100644
--- a/src/vnet/udp/udp_local.c
+++ b/src/vnet/udp/udp_local.c
@@ -54,6 +54,48 @@
 }
 #endif /* CLIB_MARCH_VARIANT */
 
+always_inline void
+udp_dispatch_error (vlib_node_runtime_t *node, vlib_buffer_t *b, u32 advance,
+		    u8 is_ip4, u32 *next)
+{
+  udp_main_t *um = &udp_main;
+  u8 punt_unknown = is_ip4 ? um->punt_unknown4 : um->punt_unknown6;
+
+  if (PREDICT_FALSE (punt_unknown))
+    {
+      vlib_buffer_advance (b, -(word) advance);
+      b->error = node->errors[UDP_ERROR_PUNT];
+      *next = UDP_LOCAL_NEXT_PUNT;
+    }
+  else if (um->icmp_send_unreachable_disabled)
+    {
+      *next = UDP_LOCAL_NEXT_DROP;
+      b->error = node->errors[UDP_ERROR_NO_LISTENER];
+    }
+  else
+    {
+      /* move the pointer back so icmp-error can find the ip packet header */
+      vlib_buffer_advance (b, -(word) advance);
+
+      if (is_ip4)
+	{
+	  icmp4_error_set_vnet_buffer (
+	    b, ICMP4_destination_unreachable,
+	    ICMP4_destination_unreachable_port_unreachable, 0);
+	  b->error = node->errors[UDP_ERROR_NO_LISTENER];
+	  *next = UDP_LOCAL_NEXT_ICMP;
+	}
+      else
+	{
+	  icmp6_error_set_vnet_buffer (
+	    b, ICMP6_destination_unreachable,
+	    ICMP6_destination_unreachable_port_unreachable, 0);
+	  b->error = node->errors[UDP_ERROR_NO_LISTENER];
+	  *next = UDP_LOCAL_NEXT_ICMP;
+	}
+    }
+}
+
 always_inline uword
 udp46_local_inline (vlib_main_t * vm,
 		    vlib_node_runtime_t * node,
@@ -61,7 +103,6 @@
 {
   udp_main_t *um = &udp_main;
   __attribute__ ((unused)) u32 n_left_from, next_index, *from, *to_next;
-  u8 punt_unknown = is_ip4 ? um->punt_unknown4 : um->punt_unknown6;
   u16 *next_by_dst_port = (is_ip4 ?
 			   um->next_by_dst_port4 : um->next_by_dst_port6);
   from = vlib_frame_vector_args (from_frame);
@@ -171,33 +212,7 @@
 	  if (PREDICT_FALSE (i0 == SPARSE_VEC_INVALID_INDEX ||
 			     next0 == UDP_NO_NODE_SET))
 	    {
-	      // move the pointer back so icmp-error can find the
-	      // ip packet header
-	      vlib_buffer_advance (b0, -(word) advance0);
-
-	      if (PREDICT_FALSE (punt_unknown))
-		{
-		  b0->error = node->errors[UDP_ERROR_PUNT];
-		  next0 = UDP_LOCAL_NEXT_PUNT;
-		}
-	      else if (is_ip4)
-		{
-		  icmp4_error_set_vnet_buffer (b0,
-					       ICMP4_destination_unreachable,
-					       ICMP4_destination_unreachable_port_unreachable,
-					       0);
-		  b0->error = node->errors[UDP_ERROR_NO_LISTENER];
-		  next0 = UDP_LOCAL_NEXT_ICMP;
-		}
-	      else
-		{
-		  icmp6_error_set_vnet_buffer (b0,
-					       ICMP6_destination_unreachable,
-					       ICMP6_destination_unreachable_port_unreachable,
-					       0);
-		  b0->error = node->errors[UDP_ERROR_NO_LISTENER];
-		  next0 = UDP_LOCAL_NEXT_ICMP;
-		}
+	      udp_dispatch_error (node, b0, advance0, is_ip4, &next0);
 	    }
 	  else
 	    {
@@ -209,33 +224,7 @@
 	  if (PREDICT_FALSE (i1 == SPARSE_VEC_INVALID_INDEX ||
 			     next1 == UDP_NO_NODE_SET))
 	    {
-	      // move the pointer back so icmp-error can find the
-	      // ip packet header
-	      vlib_buffer_advance (b1, -(word) advance1);
-
-	      if (PREDICT_FALSE (punt_unknown))
-		{
-		  b1->error = node->errors[UDP_ERROR_PUNT];
-		  next1 = UDP_LOCAL_NEXT_PUNT;
-		}
-	      else if (is_ip4)
-		{
-		  icmp4_error_set_vnet_buffer (b1,
-					       ICMP4_destination_unreachable,
-					       ICMP4_destination_unreachable_port_unreachable,
-					       0);
-		  b1->error = node->errors[UDP_ERROR_NO_LISTENER];
-		  next1 = UDP_LOCAL_NEXT_ICMP;
-		}
-	      else
-		{
-		  icmp6_error_set_vnet_buffer (b1,
-					       ICMP6_destination_unreachable,
-					       ICMP6_destination_unreachable_port_unreachable,
-					       0);
-		  b1->error = node->errors[UDP_ERROR_NO_LISTENER];
-		  next1 = UDP_LOCAL_NEXT_ICMP;
-		}
+	      udp_dispatch_error (node, b1, advance1, is_ip4, &next1);
 	    }
 	  else
 	    {
@@ -315,33 +304,7 @@
 	      if (PREDICT_FALSE ((i0 == SPARSE_VEC_INVALID_INDEX) ||
 				 next0 == UDP_NO_NODE_SET))
 		{
-		  // move the pointer back so icmp-error can find the
-		  // ip packet header
-		  vlib_buffer_advance (b0, -(word) advance0);
-
-		  if (PREDICT_FALSE (punt_unknown))
-		    {
-		      b0->error = node->errors[UDP_ERROR_PUNT];
-		      next0 = UDP_LOCAL_NEXT_PUNT;
-		    }
-		  else if (is_ip4)
-		    {
-		      icmp4_error_set_vnet_buffer (b0,
-						   ICMP4_destination_unreachable,
-						   ICMP4_destination_unreachable_port_unreachable,
-						   0);
-		      b0->error = node->errors[UDP_ERROR_NO_LISTENER];
-		      next0 = UDP_LOCAL_NEXT_ICMP;
-		    }
-		  else
-		    {
-		      icmp6_error_set_vnet_buffer (b0,
-						   ICMP6_destination_unreachable,
-						   ICMP6_destination_unreachable_port_unreachable,
-						   0);
-		      b0->error = node->errors[UDP_ERROR_NO_LISTENER];
-		      next0 = UDP_LOCAL_NEXT_ICMP;
-		    }
+		  udp_dispatch_error (node, b0, advance0, is_ip4, &next0);
 		}
 	      else
 		{