blob: ad5a03f370f6665f639cbf35852b73efb53b0473 [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 Koshibe9209ea22015-03-09 10:57:50 -070018import com.google.common.collect.Lists;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080019import com.google.common.collect.Maps;
20import com.google.common.collect.Sets;
Ayaka Koshibe839a8a92015-03-03 17:07:22 -080021
Ayaka Koshibe422916f2015-01-15 15:30:23 -080022import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
24import org.apache.felix.scr.annotations.Deactivate;
Ayaka Koshibe7dc1d042015-01-21 15:28:03 -080025import org.apache.felix.scr.annotations.Modified;
Ayaka Koshibe422916f2015-01-15 15:30:23 -080026import org.apache.felix.scr.annotations.Property;
27import org.apache.felix.scr.annotations.Reference;
28import org.apache.felix.scr.annotations.ReferenceCardinality;
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -080029import org.onosproject.cluster.ClusterService;
30import org.onosproject.cluster.NodeId;
Ayaka Koshibe0cd42822015-01-22 16:02:31 -080031import org.onosproject.mastership.MastershipService;
Ayaka Koshibe422916f2015-01-15 15:30:23 -080032import org.onosproject.net.ConnectPoint;
33import org.onosproject.net.Device;
34import org.onosproject.net.DeviceId;
Ayaka Koshibe422916f2015-01-15 15:30:23 -080035import org.onosproject.net.PortNumber;
36import org.onosproject.net.device.DeviceEvent;
37import org.onosproject.net.device.DeviceListener;
38import org.onosproject.net.device.DeviceService;
39import org.onosproject.net.link.DefaultLinkDescription;
40import org.onosproject.net.link.LinkDescription;
41import org.onosproject.net.link.LinkProvider;
42import org.onosproject.net.link.LinkProviderRegistry;
43import org.onosproject.net.link.LinkProviderService;
44import org.onosproject.net.provider.AbstractProvider;
45import org.onosproject.net.provider.ProviderId;
46import org.osgi.service.component.ComponentContext;
47import org.slf4j.Logger;
48
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080049import java.util.Dictionary;
Ayaka Koshibe9209ea22015-03-09 10:57:50 -070050import java.util.Iterator;
51import java.util.List;
52import java.util.ArrayList;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080053import java.util.Set;
54import java.util.concurrent.ConcurrentMap;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080055import java.util.concurrent.Executors;
Ayaka Koshibe9209ea22015-03-09 10:57:50 -070056import java.util.concurrent.ScheduledExecutorService;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080057import java.util.concurrent.TimeUnit;
Ayaka Koshibe839a8a92015-03-03 17:07:22 -080058import java.io.BufferedReader;
59import java.io.FileReader;
60import java.io.IOException;
61import java.net.URI;
62import java.net.URISyntaxException;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080063
64import static com.google.common.base.Strings.isNullOrEmpty;
65import static org.onlab.util.Tools.groupedThreads;
66import static org.onlab.util.Tools.toHex;
67import static org.onosproject.net.MastershipRole.MASTER;
Ayaka Koshibe839a8a92015-03-03 17:07:22 -080068import static org.onosproject.net.Link.Type.DIRECT;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080069import static org.slf4j.LoggerFactory.getLogger;
Ayaka Koshibe422916f2015-01-15 15:30:23 -080070
71/**
72 * Provider which advertises fake/nonexistent links to the core. To be used for
73 * benchmarking only.
Ayaka Koshibe839a8a92015-03-03 17:07:22 -080074 *
75 * This provider takes a topology graph file with a DOT-like syntax.
Ayaka Koshibe422916f2015-01-15 15:30:23 -080076 */
77@Component(immediate = true)
78public class NullLinkProvider extends AbstractProvider implements LinkProvider {
79
80 private final Logger log = getLogger(getClass());
81
Ayaka Koshibe9209ea22015-03-09 10:57:50 -070082 // default topology file location and name.
Ayaka Koshibe839a8a92015-03-03 17:07:22 -080083 private static final String CFG_PATH = "/opt/onos/apache-karaf-3.0.2/etc/linkGraph.cfg";
Ayaka Koshibe9209ea22015-03-09 10:57:50 -070084 // default number of workers. Eventually make this tunable
85 private static final int THREADS = 8;
Ayaka Koshibe839a8a92015-03-03 17:07:22 -080086
87 private static final int CHECK_DURATION = 10;
Ayaka Koshibe9209ea22015-03-09 10:57:50 -070088 private static final int DEFAULT_RATE = 0; // usec
89 private static final int REFRESH_RATE = 3; // sec
Ayaka Koshibe839a8a92015-03-03 17:07:22 -080090
Ayaka Koshibe422916f2015-01-15 15:30:23 -080091 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected DeviceService deviceService;
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ayaka Koshibe0cd42822015-01-22 16:02:31 -080095 protected MastershipService roleService;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -080098 protected ClusterService nodeService;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800101 protected LinkProviderRegistry providerRegistry;
102
103 private LinkProviderService providerService;
104
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800105 private final InternalLinkProvider linkProvider = new InternalLinkProvider();
106
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800107 // True for device with Driver, false otherwise.
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700108 private final ConcurrentMap<DeviceId, Set<LinkDriver>> driverMap = Maps
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800109 .newConcurrentMap();
110
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800111 // Link descriptions
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700112 private final Set<LinkDescription> linkDescrs = Sets.newConcurrentHashSet();
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800113
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700114 // Thread to description map
115 private final List<Set<LinkDescription>> linkTasks = new ArrayList<>(THREADS);
116
117 private ScheduledExecutorService linkDriver =
118 Executors.newScheduledThreadPool(THREADS, groupedThreads("onos/null", "link-driver-%d"));
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800119
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800120 // For flicker = true, duration between events in msec.
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800121 @Property(name = "eventRate", value = "0", label = "Duration between Link Event")
Ayaka Koshibe0cd42822015-01-22 16:02:31 -0800122 private int eventRate = DEFAULT_RATE;
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800123
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800124 // topology configuration file
125 @Property(name = "cfgFile",
126 value = "/opt/onos/apache-karaf-3.0.2/etc/linkGraph.cfg",
127 label = "Topology file location")
128 private String cfgFile = CFG_PATH;
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800129
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800130 // flag checked to create a LinkDriver, if rate is non-zero.
131 private boolean flicker = false;
132
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800133 public NullLinkProvider() {
134 super(new ProviderId("null", "org.onosproject.provider.nil"));
135 }
136
137 @Activate
138 public void activate(ComponentContext context) {
139 providerService = providerRegistry.register(this);
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800140 modified(context);
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800141
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700142 if (flicker) {
143 allocateLinks();
144 for (int i = 0; i < linkTasks.size(); i++) {
145 Set<LinkDescription> links = linkTasks.get(i);
146 LinkDriver driver = new LinkDriver(links, i);
147 links.forEach(v -> {
148 DeviceId d = v.src().deviceId();
149 Set<LinkDriver> s = driverMap.getOrDefault(d, Sets.newConcurrentHashSet());
150 s.add(driver);
151 driverMap.put(d, s);
152 });
153 try {
154 linkDriver.schedule(driver, eventRate, TimeUnit.MICROSECONDS);
155 } catch (Exception e) {
156 log.warn(e.getMessage());
157 }
158 }
159 } else {
160 linkDriver.schedule(new LinkDriver(linkDescrs, 0), 3, TimeUnit.SECONDS);
161 }
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800162 log.info("started");
163 }
164
165 @Deactivate
166 public void deactivate(ComponentContext context) {
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800167 linkDriver.shutdown();
168 try {
169 linkDriver.awaitTermination(1000, TimeUnit.MILLISECONDS);
170 } catch (InterruptedException e) {
171 log.error("LinkBuilder did not terminate");
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800172 linkDriver.shutdownNow();
173 }
174 deviceService.removeListener(linkProvider);
175 providerRegistry.unregister(this);
176 deviceService = null;
177
178 log.info("stopped");
179 }
180
Ayaka Koshibe7dc1d042015-01-21 15:28:03 -0800181 @Modified
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800182 public void modified(ComponentContext context) {
183 if (context == null) {
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800184 log.info("No configs, using defaults: eventRate={}", DEFAULT_RATE);
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800185 return;
186 }
187 Dictionary<?, ?> properties = context.getProperties();
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800188 int newRate;
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800189 String newPath;
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800190 try {
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800191 String s = (String) properties.get("eventRate");
Yuta HIGUCHIdd9228d2015-02-10 22:26:59 -0800192 newRate = isNullOrEmpty(s) ? eventRate : Integer.parseInt(s.trim());
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800193 s = (String) properties.get("cfgFile");
194 newPath = s.trim();
Pavlin Radoslavovb9e50df2015-02-20 20:01:26 -0800195 } catch (NumberFormatException | ClassCastException e) {
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800196 log.warn(e.getMessage());
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800197 newRate = eventRate;
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800198 newPath = cfgFile;
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800199 }
200
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800201 // topology file configuration
202 if (!newPath.equals(cfgFile)) {
203 cfgFile = newPath;
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800204 }
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800205 readGraph(cfgFile, nodeService.getLocalNode().id());
206
207 // test mode configuration
208 if (eventRate != newRate && newRate > 0) {
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800209 eventRate = newRate;
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800210 flicker = true;
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800211 } else if (newRate == 0) {
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800212 flicker = false;
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800213 }
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800214
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800215 log.info("Using settings: eventRate={}, topofile={}", eventRate, cfgFile);
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800216 }
217
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800218 // parse simplified dot-like topology graph
219 private void readGraph(String path, NodeId me) {
220 log.info("path: {}, local: {}", path, me);
221 BufferedReader br = null;
222 try {
223 br = new BufferedReader(new FileReader(path));
224 String cur = br.readLine();
225 while (cur != null) {
226 if (cur.startsWith("#")) {
227 cur = br.readLine();
228 continue;
229 }
230 String[] parts = cur.trim().split(" ");
231 if (parts.length < 1) {
232 continue;
233 }
234 if (parts[0].equals("graph")) {
235 String node = parts[1].trim();
236 if (node.equals(me.toString())) {
237 cur = br.readLine(); // move to next line, start of links list
238 while (cur != null) {
239 if (cur.trim().contains("}")) {
240 break;
241 }
242 readLink(cur.trim().split(" "), me);
243 cur = br.readLine();
244 }
245 } else {
246 while (cur != null) {
247 if (cur.trim().equals("}")) {
248 break;
249 }
250 cur = br.readLine();
251 }
252 }
253 }
254 cur = br.readLine();
255 }
256 } catch (IOException e) {
257 log.warn("Could not find topology file: {}", e);
258 } finally {
259 try {
260 if (br != null) {
261 br.close();
262 }
263 } catch (IOException e) {
264 log.warn("Could not close topology file: {}", e);
265 }
266 }
267 }
268
269 // parses a link descriptor to make a LinkDescription
270 private void readLink(String[] linkArr, NodeId me) {
271 if (linkArr[0].startsWith("#")) {
272 return;
273 }
274 if (linkArr.length != 3) {
275 log.warn("Malformed link descriptor:"
276 + " link should be of format src:port [--|->] dst:port,"
277 + " skipping");
278 return;
279 }
280
281 String op = linkArr[1];
282 String[] cp1 = linkArr[0].split(":");
283 String[] cp2 = linkArr[2].split(":");
284
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800285 if (cp1.length != 2 && (cp2.length != 2 || cp2.length != 3)) {
286 log.warn("Malformed endpoint descriptor(s):"
287 + "endpoint format should be DeviceId:port or DeviceId:port:NodeId,"
288 + "skipping");
289 return;
290 }
291 // read in hints about topology.
292 NodeId adj = null;
293 if (cp2.length == 3) {
294 adj = new NodeId(cp2[2]);
295 log.debug("found an island: {}", adj);
296 }
297
298 // reconstruct deviceIDs. Convention is based on NullDeviceProvider.
299 DeviceId sdev = recover(cp1[0], me);
300 DeviceId ddev = (adj == null) ? recover(cp2[0], me) : recover(cp2[0], adj);
301 ConnectPoint src = new ConnectPoint(sdev, PortNumber.portNumber(cp1[1]));
302 ConnectPoint dst = new ConnectPoint(ddev, PortNumber.portNumber(cp2[1]));
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700303 // both link types have incoming half-link
304 LinkDescription in = new DefaultLinkDescription(dst, src, DIRECT);
305 linkDescrs.add(in);
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800306 if (op.equals("--")) {
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700307 // bidirectional - within our node's island, make outbound link
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800308 LinkDescription out = new DefaultLinkDescription(src, dst, DIRECT);
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700309 linkDescrs.add(out);
310 log.info("Created bidirectional link: {}, {}", out, in);
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800311 } else if (op.equals("->")) {
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800312 log.info("Created unidirectional link: {}", in);
313 } else {
314 log.warn("Unknown link descriptor operand:"
315 + " operand must be '--' or '->', skipping");
316 return;
317 }
318 }
319
320 // recover DeviceId from configs and NodeID
321 private DeviceId recover(String base, NodeId node) {
322 long hash = node.hashCode() << 16;
323 int dev = Integer.valueOf(base);
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800324 try {
325 return DeviceId.deviceId(new URI("null", toHex(hash | dev), null));
326 } catch (URISyntaxException e) {
327 log.warn("could not create a DeviceID for descriptor {}", dev);
328 return DeviceId.NONE;
329 }
330 }
331
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700332 // adds a LinkDescription to a worker's to-be queue, for flickering
333 private void allocateLinks() {
334 int index, lcount = 0;
335 for (LinkDescription ld : linkDescrs) {
336 index = (lcount % THREADS);
337 log.info("allocation: total={}, index={}", linkDescrs.size(), lcount, index);
338 if (linkTasks.size() <= index) {
339 linkTasks.add(index, Sets.newHashSet(ld));
340 } else {
341 linkTasks.get(index).add(ld);
342 }
343 lcount++;
344 }
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800345 }
346
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800347 /**
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800348 * Generate LinkEvents using configurations when devices are found.
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800349 */
350 private class InternalLinkProvider implements DeviceListener {
351
352 @Override
353 public void event(DeviceEvent event) {
Ayaka Koshibe0cd42822015-01-22 16:02:31 -0800354 Device dev = event.subject();
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800355 switch (event.type()) {
356 case DEVICE_ADDED:
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700357 // TODO: wait for all devices to stop core from balking
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800358 break;
359 case DEVICE_REMOVED:
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700360 if (MASTER.equals(roleService.getLocalRole(dev.id()))) {
361 for (LinkDriver d : driverMap.get(dev.id())) {
362 d.deviceRemoved(dev.id());
363 }
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800364 }
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800365 providerService.linksVanished(dev.id());
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800366 break;
367 default:
368 break;
369 }
370 }
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800371 }
372
373 /**
374 * Generates link events using fake links.
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700375 * TODO: stats collection should be its own thing.
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800376 */
377 private class LinkDriver implements Runnable {
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700378 // List to actually work off of
379 List<LinkDescription> tasks = Lists.newArrayList();
380 float effLoad = 0;
381 Long counter = 0L;
382 int next = 0;
383
384 long startTime;
385
386 LinkDriver(Set<LinkDescription> links, int index) {
387 for (LinkDescription link : links) {
388 tasks.add(link);
389 }
390 startTime = System.currentTimeMillis();
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800391 }
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800392
393 @Override
394 public void run() {
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700395 log.info("Thread started for links {}", tasks);
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800396 if (flicker) {
397 flicker();
398 } else {
399 refresh();
400 }
401 }
402
403 private void flicker() {
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700404 if ((!linkDriver.isShutdown() || !tasks.isEmpty())) {
405 log.info("next: {}, count: {}", next, counter);
406 if (counter <= CHECK_DURATION * 1000000 / eventRate) {
407 if ((counter % 2) == 0) {
408 providerService.linkVanished(tasks.get(next++));
409 } else {
410 providerService.linkDetected(tasks.get(next++));
suibin1a7b7bd2015-02-12 09:41:47 -0800411 }
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700412 if (next == tasks.size()) {
413 next = 0;
414 }
415 counter++;
suibin1a7b7bd2015-02-12 09:41:47 -0800416 } else {
417 // log in WARN the effective load generation rate in events/sec, every 10 seconds
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700418 effLoad = (float) (counter * 1000.0 / (System
419 .currentTimeMillis() - startTime));
Ayaka Koshibed2c7ad22015-02-13 16:44:07 -0800420 log.warn("Effective Loading for thread is {} events/second",
421 String.valueOf(effLoad));
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700422 counter = 0L;
suibin1a7b7bd2015-02-12 09:41:47 -0800423 startTime = System.currentTimeMillis();
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800424 }
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700425 linkDriver.schedule(this, eventRate, TimeUnit.MICROSECONDS);
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800426 }
427 }
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800428
429 private void refresh() {
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700430 if (!linkDriver.isShutdown() || !tasks.isEmpty()) {
431 log.info("iter {} refresh_links for {} links", counter, linkDescrs.size());
432
433 for (LinkDescription desc : linkDescrs) {
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800434 providerService.linkDetected(desc);
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700435 log.info("iteration {}, {}", counter, desc);
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800436 }
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700437 counter++;
438 linkDriver.schedule(this, REFRESH_RATE, TimeUnit.SECONDS);
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800439 }
440 }
441
Ayaka Koshibe9209ea22015-03-09 10:57:50 -0700442 public void deviceRemoved(DeviceId did) {
443 synchronized (tasks) {
444 Iterator<LinkDescription> it = tasks.iterator();
445 while (it.hasNext()) {
446 LinkDescription ld = it.next();
447 if (did.equals(ld.dst().deviceId())
448 || (did.equals(ld.src().deviceId()))) {
449 it.remove();
450 }
451 }
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800452 }
453 }
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800454 }
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800455
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800456}