Ales reported that ct_tp_{src,dst} matches are working only for the
first frag for the userspace datapath, whereas they are always working
for later frags in the case of kernel datapath.

The ipf propagates the info in packets metadata, but
miniflow_extract() has no handling for them.

Fix it by pushing the relevant fields in the miniflow.
tp_{src,dst} are not set for later frags, so fill them with padding as
ct_tp_{src,dst} are not aligned:

struct flow {
    [...]
    ovs_be16                   tp_src;               /*   656     2 */
    ovs_be16                   tp_dst;               /*   658     2 */
    ovs_be16                   ct_tp_src;            /*   660     2 */
    ovs_be16                   ct_tp_dst;            /*   662     2 */
    [...]
}

The patch also includes two tests to exercise the behavior.

Reported-at: https://issues.redhat.com/browse/FDP-124
Fixes: 4ea96698f667 ("Userspace datapath: Add fragmentation handling.")
Signed-off-by: Paolo Valerio <[email protected]>
---
v2:
- Rearranged fragmented IPv6 packets in the test (Ilya)
- Added tshark dissection output for all packets (Ilya)
- while at it, changed the IPv4/UDP packet using a payload with
  repetitions to make it smaller
- updated IPv6 test
---
 lib/flow.c              |  21 ++++-
 tests/system-traffic.at | 171 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 189 insertions(+), 3 deletions(-)

diff --git a/lib/flow.c b/lib/flow.c
index 0eb34892f..68d673123 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -402,6 +402,14 @@ parse_ethertype(const void **datap, size_t *sizep)
     return htons(FLOW_DL_TYPE_NONE);
 }
 
+static inline bool
+icmp6_is_nd(const struct icmp6_data_header *icmp6)
+{
+    return (icmp6->icmp6_base.icmp6_code == 0 &&
+            (icmp6->icmp6_base.icmp6_type == ND_NEIGHBOR_SOLICIT ||
+             icmp6->icmp6_base.icmp6_type == ND_NEIGHBOR_ADVERT));
+}
+
 /* Returns 'true' if the packet is an ND packet. In that case the '*nd_target'
  * and 'arp_buf[]' are filled in.  If the packet is not an ND packet, 'false'
  * is returned and no values are filled in on '*nd_target' or 'arp_buf[]'. */
@@ -412,9 +420,7 @@ parse_icmpv6(const void **datap, size_t *sizep,
              const union ovs_16aligned_in6_addr **nd_target,
              struct eth_addr arp_buf[2], uint8_t *opt_type)
 {
-    if (icmp6->icmp6_base.icmp6_code != 0 ||
-        (icmp6->icmp6_base.icmp6_type != ND_NEIGHBOR_SOLICIT &&
-         icmp6->icmp6_base.icmp6_type != ND_NEIGHBOR_ADVERT)) {
+    if (!icmp6_is_nd(icmp6)) {
         return false;
     }
 
@@ -1166,6 +1172,15 @@ miniflow_extract(struct dp_packet *packet, struct 
miniflow *dst)
                 }
             }
         }
+    } else if (ct_nw_proto_p &&
+               (*ct_nw_proto_p == IPPROTO_TCP ||
+                *ct_nw_proto_p == IPPROTO_UDP ||
+                *ct_nw_proto_p == IPPROTO_SCTP ||
+                *ct_nw_proto_p == IPPROTO_ICMP ||
+                (*ct_nw_proto_p == IPPROTO_ICMPV6 && !icmp6_is_nd(data)))) {
+        miniflow_pad_from_64(mf, ct_tp_src);
+        miniflow_push_be16(mf, ct_tp_src, ct_tp_src);
+        miniflow_push_be16(mf, ct_tp_dst, ct_tp_dst);
     }
  out:
     dst->map = mf.map;
diff --git a/tests/system-traffic.at b/tests/system-traffic.at
index 04328db4c..035221ca0 100644
--- a/tests/system-traffic.at
+++ b/tests/system-traffic.at
@@ -4714,6 +4714,177 @@ OVS_CHECK_FRAG_LARGE()
 OVS_TRAFFIC_VSWITCHD_STOP(["/Unsupported big reassembled v4 packet/d"])
 AT_CLEANUP
 
+AT_SETUP([conntrack - IPv4 fragmentation with ct orig match])
+CHECK_CONNTRACK()
+OVS_TRAFFIC_VSWITCHD_START()
+
+ADD_NAMESPACES(at_ns0, at_ns1)
+
+ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
+ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
+
+AT_DATA([flows.txt], [dnl
+priority=1,action=drop
+priority=10,arp,action=normal
+priority=100,ip,ct_state=-trk,action=ct(table=0)
+priority=100,in_port=2,icmp,ct_state=+rpl,action=1
+priority=100,in_port=1,ip,ct_nw_proto=17,ct_tp_src=1,ct_tp_dst=2,ct_state=+new+trk,action=ct(commit)
+priority=100,in_port=1,ip,ct_nw_proto=1,ct_tp_src=8,ct_tp_dst=0,ct_state=+new+trk,action=ct(commit),2
+])
+
+AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
+
+dnl Packet content:
+dnl   Ethernet II, Src: 50:54:00:00:00:0a, Dst: 50:54:00:00:00:09
+dnl       Type: IPv4 (0x0800)
+dnl   Internet Protocol Version 4, Src: 10.1.1.1, Dst: 10.1.1.2
+dnl       Total Length: 1420
+dnl       Identification: 0x0001 (1)
+dnl       001. .... = Flags: 0x1, More fragments
+dnl           0... .... = Reserved bit: Not set
+dnl           .0.. .... = Don't fragment: Not set
+dnl           ..1. .... = More fragments: Set
+dnl       ...0 0000 0000 0000 = Fragment Offset: 0
+dnl       Time to Live: 64
+dnl       Protocol: UDP (17)
+dnl   User Datagram Protocol, Src Port: 1, Dst Port: 2
+dnl       Source Port: 1
+dnl       Destination Port: 2
+dnl       Length: 1608
+dnl       UDP payload (1392 bytes)
+dnl   Data (1392 bytes)
+eth="50 54 00 00 00 09 50 54 00 00 00 0a 08 00"
+ip="45 00 05 8c 00 01 20 00 40 11 3f 5c 0a 01 01 01 0a 01 01 02"
+udp="00 01 00 02 06 48 dd 56"
+data_len=$(seq 1392)
+data=$(printf '00 %.0s' ${data_len})
+packet="${eth} ${ip} ${udp} ${data}"
+NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 ${packet} > /dev/null])
+
+dnl Packet content:
+dnl   Ethernet II, Src: 50:54:00:00:00:0a, Dst: 50:54:00:00:00:09
+dnl       Type: IPv4 (0x0800)
+dnl   Internet Protocol Version 4, Src: 10.1.1.1, Dst: 10.1.1.2
+dnl       0100 .... = Version: 4
+dnl       .... 0101 = Header Length: 20 bytes (5)
+dnl       Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
+dnl           0000 00.. = Differentiated Services Codepoint: Default (0)
+dnl           .... ..00 = Explicit Congestion Notification: Not ECN-Capable 
Transport (0)
+dnl       Total Length: 228
+dnl       Identification: 0x0001 (1)
+dnl       000. .... = Flags: 0x0
+dnl           0... .... = Reserved bit: Not set
+dnl           .0.. .... = Don't fragment: Not set
+dnl           ..0. .... = More fragments: Not set
+dnl       ...0 0000 1010 1111 = Fragment Offset: 1400
+dnl       Time to Live: 64
+dnl       Protocol: UDP (17)
+dnl   Data (208 bytes)
+eth="50 54 00 00 00 09 50 54 00 00 00 0a 08 00"
+ip="45 00 00 e4 00 01 00 af 40 11 63 55 0a 01 01 01 0a 01 01 02"
+data_len=$(seq 208)
+data=$(printf '00 %.0s' ${data_len})
+packet="${eth} ${ip} ${data}"
+NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 ${packet} > /dev/null])
+
+NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 1 -W 1 10.1.1.2 | FORMAT_PING], 
[0], [dnl
+1 packets transmitted, 1 received, 0% packet loss, time 0ms
+])
+
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sort], [0], 
[dnl
+icmp,orig=(src=10.1.1.1,dst=10.1.1.2,id=<cleared>,type=8,code=0),reply=(src=10.1.1.2,dst=10.1.1.1,id=<cleared>,type=0,code=0)
+udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.1,sport=<cleared>,dport=<cleared>)
+])
+
+OVS_TRAFFIC_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([conntrack - IPv6 fragmentation with ct orig match])
+CHECK_CONNTRACK()
+OVS_TRAFFIC_VSWITCHD_START()
+
+ADD_NAMESPACES(at_ns0, at_ns1)
+
+ADD_VETH(p0, at_ns0, br0, "fc00::1/96", "50:54:00:00:00:09", [], "nodad")
+ADD_VETH(p1, at_ns1, br0, "fc00::2/96", "50:54:00:00:00:0a", [], "nodad")
+
+AT_DATA([flows.txt], [dnl
+priority=1,action=drop
+priority=10,ipv6,ct_state=-trk,action=ct(table=0)
+priority=10,in_port=2,ipv6,ct_tp_src=128,ct_state=+trk+est+rpl,action=1
+priority=10,in_port=1,ipv6,ct_nw_proto=17,ct_tp_src=1,ct_tp_dst=2,ct_state=+new+trk,action=ct(commit)
+priority=10,in_port=1,ipv6,ct_nw_proto=58,ct_tp_src=128,ct_tp_dst=0,ct_state=+new+trk,action=ct(commit),2
+priority=100,icmp6,icmp_type=135,action=normal
+priority=100,icmp6,icmp_type=136,action=normal
+])
+
+AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
+
+dnl Packet content:
+dnl   Ethernet II, Src: 50:54:00:00:00:0a, Dst: 50:54:00:00:00:09
+dnl       Type: IPv6 (0x86dd)
+dnl   Internet Protocol Version 6, Src: fc00::1, Dst: fc00::2
+dnl       Payload Length: 1344
+dnl       Next Header: Fragment Header for IPv6 (44)
+dnl       Hop Limit: 64
+dnl       Fragment Header for IPv6
+dnl           Next header: UDP (17)
+dnl           Reserved octet: 0x00
+dnl           0000 0000 0000 0... = Offset: 0 (0 bytes)
+dnl           .... .... .... .00. = Reserved bits: 0
+dnl           .... .... .... ...1 = More Fragments: Yes
+dnl           Identification: 0x9bdb1fa7
+dnl   User Datagram Protocol, Src Port: 1, Dst Port: 2
+dnl       Source Port: 1
+dnl       Destination Port: 2
+dnl       Length: 1608
+dnl       UDP payload (1328 bytes)
+dnl   Data (1328 bytes)
+eth="50 54 00 00 00 09 50 54 00 00 00 0a 86 dd"
+ipv6="60 00 00 00 05 40 2c 40 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 \
+      fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 11 00 00 01 9b db 1f a7"
+udp="00 01 00 02 06 48 fb 56"
+data_len=$(seq 1328)
+data=$(printf '00 %.0s' ${data_len})
+packet="${eth} ${ipv6} ${udp} ${data}"
+NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 ${packet} > /dev/null])
+
+dnl IPv6 Packet content
+dnl   Ethernet II, Src: 50:54:00:00:00:0a, Dst: 50:54:00:00:00:09
+dnl       Type: IPv6 (0x86dd)
+dnl   Internet Protocol Version 6, Src: fc00::1, Dst: fc00::2
+dnl       Payload Length: 280
+dnl       Next Header: Fragment Header for IPv6 (44)
+dnl       Hop Limit: 64
+dnl       Fragment Header for IPv6
+dnl           Next header: UDP (17)
+dnl           Reserved octet: 0x00
+dnl           0000 0101 0011 1... = Offset: 167 (1336 bytes)
+dnl           .... .... .... .00. = Reserved bits: 0
+dnl           .... .... .... ...0 = More Fragments: No
+dnl           Identification: 0x9bdb1fa7
+dnl   Data (272 bytes)
+eth="50 54 00 00 00 09 50 54 00 00 00 0a 86 dd"
+ipv6="60 00 00 00 01 18 2c 40 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 \
+      fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 11 00 05 38 9b db 1f a7"
+data_len=$(seq 272)
+data=$(printf '00 %.0s' ${data_len})
+packet="${eth} ${ipv6} ${data}"
+NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 ${packet} > /dev/null])
+
+dnl Send also fragmented ICMPv6.
+NS_CHECK_EXEC([at_ns0], [ping6 -s 1600 -q -c 1 -W 1 fc00::2 | FORMAT_PING], 
[0], [dnl
+1 packets transmitted, 1 received, 0% packet loss, time 0ms
+])
+
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fc00::2) | sort], [0], 
[dnl
+icmpv6,orig=(src=fc00::1,dst=fc00::2,id=<cleared>,type=128,code=0),reply=(src=fc00::2,dst=fc00::1,id=<cleared>,type=129,code=0)
+udp,orig=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),reply=(src=fc00::2,dst=fc00::1,sport=<cleared>,dport=<cleared>)
+])
+
+OVS_TRAFFIC_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([conntrack - IPv4 fragmentation expiry])
 CHECK_CONNTRACK()
 OVS_TRAFFIC_VSWITCHD_START()
-- 
2.47.1

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to