blob: 8587a0aac8242220d51a97189bd086786fa7c789 [file] [log] [blame]
Ayaka Koshibe422916f2015-01-15 15:30:23 -08001/*
2 * Copyright 2015 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.link.impl;
17
18import static com.google.common.base.Strings.isNullOrEmpty;
Ayaka Koshibe422916f2015-01-15 15:30:23 -080019import static org.onlab.util.Tools.namedThreads;
20import static org.slf4j.LoggerFactory.getLogger;
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -080021import static org.onlab.util.Tools.toHex;
Ayaka Koshibe0cd42822015-01-22 16:02:31 -080022import static org.onosproject.net.MastershipRole.MASTER;
Ayaka Koshibe422916f2015-01-15 15:30:23 -080023
24import java.util.Dictionary;
25import java.util.List;
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -080026import java.util.Objects;
Ayaka Koshibe422916f2015-01-15 15:30:23 -080027import java.util.concurrent.ConcurrentMap;
28import java.util.concurrent.ExecutorService;
29import java.util.concurrent.Executors;
30import java.util.concurrent.TimeUnit;
31
32import org.apache.felix.scr.annotations.Activate;
33import org.apache.felix.scr.annotations.Component;
34import org.apache.felix.scr.annotations.Deactivate;
Ayaka Koshibe7dc1d042015-01-21 15:28:03 -080035import org.apache.felix.scr.annotations.Modified;
Ayaka Koshibe422916f2015-01-15 15:30:23 -080036import org.apache.felix.scr.annotations.Property;
37import org.apache.felix.scr.annotations.Reference;
38import org.apache.felix.scr.annotations.ReferenceCardinality;
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -080039import org.onosproject.cluster.ClusterService;
40import org.onosproject.cluster.NodeId;
Ayaka Koshibe0cd42822015-01-22 16:02:31 -080041import org.onosproject.mastership.MastershipService;
Ayaka Koshibe422916f2015-01-15 15:30:23 -080042import org.onosproject.net.ConnectPoint;
43import org.onosproject.net.Device;
44import org.onosproject.net.DeviceId;
45import org.onosproject.net.Link;
46import org.onosproject.net.PortNumber;
47import org.onosproject.net.device.DeviceEvent;
48import org.onosproject.net.device.DeviceListener;
49import org.onosproject.net.device.DeviceService;
50import org.onosproject.net.link.DefaultLinkDescription;
51import org.onosproject.net.link.LinkDescription;
Ayaka Koshibe35c71e12015-01-27 17:10:04 -080052import org.onosproject.net.link.LinkEvent;
53import org.onosproject.net.link.LinkListener;
Ayaka Koshibe422916f2015-01-15 15:30:23 -080054import org.onosproject.net.link.LinkProvider;
55import org.onosproject.net.link.LinkProviderRegistry;
56import org.onosproject.net.link.LinkProviderService;
Ayaka Koshibe35c71e12015-01-27 17:10:04 -080057import org.onosproject.net.link.LinkService;
Ayaka Koshibe422916f2015-01-15 15:30:23 -080058import org.onosproject.net.provider.AbstractProvider;
59import org.onosproject.net.provider.ProviderId;
60import org.osgi.service.component.ComponentContext;
61import org.slf4j.Logger;
62
63import com.google.common.collect.Lists;
64import com.google.common.collect.Maps;
65
66/**
67 * Provider which advertises fake/nonexistent links to the core. To be used for
68 * benchmarking only.
69 */
70@Component(immediate = true)
71public class NullLinkProvider extends AbstractProvider implements LinkProvider {
72
73 private final Logger log = getLogger(getClass());
74
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected DeviceService deviceService;
77
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ayaka Koshibe0cd42822015-01-22 16:02:31 -080079 protected MastershipService roleService;
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -080082 protected ClusterService nodeService;
83
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ayaka Koshibe422916f2015-01-15 15:30:23 -080085 protected LinkProviderRegistry providerRegistry;
Ayaka Koshibe35c71e12015-01-27 17:10:04 -080086 private LinkService linkService;
Ayaka Koshibe422916f2015-01-15 15:30:23 -080087
88 private LinkProviderService providerService;
89
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -080090 private static final int DEFAULT_RATE = 0;
Ayaka Koshibe422916f2015-01-15 15:30:23 -080091 // For now, static switch port values
92 private static final PortNumber SRCPORT = PortNumber.portNumber(5);
93 private static final PortNumber DSTPORT = PortNumber.portNumber(6);
94
95 private final InternalLinkProvider linkProvider = new InternalLinkProvider();
Ayaka Koshibe35c71e12015-01-27 17:10:04 -080096 private final InternalLinkListener listener = new InternalLinkListener();
Ayaka Koshibe422916f2015-01-15 15:30:23 -080097
98 // Link descriptions
99 private final ConcurrentMap<ConnectPoint, LinkDescription> descriptions = Maps
100 .newConcurrentMap();
101
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800102 // Local Device ID's that have been seen so far
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800103 private final List<DeviceId> devices = Lists.newArrayList();
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800104 // tail ends of other islands
105 private final List<ConnectPoint> tails = Lists.newArrayList();
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800106
107 private ExecutorService linkDriver = Executors.newFixedThreadPool(1,
Thomas Vachuska9ea3e6f2015-01-23 16:34:22 -0800108 namedThreads("onos-null-link-driver"));
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800109
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800110 // For flicker = true, duration between events in msec.
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800111 @Property(name = "eventRate", value = "0",
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800112 label = "Duration between Link Event")
Ayaka Koshibe0cd42822015-01-22 16:02:31 -0800113 private int eventRate = DEFAULT_RATE;
suibin1a7b7bd2015-02-12 09:41:47 -0800114 private int checkRateDuration = 10;
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800115
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800116 // For flicker = true, duration between events in msec.
117 @Property(name = "neighbors", value = "",
118 label = "Node ID of instance for neighboring island ")
119 private String neighbor = "";
120
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800121 public NullLinkProvider() {
122 super(new ProviderId("null", "org.onosproject.provider.nil"));
123 }
124
125 @Activate
126 public void activate(ComponentContext context) {
127 providerService = providerRegistry.register(this);
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800128 linkService = (LinkService) providerRegistry;
129 linkService.addListener(listener);
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800130 deviceService.addListener(linkProvider);
131 modified(context);
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800132 log.info("started");
133 }
134
135 @Deactivate
136 public void deactivate(ComponentContext context) {
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800137 if (eventRate != 0) {
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800138 try {
139 linkDriver.awaitTermination(1000, TimeUnit.MILLISECONDS);
140 } catch (InterruptedException e) {
141 log.error("LinkBuilder did not terminate");
142 }
143 linkDriver.shutdownNow();
144 }
145 deviceService.removeListener(linkProvider);
146 providerRegistry.unregister(this);
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800147 linkService.removeListener(listener);
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800148 deviceService = null;
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800149 linkService = null;
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800150
151 log.info("stopped");
152 }
153
Ayaka Koshibe7dc1d042015-01-21 15:28:03 -0800154 @Modified
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800155 public void modified(ComponentContext context) {
156 if (context == null) {
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800157 log.info("No configs, using defaults: eventRate={}", DEFAULT_RATE);
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800158 return;
159 }
160 Dictionary<?, ?> properties = context.getProperties();
161
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800162 int newRate;
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800163 String newNbor;
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800164 try {
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800165 String s = (String) properties.get("eventRate");
Yuta HIGUCHIdd9228d2015-02-10 22:26:59 -0800166 newRate = isNullOrEmpty(s) ? eventRate : Integer.parseInt(s.trim());
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800167 s = (String) properties.get("neighbors");
168 newNbor = isNullOrEmpty(s) ? neighbor : getNeighbor(s.trim());
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800169 } catch (Exception e) {
170 log.warn(e.getMessage());
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800171 newRate = eventRate;
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800172 newNbor = neighbor;
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800173 }
174
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800175 if (newNbor != neighbor) {
176 neighbor = newNbor;
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800177 }
178
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800179 if (newRate != 0 & eventRate != newRate) {
180 eventRate = newRate;
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800181 linkDriver.submit(new LinkDriver());
182 }
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800183
184 log.info("Using new settings: eventRate={}", eventRate);
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800185 }
186
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800187 // pick out substring from Deviceid
188 private String part(String devId) {
189 return devId.split(":")[1].substring(12, 16);
190 }
191
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800192 // pick out substring from Deviceid
193 private String nIdPart(String devId) {
194 return devId.split(":")[1].substring(9, 12);
195 }
196
197 // pick out the next node ID in string, return hash (i.e. what's
198 // in a Device ID
199 private String getNeighbor(String nbors) {
200 String me = nodeService.getLocalNode().id().toString();
201 String mynb = "";
202 String[] nodes = nbors.split(",");
203 for (int i = 0; i < nodes.length; i++) {
204 if (i != 0 & nodes[i].equals(me)) {
205 mynb = nodes[i - 1];
206 break;
207 }
208 }
209 // return as hash string.
210 if (!mynb.isEmpty()) {
211 return toHex((Objects.hash(new NodeId(mynb)))).substring(13, 16);
212 }
213 return "";
214 }
215
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800216 /**
217 * Adds links as devices are found, and generates LinkEvents.
218 */
219 private class InternalLinkProvider implements DeviceListener {
220
221 @Override
222 public void event(DeviceEvent event) {
Ayaka Koshibe0cd42822015-01-22 16:02:31 -0800223 Device dev = event.subject();
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800224 switch (event.type()) {
225 case DEVICE_ADDED:
Ayaka Koshibe0cd42822015-01-22 16:02:31 -0800226 addLink(dev);
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800227 break;
228 case DEVICE_REMOVED:
Ayaka Koshibe0cd42822015-01-22 16:02:31 -0800229 removeLink(dev);
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800230 break;
231 default:
232 break;
233 }
234 }
235
236 private void addLink(Device current) {
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800237 DeviceId did = current.id();
238 if (!MASTER.equals(roleService.getLocalRole(did))) {
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800239
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800240 String part = part(did.toString());
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800241 String npart = nIdPart(did.toString());
Yuta HIGUCHIdd9228d2015-02-10 22:26:59 -0800242 if (part.equals("ffff") && npart.equals(neighbor)) {
Ayaka Koshibe8eddc0d2015-02-02 18:07:29 -0800243 // 'tail' of our neighboring island - link us <- tail
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800244 tails.add(new ConnectPoint(did, SRCPORT));
245 }
246 tryLinkTail();
247 return;
248 }
249 devices.add(did);
250
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800251 if (devices.size() == 1) {
252 return;
253 }
254
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800255 // Normal flow - attach new device to the last-seen device
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800256 DeviceId prev = devices.get(devices.size() - 2);
257 ConnectPoint src = new ConnectPoint(prev, SRCPORT);
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800258 ConnectPoint dst = new ConnectPoint(did, DSTPORT);
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800259
260 LinkDescription fdesc = new DefaultLinkDescription(src, dst,
261 Link.Type.DIRECT);
262 LinkDescription rdesc = new DefaultLinkDescription(dst, src,
263 Link.Type.DIRECT);
264 descriptions.put(src, fdesc);
265 descriptions.put(dst, rdesc);
266
267 providerService.linkDetected(fdesc);
268 providerService.linkDetected(rdesc);
269 }
270
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800271 // try to link to a tail to first element
272 private void tryLinkTail() {
273 if (tails.isEmpty() || devices.isEmpty()) {
274 return;
275 }
276 ConnectPoint first = new ConnectPoint(devices.get(0), DSTPORT);
277 boolean added = false;
278 for (ConnectPoint cp : tails) {
279 if (!linkService.getLinks(cp).isEmpty()) {
280 continue;
281 }
282 LinkDescription ld = new DefaultLinkDescription(cp, first,
283 Link.Type.DIRECT);
284 descriptions.put(cp, ld);
285 providerService.linkDetected(ld);
286 added = true;
287 break;
288 }
289 if (added) {
290 tails.clear();
291 }
292 }
293
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800294 private void removeLink(Device device) {
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800295 if (!MASTER.equals(roleService.getLocalRole(device.id()))) {
296 return;
297 }
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800298 providerService.linksVanished(device.id());
299 devices.remove(device.id());
300 }
Ayaka Koshibe35c71e12015-01-27 17:10:04 -0800301
302 }
303
304 private class InternalLinkListener implements LinkListener {
305
306 @Override
307 public void event(LinkEvent event) {
308 switch (event.type()) {
309 case LINK_ADDED:
310 // If a link from another island, cast one back.
311 DeviceId sdid = event.subject().src().deviceId();
312 PortNumber pn = event.subject().src().port();
313
314 if (roleService.getLocalRole(sdid).equals(MASTER)) {
315 String part = part(sdid.toString());
316 if (part.equals("ffff") && SRCPORT.equals(pn)) {
317 LinkDescription ld = new DefaultLinkDescription(event
318 .subject().dst(), event.subject().src(),
319 Link.Type.DIRECT);
320 descriptions.put(event.subject().dst(), ld);
321 providerService.linkDetected(ld);
322 }
323 return;
324 }
325 break;
326 default:
327 break;
328 }
329 }
330
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800331 }
332
333 /**
334 * Generates link events using fake links.
335 */
336 private class LinkDriver implements Runnable {
337
338 @Override
339 public void run() {
suibin1a7b7bd2015-02-12 09:41:47 -0800340 long startTime = System.currentTimeMillis();
341 long countEvent = 0;
342 float effLoad = 0;
343
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800344 while (!linkDriver.isShutdown()) {
suibin1a7b7bd2015-02-12 09:41:47 -0800345
346 //Assuming eventRate is in microsecond unit
347 if (countEvent <= checkRateDuration * 1000000 / eventRate) {
348 for (LinkDescription desc : descriptions.values()) {
349 providerService.linkVanished(desc);
350 countEvent++;
351 try {
352 TimeUnit.MICROSECONDS.sleep(eventRate);
353 } catch (InterruptedException e) {
354 log.warn(String.valueOf(e));
355 }
356 providerService.linkDetected(desc);
357 countEvent++;
358 try {
359 TimeUnit.MICROSECONDS.sleep(eventRate);
360 } catch (InterruptedException e) {
361 log.warn(String.valueOf(e));
362 }
363 }
364 } else {
365 // log in WARN the effective load generation rate in events/sec, every 10 seconds
366 effLoad = (float) (countEvent * 1000 / (System.currentTimeMillis() - startTime));
367 log.warn("Effective Loading is {} events/second", String.valueOf(effLoad));
368 countEvent = 0;
369 startTime = System.currentTimeMillis();
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800370 }
371 }
372 }
373 }
374}