[ovs-dev] [PATCH v8] ofproto: Honour Table Mod settings for table-miss handling

Simon Horman horms at verge.net.au
Thu Feb 20 02:19:29 UTC 2014


Apologies for sending this twice, both posts contain the same patch,
so please ignore one of them.

On Thu, Feb 20, 2014 at 11:17:41AM +0900, Simon Horman wrote:
> This reworks lookup of rules for both table 0 and table action translation.
> The result is that Table Mod settings, which can alter the miss-behaviour
> of tables, including table 0, on a per-table basis may be honoured.
> 
> Previous patches proposed by myself which build on earlier merged patches
> by Andy Zhou implement the ofproto side of Table Mod. So with this patch
> the feature should be complete.
> 
> Neither this patch, nor any other patches it builds on, alter the default
> behaviour of Open vSwitch. And in particular the OpenFlow1.1 behaviour is
> the default regardless of which OpenFlow version is negotiated between the
> switch and the controller.
> 
> An implementation detail, which lends itself to future work, is the
> handling of OFPTC_TABLE_MISS_CONTINUE. If a table has this behaviour set by
> Table Mod and a miss occurs then a loop is created, skipping to the next
> table. It is quite easy to create a situation where this loop covers ~255
> tables which is very expensive as the lookup for each table involves taking
> locks, amongst other things.
> 
> Cc: Andy Zhou <azhou at nicira.com>
> Signed-off-by: Simon Horman <horms at verge.net.au>
> 
> ---
> v8
> * Rebase
> 
> v7
> * As suggested by Ben Pfaff
>   - Used simplified loop/case logic in rule_dpif_lookup_from_table()
>     + I re-introduced next_id so that table_id is not advanced to
>       ofproto->up.n_tables.
>   - Consolidate logic of xlate_table_action() and rule_dpif_lookup()
>     into rule_dpif_lookup_from_table()
>   - Do not honour table mod settings in the case of a resubmit action
> 
> v4 - v6
> * Rebase
> 
> v3
> * Remove bogus fall-through comment in OFPTC_TABLE_MISS_CONTROLLER case
>   in rule_dpif_lookup_from_table(). This case always returns.
> * Add fall-through from OFPTC_TABLE_MISS_CONTROLLER
>   to OFPTC_TABLE_MISS_DROP in xlate_table_action() to handle
>   situations where packet_in is not allowed.
> * Re-arrange rule_dpif_lookup_from_table() and xlate_table_action()
>   to only have one call to choose_miss_rule(). This seems tidier.
> * Consistently call ovs-ofctl monitor without a -P argument
> * Remove ofproto parameter name from declaration of table_get_config().
>   This is in keeping with the coding style of other declarations in
>   ofproto.h
> * Only allow supported configurations in table_mod message
> 
> v2
> * Use ofproto->up.n_tables instead of N_TABLES as the number
>   of tables present.
> * Do not use the presence of rules in a table to indicate that it is
>   present. Instead treat all tables, other than TBL_INTERNAL, that
>   exist in ofproto.up as present. This simplifies things slightly
>   and seems to be a more logical approach.
> * As pointed out by Yamamoto-san
>   - Read config for each table that is missed rather
>     than just the first one. A logic bug that somehow I was blind to.
> ---
>  OPENFLOW-1.1+                |   5 -
>  ofproto/ofproto-dpif-xlate.c |  77 ++++++----
>  ofproto/ofproto-dpif.c       | 183 ++++++++++++++++++++--
>  ofproto/ofproto-dpif.h       |  12 +-
>  ofproto/ofproto.c            |  14 +-
>  ofproto/ofproto.h            |   5 +
>  tests/ofproto-dpif.at        | 353 +++++++++++++++++++++++++++++++++++++++++++
>  7 files changed, 600 insertions(+), 49 deletions(-)
> 
> diff --git a/OPENFLOW-1.1+ b/OPENFLOW-1.1+
> index 1b8a0ee..4363d28 100644
> --- a/OPENFLOW-1.1+
> +++ b/OPENFLOW-1.1+
> @@ -54,11 +54,6 @@ OpenFlow 1.1
>  The list of remaining work items for OpenFlow 1.1 is below.  It is
>  probably incomplete.
>  
> -    * OFPT_TABLE_MOD message.  This is new in OF1.1, so we need to
> -      implement it.  It should be implemented so that the default OVS
> -      behavior does not change.  Simon Horman has posted a patch.
> -      [required for OF1.1 and OF1.2]
> -
>      * MPLS.  Simon Horman maintains a patch series that adds this
>        feature.  This is partially merged.
>        [optional for OF1.1+]
> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
> index ccf0b75..0b3d963 100644
> --- a/ofproto/ofproto-dpif-xlate.c
> +++ b/ofproto/ofproto-dpif-xlate.c
> @@ -225,8 +225,9 @@ static void xlate_actions__(struct xlate_in *, struct xlate_out *)
>      OVS_REQ_RDLOCK(xlate_rwlock);
>      static void xlate_normal(struct xlate_ctx *);
>      static void xlate_report(struct xlate_ctx *, const char *);
> -    static void xlate_table_action(struct xlate_ctx *, ofp_port_t in_port,
> -                                   uint8_t table_id, bool may_packet_in);
> +static void xlate_table_action(struct xlate_ctx *, ofp_port_t in_port,
> +                               uint8_t table_id, bool may_packet_in,
> +                               bool force_controller_on_miss);
>  static bool input_vid_is_valid(uint16_t vid, struct xbundle *, bool warn);
>  static uint16_t input_vid_to_vlan(const struct xbundle *, uint16_t vid);
>  static void output_normal(struct xlate_ctx *, const struct xbundle *,
> @@ -1719,14 +1720,14 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
>              ctx->xout->slow |= special;
>          } else if (may_receive(peer, ctx)) {
>              if (xport_stp_forward_state(peer)) {
> -                xlate_table_action(ctx, flow->in_port.ofp_port, 0, true);
> +                xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, false);
>              } else {
>                  /* Forwarding is disabled by STP.  Let OFPP_NORMAL and the
>                   * learning action look at the packet, then drop it. */
>                  struct flow old_base_flow = ctx->base_flow;
>                  size_t old_size = ctx->xout->odp_actions.size;
>                  mirror_mask_t old_mirrors = ctx->xout->mirrors;
> -                xlate_table_action(ctx, flow->in_port.ofp_port, 0, true);
> +                xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, false);
>                  ctx->xout->mirrors = old_mirrors;
>                  ctx->base_flow = old_base_flow;
>                  ctx->xout->odp_actions.size = old_size;
> @@ -1861,15 +1862,43 @@ xlate_resubmit_resource_check(struct xlate_ctx *ctx)
>      return false;
>  }
>  
> +struct get_ofp_port_config_cb_data {
> +    const struct xbridge *xbridge;
> +    ofp_port_t ofp_port;
> +    bool may_packet_in;
> +};
> +
> +static enum ofputil_port_config
> +get_ofp_port_config_cb(const void *data_)
> +{
> +    const struct get_ofp_port_config_cb_data *data;
> +
> +    data = (struct get_ofp_port_config_cb_data *)data_;
> +
> +    if (data->may_packet_in) {
> +        struct xport *xport;
> +
> +        xport = get_ofp_port(data->xbridge, data->ofp_port);
> +        return xport->config;
> +    } else {
> +        return OFPUTIL_PC_NO_PACKET_IN;
> +    }
> +}
> +
>  static void
> -xlate_table_action(struct xlate_ctx *ctx,
> -                   ofp_port_t in_port, uint8_t table_id, bool may_packet_in)
> +xlate_table_action(struct xlate_ctx *ctx, ofp_port_t in_port, uint8_t table_id,
> +                   bool may_packet_in, bool force_controller_on_miss)
>  {
>      if (xlate_resubmit_resource_check(ctx)) {
>          ofp_port_t old_in_port = ctx->xin->flow.in_port.ofp_port;
>          bool skip_wildcards = ctx->xin->skip_wildcards;
>          uint8_t old_table_id = ctx->table_id;
>          struct rule_dpif *rule;
> +        struct get_ofp_port_config_cb_data get_ofp_port_config_cb_data = {
> +            .xbridge = ctx->xbridge,
> +            .ofp_port = ctx->xin->flow.in_port.ofp_port,
> +            .may_packet_in = may_packet_in,
> +        };
>  
>          ctx->table_id = table_id;
>  
> @@ -1877,29 +1906,20 @@ xlate_table_action(struct xlate_ctx *ctx,
>           * original input port (otherwise OFPP_NORMAL and OFPP_IN_PORT will
>           * have surprising behavior). */
>          ctx->xin->flow.in_port.ofp_port = in_port;
> -        rule_dpif_lookup_in_table(ctx->xbridge->ofproto, &ctx->xin->flow,
> -                                  !skip_wildcards ? &ctx->xout->wc : NULL,
> -                                  table_id, &rule);
> +        rule_dpif_lookup_from_table(ctx->xbridge->ofproto, &ctx->xin->flow,
> +                                    !skip_wildcards ? &ctx->xout->wc : NULL,
> +                                    ctx->xbridge->miss_rule,
> +                                    ctx->xbridge->no_packet_in_rule,
> +                                    get_ofp_port_config_cb,
> +                                    &get_ofp_port_config_cb_data,
> +                                    force_controller_on_miss,
> +                                    &ctx->table_id, &rule);
>          ctx->xin->flow.in_port.ofp_port = old_in_port;
>  
>          if (ctx->xin->resubmit_hook) {
>              ctx->xin->resubmit_hook(ctx->xin, rule, ctx->recurse);
>          }
>  
> -        if (!rule && may_packet_in) {
> -            struct xport *xport;
> -
> -            /* XXX
> -             * check if table configuration flags
> -             * OFPTC11_TABLE_MISS_CONTROLLER, default.
> -             * OFPTC11_TABLE_MISS_CONTINUE,
> -             * OFPTC11_TABLE_MISS_DROP
> -             * When OF1.0, OFPTC11_TABLE_MISS_CONTINUE is used. What to do? */
> -            xport = get_ofp_port(ctx->xbridge, ctx->xin->flow.in_port.ofp_port);
> -            choose_miss_rule(xport ? xport->config : 0,
> -                             ctx->xbridge->miss_rule,
> -                             ctx->xbridge->no_packet_in_rule, &rule);
> -        }
>          if (rule) {
>              xlate_recursively(ctx, rule);
>              rule_dpif_unref(rule);
> @@ -2032,7 +2052,7 @@ xlate_ofpact_resubmit(struct xlate_ctx *ctx,
>          table_id = ctx->table_id;
>      }
>  
> -    xlate_table_action(ctx, in_port, table_id, false);
> +    xlate_table_action(ctx, in_port, table_id, false, true);
>  }
>  
>  static void
> @@ -2240,7 +2260,7 @@ xlate_output_action(struct xlate_ctx *ctx,
>          break;
>      case OFPP_TABLE:
>          xlate_table_action(ctx, ctx->xin->flow.in_port.ofp_port,
> -                           0, may_packet_in);
> +                           0, may_packet_in, false);
>          break;
>      case OFPP_NORMAL:
>          xlate_normal(ctx);
> @@ -2753,7 +2773,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
>  
>              ovs_assert(ctx->table_id < ogt->table_id);
>              xlate_table_action(ctx, ctx->xin->flow.in_port.ofp_port,
> -                               ogt->table_id, true);
> +                               ogt->table_id, true, false);
>              break;
>          }
>  
> @@ -2979,8 +2999,9 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout)
>      ctx.exit = false;
>  
>      if (!xin->ofpacts && !ctx.rule) {
> -        rule_dpif_lookup(ctx.xbridge->ofproto, flow,
> -                         !xin->skip_wildcards ? wc : NULL, &rule);
> +        ctx.table_id = rule_dpif_lookup(ctx.xbridge->ofproto, flow,
> +                                        !xin->skip_wildcards ? wc : NULL,
> +                                        &rule);
>          if (ctx.xin->resubmit_stats) {
>              rule_dpif_credit_stats(rule, ctx.xin->resubmit_stats);
>          }
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index 328b215..01eb7a2 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -3050,25 +3050,51 @@ rule_dpif_get_actions(const struct rule_dpif *rule)
>      return rule_get_actions(&rule->up);
>  }
>  
> -/* Lookup 'flow' in 'ofproto''s classifier.  If 'wc' is non-null, sets
> - * the fields that were relevant as part of the lookup. */
> -void
> -rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow,
> -                 struct flow_wildcards *wc, struct rule_dpif **rule)
> +struct get_ofp_port_config_cb_data  {
> +    const struct ofproto_dpif *ofproto;
> +    ofp_port_t ofp_port;
> +};
> +
> +static enum ofputil_port_config
> +get_ofp_port_config_cb(const void *data_)
>  {
> +    const struct get_ofp_port_config_cb_data *data;
>      struct ofport_dpif *port;
>  
> -    if (rule_dpif_lookup_in_table(ofproto, flow, wc, 0, rule)) {
> -        return;
> -    }
> -    port = get_ofp_port(ofproto, flow->in_port.ofp_port);
> +    data = (struct get_ofp_port_config_cb_data *)data_;
> +
> +    port = get_ofp_port(data->ofproto, data->ofp_port);
>      if (!port) {
>          VLOG_WARN_RL(&rl, "packet-in on unknown OpenFlow port %"PRIu16,
> -                     flow->in_port.ofp_port);
> +                     data->ofp_port);
> +        return 0;
>      }
> +    return port->up.pp.config;
> +}
>  
> -    choose_miss_rule(port ? port->up.pp.config : 0, ofproto->miss_rule,
> -                     ofproto->no_packet_in_rule, rule);
> +/* Lookup 'flow' in table 0 of 'ofproto''s classifier.
> + * If 'wc' is non-null, sets the fields that were relevant as part of
> + * the lookup. Returns the table_id where a match or miss occurred.
> + *
> + * The return value will be zero unless there was a miss and
> + * OFPTC_TABLE_MISS_CONTINUE is in effect for the sequence of tables
> + * where misses occur. */
> +uint8_t
> +rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow,
> +                 struct flow_wildcards *wc, struct rule_dpif **rule)
> +{
> +    uint8_t table_id = 0;
> +    struct get_ofp_port_config_cb_data get_ofp_port_config_cb_data = {
> +        .ofproto = ofproto,
> +        .ofp_port = flow->in_port.ofp_port,
> +    };
> +
> +    rule_dpif_lookup_from_table(ofproto, flow, wc, ofproto->miss_rule,
> +                                ofproto->no_packet_in_rule,
> +                                get_ofp_port_config_cb,
> +                                &get_ofp_port_config_cb_data, false,
> +                                &table_id, rule);
> +    return table_id;
>  }
>  
>  bool
> @@ -3115,6 +3141,139 @@ rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto,
>      return *rule != NULL;
>  }
>  
> +enum rule_dpif_lookup_verdict {
> +    RULE_DPIF_LOOKUP_VERDICT_MATCH,         /* A match occurred. */
> +    RULE_DPIF_LOOKUP_VERDICT_CONTROLLER,    /* A miss occurred and the packet
> +                                             * should be passed to
> +                                             * the controller. */
> +    RULE_DPIF_LOOKUP_VERDICT_DROP,          /* A miss occurred and the packet
> +                                             * should be dropped. */
> +};
> +
> +/* Lookup 'flow' in 'ofproto''s classifier starting at 'table_id'.
> + *
> + * If 'wc' is non-null, sets the fields that were relevant as part
> + * of the lookup.
> + *
> + * 'table_id' is set to the table where a match or miss occurred.
> + * This value will be the input value of 'table_id' unless there was
> + * a miss and OFPTC_TABLE_MISS_CONTINUE is in effect for the sequence of
> + * tables where misses occur.
> + *
> + * If 'force_controller_on_miss' is true then if a miss occurs
> + * then RULE_OFPTC_TABLE_MISS_CONTROLLER will be returned regarless
> + * of which OFPTC_TABLE_* setting is in effect.
> + *
> + * The return value is:
> + * RULE_DPIF_LOOKUP_VERDICT_MATCH:      If a match occurred
> + * RULE_OFPTC_TABLE_MISS_CONTROLLER:    If a miss occurred and the packet
> + *                                      should be forwarded to the controller.
> + * RULE_OFPTC_TABLE_MISS_DROP:          If a miss occurred and the packet
> + *                                      should be dropped. */
> +static enum rule_dpif_lookup_verdict
> +rule_dpif_lookup_from_table__(struct ofproto_dpif *ofproto,
> +                              const struct flow *flow,
> +                              struct flow_wildcards *wc,
> +                              bool force_controller_on_miss,
> +                              uint8_t *table_id, struct rule_dpif **rule)
> +{
> +    uint8_t next_id = *table_id;
> +
> +    while (next_id < ofproto->up.n_tables) {
> +        enum ofp_table_config config;
> +
> +        *table_id = next_id;
> +
> +        if (rule_dpif_lookup_in_table(ofproto, flow, wc, *table_id, rule)) {
> +            return RULE_DPIF_LOOKUP_VERDICT_MATCH;
> +        }
> +
> +        if (force_controller_on_miss) {
> +            break;
> +        }
> +
> +        /* XXX
> +         * This does not take into account different
> +         * behaviour for different OpenFlow versions
> +         *
> +         * OFPTC11_TABLE_MISS_CONTINUE:   Behaviour of OpenFlow1.0
> +         * OFPTC11_TABLE_MISS_CONTROLLER: Default for OpenFlow1.1+
> +         * OFPTC11_TABLE_MISS_DROP:       Default for OpenFlow1.3+
> +         *
> +         * Instead the global default is OFPTC_TABLE_MISS_CONTROLLER
> +         * which may be configured globally using Table Mod. */
> +        config = table_get_config(&ofproto->up, *table_id);
> +        switch (config & OFPTC11_TABLE_MISS_MASK) {
> +        case OFPTC11_TABLE_MISS_CONTINUE:
> +            break;
> +        case OFPTC11_TABLE_MISS_CONTROLLER:
> +            return RULE_DPIF_LOOKUP_VERDICT_CONTROLLER;
> +        case OFPTC11_TABLE_MISS_DROP:
> +            return RULE_DPIF_LOOKUP_VERDICT_DROP;
> +        }
> +
> +        /* Go on to next table. */
> +        ++next_id;
> +        if (next_id == TBL_INTERNAL) {
> +            ++next_id;
> +        }
> +    }
> +
> +    /* Either we fell off the end or
> +     * a miss occured with force_controller_on_miss set */
> +    return RULE_DPIF_LOOKUP_VERDICT_CONTROLLER;
> +}
> +
> +/* Lookup 'flow' in 'ofproto''s classifier starting at 'table_id'.
> + *
> + * If 'wc' is non-null, sets the fields that were relevant as part
> + * of the lookup.
> + *
> + * 'table_id' is set to the table where a match or miss occurred.
> + * This value will be the input value of 'table_id' unless there was
> + * a miss and OFPTC_TABLE_MISS_CONTINUE is in effect for the sequence of
> + * tables where misses occur.
> + *
> + * If a no matching rule is found, even after continuting if
> + * OFPTC_TABLE_MISS_CONTINUE is in effect, then use miss_rule or
> + * no_packet_in_rule according to the ofputil_port_config returned
> + * by get_ofp_port_config_cb when called with get_ofp_port_config_cb_data
> + * as its parameter. */
> +void
> +rule_dpif_lookup_from_table(struct ofproto_dpif *ofproto,
> +                            const struct flow *flow, struct flow_wildcards *wc,
> +                            struct rule_dpif *miss_rule,
> +                            struct rule_dpif *no_packet_in_rule,
> +                            enum ofputil_port_config
> +                            (*get_ofp_port_config_cb)(const void *),
> +                            void *get_ofp_port_config_cb_data,
> +                            bool force_controller_on_miss,
> +                            uint8_t *table_id, struct rule_dpif **rule)
> +{
> +    enum rule_dpif_lookup_verdict verdict;
> +    enum ofputil_port_config config;
> +
> +    verdict = rule_dpif_lookup_from_table__(ofproto, flow, wc,
> +                                            force_controller_on_miss,
> +                                            table_id, rule);
> +
> +    switch (verdict) {
> +    case RULE_DPIF_LOOKUP_VERDICT_MATCH:
> +        return;
> +    case RULE_DPIF_LOOKUP_VERDICT_CONTROLLER:
> +        config = get_ofp_port_config_cb(get_ofp_port_config_cb_data);
> +        break;
> +    case RULE_DPIF_LOOKUP_VERDICT_DROP:
> +        config = OFPUTIL_PC_NO_PACKET_IN;
> +        break;
> +    default:
> +        OVS_NOT_REACHED();
> +    }
> +
> +    choose_miss_rule(config, miss_rule, no_packet_in_rule, rule);
> +    return;
> +}
> +
>  /* Given a port configuration (specified as zero if there's no port), chooses
>   * which of 'miss_rule' and 'no_packet_in_rule' should be used in case of a
>   * flow table miss. */
> diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h
> index d09e285..f526104 100644
> --- a/ofproto/ofproto-dpif.h
> +++ b/ofproto/ofproto-dpif.h
> @@ -67,8 +67,16 @@ extern struct ovs_rwlock xlate_rwlock;
>  
>  size_t ofproto_dpif_get_max_mpls_depth(const struct ofproto_dpif *);
>  
> -void rule_dpif_lookup(struct ofproto_dpif *, const struct flow *,
> -                      struct flow_wildcards *, struct rule_dpif **rule);
> +uint8_t rule_dpif_lookup(struct ofproto_dpif *, const struct flow *,
> +                         struct flow_wildcards *, struct rule_dpif **rule);
> +
> +void rule_dpif_lookup_from_table(struct ofproto_dpif *, const struct flow *,
> +                                 struct flow_wildcards *,
> +                                 struct rule_dpif *miss_rule,
> +                                 struct rule_dpif *no_packet_in_rule,
> +                                 enum ofputil_port_config(*)(const void *),
> +                                 void *, bool, uint8_t *,
> +                                 struct rule_dpif **rule);
>  
>  bool rule_dpif_lookup_in_table(struct ofproto_dpif *, const struct flow *,
>                                 struct flow_wildcards *, uint8_t table_id,
> diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
> index f69736c..660550f 100644
> --- a/ofproto/ofproto.c
> +++ b/ofproto/ofproto.c
> @@ -5794,11 +5794,21 @@ handle_group_mod(struct ofconn *ofconn, const struct ofp_header *oh)
>      }
>  }
>  
> +enum ofp_table_config
> +table_get_config(const struct ofproto *ofproto, uint8_t table_id)
> +{
> +    unsigned int value;
> +    atomic_read(&ofproto->tables[table_id].config, &value);
> +    return (enum ofp_table_config)value;
> +}
> +
>  static enum ofperr
>  table_mod(struct ofproto *ofproto, const struct ofputil_table_mod *tm)
>  {
> -    /* XXX Reject all configurations because none are currently supported */
> -    return OFPERR_OFPTMFC_BAD_CONFIG;
> +    /* Only accept currently supported configurations */
> +    if (tm->config & ~OFPTC11_TABLE_MISS_MASK) {
> +        return OFPERR_OFPTMFC_BAD_CONFIG;
> +    }
>  
>      if (tm->table_id == OFPTT_ALL) {
>          int i;
> diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
> index 1f9cb15..c028abc 100644
> --- a/ofproto/ofproto.h
> +++ b/ofproto/ofproto.h
> @@ -431,6 +431,11 @@ void ofproto_get_vlan_usage(struct ofproto *, unsigned long int *vlan_bitmap);
>  bool ofproto_has_vlan_usage_changed(const struct ofproto *);
>  int ofproto_port_set_realdev(struct ofproto *, ofp_port_t vlandev_ofp_port,
>                               ofp_port_t realdev_ofp_port, int vid);
> +
> +/* Table configuration */
> +
> +enum ofp_table_config table_get_config(const struct ofproto *,
> +                                       uint8_t table_id);
>  
>  #ifdef  __cplusplus
>  }
> diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
> index 06c4046..8aacdeb 100644
> --- a/tests/ofproto-dpif.at
> +++ b/tests/ofproto-dpif.at
> @@ -429,6 +429,359 @@ AT_CHECK([tail -1 stdout], [0],
>  OVS_VSWITCHD_STOP
>  AT_CLEANUP
>  
> +AT_SETUP([ofproto-dpif - Table Miss - OFPTC_TABLE_MISS_CONTROLLER])
> +OVS_VSWITCHD_START([dnl
> +   add-port br0 p1 -- set Interface p1 type=dummy
> +])
> +ON_EXIT([kill `cat ovs-ofctl.pid`])
> +
> +AT_CAPTURE_FILE([ofctl_monitor.log])
> +
> +AT_CHECK([ovs-ofctl monitor br0 65534 --detach --no-chdir --pidfile 2> ofctl_monitor.log])
> +
> +for i in 1 2 3 ; do
> +    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
> +done
> +
> +OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
> +AT_CHECK([cat ofctl_monitor.log], [0], [dnl
> +NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
> +tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010 tcp_csum:0
> +dnl
> +NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
> +tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010 tcp_csum:0
> +dnl
> +NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
> +tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010 tcp_csum:0
> +])
> +
> +AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
> +AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
> +NXST_FLOW reply:
> +])
> +
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([ofproto-dpif - Table Miss - goto table and OFPTC_TABLE_MISS_CONTROLLER])
> +OVS_VSWITCHD_START([dnl
> +   add-port br0 p1 -- set Interface p1 type=dummy
> +])
> +ON_EXIT([kill `cat ovs-ofctl.pid`])
> +
> +AT_CAPTURE_FILE([ofctl_monitor.log])
> +AT_CHECK([ovs-ofctl -OOpenFlow12 add-flow br0 'table=0 actions=goto_table(1)'])
> +
> +AT_CHECK([ovs-ofctl monitor -P openflow10 br0 65534 --detach --no-chdir --pidfile 2> ofctl_monitor.log])
> +
> +for i in 1 2 3 ; do
> +    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
> +done
> +
> +OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
> +AT_CHECK([cat ofctl_monitor.log], [0], [dnl
> +OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
> +tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010 tcp_csum:0
> +dnl
> +OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
> +tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010 tcp_csum:0
> +dnl
> +OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
> +tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010 tcp_csum:0
> +])
> +
> +AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
> +AT_CHECK([ovs-ofctl -OOpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
> + n_packets=3, n_bytes=180, actions=goto_table:1
> +OFPST_FLOW reply (OF1.2):
> +])
> +
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([ofproto-dpif - Table Miss - resubmit and OFPTC_TABLE_MISS_CONTROLLER])
> +OVS_VSWITCHD_START([dnl
> +   add-port br0 p1 -- set Interface p1 type=dummy
> +])
> +ON_EXIT([kill `cat ovs-ofctl.pid`])
> +
> +AT_CAPTURE_FILE([ofctl_monitor.log])
> +AT_CHECK([ovs-ofctl -OOpenFlow12 add-flow br0 'table=0 actions=resubmit(1,1)'])
> +
> +AT_CHECK([ovs-ofctl monitor -P openflow10 br0 65534 --detach --no-chdir --pidfile 2> ofctl_monitor.log])
> +
> +for i in 1 2 3 ; do
> +    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
> +done
> +
> +OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
> +AT_CHECK([cat ofctl_monitor.log], [0], [dnl
> +])
> +
> +AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
> +AT_CHECK([ovs-ofctl -OOpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
> + n_packets=3, n_bytes=180, actions=resubmit(1,1)
> +OFPST_FLOW reply (OF1.2):
> +])
> +
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([ofproto-dpif - Table Miss - OFPTC_TABLE_MISS_CONTINUE])
> +OVS_VSWITCHD_START([dnl
> +   add-port br0 p1 -- set Interface p1 type=dummy
> +])
> +ON_EXIT([kill `cat ovs-ofctl.pid`])
> +
> +AT_CAPTURE_FILE([ofctl_monitor.log])
> +AT_CHECK([ovs-ofctl add-flow br0 'table=1 dl_src=10:11:11:11:11:11 actions=controller'])
> +AT_CHECK([ovs-ofctl -OOpenFlow11 mod-table br0 all continue])
> +
> +dnl Miss table 0, Hit table 1
> +AT_CHECK([ovs-ofctl monitor br0 65534 --detach --no-chdir --pidfile 2> ofctl_monitor.log])
> +
> +for i in 1 2 3 ; do
> +    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=10:11:11:11:11:11,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
> +done
> +OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
> +
> +AT_CHECK([cat ofctl_monitor.log], [0], [dnl
> +NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
> +tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010 tcp_csum:0
> +dnl
> +NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
> +tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010 tcp_csum:0
> +dnl
> +NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
> +tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010 tcp_csum:0
> +])
> +
> +dnl Hit table 0, Miss all other tables, sent to controller
> +AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --no-chdir --pidfile 2> ofctl_monitor.log])
> +
> +for i in 1 2 3 ; do
> +    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
> +done
> +OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
> +
> +AT_CHECK([cat ofctl_monitor.log], [0], [dnl
> +NXT_PACKET_IN (xid=0x0): table_id=253 cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
> +tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010 tcp_csum:0
> +dnl
> +NXT_PACKET_IN (xid=0x0): table_id=253 cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
> +tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010 tcp_csum:0
> +dnl
> +NXT_PACKET_IN (xid=0x0): table_id=253 cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
> +tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010 tcp_csum:0
> +])
> +
> +AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
> +AT_CHECK([ovs-ofctl -OOpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
> + table=1, n_packets=3, n_bytes=180, dl_src=10:11:11:11:11:11 actions=CONTROLLER:65535
> +OFPST_FLOW reply (OF1.2):
> +])
> +
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([ofproto-dpif - Table Miss - goto table and OFPTC_TABLE_MISS_CONTINUE])
> +OVS_VSWITCHD_START([dnl
> +   add-port br0 p1 -- set Interface p1 type=dummy
> +])
> +ON_EXIT([kill `cat ovs-ofctl.pid`])
> +
> +AT_CAPTURE_FILE([ofctl_monitor.log])
> +AT_DATA([flows.txt], [dnl
> +table=0 actions=goto_table(1)
> +table=2 dl_src=10:11:11:11:11:11 actions=controller
> +])
> +AT_CHECK([ovs-ofctl -OOpenFlow12 add-flows br0 flows.txt])
> +AT_CHECK([ovs-ofctl -OOpenFlow11 mod-table br0 all continue])
> +
> +dnl Hit table 0, Miss table 1, Hit table 2
> +AT_CHECK([ovs-ofctl monitor br0 65534 --detach --no-chdir --pidfile 2> ofctl_monitor.log])
> +
> +for i in 1 2 3 ; do
> +    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=10:11:11:11:11:11,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
> +done
> +OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
> +
> +AT_CHECK([cat ofctl_monitor.log], [0], [dnl
> +NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
> +tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010 tcp_csum:0
> +dnl
> +NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
> +tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010 tcp_csum:0
> +dnl
> +NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
> +tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010 tcp_csum:0
> +])
> +
> +dnl Hit table 1, Miss all other tables, sent to controller
> +AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --no-chdir --pidfile 2> ofctl_monitor.log])
> +
> +for i in 1 2 3 ; do
> +    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
> +done
> +OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
> +
> +AT_CHECK([cat ofctl_monitor.log], [0], [dnl
> +NXT_PACKET_IN (xid=0x0): table_id=253 cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
> +tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010 tcp_csum:0
> +dnl
> +NXT_PACKET_IN (xid=0x0): table_id=253 cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
> +tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010 tcp_csum:0
> +dnl
> +NXT_PACKET_IN (xid=0x0): table_id=253 cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
> +tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=0x010 tcp_csum:0
> +])
> +
> +AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
> +AT_CHECK([ovs-ofctl -OOpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
> + n_packets=6, n_bytes=360, actions=goto_table:1
> + table=2, n_packets=3, n_bytes=180, dl_src=10:11:11:11:11:11 actions=CONTROLLER:65535
> +OFPST_FLOW reply (OF1.2):
> +])
> +
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([ofproto-dpif - Table Miss - resubmit and OFPTC_TABLE_MISS_CONTINUE])
> +OVS_VSWITCHD_START([dnl
> +   add-port br0 p1 -- set Interface p1 type=dummy
> +])
> +ON_EXIT([kill `cat ovs-ofctl.pid`])
> +
> +AT_CAPTURE_FILE([ofctl_monitor.log])
> +AT_DATA([flows.txt], [dnl
> +table=0 actions=resubmit(1,1)
> +table=2 dl_src=10:11:11:11:11:11 actions=controller
> +])
> +AT_CHECK([ovs-ofctl -OOpenFlow12 add-flows br0 flows.txt])
> +AT_CHECK([ovs-ofctl -OOpenFlow11 mod-table br0 all continue])
> +
> +dnl Hit table 0, Miss table 1, Dropped
> +AT_CHECK([ovs-ofctl monitor br0 65534 --detach --no-chdir --pidfile 2> ofctl_monitor.log])
> +
> +for i in 1 2 3 ; do
> +    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=10:11:11:11:11:11,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
> +done
> +OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
> +
> +AT_CHECK([cat ofctl_monitor.log], [0], [dnl
> +])
> +
> +dnl Hit table 1, Dropped
> +AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --no-chdir --pidfile 2> ofctl_monitor.log])
> +
> +for i in 1 2 3 ; do
> +    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
> +done
> +OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
> +
> +AT_CHECK([cat ofctl_monitor.log], [0], [dnl
> +])
> +
> +AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
> +AT_CHECK([ovs-ofctl -OOpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
> + n_packets=6, n_bytes=360, actions=resubmit(1,1)
> + table=2, dl_src=10:11:11:11:11:11 actions=CONTROLLER:65535
> +OFPST_FLOW reply (OF1.2):
> +])
> +
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([ofproto-dpif - Table Miss - OFPTC_TABLE_MISS_DROP])
> +OVS_VSWITCHD_START([dnl
> +   add-port br0 p1 -- set Interface p1 type=dummy
> +])
> +ON_EXIT([kill `cat ovs-ofctl.pid`])
> +
> +AT_CAPTURE_FILE([ofctl_monitor.log])
> +AT_CHECK([ovs-ofctl -OOpenFlow11 mod-table br0 all drop])
> +
> +AT_CHECK([ovs-ofctl monitor -P openflow10 br0 65534 --detach --no-chdir --pidfile 2> ofctl_monitor.log])
> +
> +dnl Test that missed packets are droped
> +for i in 1 2 3 ; do
> +    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
> +done
> +OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
> +
> +AT_CHECK([cat ofctl_monitor.log], [0], [dnl
> +])
> +
> +AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
> +AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
> +NXST_FLOW reply:
> +])
> +
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([ofproto-dpif - Table Miss - goto table and OFPTC_TABLE_MISS_DROP])
> +OVS_VSWITCHD_START([dnl
> +   add-port br0 p1 -- set Interface p1 type=dummy
> +])
> +ON_EXIT([kill `cat ovs-ofctl.pid`])
> +
> +AT_CAPTURE_FILE([ofctl_monitor.log])
> +AT_CHECK([ovs-ofctl del-flows br0])
> +AT_CHECK([ovs-ofctl -OOpenFlow12 add-flow br0 'table=0 actions=goto_table(1)'])
> +AT_CHECK([ovs-ofctl -OOpenFlow11 mod-table br0 all drop])
> +
> +AT_CHECK([ovs-ofctl monitor -P openflow10 br0 65534 --detach --no-chdir --pidfile 2> ofctl_monitor.log])
> +
> +dnl Test that missed packets are droped
> +for i in 1 2 3 ; do
> +    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
> +done
> +OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
> +
> +AT_CHECK([cat ofctl_monitor.log], [0], [dnl
> +])
> +
> +AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
> +AT_CHECK([ovs-ofctl -OOpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
> + n_packets=3, n_bytes=180, actions=goto_table:1
> +OFPST_FLOW reply (OF1.2):
> +])
> +
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
> +
> +AT_SETUP([ofproto-dpif - Table Miss - resubmit and OFPTC_TABLE_MISS_DROP])
> +OVS_VSWITCHD_START([dnl
> +   add-port br0 p1 -- set Interface p1 type=dummy
> +])
> +ON_EXIT([kill `cat ovs-ofctl.pid`])
> +
> +AT_CAPTURE_FILE([ofctl_monitor.log])
> +AT_CHECK([ovs-ofctl del-flows br0])
> +AT_CHECK([ovs-ofctl -OOpenFlow12 add-flow br0 'table=0 actions=resubmit(1,1)'])
> +AT_CHECK([ovs-ofctl -OOpenFlow11 mod-table br0 all drop])
> +
> +AT_CHECK([ovs-ofctl monitor -P openflow10 br0 65534 --detach --no-chdir --pidfile 2> ofctl_monitor.log])
> +
> +dnl Test that missed packets are droped
> +for i in 1 2 3 ; do
> +    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
> +done
> +OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
> +
> +AT_CHECK([cat ofctl_monitor.log], [0], [dnl
> +])
> +
> +AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
> +AT_CHECK([ovs-ofctl -OOpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
> + n_packets=3, n_bytes=180, actions=resubmit(1,1)
> +OFPST_FLOW reply (OF1.2):
> +])
> +
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
> +
>  AT_SETUP([ofproto-dpif - controller])
>  OVS_VSWITCHD_START([dnl
>     add-port br0 p1 -- set Interface p1 type=dummy
> -- 
> 1.8.5.2
> 



More information about the dev mailing list