add group decorator and smoke test group

The smoke group is intended to be very fast while covering most important
features.
diff --git a/src/python/oftest/testutils.py b/src/python/oftest/testutils.py
index fef34f4..fe53ecc 100644
--- a/src/python/oftest/testutils.py
+++ b/src/python/oftest/testutils.py
@@ -1044,3 +1044,14 @@
     """
     cls._disabled = True
     return cls
+
+def group(name):
+    """
+    Testcase decorator that adds the test to a group.
+    """
+    def fn(cls):
+        if not hasattr(cls, "_groups"):
+            cls._groups = []
+        cls._groups.append(name)
+        return cls
+    return fn
diff --git a/tests/basic.py b/tests/basic.py
index 6ca8b18..d78f2ff 100644
--- a/tests/basic.py
+++ b/tests/basic.py
@@ -33,6 +33,7 @@
 
 TEST_VID_DEFAULT = 2
 
+@group('smoke')
 class Echo(base_tests.SimpleProtocol):
     """
     Test echo response with no data
@@ -65,6 +66,7 @@
         self.assertEqual(request.data, response.data,
                          'response data does not match request')
 
+@group('smoke')
 class PacketIn(base_tests.SimpleDataPlane):
     """
     Test packet in function
@@ -180,6 +182,7 @@
         self.assertTrue(pkt_in is None,
                         'BCast packet received on port ' + str(of_port))
 
+@group('smoke')
 class PacketOut(base_tests.SimpleDataPlane):
     """
     Test packet out function
@@ -353,6 +356,7 @@
         rv = self.controller.message_send(request)
         self.assertTrue(rv != -1, "Error installing flow mod")
 
+@group('smoke')
 class PortConfigMod(base_tests.SimpleProtocol):
     """
     Modify a bit in port config and verify changed
@@ -432,6 +436,7 @@
 
         self.assertTrue(response is not None, 'Did not receive error message')
 
+@group('smoke')
 class BadMessage(base_tests.SimpleProtocol):
     """
     Send a message with a bad type and verify an error is returned
diff --git a/tests/message_types.py b/tests/message_types.py
index c13bfae..d0e6822 100644
--- a/tests/message_types.py
+++ b/tests/message_types.py
@@ -114,6 +114,7 @@
                                'Message field code is not OFPBRC_BAD_VERSION')
 
 
+@group('smoke')
 class FeaturesReplyBody(base_tests.SimpleProtocol):
     """Verify the body of Features Reply message"""
 
diff --git a/tests/pktact.py b/tests/pktact.py
index 0b04c56..0165597 100644
--- a/tests/pktact.py
+++ b/tests/pktact.py
@@ -78,6 +78,7 @@
 
 TEST_VID_DEFAULT = 2
 
+@group('smoke')
 class DirectPacket(base_tests.SimpleDataPlane):
     """
     Send packet to single egress port
@@ -148,6 +149,7 @@
             self.assertEqual(str(pkt), str(rcv_pkt),
                              'Response packet does not match send packet')
 
+@group('smoke')
 class DirectPacketController(base_tests.SimpleDataPlane):
     """
     Send packet to the controller port
@@ -1136,6 +1138,7 @@
         self.verifyFlow(of_ports[0], of_ports[2])
         
 
+@group("smoke")
 class WildcardPriorityWithDelete(SingleWildcardMatchPriority):
     """
     1. Add wildcard match flow, verify packet received.
@@ -1269,7 +1272,7 @@
         flow_match_test(self, config["port_map"], wildcards=ofp.OFPFW_ALL, 
                         dl_vlan=vid)
 
-    
+@group('smoke')
 class AddVLANTag(BaseMatchCase):
     """
     Add a VLAN tag to an untagged packet
@@ -1720,6 +1723,7 @@
         flow_match_test(self, config["port_map"], pkt=pkt, exp_pkt=exp_pkt, 
                         action_list=acts, max_test=2, egr_count=-1)
 
+@group("smoke")
 class ModifyAll(BaseMatchCase):
     """
     Modify all supported fields and output to a port
@@ -1931,6 +1935,7 @@
     If only VID 5 distinguishes pkt, this will fail on some platforms
     """   
 
+@group('smoke')
 class MatchEach(base_tests.SimpleDataPlane):
     """
     Check that each match field is actually matched on.
diff --git a/tests/port_stats.py b/tests/port_stats.py
index 89b2cf6..8d39d6f 100644
--- a/tests/port_stats.py
+++ b/tests/port_stats.py
@@ -129,6 +129,7 @@
     obj.assertTrue(all_packets_received,
                    "Packet received does not match number sent")
 
+@group('smoke')
 class SingleFlowStats(base_tests.SimpleDataPlane):
     """
     Verify flow stats are properly retrieved.