Add multipart reply deserializers 56/50556/22
authorTomas Slusny <tomas.slusny@pantheon.tech>
Tue, 17 Jan 2017 15:07:05 +0000 (16:07 +0100)
committerTomas Slusny <tomas.slusny@pantheon.tech>
Wed, 15 Feb 2017 15:13:41 +0000 (16:13 +0100)
 - Add yang models for multipart reply
 - Add MultipartDeserializerInjector that will inject multipart reply
   deserializers to OpenflowJava
 - Add these mutlipart reply deserializers:
    * Flow aggregate stats
    * Flow stats
    * Flow table stats
    * Group desc
    * Group features
    * Group stats
    * Meter config
    * Meter features
    * Meter stats
    * Port stats
    * Queue stats
    * Table features
    * Experimenter

See also: bug 7140

Change-Id: I0844c54435b3b029982e7cd6e6b9c2cb01138c67
Signed-off-by: Tomas Slusny <tomas.slusny@pantheon.tech>
32 files changed:
extension/openflowplugin-extension-api/src/main/yang/openflowplugin-experimenter-types.yang
model/model-flow-base/src/main/yang/opendaylight-multipart-types.yang [new file with mode: 0644]
model/model-flow-base/src/main/yang/opendaylight-port-types.yang
model/model-flow-service/src/main/yang/flow-node-inventory.yang
model/model-flow-service/src/main/yang/sal-flow.yang
model/model-flow-service/src/main/yang/sal-table.yang
model/model-flow-statistics/src/main/yang/opendaylight-flow-statistics.yang
model/model-flow-statistics/src/main/yang/opendaylight-flow-table-statistics.yang
model/model-flow-statistics/src/main/yang/opendaylight-group-statistics.yang
model/model-flow-statistics/src/main/yang/opendaylight-meter-statistics.yang
model/model-flow-statistics/src/main/yang/opendaylight-port-statistics.yang
model/model-flow-statistics/src/main/yang/opendaylight-queue-statistics.yang
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/DeserializerInjector.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/MultipartDeserializerInjector.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyDescDeserializer.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyExperimenterDeserializer.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyFlowAggregateStatsDeserializer.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyFlowStatsDeserializer.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyFlowTableStatsDeserializer.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyGroupDescDeserializer.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyGroupFeaturesDeserializer.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyGroupStatsDeserializer.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyMessageDeserializer.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyMeterConfigDeserializer.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyMeterFeaturesDeserializer.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyMeterStatsDeserializer.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyPortDescDeserializer.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyPortStatsDeserializer.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyQueueStatsDeserializer.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyTableFeaturesDeserializer.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/TableFeaturesMatchFieldDeserializer.java [new file with mode: 0644]
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/util/ActionUtil.java

index 8dcd9fdc93a86ff90e4dbfdec7ecd22659e2068f..6c9b77acc3fa5fa6f566567513db41e50a56f819 100644 (file)
@@ -2,6 +2,8 @@ module openflowplugin-experimenter-types {
     namespace "urn:opendaylight:openflowplugin:experimenter:types";
     prefix exp-type;
 
+    import opendaylight-multipart-types { prefix multipart; revision-date "2017-01-12"; }
+
     revision "2015-10-20" {
         description "Initial revision of experimenter basic types";
     }
@@ -12,4 +14,11 @@ module openflowplugin-experimenter-types {
             // to be augmented by vendors
         }
     }
+
+    augment "/multipart:multipart-reply/multipart:multipart-reply-body" {
+        case multipart-reply-experimenter {
+            uses experimenter-core-message;
+        }
+    }
+
 }
diff --git a/model/model-flow-base/src/main/yang/opendaylight-multipart-types.yang b/model/model-flow-base/src/main/yang/opendaylight-multipart-types.yang
new file mode 100644 (file)
index 0000000..0280fe5
--- /dev/null
@@ -0,0 +1,22 @@
+module opendaylight-multipart-types {
+    namespace "urn:opendaylight:multipart:types";
+    prefix multipart;
+
+    import openflow-protocol { prefix ofproto; revision-date "2013-07-31"; }
+
+    revision "2017-01-12" {
+        description "Initial revision";
+    }
+
+    container multipart-reply {
+        uses ofproto:ofHeader;
+
+        leaf request-more {
+            type boolean;
+            default false;
+        }
+
+        choice multipart-reply-body {
+        }
+    }
+}
index bc0da3629b22b4a2fbbddf9e3aa062930337b36a..a2f6ed035627e8b507555b54523dc46779c0191d 100644 (file)
@@ -5,11 +5,12 @@ module opendaylight-port-types {
     import ietf-yang-types {prefix yang; revision-date "2013-07-15";}
     import opendaylight-queue-types {prefix queue-types; revision-date "2013-09-25";}
     import openflow-protocol { prefix ofproto; revision-date "2013-07-31"; }
+    import opendaylight-multipart-types { prefix multipart; revision-date "2017-01-12"; }
 
     revision "2013-09-25" {
         description "Initial revision of Port Inventory model";
     }
-    
+
     typedef port-reason {
         type enumeration {
             enum add;
@@ -17,7 +18,7 @@ module opendaylight-port-types {
             enum update;
         }
     }
-    
+
     typedef port-config {
         type bits {
             bit PORT-DOWN;
@@ -26,19 +27,19 @@ module opendaylight-port-types {
             bit NO-PACKET-IN;
         }
     }
-    
+
     grouping port-state {
         leaf link-down {
             type boolean;
         }
         leaf blocked {
             type boolean;
-        }   
+        }
         leaf live {
             type boolean;
         }
     }
-    
+
     typedef port-features {
         type bits {
             bit ten-mb-hd;
@@ -59,7 +60,7 @@ module opendaylight-port-types {
             bit pause-asym;
         }
     }
-    
+
     typedef port-number-uni {
         description "Union port number: 4B number / string (reserved port name)";
         type union {
@@ -67,121 +68,129 @@ module opendaylight-port-types {
             type string;
         }
     }
-    
+
     grouping common-port {
 
         leaf port-number {
             type port-number-uni;
         }
-        
+
         leaf hardware-address {
             type yang:mac-address;
             description "MAC Address of the port";
-            
+
         }
-        
+
         leaf configuration {
             type port-config;
-            description "Bit map of OFPPC-* flags";          
+            description "Bit map of OFPPC-* flags";
         }
-        
+
         leaf advertised-features {
             type port-features;
-            description "Features being advertised by the port";            
+            description "Features being advertised by the port";
         }
     }
-    
+
     grouping flow-port-status {
         leaf reason {
             type port-reason;
         }
-        
+
         uses flow-capable-port;
     }
-    
+
     grouping queues {
        list queue {
                key "queue-id";
                uses queue-types:queue-packet;
        }
     }
-    
-    grouping flow-capable-port {    
-                
+
+    grouping flow-capable-port {
+
         uses common-port;
-        
+
         leaf name {
             type string;
-            description "Human readable name of the port";                    
+            description "Human readable name of the port";
         }
-        
+
         container state {
             uses port-state;
-            description "Description of state of port";            
+            description "Description of state of port";
         }
-        
+
         leaf current-feature {
             type port-features;
-            description "Bit map of OFPPF-* flags";            
-        }       
-        
+            description "Bit map of OFPPF-* flags";
+        }
+
         leaf supported {
             type port-features;
-            description "Features supported by the port";           
+            description "Features supported by the port";
         }
-        
+
         leaf peer-features {
             type port-features;
-            description "Features advertised by peer";            
+            description "Features advertised by peer";
         }
-        
+
         leaf current-speed {
             type uint32;
             units "kbps";
-            description "Current port bit rate in kbps";            
+            description "Current port bit rate in kbps";
         }
-        
+
         leaf maximum-speed {
             type uint32;
             units "kbps";
-            description "Max port bit rate in kbps";            
+            description "Max port bit rate in kbps";
         }
-        
+
         uses queues;
-    }    
-    
+    }
+
     grouping port-mod {
         container port {
             list port {
                 key "port-mod-order";
                 leaf port-mod-order {
                     type uint32;
-                }    
-                
+                }
+
                 uses common-port;
-                
+
                 leaf mask {
                     type port-config;
                     description "Bitmap of OFPPC-* flags to be changed";
-                }      
-                
+                }
+
                 leaf container-name {
-                    type string; 
+                    type string;
                 }
-            
+
                 leaf port-name {
-                    type string; 
-                } 
+                    type string;
+                }
 
                 leaf barrier {
-                    type boolean; 
-                } 
-            }            
-        }    
+                    type boolean;
+                }
+            }
+        }
     }
 
     container port-message {
         uses common-port;
         uses ofproto:ofHeader;
     }
+
+    augment "/multipart:multipart-reply/multipart:multipart-reply-body" {
+        case multipart-reply-port-desc {
+            list ports {
+                uses flow-capable-port;
+            }
+        }
+    }
 }
index 0e48db647994e76071783ae626030830a0caa29e..4901f08f24462b891d594a64845439841796456e 100644 (file)
@@ -11,6 +11,7 @@ module flow-node-inventory {
     import opendaylight-flow-types {prefix flow;revision-date "2013-10-26";}
     import opendaylight-group-types {prefix group;revision-date "2013-10-18";}
     import opendaylight-meter-types {prefix meter;revision-date "2013-09-18";}
+    import opendaylight-multipart-types { prefix multipart; revision-date "2017-01-12"; }
 
     description "Flow Capable Node extensions to the Inventory model";
 
@@ -158,8 +159,7 @@ module flow-node-inventory {
         }
     }
 
-    grouping flow-node {
-        description "Openflow node structure = device";
+    grouping desc {
         leaf manufacturer {
             type string;
         }
@@ -175,7 +175,11 @@ module flow-node-inventory {
         leaf description {
             type string;
         }
+    }
 
+    grouping flow-node {
+        description "Openflow node structure = device";
+        uses desc;
         uses tables;
         uses table:table-features;
         uses group:groups;
@@ -314,4 +318,10 @@ module flow-node-inventory {
             This is contructed by asynchronous process.";
         uses snapshot-gathering-status-grouping;
     }
+
+    augment "/multipart:multipart-reply/multipart:multipart-reply-body" {
+        case multipart-reply-desc {
+            uses desc;
+        }
+    }
 }
index 2fe3c117edbac23f8fc4629303295d568b1b9d85..9acf23ffcc4d55cf6bebaf4aaa4940c7b1427bf5 100644 (file)
@@ -20,7 +20,7 @@ module sal-flow {
         description "Openflow table identifier";
         type instance-identifier;
     }
-    
+
     grouping node-flow-removed {
         description "Flow removed message structure.";
         leaf node {
@@ -33,7 +33,7 @@ module sal-flow {
         }
         uses types:flow-mod-removed;
     }
-    
+
     grouping node-flow {
         description "Top openflow flow structure suitable for rpc input (contains node-context).";
         uses "inv:node-context-ref";
@@ -93,7 +93,7 @@ module sal-flow {
             leaf flow-ref {
                 type types:flow-ref;
             }
-            uses node-flow;            
+            uses node-flow;
         }
         output {
             uses tr:transaction-aware;
@@ -107,7 +107,7 @@ module sal-flow {
             leaf flow-ref {
                 type types:flow-ref;
             }
-            uses node-flow;            
+            uses node-flow;
         }
         output {
             uses tr:transaction-aware;
@@ -121,7 +121,7 @@ module sal-flow {
             leaf flow-ref {
                 type types:flow-ref;
             }
-            uses flow-update;           
+            uses flow-update;
         }
         output {
             uses tr:transaction-aware;
@@ -147,7 +147,7 @@ module sal-flow {
             type types:flow-ref;
         }
         uses node-flow;
-        uses tr:transaction-aware;        
+        uses tr:transaction-aware;
     }
 
     notification flow-removed {
@@ -163,13 +163,13 @@ module sal-flow {
         uses node-flow;
         uses tr:transaction-aware;
     }
-    
+
     notification switch-flow-removed {
         status deprecated;
 
         uses node-flow-removed;
     }
-    
+
     notification node-error-notification {
         status deprecated;
 
@@ -179,7 +179,7 @@ module sal-flow {
         uses node-error-reference;
         uses base-node-error-notification;
     }
-    
+
     notification node-experimenter-error-notification {
         status deprecated;
 
index e8b45ace1ad29616286eda0c319b9ee82f21ed59..ddaabebeb33f068a8632b34816a49b11cf16c7d4 100644 (file)
@@ -5,6 +5,7 @@ module sal-table {
     import opendaylight-inventory {prefix inv;revision-date "2013-08-19";}
     import opendaylight-table-types {prefix table-type;revision-date "2013-10-26";}
     import flow-capable-transaction {prefix tr; revision-date "2015-03-04";}
+    import opendaylight-multipart-types { prefix multipart; revision-date "2017-01-12"; }
 
     description "Openflow table management.";
 
@@ -47,4 +48,11 @@ module sal-table {
         uses tr:multipart-transaction-aware;
         uses table-type:table-features;
     }
+
+
+    augment "/multipart:multipart-reply/multipart:multipart-reply-body" {
+        case multipart-reply-table-features {
+            uses table-type:table-features;
+        }
+    }
 }
index 8091d5247662d66ffc221ffea3f8a48ae96aeed3..68ab1b2d4d12cdae33fcd2992fcb3ef40a482849 100644 (file)
@@ -10,6 +10,7 @@ module opendaylight-flow-statistics {
     import flow-node-inventory {prefix flow-node;revision-date "2013-08-19";}
     import flow-capable-transaction {prefix tr;}
     import ietf-inet-types {prefix inet; revision-date "2013-07-15";}
+    import opendaylight-multipart-types { prefix multipart; revision-date "2017-01-12"; }
 
     description "Openflow statistics polling.";
 
@@ -136,7 +137,7 @@ module opendaylight-flow-statistics {
     }
 
     rpc get-aggregate-flow-statistics-from-flow-table-for-given-match {
-        description "Fetch aggregate statistics for flows filtered by 
+        description "Fetch aggregate statistics for flows filtered by
           - table (eventually all tables)
           - match
           - port
@@ -165,4 +166,14 @@ module opendaylight-flow-statistics {
         uses stat-types:aggregate-flow-statistics;
         uses tr:multipart-transaction-aware;
     }
+
+    augment "/multipart:multipart-reply/multipart:multipart-reply-body" {
+        case multipart-reply-flow-stats {
+            uses flow-and-statistics-map-list;
+        }
+
+        case multipart-reply-flow-aggregate-stats {
+            uses stat-types:aggregate-flow-statistics;
+        }
+    }
 }
index bb653f8d7892095e96c87161107d5a07f8c5b293..025b9a4b31531abc8e2249b4e897b033f5129809 100644 (file)
@@ -8,6 +8,7 @@ module opendaylight-flow-table-statistics {
     import flow-node-inventory {prefix flow-node;revision-date "2013-08-19";}
     import opendaylight-table-types {prefix table-types;revision-date "2013-10-26";}
     import opendaylight-statistics-types {prefix stat-types;revision-date "2013-09-25";}
+    import opendaylight-multipart-types { prefix multipart; revision-date "2017-01-12"; }
 
     description "Openflow flow table statistics structures.";
 
@@ -68,4 +69,10 @@ module opendaylight-flow-table-statistics {
         uses flow-table-and-statistics-map;
         uses tr:multipart-transaction-aware;
     }
+
+    augment "/multipart:multipart-reply/multipart:multipart-reply-body" {
+        case multipart-reply-flow-table-stats {
+            uses flow-table-and-statistics-map;
+        }
+    }
 }
index 5563f0e28f06b38a45f20e4440ed7824e8e84dc9..318cf17430b8ef212ca7a6c16bad718e58cafeb0 100644 (file)
@@ -7,6 +7,7 @@ module opendaylight-group-statistics {
     import opendaylight-group-types {prefix group-types;revision-date "2013-10-18";}
     import flow-capable-transaction {prefix tr; revision-date "2015-03-04";}
     import flow-node-inventory {prefix fni; revision-date "2013-08-19";}
+    import opendaylight-multipart-types { prefix multipart; revision-date "2017-01-12"; }
 
     description "Openflow group statistics structures.";
 
@@ -131,4 +132,18 @@ module opendaylight-group-statistics {
         uses group-types:group-features-reply;
         uses tr:multipart-transaction-aware;
     }
+
+    augment "/multipart:multipart-reply/multipart:multipart-reply-body" {
+        case multipart-reply-group-stats {
+            uses group-types:group-statistics-reply;
+        }
+
+        case multipart-reply-group-desc {
+            uses group-types:group-desc-stats-reply;
+        }
+
+        case multipart-reply-group-features {
+            uses group-types:group-features-reply;
+        }
+    }
 }
index 7a26083ef25c523b4a28339f92defa05a3414807..0d91e4c49eae83882c9c5ecbfce16290cc791327 100644 (file)
@@ -7,6 +7,7 @@ module opendaylight-meter-statistics {
     import flow-node-inventory {prefix flow-node;revision-date "2013-08-19";}
     import opendaylight-meter-types {prefix meter-types; revision-date "2013-09-18";}
     import flow-capable-transaction {prefix tr; revision-date "2015-03-04";}
+    import opendaylight-multipart-types { prefix multipart; revision-date "2017-01-12"; }
 
     description "Openflowplugin meter statistics structures.";
 
@@ -122,4 +123,18 @@ module opendaylight-meter-statistics {
         uses meter-types:meter-features-reply;
         uses tr:multipart-transaction-aware;
     }
+
+    augment "/multipart:multipart-reply/multipart:multipart-reply-body" {
+        case multipart-reply-meter-stats {
+            uses meter-types:meter-statistics-reply;
+        }
+
+        case multipart-reply-meter-config {
+            uses meter-types:meter-config-stats-reply;
+        }
+
+        case multipart-reply-meter-features {
+            uses meter-types:meter-features-reply;
+        }
+    }
 }
index f7bf62ac5f1e6085ef72c37a5de06e5ad99bd481..e23467031a118d3a097d75aef8f573277a84dc12 100644 (file)
@@ -6,6 +6,7 @@ module opendaylight-port-statistics {
     import yang-ext {prefix ext; revision-date "2013-07-09";}
     import opendaylight-inventory {prefix inv;revision-date "2013-08-19";}
     import opendaylight-statistics-types {prefix stat-types;revision-date "2013-09-25";}
+    import opendaylight-multipart-types { prefix multipart; revision-date "2017-01-12"; }
 
     description "Openflow port statistics structures.";
 
@@ -23,14 +24,14 @@ module opendaylight-port-statistics {
         ext:augment-identifier "flow-capable-node-connector-statistics-data";
         uses flow-capable-node-connector-statistics;
     }
-    
+
     grouping flow-capable-node-connector-statistics {
         description "TODO:: simplify";
         container flow-capable-node-connector-statistics {
             uses stat-types:node-connector-statistics;
         }
     }
-    
+
     // RPC calls
     rpc get-all-node-connectors-statistics {
         status deprecated;
@@ -82,4 +83,10 @@ module opendaylight-port-statistics {
         uses node-connector-statistics-and-port-number-map;
         uses tr:multipart-transaction-aware;
     }
+
+    augment "/multipart:multipart-reply/multipart:multipart-reply-body" {
+        case multipart-reply-port-stats {
+            uses node-connector-statistics-and-port-number-map;
+        }
+    }
 }
index 097e2fcb384346f37a3c226422b9d870693c5995..2bd06816196cfd0bd9f944d20f7f08ffc42273fc 100644 (file)
@@ -8,6 +8,7 @@ module opendaylight-queue-statistics {
     import flow-node-inventory {prefix flow-node;revision-date "2013-08-19";}
     import opendaylight-queue-types {prefix queue-types;revision-date "2013-09-25";}
     import opendaylight-statistics-types {prefix stat-types;revision-date "2013-09-25";}
+    import opendaylight-multipart-types { prefix multipart; revision-date "2017-01-12"; }
 
     description "Openflowplugin queue statistics structures.";
 
@@ -107,4 +108,10 @@ module opendaylight-queue-statistics {
         uses queue-id-and-statistics-map;
         uses tr:multipart-transaction-aware;
     }
+
+    augment "/multipart:multipart-reply/multipart:multipart-reply-body" {
+        case multipart-reply-queue-stats {
+            uses queue-id-and-statistics-map;
+        }
+    }
 }
index c2455152b98b18e3c96958337d432c5b910700ca..58ff11884096e79af2a8d431768027f376872370 100644 (file)
@@ -25,5 +25,6 @@ public class DeserializerInjector {
         ActionDeserializerInjector.injectDeserializers(provider);
         InstructionDeserializerInjector.injectDeserializers(provider);
         MessageDeserializerInjector.injectDeserializers(provider);
+        MultipartDeserializerInjector.injectDeserializers(provider);
     }
 }
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/MultipartDeserializerInjector.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/MultipartDeserializerInjector.java
new file mode 100644 (file)
index 0000000..4e2a747
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2016 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization;
+
+import com.google.common.annotations.VisibleForTesting;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerExtensionProvider;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
+import org.opendaylight.openflowjava.protocol.api.keys.MessageCodeKey;
+import org.opendaylight.openflowjava.protocol.api.keys.TypeToClassKey;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart.MultipartReplyDescDeserializer;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart.MultipartReplyExperimenterDeserializer;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart.MultipartReplyFlowAggregateStatsDeserializer;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart.MultipartReplyFlowStatsDeserializer;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart.MultipartReplyFlowTableStatsDeserializer;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart.MultipartReplyGroupDescDeserializer;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart.MultipartReplyGroupFeaturesDeserializer;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart.MultipartReplyGroupStatsDeserializer;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart.MultipartReplyMessageDeserializer;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart.MultipartReplyMeterConfigDeserializer;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart.MultipartReplyMeterFeaturesDeserializer;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart.MultipartReplyMeterStatsDeserializer;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart.MultipartReplyPortDescDeserializer;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart.MultipartReplyPortStatsDeserializer;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart.MultipartReplyQueueStatsDeserializer;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart.MultipartReplyTableFeaturesDeserializer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.MultipartReply;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
+
+public class MultipartDeserializerInjector {
+
+    /**
+     * Injects message deserializers into provided {@link org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerExtensionProvider}
+     * @param provider OpenflowJava deserializer extension provider
+     */
+    static void injectDeserializers(final DeserializerExtensionProvider provider) {
+        final short version = EncodeConstants.OF13_VERSION_ID;
+
+        // Inject main multipart reply deserializer
+        injectMultipartReplyDeserializer(provider, version);
+
+        // Inject new multipart body deserializers here using injector created by createInjector method
+        final Function<Integer, Consumer<OFDeserializer<? extends MultipartReplyBody>>> injector =
+                createInjector(provider, version);
+        injector.apply(MultipartType.OFPMPDESC.getIntValue()).accept(new MultipartReplyDescDeserializer());
+        injector.apply(MultipartType.OFPMPFLOW.getIntValue()).accept(new MultipartReplyFlowStatsDeserializer());
+        injector.apply(MultipartType.OFPMPAGGREGATE.getIntValue()).accept(new MultipartReplyFlowAggregateStatsDeserializer());
+        injector.apply(MultipartType.OFPMPTABLE.getIntValue()).accept(new MultipartReplyFlowTableStatsDeserializer());
+        injector.apply(MultipartType.OFPMPPORTSTATS.getIntValue()).accept(new MultipartReplyPortStatsDeserializer());
+        injector.apply(MultipartType.OFPMPQUEUE.getIntValue()).accept(new MultipartReplyQueueStatsDeserializer());
+        injector.apply(MultipartType.OFPMPGROUP.getIntValue()).accept(new MultipartReplyGroupStatsDeserializer());
+        injector.apply(MultipartType.OFPMPGROUPDESC.getIntValue()).accept(new MultipartReplyGroupDescDeserializer());
+        injector.apply(MultipartType.OFPMPGROUPFEATURES.getIntValue()).accept(new MultipartReplyGroupFeaturesDeserializer());
+        injector.apply(MultipartType.OFPMPMETER.getIntValue()).accept(new MultipartReplyMeterStatsDeserializer());
+        injector.apply(MultipartType.OFPMPMETERCONFIG.getIntValue()).accept(new MultipartReplyMeterConfigDeserializer());
+        injector.apply(MultipartType.OFPMPMETERFEATURES.getIntValue()).accept(new MultipartReplyMeterFeaturesDeserializer());
+        injector.apply(MultipartType.OFPMPTABLEFEATURES.getIntValue()).accept(new MultipartReplyTableFeaturesDeserializer());
+        injector.apply(MultipartType.OFPMPPORTDESC.getIntValue()).accept(new MultipartReplyPortDescDeserializer());
+        injector.apply(MultipartType.OFPMPEXPERIMENTER.getIntValue()).accept(new MultipartReplyExperimenterDeserializer());
+    }
+
+    /**
+     * Register main multipart reply deserializer
+     * @param provider OpenflowJava deserializer extension provider
+     * @param version Openflow version
+     */
+    static void injectMultipartReplyDeserializer(final DeserializerExtensionProvider provider, final short version) {
+        final short code = 19;
+        final Class<? extends OfHeader> retType = MultipartReply.class;
+        provider.unregisterDeserializerMapping(new TypeToClassKey(version, code));
+        provider.registerDeserializerMapping(new TypeToClassKey(version, code), retType);
+        provider.registerDeserializer(
+                new MessageCodeKey(version, code, retType),
+                new MultipartReplyMessageDeserializer());
+    }
+
+    /**
+     * Create injector that will inject new deserializers into #{@link org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerExtensionProvider}
+     * @param provider OpenflowJava deserializer extension provider
+     * @param version Openflow version
+     * @return injector
+     */
+    @VisibleForTesting
+    static Function<Integer, Consumer<OFDeserializer<? extends MultipartReplyBody>>> createInjector(
+            final DeserializerExtensionProvider provider,
+            final short version) {
+        return code -> deserializer -> {
+            provider.registerDeserializer(
+                    new MessageCodeKey(version, code, MultipartReplyBody.class),
+                    deserializer);
+        };
+    }
+
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyDescDeserializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyDescDeserializer.java
new file mode 100644 (file)
index 0000000..57a4a35
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart;
+
+import io.netty.buffer.ByteBuf;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.multipart.reply.multipart.reply.body.MultipartReplyDescBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
+
+public class MultipartReplyDescDeserializer implements OFDeserializer<MultipartReplyBody> {
+    private static final int DESC_STR_LEN = 256;
+    private static final int SERIAL_NUM_LEN = 32;
+
+    @Override
+    public MultipartReplyBody deserialize(ByteBuf message) {
+        byte[] mfrDescBytes = new byte[DESC_STR_LEN];
+        message.readBytes(mfrDescBytes);
+
+        byte[] hwDescBytes = new byte[DESC_STR_LEN];
+        message.readBytes(hwDescBytes);
+
+        byte[] swDescBytes = new byte[DESC_STR_LEN];
+        message.readBytes(swDescBytes);
+
+        byte[] serialNumBytes = new byte[SERIAL_NUM_LEN];
+        message.readBytes(serialNumBytes);
+
+        byte[] dpDescBytes = new byte[DESC_STR_LEN];
+        message.readBytes(dpDescBytes);
+
+        return new MultipartReplyDescBuilder()
+                .setManufacturer(new String(mfrDescBytes))
+                .setHardware(new String(hwDescBytes))
+                .setSoftware(new String(swDescBytes))
+                .setSerialNumber(new String(serialNumBytes))
+                .setDescription(new String(dpDescBytes))
+                .build();
+    }
+
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyExperimenterDeserializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyExperimenterDeserializer.java
new file mode 100644 (file)
index 0000000..4a0931d
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart;
+
+import io.netty.buffer.ByteBuf;
+import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistry;
+import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistryInjector;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
+import org.opendaylight.openflowjava.protocol.api.keys.ExperimenterIdTypeDeserializerKey;
+import org.opendaylight.openflowjava.protocol.api.keys.MessageTypeKey;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowjava.util.ExperimenterDeserializerKeyFactory;
+import org.opendaylight.openflowplugin.extension.api.ConvertorMessageFromOFJava;
+import org.opendaylight.openflowplugin.extension.api.exception.ConversionException;
+import org.opendaylight.openflowplugin.extension.api.path.MessagePath;
+import org.opendaylight.openflowplugin.openflow.md.core.session.OFSessionUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.experimenter.core.ExperimenterDataOfChoice;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.experimenter.types.rev151020.experimenter.core.message.ExperimenterMessageOfChoice;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.experimenter.types.rev151020.multipart.reply.multipart.reply.body.MultipartReplyExperimenterBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MultipartReplyExperimenterDeserializer implements OFDeserializer<MultipartReplyBody>, DeserializerRegistryInjector {
+    private static final Logger LOG = LoggerFactory.getLogger(MultipartReplyExperimenterDeserializer.class);
+    private DeserializerRegistry registry;
+
+    @Override
+    public MultipartReplyBody deserialize(ByteBuf message) {
+        final MultipartReplyExperimenterBuilder builder = new MultipartReplyExperimenterBuilder();
+        final long expId = message.readUnsignedInt();
+        final long expType = message.readUnsignedInt();
+
+        try {
+            final OFDeserializer<ExperimenterMessageOfChoice> deserializer = registry
+                .getDeserializer(new ExperimenterIdTypeDeserializerKey(
+                            EncodeConstants.OF13_VERSION_ID, expId, expType, ExperimenterMessageOfChoice.class));
+
+            builder.setExperimenterMessageOfChoice(deserializer.deserialize(message));
+        } catch (ClassCastException | IllegalStateException es) {
+            final OFDeserializer<ExperimenterDataOfChoice> deserializer = registry.getDeserializer(
+                    ExperimenterDeserializerKeyFactory.createMultipartReplyMessageDeserializerKey(
+                        EncodeConstants.OF13_VERSION_ID, expId, expType));
+
+            final ExperimenterDataOfChoice data = deserializer.deserialize(message);
+            final MessageTypeKey<? extends ExperimenterDataOfChoice> key = new MessageTypeKey<>(
+                    EncodeConstants.OF13_VERSION_ID,
+                    (Class<? extends ExperimenterDataOfChoice>) data.getImplementedInterface());
+
+            final ConvertorMessageFromOFJava<ExperimenterDataOfChoice, MessagePath> convertor = OFSessionUtil
+                .getExtensionConvertorProvider()
+                .getMessageConverter(key);
+
+            try {
+                builder.setExperimenterMessageOfChoice(convertor.convert(data, MessagePath.MPMESSAGE_RPC_OUTPUT));
+            } catch (ConversionException ce) {
+                LOG.debug("Failed to deserialize multipart reply experimenter for key: {}", key);
+            }
+        }
+
+        return builder.build();
+    }
+
+    @Override
+    public void injectDeserializerRegistry(DeserializerRegistry deserializerRegistry) {
+        registry = deserializerRegistry;
+    }
+
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyFlowAggregateStatsDeserializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyFlowAggregateStatsDeserializer.java
new file mode 100644 (file)
index 0000000..08eaaa5
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart;
+
+import io.netty.buffer.ByteBuf;
+import java.math.BigInteger;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter32;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter64;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.multipart.reply.multipart.reply.body.MultipartReplyFlowAggregateStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
+
+public class MultipartReplyFlowAggregateStatsDeserializer implements OFDeserializer<MultipartReplyBody> {
+
+    private static final byte PADDING_IN_AGGREGATE_HEADER = 4;
+
+    @Override
+    public MultipartReplyBody deserialize(ByteBuf message) {
+        final MultipartReplyFlowAggregateStatsBuilder builder = new MultipartReplyFlowAggregateStatsBuilder()
+            .setPacketCount(new Counter64(BigInteger.valueOf(message.readLong())))
+            .setByteCount(new Counter64(BigInteger.valueOf(message.readLong())))
+            .setFlowCount(new Counter32(message.readUnsignedInt()));
+
+        message.skipBytes(PADDING_IN_AGGREGATE_HEADER);
+        return builder.build();
+    }
+
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyFlowStatsDeserializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyFlowStatsDeserializer.java
new file mode 100644 (file)
index 0000000..63ff4fc
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart;
+
+import io.netty.buffer.ByteBuf;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistry;
+import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistryInjector;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
+import org.opendaylight.openflowjava.protocol.api.keys.MessageCodeKey;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowjava.protocol.impl.util.InstructionConstants;
+import org.opendaylight.openflowplugin.api.openflow.protocol.deserialization.MessageCodeExperimenterKey;
+import org.opendaylight.openflowplugin.extension.api.path.ActionPath;
+import org.opendaylight.openflowplugin.extension.api.path.MatchPath;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.key.MessageCodeActionExperimenterKey;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.key.MessageCodeMatchKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter32;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter64;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.multipart.reply.multipart.reply.body.MultipartReplyFlowStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowModFlags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.duration.DurationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
+
+public class MultipartReplyFlowStatsDeserializer implements OFDeserializer<MultipartReplyBody>, DeserializerRegistryInjector {
+
+    private static final MessageCodeKey MATCH_KEY = new MessageCodeMatchKey(EncodeConstants.OF13_VERSION_ID,
+            EncodeConstants.EMPTY_VALUE, Match.class,
+            MatchPath.FLOWSSTATISTICSUPDATE_FLOWANDSTATISTICSMAPLIST_MATCH);
+
+    private static final byte PADDING_IN_FLOW_STATS_HEADER_01 = 1;
+    private static final byte PADDING_IN_FLOW_STATS_HEADER_02 = 4;
+    private DeserializerRegistry registry;
+
+    @Override
+    public MultipartReplyBody deserialize(ByteBuf message) {
+        final MultipartReplyFlowStatsBuilder builder = new MultipartReplyFlowStatsBuilder();
+        final List<FlowAndStatisticsMapList> items = new ArrayList<>();
+
+        while (message.readableBytes() > 0) {
+            final FlowAndStatisticsMapListBuilder itemBuilder = new FlowAndStatisticsMapListBuilder();
+            final int itemLength = message.readUnsignedShort();
+            final ByteBuf itemMessage = message.readSlice(itemLength - EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
+
+            itemBuilder.setTableId(itemMessage.readUnsignedByte());
+            itemMessage.skipBytes(PADDING_IN_FLOW_STATS_HEADER_01);
+
+
+            itemBuilder
+                .setDuration(new DurationBuilder()
+                        .setSecond(new Counter32(itemMessage.readUnsignedInt()))
+                        .setNanosecond(new Counter32(itemMessage.readUnsignedInt()))
+                        .build())
+                .setPriority(itemMessage.readUnsignedShort())
+                .setIdleTimeout(itemMessage.readUnsignedShort())
+                .setHardTimeout(itemMessage.readUnsignedShort())
+                .setFlags(createFlowModFlagsFromBitmap(itemMessage.readUnsignedShort()));
+
+            itemMessage.skipBytes(PADDING_IN_FLOW_STATS_HEADER_02);
+
+            itemBuilder
+                .setCookie(new FlowCookie(BigInteger.valueOf(message.readLong())))
+                .setCookieMask(new FlowCookie(BigInteger.valueOf(message.readLong())))
+                .setPacketCount(new Counter64(BigInteger.valueOf(message.readLong())))
+                .setByteCount(new Counter64(BigInteger.valueOf(message.readLong())));
+
+
+            final OFDeserializer<Match> matchDeserializer = registry.getDeserializer(MATCH_KEY);
+            itemBuilder.setMatch(new MatchBuilder(matchDeserializer.deserialize(message)).build());
+
+            final int length = itemMessage.readableBytes();
+
+            if (length > 0) {
+                final List<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list
+                    .Instruction> instructions = new ArrayList<>();
+                final int startIndex = itemMessage.readerIndex();
+                int offset = 0;
+
+                while ((itemMessage.readerIndex() - startIndex) < length) {
+                    final int type = itemMessage.getUnsignedShort(itemMessage.readerIndex());
+                    OFDeserializer<Instruction> deserializer = null;
+
+                    if (InstructionConstants.APPLY_ACTIONS_TYPE == type) {
+                        deserializer = registry.getDeserializer(
+                                new MessageCodeActionExperimenterKey(
+                                    EncodeConstants.OF13_VERSION_ID, type, Instruction.class,
+                                    ActionPath.NODES_NODE_TABLE_FLOW_INSTRUCTIONS_INSTRUCTION_APPLYACTIONSCASE_APPLYACTIONS_ACTION_ACTION_EXTENSIONLIST_EXTENSION,
+                                    null));
+                    } else if (InstructionConstants.WRITE_ACTIONS_TYPE == type) {
+                        deserializer = registry.getDeserializer(
+                                new MessageCodeActionExperimenterKey(
+                                    EncodeConstants.OF13_VERSION_ID, type, Instruction.class,
+                                    ActionPath.NODES_NODE_TABLE_FLOW_INSTRUCTIONS_INSTRUCTION_WRITEACTIONSCASE_WRITEACTIONS_ACTION_ACTION_EXTENSIONLIST_EXTENSION,
+                                    null));
+                    } else {
+                        Long expId = null;
+
+                        if (EncodeConstants.EXPERIMENTER_VALUE == type) {
+                            expId = itemMessage.getUnsignedInt(itemMessage.readerIndex() +
+                                    2 * EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
+                        }
+
+                        deserializer = registry.getDeserializer(
+                                new MessageCodeExperimenterKey(
+                                    EncodeConstants.OF13_VERSION_ID, type, Instruction.class, expId));
+                    }
+
+                    instructions.add(new InstructionBuilder()
+                            .setKey(new InstructionKey(offset))
+                            .setOrder(offset)
+                            .setInstruction(deserializer.deserialize(itemMessage))
+                            .build());
+
+                    offset++;
+                }
+
+                itemBuilder.setInstructions(new InstructionsBuilder()
+                        .setInstruction(instructions)
+                        .build());
+            }
+
+            items.add(itemBuilder.build());
+        }
+
+        return builder
+            .setFlowAndStatisticsMapList(items)
+            .build();
+    }
+
+    private static FlowModFlags createFlowModFlagsFromBitmap(int input) {
+        final Boolean _oFPFFSENDFLOWREM = (input & (1 << 0)) > 0;
+        final Boolean _oFPFFCHECKOVERLAP = (input & (1 << 1)) > 0;
+        final Boolean _oFPFFRESETCOUNTS = (input & (1 << 2)) > 0;
+        final Boolean _oFPFFNOPKTCOUNTS = (input & (1 << 3)) > 0;
+        final Boolean _oFPFFNOBYTCOUNTS = (input & (1 << 4)) > 0;
+        return new FlowModFlags(_oFPFFCHECKOVERLAP, _oFPFFNOBYTCOUNTS, _oFPFFNOPKTCOUNTS, _oFPFFRESETCOUNTS,
+                _oFPFFSENDFLOWREM);
+    }
+
+    @Override
+    public void injectDeserializerRegistry(DeserializerRegistry deserializerRegistry) {
+        registry = deserializerRegistry;
+    }
+
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyFlowTableStatsDeserializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyFlowTableStatsDeserializer.java
new file mode 100644 (file)
index 0000000..6b894c4
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart;
+
+import io.netty.buffer.ByteBuf;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter32;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter64;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMapBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.multipart.reply.multipart.reply.body.MultipartReplyFlowTableStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId;
+
+public class MultipartReplyFlowTableStatsDeserializer implements OFDeserializer<MultipartReplyBody> {
+
+    private static final byte PADDING_IN_TABLE_HEADER = 3;
+
+    @Override
+    public MultipartReplyBody deserialize(ByteBuf message) {
+        final MultipartReplyFlowTableStatsBuilder builder = new MultipartReplyFlowTableStatsBuilder();
+        final List<FlowTableAndStatisticsMap> items = new ArrayList<>();
+
+        while (message.readableBytes() > 0) {
+            final FlowTableAndStatisticsMapBuilder itemBuilder = new FlowTableAndStatisticsMapBuilder()
+                .setTableId(new TableId(message.readUnsignedByte()));
+
+            message.skipBytes(PADDING_IN_TABLE_HEADER);
+
+            items.add(itemBuilder
+                    .setActiveFlows(new Counter32(message.readUnsignedInt()))
+                    .setPacketsLookedUp(new Counter64(BigInteger.valueOf(message.readLong())))
+                    .setPacketsMatched(new Counter64(BigInteger.valueOf(message.readLong())))
+                    .build());
+        }
+
+        return builder
+            .setFlowTableAndStatisticsMap(items)
+            .build();
+    }
+
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyGroupDescDeserializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyGroupDescDeserializer.java
new file mode 100644 (file)
index 0000000..9b01d3b
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart;
+
+import io.netty.buffer.ByteBuf;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistry;
+import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistryInjector;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowplugin.extension.api.path.ActionPath;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.util.ActionUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyGroupDescBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
+
+public class MultipartReplyGroupDescDeserializer implements OFDeserializer<MultipartReplyBody>, DeserializerRegistryInjector {
+
+    private static final byte PADDING_IN_GROUP_DESC_HEADER = 1;
+    private static final byte PADDING_IN_BUCKETS_HEADER = 4;
+    private static final byte GROUP_DESC_HEADER_LENGTH = 8;
+    private static final byte BUCKETS_HEADER_LENGTH = 16;
+    private DeserializerRegistry registry;
+
+    @Override
+    public MultipartReplyBody deserialize(ByteBuf message) {
+        final MultipartReplyGroupDescBuilder builder = new MultipartReplyGroupDescBuilder();
+        final List<GroupDescStats> items = new ArrayList<>();
+
+        while (message.readableBytes() > 0) {
+            final int itemLength = message.readUnsignedShort();
+
+            final GroupDescStatsBuilder itemBuilder = new GroupDescStatsBuilder()
+                .setGroupType(GroupTypes.forValue(message.readUnsignedByte()));
+
+            message.skipBytes(PADDING_IN_GROUP_DESC_HEADER);
+            itemBuilder.setGroupId(new GroupId(message.readUnsignedInt()));
+
+            final List<Bucket> subItems = new ArrayList<>();
+            int actualLength = GROUP_DESC_HEADER_LENGTH;
+
+            while (actualLength < itemLength) {
+                final int bucketsLength = message.readUnsignedShort();
+
+                final BucketBuilder bucketBuilder = new BucketBuilder()
+                    .setWeight(message.readUnsignedShort())
+                    .setWatchPort(message.readUnsignedInt())
+                    .setWatchGroup(message.readUnsignedInt());
+
+                message.skipBytes(PADDING_IN_BUCKETS_HEADER);
+
+                if (message.readableBytes() > 0) {
+                    final List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list
+                        .Action> actions = new ArrayList<>();
+                    final int startIndex = message.readerIndex();
+                    final int bucketLength = bucketsLength - BUCKETS_HEADER_LENGTH;
+                    int offset = 0;
+
+                    while ((message.readerIndex() - startIndex) < bucketLength) {
+                        actions.add(new ActionBuilder()
+                                .setKey(new ActionKey(offset))
+                                .setOrder(offset)
+                                .setAction(ActionUtil.readAction(EncodeConstants.OF13_VERSION_ID, message, registry,
+                                        ActionPath.GROUPDESCSTATSUPDATED_GROUPDESCSTATS_BUCKETS_BUCKET_ACTION))
+                                .build());
+
+                        offset++;
+                    }
+
+                    bucketBuilder.setAction(actions);
+                }
+
+                subItems.add(bucketBuilder.build());
+                actualLength += bucketsLength;
+            }
+
+            items.add(itemBuilder
+                    .setBuckets(new BucketsBuilder()
+                        .setBucket(subItems)
+                        .build())
+                    .build());
+        }
+
+        return builder
+            .setGroupDescStats(items)
+            .build();
+    }
+
+    @Override
+    public void injectDeserializerRegistry(DeserializerRegistry deserializerRegistry) {
+        registry = deserializerRegistry;
+    }
+
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyGroupFeaturesDeserializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyGroupFeaturesDeserializer.java
new file mode 100644 (file)
index 0000000..580f880
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart;
+
+import io.netty.buffer.ByteBuf;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyGroupFeaturesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Chaining;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.ChainingChecks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupAll;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupCapability;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupFf;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupIndirect;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupSelect;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.SelectLiveness;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.SelectWeight;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
+
+public class MultipartReplyGroupFeaturesDeserializer implements OFDeserializer<MultipartReplyBody> {
+
+    private static final int GROUP_TYPES = 4;
+
+    @Override
+    public MultipartReplyBody deserialize(ByteBuf message) {
+        final MultipartReplyGroupFeaturesBuilder builder = new MultipartReplyGroupFeaturesBuilder();
+
+        return builder
+            .setGroupTypesSupported(readGroupTypes(message))
+            .setGroupCapabilitiesSupported(readGroupCapabilities(message))
+            .setMaxGroups(IntStream
+                    .range(0, GROUP_TYPES)
+                    .mapToObj(i -> message.readUnsignedInt())
+                    .collect(Collectors.toList()))
+            .setActions(IntStream
+                    .range(0, GROUP_TYPES)
+                    .mapToObj(i -> message.readUnsignedInt())
+                    .collect(Collectors.toList()))
+            .build();
+    }
+
+    private static List<Class<? extends GroupCapability>> readGroupCapabilities(ByteBuf message) {
+        final List<Class<? extends GroupCapability>> groupCapabilities = new ArrayList<>();
+        final long capabilitiesMask = message.readUnsignedInt();
+
+        final boolean gcSelectWeight = ((capabilitiesMask) & (1 << 0)) != 0;
+        final boolean gcSelectLiveness = ((capabilitiesMask) & (1 << 1)) != 0;
+        final boolean gcChaining = ((capabilitiesMask) & (1 << 2)) != 0;
+        final boolean gcChainingChecks = ((capabilitiesMask) & (1 << 3)) != 0;
+
+        if (gcSelectWeight) groupCapabilities.add(SelectWeight.class);
+        if (gcSelectLiveness) groupCapabilities.add(SelectLiveness.class);
+        if (gcChaining) groupCapabilities.add(Chaining.class);
+        if (gcChainingChecks) groupCapabilities.add(ChainingChecks.class);
+
+        return groupCapabilities;
+    }
+
+    private static List<Class<? extends GroupType>> readGroupTypes(ByteBuf message) {
+        final List<Class<? extends GroupType>> groupTypes = new ArrayList<>();
+        final long typesMask = message.readUnsignedInt();
+
+        final boolean gtAll = ((typesMask) & (1 << 0)) != 0;
+        final boolean gtSelect = ((typesMask) & (1 << 1)) != 0;
+        final boolean gtIndirect = ((typesMask) & (1 << 2)) != 0;
+        final boolean gtFF = ((typesMask) & (1 << 3)) != 0;
+
+        if (gtAll) groupTypes.add(GroupAll.class);
+        if (gtSelect) groupTypes.add(GroupSelect.class);
+        if (gtIndirect) groupTypes.add(GroupIndirect.class);
+        if (gtFF) groupTypes.add(GroupFf.class);
+
+        return groupTypes;
+    }
+
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyGroupStatsDeserializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyGroupStatsDeserializer.java
new file mode 100644 (file)
index 0000000..a2a85b1
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart;
+
+import io.netty.buffer.ByteBuf;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter32;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter64;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyGroupStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.BucketsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.DurationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.buckets.BucketCounter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.buckets.BucketCounterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
+
+public class MultipartReplyGroupStatsDeserializer implements OFDeserializer<MultipartReplyBody> {
+
+    private static final byte PADDING_IN_GROUP_HEADER_01 = 2;
+    private static final byte PADDING_IN_GROUP_HEADER_02 = 4;
+    private static final byte GROUP_BODY_LENGTH = 40;
+    private static final byte BUCKET_COUNTER_LENGTH = 16;
+
+    @Override
+    public MultipartReplyBody deserialize(ByteBuf message) {
+        final MultipartReplyGroupStatsBuilder builder = new MultipartReplyGroupStatsBuilder();
+        final List<GroupStats> items = new ArrayList<>();
+
+        while (message.readableBytes() > 0) {
+            final int itemLength = message.readUnsignedShort();
+            message.skipBytes(PADDING_IN_GROUP_HEADER_01);
+
+            final GroupStatsBuilder itemBuilder = new GroupStatsBuilder()
+                .setGroupId(new GroupId(message.readUnsignedInt()))
+                .setRefCount(new Counter32(message.readUnsignedInt()));
+
+            message.skipBytes(PADDING_IN_GROUP_HEADER_02);
+
+            itemBuilder
+                .setPacketCount(new Counter64(BigInteger.valueOf(message.readLong())))
+                .setByteCount(new Counter64(BigInteger.valueOf(message.readLong())))
+                .setDuration(new DurationBuilder()
+                        .setSecond(new Counter32(message.readUnsignedInt()))
+                        .setNanosecond(new Counter32(message.readUnsignedInt()))
+                        .build());
+
+            final List<BucketCounter> subItems = new ArrayList<>();
+            int actualLength = GROUP_BODY_LENGTH;
+
+            while (actualLength < itemLength) {
+                subItems.add(new BucketCounterBuilder()
+                        .setPacketCount(new Counter64(BigInteger.valueOf(message.readLong())))
+                        .setByteCount(new Counter64(BigInteger.valueOf(message.readLong())))
+                        .build());
+
+                actualLength += BUCKET_COUNTER_LENGTH;
+            }
+
+            items.add(itemBuilder
+                    .setBuckets(new BucketsBuilder()
+                        .setBucketCounter(subItems)
+                        .build())
+                    .build());
+        }
+
+        return builder
+            .setGroupStats(items)
+            .build();
+    }
+
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyMessageDeserializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyMessageDeserializer.java
new file mode 100644 (file)
index 0000000..82a8009
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart;
+
+import io.netty.buffer.ByteBuf;
+import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistry;
+import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistryInjector;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
+import org.opendaylight.openflowjava.protocol.api.keys.MessageCodeKey;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.MultipartReply;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.MultipartReplyBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
+
+
+public class MultipartReplyMessageDeserializer implements OFDeserializer<MultipartReply>, DeserializerRegistryInjector {
+
+    private static final byte PADDING_IN_MULTIPART_REPLY_HEADER = 4;
+
+    private DeserializerRegistry registry;
+
+    @Override
+    public MultipartReply deserialize(ByteBuf message) {
+        final long xid = message.readUnsignedInt();
+        final int type = message.readUnsignedShort();
+        final boolean reqMore = (message.readUnsignedShort() & 0x01) != 0;
+        message.skipBytes(PADDING_IN_MULTIPART_REPLY_HEADER);
+
+        final OFDeserializer<MultipartReplyBody> deserializer = registry
+            .getDeserializer(new MessageCodeKey(EncodeConstants.OF13_VERSION_ID,
+                        type, MultipartReplyBody.class));
+
+        return new MultipartReplyBuilder()
+            .setVersion((short) EncodeConstants.OF13_VERSION_ID)
+            .setXid(xid)
+            .setRequestMore(reqMore)
+            .setMultipartReplyBody(deserializer.deserialize(message))
+            .build();
+    }
+
+    @Override
+    public void injectDeserializerRegistry(DeserializerRegistry deserializerRegistry) {
+        registry = deserializerRegistry;
+    }
+
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyMeterConfigDeserializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyMeterConfigDeserializer.java
new file mode 100644 (file)
index 0000000..7cc511b
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart;
+
+import io.netty.buffer.ByteBuf;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistry;
+import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistryInjector;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
+import org.opendaylight.openflowjava.protocol.api.keys.ExperimenterIdDeserializerKey;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyMeterConfigBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterBandType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterFlags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.DropBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.DscpRemarkBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.Experimenter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.MeterBandHeadersBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.meter.band.headers.MeterBandHeader;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.meter.band.headers.MeterBandHeaderBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.meter.band.headers.meter.band.header.MeterBandTypesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
+
+public class MultipartReplyMeterConfigDeserializer implements OFDeserializer<MultipartReplyBody>, DeserializerRegistryInjector {
+
+    private static final byte METER_CONFIG_LENGTH = 8;
+
+    private static final int OFPMBTDROP = 1;
+    private static final int OFPMBTDSCP = 2;
+    private static final int OFPMBTEXPERIMENTER = 0xFFFF;
+    private static final byte PADDING_IN_METER_BAND_DROP_HEADER = 4;
+    private static final byte PADDING_IN_METER_BAND_DSCP_HEADER = 3;
+
+    private DeserializerRegistry registry;
+
+    @Override
+    public MultipartReplyBody deserialize(ByteBuf message) {
+        final MultipartReplyMeterConfigBuilder builder = new MultipartReplyMeterConfigBuilder();
+        final List<MeterConfigStats> items = new ArrayList<>();
+
+        while (message.readableBytes() > 0) {
+            final int itemLength = message.readUnsignedShort();
+
+            final MeterConfigStatsBuilder itemBuilder = new MeterConfigStatsBuilder()
+                .setFlags(readMeterFlags(message))
+                .setMeterId(new MeterId(message.readUnsignedInt()));
+
+            final List<MeterBandHeader> subItems = new ArrayList<>();
+            int actualLength = METER_CONFIG_LENGTH;
+
+            while (actualLength < itemLength) {
+                final int itemStartIndex = message.readerIndex();
+                final int itemBandType = message.readUnsignedShort();
+                final MeterBandHeaderBuilder subItemBuilder = new MeterBandHeaderBuilder();
+                actualLength += message.readUnsignedShort();
+
+                switch (itemBandType) {
+                    case OFPMBTDROP:
+                        subItemBuilder
+                            .setMeterBandTypes(new MeterBandTypesBuilder()
+                                    .setFlags(new MeterBandType(true, false, false))
+                                    .build())
+                            .setBandType(new DropBuilder()
+                                    .setDropRate(message.readUnsignedInt())
+                                    .setDropBurstSize(message.readUnsignedInt())
+                                    .build());
+                        message.skipBytes(PADDING_IN_METER_BAND_DROP_HEADER);
+                        break;
+
+                    case OFPMBTDSCP:
+                        subItemBuilder
+                            .setMeterBandTypes(new MeterBandTypesBuilder()
+                                    .setFlags(new MeterBandType(false, true, false))
+                                    .build())
+                            .setBandType(new DscpRemarkBuilder()
+                                    .setDscpRemarkRate(message.readUnsignedInt())
+                                    .setDscpRemarkBurstSize(message.readUnsignedInt())
+                                    .setPrecLevel(message.readUnsignedByte())
+                                    .build());
+                        message.skipBytes(PADDING_IN_METER_BAND_DSCP_HEADER);
+                        break;
+
+                    case OFPMBTEXPERIMENTER:
+                        // TODO: Finish meter band experimenter deserialization
+                        final long expId = message.getUnsignedInt(message.readerIndex() + 2 * EncodeConstants.SIZE_OF_INT_IN_BYTES);
+                        message.readerIndex(itemStartIndex);
+
+                        final OFDeserializer<Experimenter> deserializer = registry.getDeserializer(
+                                new ExperimenterIdDeserializerKey(EncodeConstants.OF13_VERSION_ID, expId, Experimenter.class));
+
+                        subItemBuilder
+                            .setMeterBandTypes(new MeterBandTypesBuilder()
+                                    .setFlags(new MeterBandType(false, false, true))
+                                    .build())
+                            .setBandType(deserializer.deserialize(message));
+                        break;
+
+                }
+            }
+
+            items.add(itemBuilder
+                    .setMeterBandHeaders(new MeterBandHeadersBuilder()
+                        .setMeterBandHeader(subItems)
+                        .build())
+                    .build());
+        }
+
+        return builder
+            .setMeterConfigStats(items)
+            .build();
+    }
+
+    private static MeterFlags readMeterFlags(ByteBuf message) {
+        int input = message.readUnsignedShort();
+        final Boolean mfKBPS = (input & (1)) != 0;
+        final Boolean mfPKTPS = (input & (1 << 1)) != 0;
+        final Boolean mfBURST = (input & (1 << 2)) != 0;
+        final Boolean mfSTATS = (input & (1 << 3)) != 0;
+        return new MeterFlags(mfBURST, mfKBPS, mfPKTPS, mfSTATS);
+    }
+
+    @Override
+    public void injectDeserializerRegistry(DeserializerRegistry deserializerRegistry) {
+        registry = deserializerRegistry;
+    }
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyMeterFeaturesDeserializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyMeterFeaturesDeserializer.java
new file mode 100644 (file)
index 0000000..e853453
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart;
+
+import io.netty.buffer.ByteBuf;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter32;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyMeterFeaturesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterBand;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterBandDrop;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterBandDscpRemark;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterBurst;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterCapability;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterKbps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterPktps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
+
+public class MultipartReplyMeterFeaturesDeserializer implements OFDeserializer<MultipartReplyBody> {
+
+    @Override
+    public MultipartReplyBody deserialize(ByteBuf message) {
+        return new MultipartReplyMeterFeaturesBuilder()
+            .setMaxMeter(new Counter32(message.readUnsignedInt()))
+            .setMeterBandSupported(readMeterBands(message))
+            .setMeterCapabilitiesSupported(readMeterCapabilities(message))
+            .setMaxBands(message.readUnsignedByte())
+            .setMaxColor(message.readUnsignedByte())
+            .build();
+    }
+
+    private static List<Class<? extends MeterBand>> readMeterBands(ByteBuf message) {
+        final List<Class<? extends MeterBand>> bandTypes = new ArrayList<>();
+        final long typesMask = message.readUnsignedInt();
+        final boolean mbtDROP = (typesMask & (1 << 1)) != 0;
+        final boolean mbtDSCPREMARK = (typesMask & (1 << 2)) != 0;
+
+        if (mbtDROP) bandTypes.add(MeterBandDrop.class);
+        if (mbtDSCPREMARK) bandTypes.add(MeterBandDscpRemark.class);
+
+        return bandTypes;
+    }
+
+    private static List<Class<? extends MeterCapability>> readMeterCapabilities(ByteBuf message) {
+        final List<Class<? extends MeterCapability>> meterCapabilities = new ArrayList<>();
+        final long capabilitiesMask = message.readUnsignedInt();
+
+        final boolean mfKBPS = (capabilitiesMask & (1 << 0)) != 0;
+        final boolean mfPKTPS = (capabilitiesMask & (1 << 1)) != 0;
+        final boolean mfBURST = (capabilitiesMask & (1 << 2)) != 0;
+        final boolean mfSTATS = (capabilitiesMask & (1 << 3)) != 0;
+
+        if (mfKBPS) meterCapabilities.add(MeterKbps.class);
+        if (mfPKTPS) meterCapabilities.add(MeterPktps.class);
+        if (mfBURST) meterCapabilities.add(MeterBurst.class);
+        if (mfSTATS) meterCapabilities.add(MeterStats.class);
+
+        return meterCapabilities;
+    }
+
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyMeterStatsDeserializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyMeterStatsDeserializer.java
new file mode 100644 (file)
index 0000000..09eb3a4
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart;
+
+import io.netty.buffer.ByteBuf;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter32;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter64;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyMeterStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.DurationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.MeterBandStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.meter.band.stats.BandStat;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.meter.band.stats.BandStatBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
+
+public class MultipartReplyMeterStatsDeserializer implements OFDeserializer<MultipartReplyBody> {
+
+    private static final byte PADDING_IN_METER_STATS_HEADER = 6;
+    private static final byte METER_BODY_LENGTH = 40;
+    private static final byte METER_BAND_STATS_LENGTH = 16;
+
+    @Override
+    public MultipartReplyBody deserialize(ByteBuf message) {
+        final MultipartReplyMeterStatsBuilder builder = new MultipartReplyMeterStatsBuilder();
+        final List<MeterStats> items = new ArrayList<>();
+
+        while (message.readableBytes() > 0) {
+            final MeterStatsBuilder itemBuilder = new MeterStatsBuilder()
+                .setMeterId(new MeterId(message.readUnsignedInt()));
+
+            final int itemLength = message.readUnsignedShort();
+            message.skipBytes(PADDING_IN_METER_STATS_HEADER);
+
+            itemBuilder
+                .setFlowCount(new Counter32(message.readUnsignedInt()))
+                .setPacketInCount(new Counter64(BigInteger.valueOf(message.readLong())))
+                .setByteInCount(new Counter64(BigInteger.valueOf(message.readLong())))
+                .setDuration(new DurationBuilder()
+                        .setSecond(new Counter32(message.readUnsignedInt()))
+                        .setNanosecond(new Counter32(message.readUnsignedInt()))
+                        .build());
+
+            final List<BandStat> subItems = new ArrayList<>();
+            int actualLength = METER_BODY_LENGTH;
+
+            while (actualLength < itemLength) {
+                subItems.add(new BandStatBuilder()
+                        .setPacketBandCount(new Counter64(BigInteger.valueOf(message.readLong())))
+                        .setByteBandCount(new Counter64(BigInteger.valueOf(message.readLong())))
+                        .build());
+
+                actualLength += METER_BAND_STATS_LENGTH;
+            }
+
+            items.add(itemBuilder
+                    .setMeterBandStats(new MeterBandStatsBuilder()
+                        .setBandStat(subItems)
+                        .build())
+                    .build());
+        }
+
+        return builder
+            .setMeterStats(items)
+            .build();
+    }
+
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyPortDescDeserializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyPortDescDeserializer.java
new file mode 100644 (file)
index 0000000..c4d47f5
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart;
+
+import io.netty.buffer.ByteBuf;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowjava.util.ByteBufUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortFeatures;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortNumberUni;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.State;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.StateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.multipart.reply.multipart.reply.body.MultipartReplyPortDescBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.multipart.reply.multipart.reply.body.multipart.reply.port.desc.Ports;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.multipart.reply.multipart.reply.body.multipart.reply.port.desc.PortsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
+
+public class MultipartReplyPortDescDeserializer implements OFDeserializer<MultipartReplyBody> {
+
+    private static final byte PADDING_IN_PORT_DESC_HEADER_01 = 4;
+    private static final byte PADDING_IN_PORT_DESC_HEADER_02 = 2;
+
+    @Override
+    public MultipartReplyBody deserialize(ByteBuf message) {
+        final MultipartReplyPortDescBuilder builder = new MultipartReplyPortDescBuilder();
+        final List<Ports> items = new ArrayList<>();
+
+        while (message.readableBytes() > 0) {
+            final PortsBuilder itemBuilder = new PortsBuilder();
+            itemBuilder.setPortNumber(new PortNumberUni(message.readUnsignedInt()));
+            message.skipBytes(PADDING_IN_PORT_DESC_HEADER_01);
+            itemBuilder.setHardwareAddress(ByteBufUtils.readIetfMacAddress(message));
+            message.skipBytes(PADDING_IN_PORT_DESC_HEADER_02);
+
+            items.add(itemBuilder
+                .setName(ByteBufUtils.decodeNullTerminatedString(message, EncodeConstants.MAX_PORT_NAME_LENGTH))
+                .setConfiguration(readPortConfig(message))
+                .setState(readPortState(message))
+                .setCurrentFeature(readPortFeatures(message))
+                .setAdvertisedFeatures(readPortFeatures(message))
+                .setSupported(readPortFeatures(message))
+                .setPeerFeatures(readPortFeatures(message))
+                .setCurrentSpeed(message.readUnsignedInt())
+                .setMaximumSpeed(message.readUnsignedInt())
+                .build());
+        }
+
+        return builder
+            .setPorts(items)
+            .build();
+    }
+
+
+    private static PortConfig readPortConfig(final ByteBuf message) {
+        final long input = message.readUnsignedInt();
+        final Boolean pcPortDown = ((input) & (1)) != 0;
+        final Boolean pcNRecv = ((input) & (1 << 2)) != 0;
+        final Boolean pcNFwd = ((input) & (1 << 5)) != 0;
+        final Boolean pcNPacketIn = ((input) & (1 << 6)) != 0;
+        return new PortConfig(pcNFwd, pcNPacketIn, pcNRecv, pcPortDown);
+    }
+
+    private static State readPortState(final ByteBuf message) {
+        final long input = message.readUnsignedInt();
+        final Boolean psLinkDown = ((input) & (1)) != 0;
+        final Boolean psBlocked = ((input) & (1 << 1)) != 0;
+        final Boolean psLive = ((input) & (1 << 2)) != 0;
+        return new StateBuilder()
+            .setBlocked(psBlocked)
+            .setLinkDown(psLinkDown)
+            .setLive(psLive)
+            .build();
+    }
+
+    private static PortFeatures readPortFeatures(ByteBuf message) {
+        final long input = message.readUnsignedInt();
+        final Boolean pf10mbHd = ((input) & (1)) != 0;
+        final Boolean pf10mbFd = ((input) & (1 << 1)) != 0;
+        final Boolean pf100mbHd = ((input) & (1 << 2)) != 0;
+        final Boolean pf100mbFd = ((input) & (1 << 3)) != 0;
+        final Boolean pf1gbHd = ((input) & (1 << 4)) != 0;
+        final Boolean pf1gbFd = ((input) & (1 << 5)) != 0;
+        final Boolean pf10gbFd = ((input) & (1 << 6)) != 0;
+        final Boolean pf40gbFd = ((input) & (1 << 7)) != 0;
+        final Boolean pf100gbFd = ((input) & (1 << 8)) != 0;
+        final Boolean pf1tbFd = ((input) & (1 << 9)) != 0;
+        final Boolean pfOther = ((input) & (1 << 10)) != 0;
+        final Boolean pfCopper = ((input) & (1 << 11)) != 0;
+        final Boolean pfFiber = ((input) & (1 << 12)) != 0;
+        final Boolean pfAutoneg = ((input) & (1 << 13)) != 0;
+        final Boolean pfPause = ((input) & (1 << 14)) != 0;
+        final Boolean pfPauseAsym = ((input) & (1 << 15)) != 0;
+        return new PortFeatures(pfAutoneg, pfCopper, pfFiber, pf40gbFd,
+            pf100gbFd, pf100mbFd, pf100mbHd, pf1gbFd, pf1gbHd, pf1tbFd,
+            pfOther, pfPause, pfPauseAsym, pf10gbFd, pf10mbFd, pf10mbHd);
+    }
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyPortStatsDeserializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyPortStatsDeserializer.java
new file mode 100644 (file)
index 0000000..34b35b7
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart;
+
+import io.netty.buffer.ByteBuf;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowplugin.openflow.md.util.OpenflowPortsUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter32;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.duration.DurationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.node.connector.statistics.BytesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.node.connector.statistics.PacketsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.multipart.reply.multipart.reply.body.MultipartReplyPortStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMapBuilder;
+
+public class MultipartReplyPortStatsDeserializer implements OFDeserializer<MultipartReplyBody> {
+
+    private static final byte PADDING_IN_PORT_STATS_HEADER = 4;
+
+    @Override
+    public MultipartReplyBody deserialize(ByteBuf message) {
+        final MultipartReplyPortStatsBuilder builder = new MultipartReplyPortStatsBuilder();
+        final List<NodeConnectorStatisticsAndPortNumberMap> items = new ArrayList<>();
+
+        while (message.readableBytes() > 0) {
+            final NodeConnectorStatisticsAndPortNumberMapBuilder itemBuilder =
+                new NodeConnectorStatisticsAndPortNumberMapBuilder();
+
+            final long port = message.readUnsignedInt();
+            final String portName = OpenflowPortsUtil.getPortLogicalName(EncodeConstants.OF13_VERSION_ID, port);
+
+            // We do not assign datapath ID here, because we simply do not have it
+            itemBuilder.setNodeConnectorId(new NodeConnectorId(Objects.isNull(portName)
+                        ? String.valueOf(port)
+                        : portName));
+
+            message.skipBytes(PADDING_IN_PORT_STATS_HEADER);
+
+            items.add(itemBuilder
+                    .setPackets(new PacketsBuilder()
+                        .setReceived(BigInteger.valueOf(message.readLong()))
+                        .setTransmitted(BigInteger.valueOf(message.readLong()))
+                        .build())
+                    .setBytes(new BytesBuilder()
+                        .setReceived(BigInteger.valueOf(message.readLong()))
+                        .setTransmitted(BigInteger.valueOf(message.readLong()))
+                        .build())
+                    .setReceiveDrops(BigInteger.valueOf(message.readLong()))
+                    .setTransmitDrops(BigInteger.valueOf(message.readLong()))
+                    .setReceiveErrors(BigInteger.valueOf(message.readLong()))
+                    .setTransmitErrors(BigInteger.valueOf(message.readLong()))
+                    .setReceiveFrameError(BigInteger.valueOf(message.readLong()))
+                    .setReceiveOverRunError(BigInteger.valueOf((message.readLong())))
+                    .setReceiveCrcError(BigInteger.valueOf((message.readLong())))
+                    .setCollisionCount(BigInteger.valueOf(message.readLong()))
+                    .setDuration(new DurationBuilder()
+                        .setSecond(new Counter32(message.readUnsignedInt()))
+                        .setNanosecond(new Counter32(message.readUnsignedInt()))
+                        .build())
+                    .build());
+        }
+
+        return builder
+            .setNodeConnectorStatisticsAndPortNumberMap(items)
+            .build();
+    }
+
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyQueueStatsDeserializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyQueueStatsDeserializer.java
new file mode 100644 (file)
index 0000000..bb3bc95
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart;
+
+import io.netty.buffer.ByteBuf;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowplugin.openflow.md.util.OpenflowPortsUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter32;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter64;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.duration.DurationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.multipart.reply.multipart.reply.body.MultipartReplyQueueStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMapBuilder;
+
+public class MultipartReplyQueueStatsDeserializer implements OFDeserializer<MultipartReplyBody> {
+
+    @Override
+    public MultipartReplyBody deserialize(ByteBuf message) {
+        final MultipartReplyQueueStatsBuilder builder = new MultipartReplyQueueStatsBuilder();
+        final List<QueueIdAndStatisticsMap> items = new ArrayList<>();
+
+        while (message.readableBytes() > 0) {
+            final long port = message.readUnsignedInt();
+            final String portName = OpenflowPortsUtil.getPortLogicalName(EncodeConstants.OF13_VERSION_ID, port);
+
+            // We do not assign datapath ID here, because we simply do not have it
+            items.add(new QueueIdAndStatisticsMapBuilder()
+                    .setNodeConnectorId(new NodeConnectorId(Objects.isNull(portName)
+                            ? String.valueOf(port)
+                            : portName))
+                    .setQueueId(new QueueId(message.readUnsignedInt()))
+                    .setTransmittedBytes(new Counter64(BigInteger.valueOf(message.readLong())))
+                    .setTransmittedPackets(new Counter64(BigInteger.valueOf(message.readLong())))
+                    .setTransmissionErrors(new Counter64(BigInteger.valueOf(message.readLong())))
+                    .setDuration(new DurationBuilder()
+                        .setSecond(new Counter32(message.readUnsignedInt()))
+                        .setNanosecond(new Counter32(message.readUnsignedInt()))
+                        .build())
+                    .build());
+        }
+
+        return builder
+            .setQueueIdAndStatisticsMap(items)
+            .build();
+    }
+
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyTableFeaturesDeserializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/MultipartReplyTableFeaturesDeserializer.java
new file mode 100644 (file)
index 0000000..5236f21
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart;
+
+import io.netty.buffer.ByteBuf;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistry;
+import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistryInjector;
+import org.opendaylight.openflowjava.protocol.api.extensibility.HeaderDeserializer;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowjava.protocol.impl.util.InstructionConstants;
+import org.opendaylight.openflowjava.util.ByteBufUtils;
+import org.opendaylight.openflowjava.util.ExperimenterDeserializerKeyFactory;
+import org.opendaylight.openflowplugin.api.openflow.protocol.deserialization.MessageCodeExperimenterKey;
+import org.opendaylight.openflowplugin.extension.api.path.ActionPath;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.key.MessageCodeActionExperimenterKey;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.util.ActionUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.TableFeaturesPropType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.service.rev131026.multipart.reply.multipart.reply.body.MultipartReplyTableFeaturesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.set.field.match.SetFieldMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.ApplyActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.ApplyActionsMissBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.ApplySetfieldBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.ApplySetfieldMissBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.InstructionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.InstructionsMissBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.NextTableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.NextTableMissBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.WildcardsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.WriteActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.WriteActionsMissBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.WriteSetfieldBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.WriteSetfieldMissBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.match.MatchSetfieldBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.next.table.TablesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.next.table.miss.TablesMissBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.wildcards.WildcardSetfieldBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.table.features.TableProperties;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.table.features.TablePropertiesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.table.features.table.properties.TableFeatureProperties;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.table.features.table.properties.TableFeaturePropertiesBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MultipartReplyTableFeaturesDeserializer implements OFDeserializer<MultipartReplyBody>, DeserializerRegistryInjector {
+    private static final Logger LOG = LoggerFactory.getLogger(MultipartReplyTableFeaturesDeserializer.class);
+    private static final byte PADDING_IN_MULTIPART_REPLY_TABLE_FEATURES = 5;
+    private static final byte MAX_TABLE_NAME_LENGTH = 32;
+    private static final byte MULTIPART_REPLY_TABLE_FEATURES_STRUCTURE_LENGTH = 64;
+    private static final byte COMMON_PROPERTY_LENGTH = 4;
+    private static final TableFeaturesMatchFieldDeserializer MATCH_FIELD_DESERIALIZER =
+        new TableFeaturesMatchFieldDeserializer();
+
+    private DeserializerRegistry registry;
+
+    @Override
+    public MultipartReplyBody deserialize(ByteBuf message) {
+        final MultipartReplyTableFeaturesBuilder builder = new MultipartReplyTableFeaturesBuilder();
+        final List<TableFeatures> items = new ArrayList<>();
+
+        while (message.readableBytes() > 0) {
+            final int itemLength = message.readUnsignedShort();
+            final TableFeaturesBuilder itemBuilder = new TableFeaturesBuilder()
+                .setTableId(message.readUnsignedByte());
+
+            message.skipBytes(PADDING_IN_MULTIPART_REPLY_TABLE_FEATURES);
+
+            items.add(itemBuilder
+                    .setName(ByteBufUtils.decodeNullTerminatedString(message, MAX_TABLE_NAME_LENGTH))
+                    .setMetadataMatch(BigInteger.valueOf(message.readLong()))
+                    .setMetadataWrite(BigInteger.valueOf(message.readLong()))
+                    .setConfig(readTableConfig(message))
+                    .setMaxEntries(message.readUnsignedInt())
+                    .setTableProperties(readTableProperties(message,
+                            itemLength - MULTIPART_REPLY_TABLE_FEATURES_STRUCTURE_LENGTH))
+                    .build());
+        }
+
+        return builder
+            .setTableFeatures(items)
+            .build();
+    }
+
+    private final TableConfig readTableConfig(ByteBuf message) {
+        final long input = message.readUnsignedInt();
+        final boolean deprecated = (input & 3) != 0;
+
+        return new TableConfig(deprecated);
+    }
+
+    private final TableProperties readTableProperties(ByteBuf message, int length) {
+        final List<TableFeatureProperties> items = new ArrayList<>();
+        int tableFeaturesLength = length;
+
+        while (tableFeaturesLength > 0) {
+            final int propStartIndex = message.readerIndex();
+            final TableFeaturesPropType propType = TableFeaturesPropType.forValue(message.readUnsignedShort());
+            int propertyLength = message.readUnsignedShort();
+            final int paddingRemainder = propertyLength % EncodeConstants.PADDING;
+            tableFeaturesLength -= propertyLength;
+            final int commonPropertyLength = propertyLength - COMMON_PROPERTY_LENGTH;
+            final TableFeaturePropertiesBuilder propBuilder = new TableFeaturePropertiesBuilder();
+
+            switch (propType) {
+                case OFPTFPTINSTRUCTIONS:
+                    propBuilder.setTableFeaturePropType(new InstructionsBuilder()
+                            .setInstructions(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.instructions.InstructionsBuilder()
+                                .setInstruction(readInstructions(message, commonPropertyLength))
+                                .build())
+                            .build());
+                    break;
+                case OFPTFPTINSTRUCTIONSMISS:
+                    propBuilder.setTableFeaturePropType(new InstructionsMissBuilder()
+                            .setInstructionsMiss(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.instructions.miss.InstructionsMissBuilder()
+                                .setInstruction(readInstructions(message, commonPropertyLength))
+                                .build())
+                            .build());
+                    break;
+                case OFPTFPTNEXTTABLES:
+                    propBuilder.setTableFeaturePropType(new NextTableBuilder()
+                            .setTables(new TablesBuilder()
+                                .setTableIds(readNextTableIds(message, commonPropertyLength))
+                                .build())
+                            .build());
+                    break;
+                case OFPTFPTNEXTTABLESMISS:
+                    propBuilder.setTableFeaturePropType(new NextTableMissBuilder()
+                            .setTablesMiss(new TablesMissBuilder()
+                                .setTableIds(readNextTableIds(message, commonPropertyLength))
+                                .build())
+                            .build());
+                    break;
+                case OFPTFPTWRITEACTIONS:
+                    propBuilder.setTableFeaturePropType(new WriteActionsBuilder()
+                            .setWriteActions(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.write.actions.WriteActionsBuilder()
+                                .setAction(readActions(message, commonPropertyLength))
+                                .build())
+                            .build());
+                    break;
+                case OFPTFPTWRITEACTIONSMISS:
+                    propBuilder.setTableFeaturePropType(new WriteActionsMissBuilder()
+                            .setWriteActionsMiss(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.write.actions.miss.WriteActionsMissBuilder()
+                                .setAction(readActions(message, commonPropertyLength))
+                                .build())
+                            .build());
+                    break;
+                case OFPTFPTAPPLYACTIONS:
+                    propBuilder.setTableFeaturePropType(new ApplyActionsBuilder()
+                            .setApplyActions(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.apply.actions.ApplyActionsBuilder()
+                                .setAction(readActions(message, commonPropertyLength))
+                                .build())
+                            .build());
+                    break;
+                case OFPTFPTAPPLYACTIONSMISS:
+                    propBuilder.setTableFeaturePropType(new ApplyActionsMissBuilder()
+                            .setApplyActionsMiss(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.apply.actions.miss.ApplyActionsMissBuilder()
+                                .setAction(readActions(message, commonPropertyLength))
+                                .build())
+                            .build());
+                    break;
+                case OFPTFPTMATCH:
+                    propBuilder.setTableFeaturePropType(new MatchBuilder()
+                            .setMatchSetfield(new MatchSetfieldBuilder()
+                                .setSetFieldMatch(readMatchFields(message, commonPropertyLength))
+                                .build())
+                            .build());
+                    break;
+                case OFPTFPTWILDCARDS:
+                    propBuilder.setTableFeaturePropType(new WildcardsBuilder()
+                            .setWildcardSetfield(new WildcardSetfieldBuilder()
+                                .setSetFieldMatch(readMatchFields(message, commonPropertyLength))
+                                .build())
+                            .build());
+                    break;
+                case OFPTFPTWRITESETFIELD:
+                    propBuilder.setTableFeaturePropType(new WriteSetfieldBuilder()
+                            .setWriteSetfield(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.write.setfield.WriteSetfieldBuilder()
+                                .setSetFieldMatch(readMatchFields(message, commonPropertyLength))
+                                .build())
+                            .build());
+                    break;
+                case OFPTFPTWRITESETFIELDMISS:
+                    propBuilder.setTableFeaturePropType(new WriteSetfieldMissBuilder()
+                            .setWriteSetfieldMiss(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.write.setfield.miss.WriteSetfieldMissBuilder()
+                                .setSetFieldMatch(readMatchFields(message, commonPropertyLength))
+                                .build())
+                            .build());
+                    break;
+                case OFPTFPTAPPLYSETFIELD:
+                    propBuilder.setTableFeaturePropType(new ApplySetfieldBuilder()
+                            .setApplySetfield(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.apply.setfield.ApplySetfieldBuilder()
+                                .setSetFieldMatch(readMatchFields(message, commonPropertyLength))
+                                .build())
+                            .build());
+                    break;
+                case OFPTFPTAPPLYSETFIELDMISS:
+                    propBuilder.setTableFeaturePropType(new ApplySetfieldMissBuilder()
+                            .setApplySetfieldMiss(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.apply.setfield.miss.ApplySetfieldMissBuilder()
+                                .build())
+                            .build());
+                    break;
+                case OFPTFPTEXPERIMENTER:
+                case OFPTFPTEXPERIMENTERMISS:
+                    final long expId = message.readUnsignedInt();
+                    message.readerIndex(propStartIndex);
+
+                    final OFDeserializer<TableFeatureProperties> propDeserializer = registry
+                        .getDeserializer(ExperimenterDeserializerKeyFactory
+                                .createMultipartReplyTFDeserializerKey(EncodeConstants.OF13_VERSION_ID, expId));
+
+                    // TODO: Finish experimenter table features (currently using OFJava deserialization only to skip
+                    // bytes)
+                    propDeserializer.deserialize(message);
+                    LOG.debug("Table feature property type {} is not handled yet.", propType);
+                    break;
+            }
+
+
+            if (paddingRemainder != 0) {
+                message.skipBytes(EncodeConstants.PADDING - paddingRemainder);
+                tableFeaturesLength -= EncodeConstants.PADDING - paddingRemainder;
+            }
+
+            items.add(propBuilder.build());
+        }
+
+
+        return new TablePropertiesBuilder()
+            .setTableFeatureProperties(items)
+            .build();
+    }
+
+    private List<SetFieldMatch> readMatchFields(ByteBuf message, int length) {
+        final List<SetFieldMatch> matchFields = new ArrayList<>();
+
+        final int startIndex = message.readerIndex();
+
+        while ((message.readerIndex() - startIndex) < length) {
+            MATCH_FIELD_DESERIALIZER
+                .deserialize(message)
+                .ifPresent(matchField -> matchFields.add(matchField));
+        }
+
+        return matchFields;
+    }
+
+    private List<Short> readNextTableIds(ByteBuf message, int length) {
+        final List<Short> tableIds = new ArrayList<>();
+
+        while (length > 0) {
+            tableIds.add(message.readUnsignedByte());
+            length--;
+        }
+
+        return tableIds;
+    }
+
+    private List<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list
+            .Instruction> readInstructions(ByteBuf message, int length) {
+
+        final List<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list
+            .Instruction> instructions = new ArrayList<>();
+        final int startIndex = message.readerIndex();
+        int offset = 0;
+
+        while ((message.readerIndex() - startIndex) < length) {
+            final int type = message.getUnsignedShort(message.readerIndex());
+            HeaderDeserializer<Instruction> deserializer = null;
+
+            if (InstructionConstants.APPLY_ACTIONS_TYPE == type) {
+                deserializer = registry.getDeserializer(
+                        new MessageCodeActionExperimenterKey(
+                            EncodeConstants.OF13_VERSION_ID, type, Instruction.class,
+                            ActionPath.NODES_NODE_TABLE_FLOW_INSTRUCTIONS_INSTRUCTION_APPLYACTIONSCASE_APPLYACTIONS_ACTION_ACTION_EXTENSIONLIST_EXTENSION,
+                            null));
+            } else if (InstructionConstants.WRITE_ACTIONS_TYPE == type) {
+                deserializer = registry.getDeserializer(
+                        new MessageCodeActionExperimenterKey(
+                            EncodeConstants.OF13_VERSION_ID, type, Instruction.class,
+                            ActionPath.NODES_NODE_TABLE_FLOW_INSTRUCTIONS_INSTRUCTION_WRITEACTIONSCASE_WRITEACTIONS_ACTION_ACTION_EXTENSIONLIST_EXTENSION,
+                            null));
+            } else {
+                Long expId = null;
+
+                if (EncodeConstants.EXPERIMENTER_VALUE == type) {
+                    expId = message.getUnsignedInt(message.readerIndex() +
+                            2 * EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
+                }
+
+                deserializer = registry.getDeserializer(
+                        new MessageCodeExperimenterKey(
+                            EncodeConstants.OF13_VERSION_ID, type, Instruction.class, expId));
+            }
+
+            instructions.add(new InstructionBuilder()
+                    .setKey(new InstructionKey(offset))
+                    .setOrder(offset)
+                    .setInstruction(deserializer.deserializeHeader(message))
+                    .build());
+
+            offset++;
+        }
+
+        return instructions;
+    }
+
+    private List<Action> readActions(ByteBuf message, int length) {
+        final List<Action> actions = new ArrayList<>();
+        final int startIndex = message.readerIndex();
+        int offset = 0;
+
+        while ((message.readerIndex() - startIndex) < length) {
+            try {
+                actions.add(new ActionBuilder()
+                        .setKey(new ActionKey(offset))
+                        .setOrder(offset)
+                        .setAction(ActionUtil.readActionHeader(EncodeConstants.OF13_VERSION_ID, message, registry,
+                                ActionPath.FLOWSSTATISTICSUPDATE_FLOWANDSTATISTICSMAPLIST_INSTRUCTIONS_INSTRUCTION_INSTRUCTION_APPLYACTIONSCASE_APPLYACTIONS_ACTION_ACTION))
+                        .build());
+
+                offset++;
+            } catch (ClassCastException | IllegalStateException e) {
+                message.skipBytes(2 * EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
+                continue;
+            }
+        }
+
+        return actions;
+    }
+
+    @Override
+    public void injectDeserializerRegistry(DeserializerRegistry deserializerRegistry) {
+        registry = deserializerRegistry;
+    }
+
+}
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/TableFeaturesMatchFieldDeserializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/multipart/TableFeaturesMatchFieldDeserializer.java
new file mode 100644 (file)
index 0000000..c79ac4f
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart;
+
+import com.google.common.collect.ImmutableMap;
+import io.netty.buffer.ByteBuf;
+import java.util.Map;
+import java.util.Optional;
+import org.opendaylight.openflowjava.protocol.api.keys.MatchEntryDeserializerKey;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowjava.protocol.api.util.OxmMatchConstants;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.ArpOp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.ArpSha;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.ArpSpa;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.ArpTha;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.ArpTpa;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.EthDst;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.EthSrc;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.Icmpv4Code;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.Icmpv4Type;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.Icmpv6Code;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.Icmpv6Type;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.InPhyPort;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.InPort;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.IpDscp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.IpEcn;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.IpProto;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.Ipv4Dst;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.Ipv4Src;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.Ipv6Dst;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.Ipv6Exthdr;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.Ipv6Flabel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.Ipv6NdSll;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.Ipv6NdTarget;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.Ipv6NdTll;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.Ipv6Src;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.MatchField;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.Metadata;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.MplsBos;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.MplsLabel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.MplsTc;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.PbbIsid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.SctpDst;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.SctpSrc;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TcpDst;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TcpFlags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TcpSrc;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TunnelId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.UdpDst;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.UdpSrc;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.VlanPcp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.VlanVid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.set.field.match.SetFieldMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.set.field.match.SetFieldMatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.set.field.match.SetFieldMatchKey;
+
+public class TableFeaturesMatchFieldDeserializer {
+
+    /**
+     * Mapping of match entry code to match set field class
+     */
+    private final Map<MatchEntryDeserializerKey, Class<? extends MatchField>> CODE_TO_FIELD = ImmutableMap
+        .<MatchEntryDeserializerKey, Class<? extends MatchField>>builder()
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.ARP_OP), ArpOp.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.ARP_SHA), ArpSha.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.ARP_SPA), ArpSpa.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.ARP_THA), ArpTha.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.ARP_TPA), ArpTpa.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.ETH_DST), EthDst.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.ETH_SRC), EthSrc.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.ICMPV4_CODE), Icmpv4Code.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.ICMPV4_TYPE), Icmpv4Type.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.ICMPV6_CODE), Icmpv6Code.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.ICMPV6_TYPE), Icmpv6Type.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.IN_PHY_PORT), InPhyPort.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.IN_PORT), InPort.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.IP_DSCP), IpDscp.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.IP_ECN), IpEcn.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.IP_PROTO), IpProto.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.IPV4_DST), Ipv4Dst.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.IPV4_SRC), Ipv4Src.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.IPV6_DST), Ipv6Dst.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.IPV6_SRC), Ipv6Src.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.IPV6_EXTHDR), Ipv6Exthdr.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.IPV6_FLABEL), Ipv6Flabel.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.IPV6_ND_SLL), Ipv6NdSll.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.IPV6_ND_TLL), Ipv6NdTll.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.IPV6_ND_TARGET), Ipv6NdTarget.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.METADATA), Metadata.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.MPLS_BOS), MplsBos.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.MPLS_LABEL), MplsLabel.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.MPLS_TC), MplsTc.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.PBB_ISID), PbbIsid.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.SCTP_DST), SctpDst.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.SCTP_SRC), SctpSrc.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.TCP_SRC), TcpSrc.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.TCP_DST), TcpDst.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.TUNNEL_ID), TunnelId.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.UDP_SRC), UdpSrc.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.UDP_DST), UdpDst.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.VLAN_PCP), VlanPcp.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.OPENFLOW_BASIC_CLASS,
+                    OxmMatchConstants.VLAN_VID), VlanVid.class)
+        .put(new MatchEntryDeserializerKey(
+                    EncodeConstants.OF13_VERSION_ID,
+                    OxmMatchConstants.EXPERIMENTER_CLASS,
+                    OxmMatchConstants.NXM_NX_TCP_FLAG), TcpFlags.class)
+        .build();
+
+    /**
+     * Processes match entry header and returns if it have mask, or not
+     * @param in input buffer
+     * @return SetFieldMatchBuilder with hasMask properly set
+     */
+    protected static SetFieldMatchBuilder processHeader(ByteBuf in) {
+        in.skipBytes(EncodeConstants.SIZE_OF_SHORT_IN_BYTES); // skip oxm_class
+        boolean hasMask = (in.readUnsignedByte() & 1) != 0;
+        in.skipBytes(EncodeConstants.SIZE_OF_BYTE_IN_BYTES); // skip match entry length
+
+        return new SetFieldMatchBuilder()
+            .setHasMask(hasMask);
+    }
+
+    /**
+     * Deserialize match field if deserializer supports it, otherwise returns empty optional
+     * @param message input buffer
+     * @return set field match
+     */
+    public Optional<SetFieldMatch> deserialize(ByteBuf message) {
+        int oxmClass = message.getUnsignedShort(message.readerIndex());
+        int oxmField = message.getUnsignedByte(message.readerIndex()
+                + EncodeConstants.SIZE_OF_SHORT_IN_BYTES) >>> 1;
+        Long expId = null;
+
+        if (oxmClass == EncodeConstants.EXPERIMENTER_VALUE) {
+            expId = message.getUnsignedInt(message.readerIndex() + EncodeConstants.SIZE_OF_SHORT_IN_BYTES
+                    + 2 * EncodeConstants.SIZE_OF_BYTE_IN_BYTES);
+        }
+
+        final MatchEntryDeserializerKey key =
+            new MatchEntryDeserializerKey(EncodeConstants.OF13_VERSION_ID, oxmClass, oxmField);
+
+        key.setExperimenterId(expId);
+
+        return Optional
+            .ofNullable(CODE_TO_FIELD.get(key))
+            .map(clazz -> processHeader(message)
+                    .setKey(new SetFieldMatchKey(clazz))
+                    .setMatchType(clazz)
+                    .build());
+    }
+}
index ae24d8ba938b7468763cf363590b9661e54532fd..57adfdb1910a6c0439662b6441c424a75046100e 100644 (file)
@@ -11,6 +11,7 @@ package org.opendaylight.openflowplugin.impl.protocol.deserialization.util;
 import java.util.Objects;
 
 import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistry;
+import org.opendaylight.openflowjava.protocol.api.extensibility.HeaderDeserializer;
 import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
 import org.opendaylight.openflowjava.protocol.api.keys.ActionDeserializerKey;
 import org.opendaylight.openflowjava.protocol.api.keys.ExperimenterActionDeserializerKey;
@@ -55,7 +56,7 @@ public class ActionUtil {
             final OFDeserializer<Action> deserializer = registry.getDeserializer(key);
 
             return deserializer.deserialize(message);
-        } catch (IllegalStateException e) {
+        } catch (ClassCastException | IllegalStateException e) {
             final MessageCodeKey key = Objects.nonNull(expId)
                 ? new ExperimenterActionDeserializerKey(version, expId)
                 : new ActionDeserializerKey(version, type, expId);
@@ -68,4 +69,43 @@ public class ActionUtil {
         }
     }
 
+    /**
+     * Deserialize OpenFlow action header, using extension converter if available
+     * TODO: Remove also extension converters
+     *
+     * @param version OpenFlow version
+     * @param message OpenFlow buffered message
+     * @param registry deserializer registry
+     * @param path Action path
+     */
+    public static Action readActionHeader(short version, ByteBuf message, DeserializerRegistry registry,
+            ActionPath path) {
+        int type = message.getUnsignedShort(message.readerIndex());
+        Long expId = null;
+
+        if (type == EncodeConstants.EXPERIMENTER_VALUE) {
+            expId = message.getUnsignedInt(message.readerIndex()
+                    + 2 * EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
+        }
+
+        try {
+            final MessageCodeExperimenterKey key = new MessageCodeExperimenterKey(
+                version, type, Action.class, expId);
+
+            final HeaderDeserializer<Action> deserializer = registry.getDeserializer(key);
+
+            return deserializer.deserializeHeader(message);
+        } catch (ClassCastException | IllegalStateException e) {
+            final MessageCodeKey key = Objects.nonNull(expId)
+                ? new ExperimenterActionDeserializerKey(version, expId)
+                : new ActionDeserializerKey(version, type, expId);
+
+            final HeaderDeserializer<org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev150203
+                .actions.grouping.Action> deserializer = registry.getDeserializer(key);
+
+            return ActionExtensionHelper.processAlienAction(deserializer.deserializeHeader(message),
+                    OpenflowVersion.get(version), path);
+        }
+    }
+
 }