blob: 17d420bd4bce8d6d24263c69006bf4c640e2c80a [file] [log] [blame]
tom95329eb2014-10-06 08:40:06 -07001package org.onlab.onos.net.intent.impl;
2
3import com.google.common.collect.HashMultimap;
4import com.google.common.collect.SetMultimap;
5import org.apache.felix.scr.annotations.Activate;
6import org.apache.felix.scr.annotations.Component;
7import org.apache.felix.scr.annotations.Deactivate;
8import org.apache.felix.scr.annotations.Reference;
9import org.apache.felix.scr.annotations.ReferenceCardinality;
10import org.apache.felix.scr.annotations.Service;
11import org.onlab.onos.event.Event;
12import org.onlab.onos.net.Link;
13import org.onlab.onos.net.LinkKey;
14import org.onlab.onos.net.intent.IntentId;
15import org.onlab.onos.net.link.LinkEvent;
16import org.onlab.onos.net.topology.TopologyEvent;
17import org.onlab.onos.net.topology.TopologyListener;
18import org.onlab.onos.net.topology.TopologyService;
19import org.slf4j.Logger;
20
21import java.util.Collection;
tom85258ee2014-10-07 00:10:02 -070022import java.util.HashSet;
23import java.util.Set;
tom95329eb2014-10-06 08:40:06 -070024import java.util.concurrent.ExecutorService;
25
26import static com.google.common.base.Preconditions.checkArgument;
27import static com.google.common.base.Preconditions.checkNotNull;
28import static com.google.common.collect.Multimaps.synchronizedSetMultimap;
29import static java.util.concurrent.Executors.newSingleThreadExecutor;
tom85258ee2014-10-07 00:10:02 -070030import static org.onlab.onos.net.link.LinkEvent.Type.LINK_REMOVED;
tom95329eb2014-10-06 08:40:06 -070031import static org.onlab.util.Tools.namedThreads;
32import static org.slf4j.LoggerFactory.getLogger;
33
34/**
35 * Entity responsible for tracking installed flows and for monitoring topology
36 * events to determine what flows are affected by topology changes.
37 */
38@Component
39@Service
tom85258ee2014-10-07 00:10:02 -070040public class ObjectiveTracker implements ObjectiveTrackerService {
tom95329eb2014-10-06 08:40:06 -070041
42 private final Logger log = getLogger(getClass());
43
44 private final SetMultimap<LinkKey, IntentId> intentsByLink =
45 synchronizedSetMultimap(HashMultimap.<LinkKey, IntentId>create());
46
47 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
48 protected TopologyService topologyService;
49
50 private ExecutorService executorService =
51 newSingleThreadExecutor(namedThreads("onos-flowtracker"));
52
53 private TopologyListener listener = new InternalTopologyListener();
54 private TopologyChangeDelegate delegate;
55
56 @Activate
57 public void activate() {
58 topologyService.addListener(listener);
59 log.info("Started");
60 }
61
62 @Deactivate
63 public void deactivate() {
64 topologyService.removeListener(listener);
65 log.info("Stopped");
66 }
67
68 @Override
69 public void setDelegate(TopologyChangeDelegate delegate) {
70 checkNotNull(delegate, "Delegate cannot be null");
71 checkArgument(this.delegate == null || this.delegate == delegate,
72 "Another delegate already set");
73 this.delegate = delegate;
74 }
75
76 @Override
77 public void unsetDelegate(TopologyChangeDelegate delegate) {
78 checkArgument(this.delegate == delegate, "Not the current delegate");
79 this.delegate = null;
80 }
81
82 @Override
83 public void addTrackedResources(IntentId intentId, Collection<Link> resources) {
84 for (Link link : resources) {
85 intentsByLink.put(new LinkKey(link), intentId);
86 }
87 }
88
89 @Override
90 public void removeTrackedResources(IntentId intentId, Collection<Link> resources) {
91 for (Link link : resources) {
92 intentsByLink.remove(new LinkKey(link), intentId);
93 }
94 }
95
96 // Internal re-actor to topology change events.
97 private class InternalTopologyListener implements TopologyListener {
98 @Override
99 public void event(TopologyEvent event) {
100 executorService.execute(new TopologyChangeHandler(event));
101 }
102 }
103
104 // Re-dispatcher of topology change events.
105 private class TopologyChangeHandler implements Runnable {
106
107 private final TopologyEvent event;
108
109 TopologyChangeHandler(TopologyEvent event) {
110 this.event = event;
111 }
112
113 @Override
114 public void run() {
115 if (event.reasons() == null) {
tom85258ee2014-10-07 00:10:02 -0700116 delegate.triggerCompile(null, false);
117
tom95329eb2014-10-06 08:40:06 -0700118 } else {
tom85258ee2014-10-07 00:10:02 -0700119 Set<IntentId> toBeRecompiled = new HashSet<>();
120 boolean recompileOnly = true;
121
122 // Scan through the list of reasons and keep accruing all
123 // intents that need to be recompiled.
tom95329eb2014-10-06 08:40:06 -0700124 for (Event reason : event.reasons()) {
125 if (reason instanceof LinkEvent) {
126 LinkEvent linkEvent = (LinkEvent) reason;
tom85258ee2014-10-07 00:10:02 -0700127 if (linkEvent.type() == LINK_REMOVED) {
128 Set<IntentId> intentIds = intentsByLink.get(new LinkKey(linkEvent.subject()));
129 toBeRecompiled.addAll(intentIds);
130 }
131 recompileOnly = recompileOnly && linkEvent.type() == LINK_REMOVED;
tom95329eb2014-10-06 08:40:06 -0700132 }
133 }
tom85258ee2014-10-07 00:10:02 -0700134
135 delegate.triggerCompile(toBeRecompiled, !recompileOnly);
tom95329eb2014-10-06 08:40:06 -0700136 }
137 }
138 }
139
140}