ip: translate fragmented icmp to fragmented icmp6 14/24714/2
authorAlexander Chernavin <achernavin@netgate.com>
Fri, 31 Jan 2020 14:19:49 +0000 (09:19 -0500)
committerOle Trøan <otroan@employees.org>
Tue, 4 Feb 2020 09:31:44 +0000 (09:31 +0000)
The first translated ICMPv6 packet of a fragmented ICMP message does
not have a IPv6 fragment header. All subsequent have.

With this commit, add a IPv6 fragment header to the first translated
ICMPv6 packet.

Type: fix

Change-Id: Id89409ce7273cbeed801e2e18a09d3e7c3c4e4bc
Signed-off-by: Alexander Chernavin <achernavin@netgate.com>
src/plugins/map/test/test_map.py
src/vnet/ip/ip4_to_ip6.h

index 845d1d3..123fb54 100644 (file)
@@ -12,7 +12,8 @@ import scapy.compat
 from scapy.layers.l2 import Ether
 from scapy.packet import Raw
 from scapy.layers.inet import IP, UDP, ICMP, TCP
 from scapy.layers.l2 import Ether
 from scapy.packet import Raw
 from scapy.layers.inet import IP, UDP, ICMP, TCP
-from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded, IPv6ExtHdrFragment
+from scapy.layers.inet6 import IPv6, ICMPv6TimeExceeded, IPv6ExtHdrFragment, \
+    ICMPv6EchoRequest
 
 
 class TestMAP(VppTestCase):
 
 
 class TestMAP(VppTestCase):
@@ -597,7 +598,7 @@ class TestMAP(VppTestCase):
         p6 = (p_ether6 / p_ip6 / payload)
         self.send_and_assert_no_replies(self.pg1, p6*1)
 
         p6 = (p_ether6 / p_ip6 / payload)
         self.send_and_assert_no_replies(self.pg1, p6*1)
 
-        # Packet fragmentation
+        # UDP packet fragmentation
         payload_len = 1453
         payload = UDP(sport=40000, dport=4000) / self.payload(payload_len)
         p4 = (p_ether / p_ip4 / payload)
         payload_len = 1453
         payload = UDP(sport=40000, dport=4000) / self.payload(payload_len)
         p4 = (p_ether / p_ip4 / payload)
@@ -613,7 +614,7 @@ class TestMAP(VppTestCase):
 
         self.validate_frag_payload_len(rx, UDP, payload_len)
 
 
         self.validate_frag_payload_len(rx, UDP, payload_len)
 
-        # Packet fragmentation send fragments
+        # UDP packet fragmentation send fragments
         payload = UDP(sport=40000, dport=4000) / self.payload(payload_len)
         p4 = (p_ether / p_ip4 / payload)
         frags = fragment_rfc791(p4, fragsize=1000)
         payload = UDP(sport=40000, dport=4000) / self.payload(payload_len)
         p4 = (p_ether / p_ip4 / payload)
         frags = fragment_rfc791(p4, fragsize=1000)
@@ -627,10 +628,34 @@ class TestMAP(VppTestCase):
 
         self.validate_frag_payload_len(rx, UDP, payload_len)
 
 
         self.validate_frag_payload_len(rx, UDP, payload_len)
 
-        # reass_pkt = reassemble(rx)
-        # p4_reply.ttl -= 1
-        # p4_reply.id = 256
-        # self.validate(reass_pkt, p4_reply)
+        # ICMP packet fragmentation
+        payload = ICMP(id=6529) / self.payload(payload_len)
+        p4 = (p_ether / p_ip4 / payload)
+        self.pg_enable_capture()
+        self.pg0.add_stream(p4)
+        self.pg_start()
+        rx = self.pg1.get_capture(2)
+
+        p_ip6_translated = IPv6(src='1234:5678:90ab:cdef:ac:1001:200:0',
+                                dst='2001:db8:160::c0a8:1:6')
+        for p in rx:
+            self.validate_frag(p, p_ip6_translated)
+
+        self.validate_frag_payload_len(rx, ICMPv6EchoRequest, payload_len)
+
+        # ICMP packet fragmentation send fragments
+        payload = ICMP(id=6529) / self.payload(payload_len)
+        p4 = (p_ether / p_ip4 / payload)
+        frags = fragment_rfc791(p4, fragsize=1000)
+        self.pg_enable_capture()
+        self.pg0.add_stream(frags)
+        self.pg_start()
+        rx = self.pg1.get_capture(2)
+
+        for p in rx:
+            self.validate_frag(p, p_ip6_translated)
+
+        self.validate_frag_payload_len(rx, ICMPv6EchoRequest, payload_len)
 
         # TCP MSS clamping
         self.vapi.map_param_set_tcp(1300)
 
         # TCP MSS clamping
         self.vapi.map_param_set_tcp(1300)
index e78985b..a6d87f1 100644 (file)
@@ -226,8 +226,10 @@ icmp_to_icmp6 (vlib_buffer_t * p, ip4_to_ip6_set_fn_t fn, void *ctx,
   icmp46_header_t *icmp;
   ip_csum_t csum;
   ip6_frag_hdr_t *inner_frag;
   icmp46_header_t *icmp;
   ip_csum_t csum;
   ip6_frag_hdr_t *inner_frag;
+  ip6_frag_hdr_t *outer_frag= NULL;
   u32 inner_frag_id;
   u32 inner_frag_offset;
   u32 inner_frag_id;
   u32 inner_frag_offset;
+  u32 outer_frag_id;
   u8 inner_frag_more;
   u16 *inner_L4_checksum = 0;
   int rv;
   u8 inner_frag_more;
   u16 *inner_L4_checksum = 0;
   int rv;
@@ -397,8 +399,20 @@ icmp_to_icmp6 (vlib_buffer_t * p, ip4_to_ip6_set_fn_t fn, void *ctx,
     }
   else
     {
     }
   else
     {
-      vlib_buffer_advance (p, sizeof (*ip4) - sizeof (*ip6));
-      ip6 = vlib_buffer_get_current (p);
+      if (PREDICT_FALSE (ip4->flags_and_fragment_offset &
+                        clib_host_to_net_u16 (IP4_HEADER_FLAG_MORE_FRAGMENTS)))
+       {
+         vlib_buffer_advance (p, sizeof (*ip4) - sizeof (*ip6) -
+                              sizeof (*outer_frag));
+         ip6 = vlib_buffer_get_current (p);
+         outer_frag = (ip6_frag_hdr_t *) (ip6 + 1);
+         outer_frag_id = frag_id_4to6 (ip4->fragment_id);
+       }
+      else
+       {
+         vlib_buffer_advance (p, sizeof (*ip4) - sizeof (*ip6));
+         ip6 = vlib_buffer_get_current (p);
+       }
       ip6->payload_length =
        clib_host_to_net_u16 (clib_net_to_host_u16 (ip4->length) -
                              sizeof (*ip4));
       ip6->payload_length =
        clib_host_to_net_u16 (clib_net_to_host_u16 (ip4->length) -
                              sizeof (*ip4));
@@ -414,6 +428,17 @@ icmp_to_icmp6 (vlib_buffer_t * p, ip4_to_ip6_set_fn_t fn, void *ctx,
   if ((rv = fn (p, ip4, ip6, ctx)) != 0)
     return rv;
 
   if ((rv = fn (p, ip4, ip6, ctx)) != 0)
     return rv;
 
+  if (PREDICT_FALSE (outer_frag != NULL))
+    {
+      outer_frag->next_hdr = ip6->protocol;
+      outer_frag->identification = outer_frag_id;
+      outer_frag->rsv = 0;
+      outer_frag->fragment_offset_and_more = ip6_frag_hdr_offset_and_more (0, 1);
+      ip6->protocol = IP_PROTOCOL_IPV6_FRAGMENTATION;
+      ip6->payload_length = u16_net_add (ip6->payload_length,
+                                        sizeof (*outer_frag));
+    }
+
   //Truncate when ICMPv6 error message exceeds the minimal IPv6 MTU
   if (p->current_length > 1280 && icmp->type < 128)
     {
   //Truncate when ICMPv6 error message exceeds the minimal IPv6 MTU
   if (p->current_length > 1280 && icmp->type < 128)
     {