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");
86 // ag1.add("10.0.0.2");
87 AffinityGroup ag2 = new AffinityGroup("testAG2");
89 // ag2.add("10.0.0.4");
90 this.affinityManager.addAffinityGroup(ag1);
91 this.affinityManager.addAffinityGroup(ag2);
92 AffinityLink al = new AffinityLink("testAL", ag1, ag2);
93 this.affinityManager.addAffinityLink(al);
94 al.setAttribute("redirect");
95 al.setWaypoint("10.0.0.4");
99 void unsetAffinityManager(IAffinityManager a) {
100 if (this.affinityManager.equals(a)) {
101 this.affinityManager = null;
105 void setStatisticsManager(IStatisticsManager s) {
106 this.statisticsManager = s;
109 void unsetStatisticsManager(IStatisticsManager s) {
110 if (this.statisticsManager.equals(s)) {
111 this.statisticsManager = null;
115 void setHostTracker(IfIptoHost h) {
116 this.hostTracker = h;
119 void unsetHostTracker(IfIptoHost h) {
120 if (this.hostTracker.equals(h)) {
121 this.hostTracker = null;
125 /* Returns the destination host associated with this flow, if one
126 * exists. Returns null otherwise.
128 protected Host getDestinationHostFromFlow(Flow flow, Set<HostNodeConnector> hosts) {
129 Match match = flow.getMatch();
130 MatchField dst = null;
132 // Flow has to have DL_DST field or NW_DST field to proceed
133 if (match.isPresent(MatchType.DL_DST)) {
134 dst = match.getField(MatchType.DL_DST);
135 } else if (match.isPresent(MatchType.NW_DST)) {
136 dst = match.getField(MatchType.NW_DST);
142 Host cacheHit = this.destinationHostCache.get(dst);
143 if (cacheHit != null) {
147 // Find the destination host
149 for (HostNodeConnector h : hosts) {
151 // DL_DST => compare on MAC address strings
152 if (match.isPresent(MatchType.DL_DST)) {
153 String dstMac = MatchType.DL_DST.stringify(dst.getValue());
154 String hostMac = ((EthernetAddress) h.getDataLayerAddress()).getMacAddress();
155 if (dstMac.equals(hostMac)) {
157 this.destinationHostCache.put(dst, dstHost); // Add to cache
162 // NW_DST => compare on IP address (of type InetAddress)
163 else if (match.isPresent(MatchType.NW_DST)) {
164 InetAddress hostIP = h.getNetworkAddress();
165 if (dst.getValue().equals(hostIP)) {
167 this.destinationHostCache.put(dst, dstHost); // Add to cache
176 /* Returns the source Host associated with this flow, if one
177 * exists. Returns null otherwise.
179 protected Host getSourceHostFromFlow(Flow flow, Set<HostNodeConnector> hosts) {
182 Match match = flow.getMatch();
184 // Flow must have IN_PORT field (DL_SRC rarely (never?)
186 if (match.isPresent(MatchType.IN_PORT)) {
187 MatchField inPort = match.getField(MatchType.IN_PORT);
190 Host cacheHit = this.sourceHostCache.get(inPort);
191 if (cacheHit != null) {
195 // Find the source host by comparing the NodeConnectors
196 NodeConnector inPortNc = (NodeConnector) inPort.getValue();
197 for (HostNodeConnector h : hosts) {
198 NodeConnector hostNc = h.getnodeConnector();
199 if (hostNc.equals(inPortNc)) {
201 this.sourceHostCache.put(inPort, h); // Add to cache
210 public long getByteCountBetweenHosts(Host src, Host dst) {
213 if (this.hostsToStats.get(src) != null &&
214 this.hostsToStats.get(src).get(dst) != null) {
215 byteCount = this.hostsToStats.get(src).get(dst).getByteCount();
221 public double getBitRateBetweenHosts(Host src, Host dst) {
223 if (this.hostsToStats.get(src) != null &&
224 this.hostsToStats.get(src).get(dst) != null) {
225 bitRate = this.hostsToStats.get(src).get(dst).getBitRate();
231 public double getBitRateOnAffinityLink(AffinityLink al) {
232 // Returns bit rate in *bits-per-second*
233 double maxDuration = 0;
235 List<Entry<Host, Host>> flows = this.affinityManager.getAllFlowsByHost(al);
236 for (Entry<Host, Host> flow : flows) {
237 Host h1 = flow.getKey();
238 Host h2 = flow.getValue();
239 if (this.hostsToStats.get(h1) != null &&
240 this.hostsToStats.get(h1).get(h2) != null) {
241 totalBytes += getByteCountBetweenHosts(h1, h2);
242 double duration = this.hostsToStats.get(h1).get(h2).getDuration();
243 if (duration > maxDuration) {
244 maxDuration = duration;
248 if (maxDuration == 0.0) {
251 return (totalBytes * 8.0) / maxDuration;
255 public long getByteCountOnAffinityLink(AffinityLink al) {
257 List<Entry<Host, Host>> flows = this.affinityManager.getAllFlowsByHost(al);
258 for (Entry<Host, Host> flow : flows) {
259 Host h1 = flow.getKey();
260 Host h2 = flow.getValue();
261 b += getByteCountBetweenHosts(h1, h2);
268 public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList) {
269 Set<HostNodeConnector> allHosts = this.hostTracker.getAllHosts();
271 for (FlowOnNode f : flowStatsList) {
272 Host srcHost = getSourceHostFromFlow(f.getFlow(), allHosts);
273 Host dstHost = getDestinationHostFromFlow(f.getFlow(), allHosts);
275 if (srcHost == null || dstHost == null) {
276 log.debug("Error: source or destination is null in nodeFlowStatisticsUpdated");
280 if (this.hostsToStats.get(srcHost) == null) {
281 this.hostsToStats.put(srcHost, new HashMap<Host, HostStats>());
283 if (this.hostsToStats.get(srcHost).get(dstHost) == null) {
284 this.hostsToStats.get(srcHost).put(dstHost, new HostStats());
286 this.hostsToStats.get(srcHost).get(dstHost).setStatsFromFlow(f);
291 public void nodeConnectorStatisticsUpdated(Node node, List<NodeConnectorStatistics> ncStatsList) {
292 // Not interested in this update
296 public void nodeTableStatisticsUpdated(Node node, List<NodeTableStatistics> tableStatsList) {
297 // Not interested in this update
301 public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription) {
302 // Not interested in this update