VPP-1392: VXLAN fails with IP fragmentation 97/14297/3
authorOle Troan <ot@cisco.com>
Thu, 16 Aug 2018 20:08:49 +0000 (22:08 +0200)
committerJohn Lo <loj@cisco.com>
Fri, 17 Aug 2018 21:38:47 +0000 (21:38 +0000)
Not only is it wasteful to send all fragments back through ip4-lookup, but
it doesn't work with tunnel mechanisms that don't have IP enabled on their
payload side.

Change-Id: Ic92d95982dddaa70969a2a6ea2f98edec7614425
Signed-off-by: Ole Troan <ot@cisco.com>
src/vnet/ip/ip4_forward.c
src/vnet/ip/ip6_forward.c
src/vnet/ip/ip_frag.c
src/vnet/ip/ip_frag.h
test/test_vxlan.py

index 358e666..48442a0 100644 (file)
@@ -2116,7 +2116,7 @@ ip4_mtu_check (vlib_buffer_t * b, u16 packet_len,
        {
          /* IP fragmentation */
          ip_frag_set_vnet_buffer (b, 0, adj_packet_bytes,
        {
          /* IP fragmentation */
          ip_frag_set_vnet_buffer (b, 0, adj_packet_bytes,
-                                  IP4_FRAG_NEXT_IP4_LOOKUP, 0);
+                                  IP4_FRAG_NEXT_IP4_REWRITE, 0);
          *next = IP4_REWRITE_NEXT_FRAGMENT;
        }
     }
          *next = IP4_REWRITE_NEXT_FRAGMENT;
        }
     }
index efd5e0d..5abbba5 100644 (file)
@@ -1567,7 +1567,7 @@ ip6_mtu_check (vlib_buffer_t * b, u16 packet_bytes,
        {
          /* IP fragmentation */
          ip_frag_set_vnet_buffer (b, 0, adj_packet_bytes,
        {
          /* IP fragmentation */
          ip_frag_set_vnet_buffer (b, 0, adj_packet_bytes,
-                                  IP6_FRAG_NEXT_IP6_LOOKUP, 0);
+                                  IP6_FRAG_NEXT_IP6_REWRITE, 0);
          *next = IP6_REWRITE_NEXT_FRAGMENT;
        }
       else
          *next = IP6_REWRITE_NEXT_FRAGMENT;
        }
       else
index 6309487..eb9bb4a 100644 (file)
@@ -602,6 +602,7 @@ VLIB_REGISTER_NODE (ip4_frag_node) = {
 
   .n_next_nodes = IP4_FRAG_N_NEXT,
   .next_nodes = {
 
   .n_next_nodes = IP4_FRAG_N_NEXT,
   .next_nodes = {
+    [IP4_FRAG_NEXT_IP4_REWRITE] = "ip4-rewrite",
     [IP4_FRAG_NEXT_IP4_LOOKUP] = "ip4-lookup",
     [IP4_FRAG_NEXT_IP6_LOOKUP] = "ip6-lookup",
     [IP4_FRAG_NEXT_ICMP_ERROR] = "ip4-icmp-error",
     [IP4_FRAG_NEXT_IP4_LOOKUP] = "ip4-lookup",
     [IP4_FRAG_NEXT_IP6_LOOKUP] = "ip6-lookup",
     [IP4_FRAG_NEXT_ICMP_ERROR] = "ip4-icmp-error",
@@ -623,6 +624,7 @@ VLIB_REGISTER_NODE (ip6_frag_node) = {
 
   .n_next_nodes = IP6_FRAG_N_NEXT,
   .next_nodes = {
 
   .n_next_nodes = IP6_FRAG_N_NEXT,
   .next_nodes = {
+    [IP6_FRAG_NEXT_IP6_REWRITE] = "ip6-rewrite",
     [IP6_FRAG_NEXT_IP4_LOOKUP] = "ip4-lookup",
     [IP6_FRAG_NEXT_IP6_LOOKUP] = "ip6-lookup",
     [IP6_FRAG_NEXT_DROP] = "ip6-drop"
     [IP6_FRAG_NEXT_IP4_LOOKUP] = "ip4-lookup",
     [IP6_FRAG_NEXT_IP6_LOOKUP] = "ip6-lookup",
     [IP6_FRAG_NEXT_DROP] = "ip6-drop"
index 9d19299..ef5eb4c 100644 (file)
@@ -48,6 +48,7 @@ extern vlib_node_registration_t ip6_frag_node;
 
 typedef enum
 {
 
 typedef enum
 {
+  IP4_FRAG_NEXT_IP4_REWRITE,
   IP4_FRAG_NEXT_IP4_LOOKUP,
   IP4_FRAG_NEXT_IP6_LOOKUP,
   IP4_FRAG_NEXT_ICMP_ERROR,
   IP4_FRAG_NEXT_IP4_LOOKUP,
   IP4_FRAG_NEXT_IP6_LOOKUP,
   IP4_FRAG_NEXT_ICMP_ERROR,
@@ -59,6 +60,7 @@ typedef enum
 {
   IP6_FRAG_NEXT_IP4_LOOKUP,
   IP6_FRAG_NEXT_IP6_LOOKUP,
 {
   IP6_FRAG_NEXT_IP4_LOOKUP,
   IP6_FRAG_NEXT_IP6_LOOKUP,
+  IP6_FRAG_NEXT_IP6_REWRITE,
   IP6_FRAG_NEXT_DROP,
   IP6_FRAG_N_NEXT
 } ip6_frag_next_t;
   IP6_FRAG_NEXT_DROP,
   IP6_FRAG_N_NEXT
 } ip6_frag_next_t;
index 1411dd6..3c824b5 100644 (file)
@@ -6,11 +6,27 @@ import unittest
 from framework import VppTestCase, VppTestRunner
 from template_bd import BridgeDomain
 
 from framework import VppTestCase, VppTestRunner
 from template_bd import BridgeDomain
 
-from scapy.layers.l2 import Ether
+from scapy.layers.l2 import Ether, Raw
 from scapy.layers.inet import IP, UDP
 from scapy.layers.vxlan import VXLAN
 from scapy.utils import atol
 
 from scapy.layers.inet import IP, UDP
 from scapy.layers.vxlan import VXLAN
 from scapy.utils import atol
 
+import StringIO
+
+
+def reassemble(listoffragments):
+    buffer = StringIO.StringIO()
+    first = listoffragments[0]
+    buffer.seek(20)
+    for pkt in listoffragments:
+        buffer.seek(pkt[IP].frag*8)
+        buffer.write(pkt[IP].payload)
+    first.len = len(buffer.getvalue()) + 20
+    first.flags = 0
+    del(first.chksum)
+    header = str(first[IP])[:20]
+    return first[IP].__class__(header + buffer.getvalue())
+
 
 class TestVxlan(BridgeDomain, VppTestCase):
     """ VXLAN Test Case """
 
 class TestVxlan(BridgeDomain, VppTestCase):
     """ VXLAN Test Case """
@@ -222,6 +238,35 @@ class TestVxlan(BridgeDomain, VppTestCase):
             super(TestVxlan, cls).tearDownClass()
             raise
 
             super(TestVxlan, cls).tearDownClass()
             raise
 
+    def test_encap_big_packet(self):
+        """ Encapsulation test send big frame from pg1
+        Verify receipt of encapsulated frames on pg0
+        """
+
+        self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [1500, 0, 0, 0])
+
+        frame = (Ether(src='00:00:00:00:00:02', dst='00:00:00:00:00:01') /
+                 IP(src='4.3.2.1', dst='1.2.3.4') /
+                 UDP(sport=20000, dport=10000) /
+                 Raw('\xa5' * 1450))
+
+        self.pg1.add_stream([frame])
+
+        self.pg0.enable_capture()
+
+        self.pg_start()
+
+        # Pick first received frame and check if it's correctly encapsulated.
+        out = self.pg0.get_capture(2)
+        ether = out[0]
+        pkt = reassemble(out)
+        pkt = ether / pkt
+        self.check_encapsulation(pkt, self.single_tunnel_bd)
+
+        payload = self.decapsulate(pkt)
+        # TODO: Scapy bug?
+        # self.assert_eq_pkts(payload, frame)
+
     # Method to define VPP actions before tear down of the test case.
     #  Overrides tearDown method in VppTestCase class.
     #  @param self The object pointer.
     # Method to define VPP actions before tear down of the test case.
     #  Overrides tearDown method in VppTestCase class.
     #  @param self The object pointer.