b7a6359c8f4b024d61de052ab70bc81f5e90c310
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / common / MultipartReplyTranslatorUtil.java
1 /*
2  * Copyright (c) 2017 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 package org.opendaylight.openflowplugin.impl.common;
9
10 import java.util.ArrayList;
11 import java.util.List;
12 import java.util.Map;
13 import java.util.Optional;
14 import java.util.stream.Collectors;
15 import org.eclipse.jdt.annotation.Nullable;
16 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
17 import org.opendaylight.openflowplugin.api.openflow.device.MessageTranslator;
18 import org.opendaylight.openflowplugin.api.openflow.device.TranslatorLibrary;
19 import org.opendaylight.openflowplugin.api.openflow.md.core.TranslatorKey;
20 import org.opendaylight.openflowplugin.api.openflow.md.util.OpenflowVersion;
21 import org.opendaylight.openflowplugin.extension.api.path.MatchPath;
22 import org.opendaylight.openflowplugin.impl.util.GroupUtil;
23 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorExecutor;
24 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.data.FlowStatsResponseConvertorData;
25 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.data.VersionConvertorData;
26 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.data.VersionDatapathIdConvertorData;
27 import org.opendaylight.openflowplugin.openflow.md.util.InventoryDataServiceUtil;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter32;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter64;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.multipart.reply.multipart.reply.body.MultipartReplyDescBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.multipart.reply.multipart.reply.body.MultipartReplyFlowAggregateStats;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.multipart.reply.multipart.reply.body.MultipartReplyFlowAggregateStatsBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.multipart.reply.multipart.reply.body.MultipartReplyFlowStats;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.multipart.reply.multipart.reply.body.MultipartReplyFlowStatsBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMapBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.multipart.reply.multipart.reply.body.MultipartReplyFlowTableStats;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.multipart.reply.multipart.reply.body.MultipartReplyFlowTableStatsBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.multipart.reply.multipart.reply.body.MultipartReplyPortDesc;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.multipart.reply.multipart.reply.body.MultipartReplyPortDescBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.multipart.reply.multipart.reply.body.multipart.reply.port.desc.PortsBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyGroupDescBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyGroupFeaturesBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyGroupStats;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyGroupStatsBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Chaining;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.ChainingChecks;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupAll;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupCapability;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupFf;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupIndirect;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupSelect;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupType;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.SelectLiveness;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.SelectWeight;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyMeterConfigBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyMeterFeaturesBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyMeterStats;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyMeterStatsBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterBand;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterBandDrop;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterBandDscpRemark;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterBurst;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterCapability;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterKbps;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterPktps;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterStats;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.duration.DurationBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.node.connector.statistics.BytesBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.node.connector.statistics.PacketsBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortGrouping;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyAggregateCase;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyDescCase;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyFlowCase;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyGroupCase;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyGroupDescCase;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyGroupFeaturesCase;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyMeterCase;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyMeterConfigCase;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyMeterFeaturesCase;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyPortDescCase;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyPortStatsCase;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyQueueCase;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyTableCase;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyTableFeaturesCase;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.aggregate._case.MultipartReplyAggregate;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.desc._case.MultipartReplyDesc;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.group._case.MultipartReplyGroup;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.group.desc._case.MultipartReplyGroupDesc;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.group.features._case.MultipartReplyGroupFeatures;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.meter._case.MultipartReplyMeter;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.meter.config._case.MultipartReplyMeterConfig;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.meter.features._case.MultipartReplyMeterFeatures;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.port.stats._case.MultipartReplyPortStats;
103 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;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.table.features._case.MultipartReplyTableFeatures;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.multipart.reply.multipart.reply.body.MultipartReplyPortStatsBuilder;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMapBuilder;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.multipart.reply.multipart.reply.body.MultipartReplyQueueStats;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.multipart.reply.multipart.reply.body.MultipartReplyQueueStatsBuilder;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMapBuilder;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableId;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.multipart.reply.multipart.reply.body.MultipartReplyTableFeaturesBuilder;
113 import org.opendaylight.yangtools.yang.binding.util.BindingMap;
114 import org.opendaylight.yangtools.yang.common.Uint64;
115 import org.slf4j.Logger;
116 import org.slf4j.LoggerFactory;
117
118 /**
119  * Class converts multipart reply messages to the objects that can be then written to datastore using
120  * multipart writers.
121  */
122 public final class MultipartReplyTranslatorUtil {
123     private static final Logger LOG = LoggerFactory.getLogger(MultipartReplyTranslatorUtil.class);
124
125     private MultipartReplyTranslatorUtil() {
126         // Hidden on purpose
127     }
128
129     public static Optional<? extends MultipartReplyBody> translate(final OfHeader message, final DeviceInfo deviceInfo,
130             final @Nullable ConvertorExecutor convertorExecutor, final @Nullable TranslatorLibrary translatorLibrary) {
131
132         if (message instanceof MultipartReply) {
133             final MultipartReply msg = (MultipartReply) message;
134             final OpenflowVersion ofVersion = OpenflowVersion.get(deviceInfo.getVersion());
135             final VersionDatapathIdConvertorData data = new VersionDatapathIdConvertorData(deviceInfo.getVersion());
136             data.setDatapathId(deviceInfo.getDatapathId());
137
138             switch (msg.getType()) {
139                 case OFPMPFLOW:
140                     return translateFlow(msg, data, convertorExecutor);
141                 case OFPMPAGGREGATE:
142                     return Optional.of(translateAggregate(msg));
143                 case OFPMPPORTSTATS:
144                     return Optional.of(translatePortStats(msg, ofVersion, deviceInfo.getDatapathId()));
145                 case OFPMPGROUP:
146                     return translateGroup(msg, data, convertorExecutor);
147                 case OFPMPGROUPDESC:
148                     return translateGroupDesc(msg, data, convertorExecutor);
149                 case OFPMPGROUPFEATURES:
150                     return Optional.of(translateGroupFeatures(msg));
151                 case OFPMPMETER:
152                     return translateMeter(msg, data, convertorExecutor);
153                 case OFPMPMETERCONFIG:
154                     return translateMeterConfig(msg, data, convertorExecutor);
155                 case OFPMPMETERFEATURES:
156                     return Optional.of(translateMeterFeatures(msg));
157                 case OFPMPTABLE:
158                     return Optional.of(translateTable(msg));
159                 case OFPMPQUEUE:
160                     return Optional.of(translateQueue(msg, ofVersion, deviceInfo.getDatapathId()));
161                 case OFPMPDESC:
162                     return Optional.of(translateDesc(msg));
163                 case OFPMPTABLEFEATURES:
164                     return translateTableFeatures(msg, deviceInfo.getVersion(), convertorExecutor);
165                 case OFPMPPORTDESC:
166                     return translatePortDesc(msg, deviceInfo, translatorLibrary);
167                 default:
168                     // TODO: log something?
169                     break;
170             }
171         } else if (message instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112
172             .MultipartReply) {
173             return Optional.of(((org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112
174                 .MultipartReply) message).getMultipartReplyBody());
175         }
176
177         LOG.debug("Failed to translate {} for node {}.", message.implementedInterface(), deviceInfo);
178         return Optional.empty();
179     }
180
181     private static Optional<MultipartReplyPortDesc> translatePortDesc(final MultipartReply msg,
182             final DeviceInfo deviceInfo, final TranslatorLibrary translatorLibrary) {
183         if (translatorLibrary == null) {
184             return Optional.empty();
185         }
186
187         return Optional.of(new MultipartReplyPortDescBuilder()
188             .setPorts(((MultipartReplyPortDescCase) msg.getMultipartReplyBody())
189                 .getMultipartReplyPortDesc().nonnullPorts().stream()
190                 .map(port -> {
191                     final MessageTranslator<PortGrouping, FlowCapableNodeConnector> translator =
192                         translatorLibrary .lookupTranslator(new TranslatorKey(deviceInfo.getVersion(),
193                             PortGrouping.class.getName()));
194
195                     return new PortsBuilder(translator.translate(port, deviceInfo, null)).build();
196                 })
197                 .collect(Collectors.toList()))
198             .build());
199     }
200
201     private static Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.multipart.reply
202             .multipart.reply.body.MultipartReplyTableFeatures> translateTableFeatures(final MultipartReply msg,
203                     final short version, final ConvertorExecutor convertorExecutor) {
204         if (convertorExecutor == null) {
205             return Optional.empty();
206         }
207
208         final MultipartReplyTableFeatures multipartReplyTableFeatures =
209             ((MultipartReplyTableFeaturesCase) msg.getMultipartReplyBody()).getMultipartReplyTableFeatures();
210         final Optional<List<org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features
211             .TableFeatures>> tableFeaturesList = convertorExecutor
212             .convert(multipartReplyTableFeatures, new VersionConvertorData(version));
213
214         return Optional.of(new MultipartReplyTableFeaturesBuilder()
215             .setTableFeatures(tableFeaturesList.map(BindingMap::ordered).orElse(Map.of()))
216             .build());
217     }
218
219     private static org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.multipart.reply.multipart
220             .reply.body.MultipartReplyDesc translateDesc(final MultipartReply msg) {
221         final MultipartReplyDesc desc = ((MultipartReplyDescCase) msg.getMultipartReplyBody()).getMultipartReplyDesc();
222
223         return new MultipartReplyDescBuilder()
224             .setDescription(desc.getDpDesc())
225             .setHardware(desc.getHwDesc())
226             .setManufacturer(desc.getMfrDesc())
227             .setSoftware(desc.getSwDesc())
228             .setSerialNumber(desc.getSerialNum())
229             .build();
230     }
231
232     private static Optional<MultipartReplyFlowStats> translateFlow(final MultipartReply msg,
233             final VersionDatapathIdConvertorData data, final ConvertorExecutor convertor) {
234         if (convertor == null) {
235             return Optional.empty();
236         }
237
238         final FlowStatsResponseConvertorData flowData = new FlowStatsResponseConvertorData(data.getVersion());
239         flowData.setDatapathId(data.getDatapathId());
240         flowData.setMatchPath(MatchPath.FLOWS_STATISTICS_UPDATE_MATCH);
241
242         final MultipartReplyFlowCase caseBody = (MultipartReplyFlowCase) msg.getMultipartReplyBody();
243         final Optional<List<FlowAndStatisticsMapList>> flowAndStatisticsMapLists =
244             convertor.convert(caseBody.getMultipartReplyFlow().getFlowStats(), flowData);
245
246         return Optional.of(new MultipartReplyFlowStatsBuilder()
247             .setFlowAndStatisticsMapList(flowAndStatisticsMapLists.orElse(List.of()))
248             .build());
249     }
250
251     private static MultipartReplyFlowAggregateStats translateAggregate(final MultipartReply msg) {
252         final MultipartReplyAggregate replyBody = ((MultipartReplyAggregateCase) msg.getMultipartReplyBody())
253             .getMultipartReplyAggregate();
254
255         return new MultipartReplyFlowAggregateStatsBuilder()
256             .setByteCount(new Counter64(replyBody.getByteCount()))
257             .setPacketCount(new Counter64(replyBody.getPacketCount()))
258             .setFlowCount(new Counter32(replyBody.getFlowCount()))
259             .build();
260     }
261
262     private static org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.multipart.reply.multipart
263             .reply.body.MultipartReplyPortStats translatePortStats(final MultipartReply msg,
264                     final OpenflowVersion ofVersion, final Uint64 datapathId) {
265         MultipartReplyPortStatsCase caseBody = (MultipartReplyPortStatsCase) msg.getMultipartReplyBody();
266         MultipartReplyPortStats replyBody = caseBody.getMultipartReplyPortStats();
267
268         List<NodeConnectorStatisticsAndPortNumberMap> statsMap = new ArrayList<>();
269         for (PortStats portStats : replyBody.nonnullPortStats()) {
270             final DurationBuilder durationBuilder = new DurationBuilder();
271             if (portStats.getDurationSec() != null) {
272                 durationBuilder.setSecond(new Counter32(portStats.getDurationSec()));
273             }
274             if (portStats.getDurationNsec() != null) {
275                 durationBuilder.setNanosecond(new Counter32(portStats.getDurationNsec()));
276             }
277
278             statsMap.add(new NodeConnectorStatisticsAndPortNumberMapBuilder()
279                 .setNodeConnectorId(InventoryDataServiceUtil.nodeConnectorIdfromDatapathPortNo(datapathId,
280                     portStats.getPortNo(), ofVersion))
281                 .setBytes(new BytesBuilder()
282                     .setReceived(portStats.getRxBytes())
283                     .setTransmitted(portStats.getTxBytes())
284                     .build())
285                 .setPackets(new PacketsBuilder()
286                     .setReceived(portStats.getRxPackets())
287                     .setTransmitted(portStats.getTxPackets())
288                     .build())
289                 .setDuration(durationBuilder.build())
290                 .setCollisionCount(portStats.getCollisions())
291                 .setReceiveCrcError(portStats.getRxCrcErr())
292                 .setReceiveDrops(portStats.getRxDropped())
293                 .setReceiveErrors(portStats.getRxErrors())
294                 .setReceiveFrameError(portStats.getRxFrameErr())
295                 .setReceiveOverRunError(portStats.getRxOverErr())
296                 .setTransmitDrops(portStats.getTxDropped())
297                 .setTransmitErrors(portStats.getTxErrors())
298                 .build());
299         }
300
301         return new MultipartReplyPortStatsBuilder()
302             .setNodeConnectorStatisticsAndPortNumberMap(statsMap)
303             .build();
304     }
305
306     private static Optional<MultipartReplyGroupStats> translateGroup(final MultipartReply msg,
307             final VersionDatapathIdConvertorData data, final ConvertorExecutor convertorExecutor) {
308         if (convertorExecutor == null) {
309             return Optional.empty();
310         }
311
312         final MultipartReplyGroup replyBody = ((MultipartReplyGroupCase) msg.getMultipartReplyBody())
313             .getMultipartReplyGroup();
314         final Optional<List<GroupStats>> groupStatsList = convertorExecutor.convert(
315             replyBody.getGroupStats(), data);
316
317         return Optional.of(new MultipartReplyGroupStatsBuilder()
318             .setGroupStats(groupStatsList.map(BindingMap::ordered).orElse(Map.of()))
319             .build());
320     }
321
322     private static Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.multipart.reply
323             .multipart.reply.body.MultipartReplyGroupDesc> translateGroupDesc(final MultipartReply msg,
324                     final VersionDatapathIdConvertorData data, final ConvertorExecutor convertorExecutor) {
325         if (convertorExecutor == null) {
326             return Optional.empty();
327         }
328
329         MultipartReplyGroupDescCase caseBody = (MultipartReplyGroupDescCase) msg.getMultipartReplyBody();
330         MultipartReplyGroupDesc replyBody = caseBody.getMultipartReplyGroupDesc();
331
332         final Optional<List<GroupDescStats>> groupDescStatsList = convertorExecutor.convert(
333             replyBody.getGroupDesc(), data);
334
335         return Optional.of(new MultipartReplyGroupDescBuilder()
336             .setGroupDescStats(groupDescStatsList.map(BindingMap::ordered).orElse(Map.of()))
337             .build());
338     }
339
340     private static org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.multipart.reply.multipart
341             .reply.body.MultipartReplyGroupFeatures translateGroupFeatures(final MultipartReply msg) {
342         final MultipartReplyGroupFeatures replyBody = ((MultipartReplyGroupFeaturesCase) msg.getMultipartReplyBody())
343             .getMultipartReplyGroupFeatures();
344         final List<Class<? extends GroupType>> supportedGroups = new ArrayList<>();
345         if (replyBody.getTypes().getOFPGTALL()) {
346             supportedGroups.add(GroupAll.class);
347         }
348         if (replyBody.getTypes().getOFPGTSELECT()) {
349             supportedGroups.add(GroupSelect.class);
350         }
351         if (replyBody.getTypes().getOFPGTINDIRECT()) {
352             supportedGroups.add(GroupIndirect.class);
353         }
354         if (replyBody.getTypes().getOFPGTFF()) {
355             supportedGroups.add(GroupFf.class);
356         }
357
358         List<Class<? extends GroupCapability>> supportedCapabilities = new ArrayList<>();
359         if (replyBody.getCapabilities().getOFPGFCCHAINING()) {
360             supportedCapabilities.add(Chaining.class);
361         }
362         if (replyBody.getCapabilities().getOFPGFCCHAININGCHECKS()) {
363             supportedCapabilities.add(ChainingChecks.class);
364         }
365         if (replyBody.getCapabilities().getOFPGFCSELECTLIVENESS()) {
366             supportedCapabilities.add(SelectLiveness.class);
367         }
368         if (replyBody.getCapabilities().getOFPGFCSELECTWEIGHT()) {
369             supportedCapabilities.add(SelectWeight.class);
370         }
371
372         return new MultipartReplyGroupFeaturesBuilder()
373             .setGroupTypesSupported(supportedGroups)
374             .setMaxGroups(replyBody.getMaxGroups())
375             .setGroupCapabilitiesSupported(supportedCapabilities)
376             .setActions(GroupUtil.extractGroupActionsSupportBitmap(replyBody.getActionsBitmap()))
377             .build();
378     }
379
380     private static Optional<MultipartReplyMeterStats> translateMeter(final MultipartReply msg,
381             final VersionDatapathIdConvertorData data, final ConvertorExecutor convertorExecutor) {
382         if (convertorExecutor == null) {
383             return Optional.empty();
384         }
385
386         final MultipartReplyMeter replyBody = ((MultipartReplyMeterCase) msg.getMultipartReplyBody())
387             .getMultipartReplyMeter();
388         final Optional<List<
389             org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats>>
390                 meterStatsList = convertorExecutor.convert(replyBody.getMeterStats(), data);
391
392         return Optional.of(new MultipartReplyMeterStatsBuilder()
393             .setMeterStats(meterStatsList.map(BindingMap::ordered).orElse(Map.of()))
394             .build());
395     }
396
397     private static Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.multipart.reply
398             .multipart.reply.body.MultipartReplyMeterConfig> translateMeterConfig(final MultipartReply msg,
399                     final VersionDatapathIdConvertorData data, final ConvertorExecutor convertorExecutor) {
400         if (convertorExecutor == null) {
401             return Optional.empty();
402         }
403
404         MultipartReplyMeterConfigCase caseBody = (MultipartReplyMeterConfigCase) msg.getMultipartReplyBody();
405         MultipartReplyMeterConfig replyBody = caseBody.getMultipartReplyMeterConfig();
406         final Optional<List<MeterConfigStats>> meterConfigStatsList
407                 = convertorExecutor.convert(replyBody.getMeterConfig(), data);
408
409         return Optional.of(new MultipartReplyMeterConfigBuilder()
410             .setMeterConfigStats(meterConfigStatsList.map(BindingMap::ordered).orElse(Map.of()))
411             .build());
412     }
413
414     private static org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.multipart.reply.multipart
415             .reply.body.MultipartReplyMeterFeatures translateMeterFeatures(final MultipartReply msg) {
416         MultipartReplyMeterFeaturesCase caseBody = (MultipartReplyMeterFeaturesCase) msg.getMultipartReplyBody();
417         MultipartReplyMeterFeatures replyBody = caseBody.getMultipartReplyMeterFeatures();
418
419         final List<Class<? extends MeterCapability>> supportedCapabilities = new ArrayList<>();
420         if (replyBody.getCapabilities().getOFPMFBURST()) {
421             supportedCapabilities.add(MeterBurst.class);
422         }
423         if (replyBody.getCapabilities().getOFPMFKBPS()) {
424             supportedCapabilities.add(MeterKbps.class);
425         }
426         if (replyBody.getCapabilities().getOFPMFPKTPS()) {
427             supportedCapabilities.add(MeterPktps.class);
428         }
429         if (replyBody.getCapabilities().getOFPMFSTATS()) {
430             supportedCapabilities.add(MeterStats.class);
431         }
432
433         final List<Class<? extends MeterBand>> supportedMeterBand = new ArrayList<>();
434         if (replyBody.getBandTypes().getOFPMBTDROP()) {
435             supportedMeterBand.add(MeterBandDrop.class);
436         }
437         if (replyBody.getBandTypes().getOFPMBTDSCPREMARK()) {
438             supportedMeterBand.add(MeterBandDscpRemark.class);
439         }
440
441         return new MultipartReplyMeterFeaturesBuilder()
442             .setMaxBands(replyBody.getMaxBands())
443             .setMaxColor(replyBody.getMaxColor())
444             .setMaxMeter(new Counter32(replyBody.getMaxMeter()))
445             .setMeterCapabilitiesSupported(supportedCapabilities)
446             .setMeterBandSupported(supportedMeterBand)
447             .build();
448     }
449
450     private static MultipartReplyFlowTableStats translateTable(final MultipartReply msg) {
451         final var salFlowStats = ((MultipartReplyTableCase) msg.getMultipartReplyBody()).getMultipartReplyTable()
452             .nonnullTableStats().stream()
453             //TODO: Duplicate code: look at OpendaylightFlowTableStatisticsServiceImpl method transformToNotification
454             .map(swTableStats -> new FlowTableAndStatisticsMapBuilder()
455                 .setActiveFlows(new Counter32(swTableStats.getActiveCount()))
456                 .setPacketsLookedUp(new Counter64(swTableStats.getLookupCount()))
457                 .setPacketsMatched(new Counter64(swTableStats.getMatchedCount()))
458                 .setTableId(new TableId(swTableStats.getTableId()))
459                 .build())
460             .collect(BindingMap.toOrderedMap());
461
462         return new MultipartReplyFlowTableStatsBuilder()
463             .setFlowTableAndStatisticsMap(salFlowStats)
464             .build();
465     }
466
467     private static MultipartReplyQueueStats translateQueue(final MultipartReply msg,
468                                                            final OpenflowVersion ofVersion,
469                                                            final Uint64 datapathId) {
470         final var statsMap = ((MultipartReplyQueueCase) msg.getMultipartReplyBody()).getMultipartReplyQueue()
471             .nonnullQueueStats().stream()
472             .map(queueStats -> new QueueIdAndStatisticsMapBuilder()
473                 .setNodeConnectorId(InventoryDataServiceUtil.nodeConnectorIdfromDatapathPortNo(datapathId,
474                     queueStats.getPortNo(), ofVersion))
475                 .setQueueId(new QueueId(queueStats.getQueueId()))
476                 .setTransmissionErrors(new Counter64(queueStats.getTxErrors()))
477                 .setTransmittedBytes(new Counter64(queueStats.getTxBytes()))
478                 .setTransmittedPackets(new Counter64(queueStats.getTxPackets()))
479                 .setDuration(new DurationBuilder()
480                     .setSecond(new Counter32(queueStats.getDurationSec()))
481                     .setNanosecond(new Counter32(queueStats.getDurationNsec()))
482                     .build())
483                 .build())
484             .collect(BindingMap.toOrderedMap());
485
486         return new MultipartReplyQueueStatsBuilder()
487             .setQueueIdAndStatisticsMap(statsMap)
488             .build();
489     }
490 }