Add double vlan test
diff --git a/olt.py b/olt.py
index 80f9169..ca6928f 100644
--- a/olt.py
+++ b/olt.py
@@ -15,6 +15,71 @@
 onu_port2 = test_param_get("onu_port2", 2)
 olt_port = test_param_get("olt_port", 129)
 
+def double_vlan_udp_packet(pktlen=100,
+                      eth_dst='00:01:02:03:04:05',
+                      eth_src='00:06:07:08:09:0a',
+                      dl_vlan_enable=False,
+                      c_vlan_vid=0,
+                      c_vlan_pcp=0,
+                      s_vlan_vid=0,
+                      s_vlan_pcp=0,
+                      ip_src='192.168.0.1',
+                      ip_dst='192.168.0.2',
+                      ip_tos=0,
+                      ip_ttl=64,
+                      udp_sport=1234,
+                      udp_dport=80,
+                      ip_ihl=None,
+                      ip_options=False
+                      ):
+    """
+    Return a double vlan tagged dataplane UDP packet
+    Supports a few parameters:
+    @param len Length of packet in bytes w/o CRC
+    @param eth_dst Destination MAC
+    @param eth_src Source MAC
+    @param dl_vlan_enable True if the packet is with vlan, False otherwise
+    @param c_vlan_vid CVLAN ID
+    @param c_vlan_pcp CVLAN priority
+    @param s_vlan_vid SVLAN ID
+    @param s_vlan_pcp SVLAN priority
+    @param ip_src IP source
+    @param ip_dst IP destination
+    @param ip_tos IP ToS
+    @param ip_ttl IP TTL
+    @param udp_dport UDP destination port
+    @param udp_sport UDP source port
+
+    Generates a simple UDP packet. Users shouldn't assume anything about
+    this packet other than that it is a valid ethernet/IP/UDP frame.
+    """
+
+    if MINSIZE > pktlen:
+        pktlen = MINSIZE
+
+    # Note Dot1Q.id is really CFI
+    if (dl_vlan_enable):
+        pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
+            scapy.Dot1Q(prio=s_vlan_pcp, vlan=s_vlan_vid)/ \
+            scapy.Dot1Q(prio=c_vlan_pcp, vlan=c_vlan_vid)/ \
+            scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
+            scapy.UDP(sport=udp_sport, dport=udp_dport)
+    else:
+        if not ip_options:
+            pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
+                scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl)/ \
+                scapy.UDP(sport=udp_sport, dport=udp_dport)
+	
+        else:
+            pkt = scapy.Ether(dst=eth_dst, src=eth_src)/ \
+                scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos, ttl=ip_ttl, ihl=ip_ihl, options=ip_options)/ \
+                scapy.UDP(sport=udp_sport, dport=udp_dport)
+
+    pkt = pkt/("D" * (pktlen - len(pkt)))
+
+    return pkt
+
+
 def testPacketIn(self, match, parsed_pkt):
 
     delete_all_flows(self.controller)
@@ -238,7 +303,7 @@
 
         logging.info("Inserting flow tagging upstream")
         self.controller.message_send(request)
-
+        
         #POP
         match = ofp.match()
         match.oxm_list.append(ofp.oxm.in_port(olt_port))
@@ -272,7 +337,7 @@
         # Send untagged packet in the OLT port and expect no packets to come out
         self.dataplane.send(olt_port, str(inPkt))
         verify_packets(self, outPkt, [])
-
+	
         inPkt = simple_udp_packet(pktlen=104, dl_vlan_enable=True,
                                   vlan_vid=vlan_id, vlan_pcp=0, dl_vlan_cfi=0)
         outPkt = simple_udp_packet(pktlen=104, dl_vlan_enable=True, vlan_vid=0, vlan_pcp=0)
@@ -626,4 +691,127 @@
         do_barrier(self.controller)
         verify_no_errors(self.controller)
 
+class DoubleVlanTest(base_tests.SimpleDataPlane):
+       
+    def runTest(self):
+        logging.info("Running double vlan tests")
+        delete_all_flows(self.controller)
+
+        c_vlan_id = 100
+	s_vlan_id = 102
+	# upstream flow rule
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.in_port(onu_port))
+        match.oxm_list.append(ofp.oxm.vlan_vid_masked(value=ofp.OFPVID_PRESENT, value_mask=ofp.OFPVID_PRESENT))
+        match.oxm_list.append(ofp.oxm.vlan_pcp(value = 0))
+
+	# push inner vlan (c-vlan) for upstream
+        request = ofp.message.flow_add(
+            table_id=test_param_get("table", 0),
+            cookie=42,
+            match=match,
+            instructions=[
+                ofp.instruction.apply_actions(
+                    actions=[
+                        ofp.action.set_field(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | c_vlan_id)) ] ),
+		ofp.instruction.goto_table(1) ],
+            buffer_id=ofp.OFP_NO_BUFFER,
+            priority=1000)
+
+        self.controller.message_send(request)
+        do_barrier(self.controller)
+        verify_no_errors(self.controller)
  
+	# push outer vlan (s-vlan) for upstream
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.in_port(onu_port))
+        match.oxm_list.append(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | c_vlan_id))
+        match.oxm_list.append(ofp.oxm.vlan_pcp( 0 ))
+
+        request = ofp.message.flow_add(
+            table_id=test_param_get("table", 1),
+            cookie=43,
+            match=match,
+            instructions=[
+                ofp.instruction.apply_actions(
+                    actions=[
+                        ofp.action.push_vlan(ethertype=0x8100),
+                        ofp.action.set_field(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | s_vlan_id)),
+                        ofp.action.set_field(ofp.oxm.vlan_pcp(0)),
+                        ofp.action.output(port=olt_port)]),
+                ],
+            buffer_id=ofp.OFP_NO_BUFFER,
+            priority=1000)
+
+        self.controller.message_send(request)
+        do_barrier(self.controller)
+        verify_no_errors(self.controller)
+
+	# strip outer vlan (s-vlan) for downstream
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.in_port(olt_port))
+        match.oxm_list.append(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | s_vlan_id))
+        match.oxm_list.append(ofp.oxm.vlan_pcp( 0 ))
+        request = ofp.message.flow_add(
+            table_id=test_param_get("table", 0),
+            cookie=44,
+            match=match,
+            instructions=[
+                ofp.instruction.apply_actions(
+                    actions=[ ofp.action.pop_vlan() ] ),
+		ofp.instruction.goto_table(1) ],
+            buffer_id=ofp.OFP_NO_BUFFER,
+            priority=1000)
+
+        self.controller.message_send(request)
+        do_barrier(self.controller)
+        verify_no_errors(self.controller)
+ 
+	# strip inner vlan (c-vlan) for downstream
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.in_port(olt_port))
+        match.oxm_list.append(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | c_vlan_id))
+        match.oxm_list.append(ofp.oxm.vlan_pcp( 0 ))
+
+        request = ofp.message.flow_add(
+            table_id=test_param_get("table", 1),
+            cookie=45,
+            match=match,
+            instructions=[
+                ofp.instruction.apply_actions(
+                    actions=[
+                        ofp.action.pop_vlan(),
+                        ofp.action.output(port=onu_port) ] )
+                ],
+            buffer_id=ofp.OFP_NO_BUFFER,
+            priority=1000)
+
+        self.controller.message_send(request)
+        do_barrier(self.controller)
+        verify_no_errors(self.controller)
+        # It takes some time for flows to propagate down to the data plane
+        time.sleep(10)
+        untaggedPkt = simple_udp_packet(pktlen=100, dl_vlan_enable=True, vlan_vid=0, vlan_pcp=0)
+        doubleTaggedPkt = double_vlan_udp_packet(pktlen=104, dl_vlan_enable=True, 
+						 c_vlan_vid=c_vlan_id, 
+						 s_vlan_vid=s_vlan_id, 
+						 c_vlan_pcp=0, s_vlan_pcp=0)
+        # test upstream untagged packet got double tag at OLT
+	logging.info(str(doubleTaggedPkt))
+        self.dataplane.send(onu_port, str(untaggedPkt))
+        verify_packet(self, doubleTaggedPkt, olt_port)
+        # test downstream doubletagged packet got untagged at ONU
+        self.dataplane.send(olt_port, str(doubleTaggedPkt))
+        verify_packet(self, untaggedPkt, onu_port)
+        # test upstream doubletagged packet got dropped 
+        self.dataplane.send(onu_port, str(doubleTaggedPkt))
+        verify_packets(self, untaggedPkt, [])
+        # test downstream untagged packet got dropped at ONU
+        self.dataplane.send(olt_port, str(untaggedPkt))
+        verify_packet(self, doubleTaggedPkt, [])
+        
+
+        # clean up the test
+        delete_all_flows(self.controller)
+        do_barrier(self.controller)
+        verify_no_errors(self.controller)