blob: 9cbd7c5af76d7c0f8e46e2944b1098e64682795d [file] [log] [blame]
alshabib61286342014-12-24 10:34:00 -08001/*
2 * Copyright 2014 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.device.impl;
17
alshabib61286342014-12-24 10:34:00 -080018import com.google.common.collect.Lists;
19import com.google.common.collect.Maps;
20import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
Ayaka Koshibe35c71e12015-01-27 17:10:04 -080023import org.apache.felix.scr.annotations.Modified;
24import org.apache.felix.scr.annotations.Property;
alshabib61286342014-12-24 10:34:00 -080025import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
27import org.onlab.packet.ChassisId;
suibinabeb7fa2015-01-20 20:58:49 -080028import org.onosproject.cluster.ClusterService;
Ayaka Koshibe35c71e12015-01-27 17:10:04 -080029import org.onosproject.cluster.NodeId;
alshabib61286342014-12-24 10:34:00 -080030import org.onosproject.net.Device;
31import org.onosproject.net.DeviceId;
32import org.onosproject.net.MastershipRole;
33import org.onosproject.net.Port;
34import org.onosproject.net.PortNumber;
35import org.onosproject.net.device.DefaultDeviceDescription;
36import org.onosproject.net.device.DefaultPortDescription;
37import org.onosproject.net.device.DeviceDescription;
38import org.onosproject.net.device.DeviceProvider;
39import org.onosproject.net.device.DeviceProviderRegistry;
40import org.onosproject.net.device.DeviceProviderService;
41import org.onosproject.net.device.PortDescription;
42import org.onosproject.net.provider.AbstractProvider;
43import org.onosproject.net.provider.ProviderId;
Ayaka Koshibe35c71e12015-01-27 17:10:04 -080044import org.osgi.service.component.ComponentContext;
alshabib61286342014-12-24 10:34:00 -080045import org.slf4j.Logger;
46
alshabib14233372015-01-21 13:45:25 -080047import java.net.URI;
48import java.net.URISyntaxException;
Ayaka Koshibe35c71e12015-01-27 17:10:04 -080049import java.util.Dictionary;
alshabib61286342014-12-24 10:34:00 -080050import java.util.List;
51import java.util.Map;
52import java.util.concurrent.ExecutorService;
53import java.util.concurrent.Executors;
54import java.util.concurrent.TimeUnit;
55
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080056import static com.google.common.base.Strings.isNullOrEmpty;
57import static org.onlab.util.Tools.*;
alshabib61286342014-12-24 10:34:00 -080058import static org.slf4j.LoggerFactory.getLogger;
59
60/**
61 * Provider which advertises fake/nonexistant devices to the core.
suibinabeb7fa2015-01-20 20:58:49 -080062 * nodeID is passed as part of the fake device id so that multiple nodes can run simultaneously.
alshabib61286342014-12-24 10:34:00 -080063 * To be used for benchmarking only.
64 */
65@Component(immediate = true)
66public class NullDeviceProvider extends AbstractProvider implements DeviceProvider {
67
68 private static final Logger log = getLogger(NullDeviceProvider.class);
suibinabeb7fa2015-01-20 20:58:49 -080069
70 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 protected ClusterService clusterService;
alshabib61286342014-12-24 10:34:00 -080072
73 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 protected DeviceProviderRegistry providerRegistry;
75
76 private DeviceProviderService providerService;
77
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080078 private ExecutorService deviceBuilder =
79 Executors.newFixedThreadPool(1, groupedThreads("onos/null", "device-creator"));
alshabib61286342014-12-24 10:34:00 -080080
alshabib14233372015-01-21 13:45:25 -080081 private static final String SCHEME = "null";
Ayaka Koshibe35c71e12015-01-27 17:10:04 -080082 private static final int DEF_NUMDEVICES = 10;
83 private static final int DEF_NUMPORTS = 10;
alshabib61286342014-12-24 10:34:00 -080084
85 //Delay between events in ms.
86 private static final int EVENTINTERVAL = 5;
87
88 private final Map<Integer, DeviceDescription> descriptions = Maps.newHashMap();
89
Ayaka Koshibe35c71e12015-01-27 17:10:04 -080090 @Property(name = "devConfigs", value = "", label = "Instance-specific configurations")
91 private String devConfigs = "";
92
93 private int numDevices = DEF_NUMDEVICES;
94
Ayaka Koshibe2a85e842015-01-29 15:39:40 -080095 @Property(name = "numPorts", value = "10", label = "Number of ports per devices")
Ayaka Koshibe35c71e12015-01-27 17:10:04 -080096 private int numPorts = DEF_NUMPORTS;
97
alshabib61286342014-12-24 10:34:00 -080098 private DeviceCreator creator;
99
alshabib61286342014-12-24 10:34:00 -0800100 /**
101 *
102 * Creates a provider with the supplier identifier.
103 *
104 */
105 public NullDeviceProvider() {
106 super(new ProviderId("null", "org.onosproject.provider.nil"));
107 }
108
109 @Activate
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800110 public void activate(ComponentContext context) {
alshabib61286342014-12-24 10:34:00 -0800111 providerService = providerRegistry.register(this);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800112 if (!modified(context)) {
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800113 deviceBuilder.submit(new DeviceCreator(true));
114 }
alshabib61286342014-12-24 10:34:00 -0800115 log.info("Started");
116
117 }
118
119 @Deactivate
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800120 public void deactivate(ComponentContext context) {
alshabib61286342014-12-24 10:34:00 -0800121 deviceBuilder.submit(new DeviceCreator(false));
122 try {
123 deviceBuilder.awaitTermination(1000, TimeUnit.MILLISECONDS);
124 } catch (InterruptedException e) {
125 log.error("Device builder did not terminate");
126 }
127 deviceBuilder.shutdownNow();
128 providerRegistry.unregister(this);
129 providerService = null;
130
131 log.info("Stopped");
132 }
133
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800134 @Modified
135 public boolean modified(ComponentContext context) {
136 if (context == null) {
137 log.info("No configuration file, using defaults: numDevices={}, numPorts={}",
138 numDevices, numPorts);
139 return false;
140 }
141
142 Dictionary<?, ?> properties = context.getProperties();
143
144 int newDevNum = DEF_NUMDEVICES;
145 int newPortNum = DEF_NUMPORTS;
146 try {
147 String s = (String) properties.get("devConfigs");
148 if (!isNullOrEmpty(s)) {
149 newDevNum = getDevicesConfig(s);
150 }
151 s = (String) properties.get("numPorts");
Yuta HIGUCHIdd9228d2015-02-10 22:26:59 -0800152 newPortNum = isNullOrEmpty(s) ? DEF_NUMPORTS : Integer.parseInt(s.trim());
Pavlin Radoslavovb9e50df2015-02-20 20:01:26 -0800153 } catch (NumberFormatException | ClassCastException e) {
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800154 log.warn(e.getMessage());
Ayaka Koshibe2a85e842015-01-29 15:39:40 -0800155 newDevNum = numDevices;
156 newPortNum = numPorts;
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800157 }
158
159 boolean chgd = false;
160 if (newDevNum != numDevices) {
161 numDevices = newDevNum;
162 chgd |= true;
163 }
164 if (newPortNum != numPorts) {
165 numPorts = newPortNum;
166 chgd |= true;
167 }
168 log.info("Using settings numDevices={}, numPorts={}", numDevices, numPorts);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800169 if (chgd) {
170 deviceBuilder.submit(new DeviceCreator(true));
171 }
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800172 return chgd;
173 }
174
175 private int getDevicesConfig(String config) {
176 for (String sub : config.split(",")) {
177 String[] params = sub.split(":");
178 if (params.length == 2) {
179 NodeId that = new NodeId(params[0].trim());
180 String nd = params[1];
181 if (clusterService.getLocalNode().id().equals(that)) {
Yuta HIGUCHIdd9228d2015-02-10 22:26:59 -0800182 return Integer.parseInt(nd.trim());
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800183 }
184 continue;
185 }
186 }
187 return DEF_NUMDEVICES;
188 }
189
alshabib61286342014-12-24 10:34:00 -0800190 @Override
191 public void triggerProbe(DeviceId deviceId) {}
192
193 @Override
194 public void roleChanged(DeviceId deviceId, MastershipRole newRole) {}
195
196 @Override
197 public boolean isReachable(DeviceId deviceId) {
198 return descriptions.values().stream()
199 .anyMatch(desc -> desc.deviceURI().equals(deviceId.uri()));
200 }
201
202
203 private class DeviceCreator implements Runnable {
204
205 private boolean setup;
206
207 public DeviceCreator(boolean setup) {
208 this.setup = setup;
209 }
210
211 @Override
212 public void run() {
213 if (setup) {
alshabib14233372015-01-21 13:45:25 -0800214 try {
215 advertiseDevices();
216 } catch (URISyntaxException e) {
217 log.warn("URI creation failed during device adverts {}", e.getMessage());
218 }
alshabib61286342014-12-24 10:34:00 -0800219 } else {
220 removeDevices();
221 }
222 }
223
224 private void removeDevices() {
225 for (DeviceDescription desc : descriptions.values()) {
226 providerService.deviceDisconnected(
227 DeviceId.deviceId(desc.deviceURI()));
228 delay(EVENTINTERVAL);
229 }
230 descriptions.clear();
231 }
232
alshabib14233372015-01-21 13:45:25 -0800233 private void advertiseDevices() throws URISyntaxException {
alshabib61286342014-12-24 10:34:00 -0800234 DeviceId did;
235 ChassisId cid;
suibinabeb7fa2015-01-20 20:58:49 -0800236
237 // nodeIdHash takes into account for nodeID to avoid collisions when running multi-node providers.
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800238 long nodeIdHash = clusterService.getLocalNode().id().hashCode() << 16;
suibinabeb7fa2015-01-20 20:58:49 -0800239
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800240 for (int i = 0; i < numDevices; i++) {
Ayaka Koshibe839a8a92015-03-03 17:07:22 -0800241 long id = nodeIdHash | i;
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800242
243 did = DeviceId.deviceId(new URI(SCHEME, toHex(id), null));
alshabib61286342014-12-24 10:34:00 -0800244 cid = new ChassisId(i);
245 DeviceDescription desc =
246 new DefaultDeviceDescription(did.uri(), Device.Type.SWITCH,
247 "ON.Lab", "0.0.1", "0.0.1", "1234",
248 cid);
249 descriptions.put(i, desc);
250 providerService.deviceConnected(did, desc);
251 providerService.updatePorts(did, buildPorts());
252 delay(EVENTINTERVAL);
253 }
254 }
255
256 private List<PortDescription> buildPorts() {
257 List<PortDescription> ports = Lists.newArrayList();
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800258 for (int i = 0; i < numPorts; i++) {
alshabib61286342014-12-24 10:34:00 -0800259 ports.add(new DefaultPortDescription(PortNumber.portNumber(i), true,
260 Port.Type.COPPER,
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800261 0));
alshabib61286342014-12-24 10:34:00 -0800262 }
263 return ports;
264 }
265 }
266}