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