VPWS initiation - VLAN tables

Changes:
- Adds a couple of procedures to test the VLAN tables
- Adds a couple of tests for L2 forwarding of stacked VLAN packets;
- Adds a new file for these tests
- Updates the README

Change-Id: I88edabfd3859980fb8dc744d716a3318a78fd097
diff --git a/README.md b/README.md
index 74ef3b6..b93eecc 100755
--- a/README.md
+++ b/README.md
@@ -127,3 +127,17 @@
 
 n/a means test is not available for that version of the pipeline.
 
+# VLAN Test Result Summary
+
+The following tests are implemented in vlan_flows.py and these are their results.
+
+Test Results                | 3.0 EA0
+-------                     | -------
+L2ForwardingStackedVLAN1    | ok
+L2ForwardingStackedVLAN2    | ok
+L2ForwardingStackedVLAN3    | ok
+L2ForwardingStackedVLAN4    | ok
+L2ForwardingStackedVLAN5    | ok
+
+For major details on the test look the comments in the code.
+
diff --git a/accton/accton_util.py b/accton/accton_util.py
index 784e654..3d80de7 100755
--- a/accton/accton_util.py
+++ b/accton/accton_util.py
@@ -18,9 +18,13 @@
 VLAN_TABLE_FLAG_ONLY_UNTAG=1
 VLAN_TABLE_FLAG_ONLY_TAG  =2
 VLAN_TABLE_FLAG_ONLY_BOTH =3
+VLAN_TABLE_FLAG_ONLY_STACKED=5
+VLAN_TABLE_FLAG_PRIORITY=6
+VLAN_TABLE_FLAG_ONLY_UNTAG_PRIORITY=7
 
 PORT_FLOW_TABLE=0
 VLAN_FLOW_TABLE=10
+VLAN_1_FLOW_TABLE=11
 TERMINATION_FLOW_TABLE=20
 UCAST_ROUTING_FLOW_TABLE=30
 MCAST_ROUTING_FLOW_TABLE=40
@@ -445,7 +449,6 @@
     logging.info("Add port table, match port %lx" % 0x10000)
     ctrl.message_send(request)
 
-
 def pop_vlan_flow(ctrl, ports, vlan_id=1):
     # table 10: vlan
     # goto to table 20
@@ -656,7 +659,7 @@
         logging.info("Add vlan %d tagged packets on port %d and go to table 20" %( vlan_id, of_port))
         ctrl.message_send(request)
 
-def add_one_vlan_table_flow(ctrl, of_port, vlan_id=1, vrf=0, flag=VLAN_TABLE_FLAG_ONLY_BOTH, send_barrier=False):
+def add_one_vlan_table_flow(ctrl, of_port, out_vlan_id=1, vlan_id=1, vrf=0, flag=VLAN_TABLE_FLAG_ONLY_BOTH, send_barrier=False):
     # table 10: vlan
     # goto to table 20
     if (flag == VLAN_TABLE_FLAG_ONLY_TAG) or (flag == VLAN_TABLE_FLAG_ONLY_BOTH) or (flag == 4):
@@ -734,6 +737,111 @@
         logging.info("Add vlan %d tagged packets on port %d and go to table 20" %( vlan_id, of_port))
         ctrl.message_send(request)
 
+    if (flag == VLAN_TABLE_FLAG_ONLY_STACKED):
+        # This flag is meant to managed stacked vlan packtes
+        # Matches on outer VLAN_ID, set OVID with outer VLAN.
+        # Finally expose inner VLAN_ID with a pop action and
+        # goto VLAN_1_FLOW_TABLE
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.in_port(of_port))
+        match.oxm_list.append(ofp.oxm.vlan_vid_masked(0x1000+vlan_id,0x1fff))
+
+        actions=[]
+        actions.append(ofp.action.set_field(ofp.oxm.exp2ByteValue(exp_type=ofp.oxm.OFDPA_EXP_TYPE_OVID, value=0x1000+vlan_id)))
+        actions.append(ofp.action.pop_vlan())
+
+        request = ofp.message.flow_add(
+            table_id=10,
+            cookie=42,
+            match=match,
+            instructions=[
+                ofp.instruction.apply_actions(
+                     actions=actions
+                ),
+                ofp.instruction.goto_table(VLAN_1_FLOW_TABLE)
+            ],
+            priority=0)
+        logging.info("Add vlan %d tagged packets on port %d and go to table %d" %( vlan_id, of_port, VLAN_1_FLOW_TABLE))
+        ctrl.message_send(request)
+
+    if (flag == VLAN_TABLE_FLAG_PRIORITY) :
+            match = ofp.match()
+            match.oxm_list.append(ofp.oxm.in_port(of_port))
+            match.oxm_list.append(ofp.oxm.vlan_vid_masked(0x1000, 0x1fff))
+            request = ofp.message.flow_add(
+                table_id=10,
+                cookie=42,
+                match=match,
+                instructions=[
+                  ofp.instruction.apply_actions(
+                    actions=[
+                        ofp.action.set_field(ofp.oxm.vlan_vid(0x1000+vlan_id)),
+                        ofp.action.push_vlan(0x8100),
+                        ofp.action.set_field(ofp.oxm.vlan_vid(0x1000+out_vlan_id)),
+                    ]
+                  ),
+                  ofp.instruction.goto_table(20)
+                ],
+                priority=0)
+            logging.info("Add vlan %d untagged packets on port %d and go to table 20" % (vlan_id, of_port))
+            ctrl.message_send(request)
+
+    if send_barrier:
+        do_barrier(ctrl)
+
+    return request
+
+def add_one_vlan_1_table_flow(ctrl, of_port, new_outer_vlan_id=-1, outer_vlan_id=1, inner_vlan_id=1, flag=VLAN_TABLE_FLAG_ONLY_TAG, send_barrier=False):
+    # table 11: vlan 1 table
+    # goto to table 20
+    if flag == VLAN_TABLE_FLAG_ONLY_TAG:
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.in_port(of_port))
+        match.oxm_list.append(ofp.oxm.vlan_vid_masked(0x1000+inner_vlan_id,0x1fff))
+        match.oxm_list.append(ofp.oxm.exp2ByteValue(ofp.oxm.OFDPA_EXP_TYPE_OVID, 0x1000+outer_vlan_id))
+
+        actions=[]
+        actions.append(ofp.action.push_vlan(0x8100))
+        if new_outer_vlan_id != -1:
+            actions.append(ofp.action.set_field(ofp.oxm.vlan_vid(0x1000+new_outer_vlan_id)))
+        else:
+            actions.append(ofp.action.set_field(ofp.oxm.vlan_vid(0x1000+outer_vlan_id)))
+
+        request = ofp.message.flow_add(
+            table_id=11,
+            cookie=42,
+            match=match,
+            instructions=[
+                ofp.instruction.apply_actions(
+                     actions=actions
+                ),
+                ofp.instruction.goto_table(TERMINATION_FLOW_TABLE)
+            ],
+            priority=0)
+        logging.info("Add vlan 1 double tagged %d-%d packets on port %d and go to table %d" %( outer_vlan_id, inner_vlan_id, of_port, TERMINATION_FLOW_TABLE))
+        ctrl.message_send(request)
+
+    if flag == VLAN_TABLE_FLAG_ONLY_UNTAG:
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.in_port(of_port))
+        match.oxm_list.append(ofp.oxm.vlan_vid_masked(0x1000+inner_vlan_id,0x1fff))
+        match.oxm_list.append(ofp.oxm.exp2ByteValue(ofp.oxm.OFDPA_EXP_TYPE_OVID, 0x1000+outer_vlan_id))
+
+        actions=[]
+        request = ofp.message.flow_add(
+            table_id=11,
+            cookie=42,
+            match=match,
+            instructions=[
+                ofp.instruction.apply_actions(
+                     actions=actions
+                ),
+                ofp.instruction.goto_table(TERMINATION_FLOW_TABLE)
+            ],
+            priority=0)
+        logging.info("Add vlan 1 double tagged %d-%d packets on port %d and go to table %d" %( outer_vlan_id, inner_vlan_id, of_port, TERMINATION_FLOW_TABLE))
+        ctrl.message_send(request)
+
     if send_barrier:
         do_barrier(ctrl)
 
diff --git a/ofdpa/vlan_flows.py b/ofdpa/vlan_flows.py
new file mode 100644
index 0000000..edc6535
--- /dev/null
+++ b/ofdpa/vlan_flows.py
@@ -0,0 +1,633 @@
+"""
+Check README file
+"""
+import Queue
+
+from oftest import config
+import inspect
+import logging
+import oftest.base_tests as base_tests
+import ofp
+from oftest.testutils import *
+from accton_util import *
+from utils import *
+
+MAX_INTERNAL_VLAN = 4094
+
+class L2ForwardingStackedVLAN( base_tests.SimpleDataPlane ):
+    """
+        Verify the proper operation of the pipeline part which includes VLAN table
+        and VLAN 1 table. This is necessary for classify packets in VPWS
+
+        One rules is necessary in VLAN table (10):
+        1)  inPort = 12 (Physical)  vlanId:mask = 0x1ff2:0x1fff (VLAN 4082) |
+            GoTo = 11 (VLAN 1) popVlanAction ovid = 8178 |
+            priority = 0 hard_time = 0 idle_time = 0 cookie = 1
+
+        One rules is necessary in VLAN 1 table (11):
+        2)  inPort = 12 (Physical)  vlanId = 0x1f8e (VLAN 3982) ovid = 0x1ff2 (VLAN 4082) |
+            GoTo = 20 (Termination MAC) newTpid2 = 0x8100 newVlanId2 = 0x1ff2 (VLAN 4082) |
+            priority = 0 hard_time = 0 idle_time = 0 cookie = 2
+
+        In this test case outer_vlan_id = (MAX_INTERNAL_VLAN - port_no) and
+        inner_vlan_id = (MAX_INTERNAL_VLAN - 100 - port_no)
+        The remaining part of the test is based on the use of the bridging table
+    """
+
+    def runTest( self ):
+        groups = Queue.LifoQueue( )
+        try:
+            if len( config[ "port_map" ] ) < 2:
+                logging.info( "Port count less than 2, can't run this case" )
+                return
+
+            ports = sorted( config[ "port_map" ].keys( ) )
+            for in_port in ports:
+                outer_vlan_id = MAX_INTERNAL_VLAN - in_port
+                inner_vlan_id = MAX_INTERNAL_VLAN - 100 - in_port
+                add_one_vlan_table_flow(
+                    self.controller,
+                    in_port,
+                    vlan_id=outer_vlan_id,
+                    flag=VLAN_TABLE_FLAG_ONLY_STACKED
+                    )
+                add_one_vlan_1_table_flow(
+                    self.controller,
+                    in_port,
+                    new_outer_vlan_id=-1,
+                    outer_vlan_id=outer_vlan_id,
+                    inner_vlan_id=inner_vlan_id,
+                    flag=VLAN_TABLE_FLAG_ONLY_TAG
+                    )
+                for out_port in ports:
+                    if out_port == in_port:
+                        continue
+                    L2gid, l2msg = add_one_l2_interface_group(
+                        self.controller,
+                        out_port,
+                        outer_vlan_id,
+                        True,
+                        False
+                        )
+                    groups.put( L2gid )
+                    add_bridge_flow(
+                        self.controller,
+                        [ 0x00, 0x12, 0x34, 0x56, 0x78, in_port ],
+                        outer_vlan_id,
+                        L2gid,
+                        True
+                        )
+
+            do_barrier( self.controller )
+
+            for in_port in ports:
+                outer_vlan_id = MAX_INTERNAL_VLAN - in_port
+                inner_vlan_id = MAX_INTERNAL_VLAN - 100 - in_port
+                mac_dst = '00:12:34:56:78:%02X' % in_port
+
+                parsed_pkt = simple_tcp_packet_two_vlan(
+                        pktlen=108,
+                        out_dl_vlan_enable=True,
+                        out_vlan_vid=outer_vlan_id,
+                        in_dl_vlan_enable=True,
+                        in_vlan_vid=inner_vlan_id,
+                        eth_dst=mac_dst,
+                        )
+                pkt = str( parsed_pkt )
+                self.dataplane.send( in_port, pkt )
+
+                # change dest based on port number
+                for out_port in ports:
+                    if out_port == in_port:
+                        verify_no_packet( self, pkt, in_port )
+                        continue
+                    verify_packet( self, pkt, out_port )
+                    verify_no_other_packets( self )
+
+        finally:
+            delete_all_flows( self.controller )
+            delete_groups( self.controller, groups )
+            delete_all_groups( self.controller )
+
+class L2ForwardingStackedVLAN2( base_tests.SimpleDataPlane ):
+    """
+        Verify the proper operation of the pipeline part which includes VLAN table
+        and VLAN 1 table. This is necessary for classify packets in VPWS. In this test
+        case we verify the change of outer vlan VLAN 1 table.
+
+        One rules is necessary in VLAN table (10):
+        1)  inPort = 12 (Physical)  vlanId:mask = 0x1ff2:0x1fff (VLAN 4082) |
+            GoTo = 11 (VLAN 1) popVlanAction ovid = 8178 |
+            priority = 0 hard_time = 0 idle_time = 0 cookie = 1
+
+        One rules is necessary in VLAN 1 table (11):
+        2)  inPort = 12 (Physical)  vlanId = 0x1f8e (VLAN 3982) ovid = 0x1ff2 (VLAN 4082) |
+            GoTo = 20 (Termination MAC) newTpid2 = 0x8100 newVlanId2 = 0x1f2a (VLAN 3882) |
+            priority = 0 hard_time = 0 idle_time = 0 cookie = 2
+
+        In this test case:
+        1) outer_vlan_id = (MAX_INTERNAL_VLAN - port_no)
+        2) inner_vlan_id = (MAX_INTERNAL_VLAN - 100 - port_no)
+        3) new_outer_vlan_id = (MAX_INTERNAL_VLAN - 200 - port_no)
+
+        The remaining part of the test is based on the use of the bridging table
+    """
+
+    MAX_INTERNAL_VLAN = 4094
+
+    def runTest( self ):
+        groups = Queue.LifoQueue( )
+        try:
+            if len( config[ "port_map" ] ) < 2:
+                logging.info( "Port count less than 2, can't run this case" )
+                return
+
+            ports = sorted( config[ "port_map" ].keys( ) )
+            for in_port in ports:
+                new_outer_vlan_id = MAX_INTERNAL_VLAN  - 200 - in_port
+                outer_vlan_id = MAX_INTERNAL_VLAN - in_port
+                inner_vlan_id = MAX_INTERNAL_VLAN - 100 - in_port
+                add_one_vlan_table_flow(
+                    self.controller,
+                    in_port,
+                    vlan_id=outer_vlan_id,
+                    flag=VLAN_TABLE_FLAG_ONLY_STACKED
+                    )
+                add_one_vlan_1_table_flow(
+                    self.controller,
+                    in_port,
+                    new_outer_vlan_id=new_outer_vlan_id,
+                    outer_vlan_id=outer_vlan_id,
+                    inner_vlan_id=inner_vlan_id,
+                    flag=VLAN_TABLE_FLAG_ONLY_TAG
+                    )
+                for out_port in ports:
+                    if out_port == in_port:
+                        continue
+                    L2gid, l2msg = add_one_l2_interface_group(
+                        self.controller,
+                        out_port,
+                        new_outer_vlan_id,
+                        True,
+                        False
+                        )
+                    groups.put( L2gid )
+                    add_bridge_flow(
+                        self.controller,
+                        [ 0x00, 0x12, 0x34, 0x56, 0x78, in_port ],
+                        new_outer_vlan_id,
+                        L2gid,
+                        True
+                        )
+
+            do_barrier( self.controller )
+
+            for in_port in ports:
+                new_outer_vlan_id = MAX_INTERNAL_VLAN  - 200 - in_port
+                outer_vlan_id = MAX_INTERNAL_VLAN - in_port
+                inner_vlan_id = MAX_INTERNAL_VLAN - 100 - in_port
+                mac_dst = '00:12:34:56:78:%02X' % in_port
+
+                parsed_pkt = simple_tcp_packet_two_vlan(
+                        pktlen=108,
+                        out_dl_vlan_enable=True,
+                        out_vlan_vid=outer_vlan_id,
+                        in_dl_vlan_enable=True,
+                        in_vlan_vid=inner_vlan_id,
+                        eth_dst=mac_dst,
+                        )
+                pkt = str( parsed_pkt )
+                self.dataplane.send( in_port, pkt )
+
+                # change dest based on port number
+                for out_port in ports:
+                    parsed_pkt = simple_tcp_packet_two_vlan(
+                        pktlen=108,
+                        out_dl_vlan_enable=True,
+                        out_vlan_vid=new_outer_vlan_id,
+                        in_dl_vlan_enable=True,
+                        in_vlan_vid=inner_vlan_id,
+                        eth_dst=mac_dst,
+                        )
+                    pkt = str( parsed_pkt )
+                    if out_port == in_port:
+                        verify_no_packet( self, pkt, in_port )
+                        continue
+                    verify_packet( self, pkt, out_port )
+                    verify_no_other_packets( self )
+
+        finally:
+            delete_all_flows( self.controller )
+            delete_groups( self.controller, groups )
+            delete_all_groups( self.controller )
+
+class L2ForwardingStackedVLAN3( base_tests.SimpleDataPlane ):
+    """
+        Verify the proper operation of the pipeline part which includes VLAN table.
+        This is necessary for classify packets in VPWS. In this test
+        case we verify the change of outer vlan pushing another vlan in VLAN table.
+
+        One rules is necessary in VLAN table (10):
+        1)  inPort = 12 (Physical)  vlanId:mask = 0x1f8e:0x1fff (VLAN 3982) |
+            GoTo = 20 (Termination MAC) newTpid2 = 0x8100 newVlanId2 = 0x1ff2 (VLAN 4082) |
+            priority = 0 hard_time = 0 idle_time = 0 cookie = 1
+
+        In this test case:
+        1) outer_vlan_id = (MAX_INTERNAL_VLAN - port_no)
+        2) inner_vlan_id = (MAX_INTERNAL_VLAN - 100 - port_no)
+
+        The remaining part of the test is based on the use of the bridging table
+    """
+
+    MAX_INTERNAL_VLAN = 4094
+
+    def runTest( self ):
+        groups = Queue.LifoQueue( )
+        try:
+            if len( config[ "port_map" ] ) < 2:
+                logging.info( "Port count less than 2, can't run this case" )
+                return
+
+            ports = sorted( config[ "port_map" ].keys( ) )
+            for in_port in ports:
+                outer_vlan_id = MAX_INTERNAL_VLAN - in_port
+                inner_vlan_id = MAX_INTERNAL_VLAN - 100 - in_port
+                add_vlan_table_flow_pvid(
+                    self.controller,
+                    in_port,
+                    match_vid=inner_vlan_id,
+                    pvid=outer_vlan_id,
+                    send_barrier=True
+                    )
+                for out_port in ports:
+                    if out_port == in_port:
+                        continue
+                    L2gid, l2msg = add_one_l2_interface_group(
+                        self.controller,
+                        out_port,
+                        outer_vlan_id,
+                        True,
+                        False
+                        )
+                    groups.put( L2gid )
+                    add_bridge_flow(
+                        self.controller,
+                        [ 0x00, 0x12, 0x34, 0x56, 0x78, in_port ],
+                        outer_vlan_id,
+                        L2gid,
+                        True
+                        )
+
+            do_barrier( self.controller )
+
+            for in_port in ports:
+                outer_vlan_id = MAX_INTERNAL_VLAN - in_port
+                inner_vlan_id = MAX_INTERNAL_VLAN - 100 - in_port
+                mac_dst = '00:12:34:56:78:%02X' % in_port
+
+                parsed_pkt = simple_tcp_packet(
+                        pktlen=108,
+                        dl_vlan_enable=True,
+                        vlan_vid=inner_vlan_id,
+                        eth_dst=mac_dst,
+                        )
+                pkt = str( parsed_pkt )
+                self.dataplane.send( in_port, pkt )
+
+                # change dest based on port number
+                for out_port in ports:
+                    parsed_pkt = simple_tcp_packet_two_vlan(
+                        pktlen=112,
+                        out_dl_vlan_enable=True,
+                        out_vlan_vid=outer_vlan_id,
+                        in_dl_vlan_enable=True,
+                        in_vlan_vid=inner_vlan_id,
+                        eth_dst=mac_dst,
+                        )
+                    pkt = str( parsed_pkt )
+                    if out_port == in_port:
+                        verify_no_packet( self, pkt, in_port )
+                        continue
+                    verify_packet( self, pkt, out_port )
+                    verify_no_other_packets( self )
+
+        finally:
+            delete_all_flows( self.controller )
+            delete_groups( self.controller, groups )
+            delete_all_groups( self.controller )
+
+class L2ForwardingStackedVLAN4( base_tests.SimpleDataPlane ):
+    """
+        Verify the proper operation of the pipeline part which includes VLAN table
+        and VLAN 1 table. This is necessary for classify packets in VPWS. In this test
+        case we verify the change of outer vlan popping the tag in VLAN 1 table.
+
+        One rules is necessary in VLAN table (10):
+        1)  inPort = 12 (Physical)  vlanId:mask = 0x1ff2:0x1fff (VLAN 4082) |
+            GoTo = 11 (VLAN 1) popVlanAction ovid = 8178 |
+            priority = 0 hard_time = 0 idle_time = 0 cookie = 1
+
+        One rules is necessary in VLAN table (11):
+        1)  inPort = 12 (Physical)  vlanId = 0x1f8e (VLAN 3982) ovid = 0x1ff2 (VLAN 4082) |
+            GoTo = 20 (Termination MAC) |
+            priority = 0 hard_time = 0 idle_time = 0 cookie = 2
+
+        In this test case:
+        1) outer_vlan_id = (MAX_INTERNAL_VLAN - port_no)
+        2) inner_vlan_id = (MAX_INTERNAL_VLAN - 100 - port_no)
+
+        The remaining part of the test is based on the use of the bridging table
+    """
+
+    MAX_INTERNAL_VLAN = 4094
+
+    def runTest( self ):
+        groups = Queue.LifoQueue( )
+        try:
+            if len( config[ "port_map" ] ) < 2:
+                logging.info( "Port count less than 2, can't run this case" )
+                return
+
+            ports = sorted( config[ "port_map" ].keys( ) )
+            for in_port in ports:
+                outer_vlan_id = MAX_INTERNAL_VLAN - in_port
+                inner_vlan_id = MAX_INTERNAL_VLAN - 100 - in_port
+                add_one_vlan_table_flow(
+                    self.controller,
+                    in_port,
+                    vlan_id=outer_vlan_id,
+                    flag=VLAN_TABLE_FLAG_ONLY_STACKED
+                    )
+                add_one_vlan_1_table_flow(
+                    self.controller,
+                    in_port,
+                    new_outer_vlan_id=-1,
+                    outer_vlan_id=outer_vlan_id,
+                    inner_vlan_id=inner_vlan_id,
+                    flag=VLAN_TABLE_FLAG_ONLY_UNTAG
+                    )
+                for out_port in ports:
+                    if out_port == in_port:
+                        continue
+                    L2gid, l2msg = add_one_l2_interface_group(
+                        self.controller,
+                        out_port,
+                        inner_vlan_id,
+                        True,
+                        False
+                        )
+                    groups.put( L2gid )
+                    add_bridge_flow(
+                        self.controller,
+                        [ 0x00, 0x12, 0x34, 0x56, 0x78, in_port ],
+                        inner_vlan_id,
+                        L2gid,
+                        True
+                        )
+
+            do_barrier( self.controller )
+
+            for in_port in ports:
+                outer_vlan_id = MAX_INTERNAL_VLAN - in_port
+                inner_vlan_id = MAX_INTERNAL_VLAN - 100 - in_port
+                mac_dst = '00:12:34:56:78:%02X' % in_port
+
+                parsed_pkt = simple_tcp_packet_two_vlan(
+                        pktlen=112,
+                        out_dl_vlan_enable=True,
+                        out_vlan_vid=outer_vlan_id,
+                        in_dl_vlan_enable=True,
+                        in_vlan_vid=inner_vlan_id,
+                        eth_dst=mac_dst,
+                        )
+                pkt = str( parsed_pkt )
+                self.dataplane.send( in_port, pkt )
+
+                # change dest based on port number
+                for out_port in ports:
+                    parsed_pkt = simple_tcp_packet(
+                        pktlen=108,
+                        dl_vlan_enable=True,
+                        vlan_vid=inner_vlan_id,
+                        eth_dst=mac_dst,
+                        )
+                    pkt = str( parsed_pkt )
+                    if out_port == in_port:
+                        verify_no_packet( self, pkt, in_port )
+                        continue
+                    verify_packet( self, pkt, out_port )
+                    verify_no_other_packets( self )
+
+        finally:
+            delete_all_flows( self.controller )
+            delete_groups( self.controller, groups )
+            delete_all_groups( self.controller )
+
+class L2ForwardingStackedVLAN5( base_tests.SimpleDataPlane ):
+    """
+        Verify the proper operation of the pipeline part which includes VLAN table
+        and VLAN 1 table. This is necessary for classify packets in VPWS. In this test
+        case we verify the change of outer vlan in VLAN table.
+
+        One rules is necessary in VLAN table (10):
+        1)  inPort = 12 (Physical)  vlanId:mask = 0x1ff2:0x1fff (VLAN 4082) |
+            GoTo = 20 (VLAN 1) newVlanId = 0x1f2a (VLAN 3882) |
+            priority = 0 hard_time = 0 idle_time = 0 cookie = 1
+
+        In this test case:
+        1) outer_vlan_id = (MAX_INTERNAL_VLAN - port_no)
+        3) new_outer_vlan_id = (MAX_INTERNAL_VLAN - 200 - port_no)
+
+        The remaining part of the test is based on the use of the bridging table
+    """
+
+    MAX_INTERNAL_VLAN = 4094
+
+    def runTest( self ):
+        groups = Queue.LifoQueue( )
+        try:
+            if len( config[ "port_map" ] ) < 2:
+                logging.info( "Port count less than 2, can't run this case" )
+                return
+
+            ports = sorted( config[ "port_map" ].keys( ) )
+            for in_port in ports:
+                new_outer_vlan_id = MAX_INTERNAL_VLAN  - 200 - in_port
+                outer_vlan_id = MAX_INTERNAL_VLAN - in_port
+                add_one_vlan_table_flow_translation(
+                    self.controller,
+                    in_port,
+                    vlan_id=outer_vlan_id,
+                    new_vlan_id=new_outer_vlan_id,
+                    vrf=0,
+                    flag=VLAN_TABLE_FLAG_ONLY_TAG,
+                    send_barrier=False
+                    )
+                for out_port in ports:
+                    if out_port == in_port:
+                        continue
+                    L2gid, l2msg = add_one_l2_interface_group(
+                        self.controller,
+                        out_port,
+                        new_outer_vlan_id,
+                        True,
+                        False
+                        )
+                    groups.put( L2gid )
+                    add_bridge_flow(
+                        self.controller,
+                        [ 0x00, 0x12, 0x34, 0x56, 0x78, in_port ],
+                        new_outer_vlan_id,
+                        L2gid,
+                        True
+                        )
+
+            do_barrier( self.controller )
+
+            for in_port in ports:
+                new_outer_vlan_id = MAX_INTERNAL_VLAN  - 200 - in_port
+                outer_vlan_id = MAX_INTERNAL_VLAN - in_port
+                inner_vlan_id =MAX_INTERNAL_VLAN - 100 - in_port
+                mac_dst = '00:12:34:56:78:%02X' % in_port
+
+                parsed_pkt = simple_tcp_packet_two_vlan(
+                        pktlen=112,
+                        out_dl_vlan_enable=True,
+                        out_vlan_vid=outer_vlan_id,
+                        in_dl_vlan_enable=True,
+                        in_vlan_vid=inner_vlan_id,
+                        eth_dst=mac_dst,
+                        )
+                pkt = str( parsed_pkt )
+                self.dataplane.send( in_port, pkt )
+
+                # change dest based on port number
+                for out_port in ports:
+                    parsed_pkt = simple_tcp_packet_two_vlan(
+                        pktlen=112,
+                        out_dl_vlan_enable=True,
+                        out_vlan_vid=new_outer_vlan_id,
+                        in_dl_vlan_enable=True,
+                        in_vlan_vid=inner_vlan_id,
+                        eth_dst=mac_dst,
+                        )
+                    pkt = str( parsed_pkt )
+                    if out_port == in_port:
+                        verify_no_packet( self, pkt, in_port )
+                        continue
+                    verify_packet( self, pkt, out_port )
+                    verify_no_other_packets( self )
+
+        finally:
+            delete_all_flows( self.controller )
+            delete_groups( self.controller, groups )
+            delete_all_groups( self.controller )
+
+class L2ForwardingStackedVLAN6( base_tests.SimpleDataPlane ):
+    """
+        Verify the proper operation of the pipeline part which includes VLAN table.
+        This is necessary for classify packets priority tagged. In this test
+        case we verify the change of outer vlan in VLAN table.
+
+        Two rules are necessary in VLAN table (10):
+        1)  inPort = 12 (Physical)  vlanId:mask = 0x1000:0x1fff (VLAN 0) |
+            GoTo = 20 (Termination MAC) newVlanId = 0x1f8e (VLAN 3982) newTpid2 = 0x8100 newVlanId2 = 0x1ff2 (VLAN 4082) |
+            priority = 0 hard_time = 0 idle_time = 0 cookie = 3
+        2)  inPort = 12 (Physical)  vlanId:mask = 0x1ff2:0x1fff (VLAN 4082) |
+            GoTo = 20 (Termination MAC) |
+            priority = 0 hard_time = 0 idle_time = 0 cookie = 1
+
+
+        In this test case:
+        1) outer_vlan_id = (MAX_INTERNAL_VLAN - port_no)
+        3) inner_vlan_id = (MAX_INTERNAL_VLAN - 100 - port_no)
+
+        The remaining part of the test is based on the use of the bridging table
+    """
+
+    MAX_INTERNAL_VLAN = 4094
+
+    def runTest( self ):
+        groups = Queue.LifoQueue( )
+        try:
+            if len( config[ "port_map" ] ) < 2:
+                logging.info( "Port count less than 2, can't run this case" )
+                return
+
+            ports = sorted( config[ "port_map" ].keys( ) )
+            for in_port in ports:
+                outer_vlan_id = MAX_INTERNAL_VLAN - in_port
+                inner_vlan_id = MAX_INTERNAL_VLAN - 100 - in_port
+                add_one_vlan_table_flow(
+                    ctrl=self.controller,
+                    of_port=in_port,
+                    vlan_id=outer_vlan_id,
+                    vrf=0,
+                    flag=VLAN_TABLE_FLAG_ONLY_BOTH,
+                    send_barrier=False
+                    )
+                add_one_vlan_table_flow(
+                    ctrl=self.controller,
+                    of_port=in_port,
+                    out_vlan_id=outer_vlan_id,
+                    vlan_id=inner_vlan_id,
+                    vrf=0,
+                    flag=VLAN_TABLE_FLAG_PRIORITY,
+                    send_barrier=False
+                    )
+                for out_port in ports:
+                    if out_port == in_port:
+                        continue
+                    L2gid, l2msg = add_one_l2_interface_group(
+                        self.controller,
+                        out_port,
+                        outer_vlan_id,
+                        True,
+                        False
+                        )
+                    groups.put( L2gid )
+                    add_bridge_flow(
+                        self.controller,
+                        [ 0x00, 0x12, 0x34, 0x56, 0x78, in_port ],
+                        outer_vlan_id,
+                        L2gid,
+                        True
+                        )
+
+            do_barrier( self.controller )
+
+            for in_port in ports:
+                outer_vlan_id = MAX_INTERNAL_VLAN - in_port
+                inner_vlan_id = MAX_INTERNAL_VLAN - 100 - in_port
+                mac_dst = '00:12:34:56:78:%02X' % in_port
+
+                parsed_pkt = simple_tcp_packet(
+                        pktlen=112,
+                        dl_vlan_enable=True,
+                        vlan_vid=0,
+                        eth_dst=mac_dst,
+                        )
+                pkt = str( parsed_pkt )
+                self.dataplane.send( in_port, pkt )
+
+                # change dest based on port number
+                for out_port in ports:
+                    parsed_pkt = simple_tcp_packet_two_vlan(
+                        pktlen=116,
+                        out_dl_vlan_enable=True,
+                        out_vlan_vid=outer_vlan_id,
+                        in_dl_vlan_enable=True,
+                        in_vlan_vid=inner_vlan_id,
+                        eth_dst=mac_dst,
+                        )
+                    pkt = str( parsed_pkt )
+                    if out_port == in_port:
+                        verify_no_packet( self, pkt, in_port )
+                        continue
+                    verify_packet( self, pkt, out_port )
+                    verify_no_other_packets( self )
+
+        finally:
+            delete_all_flows( self.controller )
+            delete_groups( self.controller, groups )
+            delete_all_groups( self.controller )