Updated experimenter model
[openflowjava.git] / openflow-protocol-impl / src / main / java / org / opendaylight / openflowjava / protocol / impl / deserialization / factories / OF10StatsReplyMessageFactory.java
1 /*
2  * Copyright (c) 2013 Pantheon Technologies s.r.o. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.openflowjava.protocol.impl.deserialization.factories;
10
11 import io.netty.buffer.ByteBuf;
12
13 import java.math.BigInteger;
14 import java.util.ArrayList;
15 import java.util.List;
16
17 import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistry;
18 import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistryInjector;
19 import org.opendaylight.openflowjava.protocol.api.extensibility.MessageCodeKey;
20 import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
21 import org.opendaylight.openflowjava.util.ByteBufUtils;
22 import org.opendaylight.openflowjava.protocol.impl.util.CodeKeyMaker;
23 import org.opendaylight.openflowjava.protocol.impl.util.CodeKeyMakerFactory;
24 import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
25 import org.opendaylight.openflowjava.protocol.impl.util.ListDeserializer;
26 import org.opendaylight.openflowjava.protocol.impl.util.OF10MatchDeserializer;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.actions.grouping.Action;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartRequestFlags;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.match.v10.grouping.MatchV10;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReplyMessage;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReplyMessageBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyAggregateCase;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyAggregateCaseBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyDescCase;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyDescCaseBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyExperimenterCase;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyExperimenterCaseBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyFlowCase;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyFlowCaseBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyPortStatsCase;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyPortStatsCaseBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyQueueCase;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyQueueCaseBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyTableCase;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyTableCaseBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.aggregate._case.MultipartReplyAggregateBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.desc._case.MultipartReplyDescBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.experimenter._case.MultipartReplyExperimenterBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.flow._case.MultipartReplyFlowBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.flow._case.multipart.reply.flow.FlowStats;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.flow._case.multipart.reply.flow.FlowStatsBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.port.stats._case.MultipartReplyPortStatsBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.port.stats._case.multipart.reply.port.stats.PortStats;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.port.stats._case.multipart.reply.port.stats.PortStatsBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.queue._case.MultipartReplyQueueBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.queue._case.multipart.reply.queue.QueueStats;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.queue._case.multipart.reply.queue.QueueStatsBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.table._case.MultipartReplyTableBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.table._case.multipart.reply.table.TableStats;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.table._case.multipart.reply.table.TableStatsBuilder;
62
63 /**
64  * Translates StatsReply messages (OpenFlow v1.0)
65  * @author michal.polkorab
66  */
67 public class OF10StatsReplyMessageFactory implements OFDeserializer<MultipartReplyMessage>,
68         DeserializerRegistryInjector {
69
70     private static final int DESC_STR_LEN = 256;
71     private static final int SERIAL_NUM_LEN = 32;
72     private static final byte PADDING_IN_FLOW_STATS_HEADER = 1;
73     private static final byte PADDING_IN_FLOW_STATS_HEADER_02 = 6;
74     private static final byte PADDING_IN_AGGREGATE_HEADER = 4;
75     private static final byte PADDING_IN_TABLE_HEADER = 3;
76     private static final byte MAX_TABLE_NAME_LENGTH = 32;
77     private static final byte PADDING_IN_PORT_STATS_HEADER = 6;
78     private static final byte PADDING_IN_QUEUE_HEADER = 2;
79     private static final byte LENGTH_OF_FLOW_STATS = 88;
80     private static final int TABLE_STATS_LENGTH = 64;
81     private DeserializerRegistry registry;
82
83     @Override
84     public MultipartReplyMessage deserialize(ByteBuf rawMessage) {
85         MultipartReplyMessageBuilder builder = new MultipartReplyMessageBuilder();
86         builder.setVersion((short) EncodeConstants.OF10_VERSION_ID);
87         builder.setXid(rawMessage.readUnsignedInt());
88         int type = rawMessage.readUnsignedShort();
89         builder.setType(MultipartType.forValue(type));
90         builder.setFlags(new MultipartRequestFlags((rawMessage.readUnsignedShort() & 0x01) != 0));
91         switch (type) {
92         case 0:  builder.setMultipartReplyBody(setDesc(rawMessage));
93             break;
94         case 1:  builder.setMultipartReplyBody(setFlow(rawMessage));
95             break;
96         case 2:  builder.setMultipartReplyBody(setAggregate(rawMessage));
97             break;
98         case 3:  builder.setMultipartReplyBody(setTable(rawMessage));
99             break;         
100         case 4:  builder.setMultipartReplyBody(setPortStats(rawMessage));
101             break;
102         case 5:  builder.setMultipartReplyBody(setQueue(rawMessage));
103             break;         
104         case 0xFFFF: builder.setMultipartReplyBody(setExperimenter(rawMessage));
105             break;
106         default: 
107             break;
108         }
109         return builder.build();
110     }
111     
112     private static MultipartReplyDescCase setDesc(ByteBuf input) {
113         MultipartReplyDescCaseBuilder caseBuilder = new MultipartReplyDescCaseBuilder();
114         MultipartReplyDescBuilder descBuilder = new MultipartReplyDescBuilder();
115         byte[] mfrDescBytes = new byte[DESC_STR_LEN];
116         input.readBytes(mfrDescBytes);
117         String mfrDesc = new String(mfrDescBytes);
118         descBuilder.setMfrDesc(mfrDesc.trim());
119         byte[] hwDescBytes = new byte[DESC_STR_LEN];
120         input.readBytes(hwDescBytes);
121         String hwDesc = new String(hwDescBytes);
122         descBuilder.setHwDesc(hwDesc.trim());
123         byte[] swDescBytes = new byte[DESC_STR_LEN];
124         input.readBytes(swDescBytes);
125         String swDesc = new String(swDescBytes);
126         descBuilder.setSwDesc(swDesc.trim());
127         byte[] serialNumBytes = new byte[SERIAL_NUM_LEN];
128         input.readBytes(serialNumBytes);
129         String serialNum = new String(serialNumBytes);
130         descBuilder.setSerialNum(serialNum.trim());
131         byte[] dpDescBytes = new byte[DESC_STR_LEN];
132         input.readBytes(dpDescBytes);
133         String dpDesc = new String(dpDescBytes);
134         descBuilder.setDpDesc(dpDesc.trim());
135         caseBuilder.setMultipartReplyDesc(descBuilder.build());
136         return caseBuilder.build();
137     }
138     
139     private MultipartReplyFlowCase setFlow(ByteBuf input) {
140         MultipartReplyFlowCaseBuilder caseBuilder = new MultipartReplyFlowCaseBuilder();
141         MultipartReplyFlowBuilder flowBuilder = new MultipartReplyFlowBuilder();
142         List<FlowStats> flowStatsList = new ArrayList<>();
143         while (input.readableBytes() > 0) {
144             FlowStatsBuilder flowStatsBuilder = new FlowStatsBuilder();
145             int length = input.readUnsignedShort();
146             flowStatsBuilder.setTableId(input.readUnsignedByte());
147             input.skipBytes(PADDING_IN_FLOW_STATS_HEADER);
148             OFDeserializer<MatchV10> matchDeserializer = registry.getDeserializer(
149                     new MessageCodeKey(EncodeConstants.OF10_VERSION_ID, EncodeConstants.EMPTY_VALUE, MatchV10.class));
150             flowStatsBuilder.setMatchV10(matchDeserializer.deserialize(input));
151             flowStatsBuilder.setDurationSec(input.readUnsignedInt());
152             flowStatsBuilder.setDurationNsec(input.readUnsignedInt());
153             flowStatsBuilder.setPriority(input.readUnsignedShort());
154             flowStatsBuilder.setIdleTimeout(input.readUnsignedShort());
155             flowStatsBuilder.setHardTimeout(input.readUnsignedShort());
156             input.skipBytes(PADDING_IN_FLOW_STATS_HEADER_02);
157             byte[] cookie = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
158             input.readBytes(cookie);
159             flowStatsBuilder.setCookie(new BigInteger(1, cookie));
160             byte[] packetCount = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
161             input.readBytes(packetCount);
162             flowStatsBuilder.setPacketCount(new BigInteger(1, packetCount));
163             byte[] byteCount = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
164             input.readBytes(byteCount);
165             flowStatsBuilder.setByteCount(new BigInteger(1, byteCount));
166             CodeKeyMaker keyMaker = CodeKeyMakerFactory.createActionsKeyMaker(EncodeConstants.OF10_VERSION_ID);
167             List<Action> actions = ListDeserializer.deserializeList(EncodeConstants.OF10_VERSION_ID,
168                     length - LENGTH_OF_FLOW_STATS, input, keyMaker, registry);
169             flowStatsBuilder.setAction(actions);
170             flowStatsList.add(flowStatsBuilder.build());
171         }
172         flowBuilder.setFlowStats(flowStatsList);
173         caseBuilder.setMultipartReplyFlow(flowBuilder.build());
174         return caseBuilder.build();
175     }
176     
177     private static MultipartReplyAggregateCase setAggregate(ByteBuf input) {
178         MultipartReplyAggregateCaseBuilder caseBuilder = new MultipartReplyAggregateCaseBuilder();
179         MultipartReplyAggregateBuilder builder = new MultipartReplyAggregateBuilder();
180         byte[] packetCount = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
181         input.readBytes(packetCount);
182         builder.setPacketCount(new BigInteger(1, packetCount));
183         byte[] byteCount = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
184         input.readBytes(byteCount);
185         builder.setByteCount(new BigInteger(1, byteCount));
186         builder.setFlowCount(input.readUnsignedInt());
187         input.skipBytes(PADDING_IN_AGGREGATE_HEADER);
188         caseBuilder.setMultipartReplyAggregate(builder.build());
189         return caseBuilder.build();
190     }
191     
192     private static MultipartReplyTableCase setTable(ByteBuf input) {
193         MultipartReplyTableCaseBuilder caseBuilder = new MultipartReplyTableCaseBuilder();
194         MultipartReplyTableBuilder builder = new MultipartReplyTableBuilder();
195         List<TableStats> tableStatsList = new ArrayList<>();
196         // TODO - replace ">= TABLE_STATS_LENGTH" with "> 0" after fix in OVS switch
197         while (input.readableBytes() >= TABLE_STATS_LENGTH) {
198             TableStatsBuilder tableStatsBuilder = new TableStatsBuilder();
199             tableStatsBuilder.setTableId(input.readUnsignedByte());
200             input.skipBytes(PADDING_IN_TABLE_HEADER);
201             tableStatsBuilder.setName(ByteBufUtils.decodeNullTerminatedString(input, MAX_TABLE_NAME_LENGTH));
202             long wildcards = input.readUnsignedInt();
203             tableStatsBuilder.setWildcards(OF10MatchDeserializer.createWildcards(wildcards));
204             tableStatsBuilder.setNwSrcMask(OF10MatchDeserializer.decodeNwSrcMask(wildcards));
205             tableStatsBuilder.setNwDstMask(OF10MatchDeserializer.decodeNwDstMask(wildcards));
206             tableStatsBuilder.setMaxEntries(input.readUnsignedInt());
207             tableStatsBuilder.setActiveCount(input.readUnsignedInt());
208             byte[] lookupCount = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
209             input.readBytes(lookupCount);
210             tableStatsBuilder.setLookupCount(new BigInteger(1, lookupCount));
211             byte[] matchedCount = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
212             input.readBytes(matchedCount);
213             tableStatsBuilder.setMatchedCount(new BigInteger(1, matchedCount));
214             tableStatsList.add(tableStatsBuilder.build());
215         }
216         input.skipBytes(input.readableBytes());
217         builder.setTableStats(tableStatsList);
218         caseBuilder.setMultipartReplyTable(builder.build());
219         return caseBuilder.build();
220     }
221     
222     private static MultipartReplyPortStatsCase setPortStats(ByteBuf input) {
223         MultipartReplyPortStatsCaseBuilder caseBuilder = new MultipartReplyPortStatsCaseBuilder();
224         MultipartReplyPortStatsBuilder builder = new MultipartReplyPortStatsBuilder();
225         List<PortStats> portStatsList = new ArrayList<>();
226         while (input.readableBytes() > 0) {
227             PortStatsBuilder portStatsBuilder = new PortStatsBuilder();
228             portStatsBuilder.setPortNo((long) input.readUnsignedShort());
229             input.skipBytes(PADDING_IN_PORT_STATS_HEADER);
230             byte[] rxPackets = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
231             input.readBytes(rxPackets);
232             portStatsBuilder.setRxPackets(new BigInteger(1, rxPackets));
233             byte[] txPackets = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
234             input.readBytes(txPackets);
235             portStatsBuilder.setTxPackets(new BigInteger(1, txPackets));
236             byte[] rxBytes = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
237             input.readBytes(rxBytes);
238             portStatsBuilder.setRxBytes(new BigInteger(1, rxBytes));
239             byte[] txBytes = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
240             input.readBytes(txBytes);
241             portStatsBuilder.setTxBytes(new BigInteger(1, txBytes));
242             byte[] rxDropped = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
243             input.readBytes(rxDropped);
244             portStatsBuilder.setRxDropped(new BigInteger(1, rxDropped));
245             byte[] txDropped = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
246             input.readBytes(txDropped);
247             portStatsBuilder.setTxDropped(new BigInteger(1, txDropped));
248             byte[] rxErrors = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
249             input.readBytes(rxErrors);
250             portStatsBuilder.setRxErrors(new BigInteger(1, rxErrors));
251             byte[] txErrors = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
252             input.readBytes(txErrors);
253             portStatsBuilder.setTxErrors(new BigInteger(1, txErrors));
254             byte[] rxFrameErr = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
255             input.readBytes(rxFrameErr);
256             portStatsBuilder.setRxFrameErr(new BigInteger(1, rxFrameErr));
257             byte[] rxOverErr = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
258             input.readBytes(rxOverErr);
259             portStatsBuilder.setRxOverErr(new BigInteger(1, rxOverErr));
260             byte[] rxCrcErr = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
261             input.readBytes(rxCrcErr);
262             portStatsBuilder.setRxCrcErr(new BigInteger(1, rxCrcErr));
263             byte[] collisions = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
264             input.readBytes(collisions);
265             portStatsBuilder.setCollisions(new BigInteger(1, collisions));
266             portStatsList.add(portStatsBuilder.build());
267         }
268         builder.setPortStats(portStatsList);
269         caseBuilder.setMultipartReplyPortStats(builder.build());
270         return caseBuilder.build();
271     }
272     
273     private static MultipartReplyQueueCase setQueue(ByteBuf input) {
274         MultipartReplyQueueCaseBuilder caseBuilder = new MultipartReplyQueueCaseBuilder();
275         MultipartReplyQueueBuilder builder = new MultipartReplyQueueBuilder();
276         List<QueueStats> queueStatsList = new ArrayList<>();
277         while (input.readableBytes() > 0) {
278             QueueStatsBuilder queueStatsBuilder = new QueueStatsBuilder();
279             queueStatsBuilder.setPortNo((long) input.readUnsignedShort());
280             input.skipBytes(PADDING_IN_QUEUE_HEADER);
281             queueStatsBuilder.setQueueId(input.readUnsignedInt());
282             byte[] txBytes = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
283             input.readBytes(txBytes);
284             queueStatsBuilder.setTxBytes(new BigInteger(1, txBytes));
285             byte[] txPackets = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
286             input.readBytes(txPackets);
287             queueStatsBuilder.setTxPackets(new BigInteger(1, txPackets));
288             byte[] txErrors = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
289             input.readBytes(txErrors);
290             queueStatsBuilder.setTxErrors(new BigInteger(1, txErrors));
291             queueStatsList.add(queueStatsBuilder.build());
292         }
293         builder.setQueueStats(queueStatsList);
294         caseBuilder.setMultipartReplyQueue(builder.build());
295         return caseBuilder.build();
296     }
297     
298     private static MultipartReplyExperimenterCase setExperimenter(ByteBuf input) {
299         // TODO - implement lookup into registry
300         MultipartReplyExperimenterCaseBuilder caseBuilder = new MultipartReplyExperimenterCaseBuilder();
301         MultipartReplyExperimenterBuilder builder = new MultipartReplyExperimenterBuilder();
302 //        builder.setExperimenter(input.readUnsignedInt());
303 //        byte[] data = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
304 //        input.readBytes(data);
305 //        builder.setData(data);
306         caseBuilder.setMultipartReplyExperimenter(builder.build());
307         return caseBuilder.build();
308     }
309
310     @Override
311     public void injectDeserializerRegistry(DeserializerRegistry deserializerRegistry) {
312         registry = deserializerRegistry;
313     }
314 }