blob: c32b29c31bcc1da8c84bc09c2e6f57361796e861 [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 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.net.intent.impl;
tom95329eb2014-10-06 08:40:06 -070017
Brian O'Connor86f6f7f2014-12-01 17:02:45 -080018import com.google.common.collect.HashMultimap;
19import com.google.common.collect.Lists;
20import com.google.common.collect.SetMultimap;
tom95329eb2014-10-06 08:40:06 -070021import 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;
Brian O'Connorabafb502014-12-02 22:26:20 -080027import org.onosproject.core.ApplicationId;
28import org.onosproject.event.Event;
29import org.onosproject.net.Link;
30import org.onosproject.net.LinkKey;
31import org.onosproject.net.NetworkResource;
Brian O'Connorabafb502014-12-02 22:26:20 -080032import org.onosproject.net.intent.IntentService;
Ray Milkeyf9af43c2015-02-09 16:45:48 -080033import org.onosproject.net.intent.Key;
Brian O'Connorabafb502014-12-02 22:26:20 -080034import org.onosproject.net.link.LinkEvent;
35import org.onosproject.net.resource.LinkResourceEvent;
36import org.onosproject.net.resource.LinkResourceListener;
37import org.onosproject.net.resource.LinkResourceService;
38import org.onosproject.net.topology.TopologyEvent;
39import org.onosproject.net.topology.TopologyListener;
40import org.onosproject.net.topology.TopologyService;
tom95329eb2014-10-06 08:40:06 -070041import org.slf4j.Logger;
42
Brian O'Connor86f6f7f2014-12-01 17:02:45 -080043import java.util.Collection;
44import java.util.HashSet;
45import java.util.Set;
46import java.util.concurrent.ExecutorService;
tom95329eb2014-10-06 08:40:06 -070047
48import static com.google.common.base.Preconditions.checkArgument;
49import static com.google.common.base.Preconditions.checkNotNull;
50import static com.google.common.collect.Multimaps.synchronizedSetMultimap;
51import static java.util.concurrent.Executors.newSingleThreadExecutor;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080052import static org.onlab.util.Tools.groupedThreads;
Brian O'Connorabafb502014-12-02 22:26:20 -080053import static org.onosproject.net.LinkKey.linkKey;
54import static org.onosproject.net.link.LinkEvent.Type.LINK_REMOVED;
55import static org.onosproject.net.link.LinkEvent.Type.LINK_UPDATED;
tom95329eb2014-10-06 08:40:06 -070056import static org.slf4j.LoggerFactory.getLogger;
57
58/**
59 * Entity responsible for tracking installed flows and for monitoring topology
60 * events to determine what flows are affected by topology changes.
61 */
Ray Milkeye97ede92014-11-20 10:43:12 -080062@Component(immediate = true)
tom95329eb2014-10-06 08:40:06 -070063@Service
tom85258ee2014-10-07 00:10:02 -070064public class ObjectiveTracker implements ObjectiveTrackerService {
tom95329eb2014-10-06 08:40:06 -070065
66 private final Logger log = getLogger(getClass());
67
Ray Milkeyf9af43c2015-02-09 16:45:48 -080068 private final SetMultimap<LinkKey, Key> intentsByLink =
Brian O'Connor64a0369d2015-02-20 22:02:59 -080069 //TODO this could be slow as a point of synchronization
Ray Milkeyf9af43c2015-02-09 16:45:48 -080070 synchronizedSetMultimap(HashMultimap.<LinkKey, Key>create());
tom95329eb2014-10-06 08:40:06 -070071
72 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 protected TopologyService topologyService;
74
Ray Milkeye97ede92014-11-20 10:43:12 -080075 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected LinkResourceService resourceManager;
77
Brian O'Connor5d55ed42014-12-01 18:27:47 -080078 @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY)
Brian O'Connor86f6f7f2014-12-01 17:02:45 -080079 protected IntentService intentService;
80
tom95329eb2014-10-06 08:40:06 -070081 private ExecutorService executorService =
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080082 newSingleThreadExecutor(groupedThreads("onos/intent", "flowtracker"));
tom95329eb2014-10-06 08:40:06 -070083
84 private TopologyListener listener = new InternalTopologyListener();
Ray Milkeye97ede92014-11-20 10:43:12 -080085 private LinkResourceListener linkResourceListener =
86 new InternalLinkResourceListener();
tom95329eb2014-10-06 08:40:06 -070087 private TopologyChangeDelegate delegate;
88
89 @Activate
90 public void activate() {
91 topologyService.addListener(listener);
Ray Milkeye97ede92014-11-20 10:43:12 -080092 resourceManager.addListener(linkResourceListener);
tom95329eb2014-10-06 08:40:06 -070093 log.info("Started");
94 }
95
96 @Deactivate
97 public void deactivate() {
98 topologyService.removeListener(listener);
Ray Milkeye97ede92014-11-20 10:43:12 -080099 resourceManager.removeListener(linkResourceListener);
tom95329eb2014-10-06 08:40:06 -0700100 log.info("Stopped");
101 }
102
Brian O'Connor5d55ed42014-12-01 18:27:47 -0800103 protected void bindIntentService(IntentService service) {
104 if (intentService == null) {
105 intentService = service;
106 }
107 }
108
109 protected void unbindIntentService(IntentService service) {
110 if (intentService == service) {
111 intentService = null;
112 }
113 }
114
tom95329eb2014-10-06 08:40:06 -0700115 @Override
116 public void setDelegate(TopologyChangeDelegate delegate) {
117 checkNotNull(delegate, "Delegate cannot be null");
118 checkArgument(this.delegate == null || this.delegate == delegate,
119 "Another delegate already set");
120 this.delegate = delegate;
121 }
122
123 @Override
124 public void unsetDelegate(TopologyChangeDelegate delegate) {
125 checkArgument(this.delegate == delegate, "Not the current delegate");
126 this.delegate = null;
127 }
128
129 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800130 public void addTrackedResources(Key intentKey,
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700131 Collection<NetworkResource> resources) {
132 for (NetworkResource resource : resources) {
133 if (resource instanceof Link) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800134 intentsByLink.put(linkKey((Link) resource), intentKey);
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700135 }
tom95329eb2014-10-06 08:40:06 -0700136 }
137 }
138
139 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800140 public void removeTrackedResources(Key intentKey,
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700141 Collection<NetworkResource> resources) {
142 for (NetworkResource resource : resources) {
143 if (resource instanceof Link) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800144 intentsByLink.remove(linkKey((Link) resource), intentKey);
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700145 }
tom95329eb2014-10-06 08:40:06 -0700146 }
147 }
148
149 // Internal re-actor to topology change events.
150 private class InternalTopologyListener implements TopologyListener {
151 @Override
152 public void event(TopologyEvent event) {
153 executorService.execute(new TopologyChangeHandler(event));
154 }
155 }
156
157 // Re-dispatcher of topology change events.
158 private class TopologyChangeHandler implements Runnable {
159
160 private final TopologyEvent event;
161
162 TopologyChangeHandler(TopologyEvent event) {
163 this.event = event;
164 }
165
166 @Override
167 public void run() {
Thomas Vachuska7b652ad2014-10-30 14:10:51 -0700168 // If there is no delegate, why bother? Just bail.
169 if (delegate == null) {
170 return;
171 }
172
Ray Milkey7c44c052014-12-05 10:34:54 -0800173 if (event.reasons() == null || event.reasons().isEmpty()) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800174 delegate.triggerCompile(new HashSet<Key>(), true);
tom85258ee2014-10-07 00:10:02 -0700175
tom95329eb2014-10-06 08:40:06 -0700176 } else {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800177 Set<Key> toBeRecompiled = new HashSet<>();
tom85258ee2014-10-07 00:10:02 -0700178 boolean recompileOnly = true;
179
180 // Scan through the list of reasons and keep accruing all
181 // intents that need to be recompiled.
tom95329eb2014-10-06 08:40:06 -0700182 for (Event reason : event.reasons()) {
183 if (reason instanceof LinkEvent) {
184 LinkEvent linkEvent = (LinkEvent) reason;
Praseed Balakrishnan00dd1f92014-11-19 17:12:36 -0800185 if (linkEvent.type() == LINK_REMOVED
186 || (linkEvent.type() == LINK_UPDATED &&
187 linkEvent.subject().isDurable())) {
Yuta HIGUCHI56df70f2014-10-28 22:26:15 -0700188 final LinkKey linkKey = linkKey(linkEvent.subject());
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800189 synchronized (intentsByLink) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800190 Set<Key> intentKeys = intentsByLink.get(linkKey);
191 log.debug("recompile triggered by LinkDown {} {}", linkKey, intentKeys);
192 toBeRecompiled.addAll(intentKeys);
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800193 }
tom85258ee2014-10-07 00:10:02 -0700194 }
Praseed Balakrishnan00dd1f92014-11-19 17:12:36 -0800195 recompileOnly = recompileOnly &&
196 (linkEvent.type() == LINK_REMOVED ||
197 (linkEvent.type() == LINK_UPDATED &&
198 linkEvent.subject().isDurable()));
tom95329eb2014-10-06 08:40:06 -0700199 }
200 }
tom85258ee2014-10-07 00:10:02 -0700201 delegate.triggerCompile(toBeRecompiled, !recompileOnly);
tom95329eb2014-10-06 08:40:06 -0700202 }
203 }
204 }
205
Ray Milkeye97ede92014-11-20 10:43:12 -0800206 /**
207 * Internal re-actor to resource available events.
208 */
209 private class InternalLinkResourceListener implements LinkResourceListener {
210 @Override
211 public void event(LinkResourceEvent event) {
212 executorService.execute(new ResourceAvailableHandler(event));
213 }
214 }
215
216 /*
217 * Re-dispatcher of resource available events.
218 */
219 private class ResourceAvailableHandler implements Runnable {
220
221 private final LinkResourceEvent event;
222
223 ResourceAvailableHandler(LinkResourceEvent event) {
224 this.event = event;
225 }
226
227 @Override
228 public void run() {
229 // If there is no delegate, why bother? Just bail.
230 if (delegate == null) {
231 return;
232 }
233
234 delegate.triggerCompile(new HashSet<>(), true);
235 }
236 }
237
Brian O'Connor72a034c2014-11-26 18:24:23 -0800238 //TODO consider adding flow rule event tracking
Ray Milkeye97ede92014-11-20 10:43:12 -0800239
Brian O'Connor86f6f7f2014-12-01 17:02:45 -0800240 private void updateTrackedResources(ApplicationId appId, boolean track) {
Brian O'Connor5d55ed42014-12-01 18:27:47 -0800241 if (intentService == null) {
242 log.debug("Intent service is not bound yet");
243 return;
244 }
Brian O'Connor86f6f7f2014-12-01 17:02:45 -0800245 intentService.getIntents().forEach(intent -> {
246 if (intent.appId().equals(appId)) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800247 Key key = intent.key();
Brian O'Connor86f6f7f2014-12-01 17:02:45 -0800248 Collection<NetworkResource> resources = Lists.newArrayList();
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800249 intentService.getInstallableIntents(key).stream()
Brian O'Connor86f6f7f2014-12-01 17:02:45 -0800250 .map(installable -> installable.resources())
251 .forEach(resources::addAll);
252 if (track) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800253 addTrackedResources(key, resources);
Brian O'Connor86f6f7f2014-12-01 17:02:45 -0800254 } else {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800255 removeTrackedResources(key, resources);
Brian O'Connor86f6f7f2014-12-01 17:02:45 -0800256 }
257 }
258 });
259 }
tom95329eb2014-10-06 08:40:06 -0700260}