blob: c12991a051af9c44fcf8b16ae4f4edfe6c7f8071 [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;
19import static org.onlab.util.Tools.delay;
20import static org.onlab.util.Tools.namedThreads;
21import static org.slf4j.LoggerFactory.getLogger;
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;
26import java.util.concurrent.ConcurrentMap;
27import java.util.concurrent.ExecutorService;
28import java.util.concurrent.Executors;
29import java.util.concurrent.TimeUnit;
30
31import org.apache.felix.scr.annotations.Activate;
32import org.apache.felix.scr.annotations.Component;
33import org.apache.felix.scr.annotations.Deactivate;
Ayaka Koshibe7dc1d042015-01-21 15:28:03 -080034import org.apache.felix.scr.annotations.Modified;
Ayaka Koshibe422916f2015-01-15 15:30:23 -080035import org.apache.felix.scr.annotations.Property;
36import org.apache.felix.scr.annotations.Reference;
37import org.apache.felix.scr.annotations.ReferenceCardinality;
Ayaka Koshibe0cd42822015-01-22 16:02:31 -080038import org.onosproject.mastership.MastershipService;
Ayaka Koshibe422916f2015-01-15 15:30:23 -080039import org.onosproject.net.ConnectPoint;
40import org.onosproject.net.Device;
41import org.onosproject.net.DeviceId;
42import org.onosproject.net.Link;
43import org.onosproject.net.PortNumber;
44import org.onosproject.net.device.DeviceEvent;
45import org.onosproject.net.device.DeviceListener;
46import org.onosproject.net.device.DeviceService;
47import org.onosproject.net.link.DefaultLinkDescription;
48import org.onosproject.net.link.LinkDescription;
49import org.onosproject.net.link.LinkProvider;
50import org.onosproject.net.link.LinkProviderRegistry;
51import org.onosproject.net.link.LinkProviderService;
52import org.onosproject.net.provider.AbstractProvider;
53import org.onosproject.net.provider.ProviderId;
54import org.osgi.service.component.ComponentContext;
55import org.slf4j.Logger;
56
57import com.google.common.collect.Lists;
58import com.google.common.collect.Maps;
59
60/**
61 * Provider which advertises fake/nonexistent links to the core. To be used for
62 * benchmarking only.
63 */
64@Component(immediate = true)
65public class NullLinkProvider extends AbstractProvider implements LinkProvider {
66
67 private final Logger log = getLogger(getClass());
68
69 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
70 protected DeviceService deviceService;
71
72 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ayaka Koshibe0cd42822015-01-22 16:02:31 -080073 protected MastershipService roleService;
74
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ayaka Koshibe422916f2015-01-15 15:30:23 -080076 protected LinkProviderRegistry providerRegistry;
77
78 private LinkProviderService providerService;
79
80 private static final boolean FLICKER = false;
81 private static final int DEFAULT_RATE = 3000;
82 // For now, static switch port values
83 private static final PortNumber SRCPORT = PortNumber.portNumber(5);
84 private static final PortNumber DSTPORT = PortNumber.portNumber(6);
85
86 private final InternalLinkProvider linkProvider = new InternalLinkProvider();
87
88 // Link descriptions
89 private final ConcurrentMap<ConnectPoint, LinkDescription> descriptions = Maps
90 .newConcurrentMap();
91
92 // Device ID's that have been seen so far
93 private final List<DeviceId> devices = Lists.newArrayList();
94
95 private ExecutorService linkDriver = Executors.newFixedThreadPool(1,
96 namedThreads("null-link-driver"));
97
98 // If true, 'flickers' links by alternating link up/down events at eventRate
99 @Property(name = "flicker", boolValue = FLICKER,
100 label = "Setting to flap links")
101 private boolean flicker = FLICKER;
102
103 // For flicker = true, duration between events in msec.
104 @Property(name = "eventRate", intValue = DEFAULT_RATE,
105 label = "Duration between Link Event")
Ayaka Koshibe0cd42822015-01-22 16:02:31 -0800106 private int eventRate = DEFAULT_RATE;
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800107
108 public NullLinkProvider() {
109 super(new ProviderId("null", "org.onosproject.provider.nil"));
110 }
111
112 @Activate
113 public void activate(ComponentContext context) {
114 providerService = providerRegistry.register(this);
115 deviceService.addListener(linkProvider);
116 modified(context);
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800117 log.info("started");
118 }
119
120 @Deactivate
121 public void deactivate(ComponentContext context) {
122 if (flicker) {
123 try {
124 linkDriver.awaitTermination(1000, TimeUnit.MILLISECONDS);
125 } catch (InterruptedException e) {
126 log.error("LinkBuilder did not terminate");
127 }
128 linkDriver.shutdownNow();
129 }
130 deviceService.removeListener(linkProvider);
131 providerRegistry.unregister(this);
132 deviceService = null;
133
134 log.info("stopped");
135 }
136
Ayaka Koshibe7dc1d042015-01-21 15:28:03 -0800137 @Modified
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800138 public void modified(ComponentContext context) {
139 if (context == null) {
140 log.info("No configs, using defaults: flicker={}, eventRate={}",
141 FLICKER, DEFAULT_RATE);
142 return;
143 }
144 Dictionary<?, ?> properties = context.getProperties();
145
146 boolean flickSetting;
147 int newRate;
148 try {
149 String s = (String) properties.get("flicker");
Ayaka Koshibe8851ed92015-01-22 12:07:24 -0800150 flickSetting = isNullOrEmpty(s) ? flicker : Boolean.valueOf(s.trim());
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800151 s = (String) properties.get("eventRate");
Ayaka Koshibe8851ed92015-01-22 12:07:24 -0800152 newRate = isNullOrEmpty(s) ? eventRate : Integer.valueOf(s.trim());
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800153 } catch (Exception e) {
154 log.warn(e.getMessage());
155 flickSetting = flicker;
156 newRate = eventRate;
157 }
158
159 if (flicker != flickSetting) {
160 flicker = flickSetting;
161 }
162
163 if (flicker) {
164 if (eventRate != newRate) {
165 eventRate = newRate;
166 }
167 linkDriver.submit(new LinkDriver());
168 }
169 log.info("Using new settings: flicker={}, eventRate={}", flicker,
170 eventRate);
171 }
172
173 /**
174 * Adds links as devices are found, and generates LinkEvents.
175 */
176 private class InternalLinkProvider implements DeviceListener {
177
178 @Override
179 public void event(DeviceEvent event) {
Ayaka Koshibe0cd42822015-01-22 16:02:31 -0800180 Device dev = event.subject();
181 if (!MASTER.equals(roleService.getLocalRole(dev.id()))) {
182 return;
183 }
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800184 switch (event.type()) {
185 case DEVICE_ADDED:
Ayaka Koshibe0cd42822015-01-22 16:02:31 -0800186 addLink(dev);
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800187 break;
188 case DEVICE_REMOVED:
Ayaka Koshibe0cd42822015-01-22 16:02:31 -0800189 removeLink(dev);
Ayaka Koshibe422916f2015-01-15 15:30:23 -0800190 break;
191 default:
192 break;
193 }
194 }
195
196 private void addLink(Device current) {
197 devices.add(current.id());
198 // No link if only one device
199 if (devices.size() == 1) {
200 return;
201 }
202
203 // Attach new device to the last-seen device
204 DeviceId prev = devices.get(devices.size() - 2);
205 ConnectPoint src = new ConnectPoint(prev, SRCPORT);
206 ConnectPoint dst = new ConnectPoint(current.id(), DSTPORT);
207
208 LinkDescription fdesc = new DefaultLinkDescription(src, dst,
209 Link.Type.DIRECT);
210 LinkDescription rdesc = new DefaultLinkDescription(dst, src,
211 Link.Type.DIRECT);
212 descriptions.put(src, fdesc);
213 descriptions.put(dst, rdesc);
214
215 providerService.linkDetected(fdesc);
216 providerService.linkDetected(rdesc);
217 }
218
219 private void removeLink(Device device) {
220 providerService.linksVanished(device.id());
221 devices.remove(device.id());
222 }
223 }
224
225 /**
226 * Generates link events using fake links.
227 */
228 private class LinkDriver implements Runnable {
229
230 @Override
231 public void run() {
232 while (!linkDriver.isShutdown()) {
233 for (LinkDescription desc : descriptions.values()) {
234 providerService.linkVanished(desc);
235 delay(eventRate);
236 providerService.linkDetected(desc);
237 delay(eventRate);
238 }
239 }
240 }
241 }
242}