gso: add support for IP-IP

Type: feature

Change-Id: I37752af8496e0042a1da91124f3d94216b39ff11
Signed-off-by: Mohsin Kazmi <sykazmi@cisco.com>
This commit is contained in:
Mohsin Kazmi
2020-04-23 17:59:49 +02:00
committed by Neale Ranns
parent 5ec6a4ea44
commit 84f91fa9c5
8 changed files with 465 additions and 144 deletions

View File

@ -168,13 +168,15 @@ virtio_free_used_device_desc (vlib_main_t * vm, virtio_vring_t * vring,
}
static_always_inline void
set_checksum_offsets (vlib_buffer_t * b, struct virtio_net_hdr_v1 *hdr)
set_checksum_offsets (vlib_buffer_t * b, struct virtio_net_hdr_v1 *hdr,
int is_l2)
{
if (b->flags & VNET_BUFFER_F_IS_IP4)
{
ip4_header_t *ip4;
generic_header_offset_t gho = { 0 };
vnet_generic_header_offset_parser (b, &gho);
vnet_generic_header_offset_parser (b, &gho, is_l2, 1 /* ip4 */ ,
0 /* ip6 */ );
hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
hdr->csum_start = gho.l4_hdr_offset; // 0x22;
if (b->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM)
@ -198,7 +200,8 @@ set_checksum_offsets (vlib_buffer_t * b, struct virtio_net_hdr_v1 *hdr)
else if (b->flags & VNET_BUFFER_F_IS_IP6)
{
generic_header_offset_t gho = { 0 };
vnet_generic_header_offset_parser (b, &gho);
vnet_generic_header_offset_parser (b, &gho, is_l2, 0 /* ip4 */ ,
1 /* ip6 */ );
hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
hdr->csum_start = gho.l4_hdr_offset; // 0x36;
if (b->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM)
@ -213,13 +216,14 @@ set_checksum_offsets (vlib_buffer_t * b, struct virtio_net_hdr_v1 *hdr)
}
static_always_inline void
set_gso_offsets (vlib_buffer_t * b, struct virtio_net_hdr_v1 *hdr)
set_gso_offsets (vlib_buffer_t * b, struct virtio_net_hdr_v1 *hdr, int is_l2)
{
if (b->flags & VNET_BUFFER_F_IS_IP4)
{
ip4_header_t *ip4;
generic_header_offset_t gho = { 0 };
vnet_generic_header_offset_parser (b, &gho);
vnet_generic_header_offset_parser (b, &gho, is_l2, 1 /* ip4 */ ,
0 /* ip6 */ );
hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
hdr->gso_size = vnet_buffer2 (b)->gso_size;
hdr->hdr_len = gho.hdr_sz;
@ -238,7 +242,8 @@ set_gso_offsets (vlib_buffer_t * b, struct virtio_net_hdr_v1 *hdr)
else if (b->flags & VNET_BUFFER_F_IS_IP6)
{
generic_header_offset_t gho = { 0 };
vnet_generic_header_offset_parser (b, &gho);
vnet_generic_header_offset_parser (b, &gho, is_l2, 0 /* ip4 */ ,
1 /* ip6 */ );
hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
hdr->gso_size = vnet_buffer2 (b)->gso_size;
hdr->hdr_len = gho.hdr_sz;
@ -260,13 +265,14 @@ add_buffer_to_slot (vlib_main_t * vm, virtio_if_t * vif,
d = &vring->desc[next];
vlib_buffer_t *b = vlib_get_buffer (vm, bi);
struct virtio_net_hdr_v1 *hdr = vlib_buffer_get_current (b) - hdr_sz;
int is_l2 = (vif->type & (VIRTIO_IF_TYPE_TAP | VIRTIO_IF_TYPE_PCI));
clib_memset (hdr, 0, hdr_sz);
if (b->flags & VNET_BUFFER_F_GSO)
{
if (do_gso)
set_gso_offsets (b, hdr);
set_gso_offsets (b, hdr, is_l2);
else
{
virtio_interface_drop_inline (vm, node_index, &bi, 1,
@ -278,7 +284,7 @@ add_buffer_to_slot (vlib_main_t * vm, virtio_if_t * vif,
VNET_BUFFER_F_OFFLOAD_UDP_CKSUM))
{
if (csum_offload)
set_checksum_offsets (b, hdr);
set_checksum_offsets (b, hdr, is_l2);
else
{
virtio_interface_drop_inline (vm, node_index, &bi, 1,

View File

@ -237,7 +237,11 @@ vhost_user_handle_tx_offload (vhost_user_intf_t * vui, vlib_buffer_t * b,
virtio_net_hdr_t * hdr)
{
generic_header_offset_t gho = { 0 };
vnet_generic_header_offset_parser (b, &gho);
int is_ip4 = b->flags & VNET_BUFFER_F_IS_IP4;
int is_ip6 = b->flags & VNET_BUFFER_F_IS_IP6;
ASSERT (!(is_ip4 && is_ip6));
vnet_generic_header_offset_parser (b, &gho, 1 /* l2 */ , is_ip4, is_ip6);
if (b->flags & VNET_BUFFER_F_OFFLOAD_IP_CKSUM)
{
ip4_header_t *ip4;
@ -272,13 +276,13 @@ vhost_user_handle_tx_offload (vhost_user_intf_t * vui, vlib_buffer_t * b,
{
if (b->flags & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM)
{
if ((b->flags & VNET_BUFFER_F_IS_IP4) &&
if (is_ip4 &&
(vui->features & (1ULL << FEAT_VIRTIO_NET_F_GUEST_TSO4)))
{
hdr->gso_size = vnet_buffer2 (b)->gso_size;
hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
}
else if ((b->flags & VNET_BUFFER_F_IS_IP6) &&
else if (is_ip6 &&
(vui->features & (1ULL << FEAT_VIRTIO_NET_F_GUEST_TSO6)))
{
hdr->gso_size = vnet_buffer2 (b)->gso_size;

View File

@ -5,9 +5,11 @@ features:
- Basic GSO support
- GSO for VLAN tagged packets
- GSO for VXLAN tunnel
- GSO for IP-IP tunnel
- GSO for IPSec tunnel
- Provide inline function to get header offsets
description: "Generic Segmentation Offload"
missing:
- Thorough Testing, IPIP, GRE, Geneve, IPSec
- Thorough Testing, GRE, Geneve
state: experimental
properties: [API, CLI]

View File

@ -26,30 +26,6 @@ gso_main_t gso_main;
int
vnet_sw_interface_gso_enable_disable (u32 sw_if_index, u8 enable)
{
ethernet_interface_t *eif;
vnet_sw_interface_t *si;
ethernet_main_t *em;
vnet_main_t *vnm;
vnm = vnet_get_main ();
em = &ethernet_main;
si = vnet_get_sw_interface (vnm, sw_if_index);
/*
* only ethernet HW interfaces are supported at this time
*/
if (si->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
{
return (VNET_API_ERROR_INVALID_VALUE);
}
eif = ethernet_get_interface (em, si->hw_if_index);
if (!eif)
{
return (VNET_API_ERROR_FEATURE_DISABLED);
}
vnet_feature_enable_disable ("ip4-output", "gso-ip4", sw_if_index, enable,
0, 0);
vnet_feature_enable_disable ("ip6-output", "gso-ip6", sw_if_index, enable,

View File

@ -36,7 +36,8 @@
_( 8, VXLAN_TUNNEL) \
_( 9, GRE_TUNNEL) \
_( 10, IPIP_TUNNEL) \
_( 11, GENEVE_TUNNEL)
_( 11, IPIP6_TUNNEL) \
_( 12, GENEVE_TUNNEL)
typedef enum gho_flag_t_
{
@ -45,9 +46,10 @@ typedef enum gho_flag_t_
#undef _
} gho_flag_t;
#define GHO_F_TUNNEL (GHO_F_VXLAN_TUNNEL | \
GHO_F_GENEVE_TUNNEL | \
GHO_F_IPIP_TUNNEL | \
#define GHO_F_TUNNEL (GHO_F_VXLAN_TUNNEL | \
GHO_F_GENEVE_TUNNEL | \
GHO_F_IPIP_TUNNEL | \
GHO_F_IPIP6_TUNNEL | \
GHO_F_GRE_TUNNEL)
#define GHO_F_OUTER_HDR (GHO_F_OUTER_IP4 | \
@ -173,11 +175,77 @@ static_always_inline void
vnet_ipip_inner_header_parser_inline (vlib_buffer_t * b0,
generic_header_offset_t * gho)
{
/* not supported yet */
if ((gho->gho_flags & GHO_F_IPIP_TUNNEL) == 0)
if ((gho->gho_flags & (GHO_F_IPIP_TUNNEL | GHO_F_IPIP6_TUNNEL)) == 0)
return;
ASSERT (0);
u8 l4_proto = 0;
u8 l4_hdr_sz = 0;
gho->outer_l2_hdr_offset = gho->l2_hdr_offset;
gho->outer_l3_hdr_offset = gho->l3_hdr_offset;
gho->outer_l4_hdr_offset = gho->l4_hdr_offset;
gho->outer_l4_hdr_sz = gho->l4_hdr_sz;
gho->outer_hdr_sz = gho->hdr_sz;
gho->l2_hdr_offset = 0;
gho->l3_hdr_offset = 0;
gho->l4_hdr_offset = 0;
gho->l4_hdr_sz = 0;
gho->hdr_sz = 0;
if (gho->gho_flags & GHO_F_IP4)
{
gho->gho_flags |= GHO_F_OUTER_IP4;
}
else if (gho->gho_flags & GHO_F_IP6)
{
gho->gho_flags |= GHO_F_OUTER_IP6;
}
gho->gho_flags &= ~GHO_F_INNER_HDR;
vnet_get_inner_header (b0, gho);
gho->l2_hdr_offset = b0->current_data;
gho->l3_hdr_offset = 0;
if (PREDICT_TRUE (gho->gho_flags & GHO_F_IPIP_TUNNEL))
{
ip4_header_t *ip4 = (ip4_header_t *) vlib_buffer_get_current (b0);
gho->l4_hdr_offset = ip4_header_bytes (ip4);
l4_proto = ip4->protocol;
gho->gho_flags |= GHO_F_IP4;
}
else if (PREDICT_TRUE (gho->gho_flags & GHO_F_IPIP6_TUNNEL))
{
ip6_header_t *ip6 = (ip6_header_t *) vlib_buffer_get_current (b0);
/* FIXME IPv6 EH traversal */
gho->l4_hdr_offset = sizeof (ip6_header_t);
l4_proto = ip6->protocol;
gho->gho_flags |= GHO_F_IP6;
}
if (l4_proto == IP_PROTOCOL_TCP)
{
tcp_header_t *tcp = (tcp_header_t *) (vlib_buffer_get_current (b0) +
gho->l4_hdr_offset);
l4_hdr_sz = tcp_header_bytes (tcp);
gho->gho_flags |= GHO_F_TCP;
}
else if (l4_proto == IP_PROTOCOL_UDP)
{
udp_header_t *udp = (udp_header_t *) (vlib_buffer_get_current (b0) +
gho->l4_hdr_offset);
l4_hdr_sz = sizeof (*udp);
gho->gho_flags |= GHO_F_UDP;
}
gho->l4_hdr_sz = l4_hdr_sz;
gho->hdr_sz += gho->l4_hdr_offset + l4_hdr_sz;
vnet_get_outer_header (b0, gho);
}
static_always_inline void
@ -290,7 +358,7 @@ vnet_generic_inner_header_parser_inline (vlib_buffer_t * b0,
if (gho->gho_flags & GHO_F_VXLAN_TUNNEL)
vnet_vxlan_inner_header_parser_inline (b0, gho);
else if (gho->gho_flags & GHO_F_IPIP_TUNNEL)
else if (gho->gho_flags & (GHO_F_IPIP_TUNNEL | GHO_F_IPIP6_TUNNEL))
vnet_ipip_inner_header_parser_inline (b0, gho);
else if (gho->gho_flags & GHO_F_GRE_TUNNEL)
vnet_gre_inner_header_parser_inline (b0, gho);
@ -300,33 +368,44 @@ vnet_generic_inner_header_parser_inline (vlib_buffer_t * b0,
static_always_inline void
vnet_generic_outer_header_parser_inline (vlib_buffer_t * b0,
generic_header_offset_t * gho)
generic_header_offset_t * gho,
int is_l2, int is_ip4, int is_ip6)
{
u8 l4_proto = 0;
u8 l4_hdr_sz = 0;
u16 ethertype = 0;
u16 l2hdr_sz = 0;
ethernet_header_t *eh = (ethernet_header_t *) vlib_buffer_get_current (b0);
u16 ethertype = clib_net_to_host_u16 (eh->type);
u16 l2hdr_sz = sizeof (ethernet_header_t);
ASSERT (is_ip4 ^ is_ip6);
if (ethernet_frame_is_tagged (ethertype))
if (is_l2)
{
ethernet_vlan_header_t *vlan = (ethernet_vlan_header_t *) (eh + 1);
ethernet_header_t *eh =
(ethernet_header_t *) vlib_buffer_get_current (b0);
ethertype = clib_net_to_host_u16 (eh->type);
l2hdr_sz = sizeof (ethernet_header_t);
ethertype = clib_net_to_host_u16 (vlan->type);
l2hdr_sz += sizeof (*vlan);
if (ethertype == ETHERNET_TYPE_VLAN)
if (ethernet_frame_is_tagged (ethertype))
{
vlan++;
ethernet_vlan_header_t *vlan = (ethernet_vlan_header_t *) (eh + 1);
ethertype = clib_net_to_host_u16 (vlan->type);
l2hdr_sz += sizeof (*vlan);
if (ethertype == ETHERNET_TYPE_VLAN)
{
vlan++;
ethertype = clib_net_to_host_u16 (vlan->type);
l2hdr_sz += sizeof (*vlan);
}
}
}
else
l2hdr_sz = vnet_buffer (b0)->ip.save_rewrite_length;
gho->l2_hdr_offset = b0->current_data;
gho->l3_hdr_offset = l2hdr_sz;
if (PREDICT_TRUE (ethertype == ETHERNET_TYPE_IP4))
if (PREDICT_TRUE (is_ip4))
{
ip4_header_t *ip4 =
(ip4_header_t *) (vlib_buffer_get_current (b0) + l2hdr_sz);
@ -334,7 +413,7 @@ vnet_generic_outer_header_parser_inline (vlib_buffer_t * b0,
l4_proto = ip4->protocol;
gho->gho_flags |= GHO_F_IP4;
}
else if (PREDICT_TRUE (ethertype == ETHERNET_TYPE_IP6))
else if (PREDICT_TRUE (is_ip6))
{
ip6_header_t *ip6 =
(ip6_header_t *) (vlib_buffer_get_current (b0) + l2hdr_sz);
@ -369,12 +448,16 @@ vnet_generic_outer_header_parser_inline (vlib_buffer_t * b0,
gho->gho_flags |= GHO_F_GENEVE_TUNNEL;
}
}
else if ((l4_proto == IP_PROTOCOL_IP_IN_IP)
|| (l4_proto == IP_PROTOCOL_IPV6))
else if (l4_proto == IP_PROTOCOL_IP_IN_IP)
{
l4_hdr_sz = 0;
gho->gho_flags |= GHO_F_IPIP_TUNNEL;
}
else if (l4_proto == IP_PROTOCOL_IPV6)
{
l4_hdr_sz = 0;
gho->gho_flags |= GHO_F_IPIP6_TUNNEL;
}
else if (l4_proto == IP_PROTOCOL_GRE)
{
l4_hdr_sz = 0;
@ -387,9 +470,10 @@ vnet_generic_outer_header_parser_inline (vlib_buffer_t * b0,
static_always_inline void
vnet_generic_header_offset_parser (vlib_buffer_t * b0,
generic_header_offset_t * gho)
generic_header_offset_t * gho, int is_l2,
int is_ip4, int is_ip6)
{
vnet_generic_outer_header_parser_inline (b0, gho);
vnet_generic_outer_header_parser_inline (b0, gho, is_l2, is_ip4, is_ip6);
if (gho->gho_flags & GHO_F_TUNNEL)
{

File diff suppressed because it is too large Load Diff

View File

@ -92,7 +92,8 @@ vnet_calc_checksums_inline (vlib_main_t * vm, vlib_buffer_t * b,
if (with_gso)
{
generic_header_offset_t gho = { 0 };
vnet_generic_header_offset_parser (b, &gho);
vnet_generic_header_offset_parser (b, &gho, 1 /* l2 */ , is_ip4,
is_ip6);
ASSERT (gho.gho_flags ^ (GHO_F_IP4 | GHO_F_IP6));

View File

@ -22,6 +22,7 @@ from vpp_object import VppObject
from vpp_interface import VppInterface
from vpp_ip import DpoProto
from vpp_ip_route import VppIpRoute, VppRoutePath, FibPathProto
from vpp_ipip_tun_interface import VppIpIpTunInterface
from vpp_vxlan_tunnel import VppVxlanTunnel
from socket import AF_INET, AF_INET6, inet_pton
from util import reassemble4
@ -67,12 +68,15 @@ class TestGSO(VppTestCase):
self.vxlan = VppVxlanTunnel(self, src=self.pg0.local_ip4,
dst=self.pg0.remote_ip4,
vni=self.single_tunnel_bd)
self.vxlan.add_vpp_config()
self.vxlan2 = VppVxlanTunnel(self, src=self.pg0.local_ip6,
dst=self.pg0.remote_ip6,
vni=self.single_tunnel_bd)
self.vxlan2.add_vpp_config()
self.ipip4 = VppIpIpTunInterface(self, self.pg0, self.pg0.local_ip4,
self.pg0.remote_ip4)
self.ipip6 = VppIpIpTunInterface(self, self.pg0, self.pg0.local_ip6,
self.pg0.remote_ip6)
def tearDown(self):
super(TestGSO, self).tearDown()
@ -286,6 +290,11 @@ class TestGSO(VppTestCase):
# create VXLAN VTEP on VPP pg0, and put vxlan_tunnel0 and pg2
# into BD.
#
#
# enable ipv4/vxlan
#
self.vxlan.add_vpp_config()
self.vapi.sw_interface_set_l2_bridge(
rx_sw_if_index=self.vxlan.sw_if_index, bd_id=self.single_tunnel_bd)
self.vapi.sw_interface_set_l2_bridge(
@ -300,7 +309,6 @@ class TestGSO(VppTestCase):
TCP(sport=1234, dport=1234) /
Raw(b'\xa5' * 65200))
self.pg0.enable_capture()
rxs = self.send_and_expect(self.pg2, [p45], self.pg0, 45)
size = 0
for rx in rxs:
@ -325,7 +333,6 @@ class TestGSO(VppTestCase):
TCP(sport=1234, dport=1234) /
Raw(b'\xa5' * 65200))
self.pg0.enable_capture()
rxs = self.send_and_expect(self.pg2, [p65], self.pg0, 45)
size = 0
for rx in rxs:
@ -350,6 +357,7 @@ class TestGSO(VppTestCase):
#
# enable ipv6/vxlan
#
self.vxlan2.add_vpp_config()
self.vapi.sw_interface_set_l2_bridge(
rx_sw_if_index=self.vxlan2.sw_if_index,
bd_id=self.single_tunnel_bd)
@ -362,7 +370,6 @@ class TestGSO(VppTestCase):
TCP(sport=1234, dport=1234) /
Raw(b'\xa5' * 65200))
self.pg0.enable_capture()
rxs = self.send_and_expect(self.pg2, [p46], self.pg0, 45)
size = 0
for rx in rxs:
@ -387,7 +394,6 @@ class TestGSO(VppTestCase):
TCP(sport=1234, dport=1234) /
Raw(b'\xa5' * 65200))
self.pg0.enable_capture()
rxs = self.send_and_expect(self.pg2, [p66], self.pg0, 45)
size = 0
for rx in rxs:
@ -404,5 +410,192 @@ class TestGSO(VppTestCase):
size += inner[IPv6].plen - 20
self.assertEqual(size, 65200)
#
# disable ipv4/vxlan
#
self.vxlan2.remove_vpp_config()
def test_gso_ipip(self):
""" GSO IPIP test """
self.logger.info(self.vapi.cli("sh int addr"))
#
# Send jumbo frame with gso enabled only on input interface and
# create IPIP tunnel on VPP pg0.
#
self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index)
#
# enable ipip4
#
self.ipip4.add_vpp_config()
# Set interface up and enable IP on it
self.ipip4.admin_up()
self.ipip4.set_unnumbered(self.pg0.sw_if_index)
# Add IPv4 routes via tunnel interface
self.ip4_via_ip4_tunnel = VppIpRoute(
self, "172.16.10.0", 24,
[VppRoutePath("0.0.0.0",
self.ipip4.sw_if_index,
proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
self.ip4_via_ip4_tunnel.add_vpp_config()
#
# IPv4/IPv4 - IPIP
#
p47 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
IP(src=self.pg2.remote_ip4, dst="172.16.10.3", flags='DF') /
TCP(sport=1234, dport=1234) /
Raw(b'\xa5' * 65200))
rxs = self.send_and_expect(self.pg2, [p47], self.pg0, 45)
size = 0
for rx in rxs:
self.assertEqual(rx[Ether].src, self.pg0.local_mac)
self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
self.assertEqual(rx[IP].src, self.pg0.local_ip4)
self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
self.assertEqual(rx[IP].proto, 4) # ipencap
inner = rx[IP].payload
self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
self.assertEqual(inner[IP].dst, "172.16.10.3")
size += inner[IP].len - 20 - 20
self.assertEqual(size, 65200)
self.ip6_via_ip4_tunnel = VppIpRoute(
self, "fd01:10::", 64,
[VppRoutePath("::",
self.ipip4.sw_if_index,
proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
self.ip6_via_ip4_tunnel.add_vpp_config()
#
# IPv4/IPv6 - IPIP
#
p67 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
IPv6(src=self.pg2.remote_ip6, dst="fd01:10::3") /
TCP(sport=1234, dport=1234) /
Raw(b'\xa5' * 65200))
rxs = self.send_and_expect(self.pg2, [p67], self.pg0, 45)
size = 0
for rx in rxs:
self.assertEqual(rx[Ether].src, self.pg0.local_mac)
self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
self.assertEqual(rx[IP].src, self.pg0.local_ip4)
self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
self.assertEqual(rx[IP].proto, 41) # ipv6
inner = rx[IP].payload
self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6)
self.assertEqual(inner[IPv6].dst, "fd01:10::3")
size += inner[IPv6].plen - 20
self.assertEqual(size, 65200)
#
# Send jumbo frame with gso enabled only on input interface and
# create IPIP tunnel on VPP pg0. Enable gso feature node on ipip
# tunnel - IPSec use case
#
self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index, 0)
self.vapi.feature_gso_enable_disable(self.ipip4.sw_if_index)
rxs = self.send_and_expect(self.pg2, [p47], self.pg0, 45)
size = 0
for rx in rxs:
self.assertEqual(rx[Ether].src, self.pg0.local_mac)
self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
self.assertEqual(rx[IP].src, self.pg0.local_ip4)
self.assertEqual(rx[IP].dst, self.pg0.remote_ip4)
self.assertEqual(rx[IP].proto, 4) # ipencap
inner = rx[IP].payload
self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
self.assertEqual(inner[IP].dst, "172.16.10.3")
size += inner[IP].len - 20 - 20
self.assertEqual(size, 65200)
#
# disable ipip4
#
self.vapi.feature_gso_enable_disable(self.ipip4.sw_if_index, 0)
self.ip4_via_ip4_tunnel.remove_vpp_config()
self.ip6_via_ip4_tunnel.remove_vpp_config()
self.ipip4.remove_vpp_config()
#
# enable ipip6
#
self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index)
self.ipip6.add_vpp_config()
# Set interface up and enable IP on it
self.ipip6.admin_up()
self.ipip6.set_unnumbered(self.pg0.sw_if_index)
# Add IPv4 routes via tunnel interface
self.ip4_via_ip6_tunnel = VppIpRoute(
self, "172.16.10.0", 24,
[VppRoutePath("0.0.0.0",
self.ipip6.sw_if_index,
proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
self.ip4_via_ip6_tunnel.add_vpp_config()
#
# IPv6/IPv4 - IPIP
#
p48 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
IP(src=self.pg2.remote_ip4, dst="172.16.10.3", flags='DF') /
TCP(sport=1234, dport=1234) /
Raw(b'\xa5' * 65200))
rxs = self.send_and_expect(self.pg2, [p48], self.pg0, 45)
size = 0
for rx in rxs:
self.assertEqual(rx[Ether].src, self.pg0.local_mac)
self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
self.assertEqual(rx[IPv6].src, self.pg0.local_ip6)
self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
self.assertEqual(ipv6nh[rx[IPv6].nh], "IP")
inner = rx[IPv6].payload
self.assertEqual(inner[IP].src, self.pg2.remote_ip4)
self.assertEqual(inner[IP].dst, "172.16.10.3")
size += inner[IP].len - 20 - 20
self.assertEqual(size, 65200)
self.ip6_via_ip6_tunnel = VppIpRoute(
self, "fd01:10::", 64,
[VppRoutePath("::",
self.ipip6.sw_if_index,
proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
self.ip6_via_ip6_tunnel.add_vpp_config()
#
# IPv6/IPv6 - IPIP
#
p68 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") /
IPv6(src=self.pg2.remote_ip6, dst="fd01:10::3") /
TCP(sport=1234, dport=1234) /
Raw(b'\xa5' * 65200))
rxs = self.send_and_expect(self.pg2, [p68], self.pg0, 45)
size = 0
for rx in rxs:
self.assertEqual(rx[Ether].src, self.pg0.local_mac)
self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
self.assertEqual(rx[IPv6].src, self.pg0.local_ip6)
self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6)
self.assertEqual(ipv6nh[rx[IPv6].nh], "IPv6")
inner = rx[IPv6].payload
self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6)
self.assertEqual(inner[IPv6].dst, "fd01:10::3")
size += inner[IPv6].plen - 20
self.assertEqual(size, 65200)
#
# disable ipip6
#
self.ip4_via_ip6_tunnel.remove_vpp_config()
self.ip6_via_ip6_tunnel.remove_vpp_config()
self.ipip6.remove_vpp_config()
if __name__ == '__main__':
unittest.main(testRunner=VppTestRunner)