Joe, See my comments inline,
Jarno > On Apr 30, 2015, at 12:38 PM, Joe Stringer <joestrin...@nicira.com> wrote: > > When traversing from one bridge to another via a patch port, we should > drop conntrack metadata from the OpenFlow pipeline. This should only > affect the subsequent processing on the destination bridge (and not > continued processing, resubmits, etc. on the original bridge). > > If conntrack is executed for the current bridge, then recirculation > should make the conntrack fields available for matching. In all other > cases, the conntrack fields should be zeroed during upcall processing. > > CC: Jarno Rajahalme <jrajaha...@nicira.com> > Signed-off-by: Joe Stringer <joestrin...@nicira.com> > --- > This should be folded into earlier conntrack patches, but I have left it > as an independent patch for now to aid review. > --- > lib/ofp-actions.h | 5 +++ > ofproto/ofproto-dpif-rid.c | 80 +++++++++++++++++++++++------------------- > ofproto/ofproto-dpif-rid.h | 15 ++++---- > ofproto/ofproto-dpif-xlate.c | 46 ++++++++++++++++++++---- > 4 files changed, 97 insertions(+), 49 deletions(-) > > diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h > index 01958c2..0063b60 100644 > --- a/lib/ofp-actions.h > +++ b/lib/ofp-actions.h > @@ -748,6 +748,11 @@ struct ofpact_unroll_xlate { > /* Metadata in xlate context, visible to controller via PACKET_INs. */ > uint8_t rule_table_id; /* 0xFF if none. */ > ovs_be64 rule_cookie; /* OVS_BE64_MAX if none. */ > + > + /* Whether conntrack was executed prior to recirculation. If so, related > + * fields may be made available post-recirculation, until peer traversal > + * or subsequent conntrack execution. */ > + bool conntracked; > }; > Having ‘conntracked’ in the of ofpact_unroll_xlate would make sense if we both saved and restored the ‘conntracked’ value across some actions (other than output to patch ports). Unrolling ‘conntracked’ after a resubmit that did the conntrack action would reset the bit to 0 for the rest of the pipeline, which is not what we want. In short, we do not need ‘conntracked’ here. > /* Converting OpenFlow to ofpacts. */ > diff --git a/ofproto/ofproto-dpif-rid.c b/ofproto/ofproto-dpif-rid.c > index f1b3bdc..c539e0a 100644 > --- a/ofproto/ofproto-dpif-rid.c > +++ b/ofproto/ofproto-dpif-rid.c > @@ -125,9 +125,9 @@ recirc_id_node_find(uint32_t id) > > static uint32_t > recirc_metadata_hash(struct ofproto_dpif *ofproto, uint8_t table_id, > - struct recirc_metadata *md, struct ofpbuf *stack, > - uint32_t action_set_len, uint32_t ofpacts_len, > - const struct ofpact *ofpacts) > + bool conntrack, struct recirc_metadata *md, > + struct ofpbuf *stack, uint32_t action_set_len, > + uint32_t ofpacts_len, const struct ofpact *ofpacts) > { > uint32_t hash; > > @@ -135,6 +135,7 @@ recirc_metadata_hash(struct ofproto_dpif *ofproto, > uint8_t table_id, > > hash = hash_pointer(ofproto, 0); > hash = hash_int(table_id, hash); > + hash = hash_boolean(conntrack, hash); > hash = hash_words64((const uint64_t *)md, sizeof *md / sizeof(uint64_t), > hash); > if (stack && stack->size != 0) { > @@ -153,12 +154,13 @@ recirc_metadata_hash(struct ofproto_dpif *ofproto, > uint8_t table_id, > static bool > recirc_metadata_equal(const struct recirc_id_node *node, > struct ofproto_dpif *ofproto, uint8_t table_id, > - struct recirc_metadata *md, struct ofpbuf *stack, > - uint32_t action_set_len, uint32_t ofpacts_len, > - const struct ofpact *ofpacts) > + bool conntrack, struct recirc_metadata *md, > + struct ofpbuf *stack, uint32_t action_set_len, > + uint32_t ofpacts_len, const struct ofpact *ofpacts) > { > return node->ofproto == ofproto > && node->table_id == table_id > + && node->conntrack == conntrack > && !memcmp(&node->metadata, md, sizeof *md) > && ((!node->stack && (!stack || stack->size == 0)) > || (node->stack && stack && ofpbuf_equal(node->stack, stack))) > @@ -171,15 +173,17 @@ recirc_metadata_equal(const struct recirc_id_node *node, > * state, caller should take a reference. */ > static struct recirc_id_node * > recirc_find_equal(struct ofproto_dpif *ofproto, uint8_t table_id, > - struct recirc_metadata *md, struct ofpbuf *stack, > - uint32_t action_set_len, uint32_t ofpacts_len, > - const struct ofpact *ofpacts, uint32_t hash) > + bool conntrack, struct recirc_metadata *md, > + struct ofpbuf *stack, uint32_t action_set_len, > + uint32_t ofpacts_len, const struct ofpact *ofpacts, > + uint32_t hash) > { > struct recirc_id_node *node; > > CMAP_FOR_EACH_WITH_HASH(node, metadata_node, hash, &metadata_map) { > - if (recirc_metadata_equal(node, ofproto, table_id, md, stack, > - action_set_len, ofpacts_len, ofpacts)) { > + if (recirc_metadata_equal(node, ofproto, table_id, conntrack, md, > + stack, action_set_len, ofpacts_len, > + ofpacts)) { > return node; > } > } > @@ -188,15 +192,16 @@ recirc_find_equal(struct ofproto_dpif *ofproto, uint8_t > table_id, > > static struct recirc_id_node * > recirc_ref_equal(struct ofproto_dpif *ofproto, uint8_t table_id, > - struct recirc_metadata *md, struct ofpbuf *stack, > - uint32_t action_set_len, uint32_t ofpacts_len, > - const struct ofpact *ofpacts, uint32_t hash) > + bool conntrack, struct recirc_metadata *md, > + struct ofpbuf *stack, uint32_t action_set_len, > + uint32_t ofpacts_len, const struct ofpact *ofpacts, > + uint32_t hash) > { > struct recirc_id_node *node; > > do { > - node = recirc_find_equal(ofproto, table_id, md, stack, > action_set_len, > - ofpacts_len, ofpacts, hash); > + node = recirc_find_equal(ofproto, table_id, conntrack, md, stack, > + action_set_len, ofpacts_len, ofpacts, hash); > > /* Try again if the node was released before we get the reference. */ > } while (node && !ovs_refcount_try_ref_rcu(&node->refcount)); > @@ -210,9 +215,10 @@ recirc_ref_equal(struct ofproto_dpif *ofproto, uint8_t > table_id, > * hash is recomputed if it is passed in as 0. */ > static struct recirc_id_node * > recirc_alloc_id__(struct ofproto_dpif *ofproto, uint8_t table_id, > - struct recirc_metadata *md, struct ofpbuf *stack, > - uint32_t action_set_len, uint32_t ofpacts_len, > - const struct ofpact *ofpacts, uint32_t hash) > + bool conntrack, struct recirc_metadata *md, > + struct ofpbuf *stack, uint32_t action_set_len, > + uint32_t ofpacts_len, const struct ofpact *ofpacts, > + uint32_t hash) > { > struct recirc_id_node *node = xzalloc(sizeof *node + > OFPACT_ALIGN(ofpacts_len)); > @@ -221,6 +227,7 @@ recirc_alloc_id__(struct ofproto_dpif *ofproto, uint8_t > table_id, > > node->ofproto = ofproto; > node->table_id = table_id; > + node->conntrack = conntrack; > memcpy(&node->metadata, md, sizeof node->metadata); > node->stack = (stack && stack->size) ? ofpbuf_clone(stack) : NULL; > node->action_set_len = action_set_len; > @@ -254,7 +261,7 @@ recirc_alloc_id__(struct ofproto_dpif *ofproto, uint8_t > table_id, > /* Look up an existing ID for the given flow's metadata and optional actions. > */ > uint32_t > -recirc_find_id(struct ofproto_dpif *ofproto, uint8_t table_id, > +recirc_find_id(struct ofproto_dpif *ofproto, uint8_t table_id, bool > conntrack, > struct recirc_metadata *md, struct ofpbuf *stack, > uint32_t action_set_len, uint32_t ofpacts_len, > const struct ofpact *ofpacts) > @@ -263,10 +270,10 @@ recirc_find_id(struct ofproto_dpif *ofproto, uint8_t > table_id, > struct recirc_id_node *node; > uint32_t hash; > > - hash = recirc_metadata_hash(ofproto, table_id, md, stack, action_set_len, > - ofpacts_len, ofpacts); > - node = recirc_find_equal(ofproto, table_id, md, stack, action_set_len, > - ofpacts_len, ofpacts, hash); > + hash = recirc_metadata_hash(ofproto, table_id, conntrack, md, stack, > + action_set_len, ofpacts_len, ofpacts); > + node = recirc_find_equal(ofproto, table_id, conntrack, md, stack, > + action_set_len, ofpacts_len, ofpacts, hash); > > return node ? node->id : 0; > } > @@ -275,25 +282,25 @@ recirc_find_id(struct ofproto_dpif *ofproto, uint8_t > table_id, > optional actions. */ > uint32_t > recirc_alloc_id_ctx(struct ofproto_dpif *ofproto, uint8_t table_id, > - struct recirc_metadata *md, struct ofpbuf *stack, > - uint32_t action_set_len, uint32_t ofpacts_len, > - const struct ofpact *ofpacts) > + bool conntrack, struct recirc_metadata *md, > + struct ofpbuf *stack, uint32_t action_set_len, > + uint32_t ofpacts_len, const struct ofpact *ofpacts) > { > struct recirc_id_node *node; > uint32_t hash; > > /* Look up an existing ID. */ > - hash = recirc_metadata_hash(ofproto, table_id, md, stack, action_set_len, > - ofpacts_len, ofpacts); > - node = recirc_ref_equal(ofproto, table_id, md, stack, action_set_len, > - ofpacts_len, ofpacts, hash); > + hash = recirc_metadata_hash(ofproto, table_id, conntrack, md, stack, > + action_set_len,ofpacts_len, ofpacts); > + node = recirc_ref_equal(ofproto, table_id, conntrack, md, stack, > + action_set_len, ofpacts_len, ofpacts, hash); > > /* Allocate a new recirc ID if needed. */ > if (!node) { > ovs_assert(action_set_len <= ofpacts_len); > > - node = recirc_alloc_id__(ofproto, table_id, md, stack, > action_set_len, > - ofpacts_len, ofpacts, hash); > + node = recirc_alloc_id__(ofproto, table_id, conntrack, md, stack, > + action_set_len, ofpacts_len, ofpacts, hash); > } > > return node->id; > @@ -309,9 +316,10 @@ recirc_alloc_id(struct ofproto_dpif *ofproto) > > memset(&md, 0, sizeof md); > md.in_port = OFPP_NONE; > - hash = recirc_metadata_hash(ofproto, TBL_INTERNAL, &md, NULL, 0, 0, > NULL); > - node = recirc_alloc_id__(ofproto, TBL_INTERNAL, &md, NULL, 0, 0, NULL, > - hash); > + hash = recirc_metadata_hash(ofproto, TBL_INTERNAL, false, &md, NULL, 0, > 0, > + NULL); > + node = recirc_alloc_id__(ofproto, TBL_INTERNAL, false, &md, NULL, 0, 0, > + NULL, hash); > return node->id; > } > > diff --git a/ofproto/ofproto-dpif-rid.h b/ofproto/ofproto-dpif-rid.h > index dc533ce..db77144 100644 > --- a/ofproto/ofproto-dpif-rid.h > +++ b/ofproto/ofproto-dpif-rid.h > @@ -138,6 +138,9 @@ struct recirc_id_node { > /* Initial table for post-recirculation processing. */ > uint8_t table_id; > > + /* True if conntracking occurred prior to recirculation. */ > + bool conntrack; > + > /* Pipeline context for post-recirculation processing. */ > struct ofproto_dpif *ofproto; /* Post-recirculation bridge. */ > struct recirc_metadata metadata; /* Flow metadata. */ > @@ -157,13 +160,13 @@ void recirc_init(void); > uint32_t recirc_alloc_id(struct ofproto_dpif *); > > uint32_t recirc_alloc_id_ctx(struct ofproto_dpif *, uint8_t table_id, > - struct recirc_metadata *, struct ofpbuf *stack, > - uint32_t action_set_len, uint32_t ofpacts_len, > - const struct ofpact *); > + bool conntrack, struct recirc_metadata *, > + struct ofpbuf *stack, uint32_t action_set_len, > + uint32_t ofpacts_len, const struct ofpact *); > uint32_t recirc_find_id(struct ofproto_dpif *, uint8_t table_id, > - struct recirc_metadata *, struct ofpbuf *stack, > - uint32_t action_set_len, uint32_t ofpacts_len, > - const struct ofpact *); > + bool conntrack, struct recirc_metadata *, > + struct ofpbuf *stack, uint32_t action_set_len, > + uint32_t ofpacts_len, const struct ofpact *); > void recirc_free_id(uint32_t recirc_id); > void recirc_free_ofproto(struct ofproto_dpif *, const char *ofproto_name); > > diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c > index 5561410..9a9b4a6 100644 > --- a/ofproto/ofproto-dpif-xlate.c > +++ b/ofproto/ofproto-dpif-xlate.c > @@ -283,6 +283,11 @@ struct xlate_ctx { > * the MPLS label stack that was originally present. */ > bool was_mpls; > > + /* True if conntrack has been performed on this packet during processing > + * on the current bridge. This is used to determine whether conntrack > + * state from the datapath should be honored after recirculation. */ > + bool conntracked; > + This should be initialized to false when an xlate_ctx is created. > /* OpenFlow 1.1+ action set. > * > * 'action_set' accumulates "struct ofpact"s added by > OFPACT_WRITE_ACTIONS. > @@ -2714,6 +2719,15 @@ build_tunnel_send(const struct xlate_ctx *ctx, const > struct xport *xport, > } > > static void > +clear_conntrack(struct flow *flow) > +{ > + flow->conn_state = 0; > + flow->conn_zone = 0; > + flow->conn_mark = 0; > + memset(&flow->conn_label, 0, sizeof flow->conn_label); > +} > + > +static void > compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, > const struct xlate_bond_recirc *xr, bool check_stp) > { > @@ -2777,6 +2791,7 @@ compose_output_action__(struct xlate_ctx *ctx, > ofp_port_t ofp_port, > const struct xport *peer = xport->peer; > struct flow old_flow = ctx->xin->flow; > bool old_was_mpls = ctx->was_mpls; > + bool old_conntracked = ctx->conntracked; > enum slow_path_reason special; > struct ofpbuf old_stack = ctx->stack; > union mf_subvalue new_stack[1024 / sizeof(union mf_subvalue)]; > @@ -2792,6 +2807,10 @@ compose_output_action__(struct xlate_ctx *ctx, > ofp_port_t ofp_port, > memset(flow->regs, 0, sizeof flow->regs); > flow->actset_output = OFPP_UNSET; > > + /* Drop conntrack metadata when traversing a peer. */ > + clear_conntrack(flow); > + ctx->conntracked = false; > + > special = process_special(ctx, &ctx->xin->flow, peer, > ctx->xin->packet); > if (special) { > @@ -2842,6 +2861,8 @@ compose_output_action__(struct xlate_ctx *ctx, > ofp_port_t ofp_port, > * bridge. */ > ctx->was_mpls = old_was_mpls; > > + ctx->conntracked = old_conntracked; > + > /* The fact that the peer bridge exits (for any reason) does not mean > * that the original bridge should exit. Specifically, if the peer > * bridge recirculates (which typically modifies the packet), the > @@ -3483,8 +3504,9 @@ compose_recirculate_action__(struct xlate_ctx *ctx, > struct ofpbuf *stack, > /* Allocate a unique recirc id for the given metadata state in the > * flow. The life-cycle of this recirc id is managed by associating > it > * with the udpif key ('ukey') created for each new datapath flow. */ > - id = recirc_alloc_id_ctx(ctx->xbridge->ofproto, 0, &md, stack, > - action_offset, ofpacts_len, ofpacts); > + id = recirc_alloc_id_ctx(ctx->xbridge->ofproto, 0, ctx->conntracked, > + &md, stack, action_offset, ofpacts_len, > + ofpacts); > if (!id) { > static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > VLOG_ERR_RL(&rl, "Failed to allocate recirculation id"); > @@ -3495,8 +3517,8 @@ compose_recirculate_action__(struct xlate_ctx *ctx, > struct ofpbuf *stack, > /* Look up an existing recirc id for the given metadata state in the > * flow. No new reference is taken, as the ID is RCU protected and is > * only required temporarily for verification. */ > - id = recirc_find_id(ctx->xbridge->ofproto, 0, &md, stack, > - action_offset, ofpacts_len, ofpacts); > + id = recirc_find_id(ctx->xbridge->ofproto, 0, ctx->conntracked, &md, > + stack, action_offset, ofpacts_len, ofpacts); > /* We let zero 'id' to be used in the RECIRC action below, which will > * fail all revalidations as zero is not a valid recirculation ID. */ > } > @@ -3983,14 +4005,16 @@ recirc_put_unroll_xlate(struct xlate_ctx *ctx) > > /* Restore the table_id and rule cookie for a potential PACKET > * IN if needed. */ > - if (!unroll || > - (ctx->table_id != unroll->rule_table_id > - || ctx->rule_cookie != unroll->rule_cookie)) { > + if (!unroll > + || ctx->table_id != unroll->rule_table_id > + || ctx->rule_cookie != unroll->rule_cookie > + || ctx->conntracked) { > > ctx->last_unroll_offset = ctx->action_set.size; > unroll = ofpact_put_UNROLL_XLATE(&ctx->action_set); > unroll->rule_table_id = ctx->table_id; > unroll->rule_cookie = ctx->rule_cookie; > + unroll->conntracked = ctx->conntracked; > } > } > > @@ -4113,6 +4137,9 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct > ofpact_conntrack *ofc) > put_connhelper(odp_actions, ofc); > nl_msg_end_nested(odp_actions, ct_offset); > > + /* Use conn_* fields from datapath during recirculation upcall. */ > + ctx->conntracked = true; > + > if (ofc->flags & NX_CT_F_RECIRC) { > compose_recirculate_action__(ctx, NULL, 0, 0, NULL); > } > @@ -4436,6 +4463,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t > ofpacts_len, > /* Restore translation context data that was stored earlier. */ > ctx->table_id = unroll->rule_table_id; > ctx->rule_cookie = unroll->rule_cookie; > + ctx->conntracked = unroll->conntracked; > break; > } > case OFPACT_FIN_TIMEOUT: > @@ -4848,6 +4876,10 @@ xlate_actions(struct xlate_in *xin, struct xlate_out > *xout) > * only if there are no post-recirculation actions. */ > ctx.table_id = recirc->table_id; > > + if (!recirc->conntrack) { > + clear_conntrack(flow); > + } > + > /* Restore pipeline metadata. May change flow's in_port and other > * metadata to the values that existed when recirculation was > * triggered. */ > -- > 1.7.10.4 > _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev