blob: 17ea3b995b1bd6bacf45103de2dbc1fc1da76e1f [file] [log] [blame]
Thomas Vachuskac40d4632015-04-09 16:55:03 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Thomas Vachuskac40d4632015-04-09 16:55:03 -07003 *
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;
17
18import com.google.common.collect.Lists;
Thomas Vachuska8e038eb2016-02-23 23:28:23 -080019import com.google.common.collect.Maps;
Thomas Vachuskac40d4632015-04-09 16:55:03 -070020import org.onosproject.net.ConnectPoint;
Thomas Vachuska8e038eb2016-02-23 23:28:23 -080021import org.onosproject.net.DeviceId;
22import org.onosproject.net.Link;
23import org.onosproject.net.device.DeviceProviderService;
Thomas Vachuskac40d4632015-04-09 16:55:03 -070024import org.onosproject.net.device.DeviceService;
25import org.onosproject.net.link.DefaultLinkDescription;
26import org.onosproject.net.link.LinkDescription;
27import org.onosproject.net.link.LinkProviderService;
28import org.onosproject.net.link.LinkService;
29import org.slf4j.Logger;
30import org.slf4j.LoggerFactory;
31
32import java.util.List;
Thomas Vachuska8e038eb2016-02-23 23:28:23 -080033import java.util.Map;
Thomas Vachuskac40d4632015-04-09 16:55:03 -070034import java.util.Random;
Thomas Vachuska8e038eb2016-02-23 23:28:23 -080035import java.util.Set;
Thomas Vachuskac40d4632015-04-09 16:55:03 -070036import java.util.concurrent.ExecutorService;
37import java.util.stream.Collectors;
38
39import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
40import static org.onlab.util.Tools.delay;
41import static org.onlab.util.Tools.groupedThreads;
42import static org.onosproject.net.Link.Type.DIRECT;
43import static org.onosproject.net.MastershipRole.MASTER;
44import static org.onosproject.provider.nil.TopologySimulator.description;
45
46/**
47 * Drives topology mutations at a specified rate of events per second.
48 */
49class TopologyMutationDriver implements Runnable {
50
51 private final Logger log = LoggerFactory.getLogger(getClass());
52
53 private static final int WAIT_DELAY = 2_000;
54 private static final int MAX_DOWN_LINKS = 5;
55
56 private final Random random = new Random();
57
58 private volatile boolean stopped = true;
59
60 private double mutationRate;
61 private int millis, nanos;
62
63 private LinkService linkService;
64 private DeviceService deviceService;
65 private LinkProviderService linkProviderService;
Thomas Vachuska8e038eb2016-02-23 23:28:23 -080066 private DeviceProviderService deviceProviderService;
67 private TopologySimulator simulator;
Thomas Vachuskac40d4632015-04-09 16:55:03 -070068
69 private List<LinkDescription> activeLinks;
70 private List<LinkDescription> inactiveLinks;
71
72 private final ExecutorService executor =
Andrea Campanella90f044f2016-03-02 09:14:57 -080073 newSingleThreadScheduledExecutor(groupedThreads("onos/null", "topo-mutator", log));
Thomas Vachuskac40d4632015-04-09 16:55:03 -070074
Thomas Vachuska8e038eb2016-02-23 23:28:23 -080075 private Map<DeviceId, Set<Link>> savedLinks = Maps.newConcurrentMap();
76
Thomas Vachuskac40d4632015-04-09 16:55:03 -070077 /**
78 * Starts the mutation process.
79 *
Thomas Vachuska8e038eb2016-02-23 23:28:23 -080080 * @param mutationRate link events per second
81 * @param linkService link service
82 * @param deviceService device service
83 * @param linkProviderService link provider service
84 * @param deviceProviderService device provider service
85 * @param simulator topology simulator
Thomas Vachuskac40d4632015-04-09 16:55:03 -070086 */
87 void start(double mutationRate,
88 LinkService linkService, DeviceService deviceService,
Thomas Vachuska8e038eb2016-02-23 23:28:23 -080089 LinkProviderService linkProviderService,
90 DeviceProviderService deviceProviderService,
91 TopologySimulator simulator) {
92 savedLinks.clear();
Thomas Vachuskac40d4632015-04-09 16:55:03 -070093 stopped = false;
94 this.linkService = linkService;
95 this.deviceService = deviceService;
96 this.linkProviderService = linkProviderService;
Thomas Vachuska8e038eb2016-02-23 23:28:23 -080097 this.deviceProviderService = deviceProviderService;
98 this.simulator = simulator;
Thomas Vachuskac40d4632015-04-09 16:55:03 -070099 activeLinks = reduceLinks();
100 inactiveLinks = Lists.newArrayList();
101 adjustRate(mutationRate);
Andrea Campanella90f044f2016-03-02 09:14:57 -0800102 executor.execute(this);
Thomas Vachuskac40d4632015-04-09 16:55:03 -0700103 }
104
105 /**
106 * Adjusts the topology mutation rate.
107 *
108 * @param mutationRate new topology mutation rate
109 */
110 void adjustRate(double mutationRate) {
111 this.mutationRate = mutationRate;
112 if (mutationRate > 0) {
113 this.millis = (int) (1_000 / mutationRate / 2);
114 this.nanos = (int) (1_000_000 / mutationRate / 2) % 1_000_000;
115 } else {
116 this.millis = 0;
117 this.nanos = 0;
118 }
119 log.info("Settings: millis={}, nanos={}", millis, nanos);
120 }
121
122 /**
123 * Stops the mutation process.
124 */
125 void stop() {
126 stopped = true;
127 }
128
129 /**
130 * Severs the link between the specified end-points in both directions.
131 *
132 * @param one link endpoint
133 * @param two link endpoint
134 */
135 void severLink(ConnectPoint one, ConnectPoint two) {
136 LinkDescription link = new DefaultLinkDescription(one, two, DIRECT);
137 linkProviderService.linkVanished(link);
138 linkProviderService.linkVanished(reverse(link));
139
140 }
141
142 /**
143 * Repairs the link between the specified end-points in both directions.
144 *
145 * @param one link endpoint
146 * @param two link endpoint
147 */
148 void repairLink(ConnectPoint one, ConnectPoint two) {
149 LinkDescription link = new DefaultLinkDescription(one, two, DIRECT);
150 linkProviderService.linkDetected(link);
151 linkProviderService.linkDetected(reverse(link));
152 }
153
Thomas Vachuska8e038eb2016-02-23 23:28:23 -0800154 /**
155 * Fails the specified device.
156 *
157 * @param deviceId device identifier
158 */
159 void failDevice(DeviceId deviceId) {
160 savedLinks.put(deviceId, linkService.getDeviceLinks(deviceId));
161 deviceProviderService.deviceDisconnected(deviceId);
162 }
163
164 /**
165 * Repairs the specified device.
166 *
167 * @param deviceId device identifier
168 */
169 void repairDevice(DeviceId deviceId) {
170 int chassisId = Integer.parseInt(deviceId.uri().getSchemeSpecificPart());
171 simulator.createDevice(deviceId, chassisId);
172 Set<Link> links = savedLinks.remove(deviceId);
173 if (links != null) {
174 links.forEach(l -> linkProviderService
175 .linkDetected(new DefaultLinkDescription(l.src(), l.dst(), DIRECT)));
176 }
177 }
178
179 /**
180 * Returns whether the given device is considered reachable or not.
181 *
182 * @param deviceId device identifier
183 * @return true if device is reachable
184 */
185 boolean isReachable(DeviceId deviceId) {
186 return !savedLinks.containsKey(deviceId);
187 }
188
Thomas Vachuskac40d4632015-04-09 16:55:03 -0700189 @Override
190 public void run() {
191 delay(WAIT_DELAY);
192
193 while (!stopped) {
194 if (mutationRate > 0 && inactiveLinks.isEmpty()) {
195 primeInactiveLinks();
196 } else if (mutationRate <= 0 && !inactiveLinks.isEmpty()) {
197 repairInactiveLinks();
198 } else if (inactiveLinks.isEmpty()) {
199 delay(WAIT_DELAY);
200
201 } else {
202 activeLinks.add(repairLink());
203 pause();
204 inactiveLinks.add(severLink());
205 pause();
206 }
207 }
208 }
209
210 // Primes the inactive links with a few random links.
211 private void primeInactiveLinks() {
212 for (int i = 0, n = Math.min(MAX_DOWN_LINKS, activeLinks.size()); i < n; i++) {
213 inactiveLinks.add(severLink());
214 }
215 }
216
217 // Repairs all inactive links.
218 private void repairInactiveLinks() {
219 while (!inactiveLinks.isEmpty()) {
220 repairLink();
221 }
222 }
223
224 // Picks a random active link and severs it.
225 private LinkDescription severLink() {
226 LinkDescription link = getRandomLink(activeLinks);
227 linkProviderService.linkVanished(link);
228 linkProviderService.linkVanished(reverse(link));
229 return link;
230 }
231
232 // Picks a random inactive link and repairs it.
233 private LinkDescription repairLink() {
234 LinkDescription link = getRandomLink(inactiveLinks);
235 linkProviderService.linkDetected(link);
236 linkProviderService.linkDetected(reverse(link));
237 return link;
238 }
239
240 // Produces a reverse of the specified link.
241 private LinkDescription reverse(LinkDescription link) {
242 return new DefaultLinkDescription(link.dst(), link.src(), link.type());
243 }
244
245 // Returns a random link from the specified list of links.
246 private LinkDescription getRandomLink(List<LinkDescription> links) {
247 return links.remove(random.nextInt(links.size()));
248 }
249
250 // Reduces the given list of links to just a single link in each original pair.
251 private List<LinkDescription> reduceLinks() {
252 List<LinkDescription> links = Lists.newArrayList();
253 linkService.getLinks().forEach(link -> links.add(description(link)));
254 return links.stream()
255 .filter(this::isOurLink)
256 .filter(this::isRightDirection)
257 .collect(Collectors.toList());
258 }
259
260 // Returns true if the specified link is ours.
261 private boolean isOurLink(LinkDescription linkDescription) {
262 return deviceService.getRole(linkDescription.src().deviceId()) == MASTER;
263 }
264
265 // Returns true if the link source is greater than the link destination.
266 private boolean isRightDirection(LinkDescription link) {
267 return link.src().deviceId().toString().compareTo(link.dst().deviceId().toString()) > 0;
268 }
269
270 // Pauses the current thread for the pre-computed time of millis & nanos.
271 private void pause() {
272 delay(millis, nanos);
273 }
274
275}