blob: 7cc5d47d8abf548be97553380da14d36cfb7e0bc [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
2 * Copyright 2014 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 */
tom95329eb2014-10-06 08:40:06 -070016package org.onlab.onos.net.intent.impl;
17
Ray Milkeye97ede92014-11-20 10:43:12 -080018import java.util.Collection;
19import java.util.HashSet;
20import java.util.Set;
21import java.util.concurrent.ExecutorService;
22
tom95329eb2014-10-06 08:40:06 -070023import org.apache.felix.scr.annotations.Activate;
24import org.apache.felix.scr.annotations.Component;
25import org.apache.felix.scr.annotations.Deactivate;
26import org.apache.felix.scr.annotations.Reference;
27import org.apache.felix.scr.annotations.ReferenceCardinality;
28import org.apache.felix.scr.annotations.Service;
29import org.onlab.onos.event.Event;
30import org.onlab.onos.net.Link;
31import org.onlab.onos.net.LinkKey;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070032import org.onlab.onos.net.NetworkResource;
tom95329eb2014-10-06 08:40:06 -070033import org.onlab.onos.net.intent.IntentId;
34import org.onlab.onos.net.link.LinkEvent;
Ray Milkeye97ede92014-11-20 10:43:12 -080035import org.onlab.onos.net.resource.LinkResourceEvent;
36import org.onlab.onos.net.resource.LinkResourceListener;
37import org.onlab.onos.net.resource.LinkResourceService;
tom95329eb2014-10-06 08:40:06 -070038import org.onlab.onos.net.topology.TopologyEvent;
39import org.onlab.onos.net.topology.TopologyListener;
40import org.onlab.onos.net.topology.TopologyService;
41import org.slf4j.Logger;
42
Ray Milkeye97ede92014-11-20 10:43:12 -080043import com.google.common.collect.HashMultimap;
44import com.google.common.collect.SetMultimap;
tom95329eb2014-10-06 08:40:06 -070045
46import static com.google.common.base.Preconditions.checkArgument;
47import static com.google.common.base.Preconditions.checkNotNull;
48import static com.google.common.collect.Multimaps.synchronizedSetMultimap;
49import static java.util.concurrent.Executors.newSingleThreadExecutor;
Yuta HIGUCHI18ab8a92014-10-13 11:16:19 -070050import static org.onlab.onos.net.LinkKey.linkKey;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070051import static org.onlab.onos.net.link.LinkEvent.Type.LINK_REMOVED;
Praseed Balakrishnan00dd1f92014-11-19 17:12:36 -080052import static org.onlab.onos.net.link.LinkEvent.Type.LINK_UPDATED;
tom95329eb2014-10-06 08:40:06 -070053import static org.onlab.util.Tools.namedThreads;
54import static org.slf4j.LoggerFactory.getLogger;
55
56/**
57 * Entity responsible for tracking installed flows and for monitoring topology
58 * events to determine what flows are affected by topology changes.
59 */
Ray Milkeye97ede92014-11-20 10:43:12 -080060@Component(immediate = true)
tom95329eb2014-10-06 08:40:06 -070061@Service
tom85258ee2014-10-07 00:10:02 -070062public class ObjectiveTracker implements ObjectiveTrackerService {
tom95329eb2014-10-06 08:40:06 -070063
64 private final Logger log = getLogger(getClass());
65
66 private final SetMultimap<LinkKey, IntentId> intentsByLink =
67 synchronizedSetMultimap(HashMultimap.<LinkKey, IntentId>create());
68
69 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
70 protected TopologyService topologyService;
71
Ray Milkeye97ede92014-11-20 10:43:12 -080072 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 protected LinkResourceService resourceManager;
74
tom95329eb2014-10-06 08:40:06 -070075 private ExecutorService executorService =
76 newSingleThreadExecutor(namedThreads("onos-flowtracker"));
77
78 private TopologyListener listener = new InternalTopologyListener();
Ray Milkeye97ede92014-11-20 10:43:12 -080079 private LinkResourceListener linkResourceListener =
80 new InternalLinkResourceListener();
tom95329eb2014-10-06 08:40:06 -070081 private TopologyChangeDelegate delegate;
82
83 @Activate
84 public void activate() {
85 topologyService.addListener(listener);
Ray Milkeye97ede92014-11-20 10:43:12 -080086 resourceManager.addListener(linkResourceListener);
tom95329eb2014-10-06 08:40:06 -070087 log.info("Started");
88 }
89
90 @Deactivate
91 public void deactivate() {
92 topologyService.removeListener(listener);
Ray Milkeye97ede92014-11-20 10:43:12 -080093 resourceManager.removeListener(linkResourceListener);
tom95329eb2014-10-06 08:40:06 -070094 log.info("Stopped");
95 }
96
97 @Override
98 public void setDelegate(TopologyChangeDelegate delegate) {
99 checkNotNull(delegate, "Delegate cannot be null");
100 checkArgument(this.delegate == null || this.delegate == delegate,
101 "Another delegate already set");
102 this.delegate = delegate;
103 }
104
105 @Override
106 public void unsetDelegate(TopologyChangeDelegate delegate) {
107 checkArgument(this.delegate == delegate, "Not the current delegate");
108 this.delegate = null;
109 }
110
111 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700112 public void addTrackedResources(IntentId intentId,
113 Collection<NetworkResource> resources) {
114 for (NetworkResource resource : resources) {
115 if (resource instanceof Link) {
116 intentsByLink.put(linkKey((Link) resource), intentId);
117 }
tom95329eb2014-10-06 08:40:06 -0700118 }
119 }
120
121 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700122 public void removeTrackedResources(IntentId intentId,
123 Collection<NetworkResource> resources) {
124 for (NetworkResource resource : resources) {
125 if (resource instanceof Link) {
126 intentsByLink.remove(linkKey((Link) resource), intentId);
127 }
tom95329eb2014-10-06 08:40:06 -0700128 }
129 }
130
131 // Internal re-actor to topology change events.
132 private class InternalTopologyListener implements TopologyListener {
133 @Override
134 public void event(TopologyEvent event) {
135 executorService.execute(new TopologyChangeHandler(event));
136 }
137 }
138
139 // Re-dispatcher of topology change events.
140 private class TopologyChangeHandler implements Runnable {
141
142 private final TopologyEvent event;
143
144 TopologyChangeHandler(TopologyEvent event) {
145 this.event = event;
146 }
147
148 @Override
149 public void run() {
Thomas Vachuska7b652ad2014-10-30 14:10:51 -0700150 // If there is no delegate, why bother? Just bail.
151 if (delegate == null) {
152 return;
153 }
154
tom95329eb2014-10-06 08:40:06 -0700155 if (event.reasons() == null) {
tom1dd08e42014-10-07 11:40:00 -0700156 delegate.triggerCompile(new HashSet<IntentId>(), true);
tom85258ee2014-10-07 00:10:02 -0700157
tom95329eb2014-10-06 08:40:06 -0700158 } else {
tom85258ee2014-10-07 00:10:02 -0700159 Set<IntentId> toBeRecompiled = new HashSet<>();
160 boolean recompileOnly = true;
161
162 // Scan through the list of reasons and keep accruing all
163 // intents that need to be recompiled.
tom95329eb2014-10-06 08:40:06 -0700164 for (Event reason : event.reasons()) {
165 if (reason instanceof LinkEvent) {
166 LinkEvent linkEvent = (LinkEvent) reason;
Praseed Balakrishnan00dd1f92014-11-19 17:12:36 -0800167 if (linkEvent.type() == LINK_REMOVED
168 || (linkEvent.type() == LINK_UPDATED &&
169 linkEvent.subject().isDurable())) {
Yuta HIGUCHI56df70f2014-10-28 22:26:15 -0700170 final LinkKey linkKey = linkKey(linkEvent.subject());
171 Set<IntentId> intentIds = intentsByLink.get(linkKey);
172 log.debug("recompile triggered by LinkDown {} {}", linkKey, intentIds);
tom85258ee2014-10-07 00:10:02 -0700173 toBeRecompiled.addAll(intentIds);
174 }
Praseed Balakrishnan00dd1f92014-11-19 17:12:36 -0800175 recompileOnly = recompileOnly &&
176 (linkEvent.type() == LINK_REMOVED ||
177 (linkEvent.type() == LINK_UPDATED &&
178 linkEvent.subject().isDurable()));
tom95329eb2014-10-06 08:40:06 -0700179 }
180 }
tom85258ee2014-10-07 00:10:02 -0700181
182 delegate.triggerCompile(toBeRecompiled, !recompileOnly);
tom95329eb2014-10-06 08:40:06 -0700183 }
184 }
185 }
186
Ray Milkeye97ede92014-11-20 10:43:12 -0800187 /**
188 * Internal re-actor to resource available events.
189 */
190 private class InternalLinkResourceListener implements LinkResourceListener {
191 @Override
192 public void event(LinkResourceEvent event) {
193 executorService.execute(new ResourceAvailableHandler(event));
194 }
195 }
196
197 /*
198 * Re-dispatcher of resource available events.
199 */
200 private class ResourceAvailableHandler implements Runnable {
201
202 private final LinkResourceEvent event;
203
204 ResourceAvailableHandler(LinkResourceEvent event) {
205 this.event = event;
206 }
207
208 @Override
209 public void run() {
210 // If there is no delegate, why bother? Just bail.
211 if (delegate == null) {
212 return;
213 }
214
215 delegate.triggerCompile(new HashSet<>(), true);
216 }
217 }
218
Brian O'Connor72a034c2014-11-26 18:24:23 -0800219 //TODO consider adding flow rule event tracking
Ray Milkeye97ede92014-11-20 10:43:12 -0800220
Brian O'Connor72a034c2014-11-26 18:24:23 -0800221 //FIXME the only intents that will be tracked are events that were
222 //executed on this instance. Need to have some backup trackers...
tom95329eb2014-10-06 08:40:06 -0700223}