Add in group tests
diff --git a/olt.py b/olt.py
index 0db8111..b2ea421 100644
--- a/olt.py
+++ b/olt.py
@@ -80,7 +80,7 @@
         logging.info("Running DHCP Packet In test")
 
         pkt = simple_udp_packet(udp_sport=68, udp_dport=67)
-        
+
         match = ofp.match()
         match.oxm_list.append(ofp.oxm.eth_type(0x0800))
         match.oxm_list.append(ofp.oxm.ip_proto(17))
@@ -91,7 +91,7 @@
         
         # Other UDP packets should not match the rule
         radiusPkt = simple_udp_packet(udp_sport=1812, udp_dport=1812)
-        
+
         self.dataplane.send(1, str(radiusPkt))
         verify_no_packet_in(self, radiusPkt, 1)    
         
@@ -125,9 +125,31 @@
 
         verify_no_errors(self.controller)
 
+	vlan_id = 201
         match = ofp.match()
         match.oxm_list.append(ofp.oxm.in_port(onu_port))
-        match.oxm_list.append(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | 201))
+        match.oxm_list.append(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | vlan_id ))
+
+        request = ofp.message.flow_add(
+            table_id=test_param_get("table", 0),
+            cookie=42,
+            match=match,
+            instructions=[
+                ofp.instruction.apply_actions(
+                    actions=[
+                        ofp.action.output(port=olt_port)]),
+                ofp.instruction.meter(meter_id = 1)    
+                ],
+            buffer_id=ofp.OFP_NO_BUFFER,
+            priority=1000)
+
+        self.controller.message_send(request)
+        time.sleep(1)
+        verify_no_errors(self.controller)
+ 
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.in_port(olt_port))
+        match.oxm_list.append(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | vlan_id))
 
         request = ofp.message.flow_add(
             table_id=test_param_get("table", 0),
@@ -136,18 +158,34 @@
             instructions=[
                 ofp.instruction.apply_actions(
                     actions=[
-                        ofp.action.output(port=olt_port)]),
+                        ofp.action.output(port=onu_port)]),
                     ofp.instruction.meter(meter_id = 1)    
                 ],
             buffer_id=ofp.OFP_NO_BUFFER,
             priority=1000)
 
         self.controller.message_send(request)
-        
         time.sleep(1)
-
         verify_no_errors(self.controller)
+        do_barrier(self.controller)
+        time.sleep(5)
         
+	inPkt = simple_udp_packet(dl_vlan_enable=True, vlan_vid=vlan_id, vlan_pcp=0)
+	# downstream
+        self.dataplane.send(olt_port, str(inPkt))
+        verify_packet(self, inPkt, onu_port)
+        # upstream
+        self.dataplane.send(olt_port, str(inPkt))
+        verify_packet(self, inPkt, onu_port)
+
+	# clean up the test
+        meter_mod = ofp.message.meter_mod(xid = 2, command = ofp.OFPMC_DELETE, meter_id = 1)
+        self.controller.message_send(meter_mod)
+        time.sleep(1)
+        delete_all_flows(self.controller)
+        verify_no_errors(self.controller)
+
+ 
 class TestDuplicateMeter(base_tests.SimpleDataPlane):
 
     def runTest(self):
@@ -200,7 +238,7 @@
         logging.info("Inserting flow tagging upstream")
         self.controller.message_send(request)
 
-   	    #POP
+        #POP
         match = ofp.match()
         match.oxm_list.append(ofp.oxm.in_port(olt_port))
         match.oxm_list.append(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | vlan_id))
@@ -211,9 +249,9 @@
             match=match,
             instructions=[
                 ofp.instruction.apply_actions(
-                    actions=[
-                        ofp.action.pop_vlan(),
-                        ofp.action.output(port=1)])],
+       		    actions=[
+			ofp.action.pop_vlan(),
+			ofp.action.output(port=1)])], 
             buffer_id=ofp.OFP_NO_BUFFER,
             priority=1000)
 
@@ -246,3 +284,331 @@
         self.dataplane.send(onu_port, str(inPkt))
         verify_packets(self, outPkt, [])
         
+class TestGroupAdd(base_tests.SimpleDataPlane):
+       
+    def runTest(self):
+        logging.info("Running Group tests")
+        delete_all_flows(self.controller)
+
+	test_group_id = 1 
+	onu_port1 = 130
+	onu_port2 = 131
+	# output to two ONU
+	bucket = ofp.common.bucket(actions=[ofp.action.output(port=onu_port1), ofp.action.output(port=onu_port2)]) 
+        group_add = ofp.message.group_add(xid = 1, group_type = ofp.OFPGT_ALL, group_id = test_group_id, buckets = [ bucket ])
+
+        self.controller.message_send(group_add)
+        time.sleep(1)
+        verify_no_errors(self.controller)
+
+        # Remove the group and then readd it.
+        group_delete = ofp.message.group_delete(xid = 2, group_id = test_group_id)
+        self.controller.message_send(group_delete)
+	time.sleep(1)
+        verify_no_errors(self.controller)
+
+	group_add = ofp.message.group_add(xid = 1, group_type = ofp.OFPGT_ALL, group_id = test_group_id, buckets = [ bucket ])
+        self.controller.message_send(group_add)
+        time.sleep(1)
+        verify_no_errors(self.controller)
+
+
+	# clean up the test
+        group_delete = ofp.message.group_delete(xid = 2, group_id = test_group_id)
+        self.controller.message_send(group_delete)
+        
+	time.sleep(1)
+        verify_no_errors(self.controller)
+        
+class TestGroupMod(base_tests.SimpleDataPlane):
+       
+    def runTest(self):
+        logging.info("Running Group tests")
+        delete_all_flows(self.controller)
+
+	test_group_id = 1 
+	onu_port1 = 130
+	onu_port2 = 131
+	bucket = ofp.common.bucket(actions=[ofp.action.output(port=onu_port1)]) 
+        group_add = ofp.message.group_add(xid = 1, group_type = ofp.OFPGT_ALL, group_id = test_group_id, buckets = [ bucket ])
+
+        self.controller.message_send(group_add)
+        time.sleep(1)
+        verify_no_errors(self.controller)
+	
+	# Modifying the group
+	bucket = ofp.common.bucket(actions=[ofp.action.output(port=onu_port2)]) 
+	group_mod = ofp.message.group_mod(xid = 2, command = 1, group_type = ofp.OFPGT_ALL, group_id = test_group_id, buckets = [ bucket ])
+
+	self.controller.message_send(group_mod)
+        time.sleep(1)
+        verify_no_errors(self.controller)
+
+	# Add a bucket into the group
+	bucket2 = ofp.common.bucket(actions=[ofp.action.output(port=onu_port1)]) 
+	group_mod = ofp.message.group_mod(xid = 2, command = 1, group_type = ofp.OFPGT_ALL, group_id = test_group_id, buckets = [ bucket, bucket2 ])
+	self.controller.message_send(group_mod)
+        time.sleep(1)
+        verify_no_errors(self.controller)
+
+        # Modifying a non-existing group
+	bucket = ofp.common.bucket(actions=[ofp.action.output(port=onu_port2)]) 
+	group_mod = ofp.message.group_mod(xid = 3, command = 1, group_type = ofp.OFPGT_ALL, group_id = 777, buckets = [ bucket ])
+
+	self.controller.message_send(group_mod)
+        time.sleep(10)
+	errorExperienced = 0
+        try:
+            verify_no_errors(self.controller)
+        except AssertionError as e:
+	    errorExperienced = 1
+            if (not (e.message == "unexpected error type=6 code=8")):
+               raise AssertionError("Incorrect error type: %s" % e.message)
+	if not errorExperienced: 
+           raise AssertionError("An error message is expected, but not shown.")
+	  
+ 
+	# clean up the test
+        group_delete = ofp.message.group_delete(xid = 2, group_id = test_group_id)
+        self.controller.message_send(group_delete)
+        
+	time.sleep(1)
+        verify_no_errors(self.controller)
+
+class TestDuplicateGroup(base_tests.SimpleDataPlane):
+       
+    def runTest(self):
+        logging.info("Running Group tests")
+        delete_all_flows(self.controller)
+
+	test_group_id = 1 
+	bucket = ofp.common.bucket(actions=[ofp.action.output(port=onu_port)]) 
+        group_add = ofp.message.group_add(xid = 1, group_type = ofp.OFPGT_ALL, group_id = test_group_id, buckets = [ bucket ])
+
+        self.controller.message_send(group_add)
+        time.sleep(1)
+        verify_no_errors(self.controller)
+	
+	# Add the same group id
+        duplicate_group_fail = 0 
+        group_add = ofp.message.group_add(xid = 1, group_type = ofp.OFPGT_ALL, group_id = test_group_id, buckets = [ bucket ])
+	
+        self.controller.message_send(group_add)
+        time.sleep(1)
+        try:
+            verify_no_errors(self.controller)
+        except AssertionError as e:
+            duplicate_group_fail = 1 
+            if (not e.message is "unexpected error type=12 code=1"):
+               raise AssertionError("Incorrect error type: %s" % e.message)
+      	if not duplicate_group_fail:
+           raise AssertionError("Adding duplicate groups didn't raise an error.")
+	        
+	# clean up the test
+        group_delete = ofp.message.group_delete(xid = 2, group_id = test_group_id)
+        self.controller.message_send(group_delete)
+        
+	time.sleep(1)
+        verify_no_errors(self.controller)
+
+class TestGroupAndFlow(base_tests.SimpleDataPlane):
+       
+    def runTest(self):
+        logging.info("Running Group tests")
+        delete_all_flows(self.controller)
+
+	# Create a group
+	test_group_id = 1 
+	bucket = ofp.common.bucket(actions=[ofp.action.output(port=onu_port)]) 
+        group_add = ofp.message.group_add(xid = 1, group_type = ofp.OFPGT_ALL, group_id = test_group_id, buckets = [ bucket ])
+
+        self.controller.message_send(group_add)
+        time.sleep(1)
+        verify_no_errors(self.controller)
+
+        # Create a flow rule matching olt port and vlan id
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.in_port(olt_port))
+        match.oxm_list.append(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | 201))
+
+        request = ofp.message.flow_add(
+            table_id=test_param_get("table", 0),
+            cookie=43,
+            match=match,
+            instructions=[
+                ofp.instruction.apply_actions(
+                    actions=[ ofp.action.group( group_id = test_group_id ) ] ) ],
+                    buffer_id=ofp.OFP_NO_BUFFER, priority=1000)
+
+        self.controller.message_send(request)
+	time.sleep(1)
+        verify_no_errors(self.controller)
+       
+	# After letting a flow rule point to the group, test we can do group_mod
+	onu_port2 = 131
+	bucket = ofp.common.bucket(actions=[ofp.action.output(port=onu_port2)]) 
+	group_mod = ofp.message.group_mod(xid = 2, command = 1, group_type = ofp.OFPGT_ALL, group_id = test_group_id, buckets = [ bucket ])
+	self.controller.message_send(group_mod)
+        time.sleep(1)
+        verify_no_errors(self.controller)
+
+        # Test we can remove flows and then remove group
+        request = ofp.message.flow_delete( table_id=test_param_get("table", 0))
+        self.controller.message_send(request)
+	time.sleep(1)
+        verify_no_errors(self.controller)
+
+        group_delete = ofp.message.group_delete(xid = 3, group_id = test_group_id)
+        self.controller.message_send(group_delete)
+	time.sleep(1)
+        verify_no_errors(self.controller)
+
+	# Add the group and flow back, test it we can first remove group and then remove the flow. 
+        group_add = ofp.message.group_add(xid = 1, group_type = ofp.OFPGT_ALL, group_id = test_group_id, buckets = [ bucket ])
+        self.controller.message_send(group_add)
+	request = ofp.message.flow_add(
+            table_id=test_param_get("table", 0),
+            cookie=43,
+            match=match,
+            instructions=[
+                ofp.instruction.apply_actions(
+                    actions=[ ofp.action.group( group_id = test_group_id ) ] ) ],
+                    buffer_id=ofp.OFP_NO_BUFFER, priority=1000)
+        self.controller.message_send(request)
+        verify_no_errors(self.controller)
+
+        group_delete = ofp.message.group_delete(xid = 4, group_id = test_group_id)
+        self.controller.message_send(group_delete)
+        request = ofp.message.flow_delete( table_id=test_param_get("table", 0))
+        self.controller.message_send(request)
+	time.sleep(1)
+        verify_no_errors(self.controller)
+
+
+class TestGroupForwarding(base_tests.SimpleDataPlane):
+       
+    def runTest(self):
+        logging.info("Running Group datapath forwarding tests")
+        delete_all_flows(self.controller)
+
+	vlan_id = 200
+
+	# Create a group
+	test_group_id = 1 
+	onu_port = 130
+	bucket = ofp.common.bucket(actions=[ofp.action.output(port=onu_port)]) 
+        group_add = ofp.message.group_add(xid = 1, group_type = ofp.OFPGT_ALL, group_id = test_group_id, buckets = [ bucket ])
+
+        self.controller.message_send(group_add)
+        time.sleep(1)
+        verify_no_errors(self.controller)
+
+        # Create a flow rule matching olt port and vlan id
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.in_port(olt_port))
+        match.oxm_list.append(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | vlan_id))
+
+        request = ofp.message.flow_add(
+            table_id=test_param_get("table", 0),
+            cookie=43,
+            match=match,
+            instructions=[
+                ofp.instruction.apply_actions(
+                    actions=[ ofp.action.group( group_id = test_group_id ) ] ), 
+		],
+                buffer_id=ofp.OFP_NO_BUFFER, priority=1000)
+
+        self.controller.message_send(request)
+	time.sleep(1)
+        verify_no_errors(self.controller)
+    	do_barrier(self.controller)
+	time.sleep(5)
+        
+        inPkt = simple_udp_packet(pktlen=104,dl_vlan_enable=True,
+                                  vlan_vid=vlan_id, vlan_pcp=0, dl_vlan_cfi=0)
+        outPkt = inPkt
+        self.dataplane.send(olt_port, str(inPkt))
+        verify_packet(self, outPkt, onu_port)
+        time.sleep(1)
+        verify_no_errors(self.controller)
+
+	#group_mod test
+	#bucket = ofp.common.bucket(actions=[ofp.action.output(port=onu_port), ofp.action.push_vlan(0x0081)]) 
+	#group_mod = ofp.message.group_mod(xid = 1, command = 1, group_type = ofp.OFPGT_ALL, group_id = 2, buckets = [ bucket ])
+
+	#self.controller.message_send(group_mod)
+        #time.sleep(1)
+        #verify_no_errors(self.controller)
+
+
+	# clean up the test
+        request = ofp.message.flow_delete( table_id=test_param_get("table", 0))
+        self.controller.message_send(request)
+        group_delete = ofp.message.group_delete(xid = 2, group_id = test_group_id)
+        self.controller.message_send(group_delete)
+        
+	time.sleep(1)
+        verify_no_errors(self.controller)
+
+class TransparentVlanTest(base_tests.SimpleDataPlane):
+       
+    def runTest(self):
+        logging.info("Running transparent vlan tests")
+
+	vlan_id = 201
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.in_port(onu_port))
+        match.oxm_list.append(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | vlan_id ))
+
+        request = ofp.message.flow_add(
+            table_id=test_param_get("table", 0),
+            cookie=42,
+            match=match,
+            instructions=[
+                ofp.instruction.apply_actions(
+                    actions=[
+                        ofp.action.output(port=olt_port)]),
+                ],
+            buffer_id=ofp.OFP_NO_BUFFER,
+            priority=1000)
+
+        self.controller.message_send(request)
+        time.sleep(1)
+        verify_no_errors(self.controller)
+ 
+        match = ofp.match()
+        match.oxm_list.append(ofp.oxm.in_port(olt_port))
+        match.oxm_list.append(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | vlan_id))
+
+        request = ofp.message.flow_add(
+            table_id=test_param_get("table", 0),
+            cookie=43,
+            match=match,
+            instructions=[
+                ofp.instruction.apply_actions(
+                    actions=[
+                        ofp.action.output(port=onu_port)]),
+                ],
+            buffer_id=ofp.OFP_NO_BUFFER,
+            priority=1000)
+
+        self.controller.message_send(request)
+        verify_no_errors(self.controller)
+    	do_barrier(self.controller)
+        time.sleep(5)
+        
+	inPkt = simple_udp_packet(dl_vlan_enable=True, vlan_vid=(vlan_id), vlan_pcp=0)
+	# downstream
+        self.dataplane.send(olt_port, str(inPkt))
+        verify_packet(self, inPkt, onu_port)
+        # upstream
+        self.dataplane.send(onu_port, str(inPkt))
+        verify_packet(self, inPkt, olt_port)
+        
+
+	# clean up the test
+        delete_all_flows(self.controller)
+        time.sleep(1)
+        verify_no_errors(self.controller)
+
+