> -----Original Message-----
> From: Ilya Maximets <i.maxim...@ovn.org>
> Sent: Tuesday, June 7, 2022 1:14 PM
> To: Salem Sol <sal...@nvidia.com>; d...@openvswitch.org
> Cc: Eli Britstein <el...@nvidia.com>; Michael Pattrick <m...@redhat.com>;
> i.maxim...@ovn.org
> Subject: Re: [ovs-dev] [PATCH 1/1] packets: Re-calculate IPv6 checksum only
> for last frags upon modify.
> 
> External email: Use caution opening links or attachments
> 
> 
> On 6/6/22 12:12, Salem Sol via dev wrote:
> > In case of modifying an IPv6 packet src/dst address the checksum
> > should be recalculated only for the last 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 last frag.
> 
> Hi.  Thanks for working on this!
> 
> There is definitely a problem with checksum calculation, but I don't
> understand the logic of the fix.  We're talking about re-calculation of the L4
> checksum, but the *last* fragment should not contain the L4 header.  So,
> we're just corrupting the data of the last fragment.  If we want to 
> re-calculate
> the checksum, we should do that for the *first* fragment instead, because
> it's the only fragment that will likely contain the L4 header.  Or am I 
> missing
> something?
> 
> BTW, it looks like we have the same issue for ipv4 packets.  We should
> update checksum only for the first fragment.  This can be a separate fix
> though.
> 
> Some more comments inline.
> 
> Best regards, Ilya Maximets.
> 
Thanks for the catch, you're right, my bad, in my testing I used only one 
extension header and the original patchset seemed to resolve the issue.
New implementation can be found in V3.
> >
> > Fixes: bc7a5acdff08 ("datapath: add ipv6 'set' action")
> > Signed-off-by: Salem Sol <sal...@nvidia.com>
> > Acked-by: Mike Pattrick <m...@redhat.com>
> > ---
> >  lib/packets.c           | 20 ++++++++++++++++++--
> >  tests/system-traffic.at | 35 +++++++++++++++++++++++++++++++++++
> >  2 files changed, 53 insertions(+), 2 deletions(-)
> >
> > diff --git a/lib/packets.c b/lib/packets.c index d0fba8176..b7aef41a5
> > 100644
> > --- a/lib/packets.c
> > +++ b/lib/packets.c
> > @@ -1148,6 +1148,18 @@ packet_set_ipv4_addr(struct dp_packet
> *packet,
> >      put_16aligned_be32(addr, new_addr);  }
> >
> > +static bool
> > +packet_is_last_ipv6_frag(struct dp_packet *packet) {
> > +    const struct ovs_16aligned_ip6_frag *frag_hdr;
> > +    uint8_t *data = dp_packet_l3(packet);
> > +
> > +    data += sizeof (struct ovs_16aligned_ip6_hdr);
> > +    frag_hdr = ALIGNED_CAST(struct ovs_16aligned_ip6_frag *, data);
> > +    return (frag_hdr->ip6f_offlg & IP6F_OFF_MASK) &&
> > +           !(frag_hdr->ip6f_offlg & IP6F_MORE_FRAG); }
> > +
> >  /* Returns true, if packet contains at least one routing header where
> >   * segements_left > 0.
> >   *
> > @@ -1334,17 +1346,21 @@ packet_set_ipv6(struct dp_packet *packet,
> > const struct in6_addr *src,  {
> >      struct ovs_16aligned_ip6_hdr *nh = dp_packet_l3(packet);
> >      uint8_t proto = 0;
> > +    bool recalc_csum;
> >      bool rh_present;
> >
> >      rh_present = packet_rh_present(packet, &proto);
> > +    recalc_csum = nh->ip6_nxt == IPPROTO_FRAGMENT ?
> > +        packet_is_last_ipv6_frag(packet) : true;
> 
> The fragmentation header is usually the last extension header, not the first.
> This check will work for the simple case with only one extension header, but
> it will not work in the general case.  We should search for the fragmentation
> header the same way as we look for the routing header in
> packet_rh_present().
> We should, probably, modify the packet_rh_present() function to also say if
> the packet is fragmented / is it the first fragment.
> 
Thanks for the comment, I followed your suggestion and changed 
packet_rh_present() to update if it's the first frag in V3.
> >
> >      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
> > 239105e89..16ba42d84 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], [], [stdout],
> > +[stderr]) AT_CHECK([ovs-ofctl add-flow -OOpenFlow15 br0
> > +in_port=ovs-p0,ipv6,ipv6_dst=fc00::3,ipv6_src=fc00::1,actions=set_fie
> > +ld:fc00::2-\>ipv6_dst,ovs-p1], [], [stdout], [stderr])
> > +AT_CHECK([ovs-ofctl add-flow -OOpenFlow15 br0
> > +in_port=ovs-p1,ipv6,ipv6_dst=fc00::1,ipv6_src=fc00::2,actions=set_fie
> > +ld:fc00::3-\>ipv6_src,ovs-p0], [], [stdout], [stderr])
> 
> The ', [], [stdout], [stderr]' part in above commands should not be needed.
ACK.
> 
> > +
> > +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()
> >

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to