MRI version bumpup for Aluminium
[netvirt.git] / aclservice / impl / src / main / java / org / opendaylight / netvirt / aclservice / stats / AclLiveStatisticsHelper.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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.netvirt.aclservice.stats;
10
11 import java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.concurrent.ExecutionException;
16 import java.util.concurrent.Future;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
20 import org.opendaylight.genius.mdsalutil.NwConstants;
21 import org.opendaylight.mdsal.binding.api.DataBroker;
22 import org.opendaylight.netvirt.aclservice.utils.AclConstants;
23 import org.opendaylight.netvirt.aclservice.utils.AclServiceUtils;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetFlowStatisticsInputBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetFlowStatisticsOutput;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.OpendaylightDirectStatisticsService;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListKey;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Metadata;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.MetadataBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.acl.live.statistics.rev161129.Direction;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.acl.live.statistics.rev161129.acl.stats.output.AclPortStats;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.acl.live.statistics.rev161129.acl.stats.output.AclPortStatsBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.acl.live.statistics.rev161129.acl.stats.output.acl.port.stats.AclDropStats;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.acl.live.statistics.rev161129.acl.stats.output.acl.port.stats.AclDropStatsBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.acl.live.statistics.rev161129.acl.stats.output.acl.port.stats.ErrorBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.acl.live.statistics.rev161129.acl.stats.output.acl.port.stats.acl.drop.stats.BytesBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.acl.live.statistics.rev161129.acl.stats.output.acl.port.stats.acl.drop.stats.PacketsBuilder;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.opendaylight.yangtools.yang.common.RpcResult;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 /**
54  * The helper class for ACL live statistics.
55  */
56 public final class AclLiveStatisticsHelper {
57
58     private static final Logger LOG = LoggerFactory.getLogger(AclLiveStatisticsHelper.class);
59
60     /** The Constant COOKIE_ACL_DROP_FLOW_MASK. */
61     static final BigInteger COOKIE_ACL_DROP_FLOW_MASK = new BigInteger("FFFFFFFFFFFFFFFF", 16);
62
63     private AclLiveStatisticsHelper() {
64         throw new IllegalStateException("Utility class");
65     }
66
67     /**
68      * Gets the acl port stats.
69      *
70      * @param direction the direction
71      * @param interfaceNames the interface names
72      * @param odlDirectStatsService the odl direct stats service
73      * @param dataBroker the data broker
74      * @return the acl port stats
75      */
76     public static List<AclPortStats> getAclPortStats(Direction direction, @NonNull List<String> interfaceNames,
77             OpendaylightDirectStatisticsService odlDirectStatsService, DataBroker dataBroker) {
78         LOG.trace("Get ACL port stats for direction {} and interfaces {}", direction, interfaceNames);
79         List<AclPortStats> lstAclPortStats = new ArrayList<>();
80
81         FlowCookie aclDropFlowCookieMask = new FlowCookie(COOKIE_ACL_DROP_FLOW_MASK);
82
83         for (String interfaceName : interfaceNames) {
84             AclPortStatsBuilder aclStatsBuilder = new AclPortStatsBuilder().setInterfaceName(interfaceName);
85
86             Interface interfaceState = AclServiceUtils.getInterfaceStateFromOperDS(dataBroker, interfaceName);
87             if (interfaceState == null) {
88                 String errMsg = "Interface not found in datastore.";
89                 addError(lstAclPortStats, aclStatsBuilder, errMsg);
90                 continue;
91             }
92             BigInteger dpId = AclServiceUtils.getDpIdFromIterfaceState(interfaceState);
93             if (dpId == null) {
94                 String errMsg = "Failed to find device for the interface.";
95                 addError(lstAclPortStats, aclStatsBuilder, errMsg);
96                 continue;
97             }
98
99             NodeRef nodeRef = buildNodeRef(dpId);
100             Integer lportTag = interfaceState.getIfIndex();
101             FlowCookie aclDropFlowCookie = new FlowCookie(AclServiceUtils.getDropFlowCookie(lportTag));
102
103             GetFlowStatisticsInputBuilder input =
104                     new GetFlowStatisticsInputBuilder().setNode(nodeRef).setCookie(aclDropFlowCookie)
105                             .setCookieMask(aclDropFlowCookieMask).setStoreStats(false);
106
107             Future<RpcResult<GetFlowStatisticsOutput>> rpcResultFuture =
108                     odlDirectStatsService.getFlowStatistics(input.build());
109             RpcResult<GetFlowStatisticsOutput> rpcResult = null;
110             try {
111                 rpcResult = rpcResultFuture.get();
112             } catch (InterruptedException | ExecutionException e) {
113                 String errMsg = "Unable to retrieve drop counts due to error: " + e.getMessage();
114                 addError(lstAclPortStats, aclStatsBuilder, errMsg);
115                 LOG.error("Exception occurred during get flow statistics for interface {}", interfaceName, e);
116             }
117
118             if (rpcResult != null && rpcResult.isSuccessful() && rpcResult.getResult() != null) {
119                 GetFlowStatisticsOutput flowStatsOutput = rpcResult.getResult();
120                 getAclDropStats(direction, aclStatsBuilder, flowStatsOutput);
121                 lstAclPortStats.add(aclStatsBuilder.build());
122             } else {
123                 handleRpcErrors(lstAclPortStats, aclStatsBuilder, rpcResult);
124             }
125         }
126         return lstAclPortStats;
127     }
128
129     /**
130      * Handle rpc errors.
131      *
132      * @param lstAclPortStats the lst acl port stats
133      * @param aclStatsBuilder the acl stats builder
134      * @param rpcResult the rpc result
135      */
136     private static void handleRpcErrors(List<AclPortStats> lstAclPortStats, AclPortStatsBuilder aclStatsBuilder,
137             @Nullable RpcResult<GetFlowStatisticsOutput> rpcResult) {
138         LOG.error("Unable to retrieve drop counts due to error: {}", rpcResult);
139         String errMsg = "Unable to retrieve drop counts due to error: ";
140         if (rpcResult != null && rpcResult.getErrors() != null && !rpcResult.getErrors().isEmpty()) {
141             errMsg += rpcResult.getErrors().iterator().next().getMessage();
142         } else {
143             errMsg += "Internal RPC call failed.";
144         }
145         addError(lstAclPortStats, aclStatsBuilder, errMsg);
146     }
147
148     /**
149      * Gets the acl drop stats.
150      *
151      * @param direction the direction
152      * @param aclStatsBuilder the acl stats builder
153      * @param flowStatsOutput the flow stats output
154      */
155     private static void getAclDropStats(Direction direction, AclPortStatsBuilder aclStatsBuilder,
156             GetFlowStatisticsOutput flowStatsOutput) {
157         Map<FlowAndStatisticsMapListKey, FlowAndStatisticsMapList> keyFlowAndStatisticsMapListMap
158                 = flowStatsOutput.getFlowAndStatisticsMapList();
159         if (keyFlowAndStatisticsMapListMap == null || keyFlowAndStatisticsMapListMap.isEmpty()) {
160             String errMsg = "Unable to retrieve drop counts as interface is not configured for statistics collection.";
161             aclStatsBuilder.setError(new ErrorBuilder().setErrorMessage(errMsg).build());
162             return;
163         }
164
165         BytesBuilder portEgressBytesBuilder = new BytesBuilder();
166         BytesBuilder portIngressBytesBuilder = new BytesBuilder();
167
168         PacketsBuilder portEgressPacketsBuilder = new PacketsBuilder();
169         PacketsBuilder portIngressPacketsBuilder = new PacketsBuilder();
170
171         for (FlowAndStatisticsMapList flowStats : keyFlowAndStatisticsMapListMap.values()) {
172             switch (flowStats.getTableId().toJava()) {
173                 case NwConstants.INGRESS_ACL_FILTER_CUM_DISPATCHER_TABLE:
174                     if (AclConstants.CT_STATE_TRACKED_INVALID_PRIORITY.equals(flowStats.getPriority().toJava())) {
175                         portEgressBytesBuilder.setInvalidDropCount(flowStats.getByteCount().getValue());
176                         portEgressPacketsBuilder.setInvalidDropCount(flowStats.getPacketCount().getValue());
177                     } else if (AclConstants.ACL_PORT_SPECIFIC_DROP_PRIORITY.equals(flowStats.getPriority().toJava())
178                             || AclConstants.ACE_LAST_REMOTE_ACL_PRIORITY.equals(flowStats.getPriority().toJava())) {
179                         BigInteger portEgressBytesBuilderDropCount = BigInteger.valueOf(0);
180                         BigInteger portEgressPacketsBuilderDropCount = BigInteger.valueOf(0);
181                         if (portEgressBytesBuilder.getDropCount() != null) {
182                             portEgressBytesBuilderDropCount = portEgressBytesBuilder.getDropCount().toJava()
183                                     .add(flowStats.getByteCount().getValue().toJava());
184                             portEgressPacketsBuilderDropCount = portEgressPacketsBuilder.getDropCount().toJava()
185                                     .add(flowStats.getPacketCount().getValue().toJava());
186                         } else {
187                             portEgressBytesBuilderDropCount = flowStats.getByteCount().getValue().toJava();
188                             portEgressPacketsBuilderDropCount = flowStats.getPacketCount().getValue().toJava();
189                         }
190                         portEgressBytesBuilder.setDropCount(portEgressBytesBuilderDropCount);
191                         portEgressPacketsBuilder.setDropCount(portEgressPacketsBuilderDropCount);
192                     }
193                     // TODO: Update stats for other drops
194                     break;
195
196                 case NwConstants.EGRESS_ACL_FILTER_CUM_DISPATCHER_TABLE:
197                     if (AclConstants.CT_STATE_TRACKED_INVALID_PRIORITY.equals(flowStats.getPriority().toJava())) {
198                         portIngressBytesBuilder.setInvalidDropCount(flowStats.getByteCount().getValue());
199                         portIngressPacketsBuilder.setInvalidDropCount(flowStats.getPacketCount().getValue());
200                     } else if (AclConstants.ACL_PORT_SPECIFIC_DROP_PRIORITY.equals(flowStats.getPriority().toJava())
201                             || AclConstants.ACE_LAST_REMOTE_ACL_PRIORITY.equals(flowStats.getPriority().toJava())) {
202                         BigInteger portIngressBytesBuilderDropCount = BigInteger.valueOf(0);
203                         BigInteger portIngressPacketsBuilderDropCount = BigInteger.valueOf(0);
204                         if (portIngressBytesBuilder.getDropCount() != null) {
205                             portIngressBytesBuilderDropCount = portIngressBytesBuilder.getDropCount().toJava()
206                                     .add(flowStats.getByteCount().getValue().toJava());
207                             portIngressPacketsBuilderDropCount = portIngressPacketsBuilder.getDropCount().toJava()
208                                     .add(flowStats.getPacketCount().getValue().toJava());
209                         } else {
210                             portIngressBytesBuilderDropCount = flowStats.getByteCount().getValue().toJava();
211                             portIngressPacketsBuilderDropCount = flowStats.getPacketCount().getValue().toJava();
212                         }
213                         portIngressBytesBuilder.setDropCount(portIngressBytesBuilderDropCount);
214                         portIngressPacketsBuilder.setDropCount(portIngressPacketsBuilderDropCount);
215                     }
216                     // TODO: Update stats for other drops
217                     break;
218                 case NwConstants.INGRESS_ACL_COMMITTER_TABLE:
219                     if (AclConstants.CT_STATE_TRACKED_INVALID_PRIORITY.equals(flowStats.getPriority().toJava())) {
220                         portEgressBytesBuilder.setAntiSpoofDropCount(flowStats.getByteCount().getValue());
221                         portEgressPacketsBuilder.setAntiSpoofDropCount(flowStats.getPacketCount().getValue());
222                     }
223                     break;
224                 case NwConstants.EGRESS_ACL_COMMITTER_TABLE:
225                     if (AclConstants.CT_STATE_TRACKED_INVALID_PRIORITY.equals(flowStats.getPriority().toJava())) {
226                         portIngressBytesBuilder.setAntiSpoofDropCount(flowStats.getByteCount().getValue());
227                         portIngressPacketsBuilder.setAntiSpoofDropCount(flowStats.getPacketCount().getValue());
228                     }
229                     break;
230
231                 default:
232                     LOG.warn("Invalid table ID filtered for Acl flow stats: {}", flowStats);
233                     break;
234             }
235         }
236
237         List<AclDropStats> lstAclDropStats = new ArrayList<>();
238         if (direction == Direction.Egress || direction == Direction.Both) {
239             updateTotalDropCount(portEgressBytesBuilder,portEgressPacketsBuilder);
240             AclDropStats aclEgressDropStats = new AclDropStatsBuilder().setDirection(Direction.Egress)
241                     .setBytes(portEgressBytesBuilder.build()).setPackets(portEgressPacketsBuilder.build()).build();
242             lstAclDropStats.add(aclEgressDropStats);
243         }
244
245         if (direction == Direction.Ingress || direction == Direction.Both) {
246             updateTotalDropCount(portIngressBytesBuilder,portIngressPacketsBuilder);
247             AclDropStats aclIngressDropStats = new AclDropStatsBuilder().setDirection(Direction.Ingress)
248                     .setBytes(portIngressBytesBuilder.build()).setPackets(portIngressPacketsBuilder.build()).build();
249             lstAclDropStats.add(aclIngressDropStats);
250         }
251         aclStatsBuilder.setAclDropStats(lstAclDropStats);
252     }
253
254     private static void updateTotalDropCount(BytesBuilder portBytesBuilder, PacketsBuilder portPacketsBuilder) {
255         BigInteger dropCountByt = BigInteger.ZERO;
256         BigInteger invalidDropCountByt = BigInteger.ZERO;
257         BigInteger antispoofDropCountByt = BigInteger.ZERO;
258         BigInteger dropCountPkt = BigInteger.ZERO;
259         BigInteger invalidDropCountPkt = BigInteger.ZERO;
260         BigInteger antispoofDropCountPkt = BigInteger.ZERO;
261
262         if (portBytesBuilder.getDropCount() != null) {
263             dropCountByt = portBytesBuilder.getDropCount().toJava();
264         }
265         if (portPacketsBuilder.getDropCount() != null) {
266             dropCountPkt = portPacketsBuilder.getDropCount().toJava();
267         }
268         if (portBytesBuilder.getDropCount() != null) {
269             invalidDropCountByt = portBytesBuilder.getInvalidDropCount().toJava();
270         }
271         if (portPacketsBuilder.getDropCount() != null) {
272             invalidDropCountPkt = portPacketsBuilder.getInvalidDropCount().toJava();
273         }
274         if (portBytesBuilder.getDropCount() != null) {
275             antispoofDropCountByt = portBytesBuilder.getAntiSpoofDropCount().toJava();
276         }
277         if (portPacketsBuilder.getDropCount() != null) {
278             antispoofDropCountPkt = portPacketsBuilder.getAntiSpoofDropCount().toJava();
279         }
280         portBytesBuilder.setTotalDropCount(antispoofDropCountByt.add(dropCountByt.add(invalidDropCountByt)));
281         portPacketsBuilder.setTotalDropCount(antispoofDropCountPkt.add(dropCountPkt.add(invalidDropCountPkt)));
282
283     }
284
285     /**
286      * Adds the error.
287      *
288      * @param lstAclPortStats the lst acl port stats
289      * @param aclStatsBuilder the acl stats builder
290      * @param errMsg the error message
291      */
292     private static void addError(List<AclPortStats> lstAclPortStats, AclPortStatsBuilder aclStatsBuilder,
293             String errMsg) {
294         aclStatsBuilder.setError(new ErrorBuilder().setErrorMessage(errMsg).build());
295         lstAclPortStats.add(aclStatsBuilder.build());
296     }
297
298     /**
299      * Builds the metadata match.
300      *
301      * @param lportTag the lport tag
302      * @return the match
303      */
304     protected static Match buildMetadataMatch(Integer lportTag) {
305         Metadata metadata = new MetadataBuilder().setMetadata(MetaDataUtil.getLportTagMetaData(lportTag))
306                 .setMetadataMask(MetaDataUtil.METADATA_MASK_LPORT_TAG).build();
307         return new MatchBuilder().setMetadata(metadata).build();
308     }
309
310     /**
311      * Builds the node ref.
312      *
313      * @param dpId the dp id
314      * @return the node ref
315      */
316     @SuppressWarnings("deprecation")
317     private static NodeRef buildNodeRef(BigInteger dpId) {
318         return new NodeRef(InstanceIdentifier.builder(Nodes.class)
319                 .child(Node.class, new NodeKey(new NodeId("openflow:" + dpId))).build());
320     }
321 }