diff options
author | Salem Sol <salems@nvidia.com> | 2022-06-07 18:00:35 +0300 |
---|---|---|
committer | Ilya Maximets <i.maximets@ovn.org> | 2022-08-04 13:58:42 +0200 |
commit | 506b9a7a22fba11b2ddf5831ed48ab27718b4f99 (patch) | |
tree | adab63be78079aa871c6f0f09dd0774720704ee3 | |
parent | f2024c9ef99c906e6c9eeac026fe44c0f6f75cf7 (diff) | |
download | openvswitch-506b9a7a22fba11b2ddf5831ed48ab27718b4f99.tar.gz |
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: bc7a5acdff08 ("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>
-rw-r--r-- | lib/packets.c | 12 | ||||
-rw-r--r-- | tests/system-traffic.at | 35 |
2 files changed, 43 insertions, 4 deletions
diff --git a/lib/packets.c b/lib/packets.c index 4a7643c5d..60bb25c38 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -1107,7 +1107,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; @@ -1157,6 +1157,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) { @@ -1287,18 +1289,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); diff --git a/tests/system-traffic.at b/tests/system-traffic.at index 61064ad05..fd3f13f25 100644 --- a/tests/system-traffic.at +++ b/tests/system-traffic.at @@ -192,6 +192,41 @@ NS_CHECK_EXEC([at_ns0], [ping6 -s 3200 -q -c 3 -i 0.3 -w 2 fc00:1::2 | FORMAT_PI 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() |