diff mbox series

[ovs-dev,v4] Revert "odp-util: Always report ODP_FIT_TOO_LITTLE for IGMP."

Message ID 20220106180704.2388658-1-aconole@redhat.com
State Changes Requested
Headers show
Series [ovs-dev,v4] Revert "odp-util: Always report ODP_FIT_TOO_LITTLE for IGMP." | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test success github build: passed

Commit Message

Aaron Conole Jan. 6, 2022, 6:07 p.m. UTC
This reverts commit c645550bb249 ("odp-util: Always report
ODP_FIT_TOO_LITTLE for IGMP.")

Always forcing a slow path action can result in some over-broad
flows which swallow all traffic and force them to userspace, as reported
in the thread at
https://mail.openvswitch.org/pipermail/ovs-dev/2021-September/387706.html
and at
https://mail.openvswitch.org/pipermail/ovs-dev/2021-September/387689.html

Revert the ODP_FIT_TOO_LITTLE return for IGMP specifically.
Additionally, remove the userspace wc mask to prevent revalidator from
cycling flows.

Fixes: c645550bb249 ("odp-util: Always report ODP_FIT_TOO_LITTLE for IGMP.")
Signed-off-by: Aaron Conole <aconole@redhat.com>
Acked-by: Eelco Chaudron <echaudro@redhat.com>
---
v1->v2: Add unit test for coverage of mcast traffic when not doing snooping
v2->v3: Add a unit test for the non-dummy datapaths as well to demonstrate the
        matching issue.
v3->v4: Fix up the unit tests to be consistent when reporting dp flows.  Split
        IGMP unit test into two different tests.  Use a multicast eth addr for
        the FLOOD under NORMAL action case.

 lib/odp-util.c               |  5 ---
 ofproto/ofproto-dpif-xlate.c |  1 -
 tests/mcast-snooping.at      | 68 ++++++++++++++++++++++++++++++
 tests/ofproto-macros.at      | 15 +++++++
 tests/system-traffic.at      | 80 ++++++++++++++++++++++++++++++++++++
 5 files changed, 163 insertions(+), 6 deletions(-)

Comments

Eelco Chaudron Jan. 7, 2022, 1:05 p.m. UTC | #1
On 6 Jan 2022, at 19:07, Aaron Conole wrote:

> This reverts commit c645550bb249 ("odp-util: Always report
> ODP_FIT_TOO_LITTLE for IGMP.")
>
> Always forcing a slow path action can result in some over-broad
> flows which swallow all traffic and force them to userspace, as reported
> in the thread at
> https://mail.openvswitch.org/pipermail/ovs-dev/2021-September/387706.html
> and at
> https://mail.openvswitch.org/pipermail/ovs-dev/2021-September/387689.html
>
> Revert the ODP_FIT_TOO_LITTLE return for IGMP specifically.
> Additionally, remove the userspace wc mask to prevent revalidator from
> cycling flows.
>
> Fixes: c645550bb249 ("odp-util: Always report ODP_FIT_TOO_LITTLE for IGMP.")
> Signed-off-by: Aaron Conole <aconole@redhat.com>
> Acked-by: Eelco Chaudron <echaudro@redhat.com>
> ---
> v1->v2: Add unit test for coverage of mcast traffic when not doing snooping
> v2->v3: Add a unit test for the non-dummy datapaths as well to demonstrate the
>         matching issue.
> v3->v4: Fix up the unit tests to be consistent when reporting up flows.  Split
>         IGMP unit test into two different tests.  Use a multicast eth addr for
>         the FLOOD under NORMAL action case.

I reviewed and tested the patch (even run the test cases in a 50 times loop), and all looks fine!

Acked-by: Eelco Chaudron <echaudro@redhat.com>
Ilya Maximets Jan. 26, 2022, 9:49 p.m. UTC | #2
On 1/6/22 19:07, Aaron Conole wrote:
> This reverts commit c645550bb249 ("odp-util: Always report
> ODP_FIT_TOO_LITTLE for IGMP.")
> 
> Always forcing a slow path action can result in some over-broad
> flows which swallow all traffic and force them to userspace, as reported
> in the thread at
> https://mail.openvswitch.org/pipermail/ovs-dev/2021-September/387706.html
> and at
> https://mail.openvswitch.org/pipermail/ovs-dev/2021-September/387689.html
> 
> Revert the ODP_FIT_TOO_LITTLE return for IGMP specifically.
> Additionally, remove the userspace wc mask to prevent revalidator from
> cycling flows.
> 
> Fixes: c645550bb249 ("odp-util: Always report ODP_FIT_TOO_LITTLE for IGMP.")
> Signed-off-by: Aaron Conole <aconole@redhat.com>
> Acked-by: Eelco Chaudron <echaudro@redhat.com>
> ---
> v1->v2: Add unit test for coverage of mcast traffic when not doing snooping
> v2->v3: Add a unit test for the non-dummy datapaths as well to demonstrate the
>         matching issue.
> v3->v4: Fix up the unit tests to be consistent when reporting dp flows.  Split
>         IGMP unit test into two different tests.  Use a multicast eth addr for
>         the FLOOD under NORMAL action case.
> 
>  lib/odp-util.c               |  5 ---
>  ofproto/ofproto-dpif-xlate.c |  1 -
>  tests/mcast-snooping.at      | 68 ++++++++++++++++++++++++++++++
>  tests/ofproto-macros.at      | 15 +++++++
>  tests/system-traffic.at      | 80 ++++++++++++++++++++++++++++++++++++
>  5 files changed, 163 insertions(+), 6 deletions(-)
> 
> diff --git a/lib/odp-util.c b/lib/odp-util.c
> index fbdfc7ad83..0f21ffe639 100644
> --- a/lib/odp-util.c
> +++ b/lib/odp-util.c
> @@ -7132,11 +7132,6 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
>                  }
>              }
>          }
> -    } else if (src_flow->nw_proto == IPPROTO_IGMP
> -               && src_flow->dl_type == htons(ETH_TYPE_IP)) {
> -        /* OVS userspace parses the IGMP type, code, and group, but its
> -         * datapaths do not, so there is always missing information. */
> -        return ODP_FIT_TOO_LITTLE;
>      }
>      if (is_mask && expected_bit != OVS_KEY_ATTR_UNSPEC) {
>          if ((flow->tp_src || flow->tp_dst) && flow->nw_proto != 0xff) {
> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
> index cafcd014ad..29d26cf9ac 100644
> --- a/ofproto/ofproto-dpif-xlate.c
> +++ b/ofproto/ofproto-dpif-xlate.c
> @@ -3048,7 +3048,6 @@ xlate_normal(struct xlate_ctx *ctx)
>               */
>              ctx->xout->slow |= SLOW_ACTION;
>  
> -            memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
>              if (mcast_snooping_is_membership(flow->tp_src) ||
>                  mcast_snooping_is_query(flow->tp_src)) {
>                  if (ctx->xin->allow_side_effects && ctx->xin->packet) {
> diff --git a/tests/mcast-snooping.at b/tests/mcast-snooping.at
> index 757cf7186e..e24f293a0c 100644
> --- a/tests/mcast-snooping.at
> +++ b/tests/mcast-snooping.at
> @@ -216,3 +216,70 @@ AT_CHECK([ovs-appctl mdb/show br0], [0], [dnl
>  ])
>  
>  AT_CLEANUP
> +
> +
> +AT_SETUP([mcast - igmp flood for non-snoop enabled])
> +OVS_VSWITCHD_START([])
> +
> +AT_CHECK([
> +    ovs-vsctl set bridge br0 \
> +    datapath_type=dummy], [0])
> +
> +add_of_ports br0 1 2
> +
> +AT_CHECK([ovs-ofctl add-flow br0 action=normal])
> +
> +ovs-appctl time/stop
> +
> +dnl Basic scenario - needs to flood for IGMP followed by unicast ICMP
> +dnl in reverse direction
> +AT_CHECK([ovs-appctl netdev-dummy/receive p1 \
> +    '0101000c29a0aa55aa550001080046c00028000040000102d3494565eb4ae0000016940400002200f9020000000104000000e00000fb000000000000'])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p2 \
> +    'aa55aa5500010101000c29a008004500001c00010000400164dc0a0101010a0101020800f7ffffffffff'])
> +
> +
> +AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl
> +          strip_stats | strip_used | strip_recirc | dnl
> +          sed -e 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
> +                     [0], [dnl
> +recirc_id(<recirc>),in_port(1),eth(src=aa:55:aa:55:00:01,dst=01:01:00:0c:29:a0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:100,2
> +recirc_id(<recirc>),in_port(2),eth(src=01:01:00:0c:29:a0,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:1
> +])
> +
> +ovs-appctl time/warp 100000
> +
> +dnl Next we should clear the flows and install a complex case
> +AT_CHECK([ovs-ofctl del-flows br0])
> +
> +AT_DATA([flows.txt], [dnl
> +table=0, arp actions=NORMAL
> +table=0, ip,in_port=1 actions=ct(table=1,zone=64000)
> +table=0, in_port=2 actions=output:1
> +table=1, ip,ct_state=+trk+inv actions=drop
> +table=1  ip,in_port=1,icmp,ct_state=+trk+new actions=output:2
> +table=1, in_port=1,ip,ct_state=+trk+new actions=controller(userdata=00.de.ad.be.ef.ca.fe.01)
> +table=1, in_port=1,ip,ct_state=+trk+est actions=output:2
> +])
> +AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
> +
> +ovs-appctl time/warp 100000
> +
> +dnl Send the IGMP, followed by a unicast ICMP - ensure we won't black hole
> +AT_CHECK([ovs-appctl netdev-dummy/receive p1 \
> +    '0101000c29a0aa55aa550001080046c00028000040000102d3494565eb4ae0000016940400002200f9020000000104000000e00000fb000000000000'])
> +AT_CHECK([ovs-appctl netdev-dummy/receive p1 \
> +    'aa55aa550001aa55aa55000208004500001c00010000400164dc0a0101010a0101020800f7ffffffffff'])
> +
> +
> +AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl
> +          strip_stats | strip_used | strip_recirc | dnl
> +          sed 's/pid=[[0-9]]*,//
> +               s/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
> +                     [0], [dnl
> +ct_state(+new-inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(proto=1,frag=no), packets:0, bytes:0, used:never, actions:2
> +ct_state(+new-inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(proto=2,frag=no), packets:0, bytes:0, used:never, actions:userspace(controller(reason=1,dont_send=0,continuation=0,recirc_id=<recirc>,rule_cookie=0,controller_id=0,max_len=65535))
> +recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:0.0s, actions:ct(zone=64000),recirc(<recirc>)
> +])

I tried to backport the patch to earlier branches, but this test fails
on 2.14 and 2.13 (works on 2.15+) with the following result:

--- -	2022-01-26 21:33:15.713282778 +0000
+++ /home/runner/work/ovs/ovs/openvswitch-2.13.7/_build/sub/tests/testsuite.dir/at-groups/2302/stdout	2022-01-26 21:33:15.708679313 +0000
@@ -1,4 +1,4 @@
+ct_state(+inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop
 ct_state(+new-inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(proto=1,frag=no), packets:0, bytes:0, used:never, actions:2
-ct_state(+new-inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(proto=2,frag=no), packets:0, bytes:0, used:never, actions:userspace(controller(reason=1,dont_send=0,continuation=0,recirc_id=<recirc>,rule_cookie=0,controller_id=0,max_len=65535))
 recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:0.0s, actions:ct(zone=64000),recirc(<recirc>)

Packets seems to be marked +inv by conntrack.  Is it some kind
of conntrack issue that got fixed in 2.15 that we should backport?
Can we modify the test somehow to make it work on 2.13 ?

> +
> +AT_CLEANUP
> diff --git a/tests/ofproto-macros.at b/tests/ofproto-macros.at
> index 736d9809cb..f906b5c3b5 100644
> --- a/tests/ofproto-macros.at
> +++ b/tests/ofproto-macros.at
> @@ -134,6 +134,21 @@ strip_ufid () {
>      sed 's/mega_ufid:[[-0-9a-f]]* //
>      s/ufid:[[-0-9a-f]]* //'
>  }
> +
> +# Strips packets: and bytes: from output
> +strip_stats () {
> +    sed 's/packets:[[0-9]]*/packets:0/
> +    s/bytes:[[0-9]]*/bytes:0/'
> +}
> +
> +# Changes all 'recirc(...)' and 'recirc=...' to say 'recirc(<recirc_id>)' and
> +# 'recirc=<recirc_id>' respectively.  This should make output easier to
> +# compare.
> +strip_recirc() {
> +   sed 's/recirc_id([[x0-9]]*)/recirc_id(<recirc>)/
> +        s/recirc_id=[[x0-9]]*/recirc_id=<recirc>/
> +        s/recirc([[x0-9]]*)/recirc(<recirc>)/'
> +}
>  m4_divert_pop([PREPARE_TESTS])
>  
>  m4_define([TESTABLE_LOG], [-vPATTERN:ANY:'%c|%p|%m'])
> diff --git a/tests/system-traffic.at b/tests/system-traffic.at
> index d79753a99a..5d9449fada 100644
> --- a/tests/system-traffic.at
> +++ b/tests/system-traffic.at
> @@ -6287,6 +6287,86 @@ AT_CHECK([ovs-ofctl dump-flows br0 | grep table=2, | OFPROTO_CLEAR_DURATION_IDLE
>  OVS_TRAFFIC_VSWITCHD_STOP
>  AT_CLEANUP
>  
> +AT_BANNER([IGMP])
> +
> +AT_SETUP([IGMP - flood under normal action])
> +
> +OVS_TRAFFIC_VSWITCHD_START()
> +ADD_NAMESPACES(at_ns0, at_ns1)
> +
> +ADD_VETH(p1, at_ns0, br0, "10.1.1.1/24", "f0:00:00:01:01:01")
> +ADD_VETH(p2, at_ns1, br0, "10.1.1.2/24", "f0:00:00:01:01:02")
> +
> +AT_CHECK([ovs-ofctl add-flow br0 "actions=NORMAL"])
> +
> +NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 01 00 5e 01 01 03 dnl
> +f0 00 00 01 01 01 08 00 46 c0 00 28 00 00 40 00 01 02 d3 49 45 65 eb 4a e0 dnl
> +00 00 16 94 04 00 00 22 00 f9 02 00 00 00 01 04 00 00 00 e0 00 00 fb 00 00 dnl
> +00 00 00 00 > /dev/null])
> +
> +AT_CHECK([ovs-appctl dpif/show | grep -v missed:], [0], [dnl
> +  br0:
> +    br0 65534/1: (internal)

This line is failing the system-userspace testsuite, because userspace
datapath reports 'tap' instead of 'internal'.  Suggesting a following
change:

diff --git a/tests/system-traffic.at b/tests/system-traffic.at
index 1ba28f7ee..7711f14b0 100644
--- a/tests/system-traffic.at
+++ b/tests/system-traffic.at
@@ -6681,18 +6681,11 @@ f0 00 00 01 01 01 08 00 46 c0 00 28 00 00 40 00 01 02 d3 49 45 65 eb 4a e0 dnl
 00 00 16 94 04 00 00 22 00 f9 02 00 00 00 01 04 00 00 00 e0 00 00 fb 00 00 dnl
 00 00 00 00 > /dev/null])
 
-AT_CHECK([ovs-appctl dpif/show | grep -v missed:], [0], [dnl
-  br0:
-    br0 65534/1: (internal)
-    ovs-p1 1/2: (system)
-    ovs-p2 2/3: (system)
-])
-
-AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl
+AT_CHECK([ovs-appctl dpctl/dump-flows --names | grep -e .*ipv4 | sort | dnl
           strip_stats | strip_used | strip_recirc | dnl
           sed 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
                      [0], [dnl
-recirc_id(<recirc>),in_port(2),eth(src=f0:00:00:01:01:01,dst=01:00:5e:01:01:03),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:1,3
+recirc_id(<recirc>),in_port(ovs-p1),eth(src=f0:00:00:01:01:01,dst=01:00:5e:01:01:03),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:br0,ovs-p2
 ])
 OVS_TRAFFIC_VSWITCHD_STOP
 AT_CLEANUP
---

What do you think?


> +    ovs-p1 1/2: (system)
> +    ovs-p2 2/3: (system)
> +])
> +
> +AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl
> +          strip_stats | strip_used | strip_recirc | dnl
> +          sed 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
> +                     [0], [dnl
> +recirc_id(<recirc>),in_port(2),eth(src=f0:00:00:01:01:01,dst=01:00:5e:01:01:03),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:1,3
> +])
> +OVS_TRAFFIC_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([IGMP - forward with ICMP])
> +
> +OVS_TRAFFIC_VSWITCHD_START()
> +ADD_NAMESPACES(at_ns0, at_ns1)
> +
> +ADD_VETH(p1, at_ns0, br0, "10.1.1.1/24", "f0:00:00:01:01:01")
> +ADD_VETH(p2, at_ns1, br0, "10.1.1.2/24", "f0:00:00:01:01:02")
> +
> +AT_DATA([flows.txt], [dnl
> +table=0, arp actions=NORMAL
> +table=0, ip,in_port=1 actions=ct(table=1,zone=64000)
> +table=0, in_port=2 actions=output:1
> +table=1, ip,ct_state=+trk+inv actions=drop
> +table=1  ip,in_port=1,icmp,ct_state=+trk+new actions=output:2
> +table=1, in_port=1,ip,ct_state=+trk+new actions=controller(userdata=00.de.ad.be.ef.ca.fe.01)
> +table=1, in_port=1,ip,ct_state=+trk+est actions=output:2
> +])
> +AT_CHECK([ovs-ofctl del-flows br0])
> +AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
> +
> +dnl Send the IGMP, followed by a unicast ICMP - ensure we won't black hole
> +
> +NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 f0 00 00 01 01 02 dnl
> +f0 00 00 01 01 01 08 00 46 c0 00 28 00 00 40 00 01 02 d3 49 45 65 eb 4a e0 dnl
> +00 00 16 94 04 00 00 22 00 f9 02 00 00 00 01 04 00 00 00 e0 00 00 fb 00 00 dnl
> +00 00 00 00 > /dev/null])
> +
> +NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 f0 00 00 01 01 02 dnl
> +f0 00 00 01 01 01 08 00 45 00 00 1c 00 01 00 00 40 01 64 dc 0a 01 01 01 0a dnl
> +01 01 02 08 00 f7 ff ff ff ff ff > /dev/null])
> +
> +sleep 1
> +
> +AT_CHECK([ovs-ofctl dump-flows br0 | grep -v NXST | dnl
> +          strip_duration | grep -v arp | grep -v n_packets=0 | dnl
> +          grep -v 'in_port=2 actions=output:1' | dnl
> +          sed 's/n_bytes=[[0-9]]*/n_bytes=0/
> +               s/idle_age=[[0-9]]*/idle_age=0/
> +               s/n_packets=[[1-9]]/n_packets=0/' | sort], [0], [dnl
> + cookie=0x0,  table=0, n_packets=0, n_bytes=0, idle_age=0, ip,in_port=1 actions=ct(table=1,zone=64000)
> + cookie=0x0,  table=1, n_packets=0, n_bytes=0, idle_age=0, ct_state=+new+trk,icmp,in_port=1 actions=output:2
> + cookie=0x0,  table=1, n_packets=0, n_bytes=0, idle_age=0, ct_state=+new+trk,ip,in_port=1 actions=controller(userdata=00.de.ad.be.ef.ca.fe.01)
> +])

These are OpenFlow rules.  Shouldn't we dump datapath flows, or
am I missing something?

> +
> +OVS_TRAFFIC_VSWITCHD_STOP
> +AT_CLEANUP
> +
>  AT_BANNER([802.1ad])
>  
>  AT_SETUP([802.1ad - vlan_limit])
>
Aaron Conole Feb. 23, 2022, 6:58 p.m. UTC | #3
Ilya Maximets <i.maximets@ovn.org> writes:

> On 1/6/22 19:07, Aaron Conole wrote:
>> This reverts commit c645550bb249 ("odp-util: Always report
>> ODP_FIT_TOO_LITTLE for IGMP.")
>> 
>> Always forcing a slow path action can result in some over-broad
>> flows which swallow all traffic and force them to userspace, as reported
>> in the thread at
>> https://mail.openvswitch.org/pipermail/ovs-dev/2021-September/387706.html
>> and at
>> https://mail.openvswitch.org/pipermail/ovs-dev/2021-September/387689.html
>> 
>> Revert the ODP_FIT_TOO_LITTLE return for IGMP specifically.
>> Additionally, remove the userspace wc mask to prevent revalidator from
>> cycling flows.
>> 
>> Fixes: c645550bb249 ("odp-util: Always report ODP_FIT_TOO_LITTLE for IGMP.")
>> Signed-off-by: Aaron Conole <aconole@redhat.com>
>> Acked-by: Eelco Chaudron <echaudro@redhat.com>
>> ---
>> v1->v2: Add unit test for coverage of mcast traffic when not doing snooping
>> v2->v3: Add a unit test for the non-dummy datapaths as well to demonstrate the
>>         matching issue.
>> v3->v4: Fix up the unit tests to be consistent when reporting dp flows.  Split
>>         IGMP unit test into two different tests.  Use a multicast eth addr for
>>         the FLOOD under NORMAL action case.
>> 
>>  lib/odp-util.c               |  5 ---
>>  ofproto/ofproto-dpif-xlate.c |  1 -
>>  tests/mcast-snooping.at      | 68 ++++++++++++++++++++++++++++++
>>  tests/ofproto-macros.at      | 15 +++++++
>>  tests/system-traffic.at      | 80 ++++++++++++++++++++++++++++++++++++
>>  5 files changed, 163 insertions(+), 6 deletions(-)
>> 
>> diff --git a/lib/odp-util.c b/lib/odp-util.c
>> index fbdfc7ad83..0f21ffe639 100644
>> --- a/lib/odp-util.c
>> +++ b/lib/odp-util.c
>> @@ -7132,11 +7132,6 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
>>                  }
>>              }
>>          }
>> -    } else if (src_flow->nw_proto == IPPROTO_IGMP
>> -               && src_flow->dl_type == htons(ETH_TYPE_IP)) {
>> -        /* OVS userspace parses the IGMP type, code, and group, but its
>> -         * datapaths do not, so there is always missing information. */
>> -        return ODP_FIT_TOO_LITTLE;
>>      }
>>      if (is_mask && expected_bit != OVS_KEY_ATTR_UNSPEC) {
>>          if ((flow->tp_src || flow->tp_dst) && flow->nw_proto != 0xff) {
>> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
>> index cafcd014ad..29d26cf9ac 100644
>> --- a/ofproto/ofproto-dpif-xlate.c
>> +++ b/ofproto/ofproto-dpif-xlate.c
>> @@ -3048,7 +3048,6 @@ xlate_normal(struct xlate_ctx *ctx)
>>               */
>>              ctx->xout->slow |= SLOW_ACTION;
>>  
>> -            memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
>>              if (mcast_snooping_is_membership(flow->tp_src) ||
>>                  mcast_snooping_is_query(flow->tp_src)) {
>>                  if (ctx->xin->allow_side_effects && ctx->xin->packet) {
>> diff --git a/tests/mcast-snooping.at b/tests/mcast-snooping.at
>> index 757cf7186e..e24f293a0c 100644
>> --- a/tests/mcast-snooping.at
>> +++ b/tests/mcast-snooping.at
>> @@ -216,3 +216,70 @@ AT_CHECK([ovs-appctl mdb/show br0], [0], [dnl
>>  ])
>>  
>>  AT_CLEANUP
>> +
>> +
>> +AT_SETUP([mcast - igmp flood for non-snoop enabled])
>> +OVS_VSWITCHD_START([])
>> +
>> +AT_CHECK([
>> +    ovs-vsctl set bridge br0 \
>> +    datapath_type=dummy], [0])
>> +
>> +add_of_ports br0 1 2
>> +
>> +AT_CHECK([ovs-ofctl add-flow br0 action=normal])
>> +
>> +ovs-appctl time/stop
>> +
>> +dnl Basic scenario - needs to flood for IGMP followed by unicast ICMP
>> +dnl in reverse direction
>> +AT_CHECK([ovs-appctl netdev-dummy/receive p1 \
>> +    '0101000c29a0aa55aa550001080046c00028000040000102d3494565eb4ae0000016940400002200f9020000000104000000e00000fb000000000000'])
>> +AT_CHECK([ovs-appctl netdev-dummy/receive p2 \
>> +    'aa55aa5500010101000c29a008004500001c00010000400164dc0a0101010a0101020800f7ffffffffff'])
>> +
>> +
>> +AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl
>> +          strip_stats | strip_used | strip_recirc | dnl
>> +          sed -e 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
>> +                     [0], [dnl
>> +recirc_id(<recirc>),in_port(1),eth(src=aa:55:aa:55:00:01,dst=01:01:00:0c:29:a0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:100,2
>> +recirc_id(<recirc>),in_port(2),eth(src=01:01:00:0c:29:a0,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:1
>> +])
>> +
>> +ovs-appctl time/warp 100000
>> +
>> +dnl Next we should clear the flows and install a complex case
>> +AT_CHECK([ovs-ofctl del-flows br0])
>> +
>> +AT_DATA([flows.txt], [dnl
>> +table=0, arp actions=NORMAL
>> +table=0, ip,in_port=1 actions=ct(table=1,zone=64000)
>> +table=0, in_port=2 actions=output:1
>> +table=1, ip,ct_state=+trk+inv actions=drop
>> +table=1  ip,in_port=1,icmp,ct_state=+trk+new actions=output:2
>> +table=1, in_port=1,ip,ct_state=+trk+new actions=controller(userdata=00.de.ad.be.ef.ca.fe.01)
>> +table=1, in_port=1,ip,ct_state=+trk+est actions=output:2
>> +])
>> +AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
>> +
>> +ovs-appctl time/warp 100000
>> +
>> +dnl Send the IGMP, followed by a unicast ICMP - ensure we won't black hole
>> +AT_CHECK([ovs-appctl netdev-dummy/receive p1 \
>> +    '0101000c29a0aa55aa550001080046c00028000040000102d3494565eb4ae0000016940400002200f9020000000104000000e00000fb000000000000'])
>> +AT_CHECK([ovs-appctl netdev-dummy/receive p1 \
>> +    'aa55aa550001aa55aa55000208004500001c00010000400164dc0a0101010a0101020800f7ffffffffff'])
>> +
>> +
>> +AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl
>> +          strip_stats | strip_used | strip_recirc | dnl
>> +          sed 's/pid=[[0-9]]*,//
>> +               s/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
>> +                     [0], [dnl
>> +ct_state(+new-inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(proto=1,frag=no), packets:0, bytes:0, used:never, actions:2
>> +ct_state(+new-inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(proto=2,frag=no), packets:0, bytes:0, used:never, actions:userspace(controller(reason=1,dont_send=0,continuation=0,recirc_id=<recirc>,rule_cookie=0,controller_id=0,max_len=65535))
>> +recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:0.0s, actions:ct(zone=64000),recirc(<recirc>)
>> +])
>
> I tried to backport the patch to earlier branches, but this test fails
> on 2.14 and 2.13 (works on 2.15+) with the following result:
>
> --- -	2022-01-26 21:33:15.713282778 +0000
> +++
> /home/runner/work/ovs/ovs/openvswitch-2.13.7/_build/sub/tests/testsuite.dir/at-groups/2302/stdout
> 2022-01-26 21:33:15.708679313 +0000
> @@ -1,4 +1,4 @@
> +ct_state(+inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(frag=no),
> packets:0, bytes:0, used:never, actions:drop
>  ct_state(+new-inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(proto=1,frag=no),
> packets:0, bytes:0, used:never, actions:2
> -ct_state(+new-inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(proto=2,frag=no),
> packets:0, bytes:0, used:never,
> actions:userspace(controller(reason=1,dont_send=0,continuation=0,recirc_id=<recirc>,rule_cookie=0,controller_id=0,max_len=65535))
>  recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(frag=no),
> packets:0, bytes:0, used:0.0s, actions:ct(zone=64000),recirc(<recirc>)
>
> Packets seems to be marked +inv by conntrack.  Is it some kind
> of conntrack issue that got fixed in 2.15 that we should backport?
> Can we modify the test somehow to make it work on 2.13 ?

I'll look into it.  Thanks.

>> +
>> +AT_CLEANUP
>> diff --git a/tests/ofproto-macros.at b/tests/ofproto-macros.at
>> index 736d9809cb..f906b5c3b5 100644
>> --- a/tests/ofproto-macros.at
>> +++ b/tests/ofproto-macros.at
>> @@ -134,6 +134,21 @@ strip_ufid () {
>>      sed 's/mega_ufid:[[-0-9a-f]]* //
>>      s/ufid:[[-0-9a-f]]* //'
>>  }
>> +
>> +# Strips packets: and bytes: from output
>> +strip_stats () {
>> +    sed 's/packets:[[0-9]]*/packets:0/
>> +    s/bytes:[[0-9]]*/bytes:0/'
>> +}
>> +
>> +# Changes all 'recirc(...)' and 'recirc=...' to say 'recirc(<recirc_id>)' and
>> +# 'recirc=<recirc_id>' respectively.  This should make output easier to
>> +# compare.
>> +strip_recirc() {
>> +   sed 's/recirc_id([[x0-9]]*)/recirc_id(<recirc>)/
>> +        s/recirc_id=[[x0-9]]*/recirc_id=<recirc>/
>> +        s/recirc([[x0-9]]*)/recirc(<recirc>)/'
>> +}
>>  m4_divert_pop([PREPARE_TESTS])
>>  
>>  m4_define([TESTABLE_LOG], [-vPATTERN:ANY:'%c|%p|%m'])
>> diff --git a/tests/system-traffic.at b/tests/system-traffic.at
>> index d79753a99a..5d9449fada 100644
>> --- a/tests/system-traffic.at
>> +++ b/tests/system-traffic.at
>> @@ -6287,6 +6287,86 @@ AT_CHECK([ovs-ofctl dump-flows br0 | grep table=2, | OFPROTO_CLEAR_DURATION_IDLE
>>  OVS_TRAFFIC_VSWITCHD_STOP
>>  AT_CLEANUP
>>  
>> +AT_BANNER([IGMP])
>> +
>> +AT_SETUP([IGMP - flood under normal action])
>> +
>> +OVS_TRAFFIC_VSWITCHD_START()
>> +ADD_NAMESPACES(at_ns0, at_ns1)
>> +
>> +ADD_VETH(p1, at_ns0, br0, "10.1.1.1/24", "f0:00:00:01:01:01")
>> +ADD_VETH(p2, at_ns1, br0, "10.1.1.2/24", "f0:00:00:01:01:02")
>> +
>> +AT_CHECK([ovs-ofctl add-flow br0 "actions=NORMAL"])
>> +
>> +NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 01 00 5e 01 01 03 dnl
>> +f0 00 00 01 01 01 08 00 46 c0 00 28 00 00 40 00 01 02 d3 49 45 65 eb 4a e0 dnl
>> +00 00 16 94 04 00 00 22 00 f9 02 00 00 00 01 04 00 00 00 e0 00 00 fb 00 00 dnl
>> +00 00 00 00 > /dev/null])
>> +
>> +AT_CHECK([ovs-appctl dpif/show | grep -v missed:], [0], [dnl
>> +  br0:
>> +    br0 65534/1: (internal)
>
> This line is failing the system-userspace testsuite, because userspace
> datapath reports 'tap' instead of 'internal'.  Suggesting a following
> change:
>
> diff --git a/tests/system-traffic.at b/tests/system-traffic.at
> index 1ba28f7ee..7711f14b0 100644
> --- a/tests/system-traffic.at
> +++ b/tests/system-traffic.at
> @@ -6681,18 +6681,11 @@ f0 00 00 01 01 01 08 00 46 c0 00 28 00 00 40 00 01 02 d3 49 45 65 eb 4a e0 dnl
>  00 00 16 94 04 00 00 22 00 f9 02 00 00 00 01 04 00 00 00 e0 00 00 fb 00 00 dnl
>  00 00 00 00 > /dev/null])
>  
> -AT_CHECK([ovs-appctl dpif/show | grep -v missed:], [0], [dnl
> -  br0:
> -    br0 65534/1: (internal)
> -    ovs-p1 1/2: (system)
> -    ovs-p2 2/3: (system)
> -])
> -
> -AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl
> +AT_CHECK([ovs-appctl dpctl/dump-flows --names | grep -e .*ipv4 | sort | dnl
>            strip_stats | strip_used | strip_recirc | dnl
>            sed 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
>                       [0], [dnl
> -recirc_id(<recirc>),in_port(2),eth(src=f0:00:00:01:01:01,dst=01:00:5e:01:01:03),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:1,3
> +recirc_id(<recirc>),in_port(ovs-p1),eth(src=f0:00:00:01:01:01,dst=01:00:5e:01:01:03),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:br0,ovs-p2
>  ])
>  OVS_TRAFFIC_VSWITCHD_STOP
>  AT_CLEANUP
> ---
>
> What do you think?

ACK - I'll pull that in.

>
>> +    ovs-p1 1/2: (system)
>> +    ovs-p2 2/3: (system)
>> +])
>> +
>> +AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl
>> +          strip_stats | strip_used | strip_recirc | dnl
>> +          sed 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
>> +                     [0], [dnl
>> +recirc_id(<recirc>),in_port(2),eth(src=f0:00:00:01:01:01,dst=01:00:5e:01:01:03),eth_type(0x0800),ipv4(frag=no),
>> packets:0, bytes:0, used:never, actions:1,3
>> +])
>> +OVS_TRAFFIC_VSWITCHD_STOP
>> +AT_CLEANUP
>> +
>> +AT_SETUP([IGMP - forward with ICMP])
>> +
>> +OVS_TRAFFIC_VSWITCHD_START()
>> +ADD_NAMESPACES(at_ns0, at_ns1)
>> +
>> +ADD_VETH(p1, at_ns0, br0, "10.1.1.1/24", "f0:00:00:01:01:01")
>> +ADD_VETH(p2, at_ns1, br0, "10.1.1.2/24", "f0:00:00:01:01:02")
>> +
>> +AT_DATA([flows.txt], [dnl
>> +table=0, arp actions=NORMAL
>> +table=0, ip,in_port=1 actions=ct(table=1,zone=64000)
>> +table=0, in_port=2 actions=output:1
>> +table=1, ip,ct_state=+trk+inv actions=drop
>> +table=1  ip,in_port=1,icmp,ct_state=+trk+new actions=output:2
>> +table=1, in_port=1,ip,ct_state=+trk+new actions=controller(userdata=00.de.ad.be.ef.ca.fe.01)
>> +table=1, in_port=1,ip,ct_state=+trk+est actions=output:2
>> +])
>> +AT_CHECK([ovs-ofctl del-flows br0])
>> +AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
>> +
>> +dnl Send the IGMP, followed by a unicast ICMP - ensure we won't black hole
>> +
>> +NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 f0 00 00 01 01 02 dnl
>> +f0 00 00 01 01 01 08 00 46 c0 00 28 00 00 40 00 01 02 d3 49 45 65 eb 4a e0 dnl
>> +00 00 16 94 04 00 00 22 00 f9 02 00 00 00 01 04 00 00 00 e0 00 00 fb 00 00 dnl
>> +00 00 00 00 > /dev/null])
>> +
>> +NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 f0 00 00 01 01 02 dnl
>> +f0 00 00 01 01 01 08 00 45 00 00 1c 00 01 00 00 40 01 64 dc 0a 01 01 01 0a dnl
>> +01 01 02 08 00 f7 ff ff ff ff ff > /dev/null])
>> +
>> +sleep 1
>> +
>> +AT_CHECK([ovs-ofctl dump-flows br0 | grep -v NXST | dnl
>> +          strip_duration | grep -v arp | grep -v n_packets=0 | dnl
>> +          grep -v 'in_port=2 actions=output:1' | dnl
>> +          sed 's/n_bytes=[[0-9]]*/n_bytes=0/
>> +               s/idle_age=[[0-9]]*/idle_age=0/
>> +               s/n_packets=[[1-9]]/n_packets=0/' | sort], [0], [dnl
>> + cookie=0x0, table=0, n_packets=0, n_bytes=0, idle_age=0,
>> ip,in_port=1 actions=ct(table=1,zone=64000)
>> + cookie=0x0, table=1, n_packets=0, n_bytes=0, idle_age=0,
>> ct_state=+new+trk,icmp,in_port=1 actions=output:2
>> + cookie=0x0, table=1, n_packets=0, n_bytes=0, idle_age=0,
>> ct_state=+new+trk,ip,in_port=1
>> actions=controller(userdata=00.de.ad.be.ef.ca.fe.01)
>> +])
>
> These are OpenFlow rules.  Shouldn't we dump datapath flows, or
> am I missing something?

IIRC, we use the openflow rules because they are wildly different
datapath rules between the two, so we rely on these rules being hit.
Additionally, in the kernel DP case, if ipv6 is enabled then some ND
will occur and that will tamper with n_packets/n_bytes counters (which
is why I clear it before doing the comparison).

I will look at the datapath flows again, but I believe the datapath
action set is different because of the way controller() is implemented
between the two (in the userspace DP, it can be a direct call, but in
the kerneldp it needs to be a userspace call first).

So I guess I will look at this, but expect to keep it as-is.

>> +
>> +OVS_TRAFFIC_VSWITCHD_STOP
>> +AT_CLEANUP
>> +
>>  AT_BANNER([802.1ad])
>>  
>>  AT_SETUP([802.1ad - vlan_limit])
>>
Ilya Maximets March 4, 2022, 6:56 p.m. UTC | #4
On 2/23/22 19:58, Aaron Conole wrote:
> Ilya Maximets <i.maximets@ovn.org> writes:
> 
>> On 1/6/22 19:07, Aaron Conole wrote:
>>> This reverts commit c645550bb249 ("odp-util: Always report
>>> ODP_FIT_TOO_LITTLE for IGMP.")
>>>
>>> Always forcing a slow path action can result in some over-broad
>>> flows which swallow all traffic and force them to userspace, as reported
>>> in the thread at
>>> https://mail.openvswitch.org/pipermail/ovs-dev/2021-September/387706.html
>>> and at
>>> https://mail.openvswitch.org/pipermail/ovs-dev/2021-September/387689.html
>>>
>>> Revert the ODP_FIT_TOO_LITTLE return for IGMP specifically.
>>> Additionally, remove the userspace wc mask to prevent revalidator from
>>> cycling flows.
>>>
>>> Fixes: c645550bb249 ("odp-util: Always report ODP_FIT_TOO_LITTLE for IGMP.")
>>> Signed-off-by: Aaron Conole <aconole@redhat.com>
>>> Acked-by: Eelco Chaudron <echaudro@redhat.com>
>>> ---
>>> v1->v2: Add unit test for coverage of mcast traffic when not doing snooping
>>> v2->v3: Add a unit test for the non-dummy datapaths as well to demonstrate the
>>>         matching issue.
>>> v3->v4: Fix up the unit tests to be consistent when reporting dp flows.  Split
>>>         IGMP unit test into two different tests.  Use a multicast eth addr for
>>>         the FLOOD under NORMAL action case.
>>>
>>>  lib/odp-util.c               |  5 ---
>>>  ofproto/ofproto-dpif-xlate.c |  1 -
>>>  tests/mcast-snooping.at      | 68 ++++++++++++++++++++++++++++++
>>>  tests/ofproto-macros.at      | 15 +++++++
>>>  tests/system-traffic.at      | 80 ++++++++++++++++++++++++++++++++++++
>>>  5 files changed, 163 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/lib/odp-util.c b/lib/odp-util.c
>>> index fbdfc7ad83..0f21ffe639 100644
>>> --- a/lib/odp-util.c
>>> +++ b/lib/odp-util.c
>>> @@ -7132,11 +7132,6 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
>>>                  }
>>>              }
>>>          }
>>> -    } else if (src_flow->nw_proto == IPPROTO_IGMP
>>> -               && src_flow->dl_type == htons(ETH_TYPE_IP)) {
>>> -        /* OVS userspace parses the IGMP type, code, and group, but its
>>> -         * datapaths do not, so there is always missing information. */
>>> -        return ODP_FIT_TOO_LITTLE;
>>>      }
>>>      if (is_mask && expected_bit != OVS_KEY_ATTR_UNSPEC) {
>>>          if ((flow->tp_src || flow->tp_dst) && flow->nw_proto != 0xff) {
>>> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
>>> index cafcd014ad..29d26cf9ac 100644
>>> --- a/ofproto/ofproto-dpif-xlate.c
>>> +++ b/ofproto/ofproto-dpif-xlate.c
>>> @@ -3048,7 +3048,6 @@ xlate_normal(struct xlate_ctx *ctx)
>>>               */
>>>              ctx->xout->slow |= SLOW_ACTION;
>>>  
>>> -            memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
>>>              if (mcast_snooping_is_membership(flow->tp_src) ||
>>>                  mcast_snooping_is_query(flow->tp_src)) {
>>>                  if (ctx->xin->allow_side_effects && ctx->xin->packet) {
>>> diff --git a/tests/mcast-snooping.at b/tests/mcast-snooping.at
>>> index 757cf7186e..e24f293a0c 100644
>>> --- a/tests/mcast-snooping.at
>>> +++ b/tests/mcast-snooping.at
>>> @@ -216,3 +216,70 @@ AT_CHECK([ovs-appctl mdb/show br0], [0], [dnl
>>>  ])
>>>  
>>>  AT_CLEANUP
>>> +
>>> +
>>> +AT_SETUP([mcast - igmp flood for non-snoop enabled])
>>> +OVS_VSWITCHD_START([])
>>> +
>>> +AT_CHECK([
>>> +    ovs-vsctl set bridge br0 \
>>> +    datapath_type=dummy], [0])
>>> +
>>> +add_of_ports br0 1 2
>>> +
>>> +AT_CHECK([ovs-ofctl add-flow br0 action=normal])
>>> +
>>> +ovs-appctl time/stop
>>> +
>>> +dnl Basic scenario - needs to flood for IGMP followed by unicast ICMP
>>> +dnl in reverse direction
>>> +AT_CHECK([ovs-appctl netdev-dummy/receive p1 \
>>> +    '0101000c29a0aa55aa550001080046c00028000040000102d3494565eb4ae0000016940400002200f9020000000104000000e00000fb000000000000'])
>>> +AT_CHECK([ovs-appctl netdev-dummy/receive p2 \
>>> +    'aa55aa5500010101000c29a008004500001c00010000400164dc0a0101010a0101020800f7ffffffffff'])
>>> +
>>> +
>>> +AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl
>>> +          strip_stats | strip_used | strip_recirc | dnl
>>> +          sed -e 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
>>> +                     [0], [dnl
>>> +recirc_id(<recirc>),in_port(1),eth(src=aa:55:aa:55:00:01,dst=01:01:00:0c:29:a0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:100,2
>>> +recirc_id(<recirc>),in_port(2),eth(src=01:01:00:0c:29:a0,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:1
>>> +])
>>> +
>>> +ovs-appctl time/warp 100000
>>> +
>>> +dnl Next we should clear the flows and install a complex case
>>> +AT_CHECK([ovs-ofctl del-flows br0])
>>> +
>>> +AT_DATA([flows.txt], [dnl
>>> +table=0, arp actions=NORMAL
>>> +table=0, ip,in_port=1 actions=ct(table=1,zone=64000)
>>> +table=0, in_port=2 actions=output:1
>>> +table=1, ip,ct_state=+trk+inv actions=drop
>>> +table=1  ip,in_port=1,icmp,ct_state=+trk+new actions=output:2
>>> +table=1, in_port=1,ip,ct_state=+trk+new actions=controller(userdata=00.de.ad.be.ef.ca.fe.01)
>>> +table=1, in_port=1,ip,ct_state=+trk+est actions=output:2
>>> +])
>>> +AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
>>> +
>>> +ovs-appctl time/warp 100000
>>> +
>>> +dnl Send the IGMP, followed by a unicast ICMP - ensure we won't black hole
>>> +AT_CHECK([ovs-appctl netdev-dummy/receive p1 \
>>> +    '0101000c29a0aa55aa550001080046c00028000040000102d3494565eb4ae0000016940400002200f9020000000104000000e00000fb000000000000'])
>>> +AT_CHECK([ovs-appctl netdev-dummy/receive p1 \
>>> +    'aa55aa550001aa55aa55000208004500001c00010000400164dc0a0101010a0101020800f7ffffffffff'])
>>> +
>>> +
>>> +AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl
>>> +          strip_stats | strip_used | strip_recirc | dnl
>>> +          sed 's/pid=[[0-9]]*,//
>>> +               s/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
>>> +                     [0], [dnl
>>> +ct_state(+new-inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(proto=1,frag=no), packets:0, bytes:0, used:never, actions:2
>>> +ct_state(+new-inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(proto=2,frag=no), packets:0, bytes:0, used:never, actions:userspace(controller(reason=1,dont_send=0,continuation=0,recirc_id=<recirc>,rule_cookie=0,controller_id=0,max_len=65535))
>>> +recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:0.0s, actions:ct(zone=64000),recirc(<recirc>)
>>> +])
>>
>> I tried to backport the patch to earlier branches, but this test fails
>> on 2.14 and 2.13 (works on 2.15+) with the following result:
>>
>> --- -	2022-01-26 21:33:15.713282778 +0000
>> +++
>> /home/runner/work/ovs/ovs/openvswitch-2.13.7/_build/sub/tests/testsuite.dir/at-groups/2302/stdout
>> 2022-01-26 21:33:15.708679313 +0000
>> @@ -1,4 +1,4 @@
>> +ct_state(+inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(frag=no),
>> packets:0, bytes:0, used:never, actions:drop
>>  ct_state(+new-inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(proto=1,frag=no),
>> packets:0, bytes:0, used:never, actions:2
>> -ct_state(+new-inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(proto=2,frag=no),
>> packets:0, bytes:0, used:never,
>> actions:userspace(controller(reason=1,dont_send=0,continuation=0,recirc_id=<recirc>,rule_cookie=0,controller_id=0,max_len=65535))
>>  recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(frag=no),
>> packets:0, bytes:0, used:0.0s, actions:ct(zone=64000),recirc(<recirc>)
>>
>> Packets seems to be marked +inv by conntrack.  Is it some kind
>> of conntrack issue that got fixed in 2.15 that we should backport?
>> Can we modify the test somehow to make it work on 2.13 ?
> 
> I'll look into it.  Thanks.
> 
>>> +
>>> +AT_CLEANUP
>>> diff --git a/tests/ofproto-macros.at b/tests/ofproto-macros.at
>>> index 736d9809cb..f906b5c3b5 100644
>>> --- a/tests/ofproto-macros.at
>>> +++ b/tests/ofproto-macros.at
>>> @@ -134,6 +134,21 @@ strip_ufid () {
>>>      sed 's/mega_ufid:[[-0-9a-f]]* //
>>>      s/ufid:[[-0-9a-f]]* //'
>>>  }
>>> +
>>> +# Strips packets: and bytes: from output
>>> +strip_stats () {
>>> +    sed 's/packets:[[0-9]]*/packets:0/
>>> +    s/bytes:[[0-9]]*/bytes:0/'
>>> +}
>>> +
>>> +# Changes all 'recirc(...)' and 'recirc=...' to say 'recirc(<recirc_id>)' and
>>> +# 'recirc=<recirc_id>' respectively.  This should make output easier to
>>> +# compare.
>>> +strip_recirc() {
>>> +   sed 's/recirc_id([[x0-9]]*)/recirc_id(<recirc>)/
>>> +        s/recirc_id=[[x0-9]]*/recirc_id=<recirc>/
>>> +        s/recirc([[x0-9]]*)/recirc(<recirc>)/'
>>> +}
>>>  m4_divert_pop([PREPARE_TESTS])
>>>  
>>>  m4_define([TESTABLE_LOG], [-vPATTERN:ANY:'%c|%p|%m'])
>>> diff --git a/tests/system-traffic.at b/tests/system-traffic.at
>>> index d79753a99a..5d9449fada 100644
>>> --- a/tests/system-traffic.at
>>> +++ b/tests/system-traffic.at
>>> @@ -6287,6 +6287,86 @@ AT_CHECK([ovs-ofctl dump-flows br0 | grep table=2, | OFPROTO_CLEAR_DURATION_IDLE
>>>  OVS_TRAFFIC_VSWITCHD_STOP
>>>  AT_CLEANUP
>>>  
>>> +AT_BANNER([IGMP])
>>> +
>>> +AT_SETUP([IGMP - flood under normal action])
>>> +
>>> +OVS_TRAFFIC_VSWITCHD_START()
>>> +ADD_NAMESPACES(at_ns0, at_ns1)
>>> +
>>> +ADD_VETH(p1, at_ns0, br0, "10.1.1.1/24", "f0:00:00:01:01:01")
>>> +ADD_VETH(p2, at_ns1, br0, "10.1.1.2/24", "f0:00:00:01:01:02")
>>> +
>>> +AT_CHECK([ovs-ofctl add-flow br0 "actions=NORMAL"])
>>> +
>>> +NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 01 00 5e 01 01 03 dnl
>>> +f0 00 00 01 01 01 08 00 46 c0 00 28 00 00 40 00 01 02 d3 49 45 65 eb 4a e0 dnl
>>> +00 00 16 94 04 00 00 22 00 f9 02 00 00 00 01 04 00 00 00 e0 00 00 fb 00 00 dnl
>>> +00 00 00 00 > /dev/null])
>>> +
>>> +AT_CHECK([ovs-appctl dpif/show | grep -v missed:], [0], [dnl
>>> +  br0:
>>> +    br0 65534/1: (internal)
>>
>> This line is failing the system-userspace testsuite, because userspace
>> datapath reports 'tap' instead of 'internal'.  Suggesting a following
>> change:
>>
>> diff --git a/tests/system-traffic.at b/tests/system-traffic.at
>> index 1ba28f7ee..7711f14b0 100644
>> --- a/tests/system-traffic.at
>> +++ b/tests/system-traffic.at
>> @@ -6681,18 +6681,11 @@ f0 00 00 01 01 01 08 00 46 c0 00 28 00 00 40 00 01 02 d3 49 45 65 eb 4a e0 dnl
>>  00 00 16 94 04 00 00 22 00 f9 02 00 00 00 01 04 00 00 00 e0 00 00 fb 00 00 dnl
>>  00 00 00 00 > /dev/null])
>>  
>> -AT_CHECK([ovs-appctl dpif/show | grep -v missed:], [0], [dnl
>> -  br0:
>> -    br0 65534/1: (internal)
>> -    ovs-p1 1/2: (system)
>> -    ovs-p2 2/3: (system)
>> -])
>> -
>> -AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl
>> +AT_CHECK([ovs-appctl dpctl/dump-flows --names | grep -e .*ipv4 | sort | dnl
>>            strip_stats | strip_used | strip_recirc | dnl
>>            sed 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
>>                       [0], [dnl
>> -recirc_id(<recirc>),in_port(2),eth(src=f0:00:00:01:01:01,dst=01:00:5e:01:01:03),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:1,3
>> +recirc_id(<recirc>),in_port(ovs-p1),eth(src=f0:00:00:01:01:01,dst=01:00:5e:01:01:03),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:br0,ovs-p2
>>  ])
>>  OVS_TRAFFIC_VSWITCHD_STOP
>>  AT_CLEANUP
>> ---
>>
>> What do you think?
> 
> ACK - I'll pull that in.
> 
>>
>>> +    ovs-p1 1/2: (system)
>>> +    ovs-p2 2/3: (system)
>>> +])
>>> +
>>> +AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl
>>> +          strip_stats | strip_used | strip_recirc | dnl
>>> +          sed 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
>>> +                     [0], [dnl
>>> +recirc_id(<recirc>),in_port(2),eth(src=f0:00:00:01:01:01,dst=01:00:5e:01:01:03),eth_type(0x0800),ipv4(frag=no),
>>> packets:0, bytes:0, used:never, actions:1,3
>>> +])
>>> +OVS_TRAFFIC_VSWITCHD_STOP
>>> +AT_CLEANUP
>>> +
>>> +AT_SETUP([IGMP - forward with ICMP])
>>> +
>>> +OVS_TRAFFIC_VSWITCHD_START()
>>> +ADD_NAMESPACES(at_ns0, at_ns1)
>>> +
>>> +ADD_VETH(p1, at_ns0, br0, "10.1.1.1/24", "f0:00:00:01:01:01")
>>> +ADD_VETH(p2, at_ns1, br0, "10.1.1.2/24", "f0:00:00:01:01:02")
>>> +
>>> +AT_DATA([flows.txt], [dnl
>>> +table=0, arp actions=NORMAL
>>> +table=0, ip,in_port=1 actions=ct(table=1,zone=64000)
>>> +table=0, in_port=2 actions=output:1
>>> +table=1, ip,ct_state=+trk+inv actions=drop
>>> +table=1  ip,in_port=1,icmp,ct_state=+trk+new actions=output:2
>>> +table=1, in_port=1,ip,ct_state=+trk+new actions=controller(userdata=00.de.ad.be.ef.ca.fe.01)
>>> +table=1, in_port=1,ip,ct_state=+trk+est actions=output:2
>>> +])
>>> +AT_CHECK([ovs-ofctl del-flows br0])
>>> +AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
>>> +
>>> +dnl Send the IGMP, followed by a unicast ICMP - ensure we won't black hole
>>> +
>>> +NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 f0 00 00 01 01 02 dnl
>>> +f0 00 00 01 01 01 08 00 46 c0 00 28 00 00 40 00 01 02 d3 49 45 65 eb 4a e0 dnl
>>> +00 00 16 94 04 00 00 22 00 f9 02 00 00 00 01 04 00 00 00 e0 00 00 fb 00 00 dnl
>>> +00 00 00 00 > /dev/null])
>>> +
>>> +NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 f0 00 00 01 01 02 dnl
>>> +f0 00 00 01 01 01 08 00 45 00 00 1c 00 01 00 00 40 01 64 dc 0a 01 01 01 0a dnl
>>> +01 01 02 08 00 f7 ff ff ff ff ff > /dev/null])
>>> +
>>> +sleep 1
>>> +
>>> +AT_CHECK([ovs-ofctl dump-flows br0 | grep -v NXST | dnl
>>> +          strip_duration | grep -v arp | grep -v n_packets=0 | dnl
>>> +          grep -v 'in_port=2 actions=output:1' | dnl
>>> +          sed 's/n_bytes=[[0-9]]*/n_bytes=0/
>>> +               s/idle_age=[[0-9]]*/idle_age=0/
>>> +               s/n_packets=[[1-9]]/n_packets=0/' | sort], [0], [dnl
>>> + cookie=0x0, table=0, n_packets=0, n_bytes=0, idle_age=0,
>>> ip,in_port=1 actions=ct(table=1,zone=64000)
>>> + cookie=0x0, table=1, n_packets=0, n_bytes=0, idle_age=0,
>>> ct_state=+new+trk,icmp,in_port=1 actions=output:2
>>> + cookie=0x0, table=1, n_packets=0, n_bytes=0, idle_age=0,
>>> ct_state=+new+trk,ip,in_port=1
>>> actions=controller(userdata=00.de.ad.be.ef.ca.fe.01)
>>> +])
>>
>> These are OpenFlow rules.  Shouldn't we dump datapath flows, or
>> am I missing something?
> 
> IIRC, we use the openflow rules because they are wildly different
> datapath rules between the two, so we rely on these rules being hit.
> Additionally, in the kernel DP case, if ipv6 is enabled then some ND
> will occur and that will tamper with n_packets/n_bytes counters (which
> is why I clear it before doing the comparison).
> 
> I will look at the datapath flows again, but I believe the datapath
> action set is different because of the way controller() is implemented
> between the two (in the userspace DP, it can be a direct call, but in
> the kerneldp it needs to be a userspace call first).
> 
> So I guess I will look at this, but expect to keep it as-is.

OK.  I guess, the main check here is n_packets=[[1-9]].  Is that correct?
Maybe just a comment would be enough in that case.  It's not clear what
exactly we're testing here otherwise.

Best regards, Ilya Maximets.
Aaron Conole March 4, 2022, 9:26 p.m. UTC | #5
Ilya Maximets <i.maximets@ovn.org> writes:

> On 2/23/22 19:58, Aaron Conole wrote:
>> Ilya Maximets <i.maximets@ovn.org> writes:
>> 
>>> On 1/6/22 19:07, Aaron Conole wrote:
>>>> This reverts commit c645550bb249 ("odp-util: Always report
>>>> ODP_FIT_TOO_LITTLE for IGMP.")
>>>>
>>>> Always forcing a slow path action can result in some over-broad
>>>> flows which swallow all traffic and force them to userspace, as reported
>>>> in the thread at
>>>> https://mail.openvswitch.org/pipermail/ovs-dev/2021-September/387706.html
>>>> and at
>>>> https://mail.openvswitch.org/pipermail/ovs-dev/2021-September/387689.html
>>>>
>>>> Revert the ODP_FIT_TOO_LITTLE return for IGMP specifically.
>>>> Additionally, remove the userspace wc mask to prevent revalidator from
>>>> cycling flows.
>>>>
>>>> Fixes: c645550bb249 ("odp-util: Always report ODP_FIT_TOO_LITTLE for IGMP.")
>>>> Signed-off-by: Aaron Conole <aconole@redhat.com>
>>>> Acked-by: Eelco Chaudron <echaudro@redhat.com>
>>>> ---
>>>> v1->v2: Add unit test for coverage of mcast traffic when not doing snooping
>>>> v2->v3: Add a unit test for the non-dummy datapaths as well to demonstrate the
>>>>         matching issue.
>>>> v3->v4: Fix up the unit tests to be consistent when reporting dp flows.  Split
>>>>         IGMP unit test into two different tests.  Use a multicast eth addr for
>>>>         the FLOOD under NORMAL action case.
>>>>
>>>>  lib/odp-util.c               |  5 ---
>>>>  ofproto/ofproto-dpif-xlate.c |  1 -
>>>>  tests/mcast-snooping.at      | 68 ++++++++++++++++++++++++++++++
>>>>  tests/ofproto-macros.at      | 15 +++++++
>>>>  tests/system-traffic.at      | 80 ++++++++++++++++++++++++++++++++++++
>>>>  5 files changed, 163 insertions(+), 6 deletions(-)
>>>>
>>>> diff --git a/lib/odp-util.c b/lib/odp-util.c
>>>> index fbdfc7ad83..0f21ffe639 100644
>>>> --- a/lib/odp-util.c
>>>> +++ b/lib/odp-util.c
>>>> @@ -7132,11 +7132,6 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
>>>>                  }
>>>>              }
>>>>          }
>>>> -    } else if (src_flow->nw_proto == IPPROTO_IGMP
>>>> -               && src_flow->dl_type == htons(ETH_TYPE_IP)) {
>>>> -        /* OVS userspace parses the IGMP type, code, and group, but its
>>>> -         * datapaths do not, so there is always missing information. */
>>>> -        return ODP_FIT_TOO_LITTLE;
>>>>      }
>>>>      if (is_mask && expected_bit != OVS_KEY_ATTR_UNSPEC) {
>>>>          if ((flow->tp_src || flow->tp_dst) && flow->nw_proto != 0xff) {
>>>> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
>>>> index cafcd014ad..29d26cf9ac 100644
>>>> --- a/ofproto/ofproto-dpif-xlate.c
>>>> +++ b/ofproto/ofproto-dpif-xlate.c
>>>> @@ -3048,7 +3048,6 @@ xlate_normal(struct xlate_ctx *ctx)
>>>>               */
>>>>              ctx->xout->slow |= SLOW_ACTION;
>>>>  
>>>> -            memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
>>>>              if (mcast_snooping_is_membership(flow->tp_src) ||
>>>>                  mcast_snooping_is_query(flow->tp_src)) {
>>>>                  if (ctx->xin->allow_side_effects && ctx->xin->packet) {
>>>> diff --git a/tests/mcast-snooping.at b/tests/mcast-snooping.at
>>>> index 757cf7186e..e24f293a0c 100644
>>>> --- a/tests/mcast-snooping.at
>>>> +++ b/tests/mcast-snooping.at
>>>> @@ -216,3 +216,70 @@ AT_CHECK([ovs-appctl mdb/show br0], [0], [dnl
>>>>  ])
>>>>  
>>>>  AT_CLEANUP
>>>> +
>>>> +
>>>> +AT_SETUP([mcast - igmp flood for non-snoop enabled])
>>>> +OVS_VSWITCHD_START([])
>>>> +
>>>> +AT_CHECK([
>>>> +    ovs-vsctl set bridge br0 \
>>>> +    datapath_type=dummy], [0])
>>>> +
>>>> +add_of_ports br0 1 2
>>>> +
>>>> +AT_CHECK([ovs-ofctl add-flow br0 action=normal])
>>>> +
>>>> +ovs-appctl time/stop
>>>> +
>>>> +dnl Basic scenario - needs to flood for IGMP followed by unicast ICMP
>>>> +dnl in reverse direction
>>>> +AT_CHECK([ovs-appctl netdev-dummy/receive p1 \
>>>> +    '0101000c29a0aa55aa550001080046c00028000040000102d3494565eb4ae0000016940400002200f9020000000104000000e00000fb000000000000'])
>>>> +AT_CHECK([ovs-appctl netdev-dummy/receive p2 \
>>>> +    'aa55aa5500010101000c29a008004500001c00010000400164dc0a0101010a0101020800f7ffffffffff'])
>>>> +
>>>> +
>>>> +AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl
>>>> +          strip_stats | strip_used | strip_recirc | dnl
>>>> +          sed -e 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
>>>> +                     [0], [dnl
>>>> +recirc_id(<recirc>),in_port(1),eth(src=aa:55:aa:55:00:01,dst=01:01:00:0c:29:a0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:100,2
>>>> +recirc_id(<recirc>),in_port(2),eth(src=01:01:00:0c:29:a0,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:1
>>>> +])
>>>> +
>>>> +ovs-appctl time/warp 100000
>>>> +
>>>> +dnl Next we should clear the flows and install a complex case
>>>> +AT_CHECK([ovs-ofctl del-flows br0])
>>>> +
>>>> +AT_DATA([flows.txt], [dnl
>>>> +table=0, arp actions=NORMAL
>>>> +table=0, ip,in_port=1 actions=ct(table=1,zone=64000)
>>>> +table=0, in_port=2 actions=output:1
>>>> +table=1, ip,ct_state=+trk+inv actions=drop
>>>> +table=1  ip,in_port=1,icmp,ct_state=+trk+new actions=output:2
>>>> +table=1, in_port=1,ip,ct_state=+trk+new actions=controller(userdata=00.de.ad.be.ef.ca.fe.01)
>>>> +table=1, in_port=1,ip,ct_state=+trk+est actions=output:2
>>>> +])
>>>> +AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
>>>> +
>>>> +ovs-appctl time/warp 100000
>>>> +
>>>> +dnl Send the IGMP, followed by a unicast ICMP - ensure we won't black hole
>>>> +AT_CHECK([ovs-appctl netdev-dummy/receive p1 \
>>>> +    '0101000c29a0aa55aa550001080046c00028000040000102d3494565eb4ae0000016940400002200f9020000000104000000e00000fb000000000000'])
>>>> +AT_CHECK([ovs-appctl netdev-dummy/receive p1 \
>>>> +    'aa55aa550001aa55aa55000208004500001c00010000400164dc0a0101010a0101020800f7ffffffffff'])
>>>> +
>>>> +
>>>> +AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl
>>>> +          strip_stats | strip_used | strip_recirc | dnl
>>>> +          sed 's/pid=[[0-9]]*,//
>>>> +               s/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
>>>> +                     [0], [dnl
>>>> +ct_state(+new-inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(proto=1,frag=no), packets:0, bytes:0, used:never, actions:2
>>>> +ct_state(+new-inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(proto=2,frag=no), packets:0, bytes:0, used:never, actions:userspace(controller(reason=1,dont_send=0,continuation=0,recirc_id=<recirc>,rule_cookie=0,controller_id=0,max_len=65535))
>>>> +recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:0.0s, actions:ct(zone=64000),recirc(<recirc>)
>>>> +])
>>>
>>> I tried to backport the patch to earlier branches, but this test fails
>>> on 2.14 and 2.13 (works on 2.15+) with the following result:
>>>
>>> --- -	2022-01-26 21:33:15.713282778 +0000
>>> +++
>>> /home/runner/work/ovs/ovs/openvswitch-2.13.7/_build/sub/tests/testsuite.dir/at-groups/2302/stdout
>>> 2022-01-26 21:33:15.708679313 +0000
>>> @@ -1,4 +1,4 @@
>>> +ct_state(+inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(frag=no),
>>> packets:0, bytes:0, used:never, actions:drop
>>>  ct_state(+new-inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(proto=1,frag=no),
>>> packets:0, bytes:0, used:never, actions:2
>>> -ct_state(+new-inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(proto=2,frag=no),
>>> packets:0, bytes:0, used:never,
>>> actions:userspace(controller(reason=1,dont_send=0,continuation=0,recirc_id=<recirc>,rule_cookie=0,controller_id=0,max_len=65535))
>>>  recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(frag=no),
>>> packets:0, bytes:0, used:0.0s, actions:ct(zone=64000),recirc(<recirc>)
>>>
>>> Packets seems to be marked +inv by conntrack.  Is it some kind
>>> of conntrack issue that got fixed in 2.15 that we should backport?
>>> Can we modify the test somehow to make it work on 2.13 ?
>> 
>> I'll look into it.  Thanks.
>> 
>>>> +
>>>> +AT_CLEANUP
>>>> diff --git a/tests/ofproto-macros.at b/tests/ofproto-macros.at
>>>> index 736d9809cb..f906b5c3b5 100644
>>>> --- a/tests/ofproto-macros.at
>>>> +++ b/tests/ofproto-macros.at
>>>> @@ -134,6 +134,21 @@ strip_ufid () {
>>>>      sed 's/mega_ufid:[[-0-9a-f]]* //
>>>>      s/ufid:[[-0-9a-f]]* //'
>>>>  }
>>>> +
>>>> +# Strips packets: and bytes: from output
>>>> +strip_stats () {
>>>> +    sed 's/packets:[[0-9]]*/packets:0/
>>>> +    s/bytes:[[0-9]]*/bytes:0/'
>>>> +}
>>>> +
>>>> +# Changes all 'recirc(...)' and 'recirc=...' to say 'recirc(<recirc_id>)' and
>>>> +# 'recirc=<recirc_id>' respectively.  This should make output easier to
>>>> +# compare.
>>>> +strip_recirc() {
>>>> +   sed 's/recirc_id([[x0-9]]*)/recirc_id(<recirc>)/
>>>> +        s/recirc_id=[[x0-9]]*/recirc_id=<recirc>/
>>>> +        s/recirc([[x0-9]]*)/recirc(<recirc>)/'
>>>> +}
>>>>  m4_divert_pop([PREPARE_TESTS])
>>>>  
>>>>  m4_define([TESTABLE_LOG], [-vPATTERN:ANY:'%c|%p|%m'])
>>>> diff --git a/tests/system-traffic.at b/tests/system-traffic.at
>>>> index d79753a99a..5d9449fada 100644
>>>> --- a/tests/system-traffic.at
>>>> +++ b/tests/system-traffic.at
>>>> @@ -6287,6 +6287,86 @@ AT_CHECK([ovs-ofctl dump-flows br0 | grep table=2, | OFPROTO_CLEAR_DURATION_IDLE
>>>>  OVS_TRAFFIC_VSWITCHD_STOP
>>>>  AT_CLEANUP
>>>>  
>>>> +AT_BANNER([IGMP])
>>>> +
>>>> +AT_SETUP([IGMP - flood under normal action])
>>>> +
>>>> +OVS_TRAFFIC_VSWITCHD_START()
>>>> +ADD_NAMESPACES(at_ns0, at_ns1)
>>>> +
>>>> +ADD_VETH(p1, at_ns0, br0, "10.1.1.1/24", "f0:00:00:01:01:01")
>>>> +ADD_VETH(p2, at_ns1, br0, "10.1.1.2/24", "f0:00:00:01:01:02")
>>>> +
>>>> +AT_CHECK([ovs-ofctl add-flow br0 "actions=NORMAL"])
>>>> +
>>>> +NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 01 00 5e 01 01 03 dnl
>>>> +f0 00 00 01 01 01 08 00 46 c0 00 28 00 00 40 00 01 02 d3 49 45 65 eb 4a e0 dnl
>>>> +00 00 16 94 04 00 00 22 00 f9 02 00 00 00 01 04 00 00 00 e0 00 00 fb 00 00 dnl
>>>> +00 00 00 00 > /dev/null])
>>>> +
>>>> +AT_CHECK([ovs-appctl dpif/show | grep -v missed:], [0], [dnl
>>>> +  br0:
>>>> +    br0 65534/1: (internal)
>>>
>>> This line is failing the system-userspace testsuite, because userspace
>>> datapath reports 'tap' instead of 'internal'.  Suggesting a following
>>> change:
>>>
>>> diff --git a/tests/system-traffic.at b/tests/system-traffic.at
>>> index 1ba28f7ee..7711f14b0 100644
>>> --- a/tests/system-traffic.at
>>> +++ b/tests/system-traffic.at
>>> @@ -6681,18 +6681,11 @@ f0 00 00 01 01 01 08 00 46 c0 00 28 00 00 40 00 01 02 d3 49 45 65 eb 4a e0 dnl
>>>  00 00 16 94 04 00 00 22 00 f9 02 00 00 00 01 04 00 00 00 e0 00 00 fb 00 00 dnl
>>>  00 00 00 00 > /dev/null])
>>>  
>>> -AT_CHECK([ovs-appctl dpif/show | grep -v missed:], [0], [dnl
>>> -  br0:
>>> -    br0 65534/1: (internal)
>>> -    ovs-p1 1/2: (system)
>>> -    ovs-p2 2/3: (system)
>>> -])
>>> -
>>> -AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl
>>> +AT_CHECK([ovs-appctl dpctl/dump-flows --names | grep -e .*ipv4 | sort | dnl
>>>            strip_stats | strip_used | strip_recirc | dnl
>>>            sed 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
>>>                       [0], [dnl
>>> -recirc_id(<recirc>),in_port(2),eth(src=f0:00:00:01:01:01,dst=01:00:5e:01:01:03),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:1,3
>>> +recirc_id(<recirc>),in_port(ovs-p1),eth(src=f0:00:00:01:01:01,dst=01:00:5e:01:01:03),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:br0,ovs-p2
>>>  ])
>>>  OVS_TRAFFIC_VSWITCHD_STOP
>>>  AT_CLEANUP
>>> ---
>>>
>>> What do you think?
>> 
>> ACK - I'll pull that in.
>> 
>>>
>>>> +    ovs-p1 1/2: (system)
>>>> +    ovs-p2 2/3: (system)
>>>> +])
>>>> +
>>>> +AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl
>>>> +          strip_stats | strip_used | strip_recirc | dnl
>>>> +          sed 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
>>>> +                     [0], [dnl
>>>> +recirc_id(<recirc>),in_port(2),eth(src=f0:00:00:01:01:01,dst=01:00:5e:01:01:03),eth_type(0x0800),ipv4(frag=no),
>>>> packets:0, bytes:0, used:never, actions:1,3
>>>> +])
>>>> +OVS_TRAFFIC_VSWITCHD_STOP
>>>> +AT_CLEANUP
>>>> +
>>>> +AT_SETUP([IGMP - forward with ICMP])
>>>> +
>>>> +OVS_TRAFFIC_VSWITCHD_START()
>>>> +ADD_NAMESPACES(at_ns0, at_ns1)
>>>> +
>>>> +ADD_VETH(p1, at_ns0, br0, "10.1.1.1/24", "f0:00:00:01:01:01")
>>>> +ADD_VETH(p2, at_ns1, br0, "10.1.1.2/24", "f0:00:00:01:01:02")
>>>> +
>>>> +AT_DATA([flows.txt], [dnl
>>>> +table=0, arp actions=NORMAL
>>>> +table=0, ip,in_port=1 actions=ct(table=1,zone=64000)
>>>> +table=0, in_port=2 actions=output:1
>>>> +table=1, ip,ct_state=+trk+inv actions=drop
>>>> +table=1  ip,in_port=1,icmp,ct_state=+trk+new actions=output:2
>>>> +table=1, in_port=1,ip,ct_state=+trk+new actions=controller(userdata=00.de.ad.be.ef.ca.fe.01)
>>>> +table=1, in_port=1,ip,ct_state=+trk+est actions=output:2
>>>> +])
>>>> +AT_CHECK([ovs-ofctl del-flows br0])
>>>> +AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
>>>> +
>>>> +dnl Send the IGMP, followed by a unicast ICMP - ensure we won't black hole
>>>> +
>>>> +NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 f0 00 00 01 01 02 dnl
>>>> +f0 00 00 01 01 01 08 00 46 c0 00 28 00 00 40 00 01 02 d3 49 45 65 eb 4a e0 dnl
>>>> +00 00 16 94 04 00 00 22 00 f9 02 00 00 00 01 04 00 00 00 e0 00 00 fb 00 00 dnl
>>>> +00 00 00 00 > /dev/null])
>>>> +
>>>> +NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 f0 00 00 01 01 02 dnl
>>>> +f0 00 00 01 01 01 08 00 45 00 00 1c 00 01 00 00 40 01 64 dc 0a 01 01 01 0a dnl
>>>> +01 01 02 08 00 f7 ff ff ff ff ff > /dev/null])
>>>> +
>>>> +sleep 1
>>>> +
>>>> +AT_CHECK([ovs-ofctl dump-flows br0 | grep -v NXST | dnl
>>>> +          strip_duration | grep -v arp | grep -v n_packets=0 | dnl
>>>> +          grep -v 'in_port=2 actions=output:1' | dnl
>>>> +          sed 's/n_bytes=[[0-9]]*/n_bytes=0/
>>>> +               s/idle_age=[[0-9]]*/idle_age=0/
>>>> +               s/n_packets=[[1-9]]/n_packets=0/' | sort], [0], [dnl
>>>> + cookie=0x0, table=0, n_packets=0, n_bytes=0, idle_age=0,
>>>> ip,in_port=1 actions=ct(table=1,zone=64000)
>>>> + cookie=0x0, table=1, n_packets=0, n_bytes=0, idle_age=0,
>>>> ct_state=+new+trk,icmp,in_port=1 actions=output:2
>>>> + cookie=0x0, table=1, n_packets=0, n_bytes=0, idle_age=0,
>>>> ct_state=+new+trk,ip,in_port=1
>>>> actions=controller(userdata=00.de.ad.be.ef.ca.fe.01)
>>>> +])
>>>
>>> These are OpenFlow rules.  Shouldn't we dump datapath flows, or
>>> am I missing something?
>> 
>> IIRC, we use the openflow rules because they are wildly different
>> datapath rules between the two, so we rely on these rules being hit.
>> Additionally, in the kernel DP case, if ipv6 is enabled then some ND
>> will occur and that will tamper with n_packets/n_bytes counters (which
>> is why I clear it before doing the comparison).
>> 
>> I will look at the datapath flows again, but I believe the datapath
>> action set is different because of the way controller() is implemented
>> between the two (in the userspace DP, it can be a direct call, but in
>> the kerneldp it needs to be a userspace call first).
>> 
>> So I guess I will look at this, but expect to keep it as-is.
>
> OK.  I guess, the main check here is n_packets=[[1-9]].  Is that correct?
> Maybe just a comment would be enough in that case.  It's not clear what
> exactly we're testing here otherwise.

Makes sense.  Yes, that is the main check.  Perhaps we should explicitly
add a check like that as well.  I'll see what I can do.

> Best regards, Ilya Maximets.
diff mbox series

Patch

diff --git a/lib/odp-util.c b/lib/odp-util.c
index fbdfc7ad83..0f21ffe639 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -7132,11 +7132,6 @@  parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
                 }
             }
         }
-    } else if (src_flow->nw_proto == IPPROTO_IGMP
-               && src_flow->dl_type == htons(ETH_TYPE_IP)) {
-        /* OVS userspace parses the IGMP type, code, and group, but its
-         * datapaths do not, so there is always missing information. */
-        return ODP_FIT_TOO_LITTLE;
     }
     if (is_mask && expected_bit != OVS_KEY_ATTR_UNSPEC) {
         if ((flow->tp_src || flow->tp_dst) && flow->nw_proto != 0xff) {
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index cafcd014ad..29d26cf9ac 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -3048,7 +3048,6 @@  xlate_normal(struct xlate_ctx *ctx)
              */
             ctx->xout->slow |= SLOW_ACTION;
 
-            memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
             if (mcast_snooping_is_membership(flow->tp_src) ||
                 mcast_snooping_is_query(flow->tp_src)) {
                 if (ctx->xin->allow_side_effects && ctx->xin->packet) {
diff --git a/tests/mcast-snooping.at b/tests/mcast-snooping.at
index 757cf7186e..e24f293a0c 100644
--- a/tests/mcast-snooping.at
+++ b/tests/mcast-snooping.at
@@ -216,3 +216,70 @@  AT_CHECK([ovs-appctl mdb/show br0], [0], [dnl
 ])
 
 AT_CLEANUP
+
+
+AT_SETUP([mcast - igmp flood for non-snoop enabled])
+OVS_VSWITCHD_START([])
+
+AT_CHECK([
+    ovs-vsctl set bridge br0 \
+    datapath_type=dummy], [0])
+
+add_of_ports br0 1 2
+
+AT_CHECK([ovs-ofctl add-flow br0 action=normal])
+
+ovs-appctl time/stop
+
+dnl Basic scenario - needs to flood for IGMP followed by unicast ICMP
+dnl in reverse direction
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 \
+    '0101000c29a0aa55aa550001080046c00028000040000102d3494565eb4ae0000016940400002200f9020000000104000000e00000fb000000000000'])
+AT_CHECK([ovs-appctl netdev-dummy/receive p2 \
+    'aa55aa5500010101000c29a008004500001c00010000400164dc0a0101010a0101020800f7ffffffffff'])
+
+
+AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl
+          strip_stats | strip_used | strip_recirc | dnl
+          sed -e 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
+                     [0], [dnl
+recirc_id(<recirc>),in_port(1),eth(src=aa:55:aa:55:00:01,dst=01:01:00:0c:29:a0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:100,2
+recirc_id(<recirc>),in_port(2),eth(src=01:01:00:0c:29:a0,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:1
+])
+
+ovs-appctl time/warp 100000
+
+dnl Next we should clear the flows and install a complex case
+AT_CHECK([ovs-ofctl del-flows br0])
+
+AT_DATA([flows.txt], [dnl
+table=0, arp actions=NORMAL
+table=0, ip,in_port=1 actions=ct(table=1,zone=64000)
+table=0, in_port=2 actions=output:1
+table=1, ip,ct_state=+trk+inv actions=drop
+table=1  ip,in_port=1,icmp,ct_state=+trk+new actions=output:2
+table=1, in_port=1,ip,ct_state=+trk+new actions=controller(userdata=00.de.ad.be.ef.ca.fe.01)
+table=1, in_port=1,ip,ct_state=+trk+est actions=output:2
+])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+
+ovs-appctl time/warp 100000
+
+dnl Send the IGMP, followed by a unicast ICMP - ensure we won't black hole
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 \
+    '0101000c29a0aa55aa550001080046c00028000040000102d3494565eb4ae0000016940400002200f9020000000104000000e00000fb000000000000'])
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 \
+    'aa55aa550001aa55aa55000208004500001c00010000400164dc0a0101010a0101020800f7ffffffffff'])
+
+
+AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl
+          strip_stats | strip_used | strip_recirc | dnl
+          sed 's/pid=[[0-9]]*,//
+               s/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
+                     [0], [dnl
+ct_state(+new-inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(proto=1,frag=no), packets:0, bytes:0, used:never, actions:2
+ct_state(+new-inv+trk),recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(proto=2,frag=no), packets:0, bytes:0, used:never, actions:userspace(controller(reason=1,dont_send=0,continuation=0,recirc_id=<recirc>,rule_cookie=0,controller_id=0,max_len=65535))
+recirc_id(<recirc>),in_port(1),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:0.0s, actions:ct(zone=64000),recirc(<recirc>)
+])
+
+AT_CLEANUP
diff --git a/tests/ofproto-macros.at b/tests/ofproto-macros.at
index 736d9809cb..f906b5c3b5 100644
--- a/tests/ofproto-macros.at
+++ b/tests/ofproto-macros.at
@@ -134,6 +134,21 @@  strip_ufid () {
     sed 's/mega_ufid:[[-0-9a-f]]* //
     s/ufid:[[-0-9a-f]]* //'
 }
+
+# Strips packets: and bytes: from output
+strip_stats () {
+    sed 's/packets:[[0-9]]*/packets:0/
+    s/bytes:[[0-9]]*/bytes:0/'
+}
+
+# Changes all 'recirc(...)' and 'recirc=...' to say 'recirc(<recirc_id>)' and
+# 'recirc=<recirc_id>' respectively.  This should make output easier to
+# compare.
+strip_recirc() {
+   sed 's/recirc_id([[x0-9]]*)/recirc_id(<recirc>)/
+        s/recirc_id=[[x0-9]]*/recirc_id=<recirc>/
+        s/recirc([[x0-9]]*)/recirc(<recirc>)/'
+}
 m4_divert_pop([PREPARE_TESTS])
 
 m4_define([TESTABLE_LOG], [-vPATTERN:ANY:'%c|%p|%m'])
diff --git a/tests/system-traffic.at b/tests/system-traffic.at
index d79753a99a..5d9449fada 100644
--- a/tests/system-traffic.at
+++ b/tests/system-traffic.at
@@ -6287,6 +6287,86 @@  AT_CHECK([ovs-ofctl dump-flows br0 | grep table=2, | OFPROTO_CLEAR_DURATION_IDLE
 OVS_TRAFFIC_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_BANNER([IGMP])
+
+AT_SETUP([IGMP - flood under normal action])
+
+OVS_TRAFFIC_VSWITCHD_START()
+ADD_NAMESPACES(at_ns0, at_ns1)
+
+ADD_VETH(p1, at_ns0, br0, "10.1.1.1/24", "f0:00:00:01:01:01")
+ADD_VETH(p2, at_ns1, br0, "10.1.1.2/24", "f0:00:00:01:01:02")
+
+AT_CHECK([ovs-ofctl add-flow br0 "actions=NORMAL"])
+
+NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 01 00 5e 01 01 03 dnl
+f0 00 00 01 01 01 08 00 46 c0 00 28 00 00 40 00 01 02 d3 49 45 65 eb 4a e0 dnl
+00 00 16 94 04 00 00 22 00 f9 02 00 00 00 01 04 00 00 00 e0 00 00 fb 00 00 dnl
+00 00 00 00 > /dev/null])
+
+AT_CHECK([ovs-appctl dpif/show | grep -v missed:], [0], [dnl
+  br0:
+    br0 65534/1: (internal)
+    ovs-p1 1/2: (system)
+    ovs-p2 2/3: (system)
+])
+
+AT_CHECK([ovs-appctl dpctl/dump-flows | grep -e .*ipv4 | sort | dnl
+          strip_stats | strip_used | strip_recirc | dnl
+          sed 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/'],
+                     [0], [dnl
+recirc_id(<recirc>),in_port(2),eth(src=f0:00:00:01:01:01,dst=01:00:5e:01:01:03),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:1,3
+])
+OVS_TRAFFIC_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([IGMP - forward with ICMP])
+
+OVS_TRAFFIC_VSWITCHD_START()
+ADD_NAMESPACES(at_ns0, at_ns1)
+
+ADD_VETH(p1, at_ns0, br0, "10.1.1.1/24", "f0:00:00:01:01:01")
+ADD_VETH(p2, at_ns1, br0, "10.1.1.2/24", "f0:00:00:01:01:02")
+
+AT_DATA([flows.txt], [dnl
+table=0, arp actions=NORMAL
+table=0, ip,in_port=1 actions=ct(table=1,zone=64000)
+table=0, in_port=2 actions=output:1
+table=1, ip,ct_state=+trk+inv actions=drop
+table=1  ip,in_port=1,icmp,ct_state=+trk+new actions=output:2
+table=1, in_port=1,ip,ct_state=+trk+new actions=controller(userdata=00.de.ad.be.ef.ca.fe.01)
+table=1, in_port=1,ip,ct_state=+trk+est actions=output:2
+])
+AT_CHECK([ovs-ofctl del-flows br0])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+
+dnl Send the IGMP, followed by a unicast ICMP - ensure we won't black hole
+
+NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 f0 00 00 01 01 02 dnl
+f0 00 00 01 01 01 08 00 46 c0 00 28 00 00 40 00 01 02 d3 49 45 65 eb 4a e0 dnl
+00 00 16 94 04 00 00 22 00 f9 02 00 00 00 01 04 00 00 00 e0 00 00 fb 00 00 dnl
+00 00 00 00 > /dev/null])
+
+NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p1 f0 00 00 01 01 02 dnl
+f0 00 00 01 01 01 08 00 45 00 00 1c 00 01 00 00 40 01 64 dc 0a 01 01 01 0a dnl
+01 01 02 08 00 f7 ff ff ff ff ff > /dev/null])
+
+sleep 1
+
+AT_CHECK([ovs-ofctl dump-flows br0 | grep -v NXST | dnl
+          strip_duration | grep -v arp | grep -v n_packets=0 | dnl
+          grep -v 'in_port=2 actions=output:1' | dnl
+          sed 's/n_bytes=[[0-9]]*/n_bytes=0/
+               s/idle_age=[[0-9]]*/idle_age=0/
+               s/n_packets=[[1-9]]/n_packets=0/' | sort], [0], [dnl
+ cookie=0x0,  table=0, n_packets=0, n_bytes=0, idle_age=0, ip,in_port=1 actions=ct(table=1,zone=64000)
+ cookie=0x0,  table=1, n_packets=0, n_bytes=0, idle_age=0, ct_state=+new+trk,icmp,in_port=1 actions=output:2
+ cookie=0x0,  table=1, n_packets=0, n_bytes=0, idle_age=0, ct_state=+new+trk,ip,in_port=1 actions=controller(userdata=00.de.ad.be.ef.ca.fe.01)
+])
+
+OVS_TRAFFIC_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_BANNER([802.1ad])
 
 AT_SETUP([802.1ad - vlan_limit])