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,
-                                  IP4_FRAG_NEXT_IP4_LOOKUP, 0);
+                                  IP4_FRAG_NEXT_IP4_REWRITE, 0);
          *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,
-                                  IP6_FRAG_NEXT_IP6_LOOKUP, 0);
+                                  IP6_FRAG_NEXT_IP6_REWRITE, 0);
          *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 = {
+    [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",
@@ -623,6 +624,7 @@ VLIB_REGISTER_NODE (ip6_frag_node) = {
 
   .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"
index 9d19299..ef5eb4c 100644 (file)
@@ -48,6 +48,7 @@ extern vlib_node_registration_t ip6_frag_node;
 
 typedef enum
 {
+  IP4_FRAG_NEXT_IP4_REWRITE,
   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_IP6_REWRITE,
   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 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
 
+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 """
@@ -222,6 +238,35 @@ class TestVxlan(BridgeDomain, VppTestCase):
             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.