Ayaka Koshibe
Committed by Gerrit Code Review

NullDeviceProvider now takes configurations for :

  - Number of devices per ONOS instance.
  - Number of ports on the devices. This value is global.

The islands created by each instances' providers are joined together
in a chain (circle).

Reference : ONOS-860

Change-Id: I875ad1fbc1d4441869373c25de2ae5b62838e0d4
...@@ -31,4 +31,11 @@ ...@@ -31,4 +31,11 @@
31 31
32 <description>ONOS Null protocol device provider</description> 32 <description>ONOS Null protocol device provider</description>
33 33
34 + <dependencies>
35 + <dependency>
36 + <groupId>org.osgi</groupId>
37 + <artifactId>org.osgi.compendium</artifactId>
38 + </dependency>
39 + </dependencies>
40 +
34 </project> 41 </project>
......
...@@ -15,16 +15,21 @@ ...@@ -15,16 +15,21 @@
15 */ 15 */
16 package org.onosproject.provider.nil.device.impl; 16 package org.onosproject.provider.nil.device.impl;
17 17
18 +import static com.google.common.base.Strings.isNullOrEmpty;
18 19
19 import com.google.common.collect.Lists; 20 import com.google.common.collect.Lists;
20 import com.google.common.collect.Maps; 21 import com.google.common.collect.Maps;
22 +
21 import org.apache.felix.scr.annotations.Activate; 23 import org.apache.felix.scr.annotations.Activate;
22 import org.apache.felix.scr.annotations.Component; 24 import org.apache.felix.scr.annotations.Component;
23 import org.apache.felix.scr.annotations.Deactivate; 25 import org.apache.felix.scr.annotations.Deactivate;
26 +import org.apache.felix.scr.annotations.Modified;
27 +import org.apache.felix.scr.annotations.Property;
24 import org.apache.felix.scr.annotations.Reference; 28 import org.apache.felix.scr.annotations.Reference;
25 import org.apache.felix.scr.annotations.ReferenceCardinality; 29 import org.apache.felix.scr.annotations.ReferenceCardinality;
26 import org.onlab.packet.ChassisId; 30 import org.onlab.packet.ChassisId;
27 import org.onosproject.cluster.ClusterService; 31 import org.onosproject.cluster.ClusterService;
32 +import org.onosproject.cluster.NodeId;
28 import org.onosproject.net.Device; 33 import org.onosproject.net.Device;
29 import org.onosproject.net.DeviceId; 34 import org.onosproject.net.DeviceId;
30 import org.onosproject.net.MastershipRole; 35 import org.onosproject.net.MastershipRole;
...@@ -39,10 +44,12 @@ import org.onosproject.net.device.DeviceProviderService; ...@@ -39,10 +44,12 @@ import org.onosproject.net.device.DeviceProviderService;
39 import org.onosproject.net.device.PortDescription; 44 import org.onosproject.net.device.PortDescription;
40 import org.onosproject.net.provider.AbstractProvider; 45 import org.onosproject.net.provider.AbstractProvider;
41 import org.onosproject.net.provider.ProviderId; 46 import org.onosproject.net.provider.ProviderId;
47 +import org.osgi.service.component.ComponentContext;
42 import org.slf4j.Logger; 48 import org.slf4j.Logger;
43 49
44 import java.net.URI; 50 import java.net.URI;
45 import java.net.URISyntaxException; 51 import java.net.URISyntaxException;
52 +import java.util.Dictionary;
46 import java.util.List; 53 import java.util.List;
47 import java.util.Map; 54 import java.util.Map;
48 import java.util.concurrent.ExecutorService; 55 import java.util.concurrent.ExecutorService;
...@@ -78,14 +85,22 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid ...@@ -78,14 +85,22 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid
78 85
79 //currently hardcoded. will be made configurable via rest/cli. 86 //currently hardcoded. will be made configurable via rest/cli.
80 private static final String SCHEME = "null"; 87 private static final String SCHEME = "null";
81 - private static final int NUMDEVICES = 10; 88 + private static final int DEF_NUMDEVICES = 10;
82 - private static final int NUMPORTSPERDEVICE = 10; 89 + private static final int DEF_NUMPORTS = 10;
83 90
84 //Delay between events in ms. 91 //Delay between events in ms.
85 private static final int EVENTINTERVAL = 5; 92 private static final int EVENTINTERVAL = 5;
86 93
87 private final Map<Integer, DeviceDescription> descriptions = Maps.newHashMap(); 94 private final Map<Integer, DeviceDescription> descriptions = Maps.newHashMap();
88 95
96 + @Property(name = "devConfigs", value = "", label = "Instance-specific configurations")
97 + private String devConfigs = "";
98 +
99 + private int numDevices = DEF_NUMDEVICES;
100 +
101 + @Property(name = "numPorts", intValue = DEF_NUMPORTS, label = "Number of ports per devices")
102 + private int numPorts = DEF_NUMPORTS;
103 +
89 private DeviceCreator creator; 104 private DeviceCreator creator;
90 105
91 106
...@@ -99,15 +114,17 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid ...@@ -99,15 +114,17 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid
99 } 114 }
100 115
101 @Activate 116 @Activate
102 - public void activate() { 117 + public void activate(ComponentContext context) {
103 providerService = providerRegistry.register(this); 118 providerService = providerRegistry.register(this);
104 - deviceBuilder.submit(new DeviceCreator(true)); 119 + if (modified(context)) {
120 + deviceBuilder.submit(new DeviceCreator(true));
121 + }
105 log.info("Started"); 122 log.info("Started");
106 123
107 } 124 }
108 125
109 @Deactivate 126 @Deactivate
110 - public void deactivate() { 127 + public void deactivate(ComponentContext context) {
111 deviceBuilder.submit(new DeviceCreator(false)); 128 deviceBuilder.submit(new DeviceCreator(false));
112 try { 129 try {
113 deviceBuilder.awaitTermination(1000, TimeUnit.MILLISECONDS); 130 deviceBuilder.awaitTermination(1000, TimeUnit.MILLISECONDS);
...@@ -121,6 +138,57 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid ...@@ -121,6 +138,57 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid
121 log.info("Stopped"); 138 log.info("Stopped");
122 } 139 }
123 140
141 + @Modified
142 + public boolean modified(ComponentContext context) {
143 + if (context == null) {
144 + log.info("No configuration file, using defaults: numDevices={}, numPorts={}",
145 + numDevices, numPorts);
146 + return false;
147 + }
148 +
149 + Dictionary<?, ?> properties = context.getProperties();
150 +
151 + int newDevNum = DEF_NUMDEVICES;
152 + int newPortNum = DEF_NUMPORTS;
153 + try {
154 + String s = (String) properties.get("devConfigs");
155 + if (!isNullOrEmpty(s)) {
156 + newDevNum = getDevicesConfig(s);
157 + }
158 + s = (String) properties.get("numPorts");
159 + newPortNum = isNullOrEmpty(s) ? DEF_NUMPORTS : Integer.valueOf(s.trim());
160 + } catch (Exception e) {
161 + log.warn(e.getMessage());
162 + }
163 +
164 + boolean chgd = false;
165 + if (newDevNum != numDevices) {
166 + numDevices = newDevNum;
167 + chgd |= true;
168 + }
169 + if (newPortNum != numPorts) {
170 + numPorts = newPortNum;
171 + chgd |= true;
172 + }
173 + log.info("Using settings numDevices={}, numPorts={}", numDevices, numPorts);
174 + return chgd;
175 + }
176 +
177 + private int getDevicesConfig(String config) {
178 + for (String sub : config.split(",")) {
179 + String[] params = sub.split(":");
180 + if (params.length == 2) {
181 + NodeId that = new NodeId(params[0].trim());
182 + String nd = params[1];
183 + if (clusterService.getLocalNode().id().equals(that)) {
184 + return Integer.valueOf(nd.trim());
185 + }
186 + continue;
187 + }
188 + }
189 + return DEF_NUMDEVICES;
190 + }
191 +
124 @Override 192 @Override
125 public void triggerProbe(DeviceId deviceId) {} 193 public void triggerProbe(DeviceId deviceId) {}
126 194
...@@ -169,10 +237,13 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid ...@@ -169,10 +237,13 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid
169 ChassisId cid; 237 ChassisId cid;
170 238
171 // nodeIdHash takes into account for nodeID to avoid collisions when running multi-node providers. 239 // nodeIdHash takes into account for nodeID to avoid collisions when running multi-node providers.
172 - int nodeIdHash = (clusterService.getLocalNode().hashCode() % NUMDEVICES) * NUMDEVICES; 240 + long nodeIdHash = clusterService.getLocalNode().hashCode() << 16;
241 +
242 + for (int i = 0; i < numDevices; i++) {
243 + // mark 'last' device to facilitate chaining of islands together
244 + long id = (i + 1 == numDevices) ? nodeIdHash | 0xffff : nodeIdHash | i;
173 245
174 - for (int i = nodeIdHash; i < nodeIdHash + NUMDEVICES; i++) { 246 + did = DeviceId.deviceId(new URI(SCHEME, toHex(id), null));
175 - did = DeviceId.deviceId(new URI(SCHEME, toHex(i), null));
176 cid = new ChassisId(i); 247 cid = new ChassisId(i);
177 DeviceDescription desc = 248 DeviceDescription desc =
178 new DefaultDeviceDescription(did.uri(), Device.Type.SWITCH, 249 new DefaultDeviceDescription(did.uri(), Device.Type.SWITCH,
...@@ -187,10 +258,10 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid ...@@ -187,10 +258,10 @@ public class NullDeviceProvider extends AbstractProvider implements DeviceProvid
187 258
188 private List<PortDescription> buildPorts() { 259 private List<PortDescription> buildPorts() {
189 List<PortDescription> ports = Lists.newArrayList(); 260 List<PortDescription> ports = Lists.newArrayList();
190 - for (int i = 0; i < NUMPORTSPERDEVICE; i++) { 261 + for (int i = 0; i < numPorts; i++) {
191 ports.add(new DefaultPortDescription(PortNumber.portNumber(i), true, 262 ports.add(new DefaultPortDescription(PortNumber.portNumber(i), true,
192 Port.Type.COPPER, 263 Port.Type.COPPER,
193 - (long) 0)); 264 + 0));
194 } 265 }
195 return ports; 266 return ports;
196 } 267 }
......
...@@ -132,7 +132,8 @@ public class NullHostProvider extends AbstractProvider implements HostProvider { ...@@ -132,7 +132,8 @@ public class NullHostProvider extends AbstractProvider implements HostProvider {
132 public void event(DeviceEvent event) { 132 public void event(DeviceEvent event) {
133 if (!deviceService.getRole(event.subject().id()) 133 if (!deviceService.getRole(event.subject().id())
134 .equals(MastershipRole.MASTER)) { 134 .equals(MastershipRole.MASTER)) {
135 - log.info("Local node is not master for device", event.subject().id()); 135 + log.info("Local node is not master for device {}", event
136 + .subject().id());
136 return; 137 return;
137 } 138 }
138 switch (event.type()) { 139 switch (event.type()) {
......
...@@ -46,9 +46,12 @@ import org.onosproject.net.device.DeviceListener; ...@@ -46,9 +46,12 @@ import org.onosproject.net.device.DeviceListener;
46 import org.onosproject.net.device.DeviceService; 46 import org.onosproject.net.device.DeviceService;
47 import org.onosproject.net.link.DefaultLinkDescription; 47 import org.onosproject.net.link.DefaultLinkDescription;
48 import org.onosproject.net.link.LinkDescription; 48 import org.onosproject.net.link.LinkDescription;
49 +import org.onosproject.net.link.LinkEvent;
50 +import org.onosproject.net.link.LinkListener;
49 import org.onosproject.net.link.LinkProvider; 51 import org.onosproject.net.link.LinkProvider;
50 import org.onosproject.net.link.LinkProviderRegistry; 52 import org.onosproject.net.link.LinkProviderRegistry;
51 import org.onosproject.net.link.LinkProviderService; 53 import org.onosproject.net.link.LinkProviderService;
54 +import org.onosproject.net.link.LinkService;
52 import org.onosproject.net.provider.AbstractProvider; 55 import org.onosproject.net.provider.AbstractProvider;
53 import org.onosproject.net.provider.ProviderId; 56 import org.onosproject.net.provider.ProviderId;
54 import org.osgi.service.component.ComponentContext; 57 import org.osgi.service.component.ComponentContext;
...@@ -74,6 +77,7 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -74,6 +77,7 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider {
74 77
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected LinkProviderRegistry providerRegistry; 79 protected LinkProviderRegistry providerRegistry;
80 + private LinkService linkService;
77 81
78 private LinkProviderService providerService; 82 private LinkProviderService providerService;
79 83
...@@ -84,13 +88,16 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -84,13 +88,16 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider {
84 private static final PortNumber DSTPORT = PortNumber.portNumber(6); 88 private static final PortNumber DSTPORT = PortNumber.portNumber(6);
85 89
86 private final InternalLinkProvider linkProvider = new InternalLinkProvider(); 90 private final InternalLinkProvider linkProvider = new InternalLinkProvider();
91 + private final InternalLinkListener listener = new InternalLinkListener();
87 92
88 // Link descriptions 93 // Link descriptions
89 private final ConcurrentMap<ConnectPoint, LinkDescription> descriptions = Maps 94 private final ConcurrentMap<ConnectPoint, LinkDescription> descriptions = Maps
90 .newConcurrentMap(); 95 .newConcurrentMap();
91 96
92 - // Device ID's that have been seen so far 97 + // Local Device ID's that have been seen so far
93 private final List<DeviceId> devices = Lists.newArrayList(); 98 private final List<DeviceId> devices = Lists.newArrayList();
99 + // tail ends of other islands
100 + private final List<ConnectPoint> tails = Lists.newArrayList();
94 101
95 private ExecutorService linkDriver = Executors.newFixedThreadPool(1, 102 private ExecutorService linkDriver = Executors.newFixedThreadPool(1,
96 namedThreads("onos-null-link-driver")); 103 namedThreads("onos-null-link-driver"));
...@@ -112,6 +119,8 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -112,6 +119,8 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider {
112 @Activate 119 @Activate
113 public void activate(ComponentContext context) { 120 public void activate(ComponentContext context) {
114 providerService = providerRegistry.register(this); 121 providerService = providerRegistry.register(this);
122 + linkService = (LinkService) providerRegistry;
123 + linkService.addListener(listener);
115 deviceService.addListener(linkProvider); 124 deviceService.addListener(linkProvider);
116 modified(context); 125 modified(context);
117 log.info("started"); 126 log.info("started");
...@@ -129,7 +138,9 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -129,7 +138,9 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider {
129 } 138 }
130 deviceService.removeListener(linkProvider); 139 deviceService.removeListener(linkProvider);
131 providerRegistry.unregister(this); 140 providerRegistry.unregister(this);
141 + linkService.removeListener(listener);
132 deviceService = null; 142 deviceService = null;
143 + linkService = null;
133 144
134 log.info("stopped"); 145 log.info("stopped");
135 } 146 }
...@@ -170,6 +181,11 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -170,6 +181,11 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider {
170 eventRate); 181 eventRate);
171 } 182 }
172 183
184 + // pick out substring from Deviceid
185 + private String part(String devId) {
186 + return devId.split(":")[1].substring(12, 16);
187 + }
188 +
173 /** 189 /**
174 * Adds links as devices are found, and generates LinkEvents. 190 * Adds links as devices are found, and generates LinkEvents.
175 */ 191 */
...@@ -178,9 +194,6 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -178,9 +194,6 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider {
178 @Override 194 @Override
179 public void event(DeviceEvent event) { 195 public void event(DeviceEvent event) {
180 Device dev = event.subject(); 196 Device dev = event.subject();
181 - if (!MASTER.equals(roleService.getLocalRole(dev.id()))) {
182 - return;
183 - }
184 switch (event.type()) { 197 switch (event.type()) {
185 case DEVICE_ADDED: 198 case DEVICE_ADDED:
186 addLink(dev); 199 addLink(dev);
...@@ -194,16 +207,26 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -194,16 +207,26 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider {
194 } 207 }
195 208
196 private void addLink(Device current) { 209 private void addLink(Device current) {
197 - devices.add(current.id()); 210 + DeviceId did = current.id();
198 - // No link if only one device 211 + if (!MASTER.equals(roleService.getLocalRole(did))) {
212 + String part = part(did.toString());
213 + if (part.equals("ffff")) {
214 + // 'tail' of an island - link us <- tail
215 + tails.add(new ConnectPoint(did, SRCPORT));
216 + }
217 + tryLinkTail();
218 + return;
219 + }
220 + devices.add(did);
221 +
199 if (devices.size() == 1) { 222 if (devices.size() == 1) {
200 return; 223 return;
201 } 224 }
202 225
203 - // Attach new device to the last-seen device 226 + // Normal flow - attach new device to the last-seen device
204 DeviceId prev = devices.get(devices.size() - 2); 227 DeviceId prev = devices.get(devices.size() - 2);
205 ConnectPoint src = new ConnectPoint(prev, SRCPORT); 228 ConnectPoint src = new ConnectPoint(prev, SRCPORT);
206 - ConnectPoint dst = new ConnectPoint(current.id(), DSTPORT); 229 + ConnectPoint dst = new ConnectPoint(did, DSTPORT);
207 230
208 LinkDescription fdesc = new DefaultLinkDescription(src, dst, 231 LinkDescription fdesc = new DefaultLinkDescription(src, dst,
209 Link.Type.DIRECT); 232 Link.Type.DIRECT);
...@@ -216,10 +239,66 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider { ...@@ -216,10 +239,66 @@ public class NullLinkProvider extends AbstractProvider implements LinkProvider {
216 providerService.linkDetected(rdesc); 239 providerService.linkDetected(rdesc);
217 } 240 }
218 241
242 + // try to link to a tail to first element
243 + private void tryLinkTail() {
244 + if (tails.isEmpty() || devices.isEmpty()) {
245 + return;
246 + }
247 + ConnectPoint first = new ConnectPoint(devices.get(0), DSTPORT);
248 + boolean added = false;
249 + for (ConnectPoint cp : tails) {
250 + if (!linkService.getLinks(cp).isEmpty()) {
251 + continue;
252 + }
253 + LinkDescription ld = new DefaultLinkDescription(cp, first,
254 + Link.Type.DIRECT);
255 + descriptions.put(cp, ld);
256 + providerService.linkDetected(ld);
257 + added = true;
258 + break;
259 + }
260 + if (added) {
261 + tails.clear();
262 + }
263 + }
264 +
219 private void removeLink(Device device) { 265 private void removeLink(Device device) {
266 + if (!MASTER.equals(roleService.getLocalRole(device.id()))) {
267 + return;
268 + }
220 providerService.linksVanished(device.id()); 269 providerService.linksVanished(device.id());
221 devices.remove(device.id()); 270 devices.remove(device.id());
222 } 271 }
272 +
273 + }
274 +
275 + private class InternalLinkListener implements LinkListener {
276 +
277 + @Override
278 + public void event(LinkEvent event) {
279 + switch (event.type()) {
280 + case LINK_ADDED:
281 + // If a link from another island, cast one back.
282 + DeviceId sdid = event.subject().src().deviceId();
283 + PortNumber pn = event.subject().src().port();
284 +
285 + if (roleService.getLocalRole(sdid).equals(MASTER)) {
286 + String part = part(sdid.toString());
287 + if (part.equals("ffff") && SRCPORT.equals(pn)) {
288 + LinkDescription ld = new DefaultLinkDescription(event
289 + .subject().dst(), event.subject().src(),
290 + Link.Type.DIRECT);
291 + descriptions.put(event.subject().dst(), ld);
292 + providerService.linkDetected(ld);
293 + }
294 + return;
295 + }
296 + break;
297 + default:
298 + break;
299 + }
300 + }
301 +
223 } 302 }
224 303
225 /** 304 /**
......
1 +#
2 +# Instance-specific configurations, in this case, the number of
3 +# devices per node.
4 +#
5 +devConfigs = 192.168.56.30:5,192.168.56.40:7
6 +
7 +#
8 +# Number of ports per device. This is global to all devices
9 +# on all instances.
10 +#
11 +# numPorts = 8