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;
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;
54 * The helper class for ACL live statistics.
56 public final class AclLiveStatisticsHelper {
58 private static final Logger LOG = LoggerFactory.getLogger(AclLiveStatisticsHelper.class);
60 /** The Constant COOKIE_ACL_DROP_FLOW_MASK. */
61 static final BigInteger COOKIE_ACL_DROP_FLOW_MASK = new BigInteger("FFFFFFFFFFFFFFFF", 16);
63 private AclLiveStatisticsHelper() {
64 throw new IllegalStateException("Utility class");
68 * Gets the acl port stats.
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
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<>();
81 FlowCookie aclDropFlowCookieMask = new FlowCookie(COOKIE_ACL_DROP_FLOW_MASK);
83 for (String interfaceName : interfaceNames) {
84 AclPortStatsBuilder aclStatsBuilder = new AclPortStatsBuilder().setInterfaceName(interfaceName);
86 Interface interfaceState = AclServiceUtils.getInterfaceStateFromOperDS(dataBroker, interfaceName);
87 if (interfaceState == null) {
88 String errMsg = "Interface not found in datastore.";
89 addError(lstAclPortStats, aclStatsBuilder, errMsg);
92 BigInteger dpId = AclServiceUtils.getDpIdFromIterfaceState(interfaceState);
94 String errMsg = "Failed to find device for the interface.";
95 addError(lstAclPortStats, aclStatsBuilder, errMsg);
99 NodeRef nodeRef = buildNodeRef(dpId);
100 Integer lportTag = interfaceState.getIfIndex();
101 FlowCookie aclDropFlowCookie = new FlowCookie(AclServiceUtils.getDropFlowCookie(lportTag));
103 GetFlowStatisticsInputBuilder input =
104 new GetFlowStatisticsInputBuilder().setNode(nodeRef).setCookie(aclDropFlowCookie)
105 .setCookieMask(aclDropFlowCookieMask).setStoreStats(false);
107 Future<RpcResult<GetFlowStatisticsOutput>> rpcResultFuture =
108 odlDirectStatsService.getFlowStatistics(input.build());
109 RpcResult<GetFlowStatisticsOutput> rpcResult = null;
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);
118 if (rpcResult != null && rpcResult.isSuccessful() && rpcResult.getResult() != null) {
119 GetFlowStatisticsOutput flowStatsOutput = rpcResult.getResult();
120 getAclDropStats(direction, aclStatsBuilder, flowStatsOutput);
121 lstAclPortStats.add(aclStatsBuilder.build());
123 handleRpcErrors(lstAclPortStats, aclStatsBuilder, rpcResult);
126 return lstAclPortStats;
132 * @param lstAclPortStats the lst acl port stats
133 * @param aclStatsBuilder the acl stats builder
134 * @param rpcResult the rpc result
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();
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 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());
165 BytesBuilder portEgressBytesBuilder = new BytesBuilder();
166 BytesBuilder portIngressBytesBuilder = new BytesBuilder();
168 PacketsBuilder portEgressPacketsBuilder = new PacketsBuilder();
169 PacketsBuilder portIngressPacketsBuilder = new PacketsBuilder();
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());
187 portEgressBytesBuilderDropCount = flowStats.getByteCount().getValue().toJava();
188 portEgressPacketsBuilderDropCount = flowStats.getPacketCount().getValue().toJava();
190 portEgressBytesBuilder.setDropCount(portEgressBytesBuilderDropCount);
191 portEgressPacketsBuilder.setDropCount(portEgressPacketsBuilderDropCount);
193 // TODO: Update stats for other drops
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());
210 portIngressBytesBuilderDropCount = flowStats.getByteCount().getValue().toJava();
211 portIngressPacketsBuilderDropCount = flowStats.getPacketCount().getValue().toJava();
213 portIngressBytesBuilder.setDropCount(portIngressBytesBuilderDropCount);
214 portIngressPacketsBuilder.setDropCount(portIngressPacketsBuilderDropCount);
216 // TODO: Update stats for other drops
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());
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());
232 LOG.warn("Invalid table ID filtered for Acl flow stats: {}", flowStats);
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);
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);
251 aclStatsBuilder.setAclDropStats(lstAclDropStats);
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;
262 if (portBytesBuilder.getDropCount() != null) {
263 dropCountByt = portBytesBuilder.getDropCount().toJava();
265 if (portPacketsBuilder.getDropCount() != null) {
266 dropCountPkt = portPacketsBuilder.getDropCount().toJava();
268 if (portBytesBuilder.getDropCount() != null) {
269 invalidDropCountByt = portBytesBuilder.getInvalidDropCount().toJava();
271 if (portPacketsBuilder.getDropCount() != null) {
272 invalidDropCountPkt = portPacketsBuilder.getInvalidDropCount().toJava();
274 if (portBytesBuilder.getDropCount() != null) {
275 antispoofDropCountByt = portBytesBuilder.getAntiSpoofDropCount().toJava();
277 if (portPacketsBuilder.getDropCount() != null) {
278 antispoofDropCountPkt = portPacketsBuilder.getAntiSpoofDropCount().toJava();
280 portBytesBuilder.setTotalDropCount(antispoofDropCountByt.add(dropCountByt.add(invalidDropCountByt)));
281 portPacketsBuilder.setTotalDropCount(antispoofDropCountPkt.add(dropCountPkt.add(invalidDropCountPkt)));
288 * @param lstAclPortStats the lst acl port stats
289 * @param aclStatsBuilder the acl stats builder
290 * @param errMsg the error message
292 private static void addError(List<AclPortStats> lstAclPortStats, AclPortStatsBuilder aclStatsBuilder,
294 aclStatsBuilder.setError(new ErrorBuilder().setErrorMessage(errMsg).build());
295 lstAclPortStats.add(aclStatsBuilder.build());
299 * Builds the metadata match.
301 * @param lportTag the lport tag
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();
311 * Builds the node ref.
313 * @param dpId the dp id
314 * @return the node ref
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());