Ayaka Koshibe
Committed by Ray Milkey

NullLinkProvider has been rewritten to take a topology file.

Reference: ONOS-1214, ONOS-1033

Change-Id: Ia945e4c8555afd2d74f174e51e22e2fdf3dcb356
...@@ -78,8 +78,6 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid ...@@ -78,8 +78,6 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid
78 private ExecutorService deviceBuilder = 78 private ExecutorService deviceBuilder =
79 Executors.newFixedThreadPool(1, groupedThreads("onos/null", "device-creator")); 79 Executors.newFixedThreadPool(1, groupedThreads("onos/null", "device-creator"));
80 80
81 -
82 - //currently hardcoded. will be made configurable via rest/cli.
83 private static final String SCHEME = "null"; 81 private static final String SCHEME = "null";
84 private static final int DEF_NUMDEVICES = 10; 82 private static final int DEF_NUMDEVICES = 10;
85 private static final int DEF_NUMPORTS = 10; 83 private static final int DEF_NUMPORTS = 10;
...@@ -99,7 +97,6 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid ...@@ -99,7 +97,6 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid
99 97
100 private DeviceCreator creator; 98 private DeviceCreator creator;
101 99
102 -
103 /** 100 /**
104 * 101 *
105 * Creates a provider with the supplier identifier. 102 * Creates a provider with the supplier identifier.
...@@ -238,11 +235,10 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid ...@@ -238,11 +235,10 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid
238 ChassisId cid; 235 ChassisId cid;
239 236
240 // nodeIdHash takes into account for nodeID to avoid collisions when running multi-node providers. 237 // nodeIdHash takes into account for nodeID to avoid collisions when running multi-node providers.
241 - long nodeIdHash = clusterService.getLocalNode().hashCode() << 16; 238 + long nodeIdHash = clusterService.getLocalNode().id().hashCode() << 16;
242 239
243 for (int i = 0; i < numDevices; i++) { 240 for (int i = 0; i < numDevices; i++) {
244 - // mark 'last' device to facilitate chaining of islands together 241 + long id = nodeIdHash | i;
245 - long id = (i + 1 == numDevices) ? nodeIdHash | 0xffff : nodeIdHash | i;
246 242
247 did = DeviceId.deviceId(new URI(SCHEME, toHex(id), null)); 243 did = DeviceId.deviceId(new URI(SCHEME, toHex(id), null));
248 cid = new ChassisId(i); 244 cid = new ChassisId(i);
......
...@@ -15,9 +15,9 @@ ...@@ -15,9 +15,9 @@
15 */ 15 */
16 package org.onosproject.provider.nil.link.impl; 16 package org.onosproject.provider.nil.link.impl;
17 17
18 -import com.google.common.collect.Lists;
19 import com.google.common.collect.Maps; 18 import com.google.common.collect.Maps;
20 import com.google.common.collect.Sets; 19 import com.google.common.collect.Sets;
20 +
21 import org.apache.commons.lang3.concurrent.ConcurrentUtils; 21 import org.apache.commons.lang3.concurrent.ConcurrentUtils;
22 import org.apache.felix.scr.annotations.Activate; 22 import org.apache.felix.scr.annotations.Activate;
23 import org.apache.felix.scr.annotations.Component; 23 import org.apache.felix.scr.annotations.Component;
...@@ -32,49 +32,56 @@ import org.onosproject.mastership.MastershipService; ...@@ -32,49 +32,56 @@ import org.onosproject.mastership.MastershipService;
32 import org.onosproject.net.ConnectPoint; 32 import org.onosproject.net.ConnectPoint;
33 import org.onosproject.net.Device; 33 import org.onosproject.net.Device;
34 import org.onosproject.net.DeviceId; 34 import org.onosproject.net.DeviceId;
35 -import org.onosproject.net.Link;
36 import org.onosproject.net.PortNumber; 35 import org.onosproject.net.PortNumber;
37 import org.onosproject.net.device.DeviceEvent; 36 import org.onosproject.net.device.DeviceEvent;
38 import org.onosproject.net.device.DeviceListener; 37 import org.onosproject.net.device.DeviceListener;
39 import org.onosproject.net.device.DeviceService; 38 import org.onosproject.net.device.DeviceService;
40 import org.onosproject.net.link.DefaultLinkDescription; 39 import org.onosproject.net.link.DefaultLinkDescription;
41 import org.onosproject.net.link.LinkDescription; 40 import org.onosproject.net.link.LinkDescription;
42 -import org.onosproject.net.link.LinkEvent;
43 -import org.onosproject.net.link.LinkListener;
44 import org.onosproject.net.link.LinkProvider; 41 import org.onosproject.net.link.LinkProvider;
45 import org.onosproject.net.link.LinkProviderRegistry; 42 import org.onosproject.net.link.LinkProviderRegistry;
46 import org.onosproject.net.link.LinkProviderService; 43 import org.onosproject.net.link.LinkProviderService;
47 -import org.onosproject.net.link.LinkService;
48 import org.onosproject.net.provider.AbstractProvider; 44 import org.onosproject.net.provider.AbstractProvider;
49 import org.onosproject.net.provider.ProviderId; 45 import org.onosproject.net.provider.ProviderId;
50 import org.osgi.service.component.ComponentContext; 46 import org.osgi.service.component.ComponentContext;
51 import org.slf4j.Logger; 47 import org.slf4j.Logger;
52 48
53 import java.util.Dictionary; 49 import java.util.Dictionary;
54 -import java.util.Iterator;
55 -import java.util.List;
56 -import java.util.Objects;
57 import java.util.Set; 50 import java.util.Set;
58 import java.util.concurrent.ConcurrentMap; 51 import java.util.concurrent.ConcurrentMap;
59 import java.util.concurrent.ExecutorService; 52 import java.util.concurrent.ExecutorService;
60 import java.util.concurrent.Executors; 53 import java.util.concurrent.Executors;
61 import java.util.concurrent.TimeUnit; 54 import java.util.concurrent.TimeUnit;
55 +import java.io.BufferedReader;
56 +import java.io.FileReader;
57 +import java.io.IOException;
58 +import java.net.URI;
59 +import java.net.URISyntaxException;
62 60
63 import static com.google.common.base.Strings.isNullOrEmpty; 61 import static com.google.common.base.Strings.isNullOrEmpty;
64 import static org.onlab.util.Tools.groupedThreads; 62 import static org.onlab.util.Tools.groupedThreads;
65 import static org.onlab.util.Tools.toHex; 63 import static org.onlab.util.Tools.toHex;
66 import static org.onosproject.net.MastershipRole.MASTER; 64 import static org.onosproject.net.MastershipRole.MASTER;
65 +import static org.onosproject.net.Link.Type.DIRECT;
67 import static org.slf4j.LoggerFactory.getLogger; 66 import static org.slf4j.LoggerFactory.getLogger;
68 67
69 /** 68 /**
70 * Provider which advertises fake/nonexistent links to the core. To be used for 69 * Provider which advertises fake/nonexistent links to the core. To be used for
71 * benchmarking only. 70 * benchmarking only.
71 + *
72 + * This provider takes a topology graph file with a DOT-like syntax.
72 */ 73 */
73 @Component(immediate = true) 74 @Component(immediate = true)
74 public class NullLinkProvider extends AbstractProvider implements LinkProvider { 75 public class NullLinkProvider extends AbstractProvider implements LinkProvider {
75 76
76 private final Logger log = getLogger(getClass()); 77 private final Logger log = getLogger(getClass());
77 78
79 + private static final String CFG_PATH = "/opt/onos/apache-karaf-3.0.2/etc/linkGraph.cfg";
80 +
81 + private static final int CHECK_DURATION = 10;
82 + private static final int DEFAULT_RATE = 0;
83 + private static final int REFRESH_RATE = 3000000; // in us
84 +
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected DeviceService deviceService; 86 protected DeviceService deviceService;
80 87
...@@ -86,17 +93,10 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -86,17 +93,10 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider {
86 93
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected LinkProviderRegistry providerRegistry; 95 protected LinkProviderRegistry providerRegistry;
89 - private LinkService linkService;
90 96
91 private LinkProviderService providerService; 97 private LinkProviderService providerService;
92 98
93 - private static final int DEFAULT_RATE = 0;
94 - // For now, static switch port values
95 - private static final PortNumber SRCPORT = PortNumber.portNumber(5);
96 - private static final PortNumber DSTPORT = PortNumber.portNumber(6);
97 -
98 private final InternalLinkProvider linkProvider = new InternalLinkProvider(); 99 private final InternalLinkProvider linkProvider = new InternalLinkProvider();
99 - private final InternalLinkListener listener = new InternalLinkListener();
100 100
101 // True for device with Driver, false otherwise. 101 // True for device with Driver, false otherwise.
102 private final ConcurrentMap<DeviceId, Boolean> driverMap = Maps 102 private final ConcurrentMap<DeviceId, Boolean> driverMap = Maps
...@@ -106,25 +106,18 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -106,25 +106,18 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider {
106 private final ConcurrentMap<DeviceId, Set<LinkDescription>> linkDescrs = Maps 106 private final ConcurrentMap<DeviceId, Set<LinkDescription>> linkDescrs = Maps
107 .newConcurrentMap(); 107 .newConcurrentMap();
108 108
109 - // Local Device ID's that have been seen so far
110 - private final List<DeviceId> devices = Lists.newArrayList();
111 - // tail ends of other islands
112 - private final List<ConnectPoint> tails = Lists.newArrayList();
113 -
114 - private final int checkRateDuration = 10;
115 -
116 private ExecutorService linkDriver = 109 private ExecutorService linkDriver =
117 Executors.newCachedThreadPool(groupedThreads("onos/null", "link-driver-%d")); 110 Executors.newCachedThreadPool(groupedThreads("onos/null", "link-driver-%d"));
118 111
119 // For flicker = true, duration between events in msec. 112 // For flicker = true, duration between events in msec.
120 - @Property(name = "eventRate", value = "0", 113 + @Property(name = "eventRate", value = "0", label = "Duration between Link Event")
121 - label = "Duration between Link Event")
122 private int eventRate = DEFAULT_RATE; 114 private int eventRate = DEFAULT_RATE;
123 115
124 - // For flicker = true, duration between events in msec. 116 + // topology configuration file
125 - @Property(name = "neighbors", value = "", 117 + @Property(name = "cfgFile",
126 - label = "Node ID of instance for neighboring island ") 118 + value = "/opt/onos/apache-karaf-3.0.2/etc/linkGraph.cfg",
127 - private String neighbor = ""; 119 + label = "Topology file location")
120 + private String cfgFile = CFG_PATH;
128 121
129 // flag checked to create a LinkDriver, if rate is non-zero. 122 // flag checked to create a LinkDriver, if rate is non-zero.
130 private boolean flicker = false; 123 private boolean flicker = false;
...@@ -136,9 +129,7 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -136,9 +129,7 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider {
136 @Activate 129 @Activate
137 public void activate(ComponentContext context) { 130 public void activate(ComponentContext context) {
138 providerService = providerRegistry.register(this); 131 providerService = providerRegistry.register(this);
139 - linkService = (LinkService) providerRegistry;
140 modified(context); 132 modified(context);
141 - linkService.addListener(listener);
142 deviceService.addListener(linkProvider); 133 deviceService.addListener(linkProvider);
143 134
144 log.info("started"); 135 log.info("started");
...@@ -155,9 +146,7 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -155,9 +146,7 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider {
155 } 146 }
156 deviceService.removeListener(linkProvider); 147 deviceService.removeListener(linkProvider);
157 providerRegistry.unregister(this); 148 providerRegistry.unregister(this);
158 - linkService.removeListener(listener);
159 deviceService = null; 149 deviceService = null;
160 - linkService = null;
161 150
162 log.info("stopped"); 151 log.info("stopped");
163 } 152 }
...@@ -169,140 +158,175 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -169,140 +158,175 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider {
169 return; 158 return;
170 } 159 }
171 Dictionary<?, ?> properties = context.getProperties(); 160 Dictionary<?, ?> properties = context.getProperties();
172 -
173 int newRate; 161 int newRate;
174 - String newNbor; 162 + String newPath;
175 try { 163 try {
176 String s = (String) properties.get("eventRate"); 164 String s = (String) properties.get("eventRate");
177 newRate = isNullOrEmpty(s) ? eventRate : Integer.parseInt(s.trim()); 165 newRate = isNullOrEmpty(s) ? eventRate : Integer.parseInt(s.trim());
178 - s = (String) properties.get("neighbors"); 166 + s = (String) properties.get("cfgFile");
179 - newNbor = isNullOrEmpty(s) ? neighbor : getNeighbor(s.trim()); 167 + newPath = s.trim();
180 } catch (NumberFormatException | ClassCastException e) { 168 } catch (NumberFormatException | ClassCastException e) {
181 log.warn(e.getMessage()); 169 log.warn(e.getMessage());
182 newRate = eventRate; 170 newRate = eventRate;
183 - newNbor = neighbor; 171 + newPath = cfgFile;
184 } 172 }
185 173
186 - if (newNbor != neighbor) { 174 + // topology file configuration
187 - neighbor = newNbor; 175 + if (!newPath.equals(cfgFile)) {
176 + cfgFile = newPath;
188 } 177 }
189 - if (newRate != 0 & eventRate != newRate) { 178 + readGraph(cfgFile, nodeService.getLocalNode().id());
179 +
180 + // test mode configuration
181 + if (eventRate != newRate && newRate > 0) {
182 + driverMap.replaceAll((k, v) -> false);
190 eventRate = newRate; 183 eventRate = newRate;
191 flicker = true; 184 flicker = true;
192 - // try to find and add drivers for current devices
193 - for (Device dev : deviceService.getDevices()) {
194 - DeviceId did = dev.id();
195 - synchronized (this) {
196 - if (driverMap.get(did) == null || !driverMap.get(did)) {
197 - driverMap.put(dev.id(), true);
198 - linkDriver.submit(new LinkDriver(dev));
199 - }
200 - }
201 - }
202 } else if (newRate == 0) { 185 } else if (newRate == 0) {
203 driverMap.replaceAll((k, v) -> false); 186 driverMap.replaceAll((k, v) -> false);
204 - } else { 187 + flicker = false;
205 - log.warn("Invalid link flicker rate {}", newRate);
206 } 188 }
207 189
208 - log.info("Using new settings: eventRate={}", eventRate); 190 + log.info("Using settings: eventRate={}, topofile={}", eventRate, cfgFile);
209 - } 191 + for (Device dev : deviceService.getDevices()) {
210 - 192 + DeviceId did = dev.id();
211 - // pick out substring from Deviceid 193 + synchronized (this) {
212 - private String part(String devId) { 194 + if (driverMap.get(did) == null || !driverMap.get(did)) {
213 - return devId.split(":")[1].substring(12, 16); 195 + driverMap.put(dev.id(), true);
214 - } 196 + linkDriver.submit(new LinkDriver(dev));
215 - 197 + }
216 - // pick out substring from Deviceid
217 - private String nIdPart(String devId) {
218 - return devId.split(":")[1].substring(9, 12);
219 - }
220 -
221 - // pick out the next node ID in string, return hash (i.e. what's
222 - // in a Device ID
223 - private String getNeighbor(String nbors) {
224 - String me = nodeService.getLocalNode().id().toString();
225 - String mynb = "";
226 - String[] nodes = nbors.split(",");
227 - for (int i = 0; i < nodes.length; i++) {
228 - if (i != 0 & nodes[i].equals(me)) {
229 - mynb = nodes[i - 1];
230 - break;
231 } 198 }
232 } 199 }
233 - // return as hash string.
234 - if (!mynb.isEmpty()) {
235 - return toHex((Objects.hash(new NodeId(mynb)))).substring(13, 16);
236 - }
237 - return "";
238 } 200 }
239 201
240 - private boolean addLdesc(DeviceId did, LinkDescription ldesc) { 202 + // parse simplified dot-like topology graph
241 - Set<LinkDescription> ldescs = ConcurrentUtils.putIfAbsent( 203 + private void readGraph(String path, NodeId me) {
242 - linkDescrs, did, Sets.newConcurrentHashSet()); 204 + log.info("path: {}, local: {}", path, me);
243 - return ldescs.add(ldesc); 205 + BufferedReader br = null;
206 + try {
207 + br = new BufferedReader(new FileReader(path));
208 + String cur = br.readLine();
209 + while (cur != null) {
210 + if (cur.startsWith("#")) {
211 + cur = br.readLine();
212 + continue;
213 + }
214 + String[] parts = cur.trim().split(" ");
215 + if (parts.length < 1) {
216 + continue;
217 + }
218 + if (parts[0].equals("graph")) {
219 + String node = parts[1].trim();
220 + if (node.equals(me.toString())) {
221 + cur = br.readLine(); // move to next line, start of links list
222 + while (cur != null) {
223 + if (cur.trim().contains("}")) {
224 + break;
225 + }
226 + readLink(cur.trim().split(" "), me);
227 + cur = br.readLine();
228 + }
229 + } else {
230 + while (cur != null) {
231 + if (cur.trim().equals("}")) {
232 + break;
233 + }
234 + cur = br.readLine();
235 + }
236 + }
237 + }
238 + cur = br.readLine();
239 + }
240 + } catch (IOException e) {
241 + log.warn("Could not find topology file: {}", e);
242 + } finally {
243 + try {
244 + if (br != null) {
245 + br.close();
246 + }
247 + } catch (IOException e) {
248 + log.warn("Could not close topology file: {}", e);
249 + }
250 + }
244 } 251 }
245 252
246 - private void addLink(Device current) { 253 + // parses a link descriptor to make a LinkDescription
247 - DeviceId did = current.id(); 254 + private void readLink(String[] linkArr, NodeId me) {
248 - if (!MASTER.equals(roleService.getLocalRole(did))) { 255 + if (linkArr[0].startsWith("#")) {
249 -
250 - String part = part(did.toString());
251 - String npart = nIdPart(did.toString());
252 - if (part.equals("ffff") && npart.equals(neighbor)) {
253 - // 'tail' of our neighboring island - link us <- tail
254 - tails.add(new ConnectPoint(did, SRCPORT));
255 - }
256 - tryLinkTail();
257 return; 256 return;
258 } 257 }
259 - devices.add(did); 258 + if (linkArr.length != 3) {
260 - 259 + log.warn("Malformed link descriptor:"
261 - if (devices.size() == 1) { 260 + + " link should be of format src:port [--|->] dst:port,"
261 + + " skipping");
262 return; 262 return;
263 } 263 }
264 264
265 - // Normal flow - attach new device to the last-seen device 265 + String op = linkArr[1];
266 - DeviceId prev = devices.get(devices.size() - 2); 266 + String[] cp1 = linkArr[0].split(":");
267 - ConnectPoint src = new ConnectPoint(prev, SRCPORT); 267 + String[] cp2 = linkArr[2].split(":");
268 - ConnectPoint dst = new ConnectPoint(did, DSTPORT);
269 -
270 - LinkDescription fdesc = new DefaultLinkDescription(src, dst,
271 - Link.Type.DIRECT);
272 - LinkDescription rdesc = new DefaultLinkDescription(dst, src,
273 - Link.Type.DIRECT);
274 - addLdesc(prev, fdesc);
275 - addLdesc(did, rdesc);
276 -
277 - providerService.linkDetected(fdesc);
278 - providerService.linkDetected(rdesc);
279 - }
280 268
281 - // try to link to a tail to first element 269 + log.debug("cp1:{} cp2:{}", cp1, cp2);
282 - private void tryLinkTail() { 270 + if (cp1.length != 2 && (cp2.length != 2 || cp2.length != 3)) {
283 - if (tails.isEmpty() || devices.isEmpty()) { 271 + log.warn("Malformed endpoint descriptor(s):"
272 + + "endpoint format should be DeviceId:port or DeviceId:port:NodeId,"
273 + + "skipping");
284 return; 274 return;
285 } 275 }
286 - ConnectPoint first = new ConnectPoint(devices.get(0), DSTPORT); 276 + // read in hints about topology.
287 - boolean added = false; 277 + NodeId adj = null;
288 - for (ConnectPoint cp : tails) { 278 + if (cp2.length == 3) {
289 - if (!linkService.getLinks(cp).isEmpty()) { 279 + adj = new NodeId(cp2[2]);
290 - continue; 280 + log.debug("found an island: {}", adj);
291 - }
292 - LinkDescription ld = new DefaultLinkDescription(cp, first,
293 - Link.Type.DIRECT);
294 - addLdesc(cp.deviceId(), ld);
295 - providerService.linkDetected(ld);
296 - added = true;
297 - break;
298 } 281 }
299 - if (added) { 282 +
300 - tails.clear(); 283 + // reconstruct deviceIDs. Convention is based on NullDeviceProvider.
284 + DeviceId sdev = recover(cp1[0], me);
285 + DeviceId ddev = (adj == null) ? recover(cp2[0], me) : recover(cp2[0], adj);
286 + ConnectPoint src = new ConnectPoint(sdev, PortNumber.portNumber(cp1[1]));
287 + ConnectPoint dst = new ConnectPoint(ddev, PortNumber.portNumber(cp2[1]));
288 +
289 + if (op.equals("--")) {
290 + // bidirectional - within our node's island
291 + LinkDescription out = new DefaultLinkDescription(src, dst, DIRECT);
292 + LinkDescription in = new DefaultLinkDescription(dst, src, DIRECT);
293 + addLdesc(sdev, out);
294 + addLdesc(ddev, in);
295 + log.info("Created bidirectional link: {}", out);
296 + } else if (op.equals("->")) {
297 + // unidirectional - likely from another island
298 + LinkDescription in = new DefaultLinkDescription(dst, src, DIRECT);
299 + addLdesc(ddev, in);
300 + log.info("Created unidirectional link: {}", in);
301 + } else {
302 + log.warn("Unknown link descriptor operand:"
303 + + " operand must be '--' or '->', skipping");
304 + return;
301 } 305 }
302 } 306 }
303 307
308 + // recover DeviceId from configs and NodeID
309 + private DeviceId recover(String base, NodeId node) {
310 + long hash = node.hashCode() << 16;
311 + int dev = Integer.valueOf(base);
312 + log.debug("hash: {}, dev: {}, {}", hash, dev, toHex(hash | dev));
313 + try {
314 + return DeviceId.deviceId(new URI("null", toHex(hash | dev), null));
315 + } catch (URISyntaxException e) {
316 + log.warn("could not create a DeviceID for descriptor {}", dev);
317 + return DeviceId.NONE;
318 + }
319 + }
320 +
321 + // add LinkDescriptions to map
322 + private boolean addLdesc(DeviceId did, LinkDescription ldesc) {
323 + Set<LinkDescription> ldescs = ConcurrentUtils.putIfAbsent(
324 + linkDescrs, did, Sets.newConcurrentHashSet());
325 + return ldescs.add(ldesc);
326 + }
327 +
304 /** 328 /**
305 - * Adds links as devices are found, and generates LinkEvents. 329 + * Generate LinkEvents using configurations when devices are found.
306 */ 330 */
307 private class InternalLinkProvider implements DeviceListener { 331 private class InternalLinkProvider implements DeviceListener {
308 332
...@@ -312,72 +336,24 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -312,72 +336,24 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider {
312 switch (event.type()) { 336 switch (event.type()) {
313 case DEVICE_ADDED: 337 case DEVICE_ADDED:
314 synchronized (this) { 338 synchronized (this) {
315 - if (flicker && !driverMap.getOrDefault(dev.id(), false)) { 339 + if (!driverMap.getOrDefault(dev.id(), false)) {
316 driverMap.put(dev.id(), true); 340 driverMap.put(dev.id(), true);
317 linkDriver.submit(new LinkDriver(dev)); 341 linkDriver.submit(new LinkDriver(dev));
318 } 342 }
319 } 343 }
320 - addLink(dev);
321 break; 344 break;
322 case DEVICE_REMOVED: 345 case DEVICE_REMOVED:
323 driverMap.put(dev.id(), false); 346 driverMap.put(dev.id(), false);
324 - removeLink(dev); 347 + if (!MASTER.equals(roleService.getLocalRole(dev.id()))) {
325 - break;
326 - default:
327 - break;
328 - }
329 - }
330 -
331 - private void removeLink(Device device) {
332 - if (!MASTER.equals(roleService.getLocalRole(device.id()))) {
333 - return;
334 - }
335 - providerService.linksVanished(device.id());
336 - devices.remove(device.id());
337 - synchronized (linkDescrs) {
338 - Set<LinkDescription> lds = linkDescrs.remove(device.id());
339 - for (LinkDescription ld : lds) {
340 - ConnectPoint src = ld.src();
341 - DeviceId dst = ld.dst().deviceId();
342 - Iterator<LinkDescription> it = linkDescrs.get(dst).iterator();
343 - while (it.hasNext()) {
344 - if (it.next().dst().equals(src)) {
345 - it.remove();
346 - }
347 - }
348 - }
349 - }
350 - }
351 -
352 - }
353 -
354 - private class InternalLinkListener implements LinkListener {
355 -
356 - @Override
357 - public void event(LinkEvent event) {
358 - switch (event.type()) {
359 - case LINK_ADDED:
360 - // If a link from another island, cast one back.
361 - DeviceId sdid = event.subject().src().deviceId();
362 - PortNumber pn = event.subject().src().port();
363 -
364 - if (roleService.getLocalRole(sdid).equals(MASTER)) {
365 - String part = part(sdid.toString());
366 - if (part.equals("ffff") && SRCPORT.equals(pn)) {
367 - LinkDescription ld = new DefaultLinkDescription(event
368 - .subject().dst(), event.subject().src(),
369 - Link.Type.DIRECT);
370 - addLdesc(event.subject().dst().deviceId(), ld);
371 - providerService.linkDetected(ld);
372 - }
373 return; 348 return;
374 } 349 }
350 + // no need to remove static links, just stop advertising them
351 + providerService.linksVanished(dev.id());
375 break; 352 break;
376 default: 353 default:
377 break; 354 break;
378 } 355 }
379 } 356 }
380 -
381 } 357 }
382 358
383 /** 359 /**
...@@ -392,32 +368,31 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -392,32 +368,31 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider {
392 @Override 368 @Override
393 public void run() { 369 public void run() {
394 log.info("Thread started for dev {}", myDev.id()); 370 log.info("Thread started for dev {}", myDev.id());
371 + if (flicker) {
372 + flicker();
373 + } else {
374 + refresh();
375 + }
376 + }
377 +
378 + private void flicker() {
395 long startTime = System.currentTimeMillis(); 379 long startTime = System.currentTimeMillis();
396 long countEvent = 0; 380 long countEvent = 0;
397 float effLoad = 0; 381 float effLoad = 0;
398 382
399 while (!linkDriver.isShutdown() && driverMap.get(myDev.id())) { 383 while (!linkDriver.isShutdown() && driverMap.get(myDev.id())) {
400 - if (linkDescrs.get(myDev.id()) == null) { 384 + if (!flicker) {
401 - addLink(myDev); 385 + break;
402 } 386 }
403 -
404 //Assuming eventRate is in microsecond unit 387 //Assuming eventRate is in microsecond unit
405 - if (countEvent <= checkRateDuration * 1000000 / eventRate) { 388 + if (countEvent <= CHECK_DURATION * 1000000 / eventRate) {
406 for (LinkDescription desc : linkDescrs.get(myDev.id())) { 389 for (LinkDescription desc : linkDescrs.get(myDev.id())) {
407 providerService.linkVanished(desc); 390 providerService.linkVanished(desc);
408 countEvent++; 391 countEvent++;
409 - try { 392 + sleepFor(eventRate);
410 - TimeUnit.MICROSECONDS.sleep(eventRate);
411 - } catch (InterruptedException e) {
412 - log.warn(String.valueOf(e));
413 - }
414 providerService.linkDetected(desc); 393 providerService.linkDetected(desc);
415 countEvent++; 394 countEvent++;
416 - try { 395 + sleepFor(eventRate);
417 - TimeUnit.MICROSECONDS.sleep(eventRate);
418 - } catch (InterruptedException e) {
419 - log.warn(String.valueOf(e));
420 - }
421 } 396 }
422 } else { 397 } else {
423 // log in WARN the effective load generation rate in events/sec, every 10 seconds 398 // log in WARN the effective load generation rate in events/sec, every 10 seconds
...@@ -430,5 +405,26 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -430,5 +405,26 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider {
430 } 405 }
431 } 406 }
432 } 407 }
408 +
409 + private void refresh() {
410 + while (!linkDriver.isShutdown() && driverMap.get(myDev.id())) {
411 + if (flicker) {
412 + break;
413 + }
414 + for (LinkDescription desc : linkDescrs.get(myDev.id())) {
415 + providerService.linkDetected(desc);
416 + sleepFor(REFRESH_RATE);
417 + }
418 + }
419 + }
420 +
421 + private void sleepFor(int time) {
422 + try {
423 + TimeUnit.MICROSECONDS.sleep(time);
424 + } catch (InterruptedException e) {
425 + log.warn(String.valueOf(e));
426 + }
427 + }
433 } 428 }
429 +
434 } 430 }
......
1 +# NullLinkProvider topology description (config file).
2 +#
3 +# Dot-style topology graph. Each controller's topology begins with
4 +#
5 +# graph <node ID>, followed by a list of links between braces.
6 +#
7 +# The links are either bidirectional (--) or directed (->). The directed
8 +# edges are used to connect together Null devices of different controllers.
9 +# The endpoint has the format:
10 +#
11 +# devID:port:NodeId
12 +#
13 +# The NodeId is only added if the destination is another node's device.
14 +#
15 +graph 192.168.56.20 {
16 + 0:0 -- 1:0
17 + 1:1 -> 0:0:192.168.56.30
18 + 1:2 -- 2:0
19 + 2:1 -> 1:0:192.168.56.30
20 +}
21 +graph 192.168.56.30 {
22 + 0:0 -> 1:1:192.168.56.20
23 + 0:1 -- 1:1
24 + 1:0 -> 2:1:192.168.56.20
25 + 1:2 -- 2:0
26 +}
27 +# Bugs: Comments cannot be appended to a line to be read.
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
2 # Instance-specific configurations, in this case, the number of 2 # Instance-specific configurations, in this case, the number of
3 # devices per node. 3 # devices per node.
4 # 4 #
5 -devConfigs = 192.168.97.132:5,192.168.97.131:5 5 +devConfigs = 192.168.56.20:3,192.168.56.30:3
6 6
7 # 7 #
8 # Number of ports per device. This is global to all devices 8 # Number of ports per device. This is global to all devices
......
...@@ -4,13 +4,13 @@ ...@@ -4,13 +4,13 @@
4 4
5 # 5 #
6 # If enabled, sets the time between LinkEvent generation, 6 # If enabled, sets the time between LinkEvent generation,
7 -# in milliseconds. 7 +# in microseconds.
8 # 8 #
9 9
10 -#eventRate = 100000 10 +#eventRate = 1000000
11 -
12 11
13 # 12 #
14 -# Set order of islands to chain together, in a line. 13 +# If enabled, points to the full path to the topology file.
15 # 14 #
16 -neighbors = 192.168.97.132,192.168.97.131 15 +
16 +#cfgFile = /tmp/foo.cfg
......