blob: 187ef190e00231c63418d84e61aa669096dad983 [file] [log] [blame]
Davide Sanvito05983ba2017-12-01 11:46:44 +01001/*
2 * Copyright 2017-present Open Networking Foundation
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.imr;
18
19import com.google.common.collect.ImmutableSet;
20import org.apache.commons.lang3.tuple.Pair;
Davide Sanvito05983ba2017-12-01 11:46:44 +010021import org.onlab.util.KryoNamespace;
22import org.onosproject.core.ApplicationId;
23import org.onosproject.imr.data.Path;
24import org.onosproject.imr.data.Route;
25import org.onosproject.net.ConnectPoint;
26import org.onosproject.net.DeviceId;
27import org.onosproject.net.ElementId;
28import org.onosproject.net.FilteredConnectPoint;
29import org.onosproject.net.Host;
30import org.onosproject.net.HostId;
31import org.onosproject.net.Link;
32import org.onosproject.net.PortNumber;
33import org.onosproject.net.flow.FlowEntry;
34import org.onosproject.net.flow.FlowRule;
35import org.onosproject.net.flow.FlowRuleEvent;
36import org.onosproject.net.flow.FlowRuleListener;
37import org.onosproject.net.flow.FlowRuleService;
38import org.onosproject.net.flow.instructions.Instruction;
39import org.onosproject.net.flow.instructions.Instructions;
40import org.onosproject.net.host.HostService;
41import org.onosproject.net.intent.ConnectivityIntent;
42import org.onosproject.net.intent.FlowRuleIntent;
43import org.onosproject.net.intent.Intent;
44import org.onosproject.net.intent.IntentEvent;
45import org.onosproject.net.intent.IntentListener;
46import org.onosproject.net.intent.IntentService;
47import org.onosproject.net.intent.IntentState;
48import org.onosproject.net.intent.Key;
49import org.onosproject.net.intent.LinkCollectionIntent;
50import org.onosproject.net.intent.PointToPointIntent;
51import org.onosproject.net.link.LinkService;
52import org.onosproject.net.statistic.FlowStatisticStore;
53import org.onosproject.store.serializers.KryoNamespaces;
54import org.onosproject.store.service.ConsistentMap;
55import org.onosproject.store.service.DistributedSet;
56import org.onosproject.store.service.Serializer;
57import org.onosproject.store.service.StorageService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070058import org.osgi.service.component.annotations.Activate;
59import org.osgi.service.component.annotations.Component;
60import org.osgi.service.component.annotations.Deactivate;
61import org.osgi.service.component.annotations.Reference;
62import org.osgi.service.component.annotations.ReferenceCardinality;
Davide Sanvito05983ba2017-12-01 11:46:44 +010063import org.slf4j.Logger;
64import org.slf4j.LoggerFactory;
65
66import java.util.ArrayList;
Yuta HIGUCHI71f8e7b2018-04-12 10:30:27 -070067import java.util.Comparator;
Davide Sanvito05983ba2017-12-01 11:46:44 +010068import java.util.HashMap;
69import java.util.HashSet;
70import java.util.LinkedList;
71import java.util.List;
72import java.util.Map;
73import java.util.Set;
74import java.util.concurrent.ConcurrentHashMap;
75import java.util.stream.Collectors;
76import java.util.stream.IntStream;
77
78import static com.google.common.base.Preconditions.checkArgument;
79import static com.google.common.base.Preconditions.checkNotNull;
80
81/**
82 * Manager of Intent Monitor and Reroute.
83 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070084@Component(immediate = true, service = IntentMonitorAndRerouteService.class)
Davide Sanvito05983ba2017-12-01 11:46:44 +010085public class IntentMonitorAndRerouteManager implements IntentMonitorAndRerouteService {
86
87 private final Logger log = LoggerFactory.getLogger(getClass());
88
89 private ConsistentMap<ApplicationId, Map<Key, ConnectivityIntent>> monitoredIntentsDistr;
90 private Map<ApplicationId, Map<Key, ConnectivityIntent>> monitoredIntents;
91
92 private DistributedSet<Key> toBeMonitoredIntents;
93
Ray Milkeyd84f89b2018-08-17 14:54:17 -070094 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Davide Sanvito05983ba2017-12-01 11:46:44 +010095 protected IntentService intentService;
96
Ray Milkeyd84f89b2018-08-17 14:54:17 -070097 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Davide Sanvito05983ba2017-12-01 11:46:44 +010098 protected FlowRuleService flowRuleService;
99
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700100 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Davide Sanvito05983ba2017-12-01 11:46:44 +0100101 protected LinkService linkService;
102
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700103 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Davide Sanvito05983ba2017-12-01 11:46:44 +0100104 protected HostService hostService;
105
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700106 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Davide Sanvito05983ba2017-12-01 11:46:44 +0100107 protected FlowStatisticStore statsStore;
108
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700109 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Davide Sanvito05983ba2017-12-01 11:46:44 +0100110 protected StorageService storageService;
111
112 private InternalIntentListener intentListener = new InternalIntentListener();
113
114 private InternalFlowRuleListener flowRuleListener = new InternalFlowRuleListener();
115
116 @Activate
117 protected void activate() {
118 intentService.addListener(intentListener);
119 flowRuleService.addListener(flowRuleListener);
120
121 monitoredIntentsDistr = storageService
122 .<ApplicationId, Map<Key, ConnectivityIntent>>consistentMapBuilder()
123 .withSerializer(Serializer.using(KryoNamespaces.API))
124 .withName("IMR-monitoredIntents")
125 .build();
126 monitoredIntents = monitoredIntentsDistr.asJavaMap();
127
128 toBeMonitoredIntents = storageService.<Key>setBuilder()
129 .withSerializer(Serializer.using(
130 new KryoNamespace.Builder()
131 .register(KryoNamespaces.API)
132 .register(Key.class)
133 .build()))
134 .withName("IMR-toMonitorIntents")
135 .build()
136 .asDistributedSet();
137 log.info("IntentMonitorAndReroute activated");
138 }
139
140 @Deactivate
141 protected void deactivate() {
142 intentService.removeListener(intentListener);
143 flowRuleService.removeListener(flowRuleListener);
144 monitoredIntents
145 .forEach(((applicationId, keyConnectivityIntentMap) ->
146 keyConnectivityIntentMap.keySet()
147 .forEach(this::removeIntent)));
148 log.info("IntentMonitorAndReroute deactivated");
149 }
150
151
152 private synchronized void storeMonitoredIntent(ConnectivityIntent intent) {
153 log.debug("Store Monitored Intent {}", intent.key());
154 Map<Key, ConnectivityIntent> temp = monitoredIntents.getOrDefault(intent.appId(), new ConcurrentHashMap<>());
155 temp.put(intent.key(), intent);
156 monitoredIntents.put(intent.appId(), temp);
157 }
158
159 @Override
160 public synchronized boolean startMonitorIntent(Key intentKey) {
161 checkNotNull(intentKey, "Intent Key must not be null");
162 log.debug("Start Monitor Intent: {}", intentKey.toString());
163 toBeMonitoredIntents.add(intentKey);
164
165 //Check if the requested intent is already present in the intent manager
166 Intent installedIntent = intentService.getIntent(intentKey);
167 if (!allowedIntent(installedIntent)) {
168 return false;
169 }
170 //Check if the intent that is present in the intent subsystem is already installed
171 if (intentService.getIntentState(intentKey) == IntentState.INSTALLED) {
172 storeMonitoredIntent((ConnectivityIntent) installedIntent);
173 }
174 return true;
175 }
176
177
178 /**
179 * Returns whether the intent can be monitored or not.
180 * @param intent The intent you want to check if it is allowed to be monitored.
181 * @return true if the intent's type is of one of the allowed types
182 * ({@link LinkCollectionIntent}, {@link PointToPointIntent}).
183 */
184 public boolean allowedIntent(Intent intent) {
185 return intent instanceof LinkCollectionIntent || intent instanceof PointToPointIntent;
186 }
187
188 @Override
189 public synchronized boolean stopMonitorIntent(Key intentKey) {
190 checkNotNull(intentKey, "Intent key must not be null");
191 log.debug("Stop Monitor Intent: ", intentKey.toString());
192 if (!toBeMonitoredIntents.contains(intentKey)) {
193 return false;
194 }
195 removeIntent(intentKey);
196 toBeMonitoredIntents.remove(intentKey);
197 return true;
198 }
199
200 /**
201 * Removes the intent from the internal structure.
202 * @param intentKey Key of the intent to be removed.
203 * @return true if the intent is found and removed, false otherwise.
204 */
205 private synchronized boolean removeIntent(Key intentKey) {
206 for (Map.Entry<ApplicationId, Map<Key, ConnectivityIntent>> appIntents
207 : monitoredIntents.entrySet()) {
208 if (appIntents.getValue().containsKey(intentKey)) {
209 appIntents.getValue().remove(intentKey);
210 //TODO: check if it works without reputting the map
211 flushIntentStatStore(intentKey);
212 monitoredIntents.put(appIntents.getKey(), appIntents.getValue());
213 if (appIntents.getValue().isEmpty()) {
214 monitoredIntents.remove(appIntents.getKey());
215 }
216 return true;
217 }
218 }
219 return false;
220 }
221
222 /**
223 * Flushes the statistics (from the statistics store) of an intent.
224 * @param intentKey Key of the intent which statistics has to be cleaned.
225 */
226 private synchronized void flushIntentStatStore(Key intentKey) {
227 checkNotNull(intentKey);
228 //Remove all the flow rule on the stats store related to the passed intentKey
229 intentService.getInstallableIntents(intentKey)
230 .stream()
231 .map(intent -> (FlowRuleIntent) intent)
232 .forEach(intent -> intent.flowRules()
233 .forEach(flowRule -> statsStore.removeFlowStatistic(flowRule))
234 );
235 }
236
237
238 /**
239 * Generates a new {@Link LinkCollectionIntent} applying the new path.
240 * @param links List of links of the new path.
241 * @param intentKey Key of the intent you want to re-route.
242 * @param appId Application id that submits initially the intent.
243 * @return The new intent, if not possibile it will return the old intent already installed.
244 */
245 private ConnectivityIntent generateLinkCollectionIntent(
246 List<Link> links,
247 Key intentKey,
248 ApplicationId appId) {
249 checkNotNull(links);
250 checkNotNull(appId);
251
252 // Gets the oldIntent already installed
253 ConnectivityIntent oldIntent = monitoredIntents.get(appId).get(intentKey);
254
255 //Flush the statistics of the currently installed intent
256 flushIntentStatStore(intentKey);
257
258 //get the connect point of the old intent
259 // Left element of the Pair is the ingress, right one is the egress
260 Pair<Set<FilteredConnectPoint>, Set<FilteredConnectPoint>> cpPair = extractEndConnectPoints(oldIntent);
261 if (cpPair == null) {
262 return oldIntent;
263 }
264
265 // Now generate the new intent
266 LinkCollectionIntent newIntent = LinkCollectionIntent.builder()
267 .appId(oldIntent.appId())
268 .key(intentKey)
269 .selector(oldIntent.selector())
270 .filteredIngressPoints(ImmutableSet.copyOf(cpPair.getLeft()))
271 .filteredEgressPoints(ImmutableSet.copyOf(cpPair.getRight()))
272 .treatment(oldIntent.treatment())
273 .priority(oldIntent.priority())
274 .constraints(oldIntent.constraints())
275 .links(ImmutableSet.copyOf(links))
276 //TODO: is there a way to get from the old intent?
277 .applyTreatmentOnEgress(true)
278 .build();
279
280 return newIntent;
281 }
282
283 @Override
284 public boolean applyPath(Route route) {
285 checkNotNull(route, "Route to apply must be not null");
286 checkNotNull(route.appId(), "Application id must be not null");
287 checkNotNull(route.key(), "Intent key to apply must be not null");
288 checkNotNull(route.paths(), "New path must be not null");
289 checkArgument(route.paths().size() >= 1);
290
291 ApplicationId appId = route.appId();
292 Key key = route.key();
293
294 // check if the app and the intent key are monitored
295 if (!monitoredIntents.containsKey(appId)) {
296 return false;
297 }
298 if (!monitoredIntents.get(appId).containsKey(key)) {
299 return false;
300 }
301
302 // TODO: now we manage only the unsplittable routing
303 Path currentPath = route.paths()
304 .stream()
Yuta HIGUCHI71f8e7b2018-04-12 10:30:27 -0700305 .max(Comparator.comparing(Path::weight))
Davide Sanvito05983ba2017-12-01 11:46:44 +0100306 .get();
307
308 // Check if the last and first element of the path are HostId
309 // in this case remove them from the list
310 if (currentPath.path().get(0) instanceof HostId) {
311 currentPath.path().remove(0);
312 }
313 if (currentPath.path().get(currentPath.path().size() - 1) instanceof HostId) {
314 currentPath.path().remove(currentPath.path().size() - 1);
315 }
316
317 List<Link> links = createPathFromDeviceList(currentPath.path());
318
319 // Generate the new Link collection intent, if not possible it will return the old intent
320 ConnectivityIntent intent = generateLinkCollectionIntent(links, key, appId);
321 storeMonitoredIntent(intent);
322 intentService.submit(intent);
323 return true;
324 }
325
326 @Override
327 public Map<ApplicationId, Map<Key, List<FlowEntry>>> getStats() {
328 //TODO: check if there is a better way to get the statistics
329 Map<ApplicationId, Map<Key, List<FlowEntry>>> currentStatistics = new HashMap<>();
330 monitoredIntents.forEach((appId, mapIntentKey) ->
331 currentStatistics.putAll(getStats(appId))
332 );
333 return currentStatistics;
334 }
335
336 @Override
337 public Map<ApplicationId, Map<Key, List<FlowEntry>>> getStats(ApplicationId appId) {
338 checkNotNull(appId);
339
340 //TODO: is there a better way to get statistics?
341 Map<ApplicationId, Map<Key, List<FlowEntry>>> currentStatistics = new HashMap<>();
342 currentStatistics.put(appId, new HashMap<>());
343 if (monitoredIntents.containsKey(appId)) {
344 Set<Key> keySet = monitoredIntents.get(appId).keySet();
345 for (Key intentKey : keySet) {
346
347 List<FlowEntry> flowEntries = getStats(intentKey);
348 currentStatistics.get(appId).put(intentKey, flowEntries);
349 }
350 }
351 return currentStatistics;
352 }
353
354 @Override
355 public Map<ApplicationId, Map<Key, List<FlowEntry>>> getStats(ApplicationId appId, Key intentKey) {
356 checkNotNull(appId);
357 checkNotNull(intentKey);
358 checkArgument(monitoredIntents.containsKey(appId));
359 checkArgument(monitoredIntents.get(appId).containsKey(intentKey));
360
361 Map<ApplicationId, Map<Key, List<FlowEntry>>> currentStatistics = new HashMap<>();
362 currentStatistics.put(appId, new HashMap<>());
363 List<FlowEntry> flowEntries = getStats(intentKey);
364 currentStatistics.get(appId).put(intentKey, flowEntries);
365 return currentStatistics;
366 }
367
368 /**
369 * Returns the list of flow entries of a particular intent.
370 * @param intentKey
371 * @return List of the flow entries of the specified intent,
372 * it contains all the statistics of that intent.
373 */
374 private List<FlowEntry> getStats(Key intentKey) {
375 List<FlowEntry> currentStatistics = new LinkedList<>();
376 intentService.getInstallableIntents(intentKey)
377 .forEach(intent -> ((FlowRuleIntent) intent).flowRules()
378 .forEach(flowRule -> {
379 ConnectPoint cp = buildConnectPoint(flowRule);
380 currentStatistics.addAll(getStats(cp, flowRule));
381 })
382 );
383 return currentStatistics;
384 }
385
386 /**
387 * Returns a list of flow entry related to the connect point and flow rule passed.
388 * @param cp ConnectPoint we want to retrieve the flow entry from.
389 * @param flowRule FlowRule.
390 * @return List of flow entries.
391 */
392 private List<FlowEntry> getStats(ConnectPoint cp, FlowRule flowRule) {
393 return statsStore.getCurrentFlowStatistic(cp)
394 .stream()
395 .filter(flowEntry -> flowEntry
396 .id()
397 .equals(flowRule.id()))
398 .collect(Collectors.toList());
399 }
400
401 /**
402 * Returns a list of links starting from a list of devices.
403 * @param deviceList List of devices.
404 * @return A path in terms of list of links.
405 */
406 private List<Link> createPathFromDeviceList(List<ElementId> deviceList) {
407 List<Link> path = new ArrayList<>();
408 if (deviceList.size() == 1) {
409 return path;
410 }
411
412 // Left element represents the input and right the output
413 List<Pair<DeviceId, DeviceId>> devicePairs = IntStream.
414 range(0, deviceList.size() - 1)
415 .mapToObj(i -> Pair.of((DeviceId) deviceList.get(i), (DeviceId) deviceList.get(i + 1)))
416 .collect(Collectors.toList());
417
418 devicePairs.forEach(pair -> {
419 //TODO use GetPath pair by pair?
420 // The common Link between DevEgress and DevIngress is the intersection of their links
421 Set<Link> commonLinks = new HashSet<>(linkService.getDeviceEgressLinks(pair.getLeft()));
422 commonLinks.retainAll(linkService.getDeviceIngressLinks(pair.getRight()));
423 if (commonLinks.size() == 0) {
424 log.error("No link found between node {} and node {}!",
425 pair.getLeft(), pair.getRight());
426 } else if (commonLinks.size() == 1) {
427 path.add(commonLinks.iterator().next());
428 } else {
429 //TODO select the one with more bandwidth?
430 log.warn("{} links found between node {} and node {}: taking the first one!",
431 commonLinks.size(), pair.getLeft(), pair.getRight());
432 path.add(commonLinks.iterator().next());
433 }
434 });
435
436 return path;
437 }
438
Yuta HIGUCHI71f8e7b2018-04-12 10:30:27 -0700439 @Override
Davide Sanvito05983ba2017-12-01 11:46:44 +0100440 public Map<ApplicationId, Map<Key, Pair<Set<ElementId>, Set<ElementId>>>> getMonitoredIntents() {
441 Map<ApplicationId, Map<Key, Pair<Set<ElementId>, Set<ElementId>>>> currentMonitoredIntents
442 = new ConcurrentHashMap<>();
443 monitoredIntents.forEach((appId, appIntents) -> {
444 currentMonitoredIntents.put(appId, new ConcurrentHashMap<>());
445 appIntents.forEach((intentKey, intent) -> {
446 Pair<Set<ElementId>, Set<ElementId>> endPair = extractEndPoints(intent);
447 if (endPair != null) {
448 currentMonitoredIntents.get(appId).put(intentKey, endPair);
449 }
450 });
451 });
452 return currentMonitoredIntents;
453 }
454
Yuta HIGUCHI71f8e7b2018-04-12 10:30:27 -0700455 @Override
Davide Sanvito05983ba2017-12-01 11:46:44 +0100456 public Map<ApplicationId, Map<Key, Pair<Set<ElementId>, Set<ElementId>>>> getMonitoredIntents(
457 ApplicationId appId) {
458 Map<ApplicationId, Map<Key, Pair<Set<ElementId>, Set<ElementId>>>> currentMonitoredIntents
459 = new ConcurrentHashMap<>();
460 currentMonitoredIntents.put(appId, new ConcurrentHashMap<>());
461 if (monitoredIntents.containsKey(appId)) {
462 monitoredIntents.get(appId).forEach((intentKey, intent) -> {
463 Pair<Set<ElementId>, Set<ElementId>> endPair = extractEndPoints(intent);
464 if (endPair != null) {
465 currentMonitoredIntents.get(appId).put(intentKey, endPair);
466 }
467 });
468 }
469 return currentMonitoredIntents;
470 }
471
472 private Set<ElementId> connectedElements(Set<FilteredConnectPoint> cpSet) {
473 Set<ElementId> connectedElem = new HashSet<>();
474 cpSet.forEach(
475 fcp -> {
476 Set<Host> connectedHosts = hostService.getConnectedHosts(fcp.connectPoint());
477 if (connectedHosts.size() == 0) {
478 // In this case the end point is an ELEMENT without host connected
479 connectedElem.add(fcp.connectPoint().elementId());
480 } else {
481 // In this case we can have a set of hosts connected to that endpoint
482 connectedElem.addAll(connectedHosts.stream().map(Host::id)
483 .collect(Collectors.toSet()));
484 }
485 }
486 );
487 return connectedElem;
488 }
489
490 /**
491 * Extracts the endpoint from an intent.
492 * @param intent
493 * @return {@link Pair} containing in the Left element the set of input {@link ElementId},
494 * in the Right element the set of output {@link ElementId}.
495 */
496 private Pair<Set<ElementId>, Set<ElementId>> extractEndPoints(Intent intent) {
497 checkNotNull(intent, "intent must not be null");
498 Pair<Set<FilteredConnectPoint>, Set<FilteredConnectPoint>> cpPair;
499 cpPair = extractEndConnectPoints(intent);
500 if (cpPair == null) {
501 return null;
502 }
503 return Pair.of(connectedElements(cpPair.getLeft()), connectedElements(cpPair.getRight()));
504 }
505
506 /**
507 * Returns the end connect points of an intent.
508 * @param intent
509 * @return {@link Pair} containing in the Left element the input end connect points,
510 * in the Right element the output end connect points.
511 */
512 private Pair<Set<FilteredConnectPoint>, Set<FilteredConnectPoint>> extractEndConnectPoints(Intent intent) {
513 checkNotNull(intent, "intent must not be null");
514
515 Set<FilteredConnectPoint> inSet = new HashSet<>();
516 Set<FilteredConnectPoint> outSet = new HashSet<>();
517 if (intent instanceof PointToPointIntent) {
518 inSet.add(((PointToPointIntent) intent).filteredIngressPoint());
519 outSet.add(((PointToPointIntent) intent).filteredEgressPoint());
520 } else if (intent instanceof LinkCollectionIntent) {
521 inSet.addAll(((LinkCollectionIntent) intent).filteredIngressPoints());
522 outSet.addAll(((LinkCollectionIntent) intent).filteredEgressPoints());
523 }
524 return Pair.of(inSet, outSet);
525 }
526
527 /**
528 * Returns the connect point related to the output port of the rule.
529 * @param rule
530 * @return
531 */
532 private ConnectPoint buildConnectPoint(FlowRule rule) {
533 PortNumber port = getOutput(rule);
534
535 if (port == null) {
536 return null;
537 }
538 return new ConnectPoint(rule.deviceId(), port);
539 }
540
541 /**
542 * Returns the output port related to the rule.
543 * @param rule
544 * @return
545 */
546 private PortNumber getOutput(FlowRule rule) {
547 for (Instruction i : rule.treatment().allInstructions()) {
548 if (i.type() == Instruction.Type.OUTPUT) {
549 Instructions.OutputInstruction out = (Instructions.OutputInstruction) i;
550 return out.port();
551 }
552 }
553 return null;
554 }
555
556
557 private class InternalIntentListener implements IntentListener {
558
559 @Override
560 public void event(IntentEvent event) {
561 // It receives only events related to ConnectivityIntent to be monitored
562 Key intentKey = event.subject().key();
563 switch (event.type()) {
564 case INSTALLED:
565 // When an intent is installed and it need to be monitored
566 // it will pass from the "toBeMonitored" state to the "monitored" state
567 log.info("Monitored intent INSTALLED");
568 storeMonitoredIntent((ConnectivityIntent) event.subject());
569 break;
570
571 case WITHDRAWN:
572 // When an intent is withdrawn
573 // it will go back from the "monitored" state to the "toBeMonitored"
574 log.info("Monitored intent WITHDWRAWN");
575 removeIntent(intentKey);
576 break;
577
578 case FAILED:
579 log.warn("FAILED event not handled");
580 break;
581 default:
582 log.warn("Unknown intent event");
583 }
584 }
585
586 @Override
587 public boolean isRelevant(IntentEvent event) {
588 /*
589 * Check if the Intent event is relevant.
590 * An intent event is relevant if it is of one of the allowed types
591 * and if it is one of the monitored ones.
592 */
593 Key intentKey = event.subject().key();
594 return allowedIntent(event.subject())
595 && toBeMonitoredIntents.contains(intentKey);
596 }
597 }
598
599 private class InternalFlowRuleListener implements FlowRuleListener {
600 @Override
601 public void event(FlowRuleEvent event) {
602 FlowRule rule = event.subject();
603 switch (event.type()) {
604 case RULE_ADDED:
605 case RULE_UPDATED:
606 // In case of rule update, flow statistics are updated
607 if (rule instanceof FlowEntry) {
608 statsStore.updateFlowStatistic((FlowEntry) rule);
609 }
610 break;
611 case RULE_REMOVED:
612 // In case of rule removal, flow statistics are removed from the store
613 log.info("Rule removed: {}", rule.id());
614 statsStore.removeFlowStatistic(rule);
615 break;
616 default:
617 log.warn("Unknown flow rule event");
618 }
619 }
620
621 @Override
622 public boolean isRelevant(FlowRuleEvent event) {
623 /*
624 * Check if the rule event is relevant and it needs to be managed
625 * A Rule event is relevant if the flow rule it refers to is
626 * part of one of the monitored intents
627 */
628 FlowRule rule = event.subject();
629 for (Map.Entry<ApplicationId, Map<Key, ConnectivityIntent>> entry : monitoredIntents.entrySet()) {
630 for (Key key : entry.getValue().keySet()) {
631 List<Intent> ints = intentService.getInstallableIntents(key);
632 for (Intent i : ints) {
633 if (i instanceof FlowRuleIntent
634 && ((FlowRuleIntent) i).flowRules().contains(rule)) {
635 return true;
636 }
637 }
638 }
639 }
640 return false;
641 }
642 }
643}