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