On Fri, May 24, 2013 at 08:43:59AM +0000, Rajahalme, Jarno (NSN - FI/Espoo) 
wrote:
> Simon,
> 
> Here is some initial review of the ofproto-dpif.c changes,

Thanks, very much appreciated.

>   Jarno
> 
> On May 24, 2013, at 10:18 , ext Simon Horman wrote:
> 
> > diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> > index 49f0270..8b1ccac 100644
> > --- a/ofproto/ofproto-dpif.c
> > +++ b/ofproto/ofproto-dpif.c
> > @@ -43,6 +43,7 @@
> > #include "odp-util.h"
> > #include "ofp-util.h"
> > #include "ofpbuf.h"
> > +#include "odp-execute.h"
> > #include "ofp-actions.h"
> > #include "ofp-parse.h"
> > #include "ofp-print.h"
> > @@ -121,7 +122,8 @@ static struct rule_dpif *rule_dpif_miss_rule(struct 
> > ofproto_dpif *ofproto,
> > 
> > static void rule_credit_stats(struct rule_dpif *,
> >                               const struct dpif_flow_stats *);
> > -static void flow_push_stats(struct facet *, const struct dpif_flow_stats 
> > *);
> > +static void flow_push_stats(struct facet *, const struct dpif_flow_stats *,
> > +                            const struct ofpact *, size_t ofpacts_len);
> > static tag_type rule_calculate_tag(const struct flow *,
> >                                    const struct minimask *, uint32_t basis);
> > static void rule_invalidate(const struct rule_dpif *);
> > @@ -289,6 +291,17 @@ struct action_xlate_ctx {
> >     uint16_t nf_output_iface;   /* Output interface index for NetFlow. */
> >     mirror_mask_t mirrors;      /* Bitmap of associated mirrors. */
> > 
> > +    size_t ofpacts_len;         /* The number of bytes of the ofpacts
> > +                                 * argument to xlate_actions() processed
> > +                                 * by it. This is used to calculate an
> > +                                 * offset into ofpacts for calls to
> > +                                 * xlate_actions on recirculated packets */
> > +
> > +    uint32_t recirculation_id;  /* skb_mark to use to identify
> > +                                 * recirculation. */
> 
> If this was 0 by default, and set to a valid recirculation_id when 
> recirculation is to take place, then you might get rid of the bool 
> recirculated?

There are two cases where recirculation_id is not 0 by default.

1. When RECIRCULATION_ID_DUMMY is used. This is the case when
   executing without a facet, either when handling a flow miss
   without a facet or when handling packet_out.

   The purpose of using RECIRCULATION_ID_DUMMY is to avoid the overhead
   of "allocating" a recirculation_id and the hassle of "freeing"
   the recirculation_id. This is because without a facet the
   recirculation_id used is local to the processing being performed.

2. When revalidating facets.

   a. In order to produce a consistent translation of actions in the presence
      of recirculation the recirculation_id of the facet being revalidated
      is used as the initial value of the recirculation_id element of struct
      action_xlate_ctx.

   b. A facet's recirculation_id is used as the seed value of a
      struct action_xlate_ctx in order to avoid unnecessary allocation of
      recirculation_ids when walking the chain of facets that results from
      a rule that causes recirculation. In this case the recirculated bit
      is used to detect if the facet still adds a recirculation action or
      not.

In order to make the usage of recirculation_id clearer I will update its
comment as follows.

    uint32_t recirculation_id;  /* skb_mark to use to identify recirculation.
                                 * If RECIRCULATION_ID_NONE at the time
                                 * that a recirculate action is added then
                                 * get_recirculation_id() is used to obtain
                                 * a recirculation id which is saved in
                                 * recirculation_id.
                                 * Otherwise the value recirculation_id is
                                 * used.
                                 * In this way both the value of the
                                 * recirculation_id used and the need to
                                 * call get_recirculation_id() may be
                                 * controlled.
                                 * The value RECIRCULATION_ID_DUMMY may
                                 * be used as a temporary recirculation id.
                                 */

I will also update some of the comments in facet_revalidate() as follows:

diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 6258783..97ff9f8 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -5530,9 +5543,8 @@ facet_revalidate(struct facet *facet)
         xlate_actions(&ctx, ofpacts, ofpacts_len, &odp_actions);
 
         if (f->recirculation_id != RECIRCULATION_ID_NONE && !ctx.recirculated) 
{
-           /* If the facet no longer adds a recirculation action or is
-            * queued up for removal then In this case, remove the remaining
-            * facets in the chain as they are longer useful. */
+           /* If the facet no longer adds a recirculation then it is
+            * no longer part of the chain of facets and should be removed. */
             facet_remove(facet);
             ofpbuf_uninit(&odp_actions);
             return;
@@ -5560,6 +5572,8 @@ facet_revalidate(struct facet *facet)
                               &subfacet->initial_vals, new_rule, 0, NULL,
                               recirculation_id);
         xlate_actions(&ctx, ofpacts, ofpacts_len, &odp_actions);
+        /* The recirculation_id may have changed if previously a
+         * recirculate action was not added but currently one is added. */
         recirculation_id = ctx.recirculation_id;
 
         slow = (subfacet->slow & SLOW_MATCH) | ctx.slow;

> > +    bool recirculated;          /* True if the context does not add a
> > +                                 * recirculate action. False otherwise. */
> > +
> 
> The comment seems the reverse of the intended meaning. If not then need to 
> elaborate to make this clearer.

Thanks, the comment is incorrect as you suggest.
I will update it to.

    bool recirculated;          /* True if the context added a recirculate
                                 * action. False otherwise. */

> > /* xlate_actions() initializes and uses these members, but the client has no
> >  * reason to look at them. */
> > 
> > @@ -321,7 +334,8 @@ static void action_xlate_ctx_init(struct 
> > action_xlate_ctx *,
> >                                   struct ofproto_dpif *, const struct flow 
> > *,
> >                                   const struct initial_vals *initial_vals,
> >                                   struct rule_dpif *,
> > -                                  uint8_t tcp_flags, const struct ofpbuf 
> > *);
> > +                                  uint8_t tcp_flags, const struct ofpbuf *,
> > +                                  uint32_t recirculation_id);
> > static void xlate_actions(struct action_xlate_ctx *,
> >                           const struct ofpact *ofpacts, size_t ofpacts_len,
> >                           struct ofpbuf *odp_actions);
> > @@ -504,17 +518,46 @@ struct facet {
> >     struct subfacet one_subfacet;
> > 
> >     long long int learn_rl;      /* Rate limiter for facet_learn(). */
> > +
> > +    const struct ofpact *ofpacts;   /* ofpacts for this facet.
> > +                                     * Will differ from rule->up.ofpacts
> > +                                     * if facet is for a recirculated 
> > packet. */
> > +    size_t ofpacts_len;             /* ofpacts_len for this facet
> > +                                     * Will differ from * 
> > rule->up.ofpacts_len
> > +                                     * if facet is for a recirculated 
> > packet. */
> > +
> > +    uint32_t recirculation_id;       /* Recirculation id.
> > +                                      * Non-sero for a facet
> 
> s/sero/zero/

Thanks, I will fix that.

> 
> > +                                      * that recirculates packets;
> > +                                      * used as the value of flow.skb_mark
> > +                                      * in the facet of recirculated 
> > packets.
> > +                                      * Zero otherwise. */
> > +    struct hmap_node recirculation_id_hmap_node;
> > +                                    /* In owning ofproto's 
> > 'recirculation_id'
> 
> s/'recirculation_id'/'recirculation_ids'/

Thanks, I will fix that.

> 
> > +                                     * hmap. */
> > +    const struct ofpact *recirculation_ofpacts;
> > +                                    /* ofpacts for facets of packets
> > +                                     * recirculated by this facet */
> > +    size_t recirculation_ofpacts_len;
> > +                                    /* ofpacts_len for facets of packets
> > +                                     * recirculated by this facet */
> > +
> > +    bool recirculated;              /* Facet of a recirculated packet? */
> 
> Is this flag needed, as recirculation_id is already non-zero for facets that 
> recirculate packets?
> 
> > };
> > 
> > -static struct facet *facet_create(struct rule_dpif *,
> > -                                  const struct flow *, uint32_t hash);
> > +static struct facet *facet_create(struct rule_dpif *, const struct flow *,
> > +                                  const struct ofpact *, size_t 
> > ofpacts_len,
> > +                                  bool recirculated, uint32_t hash);
> > static void facet_remove(struct facet *);
> > static void facet_free(struct facet *);
> > 
> > +static struct facet *facet_find_by_id(struct ofproto_dpif *, uint32_t id);
> > static struct facet *facet_find(struct ofproto_dpif *,
> >                                 const struct flow *, uint32_t hash);
> > static struct facet *facet_lookup_valid(struct ofproto_dpif *,
> >                                         const struct flow *, uint32_t hash);
> > +static struct facet *facet_lookup_valid_by_id(struct ofproto_dpif *,
> > +                                              uint32_t id);
> > static void facet_revalidate(struct facet *);
> > static bool facet_check_consistency(struct facet *);
> > 
> > @@ -714,6 +757,7 @@ struct ofproto_dpif {
> > 
> >     /* Facets. */
> >     struct hmap facets;
> > +    struct hmap recirculation_ids;
> >     struct hmap subfacets;
> >     struct governor *governor;
> >     long long int consistency_rl;
> > @@ -1373,6 +1417,7 @@ construct(struct ofproto *ofproto_)
> >     ofproto->has_bonded_bundles = false;
> > 
> >     hmap_init(&ofproto->facets);
> > +    hmap_init(&ofproto->recirculation_ids);
> >     hmap_init(&ofproto->subfacets);
> >     ofproto->governor = NULL;
> >     ofproto->consistency_rl = LLONG_MIN;
> > @@ -3484,6 +3529,58 @@ port_is_lacp_current(const struct ofport *ofport_)
> >             : -1);
> > }
> > 
> > +/* Recirculation Id */
> > +#define RECIRCULATION_ID_NONE  0
> > +#define RECIRCULATION_ID_DUMMY 2
> > +#define RECIRCULATION_ID_MIN   RECIRCULATION_ID_DUMMY
> > +
> > +#define RECIRCULATION_ID_MAX_LOOP 1024  /* Arbitrary value to prevent
> > +                                         * endless loop */
> > +
> > +static uint32_t recirculation_id_hash(uint32_t id)
> > +{
> > +    return hash_words(&id, 1, 0);
> > +}
> > +
> > +static uint32_t recirculation_id = RECIRCULATION_ID_MIN;
> > +static uint32_t validated_recirculation_id = RECIRCULATION_ID_NONE;
> > +
> > +static uint32_t peek_recirculation_id(struct ofproto_dpif *ofproto)
> > +{
> > +    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 15);
> > +
> > +    int loop = RECIRCULATION_ID_MAX_LOOP;
> > +
> > +    if (validated_recirculation_id == recirculation_id) {
> > +        return recirculation_id;
> > +    }
> > +
> > +    while (loop--) {
> > +        if (recirculation_id < RECIRCULATION_ID_MIN)
> > +            recirculation_id = RECIRCULATION_ID_MIN;
> > +        /* Skip IPSEC_MARK bit it is reserved */
> > +        if (recirculation_id & IPSEC_MARK) {
> > +            recirculation_id++;
> > +            ovs_assert(!(recirculation_id & IPSEC_MARK));
> 
> This essentially assumes the IPSEC_MARK bit to be 1. This would work for any 
> bit, so the assert would be unnecessary:
> 
> recirculation_id += IPSEC_MARK;

Thanks, I will update the code as you suggest.

> > +        }
> > +        if (!facet_find_by_id(ofproto, recirculation_id)) {
> > +            validated_recirculation_id = recirculation_id;
> > +            return recirculation_id;
> > +        }
> > +        recirculation_id++;
> > +    }
> > +
> > +    VLOG_WARN_RL(&rl, "Failed to allocate recirulation id after %d 
> > attempts\n",
> > +                 RECIRCULATION_ID_MAX_LOOP);
> > +    return RECIRCULATION_ID_NONE;
> > +}
> > +
> > +static uint32_t get_recirculation_id(void)
> > +{
> > +    ovs_assert(recirculation_id == validated_recirculation_id);
> > +    return recirculation_id++;
> > +}
> > +
> > /* Upcall handling. */
> > 
> > /* Flow miss batching.
> > @@ -3646,6 +3743,14 @@ static bool
> > flow_miss_should_make_facet(struct ofproto_dpif *ofproto,
> >                             struct flow_miss *miss, uint32_t hash)
> > {
> > +    /* If the packet is MPLS then recirculation may be used and
> > +     * this will not be possible with facets if there are no recirculation
> > +     * ids available */
> > +    if (eth_type_mpls(miss->flow.dl_type) &&
> > +        peek_recirculation_id(ofproto) == RECIRCULATION_ID_NONE) {
> > +        return false;
> > +    }
> > +
> >     if (!ofproto->governor) {
> >         size_t n_subfacets;
> > 
> > @@ -3661,18 +3766,66 @@ flow_miss_should_make_facet(struct ofproto_dpif 
> > *ofproto,
> >                                         list_size(&miss->packets));
> > }
> > 
> > +static const struct flow *
> > +xlate_with_recirculate(struct ofproto_dpif *ofproto, struct rule_dpif 
> > *rule,
> > +                       const struct flow *flow, struct flow *flow_storage,
> > +                       const struct initial_vals *initial_vals,
> > +                       const struct ofpact *ofpacts, size_t ofpacts_len,
> > +                       struct ofpbuf *odp_actions,
> > +                       struct dpif_flow_stats *stats, struct ofpbuf 
> > *packet)
> 
> It was a bit surprising from the name of the function that the packet is 
> actually modified. Maybe add a comment above?

Good point. I propose the following comment and minor change of name for
the function.

/* A loop which translates the actions for 'flow'. If a recirculate
 * action was not added by the translation then the loop ends. Otherwise        
 * the actions are executed, modifying 'packet' and the loop iterates,
 * performing translation again.
 *
 * The purpose of this function is to handle translation of actions
 * in cases where factes are not use. */
static const struct flow *
xlate_and_recirculate(struct ofproto_dpif *ofproto, struct rule_dpif *rule,

> > +{
> > +    struct initial_vals initial_vals_ = *initial_vals;
> > +
> > +    while (1) {
> > +        struct action_xlate_ctx ctx;
> > +
> > +        ofpbuf_clear(odp_actions);
> > +        action_xlate_ctx_init(&ctx, ofproto, flow, &initial_vals_,
> > +                              rule, stats->tcp_flags, packet,
> > +                              RECIRCULATION_ID_DUMMY);
> > +        ctx.resubmit_stats = stats;
> > +        xlate_actions(&ctx, ofpacts, ofpacts_len, odp_actions);
> > +
> > +        if (!ctx.recirculated) {
> > +            break;
> > +        }
> > +
> > +        /* Copy flow into flow_storage and update flow to point
> > +         * to flow_storage if this is the first iteration of the loop */
> > +        if (flow != flow_storage) {
> > +            *flow_storage = *flow;
> > +            flow = flow_storage;
> > +        }
> > +
> > +        /* Update the packet */
> > +        odp_execute_actions(NULL, packet, odp_actions->data,
> > +                            odp_actions->size, flow_storage, NULL, NULL);
> > +        ofpbuf_clear(odp_actions);
> > +
> > +        /* Replace the flow */
> > +        flow_extract(packet, flow->skb_priority, flow->skb_mark,
> > +                     &flow->tunnel, flow->in_port, flow_storage);
> > +        initial_vals_.vlan_tci = flow->vlan_tci;
> > +
> > +        ofpacts = ofpact_end(ofpacts, ctx.ofpacts_len);
> > +        ofpacts_len -= ctx.ofpacts_len;
> > +    }
> > +
> > +    return flow;
> > +}
> > 
> ...
> > @@ -4874,6 +5113,33 @@ facet_find(struct ofproto_dpif *ofproto,
> >     return NULL;
> > }
> > 
> > +/* Searches 'ofproto''s table of facets with recirculation ids
> > + * for a facet whose recirculation_id is 'id'.
> > + * Returns it if found, otherwise a null pointer.
> > + *
> > + * The returned facet might need revalidation; use 
> > facet_lookup_valid_by_id()
> > + * instead if that is important. */
> > +static struct facet *
> > +facet_find_by_id(struct ofproto_dpif *ofproto, uint32_t id)
> > +{
> > +    uint32_t hash = recirculation_id_hash(id);
> > +    struct facet *facet;
> > +
> > +    /* some values are never used */
> > +    if (id == RECIRCULATION_ID_NONE || (id & IPSEC_MARK)) {
> > +        return NULL;
> > +    }
> 
> Maybe compute hash here instead?

Sure, I will change the code as you suggest.

> 
> > +
> > +    HMAP_FOR_EACH_WITH_HASH (facet, recirculation_id_hmap_node,
> > +                             hash, &ofproto->recirculation_ids) {
> > +        if (facet->recirculation_id == id) {
> > +            return facet;
> > +        }
> > +    }
> > +
> > +    return NULL;
> > +}
> > +
> ...
> > @@ -6473,6 +6932,16 @@ execute_dec_mpls_ttl_action(struct action_xlate_ctx 
> > *ctx)
> > }
> > 
> > static void
> > +execute_recircualte_action(struct action_xlate_ctx *ctx)
> 
> s/recircualte/recirculate/

Thanks, I thought I had weeded out all such miss-spellings.
I will fix this.

> 
> > +{
> > +    if (ctx->recirculation_id == RECIRCULATION_ID_NONE) {
> > +        ctx->recirculation_id = get_recirculation_id();
> > +    }
> > +    ctx->recirculated = true;
> > +    ctx->flow.skb_mark = ctx->recirculation_id;
> > +}
> > +
> > +static void
> > xlate_output_action(struct action_xlate_ctx *ctx,
> >                     uint16_t port, uint16_t max_len, bool may_packet_in)
> > {
> > @@ -6725,6 +7194,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t 
> > ofpacts_len,
> >                  struct action_xlate_ctx *ctx)
> > {
> >     bool was_evictable = true;
> > +    bool may_recirculate = false;
> 
> "may_recirculate" is not exactly what is meant here. It is more like 
> "recirculate before any further L3+ actions", so maybe rename this as 
> "may_xlate_l3_actions", reversing the truth value?

Sure, that sounds reasonable.
I will update the code as you suggest.

> 
> >     const struct ofpact *a;
> > 
> >     if (ctx->rule) {
> > @@ -6793,18 +7263,30 @@ do_xlate_actions(const struct ofpact *ofpacts, 
> > size_t ofpacts_len,
> > 
> >         case OFPACT_SET_IPV4_SRC:
> >             if (ctx->flow.dl_type == htons(ETH_TYPE_IP)) {
> > +                if (may_recirculate) {
> > +                    execute_recircualte_action(ctx);
> > +                    goto out;
> > +                }
> 
> Repetition of this block is ugly. Simplify it with a new label (e.g., 
> "recirculate_out:)" that would do the call to execute_recirculate_action() 
> right above "out:", hence you could write here:
> 
>   if (may_recirculate) {
>     goto recirculate_out;
>   }


I think that would cause recirculation to occur unnecessarily in
cases where may_recirculate has been set and the code leaves
the OFPACT_FOR_EACH() loop than via a goto.


> 
> >                 ctx->flow.nw_src = ofpact_get_SET_IPV4_SRC(a)->ipv4;
> >             }
> >             break;
> > 
> >         case OFPACT_SET_IPV4_DST:
> >             if (ctx->flow.dl_type == htons(ETH_TYPE_IP)) {
> > +                if (may_recirculate) {
> > +                    execute_recircualte_action(ctx);
> > +                    goto out;
> > +                }
> >                 ctx->flow.nw_dst = ofpact_get_SET_IPV4_DST(a)->ipv4;
> >             }
> >             break;
> > 
> >         case OFPACT_SET_IPV4_DSCP:
> >             /* OpenFlow 1.0 only supports IPv4. */
> > +            if (may_recirculate) {
> > +                execute_recircualte_action(ctx);
> > +                goto out;
> > +            }
> >             if (ctx->flow.dl_type == htons(ETH_TYPE_IP)) {
> >                 ctx->flow.nw_tos &= ~IP_DSCP_MASK;
> >                 ctx->flow.nw_tos |= ofpact_get_SET_IPV4_DSCP(a)->dscp;
> > @@ -6813,12 +7295,20 @@ do_xlate_actions(const struct ofpact *ofpacts, 
> > size_t ofpacts_len,
> > 
> >         case OFPACT_SET_L4_SRC_PORT:
> >             if (is_ip_any(&ctx->flow)) {
> > +                if (may_recirculate) {
> > +                    execute_recircualte_action(ctx);
> > +                    goto out;
> > +                }
> >                 ctx->flow.tp_src = 
> > htons(ofpact_get_SET_L4_SRC_PORT(a)->port);
> >             }
> >             break;
> > 
> >         case OFPACT_SET_L4_DST_PORT:
> >             if (is_ip_any(&ctx->flow)) {
> > +                if (may_recirculate) {
> > +                    execute_recircualte_action(ctx);
> > +                    goto out;
> > +                }
> >                 ctx->flow.tp_dst = 
> > htons(ofpact_get_SET_L4_DST_PORT(a)->port);
> >             }
> >             break;
> > @@ -6840,29 +7330,50 @@ do_xlate_actions(const struct ofpact *ofpacts, 
> > size_t ofpacts_len,
> >             break;
> > 
> >         case OFPACT_REG_MOVE:
> > +            if (may_recirculate) {
> > +                execute_recircualte_action(ctx);
> > +                goto out;
> > +            }
> >             nxm_execute_reg_move(ofpact_get_REG_MOVE(a), &ctx->flow);
> >             break;
> > 
> >         case OFPACT_REG_LOAD:
> > +            if (may_recirculate) {
> > +                execute_recircualte_action(ctx);
> > +                goto out;
> > +            }
> >             nxm_execute_reg_load(ofpact_get_REG_LOAD(a), &ctx->flow);
> >             break;
> > 
> >         case OFPACT_STACK_PUSH:
> > +            if (may_recirculate) {
> > +                execute_recircualte_action(ctx);
> > +                goto out;
> > +            }
> >             nxm_execute_stack_push(ofpact_get_STACK_PUSH(a), &ctx->flow,
> >                                    &ctx->stack);
> >             break;
> > 
> >         case OFPACT_STACK_POP:
> > +            if (may_recirculate) {
> > +                execute_recircualte_action(ctx);
> > +                goto out;
> > +            }
> >             nxm_execute_stack_pop(ofpact_get_STACK_POP(a), &ctx->flow,
> >                                   &ctx->stack);
> >             break;
> 
> I guess that the above four actions could be executed on a limited set of 
> registers even if "may_recirculate"?

Yes. I guess guess would be possible to make a more fine-grained check.
But I'm not sure if the added complexity would be worth it.

> 
> > 
> >         case OFPACT_PUSH_MPLS:
> >             execute_mpls_push_action(ctx, 
> > ofpact_get_PUSH_MPLS(a)->ethertype);
> > +            may_recirculate = false;
> >             break;
> > 
> >         case OFPACT_POP_MPLS:
> >             execute_mpls_pop_action(ctx, ofpact_get_POP_MPLS(a)->ethertype);
> > +            if (ctx->flow.dl_type == htons(ETH_TYPE_IP) ||
> > +                ctx->flow.dl_type == htons(ETH_TYPE_IPV6)) {
> > +                may_recirculate = true;
> > +            }
> >             break;
> > 
> >         case OFPACT_SET_MPLS_TTL:
> > @@ -6878,7 +7389,10 @@ do_xlate_actions(const struct ofpact *ofpacts, 
> > size_t ofpacts_len,
> >             break;
> > 
> >         case OFPACT_DEC_TTL:
> > -            if (compose_dec_ttl(ctx, ofpact_get_DEC_TTL(a))) {
> > +            if (may_recirculate) {
> > +                execute_recircualte_action(ctx);
> > +                goto out;
> > +            } else if (compose_dec_ttl(ctx, ofpact_get_DEC_TTL(a))) {
> >                 goto out;
> >             }
> >             break;
> > @@ -6888,10 +7402,18 @@ do_xlate_actions(const struct ofpact *ofpacts, 
> > size_t ofpacts_len,
> >             break;
> > 
> >         case OFPACT_MULTIPATH:
> > +            if (may_recirculate) {
> > +                execute_recircualte_action(ctx);
> > +                goto out;
> > +            }
> >             multipath_execute(ofpact_get_MULTIPATH(a), &ctx->flow);
> >             break;
> > 
> >         case OFPACT_BUNDLE:
> > +            if (may_recirculate) {
> > +                execute_recircualte_action(ctx);
> > +                goto out;
> > +            }
> >             ctx->ofproto->has_bundle_action = true;
> >             xlate_bundle_action(ctx, ofpact_get_BUNDLE(a));
> >             break;
> 
> Are these two always L3+ related actions?

No, not always.

> 
> > @@ -6902,6 +7424,10 @@ do_xlate_actions(const struct ofpact *ofpacts, 
> > size_t ofpacts_len,
> > 
> >         case OFPACT_LEARN:
> >             ctx->has_learn = true;
> > +            if (may_recirculate) {
> > +                execute_recircualte_action(ctx);
> > +                goto out;
> > +            }
> >             if (ctx->may_learn) {
> >                 xlate_learn_action(ctx, ofpact_get_LEARN(a));
> >             }
> 
> I guess there is no point recirculating here if may_learn == false?

I thought so too. And that is how I originally write the code.
However, during testing I noticed that it is necessary in order
for facet revalidation to work correctly.

> > @@ -6969,6 +7495,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t 
> > ofpacts_len,
> >     }
> > 
> > out:
> > +    ctx->ofpacts_len = (char *)(a) - (char *)ofpacts;
> >     if (ctx->rule) {
> >         ctx->rule->up.evictable = was_evictable;
> >     }
> > @@ -6979,7 +7506,8 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx,
> >                       struct ofproto_dpif *ofproto, const struct flow *flow,
> >                       const struct initial_vals *initial_vals,
> >                       struct rule_dpif *rule,
> > -                      uint8_t tcp_flags, const struct ofpbuf *packet)
> > +                      uint8_t tcp_flags, const struct ofpbuf *packet,
> > +                      uint32_t recirculation_id)
> > {
> >     /* Flow initialization rules:
> >      * - 'base_flow' must match the kernel's view of the packet at the
> > @@ -7000,7 +7528,13 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx,
> >      *   tunnel output action.
> >      * - Tunnel 'base_flow' is completely cleared since that is what the
> >      *   kernel does.  If we wish to maintain the original values an action
> > -     *   needs to be generated. */
> > +     *   needs to be generated.
> > +     * - The recirculation_id element of flow and base flow are set to
> > +     *   recirculate_id, which is the id that will be used by a 
> > recirculation
> > +     *   action of one is added. It is stored in flow and base_flow for
> 
> s/of/if/
> 
> > +     *   convenience as the recirculation_id element of flow and base flow
> > +     *   are otherwise unused  by action_xlate_ctx_init().
> > +     */
> > 
> 
> This comment is not completely accurate any more, since there is no 
> recirculation_id in struct flow.

Thanks. I will update the patch not to append to the comment above.
This is because the comment refers to flow initialisation an as you
correctly point out recirculation_id is not present in the flow any more.

> 
> >     ctx->ofproto = ofproto;
> >     ctx->flow = *flow;
> > @@ -7014,6 +7548,7 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx,
> >     ctx->resubmit_hook = NULL;
> >     ctx->report_hook = NULL;
> >     ctx->resubmit_stats = NULL;
> > +    ctx->recirculation_id = recirculation_id;
> > 
> >     if (initial_vals) {
> >         ctx->base_flow.vlan_tci = initial_vals->vlan_tci;
> > 
> 
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to