[ovs-dev] [rwlock 3/5] ofproto-dpif-xlate: Avoid recursively taking read side of ofgroup rwlock.

Joe Stringer joestringer at nicira.com
Fri Feb 21 23:16:28 UTC 2014


Looks good to me.

Acked-by: Joe Stringer <joestringer at nicira.com>


On 21 February 2014 10:46, Ben Pfaff <blp at nicira.com> wrote:

> On Wed, Feb 19, 2014 at 02:53:11PM -0800, Joe Stringer wrote:
> > This looks good to me, although aren't we meant to report something at
> the
> > OpenFlow layer?
> >
> > Is this equivalent to the OpenFlow "chaining" description? So if we don't
> > support chaining groups together, we should return an error message with
> > reason OFPGMFC_CHAINING_UNSUPPORTED, rather than accepting the rules then
> > misbehaving?
>
> You're right.  Here's a version that does that, and adds a test.
>
> --8<--------------------------cut here-------------------------->8--
>
> From: Ben Pfaff <blp at nicira.com>
> Date: Fri, 21 Feb 2014 10:45:00 -0800
> Subject: [PATCH] ofproto-dpif-xlate: Avoid recursively taking read side of
>  ofgroup rwlock.
>
> With glibc, rwlocks by default allow recursive read-locking even if a
> thread is blocked waiting for the write-lock.  POSIX allows such attempts
> to deadlock, and it appears that the libc used in NetBSD, at least, does
> deadlock.  ofproto-dpif-xlate could take the ofgroup rwlock recursively if
> an ofgroup's actions caused the ofgroup to be executed again.  This commit
> avoids that issue by preventing recursive translation of groups (the same
> group or another group).  This is not the most user friendly solution,
> but OpenFlow allows this restriction, and we can always remove the
> restriction later (probably requiring more complicated code) if it
> proves to be a real problem to real users.
>
> Found by inspection.
>
> Signed-off-by: Ben Pfaff <blp at nicira.com>
> ---
>  ofproto/ofproto-dpif-xlate.c |   32 +++++++++++++++++++++++++++++++-
>  ofproto/ofproto-dpif.c       |   14 ++++++++++++++
>  tests/ofproto-dpif.at        |   11 +++++++++++
>  3 files changed, 56 insertions(+), 1 deletion(-)
>
> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
> index ccf0b75..89d92af 100644
> --- a/ofproto/ofproto-dpif-xlate.c
> +++ b/ofproto/ofproto-dpif-xlate.c
> @@ -178,6 +178,7 @@ struct xlate_ctx {
>      /* Resubmit statistics, via xlate_table_action(). */
>      int recurse;                /* Current resubmit nesting depth. */
>      int resubmits;              /* Total number of resubmits. */
> +    bool in_group;              /* Currently translating ofgroup, if
> true. */
>
>      uint32_t orig_skb_priority; /* Priority when packet arrived. */
>      uint8_t table_id;           /* OpenFlow table ID where flow was
> found. */
> @@ -1980,6 +1981,8 @@ xlate_select_group(struct xlate_ctx *ctx, struct
> group_dpif *group)
>  static void
>  xlate_group_action__(struct xlate_ctx *ctx, struct group_dpif *group)
>  {
> +    ctx->in_group = true;
> +
>      switch (group_dpif_get_type(group)) {
>      case OFPGT11_ALL:
>      case OFPGT11_INDIRECT:
> @@ -1995,12 +1998,38 @@ xlate_group_action__(struct xlate_ctx *ctx, struct
> group_dpif *group)
>          OVS_NOT_REACHED();
>      }
>      group_dpif_release(group);
> +
> +    ctx->in_group = false;
> +}
> +
> +static bool
> +xlate_group_resource_check(struct xlate_ctx *ctx)
> +{
> +    if (!xlate_resubmit_resource_check(ctx)) {
> +        return false;
> +    } else if (ctx->in_group) {
> +        /* Prevent nested translation of OpenFlow groups.
> +         *
> +         * OpenFlow allows this restriction.  We enforce this restriction
> only
> +         * because, with the current architecture, we would otherwise
> have to
> +         * take a possibly recursive read lock on the ofgroup rwlock,
> which is
> +         * unsafe given that POSIX allows taking a read lock to block if
> there
> +         * is a thread blocked on taking the write lock.  Other solutions
> +         * without this restriction are also possible, but seem
> unwarranted
> +         * given the current limited use of groups. */
> +        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
> +
> +        VLOG_ERR_RL(&rl, "cannot recursively translate OpenFlow group");
> +        return false;
> +    } else {
> +        return true;
> +    }
>  }
>
>  static bool
>  xlate_group_action(struct xlate_ctx *ctx, uint32_t group_id)
>  {
> -    if (xlate_resubmit_resource_check(ctx)) {
> +    if (xlate_group_resource_check(ctx)) {
>          struct group_dpif *group;
>          bool got_group;
>
> @@ -2974,6 +3003,7 @@ xlate_actions__(struct xlate_in *xin, struct
> xlate_out *xout)
>
>      ctx.recurse = 0;
>      ctx.resubmits = 0;
> +    ctx.in_group = false;
>      ctx.orig_skb_priority = flow->skb_priority;
>      ctx.table_id = 0;
>      ctx.exit = false;
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index 328b215..7c5b941 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -3291,6 +3291,20 @@ static enum ofperr
>  group_construct(struct ofgroup *group_)
>  {
>      struct group_dpif *group = group_dpif_cast(group_);
> +    const struct ofputil_bucket *bucket;
> +
> +    /* Prevent group chaining because our locking structure makes it hard
> to
> +     * implement deadlock-free.  (See xlate_group_resource_check().) */
> +    LIST_FOR_EACH (bucket, list_node, &group->up.buckets) {
> +        const struct ofpact *a;
> +
> +        OFPACT_FOR_EACH (a, bucket->ofpacts, bucket->ofpacts_len) {
> +            if (a->type == OFPACT_GROUP) {
> +                return OFPERR_OFPGMFC_CHAINING_UNSUPPORTED;
> +            }
> +        }
> +    }
> +
>      ovs_mutex_init_adaptive(&group->stats_mutex);
>      ovs_mutex_lock(&group->stats_mutex);
>      group_construct_stats(group);
> diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
> index 06c4046..6d48e5a 100644
> --- a/tests/ofproto-dpif.at
> +++ b/tests/ofproto-dpif.at
> @@ -112,6 +112,17 @@ AT_CHECK([tail -1 stdout], [0],
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
>
> +AT_SETUP([ofproto-dpif - group chaining not supported])
> +OVS_VSWITCHD_START
> +ADD_OF_PORTS([br0], [1], [10], [11])
> +AT_CHECK([ovs-ofctl -O OpenFlow12 add-group br0
> 'group_id=1234,type=all,bucket=output:10,set_field:192.168.3.90->ip_src,group:123,bucket=output:11'],
> +  [1], [], [stderr])
> +AT_CHECK([STRIP_XIDS stderr | sed 1q], [0],
> +  [OFPT_ERROR (OF1.2): OFPGMFC_CHAINING_UNSUPPORTED
> +])
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
> +
>  AT_SETUP([ofproto-dpif - all group in action list])
>  OVS_VSWITCHD_START
>  ADD_OF_PORTS([br0], [1], [10], [11])
> --
> 1.7.10.4
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openvswitch.org/pipermail/ovs-dev/attachments/20140221/030135b0/attachment-0005.html>


More information about the dev mailing list