Committed by
Ray Milkey
NullLinkProvider has been rewritten to take a topology file.
Reference: ONOS-1214, ONOS-1033 Change-Id: Ia945e4c8555afd2d74f174e51e22e2fdf3dcb356
Showing
5 changed files
with
215 additions
and
196 deletions
providers/null/device/src/main/java/org/onosproject/provider/nil/device/impl/NullDeviceProvider.java
... | @@ -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,27 +158,36 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider { | ... | @@ -169,27 +158,36 @@ 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 | 185 | + } else if (newRate == 0) { |
186 | + driverMap.replaceAll((k, v) -> false); | ||
187 | + flicker = false; | ||
188 | + } | ||
189 | + | ||
190 | + log.info("Using settings: eventRate={}, topofile={}", eventRate, cfgFile); | ||
193 | for (Device dev : deviceService.getDevices()) { | 191 | for (Device dev : deviceService.getDevices()) { |
194 | DeviceId did = dev.id(); | 192 | DeviceId did = dev.id(); |
195 | synchronized (this) { | 193 | synchronized (this) { |
... | @@ -199,110 +197,136 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider { | ... | @@ -199,110 +197,136 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider { |
199 | } | 197 | } |
200 | } | 198 | } |
201 | } | 199 | } |
202 | - } else if (newRate == 0) { | ||
203 | - driverMap.replaceAll((k, v) -> false); | ||
204 | - } else { | ||
205 | - log.warn("Invalid link flicker rate {}", newRate); | ||
206 | } | 200 | } |
207 | 201 | ||
208 | - log.info("Using new settings: eventRate={}", eventRate); | 202 | + // parse simplified dot-like topology graph |
203 | + private void readGraph(String path, NodeId me) { | ||
204 | + log.info("path: {}, local: {}", path, me); | ||
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; | ||
209 | } | 213 | } |
210 | - | 214 | + String[] parts = cur.trim().split(" "); |
211 | - // pick out substring from Deviceid | 215 | + if (parts.length < 1) { |
212 | - private String part(String devId) { | 216 | + continue; |
213 | - return devId.split(":")[1].substring(12, 16); | ||
214 | } | 217 | } |
215 | - | 218 | + if (parts[0].equals("graph")) { |
216 | - // pick out substring from Deviceid | 219 | + String node = parts[1].trim(); |
217 | - private String nIdPart(String devId) { | 220 | + if (node.equals(me.toString())) { |
218 | - return devId.split(":")[1].substring(9, 12); | 221 | + cur = br.readLine(); // move to next line, start of links list |
222 | + while (cur != null) { | ||
223 | + if (cur.trim().contains("}")) { | ||
224 | + break; | ||
219 | } | 225 | } |
220 | - | 226 | + readLink(cur.trim().split(" "), me); |
221 | - // pick out the next node ID in string, return hash (i.e. what's | 227 | + cur = br.readLine(); |
222 | - // in a Device ID | 228 | + } |
223 | - private String getNeighbor(String nbors) { | 229 | + } else { |
224 | - String me = nodeService.getLocalNode().id().toString(); | 230 | + while (cur != null) { |
225 | - String mynb = ""; | 231 | + if (cur.trim().equals("}")) { |
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; | 232 | break; |
231 | } | 233 | } |
234 | + cur = br.readLine(); | ||
232 | } | 235 | } |
233 | - // return as hash string. | ||
234 | - if (!mynb.isEmpty()) { | ||
235 | - return toHex((Objects.hash(new NodeId(mynb)))).substring(13, 16); | ||
236 | } | 236 | } |
237 | - return ""; | ||
238 | } | 237 | } |
239 | - | 238 | + cur = br.readLine(); |
240 | - private boolean addLdesc(DeviceId did, LinkDescription ldesc) { | 239 | + } |
241 | - Set<LinkDescription> ldescs = ConcurrentUtils.putIfAbsent( | 240 | + } catch (IOException e) { |
242 | - linkDescrs, did, Sets.newConcurrentHashSet()); | 241 | + log.warn("Could not find topology file: {}", e); |
243 | - return ldescs.add(ldesc); | 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); | ||
244 | } | 249 | } |
245 | - | ||
246 | - private void addLink(Device current) { | ||
247 | - DeviceId did = current.id(); | ||
248 | - if (!MASTER.equals(roleService.getLocalRole(did))) { | ||
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 | } | 250 | } |
256 | - tryLinkTail(); | ||
257 | - return; | ||
258 | } | 251 | } |
259 | - devices.add(did); | ||
260 | 252 | ||
261 | - if (devices.size() == 1) { | 253 | + // parses a link descriptor to make a LinkDescription |
254 | + private void readLink(String[] linkArr, NodeId me) { | ||
255 | + if (linkArr[0].startsWith("#")) { | ||
256 | + return; | ||
257 | + } | ||
258 | + if (linkArr.length != 3) { | ||
259 | + log.warn("Malformed link descriptor:" | ||
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 | 268 | ||
277 | - providerService.linkDetected(fdesc); | 269 | + log.debug("cp1:{} cp2:{}", cp1, cp2); |
278 | - providerService.linkDetected(rdesc); | 270 | + if (cp1.length != 2 && (cp2.length != 2 || cp2.length != 3)) { |
271 | + log.warn("Malformed endpoint descriptor(s):" | ||
272 | + + "endpoint format should be DeviceId:port or DeviceId:port:NodeId," | ||
273 | + + "skipping"); | ||
274 | + return; | ||
279 | } | 275 | } |
280 | - | 276 | + // read in hints about topology. |
281 | - // try to link to a tail to first element | 277 | + NodeId adj = null; |
282 | - private void tryLinkTail() { | 278 | + if (cp2.length == 3) { |
283 | - if (tails.isEmpty() || devices.isEmpty()) { | 279 | + adj = new NodeId(cp2[2]); |
280 | + log.debug("found an island: {}", adj); | ||
281 | + } | ||
282 | + | ||
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"); | ||
284 | return; | 304 | return; |
285 | } | 305 | } |
286 | - ConnectPoint first = new ConnectPoint(devices.get(0), DSTPORT); | ||
287 | - boolean added = false; | ||
288 | - for (ConnectPoint cp : tails) { | ||
289 | - if (!linkService.getLinks(cp).isEmpty()) { | ||
290 | - continue; | ||
291 | } | 306 | } |
292 | - LinkDescription ld = new DefaultLinkDescription(cp, first, | 307 | + |
293 | - Link.Type.DIRECT); | 308 | + // recover DeviceId from configs and NodeID |
294 | - addLdesc(cp.deviceId(), ld); | 309 | + private DeviceId recover(String base, NodeId node) { |
295 | - providerService.linkDetected(ld); | 310 | + long hash = node.hashCode() << 16; |
296 | - added = true; | 311 | + int dev = Integer.valueOf(base); |
297 | - break; | 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; | ||
298 | } | 318 | } |
299 | - if (added) { | ||
300 | - tails.clear(); | ||
301 | } | 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); | ||
302 | } | 326 | } |
303 | 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 | + } | ||
433 | } | 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 | + } | ||
428 | + } | ||
429 | + | ||
434 | } | 430 | } | ... | ... |
tools/package/etc/samples/linkGraph.cfg
0 → 100644
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 | ... | ... |
-
Please register or login to post a comment