Ilya Maximets <[email protected]> 于2023年6月23日周五 20:40写道:

> On 6/23/23 14:20, Eelco Chaudron wrote:
> >
> >
> > On 9 Jun 2023, at 17:03, 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.
> >>
> >> Signed-off-by: Peng He <[email protected]>
> >
> > Thanks for making these changes, there is a merge conflict on the tests
> case and some small comments below.
> >
> > So maybe you can send a v12 and I’ll do a quick check and ACK it. What
> do you think?
> >
> > Cheers,
> >
> > Eelco
> >
> >
> >> ---
> >>  ofproto/ofproto-dpif-upcall.c | 51 +++++++++++++++++++++++++----------
> >>  tests/dpif-netdev.at          | 44 ++++++++++++++++++++++++++++++
> >>  2 files changed, 81 insertions(+), 14 deletions(-)
> >>
> >> diff --git a/ofproto/ofproto-dpif-upcall.c
> b/ofproto/ofproto-dpif-upcall.c
> >> index cd57fdbd9..c920c749c 100644
> >> --- a/ofproto/ofproto-dpif-upcall.c
> >> +++ b/ofproto/ofproto-dpif-upcall.c
> >> @@ -62,6 +62,7 @@ COVERAGE_DEFINE(upcall_flow_limit_hit);
> >>  COVERAGE_DEFINE(upcall_flow_limit_kill);
> >>  COVERAGE_DEFINE(upcall_ukey_contention);
> >>  COVERAGE_DEFINE(upcall_ukey_replace);
> >> +COVERAGE_DEFINE(dumped_inconsistent_flow);
> >
> > Can you add this in alphabetical order?
> >
> >>
> >>  /* A thread that reads upcalls from dpif, forwards each upcall's
> packet,
> >>   * and possibly sets up a kernel flow as a cache. */
> >> @@ -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;
> >> @@ -2472,26 +2479,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 */
> >
> > You forgot to copy the dot.
> >
> >> +                    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);
> >> @@ -2839,6 +2851,16 @@ revalidate(struct revalidator *revalidator)
> >>                  continue;
> >>              }
> >>
> >> +            if (ukey->state == UKEY_INCONSISTENT) {
> >> +                ukey->dump_seq = dump_seq;
> >> +                COVERAGE_INC(dumped_inconsistent_flow);
> >
> > I suggested moving the coverage counter outside of the mutex.
> >
> >> +                reval_op_init(&ops[n_ops++], UKEY_DELETE, udpif, ukey,
> >> +                              &recircs, &odp_actions);
> >> +                ovs_mutex_unlock(&ukey->mutex);
> >> +                continue;
> >> +            }
> >> +
> >> +
> >
> > One empty newline will be enough here.
> >
> >>              if (ukey->state <= UKEY_OPERATIONAL) {
> >>                  /* The flow is now confirmed to be in the datapath. */
> >>                  transition_ukey(ukey, UKEY_OPERATIONAL);
> >> @@ -2927,13 +2949,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 baab60a22..2d0dc14c1 100644
> >> --- a/tests/dpif-netdev.at
> >> +++ b/tests/dpif-netdev.at
> >> @@ -716,3 +716,47 @@ AT_CHECK([test `ovs-vsctl get Interface p2
> statistics:tx_q0_packets` -gt 0 -a dn
> >>
> >>  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 --
> >> +   ])
> >> +
> >> +ovs-ofctl add-flow br0 'table=0,in_port=p1,actions=p2'
> >> +ovs-appctl netdev-dummy/receive p1
> 'ipv4(src=10.0.0.1,dst=10.0.0.2),tcp(src=1,dst=2)'
> >> +ovs-appctl netdev-dummy/receive p1
> 'ipv4(src=10.0.0.1,dst=10.0.0.2),tcp(src=1,dst=2)'
>
> Could you, please, also wrap above commands in AT_CHECK ?
>
> sure. will send a new version.


> It not only checks the result, but it also adds these commands into the
> testsuite log.  Otherwise it will be hard to understand what went wrong
> if these ever fail.
>
> >> +
> >> +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.
> >> +ovs-appctl revalidator/wait
>
> Same here.
>
> >> +
> >> +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 -])
> >> +ovs-appctl revalidator/wait
>
> And here.
>
> >> +
> >> +dnl Inconsistent ukey should be deleted.
> >> +AT_CHECK([ovs-appctl upcall/show | grep keys | grep -q -v 0], [1])
> >> +
> >> +dnl Check the error log of the flow modification
> >
> > You forgot to add a dot. But maybe:
> >
> >  +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 testsuite pass.
> >
> > +dnl Remove warning logs to let the test suite pass.
> >
> >> +OVS_VSWITCHD_STOP([dnl
> >> +"/.*failed to put.*$/d
> >> +/.*failed to flow_del.*$/d"
> >> +])
>
> Nit: You may put quotes on separate lines and sed commands
> do not need to start from the line beginning:
>

sure.

>
> OVS_VSWITCHD_STOP(["
>   /.*failed to put.*$/d
>   /.*failed to flow_del.*$/d
> "])
>
> >> +AT_CLEANUP
> >> --
> >> 2.25.1
> >
>
>

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

Reply via email to