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 AffinityGroup ag1 = new AffinityGroup("testAG1");
87 AffinityGroup ag2 = new AffinityGroup("testAG2");
90 this.affinityManager.addAffinityGroup(ag1);
91 this.affinityManager.addAffinityGroup(ag2);
92 AffinityLink al = new AffinityLink("testAL", ag1, ag2);
93 this.affinityManager.addAffinityLink(al);
97 void unsetAffinityManager(IAffinityManager a) {
98 if (this.affinityManager.equals(a)) {
99 this.affinityManager = null;
103 void setStatisticsManager(IStatisticsManager s) {
104 this.statisticsManager = s;
107 void unsetStatisticsManager(IStatisticsManager s) {
108 if (this.statisticsManager.equals(s)) {
109 this.statisticsManager = null;
113 void setHostTracker(IfIptoHost h) {
114 this.hostTracker = h;
117 void unsetHostTracker(IfIptoHost h) {
118 if (this.hostTracker.equals(h)) {
119 this.hostTracker = null;
123 /* Returns the destination host associated with this flow, if one
124 * exists. Returns null otherwise.
126 protected Host getDestinationHostFromFlow(Flow flow, Set<HostNodeConnector> hosts) {
127 Match match = flow.getMatch();
128 MatchField dst = null;
130 // Flow has to have DL_DST field or NW_DST field to proceed
131 if (match.isPresent(MatchType.DL_DST)) {
132 dst = match.getField(MatchType.DL_DST);
133 } else if (match.isPresent(MatchType.NW_DST)) {
134 dst = match.getField(MatchType.NW_DST);
140 Host cacheHit = this.destinationHostCache.get(dst);
141 if (cacheHit != null) {
145 // Find the destination host
147 for (HostNodeConnector h : hosts) {
149 // DL_DST => compare on MAC address strings
150 if (match.isPresent(MatchType.DL_DST)) {
151 String dstMac = MatchType.DL_DST.stringify(dst.getValue());
152 String hostMac = ((EthernetAddress) h.getDataLayerAddress()).getMacAddress();
153 if (dstMac.equals(hostMac)) {
155 this.destinationHostCache.put(dst, dstHost); // Add to cache
160 // NW_DST => compare on IP address (of type InetAddress)
161 else if (match.isPresent(MatchType.NW_DST)) {
162 InetAddress hostIP = h.getNetworkAddress();
163 if (dst.getValue().equals(hostIP)) {
165 this.destinationHostCache.put(dst, dstHost); // Add to cache
174 /* Returns the source Host associated with this flow, if one
175 * exists. Returns null otherwise.
177 protected Host getSourceHostFromFlow(Flow flow, Set<HostNodeConnector> hosts) {
180 Match match = flow.getMatch();
182 // Flow must have IN_PORT field (DL_SRC rarely (never?)
184 if (match.isPresent(MatchType.IN_PORT)) {
185 MatchField inPort = match.getField(MatchType.IN_PORT);
188 Host cacheHit = this.sourceHostCache.get(inPort);
189 if (cacheHit != null) {
193 // Find the source host by comparing the NodeConnectors
194 NodeConnector inPortNc = (NodeConnector) inPort.getValue();
195 for (HostNodeConnector h : hosts) {
196 NodeConnector hostNc = h.getnodeConnector();
197 if (hostNc.equals(inPortNc)) {
199 this.sourceHostCache.put(inPort, h); // Add to cache
208 public long getByteCountBetweenHosts(Host src, Host dst) {
211 if (this.hostsToStats.get(src) != null &&
212 this.hostsToStats.get(src).get(dst) != null) {
213 byteCount = this.hostsToStats.get(src).get(dst).getByteCount();
219 public double getBitRateBetweenHosts(Host src, Host dst) {
221 if (this.hostsToStats.get(src) != null &&
222 this.hostsToStats.get(src).get(dst) != null) {
223 bitRate = this.hostsToStats.get(src).get(dst).getBitRate();
229 public double getBitRateOnAffinityLink(AffinityLink al) {
230 // Returns bit rate in *bits-per-second*
231 double maxDuration = 0;
233 List<Entry<Host, Host>> flows = this.affinityManager.getAllFlowsByHost(al);
234 for (Entry<Host, Host> flow : flows) {
235 Host h1 = flow.getKey();
236 Host h2 = flow.getValue();
237 if (this.hostsToStats.get(h1) != null &&
238 this.hostsToStats.get(h1).get(h2) != null) {
239 totalBytes += getByteCountBetweenHosts(h1, h2);
240 double duration = this.hostsToStats.get(h1).get(h2).getDuration();
241 if (duration > maxDuration) {
242 maxDuration = duration;
246 if (maxDuration == 0.0) {
249 return (totalBytes * 8.0) / maxDuration;
253 public long getByteCountOnAffinityLink(AffinityLink al) {
255 List<Entry<Host, Host>> flows = this.affinityManager.getAllFlowsByHost(al);
256 for (Entry<Host, Host> flow : flows) {
257 Host h1 = flow.getKey();
258 Host h2 = flow.getValue();
259 b += getByteCountBetweenHosts(h1, h2);
266 public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList) {
267 Set<HostNodeConnector> allHosts = this.hostTracker.getAllHosts();
269 for (FlowOnNode f : flowStatsList) {
270 Host srcHost = getSourceHostFromFlow(f.getFlow(), allHosts);
271 Host dstHost = getDestinationHostFromFlow(f.getFlow(), allHosts);
273 if (srcHost == null || dstHost == null) {
274 log.debug("Error: source or destination is null in nodeFlowStatisticsUpdated");
278 if (this.hostsToStats.get(srcHost) == null) {
279 this.hostsToStats.put(srcHost, new HashMap<Host, HostStats>());
281 if (this.hostsToStats.get(srcHost).get(dstHost) == null) {
282 this.hostsToStats.get(srcHost).put(dstHost, new HostStats());
284 this.hostsToStats.get(srcHost).get(dstHost).setStatsFromFlow(f);
289 public void nodeConnectorStatisticsUpdated(Node node, List<NodeConnectorStatistics> ncStatsList) {
290 // Not interested in this update
294 public void nodeTableStatisticsUpdated(Node node, List<NodeTableStatistics> tableStatsList) {
295 // Not interested in this update
299 public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription) {
300 // Not interested in this update