VPP-1283: IPv6 PMTU missing MTU value in ICMP6 message.

Fix GRE/IPv6 setting of ip->payload_length (which has never worked).

Change-Id: Ie68f1cc7bbb70489d6ec97356132c783f2345e1e
Signed-off-by: Ole Troan <ot@cisco.com>
diff --git a/src/vnet/gre/gre.c b/src/vnet/gre/gre.c
index 0b8d2cc..e82befe 100644
--- a/src/vnet/gre/gre.c
+++ b/src/vnet/gre/gre.c
@@ -292,8 +292,8 @@
   /* Fixup the payload length field in the GRE tunnel encap that was applied
    * at the midchain node */
   ip0->payload_length =
-    clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0))
-    - sizeof (*ip0);
+    clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) -
+			  sizeof (*ip0));
 }
 
 void
diff --git a/src/vnet/ip/icmp6.c b/src/vnet/ip/icmp6.c
index fd5d0ec..6ebdef4 100644
--- a/src/vnet/ip/icmp6.c
+++ b/src/vnet/ip/icmp6.c
@@ -526,13 +526,15 @@
 		  b->current_length = 0;
 		}
 	    }
-	  p0->current_length =
-	    p0->current_length > 1280 ? 1280 : p0->current_length;
 
 	  /* Add IP header and ICMPv6 header including a 4 byte data field */
 	  vlib_buffer_advance (p0,
 			       -sizeof (ip6_header_t) -
 			       sizeof (icmp46_header_t) - 4);
+
+	  p0->current_length =
+	    p0->current_length > 1280 ? 1280 : p0->current_length;
+
 	  out_ip0 = vlib_buffer_get_current (p0);
 	  icmp0 = (icmp46_header_t *) & out_ip0[1];
 
diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c
index c45b65f..f4c51e2 100644
--- a/src/vnet/ip/ip6_forward.c
+++ b/src/vnet/ip/ip6_forward.c
@@ -1561,6 +1561,19 @@
  */
 #define IP6_MCAST_ADDR_MASK 0xffffffff
 
+always_inline void
+ip6_mtu_check (vlib_buffer_t * b, u16 packet_bytes,
+	       u16 adj_packet_bytes, u32 * next, u32 * error)
+{
+  if (adj_packet_bytes >= 1280 && packet_bytes > adj_packet_bytes)
+    {
+      *error = IP6_ERROR_MTU_EXCEEDED;
+      icmp6_error_set_vnet_buffer (b, ICMP6_packet_too_big, 0,
+				   adj_packet_bytes);
+      *next = IP6_REWRITE_NEXT_ICMP_ERROR;
+    }
+}
+
 always_inline uword
 ip6_rewrite_inline (vlib_main_t * vm,
 		    vlib_node_runtime_t * node,
@@ -1706,16 +1719,14 @@
 	    }
 
 	  /* Check MTU of outgoing interface. */
-	  error0 =
-	    (vlib_buffer_length_in_chain (vm, p0) >
-	     adj0[0].
-	     rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
-	     error0);
-	  error1 =
-	    (vlib_buffer_length_in_chain (vm, p1) >
-	     adj1[0].
-	     rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
-	     error1);
+	  ip6_mtu_check (p0, clib_net_to_host_u16 (ip0->payload_length) +
+			 sizeof (ip6_header_t),
+			 adj0[0].rewrite_header.max_l3_packet_bytes,
+			 &next0, &error0);
+	  ip6_mtu_check (p1, clib_net_to_host_u16 (ip1->payload_length) +
+			 sizeof (ip6_header_t),
+			 adj1[0].rewrite_header.max_l3_packet_bytes,
+			 &next1, &error1);
 
 	  /* Don't adjust the buffer for hop count issue; icmp-error node
 	   * wants to see the IP headerr */
@@ -1849,14 +1860,13 @@
 	    }
 
 	  /* Check MTU of outgoing interface. */
-	  error0 =
-	    (vlib_buffer_length_in_chain (vm, p0) >
-	     adj0[0].
-	     rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
-	     error0);
+	  ip6_mtu_check (p0, clib_net_to_host_u16 (ip0->payload_length) +
+			 sizeof (ip6_header_t),
+			 adj0[0].rewrite_header.max_l3_packet_bytes,
+			 &next0, &error0);
 
 	  /* Don't adjust the buffer for hop count issue; icmp-error node
-	   * wants to see the IP headerr */
+	   * wants to see the IP header */
 	  if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
 	    {
 	      p0->current_data -= rw_len0;
diff --git a/test/test_mtu.py b/test/test_mtu.py
index abf0c94..cef0ec0 100644
--- a/test/test_mtu.py
+++ b/test/test_mtu.py
@@ -165,16 +165,22 @@
         self.validate(reass_pkt, p4_reply)
         '''
         # Reset MTU
-        self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, current_mtu)
+        self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index,
+                                       current_mtu + mtu_offset)
 
-    @unittest.skip("Enable when IPv6 fragmentation is added")
     def test_ip6_mtu(self):
         """ IP6 MTU test """
 
+        #
+        # TODO: Link MTU is 216 bytes 'off'. Fix when L3 MTU patches committed
+        #
+        mtu_offset = 216
+        current_mtu = self.get_mtu(self.pg1.sw_if_index)
+        current_mtu -= mtu_offset
+
         p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
         p_ip6 = IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6)
 
-        current_mtu = self.get_mtu(self.pg1.sw_if_index)
         p_payload = UDP(sport=1234, dport=1234) / self.payload(
             current_mtu - 40 - 8)
 
@@ -186,8 +192,8 @@
             self.validate(p[1], p6_reply)
 
         # MTU (only checked on encap)
-        self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, 1280)
-        self.assertEqual(1280, self.get_mtu(self.pg1.sw_if_index))
+        self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, 1280 + mtu_offset)
+        self.assertEqual(1280, self.get_mtu(self.pg1.sw_if_index) - mtu_offset)
 
         # Should fail. Too large MTU
         p_icmp6 = ICMPv6PacketTooBig(mtu=1280, cksum=0x4c7a)