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
[email protected]
http://openvswitch.org/mailman/listinfo/dev