mirror of
https://github.com/openvswitch/ovs
synced 2025-09-03 15:55:19 +00:00
packets: Re-calculate IPv6 checksum only for first frag upon modify.
In case of modifying an IPv6 packet src/dst address the L4 checksum
should be recalculated only for the first frag. Currently it's done
for all frags, leading to incorrect reassembled packet checksum.
Fix it by adding a new flag to recalculate the checksum only for the
first frag.
Fixes: bc7a5acdff
("datapath: add ipv6 'set' action")
Signed-off-by: Salem Sol <salems@nvidia.com>
Acked-by: Mike Pattrick <mkp@redhat.com>
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
This commit is contained in:
@@ -1153,7 +1153,7 @@ packet_set_ipv4_addr(struct dp_packet *packet,
|
||||
*
|
||||
* This function assumes that L3 and L4 offsets are set in the packet. */
|
||||
static bool
|
||||
packet_rh_present(struct dp_packet *packet, uint8_t *nexthdr)
|
||||
packet_rh_present(struct dp_packet *packet, uint8_t *nexthdr, bool *first_frag)
|
||||
{
|
||||
const struct ovs_16aligned_ip6_hdr *nh;
|
||||
size_t len;
|
||||
@@ -1203,6 +1203,8 @@ packet_rh_present(struct dp_packet *packet, uint8_t *nexthdr)
|
||||
const struct ovs_16aligned_ip6_frag *frag_hdr
|
||||
= ALIGNED_CAST(struct ovs_16aligned_ip6_frag *, data);
|
||||
|
||||
*first_frag = !(frag_hdr->ip6f_offlg & IP6F_OFF_MASK) &&
|
||||
(frag_hdr->ip6f_offlg & IP6F_MORE_FRAG);
|
||||
*nexthdr = frag_hdr->ip6f_nxt;
|
||||
len = sizeof *frag_hdr;
|
||||
} else if (*nexthdr == IPPROTO_ROUTING) {
|
||||
@@ -1333,18 +1335,20 @@ packet_set_ipv6(struct dp_packet *packet, const struct in6_addr *src,
|
||||
uint8_t key_hl)
|
||||
{
|
||||
struct ovs_16aligned_ip6_hdr *nh = dp_packet_l3(packet);
|
||||
bool recalc_csum = true;
|
||||
uint8_t proto = 0;
|
||||
bool rh_present;
|
||||
|
||||
rh_present = packet_rh_present(packet, &proto);
|
||||
rh_present = packet_rh_present(packet, &proto, &recalc_csum);
|
||||
|
||||
if (memcmp(&nh->ip6_src, src, sizeof(ovs_be32[4]))) {
|
||||
packet_set_ipv6_addr(packet, proto, nh->ip6_src.be32, src, true);
|
||||
packet_set_ipv6_addr(packet, proto, nh->ip6_src.be32,
|
||||
src, recalc_csum);
|
||||
}
|
||||
|
||||
if (memcmp(&nh->ip6_dst, dst, sizeof(ovs_be32[4]))) {
|
||||
packet_set_ipv6_addr(packet, proto, nh->ip6_dst.be32, dst,
|
||||
!rh_present);
|
||||
!rh_present && recalc_csum);
|
||||
}
|
||||
|
||||
packet_set_ipv6_tc(&nh->ip6_flow, key_tc);
|
||||
|
@@ -226,6 +226,41 @@ NS_CHECK_EXEC([at_ns0], [grep ipv6 stdout.txt | grep frag=later | grep -v -q pro
|
||||
OVS_TRAFFIC_VSWITCHD_STOP
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([datapath - ping6 between two ports with header modify])
|
||||
OVS_TRAFFIC_VSWITCHD_START()
|
||||
|
||||
AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
|
||||
|
||||
ADD_NAMESPACES(at_ns0, at_ns1)
|
||||
|
||||
ADD_VETH(p0, at_ns0, br0, "fc00::1/96", e4:11:22:33:44:55)
|
||||
ADD_VETH(p1, at_ns1, br0, "fc00::2/96", e4:11:22:33:44:54)
|
||||
NS_CHECK_EXEC([at_ns0], [ip -6 neigh add fc00::3 lladdr e4:11:22:33:44:54 dev p0])
|
||||
NS_CHECK_EXEC([at_ns0], [ip -6 neigh add fc00::2 lladdr e4:11:22:33:44:54 dev p0])
|
||||
NS_CHECK_EXEC([at_ns0], [ip -6 neigh add fc00::1 lladdr e4:11:22:33:44:55 dev p0])
|
||||
|
||||
dnl Linux seems to take a little time to get its IPv6 stack in order. Without
|
||||
dnl waiting, we get occasional failures due to the following error:
|
||||
dnl "connect: Cannot assign requested address"
|
||||
OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2])
|
||||
|
||||
AT_CHECK([ovs-ofctl del-flows -OOpenFlow15 br0])
|
||||
AT_CHECK([ovs-ofctl add-flow -OOpenFlow15 br0 in_port=ovs-p0,ipv6,ipv6_dst=fc00::3,ipv6_src=fc00::1,actions=set_field:fc00::2-\>ipv6_dst,ovs-p1])
|
||||
AT_CHECK([ovs-ofctl add-flow -OOpenFlow15 br0 in_port=ovs-p1,ipv6,ipv6_dst=fc00::1,ipv6_src=fc00::2,actions=set_field:fc00::3-\>ipv6_src,ovs-p0])
|
||||
|
||||
NS_CHECK_EXEC([at_ns0], [ping6 -q -c 3 -i 0.3 -w 2 fc00::3 | FORMAT_PING], [0], [dnl
|
||||
3 packets transmitted, 3 received, 0% packet loss, time 0ms
|
||||
])
|
||||
NS_CHECK_EXEC([at_ns0], [ping6 -s 1600 -q -c 3 -i 0.3 -w 2 fc00::3 | FORMAT_PING], [0], [dnl
|
||||
3 packets transmitted, 3 received, 0% packet loss, time 0ms
|
||||
])
|
||||
NS_CHECK_EXEC([at_ns0], [ping6 -s 3200 -q -c 3 -i 0.3 -w 2 fc00::3 | FORMAT_PING], [0], [dnl
|
||||
3 packets transmitted, 3 received, 0% packet loss, time 0ms
|
||||
])
|
||||
|
||||
OVS_TRAFFIC_VSWITCHD_STOP
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([datapath - ping over bond])
|
||||
OVS_TRAFFIC_VSWITCHD_START()
|
||||
|
||||
|
Reference in New Issue
Block a user