lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20131007063447.GF19926@verge.net.au>
Date:	Mon, 7 Oct 2013 15:34:47 +0900
From:	Simon Horman <horms@...ge.net.au>
To:	Ben Pfaff <blp@...ira.com>
Cc:	dev@...nvswitch.org, netdev@...r.kernel.org,
	Jesse Gross <jesse@...ira.com>,
	Pravin B Shelar <pshelar@...ira.com>,
	Ravi K <rkerur@...il.com>,
	Isaku Yamahata <yamahata@...inux.co.jp>,
	Joe Stringer <joe@...d.net.nz>
Subject: Re: [PATCH v2.42 1/5] odp: Allow VLAN actions after MPLS actions

On Fri, Oct 04, 2013 at 09:21:33AM -0700, Ben Pfaff wrote:
> On Fri, Oct 04, 2013 at 05:09:56PM +0900, Simon Horman wrote:
> > From: Joe Stringer <joe@...d.net.nz>
> > 
> > OpenFlow 1.1 and 1.2, and 1.3 differ in their handling of MPLS actions in the
> > presence of VLAN tags. To allow correct behaviour to be committed in
> > each situation, this patch adds a second round of VLAN tag action
> > handling to commit_odp_actions(), which occurs after MPLS actions. This
> > is implemented with a new field in 'struct xlate_in' called 'vlan_tci'.
> > 
> > When an push_mpls action is composed, the flow's current VLAN state is
> > stored into xin->vlan_tci, and flow->vlan_tci is set to 0 (pop_vlan). If
> > a VLAN tag is present, it is stripped; if not, then there is no change.
> > Any later modifications to the VLAN state is written to xin->vlan_tci.
> > When committing the actions, flow->vlan_tci is used before MPLS actions,
> > and xin->vlan_tci is used afterwards. This retains the current datapath
> > behaviour, but allows VLAN actions to be applied in a more flexible
> > manner.
> > 
> > Both before and after this patch MPLS LSEs are pushed onto a packet after
> > any VLAN tags that may be present. This is the behaviour described in
> > OpenFlow 1.1 and 1.2. OpenFlow 1.3 specifies that MPLS LSEs should be
> > pushed onto a packet before any VLAN tags that are present. Support
> > for this will be added by a subsequent patch that makes use of
> > the infrastructure added by this patch.
> > 
> > Signed-off-by: Joe Stringer <joe@...d.net.nz>
> > Signed-off-by: Simon Horman <horms@...ge.net.au>
> 
> I noticed a couple more minor points.
> 
> First, it seems to me that the "vlan_tci" member that this adds to
> xlate_in could go in xlate_ctx just as well.  I would prefer that,
> because (as far as I can tell) there is no reason for the client to use
> any value other than flow->vlan_tci here, and putting it in xlate_ctx
> hides it from the client.

Thanks. Yes I agree that is a good idea.

> Thanks for rearranging the code and updating the comment in
> do_xlate_actions().  It makes the operation clearer.  But now that it's
> clear I have an additional question.  Does it really make sense to have
> 'vlan_tci' as only a local variable in do_xlate_actions()?  Presumably,
> MPLS and VLANs should interact the same way regardless of whether they
> are separated by resubmits or goto_tables.  That is, I suspect that this
> is xlate_ctx state, not local state.

Agreed.

What I have done is to make an incremental patch which:

1. Moves the 'vlan_tci' member of strict xlate_in to
   be the 'final_vlan_tci' member of struct xlate_ctx.

2. Moves the 'vlan_tci' local variable of do_xlate_actions()
   to be the 'next_vlan_tci' member of struct xlate_ctx.

3. Restructures the comments surrounding the logic of the vlan_tci
   code that this patch adds mostly as comments for the new
   members of struct xlate_ctx. I hope things are (still?) clear.

For reference, the incremental patch I have so far is as follows.
I will squash it into this patch before reposting this series.

commit d57735cec0d3e53c7479725ae1cf825563902c30
Author: Simon Horman <horms@...ge.net.au>
Date:   Mon Oct 7 14:30:28 2013 +0900

    Move vlan state into struct xlate_ctx
    
    1. Add final_vlan_tci member to struct xlate_ctx instead of vlan_tci member
       struct xlate_xin.  This seems to be a better palace for it as it does
       not need to be accessible from the caller.
    
    2. Move local vlan_tci variable of do_xlate_actions() to be the
       next_vlan_tci member of strict xlate_ctx.  This allows for it to work
       across resubmit actions and goto table instructions.
    
    As suggested by Ben Pfaff

diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 2afd760..845c6fe 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -172,6 +172,37 @@ struct xlate_ctx {
     odp_port_t sflow_odp_port;  /* Output port for composing sFlow action. */
     uint16_t user_cookie_offset;/* Used for user_action_cookie fixup. */
     bool exit;                  /* No further actions should be processed. */
+
+    /* The final vlan_tci state.
+     *
+     * The value of the vlan TCI prior to the committing of ODP MPLS
+     * actions should be stored in 'xin->flow->vlan_tci'.
+     *
+     * The final value of the VLAN TCI should be stored in 'vlan_tci'. And
+     * is if the value of 'vlan_tci' and 'xin->flow->vlan_tci' differ then
+     * VLAN ODP actions will be committed after any MPLS actions regardless
+     * of whether VLAN actions were also committed before the MPLS actions or
+     * not.
+     *
+     * This mechanism allows a VLAN tag to be popped before pushing
+     * an MPLS LSE and then the same VLAN tag pushed after pushing
+     * the MPLS LSE. In this way it is possible to push an MPLS LSE
+     * before an existing VLAN tag. Moreover this mechanism allows
+     * the order in which VLAN tags and MPLS LSEs are pushed. */
+    ovs_be16 final_vlan_tci;
+
+    /* The next vlan_tci state.
+     *
+     * This value this variable points to updated each time an
+     * action updates the VLAN tci.
+     *
+     * This variable initially points to 'xin->flow->vlan_tci' so that ODP
+     * VLAN actions are committed before any MPLS actions. When an MPLS
+     * action is composed 'next_vlan_tci' is updated to point to
+     * 'final_vlan_tci'. This causes subsequent VLAN actions to be
+     * committed after MPLS actions. */
+    ovs_be16 *next_vlan_tci;
+
 };
 
 /* A controller may use OFPP_NONE as the ingress port to indicate that
@@ -982,7 +1013,7 @@ static void
 output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle,
               uint16_t vlan)
 {
-    ovs_be16 *flow_tci = &ctx->xin->vlan_tci;
+    ovs_be16 *flow_tci = &ctx->final_vlan_tci;
     uint16_t vid;
     ovs_be16 tci, old_tci;
     struct xport *xport;
@@ -1258,7 +1289,7 @@ xlate_normal(struct xlate_ctx *ctx)
 
     /* Drop malformed frames. */
     if (flow->dl_type == htons(ETH_TYPE_VLAN) &&
-        !(ctx->xin->vlan_tci & htons(VLAN_CFI))) {
+        !(ctx->final_vlan_tci & htons(VLAN_CFI))) {
         if (ctx->xin->packet != NULL) {
             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
             VLOG_WARN_RL(&rl, "bridge %s: dropping packet with partial "
@@ -1282,7 +1313,7 @@ xlate_normal(struct xlate_ctx *ctx)
     }
 
     /* Check VLAN. */
-    vid = vlan_tci_to_vid(ctx->xin->vlan_tci);
+    vid = vlan_tci_to_vid(ctx->final_vlan_tci);
     if (!input_vid_is_valid(vid, in_xbundle, ctx->xin->packet != NULL)) {
         xlate_report(ctx, "disallowed VLAN VID for this input port, dropping");
         return;
@@ -1540,7 +1571,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
     const struct xport *xport = get_ofp_port(ctx->xbridge, ofp_port);
     struct flow_wildcards *wc = &ctx->xout->wc;
     struct flow *flow = &ctx->xin->flow;
-    ovs_be16 flow_vlan_tci, xin_vlan_tci;
+    ovs_be16 flow_vlan_tci, vlan_tci;
     uint32_t flow_pkt_mark;
     uint8_t flow_nw_tos;
     odp_port_t out_port, odp_port;
@@ -1609,7 +1640,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
     }
 
     flow_vlan_tci = flow->vlan_tci;
-    xin_vlan_tci = ctx->xin->vlan_tci;
+    vlan_tci = ctx->final_vlan_tci;
     flow_pkt_mark = flow->pkt_mark;
     flow_nw_tos = flow->nw_tos;
 
@@ -1649,20 +1680,20 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
             wc->masks.vlan_tci |= htons(VLAN_VID_MASK | VLAN_CFI);
         }
         vlandev_port = vsp_realdev_to_vlandev(ctx->xbridge->ofproto, ofp_port,
-                                              ctx->xin->vlan_tci);
+                                              ctx->final_vlan_tci);
         if (vlandev_port == ofp_port) {
             out_port = odp_port;
         } else {
             out_port = ofp_port_to_odp_port(ctx->xbridge, vlandev_port);
             flow->vlan_tci = htons(0);
-            ctx->xin->vlan_tci = htons(0);
+            ctx->final_vlan_tci = htons(0);
         }
     }
 
     if (out_port != ODPP_NONE) {
         commit_odp_actions(flow, &ctx->base_flow,
                            &ctx->xout->odp_actions, &ctx->xout->wc,
-                           &ctx->mpls_depth_delta, ctx->xin->vlan_tci);
+                           &ctx->mpls_depth_delta, ctx->final_vlan_tci);
         nl_msg_put_odp_port(&ctx->xout->odp_actions, OVS_ACTION_ATTR_OUTPUT,
                             out_port);
 
@@ -1674,7 +1705,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
  out:
     /* Restore flow */
     flow->vlan_tci = flow_vlan_tci;
-    ctx->xin->vlan_tci = xin_vlan_tci;
+    ctx->final_vlan_tci = vlan_tci;
     flow->pkt_mark = flow_pkt_mark;
     flow->nw_tos = flow_nw_tos;
 }
@@ -1819,7 +1850,7 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
 
     commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
                        &ctx->xout->odp_actions, &ctx->xout->wc,
-                       &ctx->mpls_depth_delta, ctx->xin->vlan_tci);
+                       &ctx->mpls_depth_delta, ctx->final_vlan_tci);
 
     odp_execute_actions(NULL, packet, &key, ctx->xout->odp_actions.data,
                         ctx->xout->odp_actions.size, NULL, NULL);
@@ -2207,7 +2238,7 @@ xlate_sample_action(struct xlate_ctx *ctx,
 
   commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
                      &ctx->xout->odp_actions, &ctx->xout->wc,
-                     &ctx->mpls_depth_delta, ctx->xin->vlan_tci);
+                     &ctx->mpls_depth_delta, ctx->final_vlan_tci);
 
   compose_flow_sample_cookie(os->probability, os->collector_set_id,
                              os->obs_domain_id, os->obs_point_id, &cookie);
@@ -2236,13 +2267,14 @@ may_receive(const struct xport *xport, struct xlate_ctx *ctx)
 }
 
 static void
-vlan_tci_restore(struct xlate_in *xin, ovs_be16 *tci_ptr, ovs_be16 orig_tci)
+vlan_tci_restore(struct xlate_ctx *ctx, ovs_be16 orig_tci)
 {
     /* If MPLS actions were executed after vlan actions then
      * copy the final vlan_tci out and restore the intermediate VLAN state. */
-    if (xin->flow.vlan_tci != orig_tci && tci_ptr == &xin->vlan_tci) {
-        xin->vlan_tci = xin->flow.vlan_tci;
-        xin->flow.vlan_tci = orig_tci;
+    if (ctx->xin->flow.vlan_tci != orig_tci &&
+        ctx->next_vlan_tci == &ctx->final_vlan_tci) {
+        ctx->final_vlan_tci = ctx->xin->flow.vlan_tci;
+        ctx->xin->flow.vlan_tci = orig_tci;
     }
 }
 
@@ -2252,19 +2284,8 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
 {
     struct flow_wildcards *wc = &ctx->xout->wc;
     struct flow *flow = &ctx->xin->flow;
-    ovs_be16 *vlan_tci;
     const struct ofpact *a;
 
-
-    /* VLAN actions are stored in '*vlan_tci'. This variable initially
-     * points to 'xin->flow->vlan_tci', so that VLAN actions are applied
-     * before any MPLS actions. When an MPLS action is translated,
-     * 'vlan_tci' is updated to point to 'xin->vlan_tci'. This causes later
-     * VLAN actions to be applied after MPLS actions.  For each iteration
-     * of the loop 'xin->vlan_tci' is updated to reflect the final VLAN
-     * state of the flow. */
-    vlan_tci = &ctx->xin->flow.vlan_tci;
-
     OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
         struct ofpact_controller *controller;
         const struct ofpact_metadata *metadata;
@@ -2274,7 +2295,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
         }
 
         /* Update the final vlan state to match the current state. */
-        ctx->xin->vlan_tci = *vlan_tci;
+        ctx->final_vlan_tci = *ctx->next_vlan_tci;
 
         switch (a->type) {
         case OFPACT_OUTPUT:
@@ -2299,28 +2320,28 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
 
         case OFPACT_SET_VLAN_VID:
             wc->masks.vlan_tci |= htons(VLAN_VID_MASK | VLAN_CFI);
-            *vlan_tci &= ~htons(VLAN_VID_MASK);
-            *vlan_tci |= (htons(ofpact_get_SET_VLAN_VID(a)->vlan_vid)
+            *ctx->next_vlan_tci &= ~htons(VLAN_VID_MASK);
+            *ctx->next_vlan_tci |= (htons(ofpact_get_SET_VLAN_VID(a)->vlan_vid)
                           | htons(VLAN_CFI));
             break;
 
         case OFPACT_SET_VLAN_PCP:
             wc->masks.vlan_tci |= htons(VLAN_VID_MASK | VLAN_CFI);
-            *vlan_tci &= ~htons(VLAN_PCP_MASK);
-            *vlan_tci |=
+            *ctx->next_vlan_tci &= ~htons(VLAN_PCP_MASK);
+            *ctx->next_vlan_tci |=
                 htons((ofpact_get_SET_VLAN_PCP(a)->vlan_pcp << VLAN_PCP_SHIFT)
                       | VLAN_CFI);
             break;
 
         case OFPACT_STRIP_VLAN:
             memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci);
-            *vlan_tci = htons(0);
+            *ctx->next_vlan_tci = htons(0);
             break;
 
         case OFPACT_PUSH_VLAN:
             /* XXX 802.1AD(QinQ) */
             memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci);
-            *vlan_tci = htons(VLAN_CFI);
+            *ctx->next_vlan_tci = htons(VLAN_CFI);
             break;
 
         case OFPACT_SET_ETH_SRC:
@@ -2391,20 +2412,20 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
         case OFPACT_REG_MOVE: {
             ovs_be16 orig_tci = flow->vlan_tci;
             nxm_execute_reg_move(ofpact_get_REG_MOVE(a), flow, wc);
-            vlan_tci_restore(ctx->xin, vlan_tci, orig_tci);
+            vlan_tci_restore(ctx, orig_tci);
             break;
         }
 
         case OFPACT_REG_LOAD: {
             ovs_be16 orig_tci = flow->vlan_tci;
             nxm_execute_reg_load(ofpact_get_REG_LOAD(a), flow);
-            vlan_tci_restore(ctx->xin, vlan_tci, orig_tci);
+            vlan_tci_restore(ctx, orig_tci);
             break;
         }
 
         case OFPACT_STACK_PUSH: {
             ovs_be16 orig_tci = flow->vlan_tci;
-            flow->vlan_tci = *vlan_tci;
+            flow->vlan_tci = *ctx->next_vlan_tci;
             nxm_execute_stack_push(ofpact_get_STACK_PUSH(a), flow, wc,
                                    &ctx->stack);
             flow->vlan_tci = orig_tci;
@@ -2415,7 +2436,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             ovs_be16 orig_tci = flow->vlan_tci;
             nxm_execute_stack_pop(ofpact_get_STACK_POP(a), flow, wc,
                                   &ctx->stack);
-            vlan_tci_restore(ctx->xin, vlan_tci, orig_tci);
+            vlan_tci_restore(ctx, orig_tci);
             break;
         }
 
@@ -2433,11 +2454,11 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
              * Do not save and therefore pop the VLAN tags if the MPLS LSE
              * should be pushed before any VLAN tags that are present.
              * This is the behaviour described for OpenFlow 1.3. */
-            ctx->xin->vlan_tci = *vlan_tci;
+            ctx->final_vlan_tci = *ctx->next_vlan_tci;
             if (!oam->mpls_before_vlan) {
                 flow->vlan_tci = htons(0);
             }
-            vlan_tci = &ctx->xin->vlan_tci;
+            ctx->next_vlan_tci = &ctx->final_vlan_tci;
             break;
         }
 
@@ -2540,7 +2561,6 @@ xlate_in_init(struct xlate_in *xin, struct ofproto_dpif *ofproto,
 {
     xin->ofproto = ofproto;
     xin->flow = *flow;
-    xin->vlan_tci = flow->vlan_tci;
     xin->packet = packet;
     xin->may_learn = packet != NULL;
     xin->rule = rule;
@@ -2770,6 +2790,8 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
     ctx.table_id = 0;
     ctx.exit = false;
     ctx.mpls_depth_delta = 0;
+    ctx.final_vlan_tci = ctx->xin->flow.vlan_tci;
+    ctx.next_vlan_tci = &ctx->xin->flow.vlan_tci;
 
     if (xin->ofpacts) {
         ofpacts = xin->ofpacts;
diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h
index 54fd36d..6403f50 100644
--- a/ofproto/ofproto-dpif-xlate.h
+++ b/ofproto/ofproto-dpif-xlate.h
@@ -60,11 +60,6 @@ struct xlate_in {
      * this flow when actions change header fields. */
     struct flow flow;
 
-    /* If MPLS and VLAN actions were both present in the translation, and VLAN
-     * actions should occur after the MPLS actions, then this field is used
-     * to store the final vlan_tci state. */
-    ovs_be16 vlan_tci;
-
     /* The packet corresponding to 'flow', or a null pointer if we are
      * revalidating without a packet to refer to. */
     const struct ofpbuf *packet;
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ