4da5136ddef5bc1c832eada629b37147ce0ee911
[affinity.git] / analytics / implementation / src / main / java / org / opendaylight / affinity / analytics / internal / AnalyticsManager.java
1 /*
2  * Copyright (c) 2013 Plexxi, Inc.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.affinity.analytics.internal;
10
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;
17 import java.util.Map;
18 import java.util.Map.Entry;
19 import java.util.Set;
20
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
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;
45
46 public class AnalyticsManager implements IReadServiceListener, IAnalyticsManager {
47
48     private static final Logger log = LoggerFactory.getLogger(AnalyticsManager.class);
49
50     private IAffinityManager affinityManager;
51     private IStatisticsManager statisticsManager;
52     private IfIptoHost hostTracker;
53
54     private Map<MatchField, Host> destinationHostCache;
55     private Map<MatchField, Host> sourceHostCache;
56     private Map<Host, Map<Host, HostStats>> hostsToStats;
57
58     void init() {
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>>();
63     }
64
65     void destroy() {
66         log.debug("DESTROY called!");
67     }
68
69     void start() {
70         log.debug("START called!");
71     }
72
73     void started(){
74     }
75
76     void stop() {
77         log.debug("STOP called!");
78     }
79
80     void setAffinityManager(IAffinityManager a) {
81         this.affinityManager = a;
82
83         // TODO: Testing
84         AffinityGroup ag1 = new AffinityGroup("testAG1");
85         ag1.add("10.0.0.1");
86         //        ag1.add("10.0.0.2");
87         AffinityGroup ag2 = new AffinityGroup("testAG2");
88         ag2.add("10.0.0.3");
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");
96         // TODO: End testing
97     }
98
99     void unsetAffinityManager(IAffinityManager a) {
100         if (this.affinityManager.equals(a)) {
101             this.affinityManager = null;
102         }
103     }
104
105     void setStatisticsManager(IStatisticsManager s) {
106         this.statisticsManager = s;
107     }
108
109     void unsetStatisticsManager(IStatisticsManager s) {
110         if (this.statisticsManager.equals(s)) {
111             this.statisticsManager = null;
112         }
113     }
114
115     void setHostTracker(IfIptoHost h) {
116         this.hostTracker = h;
117     }
118
119     void unsetHostTracker(IfIptoHost h) {
120         if (this.hostTracker.equals(h)) {
121             this.hostTracker = null;
122         }
123     }
124
125     /* Returns the destination host associated with this flow, if one
126      * exists.  Returns null otherwise.
127      */
128     protected Host getDestinationHostFromFlow(Flow flow, Set<HostNodeConnector> hosts) {
129         Match match = flow.getMatch();
130         MatchField dst = null;
131
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);
137         } else { 
138             return null;
139         }
140
141         // Check cache
142         Host cacheHit = this.destinationHostCache.get(dst);
143         if (cacheHit != null) {
144             return cacheHit;
145         }
146
147         // Find the destination host
148         Host dstHost = null;
149         for (HostNodeConnector h : hosts) {
150             
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)) {
156                     dstHost = h;
157                     this.destinationHostCache.put(dst, dstHost); // Add to cache
158                     break;
159                 }
160             }
161           
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)) {
166                     dstHost = h;
167                     this.destinationHostCache.put(dst, dstHost); // Add to cache
168                     break;
169                 }
170             }
171         }
172
173         return dstHost;
174     }
175
176     /* Returns the source Host associated with this flow, if one
177      * exists.  Returns null otherwise.
178      */
179     protected Host getSourceHostFromFlow(Flow flow, Set<HostNodeConnector> hosts) {
180
181         Host srcHost = null;
182         Match match = flow.getMatch();
183
184         // Flow must have IN_PORT field (DL_SRC rarely (never?)
185         // exists).
186         if (match.isPresent(MatchType.IN_PORT)) {
187             MatchField inPort = match.getField(MatchType.IN_PORT);
188
189             // Check cache
190             Host cacheHit = this.sourceHostCache.get(inPort);
191             if (cacheHit != null) {
192                 return cacheHit;
193             }
194
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)) {
200                     srcHost = h;
201                     this.sourceHostCache.put(inPort, h); // Add to cache
202                     break;
203                 }
204             }
205         }
206
207         return srcHost;
208     }
209
210     public long getByteCountBetweenHosts(Host src, Host dst) {
211
212         long byteCount = 0;
213         if (this.hostsToStats.get(src) != null &&
214             this.hostsToStats.get(src).get(dst) != null) {
215             byteCount = this.hostsToStats.get(src).get(dst).getByteCount();
216         }
217
218         return byteCount;
219     }
220
221     public double getBitRateBetweenHosts(Host src, Host dst) {
222         double bitRate = 0;
223         if (this.hostsToStats.get(src) != null &&
224             this.hostsToStats.get(src).get(dst) != null) {
225             bitRate = this.hostsToStats.get(src).get(dst).getBitRate();
226         }
227
228         return bitRate;
229     }
230
231     public double getBitRateOnAffinityLink(AffinityLink al) {
232         // Returns bit rate in *bits-per-second*
233         double maxDuration = 0;
234         int totalBytes = 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;
245                 }
246             }
247         }
248         if (maxDuration == 0.0) {
249             return 0.0;
250         } else {
251             return (totalBytes * 8.0) / maxDuration;
252         }
253     }
254
255     public long getByteCountOnAffinityLink(AffinityLink al) {
256         long b = 0;
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);
262         }
263
264         return b;
265     }
266
267     @Override
268     public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList) {
269         Set<HostNodeConnector> allHosts = this.hostTracker.getAllHosts();
270
271         for (FlowOnNode f : flowStatsList) {
272             Host srcHost = getSourceHostFromFlow(f.getFlow(), allHosts);
273             Host dstHost = getDestinationHostFromFlow(f.getFlow(), allHosts);
274
275             if (srcHost == null || dstHost == null) {
276                 log.debug("Error: source or destination is null in nodeFlowStatisticsUpdated");
277                 continue;
278             }
279
280             if (this.hostsToStats.get(srcHost) == null) {
281                 this.hostsToStats.put(srcHost, new HashMap<Host, HostStats>());
282             }
283             if (this.hostsToStats.get(srcHost).get(dstHost) == null) {
284                 this.hostsToStats.get(srcHost).put(dstHost, new HostStats());
285             }
286             this.hostsToStats.get(srcHost).get(dstHost).setStatsFromFlow(f);
287         }
288     }
289
290     @Override
291     public void nodeConnectorStatisticsUpdated(Node node, List<NodeConnectorStatistics> ncStatsList) {
292         // Not interested in this update
293     }
294
295     @Override
296     public void nodeTableStatisticsUpdated(Node node, List<NodeTableStatistics> tableStatsList) {
297         // Not interested in this update
298     }
299
300     @Override
301     public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription) {
302         // Not interested in this update
303     }
304 }