diff --git a/src/main/java/org/openflow/protocol/action/OFActionType.java b/src/main/java/org/openflow/protocol/action/OFActionType.java
index b0c2c47d9af7b3181539f9f7a9174bf709a96bc4..18229170b77dc1a01984cfc9f156272f5ad858c5 100644
--- a/src/main/java/org/openflow/protocol/action/OFActionType.java
+++ b/src/main/java/org/openflow/protocol/action/OFActionType.java
@@ -1,7 +1,7 @@
 /**
 *    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
 *    University
-* 
+*
 *    Licensed under the Apache License, Version 2.0 (the "License"); you may
 *    not use this file except in compliance with the License. You may obtain
 *    a copy of the License at
@@ -94,7 +94,7 @@ public enum OFActionType {
     VENDOR              (0xffff, OFActionVendor.class, new Instantiable<OFAction>() {
                             @Override
                             public OFAction instantiate() {
-                                return new OFActionVendor();
+                                return new OFActionVendorGeneric();
                             }});
 
     protected static OFActionType[] mapping;
diff --git a/src/main/java/org/openflow/protocol/action/OFActionVendor.java b/src/main/java/org/openflow/protocol/action/OFActionVendor.java
index b5a15c280cd5342cd28171f378f0afa212a1d3f3..c8f3cd1ec94e84a31948c9bac0af305b5c0d7763 100644
--- a/src/main/java/org/openflow/protocol/action/OFActionVendor.java
+++ b/src/main/java/org/openflow/protocol/action/OFActionVendor.java
@@ -1,7 +1,7 @@
 /**
 *    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
 *    University
-* 
+*
 *    Licensed under the Apache License, Version 2.0 (the "License"); you may
 *    not use this file except in compliance with the License. You may obtain
 *    a copy of the License at
@@ -24,7 +24,7 @@ import org.jboss.netty.buffer.ChannelBuffer;
  *
  * @author David Erickson (daviderickson@cs.stanford.edu)
  */
-public class OFActionVendor extends OFAction {
+public abstract class OFActionVendor extends OFAction {
     public static int MINIMUM_LENGTH = 8;
 
     protected int vendor;
diff --git a/src/main/java/org/openflow/protocol/action/OFActionVendorGeneric.java b/src/main/java/org/openflow/protocol/action/OFActionVendorGeneric.java
new file mode 100644
index 0000000000000000000000000000000000000000..4f7859f5ec43e8e13ff8340c50f5cda6f2d2311c
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/action/OFActionVendorGeneric.java
@@ -0,0 +1,96 @@
+/**
+*    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
+*    University
+*
+*    Licensed under the Apache License, Version 2.0 (the "License"); you may
+*    not use this file except in compliance with the License. You may obtain
+*    a copy of the License at
+*
+*         http://www.apache.org/licenses/LICENSE-2.0
+*
+*    Unless required by applicable law or agreed to in writing, software
+*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+*    License for the specific language governing permissions and limitations
+*    under the License.
+**/
+
+package org.openflow.protocol.action;
+
+
+import java.util.Arrays;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+/** A generic / unparsed vendor action. This action is returned by
+ *  BasicFactory.readFromWire if no more specific OFVendorActionFactory
+ *  is registered.
+ *
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+ */
+public class OFActionVendorGeneric extends OFActionVendor {
+    public static int MINIMUM_LENGTH = 8;
+
+    private final static byte[] EMPTY_ARRAY = new byte[0];
+
+    protected byte[] vendorData;
+
+    public OFActionVendorGeneric() {
+        super();
+    }
+
+    public byte[] getVendorData() {
+        return vendorData;
+    }
+
+    public void setVendorData(byte[] vendorData) {
+        this.vendorData = vendorData;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+
+        int vendorDataLength = this.getLength() - MINIMUM_LENGTH;
+        if (vendorDataLength > 0) {
+            vendorData = new byte[vendorDataLength];
+            data.readBytes(vendorData);
+        } else {
+            vendorData = EMPTY_ARRAY;
+        }
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeInt(this.vendor);
+        data.writeBytes(vendorData);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 379;
+        int result = super.hashCode();
+        result = prime * result + Arrays.hashCode(vendorData);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!(obj instanceof OFActionVendorGeneric)) {
+            return false;
+        }
+        OFActionVendorGeneric other = (OFActionVendorGeneric) obj;
+        if (!Arrays.equals(vendorData, other.vendorData)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/factory/BasicFactory.java b/src/main/java/org/openflow/protocol/factory/BasicFactory.java
index 7b06f2c0c91a5a8a966be3430d34f4dbbb9f23cc..c4d148337526ecbae5ea8d9aa67d89e657404da7 100644
--- a/src/main/java/org/openflow/protocol/factory/BasicFactory.java
+++ b/src/main/java/org/openflow/protocol/factory/BasicFactory.java
@@ -1,7 +1,7 @@
 /**
 *    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
 *    University
-* 
+*
 *    Licensed under the Apache License, Version 2.0 (the "License"); you may
 *    not use this file except in compliance with the License. You may obtain
 *    a copy of the License at
@@ -25,6 +25,7 @@ import org.openflow.protocol.OFMessage;
 import org.openflow.protocol.OFType;
 import org.openflow.protocol.action.OFAction;
 import org.openflow.protocol.action.OFActionType;
+import org.openflow.protocol.action.OFActionVendor;
 import org.openflow.protocol.statistics.OFStatistics;
 import org.openflow.protocol.statistics.OFStatisticsType;
 import org.openflow.protocol.statistics.OFVendorStatistics;
@@ -45,6 +46,12 @@ import org.openflow.protocol.vendor.OFVendorId;
 public class BasicFactory implements OFMessageFactory, OFActionFactory,
         OFStatisticsFactory, OFVendorDataFactory {
 
+    private final OFVendorActionRegistry vendorActionRegistry;
+
+    public BasicFactory() {
+        vendorActionRegistry = OFVendorActionRegistry.getInstance();
+    }
+
     /**
      * create and return a new instance of a message for OFType t. Also injects
      * factories for those message types that implement the *FactoryAware
@@ -169,19 +176,42 @@ public class BasicFactory implements OFMessageFactory, OFActionFactory,
                 (data.readerIndex() + demux.getLengthU()) > end))
                 return results;
 
-            ofa = getAction(demux.getType());
-            ofa.readFrom(data);
-            if (OFAction.class.equals(ofa.getClass())) {
-                // advance the position for un-implemented messages
-                data.readerIndex(data.readerIndex()+(ofa.getLengthU() -
-                        OFAction.MINIMUM_LENGTH));
-            }
+            ofa = parseActionOne(demux.getType(), data);
             results.add(ofa);
         }
 
         return results;
     }
 
+    private OFAction parseActionOne(OFActionType type, ChannelBuffer data) {
+        OFAction ofa;
+        data.markReaderIndex();
+        ofa = getAction(type);
+        ofa.readFrom(data);
+
+        if(type == OFActionType.VENDOR) {
+            OFActionVendor vendorAction = (OFActionVendor) ofa;
+
+            OFVendorActionFactory vendorActionFactory = vendorActionRegistry.get(vendorAction.getVendor());
+
+            if(vendorActionFactory != null) {
+                // if we have a specific vendorActionFactory for this vendor id,
+                // delegate to it for vendor-specific reparsing of the message
+                data.resetReaderIndex();
+                OFActionVendor newAction = vendorActionFactory.readFrom(data);
+                if(newAction != null)
+                    ofa = newAction;
+            }
+        }
+
+        if (OFAction.class.equals(ofa.getClass())) {
+            // advance the position for un-implemented messages
+            data.readerIndex(data.readerIndex()+(ofa.getLengthU() -
+                    OFAction.MINIMUM_LENGTH));
+        }
+        return ofa;
+    }
+
     @Override
     public OFActionFactory getActionFactory() {
         return this;
diff --git a/src/main/java/org/openflow/protocol/factory/OFVendorActionFactory.java b/src/main/java/org/openflow/protocol/factory/OFVendorActionFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..ea27b6119820c834a00b5723f8c73efd910fbefc
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/factory/OFVendorActionFactory.java
@@ -0,0 +1,27 @@
+package org.openflow.protocol.factory;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.action.OFActionVendor;
+
+/** Interface contract for an actionfactory that creates vendor-specific actions.
+ *  VendorActionFactories are registered with the BasicFactory for a specific
+ *  vendor id.
+ *  <p>
+ *  <b>Note:</b> Implementations are expected to be thread-safe.
+ *
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+ */
+public interface OFVendorActionFactory {
+
+    /** parse the data from the wire, create and return a vendor-specific action.
+     *
+     * @param data contains a serialized vendor action at the current readerPosition.
+     *    The full message is guaranteed to be available in the buffer.
+     *
+     * @return upon success returns a newly allocated vendor-specific
+     *   action instance, and advances the readerPosition in data for the
+     *   entire length. Upon failure, returns null and leaves the readerPosition
+     *   in data unmodified.
+     */
+    OFActionVendor readFrom(ChannelBuffer data);
+}
diff --git a/src/main/java/org/openflow/protocol/factory/OFVendorActionRegistry.java b/src/main/java/org/openflow/protocol/factory/OFVendorActionRegistry.java
new file mode 100644
index 0000000000000000000000000000000000000000..190bdd4fd42f7bf4ef58dc88a9ea52399eb5a512
--- /dev/null
+++ b/src/main/java/org/openflow/protocol/factory/OFVendorActionRegistry.java
@@ -0,0 +1,34 @@
+package org.openflow.protocol.factory;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/** Singleton registry object that holds a mapping from vendor ids to vendor-specific
+ *  mapping factories. Threadsafe.
+ *
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+ */
+public class OFVendorActionRegistry {
+    private static class InstanceHolder {
+        private final static OFVendorActionRegistry instance = new OFVendorActionRegistry();
+    }
+
+    public static OFVendorActionRegistry getInstance() {
+        return InstanceHolder.instance;
+    }
+    private final Map <Integer, OFVendorActionFactory> vendorActionFactories;
+
+    public OFVendorActionRegistry() {
+        vendorActionFactories = new ConcurrentHashMap<Integer, OFVendorActionFactory>();
+    }
+
+    public OFVendorActionFactory register(int vendorId, OFVendorActionFactory factory) {
+        return vendorActionFactories.put(vendorId, factory);
+    }
+
+    public OFVendorActionFactory get(int vendorId) {
+        return vendorActionFactories.get(vendorId);
+    }
+
+
+}
diff --git a/src/test/java/org/openflow/protocol/BasicFactoryTest.java b/src/test/java/org/openflow/protocol/BasicFactoryTest.java
index 6825008d98b0f9c0134b77a3f13dc39b54911fd7..312fcd3f57d616c6716e7f702e56a086a44609d0 100644
--- a/src/test/java/org/openflow/protocol/BasicFactoryTest.java
+++ b/src/test/java/org/openflow/protocol/BasicFactoryTest.java
@@ -1,7 +1,7 @@
 /**
 *    Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior
 *    University
-* 
+*
 *    Licensed under the Apache License, Version 2.0 (the "License"); you may
 *    not use this file except in compliance with the License. You may obtain
 *    a copy of the License at
@@ -17,16 +17,23 @@
 
 package org.openflow.protocol;
 
+import static org.junit.Assert.assertArrayEquals;
+
 import java.util.List;
 
+import junit.framework.TestCase;
+
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.jboss.netty.buffer.ChannelBuffers;
+import org.openflow.protocol.action.MockVendorAction;
+import org.openflow.protocol.action.MockVendorActionFactory;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.action.OFActionVendorGeneric;
 import org.openflow.protocol.factory.BasicFactory;
 import org.openflow.protocol.factory.MessageParseException;
+import org.openflow.protocol.factory.OFVendorActionRegistry;
 import org.openflow.util.U16;
 
-import junit.framework.TestCase;
-
 public class BasicFactoryTest extends TestCase {
 
     public void testCreateAndParse() throws MessageParseException {
@@ -78,4 +85,50 @@ public class BasicFactoryTest extends TestCase {
         }
     }
 
+    public void testCustomVendorAction() throws MessageParseException {
+        BasicFactory factory = new BasicFactory();
+        OFVendorActionRegistry.getInstance().register(
+                MockVendorAction.VENDOR_ID, new MockVendorActionFactory());
+
+
+        byte[] deadBeefMessage = {
+            (byte) 0xff, (byte) 0xff,          // action vendor
+            0x00, 0x10,                        // length
+            (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte)0xef,            // deadbeaf
+            0x01, 0x02, 0x03, 0x04,
+            0x05, 0x06, 0x07, 0x08               // pad
+        };
+
+        ChannelBuffer buf = ChannelBuffers.copiedBuffer(deadBeefMessage);
+
+        List<OFAction> actions = factory.parseActions(buf,deadBeefMessage.length);
+        assertEquals(1, actions.size());
+        OFAction ofAction = actions.get(0);
+        assertTrue("Action should be MockVendorAction, but is "+ofAction.getClass(), ofAction instanceof MockVendorAction);
+        assertArrayEquals( new byte[]  { 1,2,3,4,5,6,7,8}, ((MockVendorAction)ofAction).getMockData());
+
+
+    }
+
+    public void testGenericVendorAction() throws MessageParseException {
+        byte[] nonDeadBeefMessage = {
+                (byte) 0xff, (byte) 0xff,          // action vendor
+                0x00, 0x10,                        // length
+                (byte) 0x7e, (byte) 0xe7, (byte) 0xbe, (byte)0xef,            // deadbeaf
+                0x01, 0x02, 0x03, 0x04,
+                0x05, 0x06, 0x07, 0x08               // pad
+            };
+
+        BasicFactory factory = new BasicFactory();
+        OFVendorActionRegistry.getInstance().register(
+                MockVendorAction.VENDOR_ID, new MockVendorActionFactory());
+
+        ChannelBuffer buf = ChannelBuffers.copiedBuffer(nonDeadBeefMessage);
+
+        List<OFAction> actions = factory.parseActions(buf,nonDeadBeefMessage.length);
+        assertEquals(1, actions.size());
+        OFAction ofAction = actions.get(0);
+        assertTrue("Action should be OFActionVendorGeneric, but is "+ofAction.getClass(), ofAction instanceof OFActionVendorGeneric);
+    }
+
 }
diff --git a/src/test/java/org/openflow/protocol/action/MockVendorAction.java b/src/test/java/org/openflow/protocol/action/MockVendorAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..49b69fb8181d4a6dd6959a40786d643fe05ead20
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/action/MockVendorAction.java
@@ -0,0 +1,41 @@
+package org.openflow.protocol.action;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+
+public class MockVendorAction extends OFActionVendor {
+    public static final int VENDOR_ID = 0xdeadbeef;
+
+    private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
+    private byte[] mockData;
+
+    public byte[] getMockData() {
+        return mockData;
+    }
+
+    public void setMockData(byte[] mockData) {
+        this.mockData = mockData;
+    }
+
+    @Override
+    public void readFrom(ChannelBuffer data) {
+        super.readFrom(data);
+
+        int dataLength = getLength() - MINIMUM_LENGTH;
+        if(dataLength > 0) {
+            mockData = new byte[dataLength];
+            data.readBytes(mockData);
+        } else {
+            mockData = EMPTY_BYTE_ARRAY;
+        }
+
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer data) {
+        super.writeTo(data);
+        data.writeBytes(mockData);
+    }
+
+
+}
diff --git a/src/test/java/org/openflow/protocol/action/MockVendorActionFactory.java b/src/test/java/org/openflow/protocol/action/MockVendorActionFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..bbc254ca0074cc9e418c5541f976d000074cf0b1
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/action/MockVendorActionFactory.java
@@ -0,0 +1,15 @@
+package org.openflow.protocol.action;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.factory.OFVendorActionFactory;
+
+public class MockVendorActionFactory implements OFVendorActionFactory {
+
+    @Override
+    public OFActionVendor readFrom(ChannelBuffer data) {
+        MockVendorAction action = new MockVendorAction();
+        action.readFrom(data);
+        return action;
+    }
+
+}
diff --git a/src/test/java/org/openflow/protocol/action/OFVendorActionRegistryTest.java b/src/test/java/org/openflow/protocol/action/OFVendorActionRegistryTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..31ad675d6a0a708c5a69a7ae3b0dcb21bc24e5c5
--- /dev/null
+++ b/src/test/java/org/openflow/protocol/action/OFVendorActionRegistryTest.java
@@ -0,0 +1,17 @@
+package org.openflow.protocol.action;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.openflow.protocol.factory.OFVendorActionRegistry;
+
+public class OFVendorActionRegistryTest {
+
+    @Test
+    public void test() {
+        MockVendorActionFactory factory = new MockVendorActionFactory();
+        OFVendorActionRegistry.getInstance().register(MockVendorAction.VENDOR_ID, factory);
+        assertEquals(factory, OFVendorActionRegistry.getInstance().get(MockVendorAction.VENDOR_ID));
+    }
+
+}