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