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