Ilya Maximets <i.maxim...@ovn.org> 于2023年8月12日周六 02:18写道:

> On 8/11/23 19:37, Ilya Maximets wrote:
> > On 8/9/23 05:02, Peng He wrote:
> >> OVS allows overlapping megaflows, as long as the actions of these
> >> megaflows are equal. However, the current implementation of action
> >> modification relies on flow_lookup instead of ufid, this could result
> >> in looking up a wrong megaflow and make the ukeys and megaflows
> inconsistent
> >>
> >> Just like the test case in the patch, at first we have a rule with the
> >> prefix:
> >>
> >> 10.1.2.0/24
> >>
> >> and we will get a megaflow with prefixes 10.1.2.2/24 when a packet
> with IP
> >> 10.1.2.2 is received.
> >>
> >> Then suppose we change the rule into 10.1.0.0/16. OVS prefers to keep
> the
> >> 10.1.2.2/24 megaflow and just changes its action instead of extending
> >> the prefix into 10.1.2.2/16.
> >>
> >> then suppose we have a 10.1.0.2 packet, since it misses the megaflow,
> >> this time, we will have an overlapping megaflow with the right prefix:
> >> 10.1.0.2/16
> >>
> >> now we have two megaflows:
> >> 10.1.2.2/24
> >> 10.1.0.2/16
> >>
> >> last, suppose we have changed the ruleset again. The revalidator this
> >> time still decides to change the actions of both megaflows instead of
> >> deleting them.
> >>
> >> The dpif_netdev_flow_put will search the megaflow to modify with
> unmasked
> >> keys, however it might lookup the wrong megaflow as the key 10.1.2.2
> matches
> >> both 10.1.2.2/24 and 10.1.0.2/16!
> >>
> >> This patch changes the megaflow lookup code in modification path into
> >> relying the ufid to find the correct megaflow instead of key lookup.
> >>
> >> Signed-off-by: Peng He <hepeng.0...@bytedance.com>
> >> ---
> >>  lib/dpif-netdev.c | 45 ++++++++++++++++++++++++++++++---------------
> >>  tests/pmd.at      | 47 +++++++++++++++++++++++++++++++++++++++++++++++
> >>  2 files changed, 77 insertions(+), 15 deletions(-)
> >>
> >> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> >> index 70b953ae6..8479630b8 100644
> >> --- a/lib/dpif-netdev.c
> >> +++ b/lib/dpif-netdev.c
> >> @@ -4191,7 +4191,7 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd,
> >>                  const struct dpif_flow_put *put,
> >>                  struct dpif_flow_stats *stats)
> >>  {
> >> -    struct dp_netdev_flow *netdev_flow;
> >> +    struct dp_netdev_flow *netdev_flow = NULL;
> >>      int error = 0;
> >>
> >>      if (stats) {
> >> @@ -4199,16 +4199,35 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread
> *pmd,
> >>      }
> >>
> >>      ovs_mutex_lock(&pmd->flow_mutex);
> >> -    netdev_flow = dp_netdev_pmd_lookup_flow(pmd, key, NULL);
> >> -    if (!netdev_flow) {
> >> -        if (put->flags & DPIF_FP_CREATE) {
> >> -            dp_netdev_flow_add(pmd, match, ufid, put->actions,
> >> -                               put->actions_len, ODPP_NONE);
> >> +    if (put->ufid) {
> >> +        netdev_flow = dp_netdev_pmd_find_flow(pmd, put->ufid,
> >> +                                              put->key, put->key_len);
> >> +    } else {
> >> +        /* Use key instead of the locally generated ufid
> >> +         * to search netdev_flow. */
> >> +        netdev_flow = dp_netdev_pmd_lookup_flow(pmd, key, NULL);
> >> +    }
> >> +
> >> +    if (put->flags & DPIF_FP_CREATE) {
> >> +        if (!netdev_flow) {
> >> +            dp_netdev_flow_add(pmd, match, ufid,
> >> +                               put->actions, put->actions_len,
> ODPP_NONE);
> >>          } else {
> >> -            error = ENOENT;
> >> +            error = EEXIST;
> >>          }
> >> -    } else {
> >> -        if (put->flags & DPIF_FP_MODIFY) {
> >> +        goto exit;
> >> +    }
> >> +
> >> +    if (put->flags & DPIF_FP_MODIFY) {
> >> +        if (!netdev_flow) {
> >> +            error = ENOENT;
> >> +        } else {
> >> +            if (!put->ufid && !flow_equal(&match->flow,
> &netdev_flow->flow)) {
> >> +                /* Overlapping flow. */
> >> +                error = EINVAL;
> >> +                goto exit;
> >> +            }
> >> +
> >>              struct dp_netdev_actions *new_actions;
> >>              struct dp_netdev_actions *old_actions;
> >>
> >> @@ -4239,15 +4258,11 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread
> *pmd,
> >>                   *   counter, and subtracting it before outputting the
> stats */
> >>                  error = EOPNOTSUPP;
> >>              }
> >> -
> >>              ovsrcu_postpone(dp_netdev_actions_free, old_actions);
> >> -        } else if (put->flags & DPIF_FP_CREATE) {
> >> -            error = EEXIST;
> >> -        } else {
> >> -            /* Overlapping flow. */
> >> -            error = EINVAL;
> >>          }
> >>      }
> >> +
> >> +exit:
> >>      ovs_mutex_unlock(&pmd->flow_mutex);
> >>      return error;
> >>  }
> >> diff --git a/tests/pmd.at b/tests/pmd.at
> >> index 48f3d432d..b03cd831e 100644
> >> --- a/tests/pmd.at
> >> +++ b/tests/pmd.at
> >> @@ -1300,3 +1300,50 @@ OVS_WAIT_UNTIL([tail -n +$LINENUM
> ovs-vswitchd.log | grep "PMD load based sleeps
> >>
> >>  OVS_VSWITCHD_STOP
> >>  AT_CLEANUP
> >> +
> >> +AT_SETUP([PMD - revalidator wrongly modify userspace megaflows])
> >> +
> >> +OVS_VSWITCHD_START(
> >> +[add-port br0 p1 \
> >> +   -- set bridge br0 datapath-type=dummy \
> >> +   -- set interface p1 type=dummy-pmd \
> >> +   -- add-port br0 p2 \
> >> +   -- set interface p2 type=dummy-pmd
> >> +])
>
> OK.  I found the reason why the test is failing on FreeSBD.
> OVS doesn't implement CPU/NUMA discovery on non-linux systems,
> so dummy NUMA configuration has to be provided in order for
> OVS to actually create PMD threads.  Without dummy NUMA config
> no threads are started and so no traffic is forwarded.
>

I see. will fix it in the next version.

>
> See other tests in the fie on how dummy NUMA is provided in
> the OVS_VSWITCHD_START macro.
>
> >> +
> >> +dnl Add one openflow rule and generate a megaflow.
> >> +AT_CHECK([ovs-ofctl add-flow br0 'table=0,in_port=p1,ip,nw_dst=
> 10.1.2.0/24,actions=p2'])
> >> +AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'ipv4(src=10.0.0.1,dst=10.1.2.2),tcp(src=1,dst=2)'])
>
> Not very important, but this packet is invalid.
> You're no specifying important fields of ipv4 header, for
> example the ipv4.proto is not set and hence equals zero.
> In this case the tcp configuration is considered invalid,
> because it's not a tcp packet.
>

Ok, will fix it in the next version.

>
> It's not an OpenFlow formatting and OVS doesn't fill out any
> missing fields.  Everything that is missing will be zero.
> It's better to provide a correct packet here and below in
> the test to avoid potential issues in the future.
>
> Best regards, Ilya Maximets.
>
> >> +
> >> +OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/dump-flows | sed 's/.*core:
> [[0-9]]*//'], [
> >>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=
> 10.1.2.2/255.255.255.0,frag=no), packets:0, bytes:0, used:never,
> actions:2])
> >
> > For some reason this check keeps failing on FreeBSD.  Investigating...
> >
> > Best regards, Ilya Maximets.
> >
> >> +
> >> +AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'ipv4(src=10.0.0.1,dst=10.1.2.2),tcp(src=1,dst=2)'])
> >> +dnl Replace openflow rules, trigger the revalidation.
> >> +AT_CHECK([echo 'table=0,in_port=p1,ip,nw_dst=10.1.0.0/16
> actions=ct(commit)' | dnl
> >> +          ovs-ofctl --bundle replace-flows br0 -])
> >> +AT_CHECK([ovs-appctl revalidator/wait])
> >> +
> >> +AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'ipv4(src=10.0.0.1,dst=10.1.0.2),tcp(src=1,dst=2)'])
> >> +OVS_WAIT_UNTIL_EQUAL([ovs-appctl dpctl/dump-flows | sed 's/.*core:
> [[0-9]]*//' | strip_xout_keep_actions], [
> >>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=
> 10.1.0.2/255.255.0.0,frag=no), packets:0, bytes:0, used:never,
> actions:ct(commit)
> >>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=
> 10.1.2.2/255.255.255.0,frag=no), packets:0, bytes:0, used:0.0s,
> actions:ct(commit)])
> >> +
> >> +dnl Hold the prefix 10.1.2.2/24 by another 10s.
> >> +AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'ipv4(src=10.0.0.1,dst=10.1.2.2),tcp(src=1,dst=2)'])
> >> +dnl Send more 10.1.0.2 to make 10.1.0.0/16 tuple preprend 10.1.2.0/24
> tuple in the pvector of subtables.
> >> +for i in $(seq 0 256); do
> >> +    AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'ipv4(src=10.0.0.1,dst=10.1.0.2),tcp(src=1,dst=2)'])
> >> +done
> >> +
> >> +AT_CHECK([echo 'table=0,in_port=p1,ip,nw_dst=10.1.0.0/16 actions=p2'
> | dnl
> >> +          ovs-ofctl --bundle replace-flows br0 -])
> >> +
> >> +AT_CHECK([ovs-appctl revalidator/wait])
> >> +AT_CHECK([ovs-appctl dpctl/dump-flows | sed 's/.*core: [[0-9]]*//' |
> strip_xout_keep_actions], [0], [
> >>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=
> 10.1.0.2/255.255.0.0,frag=no), packets:0, bytes:0, used:0.0s, actions:2
> >>
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=
> 10.1.2.2/255.255.255.0,frag=no), packets:0, bytes:0, used:0.0s, actions:2
> >> +])
> >> +
> >> +OVS_VSWITCHD_STOP
> >> +AT_CLEANUP
> >
>
>

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

Reply via email to