How do you suggest changing the guarded-list abstraction to accommodate
that?

On Thu, Sep 12, 2013 at 04:26:43PM -0700, Ethan Jackson wrote:
> I'm not sure how much this matters in practice, but in
> handle_miss_upcalls() I'd prefer we don't queue up fmbs which we know
> are just going to get dropped later.  I'm worried that the threads are
> going to saturate the queue much more quickly than the main thread can
> handle and we're going to have problems.
> 
> Similarly I'd like flow_miss_batch_next() to be bounded.  One could
> imagine child threads pounding the main threads with invalid flows and
> causing an infinite loop.  Again, not sure how much it matters in
> practice.
> 
> Ethan
> 
> On Thu, Sep 12, 2013 at 12:39 AM, Ben Pfaff <b...@nicira.com> wrote:
> > We already had queues that were suitable for replacement by this data
> > structure, and I intend to add another one later on.
> >
> > flow_miss_batch_ofproto_destroyed() did not work well with the guarded-list
> > structure (it required either adding a lot more functions or breaking the
> > abstraction) so I changed the caller to just use udpif_revalidate().
> >
> > Checking reval_seq at the end of handle_miss_upcalls() also didn't work
> > well with the abstraction, so I decided that since this was a corner case
> > anyway it would be acceptable to just drop those in flow_miss_batch_next().
> >
> > Signed-off-by: Ben Pfaff <b...@nicira.com>
> > Acked-by: Ethan Jackson <et...@nicira.com>
> > ---
> >  lib/automake.mk               |    2 +
> >  lib/guarded-list.c            |   97 ++++++++++++++++++++
> >  lib/guarded-list.h            |   41 +++++++++
> >  ofproto/ofproto-dpif-upcall.c |  196 
> > ++++++++++++-----------------------------
> >  ofproto/ofproto-dpif-upcall.h |    6 +-
> >  ofproto/ofproto-dpif.c        |   77 ++++------------
> >  6 files changed, 216 insertions(+), 203 deletions(-)
> >  create mode 100644 lib/guarded-list.c
> >  create mode 100644 lib/guarded-list.h
> >
> > diff --git a/lib/automake.mk b/lib/automake.mk
> > index da1896a..92cfc13 100644
> > --- a/lib/automake.mk
> > +++ b/lib/automake.mk
> > @@ -58,6 +58,8 @@ lib_libopenvswitch_a_SOURCES = \
> >         lib/fatal-signal.h \
> >         lib/flow.c \
> >         lib/flow.h \
> > +       lib/guarded-list.c \
> > +       lib/guarded-list.h \
> >         lib/hash.c \
> >         lib/hash.h \
> >         lib/hindex.c \
> > diff --git a/lib/guarded-list.c b/lib/guarded-list.c
> > new file mode 100644
> > index 0000000..cbb2030
> > --- /dev/null
> > +++ b/lib/guarded-list.c
> > @@ -0,0 +1,97 @@
> > +/*
> > + * Copyright (c) 2013 Nicira, Inc.
> > + *
> > + * Licensed under the Apache License, Version 2.0 (the "License");
> > + * you may not use this file except in compliance with the License.
> > + * You may obtain a copy of the License at:
> > + *
> > + *     http://www.apache.org/licenses/LICENSE-2.0
> > + *
> > + * Unless required by applicable law or agreed to in writing, software
> > + * distributed under the License is distributed on an "AS IS" BASIS,
> > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> > + * See the License for the specific language governing permissions and
> > + * limitations under the License.
> > + */
> > +
> > +#include <config.h>
> > +
> > +#include "guarded-list.h"
> > +
> > +void
> > +guarded_list_init(struct guarded_list *list)
> > +{
> > +    ovs_mutex_init(&list->mutex);
> > +    list_init(&list->list);
> > +    list->n = 0;
> > +}
> > +
> > +void
> > +guarded_list_destroy(struct guarded_list *list)
> > +{
> > +    ovs_mutex_destroy(&list->mutex);
> > +}
> > +
> > +bool
> > +guarded_list_is_empty(const struct guarded_list *list)
> > +{
> > +    bool empty;
> > +
> > +    ovs_mutex_lock(&list->mutex);
> > +    empty = list->n == 0;
> > +    ovs_mutex_unlock(&list->mutex);
> > +
> > +    return empty;
> > +}
> > +
> > +/* If 'list' has fewer than 'max' elements, adds 'node' at the end of the 
> > list
> > + * and returns the number of elements now on the list.
> > + *
> > + * If 'list' already has at least 'max' elements, returns 0 without 
> > modifying
> > + * the list. */
> > +size_t
> > +guarded_list_push_back(struct guarded_list *list,
> > +                       struct list *node, size_t max)
> > +{
> > +    size_t retval = 0;
> > +
> > +    ovs_mutex_lock(&list->mutex);
> > +    if (list->n < max) {
> > +        list_push_back(&list->list, node);
> > +        retval = ++list->n;
> > +    }
> > +    ovs_mutex_unlock(&list->mutex);
> > +
> > +    return retval;
> > +}
> > +
> > +struct list *
> > +guarded_list_pop_front(struct guarded_list *list)
> > +{
> > +    struct list *node = NULL;
> > +
> > +    ovs_mutex_lock(&list->mutex);
> > +    if (list->n) {
> > +        node = list_pop_front(&list->list);
> > +        list->n--;
> > +    }
> > +    ovs_mutex_unlock(&list->mutex);
> > +
> > +    return node;
> > +}
> > +
> > +size_t
> > +guarded_list_pop_all(struct guarded_list *list, struct list *elements)
> > +{
> > +    size_t n;
> > +
> > +    ovs_mutex_lock(&list->mutex);
> > +    list_move(elements, &list->list);
> > +    n = list->n;
> > +
> > +    list_init(&list->list);
> > +    list->n = 0;
> > +    ovs_mutex_unlock(&list->mutex);
> > +
> > +    return n;
> > +}
> > diff --git a/lib/guarded-list.h b/lib/guarded-list.h
> > new file mode 100644
> > index 0000000..625865d
> > --- /dev/null
> > +++ b/lib/guarded-list.h
> > @@ -0,0 +1,41 @@
> > +/*
> > + * Copyright (c) 2013 Nicira, Inc.
> > + *
> > + * Licensed under the Apache License, Version 2.0 (the "License");
> > + * you may not use this file except in compliance with the License.
> > + * You may obtain a copy of the License at:
> > + *
> > + *     http://www.apache.org/licenses/LICENSE-2.0
> > + *
> > + * Unless required by applicable law or agreed to in writing, software
> > + * distributed under the License is distributed on an "AS IS" BASIS,
> > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> > + * See the License for the specific language governing permissions and
> > + * limitations under the License.
> > + */
> > +
> > +#ifndef GUARDED_LIST_H
> > +#define GUARDED_LIST_H 1
> > +
> > +#include <stddef.h>
> > +#include "compiler.h"
> > +#include "list.h"
> > +#include "ovs-thread.h"
> > +
> > +struct guarded_list {
> > +    struct ovs_mutex mutex;
> > +    struct list list;
> > +    size_t n;
> > +};
> > +
> > +void guarded_list_init(struct guarded_list *);
> > +void guarded_list_destroy(struct guarded_list *);
> > +
> > +bool guarded_list_is_empty(const struct guarded_list *);
> > +
> > +size_t guarded_list_push_back(struct guarded_list *, struct list *,
> > +                              size_t max);
> > +struct list *guarded_list_pop_front(struct guarded_list *);
> > +size_t guarded_list_pop_all(struct guarded_list *, struct list *);
> > +
> > +#endif /* guarded-list.h */
> > diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
> > index ae856a4..850633d 100644
> > --- a/ofproto/ofproto-dpif-upcall.c
> > +++ b/ofproto/ofproto-dpif-upcall.c
> > @@ -23,6 +23,7 @@
> >  #include "dynamic-string.h"
> >  #include "dpif.h"
> >  #include "fail-open.h"
> > +#include "guarded-list.h"
> >  #include "latch.h"
> >  #include "seq.h"
> >  #include "list.h"
> > @@ -79,26 +80,15 @@ struct udpif {
> >      struct handler *handlers;          /* Miss handlers. */
> >      size_t n_handlers;
> >
> > -    /* Atomic queue of unprocessed drop keys. */
> > -    struct ovs_mutex drop_key_mutex;
> > -    struct list drop_keys OVS_GUARDED;
> > -    size_t n_drop_keys OVS_GUARDED;
> > -
> > -    /* Atomic queue of special upcalls for ofproto-dpif to process. */
> > -    struct ovs_mutex upcall_mutex;
> > -    struct list upcalls OVS_GUARDED;
> > -    size_t n_upcalls OVS_GUARDED;
> > -
> > -    /* Atomic queue of flow_miss_batches. */
> > -    struct ovs_mutex fmb_mutex;
> > -    struct list fmbs OVS_GUARDED;
> > -    size_t n_fmbs OVS_GUARDED;
> > +    /* Queues to pass up to ofproto-dpif. */
> > +    struct guarded_list drop_keys; /* "struct drop key"s. */
> > +    struct guarded_list upcalls;   /* "struct upcall"s. */
> > +    struct guarded_list fmbs;      /* "struct flow_miss_batch"es. */
> >
> >      /* Number of times udpif_revalidate() has been called. */
> >      atomic_uint reval_seq;
> >
> >      struct seq *wait_seq;
> > -    uint64_t last_seq;
> >
> >      struct latch exit_latch; /* Tells child threads to exit. */
> >  };
> > @@ -121,13 +111,10 @@ udpif_create(struct dpif_backer *backer, struct dpif 
> > *dpif)
> >      udpif->secret = random_uint32();
> >      udpif->wait_seq = seq_create();
> >      latch_init(&udpif->exit_latch);
> > -    list_init(&udpif->drop_keys);
> > -    list_init(&udpif->upcalls);
> > -    list_init(&udpif->fmbs);
> > +    guarded_list_init(&udpif->drop_keys);
> > +    guarded_list_init(&udpif->upcalls);
> > +    guarded_list_init(&udpif->fmbs);
> >      atomic_init(&udpif->reval_seq, 0);
> > -    ovs_mutex_init(&udpif->drop_key_mutex);
> > -    ovs_mutex_init(&udpif->upcall_mutex);
> > -    ovs_mutex_init(&udpif->fmb_mutex);
> >
> >      return udpif;
> >  }
> > @@ -153,9 +140,9 @@ udpif_destroy(struct udpif *udpif)
> >          flow_miss_batch_destroy(fmb);
> >      }
> >
> > -    ovs_mutex_destroy(&udpif->drop_key_mutex);
> > -    ovs_mutex_destroy(&udpif->upcall_mutex);
> > -    ovs_mutex_destroy(&udpif->fmb_mutex);
> > +    guarded_list_destroy(&udpif->drop_keys);
> > +    guarded_list_destroy(&udpif->upcalls);
> > +    guarded_list_destroy(&udpif->fmbs);
> >      latch_destroy(&udpif->exit_latch);
> >      seq_destroy(udpif->wait_seq);
> >      free(udpif);
> > @@ -229,33 +216,16 @@ udpif_recv_set(struct udpif *udpif, size_t 
> > n_handlers, bool enable)
> >  }
> >
> >  void
> > -udpif_run(struct udpif *udpif)
> > -{
> > -    udpif->last_seq = seq_read(udpif->wait_seq);
> > -}
> > -
> > -void
> >  udpif_wait(struct udpif *udpif)
> >  {
> > -    ovs_mutex_lock(&udpif->drop_key_mutex);
> > -    if (udpif->n_drop_keys) {
> > -        poll_immediate_wake();
> > -    }
> > -    ovs_mutex_unlock(&udpif->drop_key_mutex);
> > -
> > -    ovs_mutex_lock(&udpif->upcall_mutex);
> > -    if (udpif->n_upcalls) {
> > -        poll_immediate_wake();
> > -    }
> > -    ovs_mutex_unlock(&udpif->upcall_mutex);
> > -
> > -    ovs_mutex_lock(&udpif->fmb_mutex);
> > -    if (udpif->n_fmbs) {
> > +    uint64_t seq = seq_read(udpif->wait_seq);
> > +    if (!guarded_list_is_empty(&udpif->drop_keys) ||
> > +        !guarded_list_is_empty(&udpif->upcalls) ||
> > +        !guarded_list_is_empty(&udpif->fmbs)) {
> >          poll_immediate_wake();
> > +    } else {
> > +        seq_wait(udpif->wait_seq, seq);
> >      }
> > -    ovs_mutex_unlock(&udpif->fmb_mutex);
> > -
> > -    seq_wait(udpif->wait_seq, udpif->last_seq);
> >  }
> >
> >  /* Notifies 'udpif' that something changed which may render previous
> > @@ -265,20 +235,21 @@ udpif_revalidate(struct udpif *udpif)
> >  {
> >      struct flow_miss_batch *fmb, *next_fmb;
> >      unsigned int junk;
> > +    struct list fmbs;
> >
> >      /* Since we remove each miss on revalidation, their statistics won't be
> >       * accounted to the appropriate 'facet's in the upper layer.  In most
> >       * cases, this is alright because we've already pushed the stats to the
> >       * relevant rules.  However, NetFlow requires absolute packet counts on
> >       * 'facet's which could now be incorrect. */
> > -    ovs_mutex_lock(&udpif->fmb_mutex);
> >      atomic_add(&udpif->reval_seq, 1, &junk);
> > -    LIST_FOR_EACH_SAFE (fmb, next_fmb, list_node, &udpif->fmbs) {
> > +
> > +    guarded_list_pop_all(&udpif->fmbs, &fmbs);
> > +    LIST_FOR_EACH_SAFE (fmb, next_fmb, list_node, &fmbs) {
> >          list_remove(&fmb->list_node);
> >          flow_miss_batch_destroy(fmb);
> > -        udpif->n_fmbs--;
> >      }
> > -    ovs_mutex_unlock(&udpif->fmb_mutex);
> > +
> >      udpif_drop_key_clear(udpif);
> >  }
> >
> > @@ -288,16 +259,8 @@ udpif_revalidate(struct udpif *udpif)
> >  struct upcall *
> >  upcall_next(struct udpif *udpif)
> >  {
> > -    struct upcall *next = NULL;
> > -
> > -    ovs_mutex_lock(&udpif->upcall_mutex);
> > -    if (udpif->n_upcalls) {
> > -        udpif->n_upcalls--;
> > -        next = CONTAINER_OF(list_pop_front(&udpif->upcalls), struct upcall,
> > -                            list_node);
> > -    }
> > -    ovs_mutex_unlock(&udpif->upcall_mutex);
> > -    return next;
> > +    struct list *next = guarded_list_pop_front(&udpif->upcalls);
> > +    return next ? CONTAINER_OF(next, struct upcall, list_node) : NULL;
> >  }
> >
> >  /* Destroys and deallocates 'upcall'. */
> > @@ -316,16 +279,24 @@ upcall_destroy(struct upcall *upcall)
> >  struct flow_miss_batch *
> >  flow_miss_batch_next(struct udpif *udpif)
> >  {
> > -    struct flow_miss_batch *next = NULL;
> > +    for (;;) {
> > +        struct flow_miss_batch *next;
> > +        unsigned int reval_seq;
> > +        struct list *next_node;
> >
> > -    ovs_mutex_lock(&udpif->fmb_mutex);
> > -    if (udpif->n_fmbs) {
> > -        udpif->n_fmbs--;
> > -        next = CONTAINER_OF(list_pop_front(&udpif->fmbs),
> > -                            struct flow_miss_batch, list_node);
> > +        next_node = guarded_list_pop_front(&udpif->fmbs);
> > +        if (!next_node) {
> > +            return NULL;
> > +        }
> > +
> > +        next = CONTAINER_OF(next_node, struct flow_miss_batch, list_node);
> > +        atomic_read(&udpif->reval_seq, &reval_seq);
> > +        if (next->reval_seq == reval_seq) {
> > +            return next;
> > +        }
> > +
> > +        flow_miss_batch_destroy(next);
> >      }
> > -    ovs_mutex_unlock(&udpif->fmb_mutex);
> > -    return next;
> >  }
> >
> >  /* Destroys and deallocates 'fmb'. */
> > @@ -347,52 +318,13 @@ flow_miss_batch_destroy(struct flow_miss_batch *fmb)
> >      free(fmb);
> >  }
> >
> > -/* Discards any flow miss batches queued up in 'udpif' for 'ofproto' 
> > (because
> > - * 'ofproto' is being destroyed).
> > - *
> > - * 'ofproto''s xports must already have been removed, otherwise new flow 
> > miss
> > - * batches could still end up getting queued. */
> > -void
> > -flow_miss_batch_ofproto_destroyed(struct udpif *udpif,
> > -                                  const struct ofproto_dpif *ofproto)
> > -{
> > -    struct flow_miss_batch *fmb, *next_fmb;
> > -
> > -    ovs_mutex_lock(&udpif->fmb_mutex);
> > -    LIST_FOR_EACH_SAFE (fmb, next_fmb, list_node, &udpif->fmbs) {
> > -        struct flow_miss *miss, *next_miss;
> > -
> > -        HMAP_FOR_EACH_SAFE (miss, next_miss, hmap_node, &fmb->misses) {
> > -            if (miss->ofproto == ofproto) {
> > -                hmap_remove(&fmb->misses, &miss->hmap_node);
> > -                miss_destroy(miss);
> > -            }
> > -        }
> > -
> > -        if (hmap_is_empty(&fmb->misses)) {
> > -            list_remove(&fmb->list_node);
> > -            flow_miss_batch_destroy(fmb);
> > -            udpif->n_fmbs--;
> > -        }
> > -    }
> > -    ovs_mutex_unlock(&udpif->fmb_mutex);
> > -}
> > -
> >  /* Retreives the next drop key which ofproto-dpif needs to process.  The 
> > caller
> >   * is responsible for destroying it with drop_key_destroy(). */
> >  struct drop_key *
> >  drop_key_next(struct udpif *udpif)
> >  {
> > -    struct drop_key *next = NULL;
> > -
> > -    ovs_mutex_lock(&udpif->drop_key_mutex);
> > -    if (udpif->n_drop_keys) {
> > -        udpif->n_drop_keys--;
> > -        next = CONTAINER_OF(list_pop_front(&udpif->drop_keys), struct 
> > drop_key,
> > -                            list_node);
> > -    }
> > -    ovs_mutex_unlock(&udpif->drop_key_mutex);
> > -    return next;
> > +    struct list *next = guarded_list_pop_front(&udpif->drop_keys);
> > +    return next ? CONTAINER_OF(next, struct drop_key, list_node) : NULL;
> >  }
> >
> >  /* Destorys and deallocates 'drop_key'. */
> > @@ -410,14 +342,13 @@ void
> >  udpif_drop_key_clear(struct udpif *udpif)
> >  {
> >      struct drop_key *drop_key, *next;
> > +    struct list list;
> >
> > -    ovs_mutex_lock(&udpif->drop_key_mutex);
> > -    LIST_FOR_EACH_SAFE (drop_key, next, list_node, &udpif->drop_keys) {
> > +    guarded_list_pop_all(&udpif->drop_keys, &list);
> > +    LIST_FOR_EACH_SAFE (drop_key, next, list_node, &list) {
> >          list_remove(&drop_key->list_node);
> >          drop_key_destroy(drop_key);
> > -        udpif->n_drop_keys--;
> >      }
> > -    ovs_mutex_unlock(&udpif->drop_key_mutex);
> >  }
> >
> >  /* The dispatcher thread is responsible for receving upcalls from the 
> > kernel,
> > @@ -618,17 +549,16 @@ recv_upcalls(struct udpif *udpif)
> >                  upcall_destroy(upcall);
> >              }
> >          } else {
> > -            ovs_mutex_lock(&udpif->upcall_mutex);
> > -            if (udpif->n_upcalls < MAX_QUEUE_LENGTH) {
> > -                n_udpif_new_upcalls = ++udpif->n_upcalls;
> > -                list_push_back(&udpif->upcalls, &upcall->list_node);
> > -                ovs_mutex_unlock(&udpif->upcall_mutex);
> > +            size_t len;
> >
> > +            len = guarded_list_push_back(&udpif->upcalls, 
> > &upcall->list_node,
> > +                                         MAX_QUEUE_LENGTH);
> > +            if (len > 0) {
> > +                n_udpif_new_upcalls = len;
> >                  if (n_udpif_new_upcalls >= FLOW_MISS_MAX_BATCH) {
> >                      seq_change(udpif->wait_seq);
> >                  }
> >              } else {
> > -                ovs_mutex_unlock(&udpif->upcall_mutex);
> >                  COVERAGE_INC(upcall_queue_overflow);
> >                  upcall_destroy(upcall);
> >              }
> > @@ -762,20 +692,18 @@ handle_miss_upcalls(struct udpif *udpif, struct list 
> > *upcalls)
> >  {
> >      struct dpif_op *opsp[FLOW_MISS_MAX_BATCH];
> >      struct dpif_op ops[FLOW_MISS_MAX_BATCH];
> > -    unsigned int old_reval_seq, new_reval_seq;
> >      struct upcall *upcall, *next;
> >      struct flow_miss_batch *fmb;
> >      size_t n_upcalls, n_ops, i;
> >      struct flow_miss *miss;
> >
> > -    atomic_read(&udpif->reval_seq, &old_reval_seq);
> > -
> >      /* Construct the to-do list.
> >       *
> >       * This just amounts to extracting the flow from each packet and 
> > sticking
> >       * the packets that have the same flow in the same "flow_miss" 
> > structure so
> >       * that we can process them together. */
> >      fmb = xmalloc(sizeof *fmb);
> > +    atomic_read(&udpif->reval_seq, &fmb->reval_seq);
> >      hmap_init(&fmb->misses);
> >      n_upcalls = 0;
> >      LIST_FOR_EACH_SAFE (upcall, next, list_node, upcalls) {
> > @@ -808,14 +736,10 @@ handle_miss_upcalls(struct udpif *udpif, struct list 
> > *upcalls)
> >              drop_key->key = xmemdup(dupcall->key, dupcall->key_len);
> >              drop_key->key_len = dupcall->key_len;
> >
> > -            ovs_mutex_lock(&udpif->drop_key_mutex);
> > -            if (udpif->n_drop_keys < MAX_QUEUE_LENGTH) {
> > -                udpif->n_drop_keys++;
> > -                list_push_back(&udpif->drop_keys, &drop_key->list_node);
> > -                ovs_mutex_unlock(&udpif->drop_key_mutex);
> > +            if (guarded_list_push_back(&udpif->drop_keys, 
> > &drop_key->list_node,
> > +                                       MAX_QUEUE_LENGTH)) {
> >                  seq_change(udpif->wait_seq);
> >              } else {
> > -                ovs_mutex_unlock(&udpif->drop_key_mutex);
> >                  COVERAGE_INC(drop_queue_overflow);
> >                  drop_key_destroy(drop_key);
> >              }
> > @@ -868,21 +792,11 @@ handle_miss_upcalls(struct udpif *udpif, struct list 
> > *upcalls)
> >      }
> >      dpif_operate(udpif->dpif, opsp, n_ops);
> >
> > -    ovs_mutex_lock(&udpif->fmb_mutex);
> > -    atomic_read(&udpif->reval_seq, &new_reval_seq);
> > -    if (old_reval_seq != new_reval_seq) {
> > -        /* udpif_revalidate() was called as we were calculating the 
> > actions.
> > -         * To be safe, we need to assume all the misses need revalidation. 
> > */
> > -        ovs_mutex_unlock(&udpif->fmb_mutex);
> > -        flow_miss_batch_destroy(fmb);
> > -    } else if (udpif->n_fmbs < MAX_QUEUE_LENGTH) {
> > -        udpif->n_fmbs++;
> > -        list_push_back(&udpif->fmbs, &fmb->list_node);
> > -        ovs_mutex_unlock(&udpif->fmb_mutex);
> > +    if (guarded_list_push_back(&udpif->fmbs, &fmb->list_node,
> > +                               MAX_QUEUE_LENGTH)) {
> >          seq_change(udpif->wait_seq);
> >      } else {
> >          COVERAGE_INC(fmb_queue_overflow);
> > -        ovs_mutex_unlock(&udpif->fmb_mutex);
> >          flow_miss_batch_destroy(fmb);
> >      }
> >  }
> > diff --git a/ofproto/ofproto-dpif-upcall.h b/ofproto/ofproto-dpif-upcall.h
> > index 8e8264e..57d462d 100644
> > --- a/ofproto/ofproto-dpif-upcall.h
> > +++ b/ofproto/ofproto-dpif-upcall.h
> > @@ -36,7 +36,6 @@ struct udpif *udpif_create(struct dpif_backer *, struct 
> > dpif *);
> >  void udpif_recv_set(struct udpif *, size_t n_workers, bool enable);
> >  void udpif_destroy(struct udpif *);
> >
> > -void udpif_run(struct udpif *);
> >  void udpif_wait(struct udpif *);
> >
> >  void udpif_revalidate(struct udpif *);
> > @@ -105,13 +104,12 @@ struct flow_miss_batch {
> >
> >      struct flow_miss miss_buf[FLOW_MISS_MAX_BATCH];
> >      struct hmap misses;
> > +
> > +    unsigned int reval_seq;
> >  };
> >
> >  struct flow_miss_batch *flow_miss_batch_next(struct udpif *);
> >  void flow_miss_batch_destroy(struct flow_miss_batch *);
> > -
> > -void flow_miss_batch_ofproto_destroyed(struct udpif *,
> > -                                       const struct ofproto_dpif *);
> >
> >  /* Drop keys are odp flow keys which have drop flows installed in the 
> > kernel.
> >   * These are datapath flows which have no associated ofproto, if they did 
> > we
> > diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> > index 6f1a4e5..bf5af33 100644
> > --- a/ofproto/ofproto-dpif.c
> > +++ b/ofproto/ofproto-dpif.c
> > @@ -31,6 +31,7 @@
> >  #include "dpif.h"
> >  #include "dynamic-string.h"
> >  #include "fail-open.h"
> > +#include "guarded-list.h"
> >  #include "hmapx.h"
> >  #include "lacp.h"
> >  #include "learn.h"
> > @@ -507,13 +508,8 @@ struct ofproto_dpif {
> >      uint64_t n_missed;
> >
> >      /* Work queues. */
> > -    struct ovs_mutex flow_mod_mutex;
> > -    struct list flow_mods OVS_GUARDED;
> > -    size_t n_flow_mods OVS_GUARDED;
> > -
> > -    struct ovs_mutex pin_mutex;
> > -    struct list pins OVS_GUARDED;
> > -    size_t n_pins OVS_GUARDED;
> > +    struct guarded_list flow_mods; /* Contains "struct flow_mod"s. */
> > +    struct guarded_list pins;      /* Contains "struct 
> > ofputil_packet_in"s. */
> >  };
> >
> >  /* By default, flows in the datapath are wildcarded (megaflows).  They
> > @@ -560,18 +556,11 @@ void
> >  ofproto_dpif_flow_mod(struct ofproto_dpif *ofproto,
> >                        struct ofputil_flow_mod *fm)
> >  {
> > -    ovs_mutex_lock(&ofproto->flow_mod_mutex);
> > -    if (ofproto->n_flow_mods > 1024) {
> > -        ovs_mutex_unlock(&ofproto->flow_mod_mutex);
> > +    if (!guarded_list_push_back(&ofproto->flow_mods, &fm->list_node, 
> > 1024)) {
> >          COVERAGE_INC(flow_mod_overflow);
> >          free(fm->ofpacts);
> >          free(fm);
> > -        return;
> >      }
> > -
> > -    list_push_back(&ofproto->flow_mods, &fm->list_node);
> > -    ofproto->n_flow_mods++;
> > -    ovs_mutex_unlock(&ofproto->flow_mod_mutex);
> >  }
> >
> >  /* Appends 'pin' to the queue of "packet ins" to be sent to the controller.
> > @@ -580,18 +569,11 @@ void
> >  ofproto_dpif_send_packet_in(struct ofproto_dpif *ofproto,
> >                              struct ofputil_packet_in *pin)
> >  {
> > -    ovs_mutex_lock(&ofproto->pin_mutex);
> > -    if (ofproto->n_pins > 1024) {
> > -        ovs_mutex_unlock(&ofproto->pin_mutex);
> > +    if (!guarded_list_push_back(&ofproto->pins, &pin->list_node, 1024)) {
> >          COVERAGE_INC(packet_in_overflow);
> >          free(CONST_CAST(void *, pin->packet));
> >          free(pin);
> > -        return;
> >      }
> > -
> > -    list_push_back(&ofproto->pins, &pin->list_node);
> > -    ofproto->n_pins++;
> > -    ovs_mutex_unlock(&ofproto->pin_mutex);
> >  }
> >
> >  /* Factory functions. */
> > @@ -1024,7 +1006,6 @@ process_dpif_port_error(struct dpif_backer *backer, 
> > int error)
> >  static int
> >  dpif_backer_run_fast(struct dpif_backer *backer)
> >  {
> > -    udpif_run(backer->udpif);
> >      handle_upcalls(backer);
> >
> >      return 0;
> > @@ -1286,17 +1267,8 @@ construct(struct ofproto *ofproto_)
> >      classifier_init(&ofproto->facets);
> >      ofproto->consistency_rl = LLONG_MIN;
> >
> > -    ovs_mutex_init(&ofproto->flow_mod_mutex);
> > -    ovs_mutex_lock(&ofproto->flow_mod_mutex);
> > -    list_init(&ofproto->flow_mods);
> > -    ofproto->n_flow_mods = 0;
> > -    ovs_mutex_unlock(&ofproto->flow_mod_mutex);
> > -
> > -    ovs_mutex_init(&ofproto->pin_mutex);
> > -    ovs_mutex_lock(&ofproto->pin_mutex);
> > -    list_init(&ofproto->pins);
> > -    ofproto->n_pins = 0;
> > -    ovs_mutex_unlock(&ofproto->pin_mutex);
> > +    guarded_list_init(&ofproto->flow_mods);
> > +    guarded_list_init(&ofproto->pins);
> >
> >      ofproto_dpif_unixctl_init();
> >
> > @@ -1422,6 +1394,7 @@ destruct(struct ofproto *ofproto_)
> >      struct ofputil_packet_in *pin, *next_pin;
> >      struct ofputil_flow_mod *fm, *next_fm;
> >      struct facet *facet, *next_facet;
> > +    struct list flow_mods, pins;
> >      struct cls_cursor cursor;
> >      struct oftable *table;
> >
> > @@ -1437,7 +1410,9 @@ destruct(struct ofproto *ofproto_)
> >      xlate_remove_ofproto(ofproto);
> >      ovs_rwlock_unlock(&xlate_rwlock);
> >
> > -    flow_miss_batch_ofproto_destroyed(ofproto->backer->udpif, ofproto);
> > +    /* Discard any flow_miss_batches queued up for 'ofproto', avoiding a
> > +     * use-after-free error. */
> > +    udpif_revalidate(ofproto->backer->udpif);
> >
> >      hmap_remove(&all_ofproto_dpifs, &ofproto->all_ofproto_dpifs_node);
> >
> > @@ -1452,25 +1427,21 @@ destruct(struct ofproto *ofproto_)
> >          ovs_rwlock_unlock(&table->cls.rwlock);
> >      }
> >
> > -    ovs_mutex_lock(&ofproto->flow_mod_mutex);
> > -    LIST_FOR_EACH_SAFE (fm, next_fm, list_node, &ofproto->flow_mods) {
> > +    guarded_list_pop_all(&ofproto->flow_mods, &flow_mods);
> > +    LIST_FOR_EACH_SAFE (fm, next_fm, list_node, &flow_mods) {
> >          list_remove(&fm->list_node);
> > -        ofproto->n_flow_mods--;
> >          free(fm->ofpacts);
> >          free(fm);
> >      }
> > -    ovs_mutex_unlock(&ofproto->flow_mod_mutex);
> > -    ovs_mutex_destroy(&ofproto->flow_mod_mutex);
> > +    guarded_list_destroy(&ofproto->flow_mods);
> >
> > -    ovs_mutex_lock(&ofproto->pin_mutex);
> > -    LIST_FOR_EACH_SAFE (pin, next_pin, list_node, &ofproto->pins) {
> > +    guarded_list_pop_all(&ofproto->pins, &pins);
> > +    LIST_FOR_EACH_SAFE (pin, next_pin, list_node, &pins) {
> >          list_remove(&pin->list_node);
> > -        ofproto->n_pins--;
> >          free(CONST_CAST(void *, pin->packet));
> >          free(pin);
> >      }
> > -    ovs_mutex_unlock(&ofproto->pin_mutex);
> > -    ovs_mutex_destroy(&ofproto->pin_mutex);
> > +    guarded_list_destroy(&ofproto->pins);
> >
> >      mbridge_unref(ofproto->mbridge);
> >
> > @@ -1508,12 +1479,7 @@ run_fast(struct ofproto *ofproto_)
> >          return 0;
> >      }
> >
> > -    ovs_mutex_lock(&ofproto->flow_mod_mutex);
> > -    list_move(&flow_mods, &ofproto->flow_mods);
> > -    list_init(&ofproto->flow_mods);
> > -    ofproto->n_flow_mods = 0;
> > -    ovs_mutex_unlock(&ofproto->flow_mod_mutex);
> > -
> > +    guarded_list_pop_all(&ofproto->flow_mods, &flow_mods);
> >      LIST_FOR_EACH_SAFE (fm, next_fm, list_node, &flow_mods) {
> >          int error = ofproto_flow_mod(&ofproto->up, fm);
> >          if (error && !VLOG_DROP_WARN(&rl)) {
> > @@ -1526,12 +1492,7 @@ run_fast(struct ofproto *ofproto_)
> >          free(fm);
> >      }
> >
> > -    ovs_mutex_lock(&ofproto->pin_mutex);
> > -    list_move(&pins, &ofproto->pins);
> > -    list_init(&ofproto->pins);
> > -    ofproto->n_pins = 0;
> > -    ovs_mutex_unlock(&ofproto->pin_mutex);
> > -
> > +    guarded_list_pop_all(&ofproto->pins, &pins);
> >      LIST_FOR_EACH_SAFE (pin, next_pin, list_node, &pins) {
> >          connmgr_send_packet_in(ofproto->up.connmgr, pin);
> >          list_remove(&pin->list_node);
> > --
> > 1.7.10.4
> >
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to