ip: Fragmentation fixes
Type: fix if the packet is about to be fragmented, then don't call any of the actions that expect the rewrite to have been written. 1) don't double count packets thru the adjacency (original & fragments) 2) don't double decrement the TTL for fragments 3) return to ip4-midchain post ip-frag if that's where we started. 4) only run midchain/mcast fixups if not fragmenting (if no errors) Change-Id: Ib2866787a42713ee5871b87b597d8f74b901044b Signed-off-by: Neale Ranns <nranns@cisco.com>
This commit is contained in:
@@ -62,7 +62,6 @@ calc_checksums (vlib_main_t * vm, vlib_buffer_t * b)
|
||||
|
||||
if (is_ip4)
|
||||
{
|
||||
ip4 = (ip4_header_t *) (b->data + vnet_buffer (b)->l3_hdr_offset);
|
||||
if (b->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM)
|
||||
ip4->checksum = ip4_header_checksum (ip4);
|
||||
if (b->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM)
|
||||
@@ -71,7 +70,10 @@ calc_checksums (vlib_main_t * vm, vlib_buffer_t * b)
|
||||
th->checksum = ip4_tcp_udp_compute_checksum (vm, b, ip4);
|
||||
}
|
||||
if (b->flags & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM)
|
||||
uh->checksum = ip4_tcp_udp_compute_checksum (vm, b, ip4);
|
||||
{
|
||||
uh->checksum = 0;
|
||||
uh->checksum = ip4_tcp_udp_compute_checksum (vm, b, ip4);
|
||||
}
|
||||
}
|
||||
if (is_ip6)
|
||||
{
|
||||
|
||||
+124
-99
File diff suppressed because it is too large
Load Diff
@@ -908,7 +908,7 @@ format_ip6_rewrite_trace (u8 * s, va_list * args)
|
||||
s = format (s, "\n%U%U",
|
||||
format_white_space, indent,
|
||||
format_ip_adjacency_packet_data,
|
||||
t->adj_index, t->packet_data, sizeof (t->packet_data));
|
||||
t->packet_data, sizeof (t->packet_data));
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -200,6 +200,17 @@ ip4_frag_do_fragment (vlib_main_t * vm, u32 from_bi, u32 ** buffer,
|
||||
clib_memcpy_fast (to_b->data, org_from_packet, sizeof (ip4_header_t));
|
||||
to_ip4 = vlib_buffer_get_current (to_b);
|
||||
to_data = (void *) (to_ip4 + 1);
|
||||
vnet_buffer (to_b)->l3_hdr_offset = to_b->current_data;
|
||||
to_b->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
|
||||
|
||||
if (from_b->flags & VNET_BUFFER_F_L4_HDR_OFFSET_VALID)
|
||||
{
|
||||
vnet_buffer (to_b)->l4_hdr_offset =
|
||||
(vnet_buffer (to_b)->l3_hdr_offset +
|
||||
(vnet_buffer (from_b)->l4_hdr_offset -
|
||||
vnet_buffer (from_b)->l3_hdr_offset));
|
||||
to_b->flags |= VNET_BUFFER_F_L4_HDR_OFFSET_VALID;
|
||||
}
|
||||
|
||||
/* Spin through from buffers filling up the to buffer */
|
||||
u16 left_in_to_buffer = len, to_ptr = 0;
|
||||
@@ -232,6 +243,7 @@ ip4_frag_do_fragment (vlib_main_t * vm, u32 from_bi, u32 ** buffer,
|
||||
}
|
||||
|
||||
to_b->current_length = len + sizeof (ip4_header_t);
|
||||
to_b->flags |= VNET_BUFFER_F_IS_IP4;
|
||||
|
||||
to_ip4->fragment_id = ip_frag_id;
|
||||
to_ip4->flags_and_fragment_offset =
|
||||
@@ -241,6 +253,9 @@ ip4_frag_do_fragment (vlib_main_t * vm, u32 from_bi, u32 ** buffer,
|
||||
to_ip4->length = clib_host_to_net_u16 (len + sizeof (ip4_header_t));
|
||||
to_ip4->checksum = ip4_header_checksum (to_ip4);
|
||||
|
||||
/* we've just done the IP checksum .. */
|
||||
to_b->flags &= ~VNET_BUFFER_F_OFFLOAD_IP_CKSUM;
|
||||
|
||||
if (vnet_buffer (org_from_b)->ip_frag.flags & IP_FRAG_FLAG_IP4_HEADER)
|
||||
{
|
||||
/* Encapsulating ipv4 header */
|
||||
@@ -482,6 +497,19 @@ ip6_frag_do_fragment (vlib_main_t * vm, u32 from_bi, u32 ** buffer,
|
||||
to_frag_hdr = (ip6_frag_hdr_t *) (to_ip6 + 1);
|
||||
to_data = (void *) (to_frag_hdr + 1);
|
||||
|
||||
vnet_buffer (to_b)->l3_hdr_offset = to_b->current_data;
|
||||
to_b->flags |= VNET_BUFFER_F_L3_HDR_OFFSET_VALID;
|
||||
|
||||
if (from_b->flags & VNET_BUFFER_F_L4_HDR_OFFSET_VALID)
|
||||
{
|
||||
vnet_buffer (to_b)->l4_hdr_offset =
|
||||
(vnet_buffer (to_b)->l3_hdr_offset +
|
||||
(vnet_buffer (from_b)->l4_hdr_offset -
|
||||
vnet_buffer (from_b)->l3_hdr_offset));
|
||||
to_b->flags |= VNET_BUFFER_F_L4_HDR_OFFSET_VALID;
|
||||
}
|
||||
to_b->flags |= VNET_BUFFER_F_IS_IP6;
|
||||
|
||||
/* Spin through from buffers filling up the to buffer */
|
||||
u16 left_in_to_buffer = len, to_ptr = 0;
|
||||
while (1)
|
||||
@@ -551,6 +579,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_REWRITE_MIDCHAIN] = "ip4-midchain",
|
||||
[IP4_FRAG_NEXT_IP4_LOOKUP] = "ip4-lookup",
|
||||
[IP4_FRAG_NEXT_IP6_LOOKUP] = "ip6-lookup",
|
||||
[IP4_FRAG_NEXT_MPLS_OUTPUT] = "mpls-output",
|
||||
@@ -574,6 +603,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_IP6_REWRITE_MIDCHAIN] = "ip6-midchain",
|
||||
[IP6_FRAG_NEXT_IP4_LOOKUP] = "ip4-lookup",
|
||||
[IP6_FRAG_NEXT_IP6_LOOKUP] = "ip6-lookup",
|
||||
[IP6_FRAG_NEXT_MPLS_OUTPUT] = "mpls-output",
|
||||
|
||||
@@ -50,6 +50,7 @@ extern vlib_node_registration_t ip6_frag_node;
|
||||
typedef enum
|
||||
{
|
||||
IP4_FRAG_NEXT_IP4_REWRITE,
|
||||
IP4_FRAG_NEXT_IP4_REWRITE_MIDCHAIN,
|
||||
IP4_FRAG_NEXT_IP4_LOOKUP,
|
||||
IP4_FRAG_NEXT_IP6_LOOKUP,
|
||||
IP4_FRAG_NEXT_MPLS_OUTPUT,
|
||||
@@ -63,6 +64,7 @@ typedef enum
|
||||
IP6_FRAG_NEXT_IP4_LOOKUP,
|
||||
IP6_FRAG_NEXT_IP6_LOOKUP,
|
||||
IP6_FRAG_NEXT_IP6_REWRITE,
|
||||
IP6_FRAG_NEXT_IP6_REWRITE_MIDCHAIN,
|
||||
IP6_FRAG_NEXT_MPLS_OUTPUT,
|
||||
IP6_FRAG_NEXT_DROP,
|
||||
IP6_FRAG_N_NEXT
|
||||
|
||||
+1
-18
@@ -258,27 +258,10 @@ format_ip_flow_hash_config (u8 * s, va_list * args)
|
||||
u8 *
|
||||
format_ip_adjacency_packet_data (u8 * s, va_list * args)
|
||||
{
|
||||
u32 adj_index = va_arg (*args, u32);
|
||||
u8 *packet_data = va_arg (*args, u8 *);
|
||||
u32 n_packet_data_bytes = va_arg (*args, u32);
|
||||
ip_adjacency_t *adj;
|
||||
|
||||
if (!adj_is_valid (adj_index))
|
||||
return format (s, "<invalid adjacency>");
|
||||
|
||||
adj = adj_get (adj_index);
|
||||
|
||||
switch (adj->lookup_next_index)
|
||||
{
|
||||
case IP_LOOKUP_NEXT_REWRITE:
|
||||
case IP_LOOKUP_NEXT_MCAST:
|
||||
s =
|
||||
format (s, "%U", format_hex_bytes, packet_data, n_packet_data_bytes);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
s = format (s, "%U", format_hex_bytes, packet_data, n_packet_data_bytes);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpMRoute, \
|
||||
from vpp_ip import VppIpAddress
|
||||
from vpp_sub_interface import VppSubInterface, VppDot1QSubint, VppDot1ADSubint
|
||||
from vpp_papi import VppEnum
|
||||
from vpp_neighbor import VppNeighbor
|
||||
|
||||
NUM_PKTS = 67
|
||||
|
||||
@@ -1918,12 +1919,19 @@ class TestIPv4Frag(VppTestCase):
|
||||
def test_frag_large_packets(self):
|
||||
""" Fragmentation of large packets """
|
||||
|
||||
self.vapi.cli("adjacency counters enable")
|
||||
|
||||
p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
|
||||
IP(src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4) /
|
||||
UDP(sport=1234, dport=5678) / Raw())
|
||||
self.extend_packet(p, 6000, "abcde")
|
||||
saved_payload = p[Raw].load
|
||||
|
||||
nbr = VppNeighbor(self,
|
||||
self.dst_if.sw_if_index,
|
||||
self.dst_if.remote_mac,
|
||||
self.dst_if.remote_ip4).add_vpp_config()
|
||||
|
||||
# Force fragmentation by setting MTU of output interface
|
||||
# lower than packet size
|
||||
self.vapi.sw_interface_set_mtu(self.dst_if.sw_if_index,
|
||||
@@ -1937,6 +1945,9 @@ class TestIPv4Frag(VppTestCase):
|
||||
# cannot be larger then VPP buffer size (which is 2048)
|
||||
packets = self.dst_if.get_capture(3)
|
||||
|
||||
# we should show 3 packets thru the neighbor
|
||||
self.assertEqual(3, nbr.get_stats()['packets'])
|
||||
|
||||
# Assume VPP sends the fragments in order
|
||||
payload = b''
|
||||
for p in packets:
|
||||
|
||||
+21
-4
@@ -2,7 +2,7 @@
|
||||
"""IP{4,6} over IP{v,6} tunnel functional tests"""
|
||||
|
||||
import unittest
|
||||
from scapy.layers.inet6 import IPv6, Ether, IP, UDP, IPv6ExtHdrFragment
|
||||
from scapy.layers.inet6 import IPv6, Ether, IP, UDP, IPv6ExtHdrFragment, Raw
|
||||
from scapy.all import fragment, fragment6, RandShort, defragment6
|
||||
from framework import VppTestCase, VppTestRunner
|
||||
from vpp_ip import DpoProto
|
||||
@@ -81,7 +81,7 @@ class TestIPIP(VppTestCase):
|
||||
p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
|
||||
p_ip6 = IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=42)
|
||||
p_ip4 = IP(src="1.2.3.4", dst="130.67.0.1", tos=42)
|
||||
p_payload = UDP(sport=1234, dport=1234)
|
||||
p_payload = UDP(sport=1234, dport=1234) / Raw(b'X' * 100)
|
||||
|
||||
# IPv4 transport
|
||||
rv = ipip_add_tunnel(self,
|
||||
@@ -121,6 +121,7 @@ class TestIPIP(VppTestCase):
|
||||
rx = self.send_and_expect(self.pg0, p6 * 10, self.pg1)
|
||||
for p in rx:
|
||||
self.validate(p[1], p6_reply)
|
||||
self.assert_packet_checksums_valid(p)
|
||||
|
||||
# IPv4 in to IPv4 tunnel
|
||||
p4 = (p_ether / p_ip4 / p_payload)
|
||||
@@ -134,6 +135,7 @@ class TestIPIP(VppTestCase):
|
||||
rx = self.send_and_expect(self.pg0, p4 * 10, self.pg1)
|
||||
for p in rx:
|
||||
self.validate(p[1], p4_reply)
|
||||
self.assert_packet_checksums_valid(p)
|
||||
|
||||
# Decapsulation
|
||||
p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
|
||||
@@ -147,6 +149,7 @@ class TestIPIP(VppTestCase):
|
||||
rx = self.send_and_expect(self.pg1, p4 * 10, self.pg0)
|
||||
for p in rx:
|
||||
self.validate(p[1], p4_reply)
|
||||
self.assert_packet_checksums_valid(p)
|
||||
|
||||
err = self.statistics.get_err_counter(
|
||||
'/err/ipip4-input/packets decapsulated')
|
||||
@@ -161,6 +164,7 @@ class TestIPIP(VppTestCase):
|
||||
rx = self.send_and_expect(self.pg1, p6 * 10, self.pg0)
|
||||
for p in rx:
|
||||
self.validate(p[1], p6_reply)
|
||||
self.assert_packet_checksums_valid(p)
|
||||
|
||||
err = self.statistics.get_err_counter(
|
||||
'/err/ipip4-input/packets decapsulated')
|
||||
@@ -222,7 +226,6 @@ class TestIPIP(VppTestCase):
|
||||
self.pg_start()
|
||||
rx = self.pg0.get_capture(6)
|
||||
reass_pkt = reassemble4(rx)
|
||||
p4_reply.ttl -= 1
|
||||
p4_reply.id = 256
|
||||
self.validate(reass_pkt, p4_reply)
|
||||
|
||||
@@ -233,10 +236,24 @@ class TestIPIP(VppTestCase):
|
||||
self.pg_start()
|
||||
rx = self.pg0.get_capture(2)
|
||||
reass_pkt = reassemble4(rx)
|
||||
p4_reply.ttl -= 1
|
||||
p4_reply.id = 512
|
||||
self.validate(reass_pkt, p4_reply)
|
||||
|
||||
# send large packets through the tunnel, expect them to be fragmented
|
||||
self.vapi.sw_interface_set_mtu(sw_if_index, [600, 0, 0, 0])
|
||||
|
||||
p4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
|
||||
IP(src="1.2.3.4", dst="130.67.0.1", tos=42) /
|
||||
UDP(sport=1234, dport=1234) / Raw(b'Q' * 1000))
|
||||
rx = self.send_and_expect(self.pg0, p4 * 15, self.pg1, 30)
|
||||
inners = []
|
||||
for p in rx:
|
||||
inners.append(p[IP].payload)
|
||||
reass_pkt = reassemble4(inners)
|
||||
for p in reass_pkt:
|
||||
self.assert_packet_checksums_valid(p)
|
||||
self.assertEqual(p[IP].ttl, 63)
|
||||
|
||||
def test_ipip_create(self):
|
||||
""" ipip create / delete interface test """
|
||||
rv = ipip_add_tunnel(self, '1.2.3.4', '2.3.4.5')
|
||||
|
||||
+1
-2
@@ -101,7 +101,6 @@ class TestMTU(VppTestCase):
|
||||
dst=self.pg0.remote_ip4,
|
||||
ttl=254, len=576, id=0) /
|
||||
p_icmp4 / p_ip4 / p_payload)
|
||||
icmp4_reply[1].ttl -= 1
|
||||
n = icmp4_reply.__class__(icmp4_reply)
|
||||
s = bytes(icmp4_reply)
|
||||
icmp4_reply = s[0:576]
|
||||
@@ -118,7 +117,7 @@ class TestMTU(VppTestCase):
|
||||
p4 = p_ether / p_ip4 / p_payload
|
||||
p4.flags = 0
|
||||
p4_reply = p_ip4 / p_payload
|
||||
p4_reply.ttl = 62 # check this
|
||||
p4_reply.ttl = p_ip4.ttl - 1
|
||||
p4_reply.flags = 0
|
||||
p4_reply.id = 256
|
||||
self.pg_enable_capture()
|
||||
|
||||
@@ -58,6 +58,7 @@ class VppNeighbor(VppObject):
|
||||
flags=self.flags)
|
||||
self.stats_index = r.stats_index
|
||||
self._test.registry.register(self, self._test.logger)
|
||||
return self
|
||||
|
||||
def remove_vpp_config(self):
|
||||
self._test.vapi.ip_neighbor_add_del(
|
||||
|
||||
Reference in New Issue
Block a user