blob: 5d928a048af5e5b3e800b7a98bc704abfda6039f [file] [log] [blame]
Andrea Campanella732ea832017-02-06 09:25:59 -08001/*
2 * Copyright 2017-present 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 */
16
17package org.onosproject.ui.impl;
18
19import com.google.common.collect.ImmutableList;
20import com.google.common.collect.Sets;
21import org.onosproject.net.DeviceId;
22import org.onosproject.net.ElementId;
23import org.onosproject.net.HostId;
24import org.onosproject.net.Link;
25import org.onosproject.net.MarkerResource;
26import org.onosproject.net.NetworkResource;
27import org.onosproject.net.behaviour.protection.TransportEndpointDescription;
28import org.onosproject.net.intent.FlowRuleIntent;
29import org.onosproject.net.intent.Intent;
30import org.onosproject.net.intent.OpticalConnectivityIntent;
31import org.onosproject.net.intent.ProtectionEndpointIntent;
32import org.onosproject.ui.impl.topo.util.ServicesBundle;
33import org.onosproject.ui.impl.topo.util.TrafficLink;
34import org.onosproject.ui.impl.topo.util.TrafficLink.StatsType;
35import org.onosproject.ui.impl.topo.util.TrafficLinkMap;
36import org.onosproject.ui.topo.AbstractTopoMonitor;
37import org.onosproject.ui.topo.DeviceHighlight;
38import org.onosproject.ui.topo.Highlights;
39import org.onosproject.ui.topo.HostHighlight;
40import org.onosproject.ui.topo.LinkHighlight.Flavor;
41import org.onosproject.ui.topo.NodeHighlight;
42import org.slf4j.Logger;
43import org.slf4j.LoggerFactory;
44
45import java.util.Collection;
46import java.util.HashSet;
47import java.util.List;
48import java.util.Set;
49import java.util.Timer;
50import java.util.TimerTask;
51
52import static org.onosproject.ui.impl.ProtectedIntentMonitor.ProtectedMode.IDLE;
53import static org.onosproject.ui.impl.ProtectedIntentMonitor.ProtectedMode.SELECTED_INTENT;
54
55/**
56 * Encapsulates the behavior of monitoring protected intents.
57 */
58//TODO refactor duplicated methods from here and the TrafficMonitor to AbstractTopoMonitor
59public class ProtectedIntentMonitor extends AbstractTopoMonitor {
60
61 private static final Logger log =
62 LoggerFactory.getLogger(ProtectedIntentMonitor.class);
63 public static final String PRIMARY_PATH_TAG = "protection1";
64
65 /**
66 * Designates the different modes of operation.
67 */
68 public enum ProtectedMode {
69 IDLE,
70 SELECTED_INTENT
71 }
72
73 private final long trafficPeriod;
74 private final ServicesBundle servicesBundle;
75 private final TopologyViewMessageHandler msgHandler;
76
77 private final Timer timer = new Timer("topo-protected-intents");
78
79 private TimerTask trafficTask = null;
80 private ProtectedMode mode = ProtectedMode.IDLE;
81 private Intent selectedIntent = null;
82
83
84 /**
85 * Constructs a protected intent monitor.
86 *
87 * @param trafficPeriod traffic task period in ms
88 * @param servicesBundle bundle of services
89 * @param msgHandler our message handler
90 */
91 public ProtectedIntentMonitor(long trafficPeriod, ServicesBundle servicesBundle,
92 TopologyViewMessageHandler msgHandler) {
93 this.trafficPeriod = trafficPeriod;
94 this.servicesBundle = servicesBundle;
95 this.msgHandler = msgHandler;
96
97 }
98
99 // =======================================================================
100 // === API ===
101
102 // TODO: move this out to the "h2h/multi-intent app"
103
104 /**
105 * Monitor for protected intent data to be sent back to the web client,
106 * for the given intent.
107 *
108 * @param intent the intent to monitor
109 */
110 public synchronized void monitor(Intent intent) {
111 log.debug("monitor intent: {}", intent.id());
112 selectedIntent = intent;
113 mode = SELECTED_INTENT;
114 scheduleTask();
115 sendSelectedIntents();
116 }
117
118 /**
119 * Stop all traffic monitoring.
120 */
121 public synchronized void stopMonitoring() {
122 log.debug("STOP monitoring");
123 if (mode != IDLE) {
124 sendClearAll();
125 }
126 }
127
128
129 // =======================================================================
130 // === Helper methods ===
131 private void sendClearAll() {
132 clearAll();
133 sendClearHighlights();
134 }
135
136 private void clearAll() {
137 this.mode = IDLE;
138 clearSelection();
139 cancelTask();
140 }
141
142 private void clearSelection() {
143 selectedIntent = null;
144 }
145
146 //TODO duplicate and can be brought in abstract upper class.
147 private synchronized void scheduleTask() {
148 if (trafficTask == null) {
149 log.debug("Starting up background protected intent task...");
150 trafficTask = new TrafficUpdateTask();
151 timer.schedule(trafficTask, trafficPeriod, trafficPeriod);
152 } else {
153 log.debug("(protected intent task already running)");
154 }
155 }
156
157 private synchronized void cancelTask() {
158 if (trafficTask != null) {
159 trafficTask.cancel();
160 trafficTask = null;
161 }
162 }
163
164 private void sendSelectedIntents() {
165 log.debug("sendSelectedIntents: {}", selectedIntent);
166 msgHandler.sendHighlights(protectedIntentHighlights());
167 }
168
169 private void sendClearHighlights() {
170 log.debug("sendClearHighlights");
171 msgHandler.sendHighlights(new Highlights());
172 }
173
174 // =======================================================================
175 // === Generate messages in JSON object node format
176 private Highlights protectedIntentHighlights() {
177 Highlights highlights = new Highlights();
178 TrafficLinkMap linkMap = new TrafficLinkMap();
179 if (selectedIntent != null) {
180 List<Intent> installables = servicesBundle.intentService()
181 .getInstallableIntents(selectedIntent.key());
182 Set<Link> primary = new HashSet<>();
183 Set<Link> backup = new HashSet<>();
184 if (installables != null) {
185 //There should be exactly two FlowRuleIntent and four
186 //ProtectionEndpointIntent for each ProtectedTransportIntent.
187 for (Intent installable : installables) {
188 if (installable instanceof FlowRuleIntent) {
189 handleFlowRuleIntent(primary, backup, (FlowRuleIntent) installable);
190 } else if (installable instanceof ProtectionEndpointIntent) {
191 handleProtectionEndpointIntent(primary, backup,
192 (ProtectionEndpointIntent) installable);
193 } else {
194 log.warn("Intent {} is not an expected installable type {} " +
195 "related to ProtectedTransportIntent",
196 installable.id(), installable.getClass().getSimpleName());
197 stopMonitoring();
198 }
199 }
200 boolean isOptical = selectedIntent instanceof OpticalConnectivityIntent;
201 //last parameter (traffic) signals if the link is highlited with ants or solid line
202 //Flavor is swapped so green is primary path.
203 if (usingBackup(primary)) {
204 //the backup becomes in use so we have a dotted line
205 processLinks(linkMap, backup, Flavor.PRIMARY_HIGHLIGHT, isOptical, true);
206 } else {
207 processLinks(linkMap, primary, Flavor.SECONDARY_HIGHLIGHT, isOptical, true);
208 processLinks(linkMap, backup, Flavor.PRIMARY_HIGHLIGHT, isOptical, false);
209 }
210 updateHighlights(highlights, primary);
211 updateHighlights(highlights, backup);
212 colorLinks(highlights, linkMap);
213 highlights.subdueAllElse(Highlights.Amount.MINIMALLY);
214 } else {
215 log.debug("Selected Intent has no installables intents");
216 }
217 } else {
218 log.debug("Selected Intent is null");
219 }
220 return highlights;
221 }
222
223 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
224
225 private void handleProtectionEndpointIntent(Set<Link> primary, Set<Link> backup,
226 ProtectionEndpointIntent peIntent) {
227 TransportEndpointDescription primaryDesc = peIntent
228 .description().paths().get(0);
229 TransportEndpointDescription secondaryDesc = peIntent
230 .description().paths().get(1);
231 primary.addAll(servicesBundle.linkService()
232 .getLinks(primaryDesc.output()
233 .connectPoint()));
234 backup.addAll(servicesBundle.linkService()
235 .getLinks(secondaryDesc.output()
236 .connectPoint()));
237 }
238
239 private void handleFlowRuleIntent(Set<Link> primary, Set<Link> backup,
240 FlowRuleIntent frIntent) {
241 boolean protection1 = frIntent.resources().stream()
242 .filter(r -> r instanceof MarkerResource)
243 .map(NetworkResource::toString)
244 .anyMatch(rstring -> rstring.equals(PRIMARY_PATH_TAG));
245 if (protection1) {
246 primary.addAll(linkResources(frIntent));
247 } else {
248 backup.addAll(linkResources(frIntent));
249 }
250 }
251
252 // returns true if the backup path is the one where the traffic is currently flowing
253 private boolean usingBackup(Set<Link> primary) {
254 Set<Link> activeLinks = Sets.newHashSet(servicesBundle.linkService().getActiveLinks());
255 return primary.isEmpty() || !activeLinks.containsAll(primary);
256 }
257
258 private void updateHighlights(Highlights highlights, Iterable<Link> links) {
259 for (Link link : links) {
260 ensureNodePresent(highlights, link.src().elementId());
261 ensureNodePresent(highlights, link.dst().elementId());
262 }
263 }
264
265 //TODO duplicate and can be brought in abstract upper class.
266 private void ensureNodePresent(Highlights highlights, ElementId eid) {
267 String id = eid.toString();
268 NodeHighlight nh = highlights.getNode(id);
269 if (nh == null) {
270 if (eid instanceof DeviceId) {
271 nh = new DeviceHighlight(id);
272 highlights.add((DeviceHighlight) nh);
273 } else if (eid instanceof HostId) {
274 nh = new HostHighlight(id);
275 highlights.add((HostHighlight) nh);
276 }
277 }
278 }
279
280 private void processLinks(TrafficLinkMap linkMap, Iterable<Link> links,
281 Flavor flavor, boolean isOptical,
282 boolean showTraffic) {
283 if (links != null) {
284 for (Link link : links) {
285 TrafficLink tlink = linkMap.add(link);
286 tlink.tagFlavor(flavor);
287 tlink.optical(isOptical);
288 if (showTraffic) {
289 tlink.antMarch(true);
290 }
291 }
292 }
293 }
294
295 //TODO duplicate and can be brought in abstract upper class.
296 private void colorLinks(Highlights highlights, TrafficLinkMap linkMap) {
297 for (TrafficLink tlink : linkMap.biLinks()) {
298 highlights.add(tlink.highlight(StatsType.TAGGED));
299 }
300 }
301
302 //TODO duplicate and can be brought in abstract upper class.
303 // Extracts links from the specified flow rule intent resources
304 private Collection<Link> linkResources(Intent installable) {
305 ImmutableList.Builder<Link> builder = ImmutableList.builder();
306 installable.resources().stream().filter(r -> r instanceof Link)
307 .forEach(r -> builder.add((Link) r));
308 return builder.build();
309 }
310
311 // =======================================================================
312 // === Background Task
313
314 // Provides periodic update of traffic information to the client
315 private class TrafficUpdateTask extends TimerTask {
316 @Override
317 public void run() {
318 try {
319 switch (mode) {
320 case SELECTED_INTENT:
321 sendSelectedIntents();
322 break;
323
324 default:
325 // RELATED_INTENTS and IDLE modes should never invoke
326 // the background task, but if they do, they have
327 // nothing to do
328 break;
329 }
330
331 } catch (Exception e) {
332 log.warn("Unable to process protected intent task due to {}", e.getMessage());
333 log.warn("Boom!", e);
334 }
335 }
336 }
337}