If a packet's vlan vid has been changed(striped or modified) before
entering the "normal" processing, it should be consider a packet on the
new VLAN. Therefore vlan checking is not needed.

Signed-off-by: Hunt Xu <mhun...@gmail.com>
---
 ofproto/ofproto-dpif-xlate.c | 23 ++++++++++++----
 tests/ofproto-dpif.at        | 65 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 82 insertions(+), 6 deletions(-)

diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index f6391ed..c533a4e 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -374,8 +374,9 @@ struct xlate_ctx {
      * When translation is otherwise complete, ofpacts_execute_action_set()
      * converts it to a set of "struct ofpact"s that can be translated into
      * datapath actions. */
-    bool action_set_has_group;  /* Action set contains OFPACT_GROUP? */
-    struct ofpbuf action_set;   /* Action set. */
+    bool action_set_has_group;        /* Action set contains OFPACT_GROUP? */
+    bool action_set_changes_vlan_vid; /* Action set changes VLAN vid? */
+    struct ofpbuf action_set;         /* Action set. */
 
     enum xlate_error error;     /* Translation failed. */
 };
@@ -2314,11 +2315,17 @@ xlate_normal(struct xlate_ctx *ctx)
 
     /* Check VLAN. */
     vid = vlan_tci_to_vid(flow->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;
+    if (ctx->action_set_changes_vlan_vid) {
+        xlate_report(ctx, "flow VLAN VID changed to %u, not checking", vid);
+        vlan = vid;
+    } else  {
+        if (!input_vid_is_valid(vid, in_xbundle, ctx->xin->packet != NULL)) {
+            xlate_report(ctx, "disallowed VLAN VID for this input "
+                         "port, dropping");
+            return;
+        }
+        vlan = input_vid_to_vlan(in_xbundle, vid);
     }
-    vlan = input_vid_to_vlan(in_xbundle, vid);
 
     /* Check other admissibility requirements. */
     if (in_port && !is_admissible(ctx, in_port, vlan)) {
@@ -4767,6 +4774,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t 
ofpacts_len,
                 flow->vlan_tci &= ~htons(VLAN_VID_MASK);
                 flow->vlan_tci |= (htons(ofpact_get_SET_VLAN_VID(a)->vlan_vid)
                                    | htons(VLAN_CFI));
+                ctx->action_set_changes_vlan_vid = true;
             }
             break;
 
@@ -4783,12 +4791,14 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t 
ofpacts_len,
         case OFPACT_STRIP_VLAN:
             memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci);
             flow->vlan_tci = htons(0);
+            ctx->action_set_changes_vlan_vid = true;
             break;
 
         case OFPACT_PUSH_VLAN:
             /* XXX 802.1AD(QinQ) */
             memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci);
             flow->vlan_tci = htons(VLAN_CFI);
+            ctx->action_set_changes_vlan_vid = true;
             break;
 
         case OFPACT_SET_ETH_SRC:
@@ -5362,6 +5372,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out 
*xout)
         .ct_nat_action = NULL,
 
         .action_set_has_group = false,
+        .action_set_changes_vlan_vid = false,
         .action_set = OFPBUF_STUB_INITIALIZER(action_set_stub),
     };
 
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index ec7bd60..123394d 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -3269,6 +3269,71 @@ done
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([ofproto-dpif - VLAN handling, vid changed])
+OVS_VSWITCHD_START(
+  [set Bridge br0 fail-mode=secure -- \
+   add-port br0 p1                           tag=1              -- \
+   add-port br0 p2                           tag=2              -- \
+   add-port br0 p3                           tag=3              -- \
+   add-port br0 p4                                 trunks=4,5   -- \
+   add-port br0 p5                           tag=4              \
+                   other-config:priority-tags=true              -- \
+   add-port br0 p6 vlan_mode=native-untagged tag=6 trunks=4,5,6 \
+                   other-config:priority-tags=true              -- \
+   set Interface p1 type=dummy ofport_request=101 -- \
+   set Interface p2 type=dummy ofport_request=102 -- \
+   set Interface p3 type=dummy ofport_request=103 -- \
+   set Interface p4 type=dummy ofport_request=104 -- \
+   set Interface p5 type=dummy ofport_request=105 -- \
+   set Interface p6 type=dummy ofport_request=106 --])
+
+AT_CHECK([ovs-ofctl add-flow br0 in_port=101,actions=mod_vlan_vid:0,normal])
+AT_CHECK([ovs-ofctl add-flow br0 in_port=102,actions=strip_vlan,normal])
+AT_CHECK([ovs-ofctl add-flow br0 in_port=103,actions=mod_vlan_vid:4,normal])
+AT_CHECK([ovs-ofctl add-flow br0 in_port=104,actions=mod_vlan_vid:6,normal])
+
+dnl Each of these specifies an in_port by number, a VLAN VID (or "none"),
+dnl a VLAN PCP (used if the VID isn't "none") and the expected set of datapath
+dnl actions.
+for tuple in \
+        "1 none 0 100" \
+        "1 10   0 pop_vlan,100" \
+        "1 11   1 pop_vlan,100" \
+        "2 none 0 100" \
+        "2 12   1 pop_vlan,100" \
+        "2 13   0 pop_vlan,100" \
+        "3 none 0 5,push_vlan(vid=4,pcp=0),4,6,100" \
+        "3 14   0 pop_vlan,5,push_vlan(vid=4,pcp=0),4,6,100" \
+        "3 15   1 
pop_vlan,push_vlan(vid=0,pcp=1),5,pop_vlan,push_vlan(vid=4,pcp=1),4,6,100" \
+        "4 none 0 6,push_vlan(vid=6,pcp=0),100" \
+        "4 16   1 
pop_vlan,push_vlan(vid=0,pcp=1),6,pop_vlan,push_vlan(vid=6,pcp=1),100"
+do
+  set $tuple
+  in_port=$1
+  vlan=$2
+  pcp=$3
+  expected=$4
+
+  if test $vlan = none; then
+    
flow="in_port($in_port),eth(src=50:54:00:00:00:01,dst=ff:ff:ff:ff:ff:ff),eth_type(0xabcd)"
+  else
+    
flow="in_port($in_port),eth(src=50:54:00:00:00:01,dst=ff:ff:ff:ff:ff:ff),eth_type(0x8100),vlan(vid=$vlan,pcp=$pcp),encap(eth_type(0xabcd))"
+  fi
+
+  echo "----------------------------------------------------------------------"
+  echo "in_port=$in_port vlan=$vlan pcp=$pcp"
+
+  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow"], [0], [stdout])
+  actual=`tail -1 stdout | sed 's/Datapath actions: //'`
+
+  AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
+  mv stdout expout
+  AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
+done
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([ofproto-dpif - MPLS handling])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
-- 
2.10.2

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to