blob: b819eb7fe887bb28977d29895510a832e8bb05d2 [file] [log] [blame]
Ayaka Koshibe422916f2015-01-15 15:30:23 -08001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.provider.nil.link.impl;
17
Ayaka Koshibe13f896f2015-03-10 15:01:44 -070018import com.google.common.collect.HashMultimap;
Ayaka Koshibe9209ea22015-03-09 10:57:50 -070019import com.google.common.collect.Lists;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080020import com.google.common.collect.Maps;
21import com.google.common.collect.Sets;
Ayaka Koshibe839a8a92015-03-03 17:07:22 -080022
Ayaka Koshibe422916f2015-01-15 15:30:23 -080023import org.apache.felix.scr.annotations.Activate;
24import org.apache.felix.scr.annotations.Component;
25import org.apache.felix.scr.annotations.Deactivate;
Ayaka Koshibe7dc1d042015-01-21 15:28:03 -080026import org.apache.felix.scr.annotations.Modified;
Ayaka Koshibe422916f2015-01-15 15:30:23 -080027import org.apache.felix.scr.annotations.Property;
28import org.apache.felix.scr.annotations.Reference;
29import org.apache.felix.scr.annotations.ReferenceCardinality;
Thomas Vachuska6519e6f2015-03-11 02:29:31 -070030import org.onosproject.cfg.ComponentConfigService;
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -080031import org.onosproject.cluster.ClusterService;
32import org.onosproject.cluster.NodeId;
Ayaka Koshibe0cd42822015-01-22 16:02:31 -080033import org.onosproject.mastership.MastershipService;
Ayaka Koshibe422916f2015-01-15 15:30:23 -080034import org.onosproject.net.ConnectPoint;
35import org.onosproject.net.Device;
36import org.onosproject.net.DeviceId;
Ayaka Koshibe422916f2015-01-15 15:30:23 -080037import org.onosproject.net.PortNumber;
38import org.onosproject.net.device.DeviceEvent;
39import org.onosproject.net.device.DeviceListener;
40import org.onosproject.net.device.DeviceService;
41import org.onosproject.net.link.DefaultLinkDescription;
42import org.onosproject.net.link.LinkDescription;
43import org.onosproject.net.link.LinkProvider;
44import org.onosproject.net.link.LinkProviderRegistry;
45import org.onosproject.net.link.LinkProviderService;
46import org.onosproject.net.provider.AbstractProvider;
47import org.onosproject.net.provider.ProviderId;
48import org.osgi.service.component.ComponentContext;
49import org.slf4j.Logger;
50
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080051import java.util.Dictionary;
Ayaka Koshibe9209ea22015-03-09 10:57:50 -070052import java.util.Iterator;
53import java.util.List;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080054import java.util.Set;
55import java.util.concurrent.ConcurrentMap;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080056import java.util.concurrent.Executors;
Ayaka Koshibe9209ea22015-03-09 10:57:50 -070057import java.util.concurrent.ScheduledExecutorService;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080058import java.util.concurrent.TimeUnit;
Ayaka Koshibe839a8a92015-03-03 17:07:22 -080059import java.io.BufferedReader;
60import java.io.FileReader;
61import java.io.IOException;
62import java.net.URI;
63import java.net.URISyntaxException;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080064
65import static com.google.common.base.Strings.isNullOrEmpty;
66import static org.onlab.util.Tools.groupedThreads;
67import static org.onlab.util.Tools.toHex;
68import static org.onosproject.net.MastershipRole.MASTER;
Ayaka Koshibe839a8a92015-03-03 17:07:22 -080069import static org.onosproject.net.Link.Type.DIRECT;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080070import static org.slf4j.LoggerFactory.getLogger;
Ayaka Koshibe422916f2015-01-15 15:30:23 -080071
72/**
73 * Provider which advertises fake/nonexistent links to the core. To be used for
74 * benchmarking only.
Ayaka Koshibe839a8a92015-03-03 17:07:22 -080075 *
76 * This provider takes a topology graph file with a DOT-like syntax.
Ayaka Koshibe422916f2015-01-15 15:30:23 -080077 */
78@Component(immediate = true)
79public class NullLinkProvider extends AbstractProvider implements LinkProvider {
80
81 private final Logger log = getLogger(getClass());
82
Ayaka Koshibe9209ea22015-03-09 10:57:50 -070083 // default topology file location and name.
Ayaka Koshibe839a8a92015-03-03 17:07:22 -080084 private static final String CFG_PATH = "/opt/onos/apache-karaf-3.0.2/etc/linkGraph.cfg";
Ayaka Koshibe9209ea22015-03-09 10:57:50 -070085 // default number of workers. Eventually make this tunable
86 private static final int THREADS = 8;
Ayaka Koshibe839a8a92015-03-03 17:07:22 -080087
88 private static final int CHECK_DURATION = 10;
Ayaka Koshibe9209ea22015-03-09 10:57:50 -070089 private static final int DEFAULT_RATE = 0; // usec
90 private static final int REFRESH_RATE = 3; // sec
Ayaka Koshibe13f896f2015-03-10 15:01:44 -070091 private static final DeviceId DEFAULT = DeviceId.deviceId("null:ffffffffffffffff");
Ayaka Koshibe839a8a92015-03-03 17:07:22 -080092
Ayaka Koshibe422916f2015-01-15 15:30:23 -080093 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected DeviceService deviceService;
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ayaka Koshibe0cd42822015-01-22 16:02:31 -080097 protected MastershipService roleService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800100 protected ClusterService nodeService;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800103 protected LinkProviderRegistry providerRegistry;
104
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected ComponentConfigService cfgService;
107
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800108 private LinkProviderService providerService;
109
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800110 private final InternalLinkProvider linkProvider = new InternalLinkProvider();
111
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800112 // True for device with Driver, false otherwise.
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700113 private final ConcurrentMap<DeviceId, Set<LinkDriver>> driverMap = Maps
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800114 .newConcurrentMap();
115
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800116 // Link descriptions
Ayaka Koshibe13f896f2015-03-10 15:01:44 -0700117 private final List<LinkDescription> linkDescrs = Lists.newArrayList();
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800118
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700119 // Thread to description map
Ayaka Koshibe13f896f2015-03-10 15:01:44 -0700120 private final List<List<LinkDescription>> linkTasks = Lists.newArrayList();
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700121
122 private ScheduledExecutorService linkDriver =
123 Executors.newScheduledThreadPool(THREADS, groupedThreads("onos/null", "link-driver-%d"));
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800124
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800125 // For flicker = true, duration between events in msec.
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700126 @Property(name = "eventRate", intValue = 0, label = "Duration between Link Event")
Ayaka Koshibe0cd42822015-01-22 16:02:31 -0800127 private int eventRate = DEFAULT_RATE;
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800128
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800129 // topology configuration file
130 @Property(name = "cfgFile",
131 value = "/opt/onos/apache-karaf-3.0.2/etc/linkGraph.cfg",
132 label = "Topology file location")
133 private String cfgFile = CFG_PATH;
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800134
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800135 // flag checked to create a LinkDriver, if rate is non-zero.
136 private boolean flicker = false;
137
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800138 public NullLinkProvider() {
139 super(new ProviderId("null", "org.onosproject.provider.nil"));
140 }
141
142 @Activate
143 public void activate(ComponentContext context) {
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700144 cfgService.registerProperties(getClass());
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800145 providerService = providerRegistry.register(this);
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800146 modified(context);
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800147
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700148 if (flicker) {
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700149 for (int i = 0; i < linkTasks.size(); i++) {
Ayaka Koshibe13f896f2015-03-10 15:01:44 -0700150 List<LinkDescription> links = linkTasks.get(i);
151 LinkDriver driver = new LinkDriver(links);
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700152 links.forEach(v -> {
153 DeviceId d = v.src().deviceId();
154 Set<LinkDriver> s = driverMap.getOrDefault(d, Sets.newConcurrentHashSet());
155 s.add(driver);
156 driverMap.put(d, s);
157 });
158 try {
159 linkDriver.schedule(driver, eventRate, TimeUnit.MICROSECONDS);
160 } catch (Exception e) {
161 log.warn(e.getMessage());
162 }
163 }
164 } else {
Ayaka Koshibe13f896f2015-03-10 15:01:44 -0700165 LinkDriver driver = new LinkDriver(linkDescrs);
166 driverMap.put(DEFAULT, Sets.newHashSet(driver));
167 linkDriver.schedule(driver, 3, TimeUnit.SECONDS);
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700168 }
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800169 log.info("started");
170 }
171
172 @Deactivate
173 public void deactivate(ComponentContext context) {
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700174 cfgService.unregisterProperties(getClass(), false);
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800175 linkDriver.shutdown();
176 try {
177 linkDriver.awaitTermination(1000, TimeUnit.MILLISECONDS);
178 } catch (InterruptedException e) {
179 log.error("LinkBuilder did not terminate");
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800180 linkDriver.shutdownNow();
181 }
182 deviceService.removeListener(linkProvider);
183 providerRegistry.unregister(this);
184 deviceService = null;
185
186 log.info("stopped");
187 }
188
Ayaka Koshibe7dc1d042015-01-21 15:28:03 -0800189 @Modified
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800190 public void modified(ComponentContext context) {
191 if (context == null) {
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800192 log.info("No configs, using defaults: eventRate={}", DEFAULT_RATE);
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800193 return;
194 }
195 Dictionary<?, ?> properties = context.getProperties();
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800196 int newRate;
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800197 String newPath;
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800198 try {
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800199 String s = (String) properties.get("eventRate");
Yuta HIGUCHIdd9228d2015-02-10 22:26:59 -0800200 newRate = isNullOrEmpty(s) ? eventRate : Integer.parseInt(s.trim());
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800201 s = (String) properties.get("cfgFile");
202 newPath = s.trim();
Pavlin Radoslavovb9e50df2015-02-20 20:01:26 -0800203 } catch (NumberFormatException | ClassCastException e) {
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800204 log.warn(e.getMessage());
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800205 newRate = eventRate;
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800206 newPath = cfgFile;
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800207 }
208
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800209 // topology file configuration
210 if (!newPath.equals(cfgFile)) {
211 cfgFile = newPath;
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800212 }
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800213 readGraph(cfgFile, nodeService.getLocalNode().id());
214
215 // test mode configuration
216 if (eventRate != newRate && newRate > 0) {
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800217 eventRate = newRate;
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800218 flicker = true;
Ayaka Koshibe13f896f2015-03-10 15:01:44 -0700219 allocateLinks();
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800220 } else if (newRate == 0) {
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800221 flicker = false;
Ayaka Koshibe13f896f2015-03-10 15:01:44 -0700222 // reconfigure driver - dumb but should work.
223 driverMap.getOrDefault(DEFAULT, Sets.newHashSet()).forEach(
224 v -> v.setTasks(linkDescrs));
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800225 }
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800226
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800227 log.info("Using settings: eventRate={}, topofile={}", eventRate, cfgFile);
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800228 }
229
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800230 // parse simplified dot-like topology graph
231 private void readGraph(String path, NodeId me) {
232 log.info("path: {}, local: {}", path, me);
Ayaka Koshibe13f896f2015-03-10 15:01:44 -0700233 Set<LinkDescription> read = Sets.newHashSet();
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800234 BufferedReader br = null;
235 try {
236 br = new BufferedReader(new FileReader(path));
237 String cur = br.readLine();
238 while (cur != null) {
239 if (cur.startsWith("#")) {
240 cur = br.readLine();
241 continue;
242 }
243 String[] parts = cur.trim().split(" ");
244 if (parts.length < 1) {
245 continue;
246 }
247 if (parts[0].equals("graph")) {
248 String node = parts[1].trim();
249 if (node.equals(me.toString())) {
250 cur = br.readLine(); // move to next line, start of links list
251 while (cur != null) {
252 if (cur.trim().contains("}")) {
253 break;
254 }
Ayaka Koshibe13f896f2015-03-10 15:01:44 -0700255 readLink(cur.trim().split(" "), me, read);
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800256 cur = br.readLine();
257 }
258 } else {
259 while (cur != null) {
260 if (cur.trim().equals("}")) {
261 break;
262 }
263 cur = br.readLine();
264 }
265 }
266 }
267 cur = br.readLine();
268 }
269 } catch (IOException e) {
270 log.warn("Could not find topology file: {}", e);
271 } finally {
272 try {
273 if (br != null) {
274 br.close();
275 }
276 } catch (IOException e) {
277 log.warn("Could not close topology file: {}", e);
278 }
279 }
Ayaka Koshibe13f896f2015-03-10 15:01:44 -0700280 synchronized (linkDescrs) {
281 if (!read.isEmpty()) {
282 linkDescrs.clear();
283 linkDescrs.addAll(read);
284 }
285 }
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800286 }
287
288 // parses a link descriptor to make a LinkDescription
Ayaka Koshibe13f896f2015-03-10 15:01:44 -0700289 private void readLink(String[] linkArr, NodeId me, Set<LinkDescription> links) {
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800290 if (linkArr[0].startsWith("#")) {
291 return;
292 }
293 if (linkArr.length != 3) {
294 log.warn("Malformed link descriptor:"
295 + " link should be of format src:port [--|->] dst:port,"
296 + " skipping");
297 return;
298 }
299
300 String op = linkArr[1];
301 String[] cp1 = linkArr[0].split(":");
302 String[] cp2 = linkArr[2].split(":");
303
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800304 if (cp1.length != 2 && (cp2.length != 2 || cp2.length != 3)) {
305 log.warn("Malformed endpoint descriptor(s):"
306 + "endpoint format should be DeviceId:port or DeviceId:port:NodeId,"
307 + "skipping");
308 return;
309 }
310 // read in hints about topology.
311 NodeId adj = null;
312 if (cp2.length == 3) {
313 adj = new NodeId(cp2[2]);
314 log.debug("found an island: {}", adj);
315 }
316
317 // reconstruct deviceIDs. Convention is based on NullDeviceProvider.
318 DeviceId sdev = recover(cp1[0], me);
319 DeviceId ddev = (adj == null) ? recover(cp2[0], me) : recover(cp2[0], adj);
320 ConnectPoint src = new ConnectPoint(sdev, PortNumber.portNumber(cp1[1]));
321 ConnectPoint dst = new ConnectPoint(ddev, PortNumber.portNumber(cp2[1]));
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700322 // both link types have incoming half-link
323 LinkDescription in = new DefaultLinkDescription(dst, src, DIRECT);
Ayaka Koshibe13f896f2015-03-10 15:01:44 -0700324 links.add(in);
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800325 if (op.equals("--")) {
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700326 // bidirectional - within our node's island, make outbound link
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800327 LinkDescription out = new DefaultLinkDescription(src, dst, DIRECT);
Ayaka Koshibe13f896f2015-03-10 15:01:44 -0700328 links.add(out);
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700329 log.info("Created bidirectional link: {}, {}", out, in);
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800330 } else if (op.equals("->")) {
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800331 log.info("Created unidirectional link: {}", in);
332 } else {
333 log.warn("Unknown link descriptor operand:"
334 + " operand must be '--' or '->', skipping");
335 return;
336 }
337 }
338
339 // recover DeviceId from configs and NodeID
340 private DeviceId recover(String base, NodeId node) {
341 long hash = node.hashCode() << 16;
342 int dev = Integer.valueOf(base);
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800343 try {
344 return DeviceId.deviceId(new URI("null", toHex(hash | dev), null));
345 } catch (URISyntaxException e) {
346 log.warn("could not create a DeviceID for descriptor {}", dev);
347 return DeviceId.NONE;
348 }
349 }
350
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700351 // adds a LinkDescription to a worker's to-be queue, for flickering
352 private void allocateLinks() {
353 int index, lcount = 0;
354 for (LinkDescription ld : linkDescrs) {
355 index = (lcount % THREADS);
356 log.info("allocation: total={}, index={}", linkDescrs.size(), lcount, index);
357 if (linkTasks.size() <= index) {
Ayaka Koshibe13f896f2015-03-10 15:01:44 -0700358 linkTasks.add(index, Lists.newArrayList(ld));
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700359 } else {
360 linkTasks.get(index).add(ld);
361 }
362 lcount++;
363 }
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800364 }
365
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800366 /**
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800367 * Generate LinkEvents using configurations when devices are found.
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800368 */
369 private class InternalLinkProvider implements DeviceListener {
370
371 @Override
372 public void event(DeviceEvent event) {
Ayaka Koshibe0cd42822015-01-22 16:02:31 -0800373 Device dev = event.subject();
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800374 switch (event.type()) {
375 case DEVICE_ADDED:
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700376 // TODO: wait for all devices to stop core from balking
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800377 break;
378 case DEVICE_REMOVED:
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700379 if (MASTER.equals(roleService.getLocalRole(dev.id()))) {
380 for (LinkDriver d : driverMap.get(dev.id())) {
381 d.deviceRemoved(dev.id());
382 }
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800383 }
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800384 providerService.linksVanished(dev.id());
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800385 break;
386 default:
387 break;
388 }
389 }
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800390 }
391
392 /**
393 * Generates link events using fake links.
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700394 * TODO: stats collection should be its own thing.
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800395 */
396 private class LinkDriver implements Runnable {
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700397 // List to actually work off of
398 List<LinkDescription> tasks = Lists.newArrayList();
399 float effLoad = 0;
400 Long counter = 0L;
401 int next = 0;
402
403 long startTime;
404
Ayaka Koshibe13f896f2015-03-10 15:01:44 -0700405 LinkDriver(List<LinkDescription> links) {
406 setTasks(links);
407 startTime = System.currentTimeMillis(); // yes, this will start off inaccurate
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800408 }
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800409
410 @Override
411 public void run() {
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800412 if (flicker) {
413 flicker();
414 } else {
415 refresh();
416 }
417 }
418
419 private void flicker() {
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700420 if ((!linkDriver.isShutdown() || !tasks.isEmpty())) {
421 log.info("next: {}, count: {}", next, counter);
422 if (counter <= CHECK_DURATION * 1000000 / eventRate) {
423 if ((counter % 2) == 0) {
424 providerService.linkVanished(tasks.get(next++));
425 } else {
426 providerService.linkDetected(tasks.get(next++));
suibin1a7b7bd2015-02-12 09:41:47 -0800427 }
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700428 if (next == tasks.size()) {
429 next = 0;
430 }
431 counter++;
suibin1a7b7bd2015-02-12 09:41:47 -0800432 } else {
433 // log in WARN the effective load generation rate in events/sec, every 10 seconds
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700434 effLoad = (float) (counter * 1000.0 / (System
435 .currentTimeMillis() - startTime));
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800436 log.warn("Effective Loading for thread is {} events/second",
437 String.valueOf(effLoad));
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700438 counter = 0L;
suibin1a7b7bd2015-02-12 09:41:47 -0800439 startTime = System.currentTimeMillis();
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800440 }
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700441 linkDriver.schedule(this, eventRate, TimeUnit.MICROSECONDS);
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800442 }
443 }
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800444
445 private void refresh() {
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700446 if (!linkDriver.isShutdown() || !tasks.isEmpty()) {
Ayaka Koshibe13f896f2015-03-10 15:01:44 -0700447 log.info("iter {} refresh_links", counter);
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700448
Ayaka Koshibe13f896f2015-03-10 15:01:44 -0700449 for (LinkDescription desc : tasks) {
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800450 providerService.linkDetected(desc);
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700451 log.info("iteration {}, {}", counter, desc);
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800452 }
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700453 counter++;
454 linkDriver.schedule(this, REFRESH_RATE, TimeUnit.SECONDS);
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800455 }
456 }
457
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700458 public void deviceRemoved(DeviceId did) {
459 synchronized (tasks) {
460 Iterator<LinkDescription> it = tasks.iterator();
461 while (it.hasNext()) {
462 LinkDescription ld = it.next();
463 if (did.equals(ld.dst().deviceId())
464 || (did.equals(ld.src().deviceId()))) {
465 it.remove();
466 }
467 }
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800468 }
469 }
Ayaka Koshibe13f896f2015-03-10 15:01:44 -0700470
471 public void setTasks(List<LinkDescription> links) {
472 HashMultimap<ConnectPoint, ConnectPoint> nm = HashMultimap.create();
473 links.forEach(v -> nm.put(v.src(), v.dst()));
474 // remove and send linkVanished for stale links.
475 synchronized (this) {
476 for (LinkDescription l : tasks) {
477 if (!nm.containsEntry(l.src(), l.dst())) {
478 providerService.linkVanished(l);
479 }
480 }
481 tasks.clear();
482 tasks.addAll(links);
483 }
484 }
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800485 }
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800486
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800487}