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