2 * Copyright (c) 2013 Plexxi, Inc. 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.affinity.analytics.internal;
11 import java.net.InetAddress;
12 import java.net.UnknownHostException;
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.List;
18 import java.util.Map.Entry;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
24 import org.opendaylight.affinity.affinity.AffinityGroup;
25 import org.opendaylight.affinity.affinity.AffinityLink;
26 import org.opendaylight.affinity.affinity.IAffinityManager;
27 import org.opendaylight.affinity.analytics.IAnalyticsManager;
28 import org.opendaylight.controller.hosttracker.IfIptoHost;
29 import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
30 import org.opendaylight.controller.sal.core.Host;
31 import org.opendaylight.controller.sal.core.Node;
32 import org.opendaylight.controller.sal.core.NodeConnector;
33 import org.opendaylight.controller.sal.flowprogrammer.Flow;
34 import org.opendaylight.controller.sal.match.Match;
35 import org.opendaylight.controller.sal.match.MatchField;
36 import org.opendaylight.controller.sal.match.MatchType;
37 import org.opendaylight.controller.sal.packet.address.EthernetAddress;
38 import org.opendaylight.controller.sal.reader.FlowOnNode;
39 import org.opendaylight.controller.sal.reader.IReadServiceListener;
40 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
41 import org.opendaylight.controller.sal.reader.NodeDescription;
42 import org.opendaylight.controller.sal.reader.NodeTableStatistics;
43 import org.opendaylight.controller.sal.utils.Status;
44 import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
46 public class AnalyticsManager implements IReadServiceListener, IAnalyticsManager {
48 private static final Logger log = LoggerFactory.getLogger(AnalyticsManager.class);
50 private IAffinityManager affinityManager;
51 private IStatisticsManager statisticsManager;
52 private IfIptoHost hostTracker;
54 private Map<MatchField, Host> destinationHostCache;
55 private Map<MatchField, Host> sourceHostCache;
56 private Map<Host, Map<Host, HostStats>> hostsToStats;
59 log.debug("INIT called!");
60 this.destinationHostCache = new HashMap<MatchField, Host>();
61 this.sourceHostCache = new HashMap<MatchField, Host>();
62 this.hostsToStats = new HashMap<Host, Map<Host, HostStats>>();
66 log.debug("DESTROY called!");
70 log.debug("START called!");
77 log.debug("STOP called!");
80 void setAffinityManager(IAffinityManager a) {
81 this.affinityManager = a;
84 void unsetAffinityManager(IAffinityManager a) {
85 if (this.affinityManager.equals(a)) {
86 this.affinityManager = null;
90 void setStatisticsManager(IStatisticsManager s) {
91 this.statisticsManager = s;
94 void unsetStatisticsManager(IStatisticsManager s) {
95 if (this.statisticsManager.equals(s)) {
96 this.statisticsManager = null;
100 void setHostTracker(IfIptoHost h) {
101 this.hostTracker = h;
104 void unsetHostTracker(IfIptoHost h) {
105 if (this.hostTracker.equals(h)) {
106 this.hostTracker = null;
110 /* Returns the destination host associated with this flow, if one
111 * exists. Returns null otherwise.
113 protected Host getDestinationHostFromFlow(Flow flow, Set<HostNodeConnector> hosts) {
114 Match match = flow.getMatch();
115 MatchField dst = null;
117 // Flow has to have DL_DST field or NW_DST field to proceed
118 if (match.isPresent(MatchType.DL_DST)) {
119 dst = match.getField(MatchType.DL_DST);
120 } else if (match.isPresent(MatchType.NW_DST)) {
121 dst = match.getField(MatchType.NW_DST);
127 Host cacheHit = this.destinationHostCache.get(dst);
128 if (cacheHit != null) {
132 // Find the destination host
134 for (HostNodeConnector h : hosts) {
136 // DL_DST => compare on MAC address strings
137 if (match.isPresent(MatchType.DL_DST)) {
138 String dstMac = MatchType.DL_DST.stringify(dst.getValue());
139 String hostMac = ((EthernetAddress) h.getDataLayerAddress()).getMacAddress();
140 if (dstMac.equals(hostMac)) {
142 this.destinationHostCache.put(dst, dstHost); // Add to cache
147 // NW_DST => compare on IP address (of type InetAddress)
148 else if (match.isPresent(MatchType.NW_DST)) {
149 InetAddress hostIP = h.getNetworkAddress();
150 if (dst.getValue().equals(hostIP)) {
152 this.destinationHostCache.put(dst, dstHost); // Add to cache
161 /* Returns the source Host associated with this flow, if one
162 * exists. Returns null otherwise.
164 protected Host getSourceHostFromFlow(Flow flow, Set<HostNodeConnector> hosts) {
167 Match match = flow.getMatch();
169 // Flow must have IN_PORT field (DL_SRC rarely (never?)
171 if (match.isPresent(MatchType.IN_PORT)) {
172 MatchField inPort = match.getField(MatchType.IN_PORT);
175 Host cacheHit = this.sourceHostCache.get(inPort);
176 if (cacheHit != null) {
180 // Find the source host by comparing the NodeConnectors
181 NodeConnector inPortNc = (NodeConnector) inPort.getValue();
182 for (HostNodeConnector h : hosts) {
183 NodeConnector hostNc = h.getnodeConnector();
184 if (hostNc.equals(inPortNc)) {
186 this.sourceHostCache.put(inPort, h); // Add to cache
195 public long getByteCountBetweenHosts(Host src, Host dst) {
198 if (this.hostsToStats.get(src) != null &&
199 this.hostsToStats.get(src).get(dst) != null) {
200 byteCount = this.hostsToStats.get(src).get(dst).getByteCount();
206 public double getBitRateBetweenHosts(Host src, Host dst) {
208 if (this.hostsToStats.get(src) != null &&
209 this.hostsToStats.get(src).get(dst) != null) {
210 bitRate = this.hostsToStats.get(src).get(dst).getBitRate();
216 public double getBitRateOnAffinityLink(AffinityLink al) {
217 // Returns bit rate in *bits-per-second*
218 double maxDuration = 0;
220 List<Entry<Host, Host>> flows = this.affinityManager.getAllFlowsByHost(al);
221 for (Entry<Host, Host> flow : flows) {
222 Host h1 = flow.getKey();
223 Host h2 = flow.getValue();
224 if (this.hostsToStats.get(h1) != null &&
225 this.hostsToStats.get(h1).get(h2) != null) {
226 totalBytes += getByteCountBetweenHosts(h1, h2);
227 double duration = this.hostsToStats.get(h1).get(h2).getDuration();
228 if (duration > maxDuration) {
229 maxDuration = duration;
233 if (maxDuration == 0.0) {
236 return (totalBytes * 8.0) / maxDuration;
240 public long getByteCountOnAffinityLink(AffinityLink al) {
242 List<Entry<Host, Host>> flows = this.affinityManager.getAllFlowsByHost(al);
243 for (Entry<Host, Host> flow : flows) {
244 Host h1 = flow.getKey();
245 Host h2 = flow.getValue();
246 b += getByteCountBetweenHosts(h1, h2);
253 public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList) {
254 Set<HostNodeConnector> allHosts = this.hostTracker.getAllHosts();
256 for (FlowOnNode f : flowStatsList) {
257 Host srcHost = getSourceHostFromFlow(f.getFlow(), allHosts);
258 Host dstHost = getDestinationHostFromFlow(f.getFlow(), allHosts);
260 if (srcHost == null || dstHost == null) {
261 log.debug("Error: source or destination is null in nodeFlowStatisticsUpdated");
265 if (this.hostsToStats.get(srcHost) == null) {
266 this.hostsToStats.put(srcHost, new HashMap<Host, HostStats>());
268 if (this.hostsToStats.get(srcHost).get(dstHost) == null) {
269 this.hostsToStats.get(srcHost).put(dstHost, new HostStats());
271 this.hostsToStats.get(srcHost).get(dstHost).setStatsFromFlow(f);
276 public void nodeConnectorStatisticsUpdated(Node node, List<NodeConnectorStatistics> ncStatsList) {
277 // Not interested in this update
281 public void nodeTableStatisticsUpdated(Node node, List<NodeTableStatistics> tableStatsList) {
282 // Not interested in this update
286 public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription) {
287 // Not interested in this update