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