blob: d18ba5a2a730a7a7e2fa2403a9bf9dc5fd119be8 [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
Ayaka Koshibe35c71e12015-01-27 17:10:04 -080018import static com.google.common.base.Strings.isNullOrEmpty;
alshabib61286342014-12-24 10:34:00 -080019
20import com.google.common.collect.Lists;
21import com.google.common.collect.Maps;
Ayaka Koshibe35c71e12015-01-27 17:10:04 -080022
alshabib61286342014-12-24 10:34:00 -080023import org.apache.felix.scr.annotations.Activate;
24import org.apache.felix.scr.annotations.Component;
25import org.apache.felix.scr.annotations.Deactivate;
Ayaka Koshibe35c71e12015-01-27 17:10:04 -080026import org.apache.felix.scr.annotations.Modified;
27import org.apache.felix.scr.annotations.Property;
alshabib61286342014-12-24 10:34:00 -080028import org.apache.felix.scr.annotations.Reference;
29import org.apache.felix.scr.annotations.ReferenceCardinality;
30import org.onlab.packet.ChassisId;
suibinabeb7fa2015-01-20 20:58:49 -080031import org.onosproject.cluster.ClusterService;
Ayaka Koshibe35c71e12015-01-27 17:10:04 -080032import org.onosproject.cluster.NodeId;
alshabib61286342014-12-24 10:34:00 -080033import org.onosproject.net.Device;
34import org.onosproject.net.DeviceId;
35import org.onosproject.net.MastershipRole;
36import org.onosproject.net.Port;
37import org.onosproject.net.PortNumber;
38import org.onosproject.net.device.DefaultDeviceDescription;
39import org.onosproject.net.device.DefaultPortDescription;
40import org.onosproject.net.device.DeviceDescription;
41import org.onosproject.net.device.DeviceProvider;
42import org.onosproject.net.device.DeviceProviderRegistry;
43import org.onosproject.net.device.DeviceProviderService;
44import org.onosproject.net.device.PortDescription;
45import org.onosproject.net.provider.AbstractProvider;
46import org.onosproject.net.provider.ProviderId;
Ayaka Koshibe35c71e12015-01-27 17:10:04 -080047import org.osgi.service.component.ComponentContext;
alshabib61286342014-12-24 10:34:00 -080048import org.slf4j.Logger;
49
alshabib14233372015-01-21 13:45:25 -080050import java.net.URI;
51import java.net.URISyntaxException;
Ayaka Koshibe35c71e12015-01-27 17:10:04 -080052import java.util.Dictionary;
alshabib61286342014-12-24 10:34:00 -080053import java.util.List;
54import java.util.Map;
55import java.util.concurrent.ExecutorService;
56import java.util.concurrent.Executors;
57import java.util.concurrent.TimeUnit;
58
59import static org.onlab.util.Tools.delay;
60import static org.onlab.util.Tools.namedThreads;
alshabib14233372015-01-21 13:45:25 -080061import static org.onlab.util.Tools.toHex;
alshabib61286342014-12-24 10:34:00 -080062import static org.slf4j.LoggerFactory.getLogger;
63
64/**
65 * Provider which advertises fake/nonexistant devices to the core.
suibinabeb7fa2015-01-20 20:58:49 -080066 * nodeID is passed as part of the fake device id so that multiple nodes can run simultaneously.
alshabib61286342014-12-24 10:34:00 -080067 * To be used for benchmarking only.
68 */
69@Component(immediate = true)
70public class NullDeviceProvider extends AbstractProvider implements DeviceProvider {
71
72 private static final Logger log = getLogger(NullDeviceProvider.class);
suibinabeb7fa2015-01-20 20:58:49 -080073
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected ClusterService clusterService;
alshabib61286342014-12-24 10:34:00 -080076
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected DeviceProviderRegistry providerRegistry;
79
80 private DeviceProviderService providerService;
81
82 private ExecutorService deviceBuilder = Executors.newFixedThreadPool(1,
Thomas Vachuska9ea3e6f2015-01-23 16:34:22 -080083 namedThreads("onos-null-device-creator"));
alshabib61286342014-12-24 10:34:00 -080084
85
alshabib61286342014-12-24 10:34:00 -080086 //currently hardcoded. will be made configurable via rest/cli.
alshabib14233372015-01-21 13:45:25 -080087 private static final String SCHEME = "null";
Ayaka Koshibe35c71e12015-01-27 17:10:04 -080088 private static final int DEF_NUMDEVICES = 10;
89 private static final int DEF_NUMPORTS = 10;
alshabib61286342014-12-24 10:34:00 -080090
91 //Delay between events in ms.
92 private static final int EVENTINTERVAL = 5;
93
94 private final Map<Integer, DeviceDescription> descriptions = Maps.newHashMap();
95
Ayaka Koshibe35c71e12015-01-27 17:10:04 -080096 @Property(name = "devConfigs", value = "", label = "Instance-specific configurations")
97 private String devConfigs = "";
98
99 private int numDevices = DEF_NUMDEVICES;
100
Ayaka Koshibe2a85e842015-01-29 15:39:40 -0800101 @Property(name = "numPorts", value = "10", label = "Number of ports per devices")
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800102 private int numPorts = DEF_NUMPORTS;
103
alshabib61286342014-12-24 10:34:00 -0800104 private DeviceCreator creator;
105
106
107 /**
108 *
109 * Creates a provider with the supplier identifier.
110 *
111 */
112 public NullDeviceProvider() {
113 super(new ProviderId("null", "org.onosproject.provider.nil"));
114 }
115
116 @Activate
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800117 public void activate(ComponentContext context) {
alshabib61286342014-12-24 10:34:00 -0800118 providerService = providerRegistry.register(this);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800119 if (!modified(context)) {
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800120 deviceBuilder.submit(new DeviceCreator(true));
121 }
alshabib61286342014-12-24 10:34:00 -0800122 log.info("Started");
123
124 }
125
126 @Deactivate
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800127 public void deactivate(ComponentContext context) {
alshabib61286342014-12-24 10:34:00 -0800128 deviceBuilder.submit(new DeviceCreator(false));
129 try {
130 deviceBuilder.awaitTermination(1000, TimeUnit.MILLISECONDS);
131 } catch (InterruptedException e) {
132 log.error("Device builder did not terminate");
133 }
134 deviceBuilder.shutdownNow();
135 providerRegistry.unregister(this);
136 providerService = null;
137
138 log.info("Stopped");
139 }
140
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800141 @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");
Yuta HIGUCHIdd9228d2015-02-10 22:26:59 -0800159 newPortNum = isNullOrEmpty(s) ? DEF_NUMPORTS : Integer.parseInt(s.trim());
Pavlin Radoslavovb9e50df2015-02-20 20:01:26 -0800160 } catch (NumberFormatException | ClassCastException e) {
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800161 log.warn(e.getMessage());
Ayaka Koshibe2a85e842015-01-29 15:39:40 -0800162 newDevNum = numDevices;
163 newPortNum = numPorts;
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800164 }
165
166 boolean chgd = false;
167 if (newDevNum != numDevices) {
168 numDevices = newDevNum;
169 chgd |= true;
170 }
171 if (newPortNum != numPorts) {
172 numPorts = newPortNum;
173 chgd |= true;
174 }
175 log.info("Using settings numDevices={}, numPorts={}", numDevices, numPorts);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800176 if (chgd) {
177 deviceBuilder.submit(new DeviceCreator(true));
178 }
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800179 return chgd;
180 }
181
182 private int getDevicesConfig(String config) {
183 for (String sub : config.split(",")) {
184 String[] params = sub.split(":");
185 if (params.length == 2) {
186 NodeId that = new NodeId(params[0].trim());
187 String nd = params[1];
188 if (clusterService.getLocalNode().id().equals(that)) {
Yuta HIGUCHIdd9228d2015-02-10 22:26:59 -0800189 return Integer.parseInt(nd.trim());
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800190 }
191 continue;
192 }
193 }
194 return DEF_NUMDEVICES;
195 }
196
alshabib61286342014-12-24 10:34:00 -0800197 @Override
198 public void triggerProbe(DeviceId deviceId) {}
199
200 @Override
201 public void roleChanged(DeviceId deviceId, MastershipRole newRole) {}
202
203 @Override
204 public boolean isReachable(DeviceId deviceId) {
205 return descriptions.values().stream()
206 .anyMatch(desc -> desc.deviceURI().equals(deviceId.uri()));
207 }
208
209
210 private class DeviceCreator implements Runnable {
211
212 private boolean setup;
213
214 public DeviceCreator(boolean setup) {
215 this.setup = setup;
216 }
217
218 @Override
219 public void run() {
220 if (setup) {
alshabib14233372015-01-21 13:45:25 -0800221 try {
222 advertiseDevices();
223 } catch (URISyntaxException e) {
224 log.warn("URI creation failed during device adverts {}", e.getMessage());
225 }
alshabib61286342014-12-24 10:34:00 -0800226 } else {
227 removeDevices();
228 }
229 }
230
231 private void removeDevices() {
232 for (DeviceDescription desc : descriptions.values()) {
233 providerService.deviceDisconnected(
234 DeviceId.deviceId(desc.deviceURI()));
235 delay(EVENTINTERVAL);
236 }
237 descriptions.clear();
238 }
239
alshabib14233372015-01-21 13:45:25 -0800240 private void advertiseDevices() throws URISyntaxException {
alshabib61286342014-12-24 10:34:00 -0800241 DeviceId did;
242 ChassisId cid;
suibinabeb7fa2015-01-20 20:58:49 -0800243
244 // nodeIdHash takes into account for nodeID to avoid collisions when running multi-node providers.
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800245 long nodeIdHash = clusterService.getLocalNode().hashCode() << 16;
suibinabeb7fa2015-01-20 20:58:49 -0800246
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800247 for (int i = 0; i < numDevices; i++) {
248 // mark 'last' device to facilitate chaining of islands together
249 long id = (i + 1 == numDevices) ? nodeIdHash | 0xffff : nodeIdHash | i;
250
251 did = DeviceId.deviceId(new URI(SCHEME, toHex(id), null));
alshabib61286342014-12-24 10:34:00 -0800252 cid = new ChassisId(i);
253 DeviceDescription desc =
254 new DefaultDeviceDescription(did.uri(), Device.Type.SWITCH,
255 "ON.Lab", "0.0.1", "0.0.1", "1234",
256 cid);
257 descriptions.put(i, desc);
258 providerService.deviceConnected(did, desc);
259 providerService.updatePorts(did, buildPorts());
260 delay(EVENTINTERVAL);
261 }
262 }
263
264 private List<PortDescription> buildPorts() {
265 List<PortDescription> ports = Lists.newArrayList();
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800266 for (int i = 0; i < numPorts; i++) {
alshabib61286342014-12-24 10:34:00 -0800267 ports.add(new DefaultPortDescription(PortNumber.portNumber(i), true,
268 Port.Type.COPPER,
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800269 0));
alshabib61286342014-12-24 10:34:00 -0800270 }
271 return ports;
272 }
273 }
274}