pyloxi: support OXM member in set-field actions

The C backend needs more work to support of_oxm_t, so I've added a hack so it
can keep using of_octets_t.

Also added several set-field action testcases.
diff --git a/py_gen/oftype.py b/py_gen/oftype.py
index cf87ded..67af1e7 100644
--- a/py_gen/oftype.py
+++ b/py_gen/oftype.py
@@ -99,6 +99,11 @@
         pack='util.pack_list(%s)',
         unpack='oxm.unpack_list(%s.slice(_length-4))'),
 
+    'of_oxm_t': OFTypeData(
+        init='None',
+        pack='%s.pack()',
+        unpack='oxm.unpack(%s)'),
+
     # TODO implement unpack
     'list(of_table_features_t)': OFTypeData(
         init='[]',
diff --git a/py_gen/templates/_pack.py b/py_gen/templates/_pack.py
index 4714e97..b6e8ef7 100644
--- a/py_gen/templates/_pack.py
+++ b/py_gen/templates/_pack.py
@@ -56,6 +56,11 @@
 :: #endfor
 :: if length_member_index != None:
         length = sum([len(x) for x in packed])
+:: if ofclass.name == 'of_action_set_field':
+        pad_len = (length + 7)/8*8 - length
+        length += pad_len
+        packed.append('\x00' * pad_len)
+:: #endif
         packed[${length_member_index}] = ${gen_pack_expr(length_member.oftype, 'length')}
 :: #endif
 :: if ofclass.name == 'of_match_v3':
diff --git a/py_gen/templates/action.py b/py_gen/templates/action.py
index dccb46e..fba5294 100644
--- a/py_gen/templates/action.py
+++ b/py_gen/templates/action.py
@@ -37,6 +37,9 @@
 import util
 import loxi.generic_util
 import loxi
+:: if version >= 3:
+import oxm # for unpack
+:: #endif
 
 def unpack_list(reader):
     def deserializer(reader, typ):
diff --git a/py_gen/templates/oxm.py b/py_gen/templates/oxm.py
index d95dd8e..792c277 100644
--- a/py_gen/templates/oxm.py
+++ b/py_gen/templates/oxm.py
@@ -38,15 +38,16 @@
 import loxi.generic_util
 import loxi
 
+def unpack(reader):
+    type_len, = reader.peek('!L')
+    if type_len in parsers:
+        return parsers[type_len](reader)
+    else:
+        raise loxi.ProtocolError("unknown OXM cls=%#x type=%#x masked=%d len=%d (%#x)" % \
+            ((type_len >> 16) & 0xffff, (type_len >> 9) & 0x7f, (type_len >> 8) & 1, type_len & 0xff, type_len))
+
 def unpack_list(reader):
-    def deserializer(reader):
-        type_len, = reader.peek('!L')
-        if type_len in parsers:
-            return parsers[type_len](reader)
-        else:
-            raise loxi.ProtocolError("unknown OXM cls=%#x type=%#x masked=%d len=%d (%#x)" % \
-                ((type_len >> 16) & 0xffff, (type_len >> 9) & 0x7f, (type_len >> 8) & 1, type_len & 0xff, type_len))
-    return loxi.generic_util.unpack_list(reader, deserializer)
+    return loxi.generic_util.unpack_list(reader, unpack)
 
 class OXM(object):
     type_len = None # override in subclass
diff --git a/py_gen/tests/of12.py b/py_gen/tests/of12.py
index c6c94ab..98d999b 100644
--- a/py_gen/tests/of12.py
+++ b/py_gen/tests/of12.py
@@ -78,7 +78,9 @@
         self.klasses.sort(key=lambda x: str(x))
 
     def test_serialization(self):
-        expected_failures = []
+        expected_failures = [
+            ofp.action.set_field, # field defaults to None
+        ]
         for klass in self.klasses:
             def fn():
                 obj = klass()
diff --git a/py_gen/tests/of13.py b/py_gen/tests/of13.py
index 349881f..8c18f41 100644
--- a/py_gen/tests/of13.py
+++ b/py_gen/tests/of13.py
@@ -93,6 +93,7 @@
 
     def test_serialization(self):
         expected_failures = [
+            ofp.action.set_field, # field defaults to None
             ofp.common.table_feature_prop_apply_actions,
             ofp.common.table_feature_prop_apply_actions_miss,
             ofp.common.table_feature_prop_write_actions,