2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
9 package org.opendaylight.netvirt.aclservice.stats;
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;
51 * The helper class for ACL live statistics.
53 public final class AclLiveStatisticsHelper {
55 private static final Logger LOG = LoggerFactory.getLogger(AclLiveStatisticsHelper.class);
57 /** The Constant COOKIE_ACL_DROP_FLOW_MASK. */
58 static final BigInteger COOKIE_ACL_DROP_FLOW_MASK = new BigInteger("FFFFFFFFFFFFFFFF", 16);
60 private AclLiveStatisticsHelper() {
61 throw new IllegalStateException("Utility class");
65 * Gets the acl port stats.
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
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<>();
78 FlowCookie aclDropFlowCookieMask = new FlowCookie(COOKIE_ACL_DROP_FLOW_MASK);
80 for (String interfaceName : interfaceNames) {
81 AclPortStatsBuilder aclStatsBuilder = new AclPortStatsBuilder().setInterfaceName(interfaceName);
83 Interface interfaceState = AclServiceUtils.getInterfaceStateFromOperDS(dataBroker, interfaceName);
84 if (interfaceState == null) {
85 String errMsg = "Interface not found in datastore.";
86 addError(lstAclPortStats, aclStatsBuilder, errMsg);
89 BigInteger dpId = AclServiceUtils.getDpIdFromIterfaceState(interfaceState);
91 String errMsg = "Failed to find device for the interface.";
92 addError(lstAclPortStats, aclStatsBuilder, errMsg);
96 NodeRef nodeRef = buildNodeRef(dpId);
97 Integer lportTag = interfaceState.getIfIndex();
98 FlowCookie aclDropFlowCookie = new FlowCookie(AclServiceUtils.getDropFlowCookie(lportTag));
100 GetFlowStatisticsInputBuilder input =
101 new GetFlowStatisticsInputBuilder().setNode(nodeRef).setCookie(aclDropFlowCookie)
102 .setCookieMask(aclDropFlowCookieMask).setStoreStats(false);
104 Future<RpcResult<GetFlowStatisticsOutput>> rpcResultFuture =
105 odlDirectStatsService.getFlowStatistics(input.build());
106 RpcResult<GetFlowStatisticsOutput> rpcResult = null;
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);
115 if (rpcResult != null && rpcResult.isSuccessful() && rpcResult.getResult() != null) {
116 GetFlowStatisticsOutput flowStatsOutput = rpcResult.getResult();
117 getAclDropStats(direction, aclStatsBuilder, flowStatsOutput);
118 lstAclPortStats.add(aclStatsBuilder.build());
120 handleRpcErrors(lstAclPortStats, aclStatsBuilder, rpcResult);
123 return lstAclPortStats;
129 * @param lstAclPortStats the lst acl port stats
130 * @param aclStatsBuilder the acl stats builder
131 * @param rpcResult the rpc result
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();
143 errMsg += "Internal RPC call failed.";
145 addError(lstAclPortStats, aclStatsBuilder, errMsg);
149 * Gets the acl drop stats.
151 * @param direction the direction
152 * @param aclStatsBuilder the acl stats builder
153 * @param flowStatsOutput the flow stats output
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());
164 BytesBuilder portEgressBytesBuilder = new BytesBuilder();
165 BytesBuilder portIngressBytesBuilder = new BytesBuilder();
167 PacketsBuilder portEgressPacketsBuilder = new PacketsBuilder();
168 PacketsBuilder portIngressPacketsBuilder = new PacketsBuilder();
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);
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());
188 portEgressBytesBuilderDropCount = flowStats.getByteCount().getValue();
189 portEgressPacketsBuilderDropCount = flowStats.getPacketCount().getValue();
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());
198 portEgressBytesBuilderDropCount = flowStats.getByteCount().getValue();
199 portEgressPacketsBuilderDropCount = flowStats.getPacketCount().getValue();
202 // TODO: Update stats for other drops
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());
216 portIngressBytesBuilderDropCount = flowStats.getByteCount().getValue();
217 portIngressPacketsBuilderDropCount = flowStats.getPacketCount().getValue();
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());
226 portIngressBytesBuilderDropCount = flowStats.getByteCount().getValue();
227 portIngressPacketsBuilderDropCount = flowStats.getPacketCount().getValue();
230 // TODO: Update stats for other drops
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());
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());
246 LOG.warn("Invalid table ID filtered for Acl flow stats: {}", flowStats);
249 portEgressBytesBuilder.setDropCount(portEgressBytesBuilderDropCount);
250 portEgressPacketsBuilder.setDropCount(portEgressPacketsBuilderDropCount);
251 portIngressBytesBuilder.setDropCount(portIngressBytesBuilderDropCount);
252 portIngressPacketsBuilder.setDropCount(portIngressPacketsBuilderDropCount);
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);
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);
269 aclStatsBuilder.setAclDropStats(lstAclDropStats);
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;
280 if (portBytesBuilder.getDropCount() != null) {
281 dropCountByt = portBytesBuilder.getDropCount();
283 if (portPacketsBuilder.getDropCount() != null) {
284 dropCountPkt = portPacketsBuilder.getDropCount();
286 if (portBytesBuilder.getDropCount() != null) {
287 invalidDropCountByt = portBytesBuilder.getInvalidDropCount();
289 if (portPacketsBuilder.getDropCount() != null) {
290 invalidDropCountPkt = portPacketsBuilder.getInvalidDropCount();
292 if (portBytesBuilder.getDropCount() != null) {
293 antispoofDropCountByt = portBytesBuilder.getAntiSpoofDropCount();
295 if (portPacketsBuilder.getDropCount() != null) {
296 antispoofDropCountPkt = portPacketsBuilder.getAntiSpoofDropCount();
298 portBytesBuilder.setTotalDropCount(antispoofDropCountByt.add(dropCountByt.add(invalidDropCountByt)));
299 portPacketsBuilder.setTotalDropCount(antispoofDropCountPkt.add(dropCountPkt.add(invalidDropCountPkt)));
306 * @param lstAclPortStats the lst acl port stats
307 * @param aclStatsBuilder the acl stats builder
308 * @param errMsg the error message
310 private static void addError(List<AclPortStats> lstAclPortStats, AclPortStatsBuilder aclStatsBuilder,
312 aclStatsBuilder.setError(new ErrorBuilder().setErrorMessage(errMsg).build());
313 lstAclPortStats.add(aclStatsBuilder.build());
317 * Builds the metadata match.
319 * @param lportTag the lport tag
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();
329 * Builds the node ref.
331 * @param dpId the dp id
332 * @return the node ref
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());