Eelco Chaudron <echau...@redhat.com> 于2023年7月5日周三 21:24写道:

>
>
> On 1 Jul 2023, at 7:11, Peng He wrote:
>
> > push_dp_ops only handles delete ops errors but ignores the modify
> > ops results. It's better to handle all the dp operation errors in
> > a consistent way.
> >
> > This patch prevents the inconsistency by considering modify failure
> > in revalidators.
> >
> > To note, we cannot perform two state transitions and change ukey_state
> > into UKEY_EVICTED directly here, because, if we do so, the
> > sweep will remove the ukey alone and leave dp flow alive. Later, the
> > dump will retrieve the dp flow and might even recover it. This will
> > contribute the stats of this dp flow twice.
> >
> > v8->v9:   add testsuite and delete INCONSISTENT ukey at revalidate_sweep.
> > v9->v10:  change the commit message and refine the test case.
> > v10->v11: fix indentation and refine the test case.
> > v11->v12: fix the test suite.
> >
> > Signed-off-by: Peng He <hepeng.0...@bytedance.com>
>
> Thanks for fixing the comments on v11. The changes look good, with one
> little nit (see below), but those can be applied during commit.
>
> Acked-by: Eelco Chaudron <echau...@redhat.com>
>
> > ---
> >  ofproto/ofproto-dpif-upcall.c | 50 +++++++++++++++++++++++++----------
> >  tests/dpif-netdev.at          | 43 ++++++++++++++++++++++++++++++
> >  2 files changed, 79 insertions(+), 14 deletions(-)
> >
> > diff --git a/ofproto/ofproto-dpif-upcall.c
> b/ofproto/ofproto-dpif-upcall.c
> > index 04b583f81..cde03abc6 100644
> > --- a/ofproto/ofproto-dpif-upcall.c
> > +++ b/ofproto/ofproto-dpif-upcall.c
> > @@ -53,6 +53,7 @@
> >  VLOG_DEFINE_THIS_MODULE(ofproto_dpif_upcall);
> >
> >  COVERAGE_DEFINE(dumped_duplicate_flow);
> > +COVERAGE_DEFINE(dumped_inconsistent_flow);
> >  COVERAGE_DEFINE(dumped_new_flow);
> >  COVERAGE_DEFINE(handler_duplicate_upcall);
> >  COVERAGE_DEFINE(revalidate_missed_dp_flow);
> > @@ -258,6 +259,7 @@ enum ukey_state {
> >      UKEY_CREATED = 0,
> >      UKEY_VISIBLE,       /* Ukey is in umap, datapath flow install is
> queued. */
> >      UKEY_OPERATIONAL,   /* Ukey is in umap, datapath flow is installed.
> */
> > +    UKEY_INCONSISTENT,  /* Ukey is in umap, datapath flow is
> inconsistent. */
> >      UKEY_EVICTING,      /* Ukey is in umap, datapath flow delete is
> queued. */
> >      UKEY_EVICTED,       /* Ukey is in umap, datapath flow is deleted. */
> >      UKEY_DELETED,       /* Ukey removed from umap, ukey free is
> deferred. */
> > @@ -1999,6 +2001,10 @@ transition_ukey_at(struct udpif_key *ukey, enum
> ukey_state dst,
> >       * UKEY_VISIBLE -> UKEY_EVICTED
> >       *  A handler attempts to install the flow, but the datapath
> rejects it.
> >       *  Consider that the datapath has already destroyed it.
> > +     * UKEY_OPERATIONAL -> UKEY_INCONSISTENT
> > +     *  A revalidator modifies the flow with error returns.
> > +     * UKEY_INCONSISTENT -> UKEY_EVICTING
> > +     *  A revalidator decides to evict the datapath flow.
> >       * UKEY_OPERATIONAL -> UKEY_EVICTING
> >       *  A revalidator decides to evict the datapath flow.
> >       * UKEY_EVICTING    -> UKEY_EVICTED
> > @@ -2006,8 +2012,9 @@ transition_ukey_at(struct udpif_key *ukey, enum
> ukey_state dst,
> >       * UKEY_EVICTED     -> UKEY_DELETED
> >       *  A revalidator has removed the ukey from the umap and is
> deleting it.
> >       */
> > -    if (ukey->state == dst - 1 || (ukey->state == UKEY_VISIBLE &&
> > -                                   dst < UKEY_DELETED)) {
> > +    if (ukey->state == dst - 1 ||
> > +       (ukey->state == UKEY_VISIBLE && dst < UKEY_DELETED) ||
> > +       (ukey->state == UKEY_OPERATIONAL && dst == UKEY_EVICTING)) {
> >          ukey->state = dst;
> >      } else {
> >          struct ds ds = DS_EMPTY_INITIALIZER;
> > @@ -2490,26 +2497,31 @@ push_dp_ops(struct udpif *udpif, struct ukey_op
> *ops, size_t n_ops)
> >
> >      for (i = 0; i < n_ops; i++) {
> >          struct ukey_op *op = &ops[i];
> > -        struct dpif_flow_stats *push, *stats, push_buf;
> > -
> > -        stats = op->dop.flow_del.stats;
> > -        push = &push_buf;
> > -
> > -        if (op->dop.type != DPIF_OP_FLOW_DEL) {
> > -            /* Only deleted flows need their stats pushed. */
> > -            continue;
> > -        }
> >
> >          if (op->dop.error) {
> > -            /* flow_del error, 'stats' is unusable. */
> >              if (op->ukey) {
> >                  ovs_mutex_lock(&op->ukey->mutex);
> > -                transition_ukey(op->ukey, UKEY_EVICTED);
> > +                if (op->dop.type == DPIF_OP_FLOW_DEL) {
> > +                    transition_ukey(op->ukey, UKEY_EVICTED);
> > +                } else {
> > +                    /* Modification of the flow failed. */
> > +                    transition_ukey(op->ukey, UKEY_INCONSISTENT);
> > +                }
> >                  ovs_mutex_unlock(&op->ukey->mutex);
> >              }
> >              continue;
> >          }
> >
> > +        if (op->dop.type != DPIF_OP_FLOW_DEL) {
> > +            /* Only deleted flows need their stats pushed. */
> > +            continue;
> > +        }
> > +
> > +        struct dpif_flow_stats *push, *stats, push_buf;
> > +
> > +        stats = op->dop.flow_del.stats;
> > +        push = &push_buf;
> > +
> >          if (op->ukey) {
> >              ovs_mutex_lock(&op->ukey->mutex);
> >              transition_ukey(op->ukey, UKEY_EVICTED);
> > @@ -2857,6 +2869,15 @@ revalidate(struct revalidator *revalidator)
> >                  continue;
> >              }
> >
> > +            if (ukey->state == UKEY_INCONSISTENT) {
> > +                ukey->dump_seq = dump_seq;
> > +                reval_op_init(&ops[n_ops++], UKEY_DELETE, udpif, ukey,
> > +                              &recircs, &odp_actions);
> > +                ovs_mutex_unlock(&ukey->mutex);
> > +                COVERAGE_INC(dumped_inconsistent_flow);
> > +                continue;
> > +            }
> > +
> >              if (ukey->state <= UKEY_OPERATIONAL) {
> >                  /* The flow is now confirmed to be in the datapath. */
> >                  transition_ukey(ukey, UKEY_OPERATIONAL);
> > @@ -2945,13 +2966,14 @@ revalidator_sweep__(struct revalidator
> *revalidator, bool purge)
> >              }
> >              ukey_state = ukey->state;
> >              if (ukey_state == UKEY_OPERATIONAL
> > +                || (ukey_state == UKEY_INCONSISTENT)
> >                  || (ukey_state == UKEY_VISIBLE && purge)) {
> >                  struct recirc_refs recircs =
> RECIRC_REFS_EMPTY_INITIALIZER;
> >                  bool seq_mismatch = (ukey->dump_seq != dump_seq
> >                                       && ukey->reval_seq != reval_seq);
> >                  enum reval_result result;
> >
> > -                if (purge) {
> > +                if (purge || ukey_state == UKEY_INCONSISTENT) {
> >                      result = UKEY_DELETE;
> >                  } else if (!seq_mismatch) {
> >                      result = UKEY_KEEP;
> > diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at
> > index 67adf27fb..ce7662aca 100644
> > --- a/tests/dpif-netdev.at
> > +++ b/tests/dpif-netdev.at
> > @@ -812,3 +812,46 @@ AT_CHECK([tail -n 1 p2.pcap.txt], [0], [dnl
> >  ])
> >  OVS_VSWITCHD_STOP
> >  AT_CLEANUP
> > +
> > +AT_SETUP([dpif-netdev - revalidators handle dp modification fail
> correctly])
> > +OVS_VSWITCHD_START(
> > +  [add-port br0 p1 \
> > +   -- set interface p1 type=dummy \
> > +   -- set bridge br0 datapath-type=dummy \
> > +   -- add-port br0 p2 \
> > +   -- set interface p2 type=dummy --
> > +   ])
> > +
> > +AT_CHECK([ovs-ofctl add-flow br0 'table=0,in_port=p1,actions=p2'])
> > +AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'ipv4(src=10.0.0.1,dst=10.0.0.2),tcp(src=1,dst=2)'])
> > +AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'ipv4(src=10.0.0.1,dst=10.0.0.2),tcp(src=1,dst=2)'])
> > +
> > +AT_CHECK([ovs-appctl dpctl/dump-flows | sed 's/.*thread://' |
> strip_xout_keep_actions ], [0], [
> >
> +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no),
> packets:0, bytes:0, used:0.0s, actions:2
> > +])
> > +
> > +dnl Wait for the dp flow to enter OPERATIONAL state.
> > +AT_CHECK([ovs-appctl revalidator/wait])
> > +
> > +AT_CHECK([ovs-appctl revalidator/pause])
> > +
> > +dnl Delete all dp flows, so flow modification will fail.
> > +AT_CHECK([ovs-appctl dpctl/del-flows])
> > +
> > +AT_CHECK([ovs-appctl revalidator/resume])
> > +
> > +dnl Replace OpenFlow rules, trigger revalidation and wait for it to
> complete.
> > +AT_CHECK([echo 'table=0,in_port=p1,ip actions=ct(commit)' | ovs-ofctl
> --bundle replace-flows br0 -])
> > +AT_CHECK([ovs-appctl revalidator/wait])
> > +
> > +dnl Inconsistent ukey should be deleted.
> > +AT_CHECK([ovs-appctl upcall/show | grep keys | grep -q -v 0], [1])
> > +
> > +dnl Check the log for the flow modification error.
> > +AT_CHECK([grep -q -E ".*failed to put.*$" ovs-vswitchd.log])
> > +
> > +dnl Remove warning logs to let test suite pass.
> > +OVS_VSWITCHD_STOP(["dnl
> > +/.*failed to put.*$/d
> > +/.*failed to flow_del.*$/d"])
>
> You missed the indentation suggested by Ilya:
>
>
Which kind of the email client are you using...
The indentation here is really easy to miss....



>
>
>  dnl Remove warning logs to let test suite pass.
>  OVS_VSWITCHD_STOP(["dnl
> -/.*failed to put.*$/d
> -/.*failed to flow_del.*$/d"])
> +  /.*failed to put.*$/d
> +  /.*failed to flow_del.*$/d"])
>  AT_CLEANUP
>
>
> > +AT_CLEANUP
> > --
> > 2.25.1
>
>

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

Reply via email to