Added AffinityGroups and Links via northbound API
[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
84     void unsetAffinityManager(IAffinityManager a) {
85         if (this.affinityManager.equals(a)) {
86             this.affinityManager = null;
87         }
88     }
89
90     void setStatisticsManager(IStatisticsManager s) {
91         this.statisticsManager = s;
92     }
93
94     void unsetStatisticsManager(IStatisticsManager s) {
95         if (this.statisticsManager.equals(s)) {
96             this.statisticsManager = null;
97         }
98     }
99
100     void setHostTracker(IfIptoHost h) {
101         this.hostTracker = h;
102     }
103
104     void unsetHostTracker(IfIptoHost h) {
105         if (this.hostTracker.equals(h)) {
106             this.hostTracker = null;
107         }
108     }
109
110     /* Returns the destination host associated with this flow, if one
111      * exists.  Returns null otherwise.
112      */
113     protected Host getDestinationHostFromFlow(Flow flow, Set<HostNodeConnector> hosts) {
114         Match match = flow.getMatch();
115         MatchField dst = null;
116
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);
122         } else { 
123             return null;
124         }
125
126         // Check cache
127         Host cacheHit = this.destinationHostCache.get(dst);
128         if (cacheHit != null) {
129             return cacheHit;
130         }
131
132         // Find the destination host
133         Host dstHost = null;
134         for (HostNodeConnector h : hosts) {
135             
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)) {
141                     dstHost = h;
142                     this.destinationHostCache.put(dst, dstHost); // Add to cache
143                     break;
144                 }
145             }
146           
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)) {
151                     dstHost = h;
152                     this.destinationHostCache.put(dst, dstHost); // Add to cache
153                     break;
154                 }
155             }
156         }
157
158         return dstHost;
159     }
160
161     /* Returns the source Host associated with this flow, if one
162      * exists.  Returns null otherwise.
163      */
164     protected Host getSourceHostFromFlow(Flow flow, Set<HostNodeConnector> hosts) {
165
166         Host srcHost = null;
167         Match match = flow.getMatch();
168
169         // Flow must have IN_PORT field (DL_SRC rarely (never?)
170         // exists).
171         if (match.isPresent(MatchType.IN_PORT)) {
172             MatchField inPort = match.getField(MatchType.IN_PORT);
173
174             // Check cache
175             Host cacheHit = this.sourceHostCache.get(inPort);
176             if (cacheHit != null) {
177                 return cacheHit;
178             }
179
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)) {
185                     srcHost = h;
186                     this.sourceHostCache.put(inPort, h); // Add to cache
187                     break;
188                 }
189             }
190         }
191
192         return srcHost;
193     }
194
195     public long getByteCountBetweenHosts(Host src, Host dst) {
196
197         long byteCount = 0;
198         if (this.hostsToStats.get(src) != null &&
199             this.hostsToStats.get(src).get(dst) != null) {
200             byteCount = this.hostsToStats.get(src).get(dst).getByteCount();
201         }
202
203         return byteCount;
204     }
205
206     public double getBitRateBetweenHosts(Host src, Host dst) {
207         double bitRate = 0;
208         if (this.hostsToStats.get(src) != null &&
209             this.hostsToStats.get(src).get(dst) != null) {
210             bitRate = this.hostsToStats.get(src).get(dst).getBitRate();
211         }
212
213         return bitRate;
214     }
215
216     public double getBitRateOnAffinityLink(AffinityLink al) {
217         // Returns bit rate in *bits-per-second*
218         double maxDuration = 0;
219         int totalBytes = 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;
230                 }
231             }
232         }
233         if (maxDuration == 0.0) {
234             return 0.0;
235         } else {
236             return (totalBytes * 8.0) / maxDuration;
237         }
238     }
239
240     public long getByteCountOnAffinityLink(AffinityLink al) {
241         long b = 0;
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);
247         }
248
249         return b;
250     }
251
252     @Override
253     public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList) {
254         Set<HostNodeConnector> allHosts = this.hostTracker.getAllHosts();
255
256         for (FlowOnNode f : flowStatsList) {
257             Host srcHost = getSourceHostFromFlow(f.getFlow(), allHosts);
258             Host dstHost = getDestinationHostFromFlow(f.getFlow(), allHosts);
259
260             if (srcHost == null || dstHost == null) {
261                 log.debug("Error: source or destination is null in nodeFlowStatisticsUpdated");
262                 continue;
263             }
264
265             if (this.hostsToStats.get(srcHost) == null) {
266                 this.hostsToStats.put(srcHost, new HashMap<Host, HostStats>());
267             }
268             if (this.hostsToStats.get(srcHost).get(dstHost) == null) {
269                 this.hostsToStats.get(srcHost).put(dstHost, new HostStats());
270             }
271             this.hostsToStats.get(srcHost).get(dstHost).setStatsFromFlow(f);
272         }
273     }
274
275     @Override
276     public void nodeConnectorStatisticsUpdated(Node node, List<NodeConnectorStatistics> ncStatsList) {
277         // Not interested in this update
278     }
279
280     @Override
281     public void nodeTableStatisticsUpdated(Node node, List<NodeTableStatistics> tableStatsList) {
282         // Not interested in this update
283     }
284
285     @Override
286     public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription) {
287         // Not interested in this update
288     }
289 }