blob: 53b1239feef9292727859e5d81e139b7f3ef4e5a [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
18import com.google.common.collect.HashMultimap;
19import com.google.common.collect.SetMultimap;
20import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.apache.felix.scr.annotations.Service;
26import org.onlab.onos.event.Event;
27import org.onlab.onos.net.Link;
28import org.onlab.onos.net.LinkKey;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070029import org.onlab.onos.net.NetworkResource;
tom95329eb2014-10-06 08:40:06 -070030import org.onlab.onos.net.intent.IntentId;
31import org.onlab.onos.net.link.LinkEvent;
32import org.onlab.onos.net.topology.TopologyEvent;
33import org.onlab.onos.net.topology.TopologyListener;
34import org.onlab.onos.net.topology.TopologyService;
35import org.slf4j.Logger;
36
37import java.util.Collection;
tom85258ee2014-10-07 00:10:02 -070038import java.util.HashSet;
39import java.util.Set;
tom95329eb2014-10-06 08:40:06 -070040import java.util.concurrent.ExecutorService;
41
42import static com.google.common.base.Preconditions.checkArgument;
43import static com.google.common.base.Preconditions.checkNotNull;
44import static com.google.common.collect.Multimaps.synchronizedSetMultimap;
45import static java.util.concurrent.Executors.newSingleThreadExecutor;
Yuta HIGUCHI18ab8a92014-10-13 11:16:19 -070046import static org.onlab.onos.net.LinkKey.linkKey;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070047import static org.onlab.onos.net.link.LinkEvent.Type.LINK_REMOVED;
tom95329eb2014-10-06 08:40:06 -070048import static org.onlab.util.Tools.namedThreads;
49import static org.slf4j.LoggerFactory.getLogger;
50
51/**
52 * Entity responsible for tracking installed flows and for monitoring topology
53 * events to determine what flows are affected by topology changes.
54 */
55@Component
56@Service
tom85258ee2014-10-07 00:10:02 -070057public class ObjectiveTracker implements ObjectiveTrackerService {
tom95329eb2014-10-06 08:40:06 -070058
59 private final Logger log = getLogger(getClass());
60
61 private final SetMultimap<LinkKey, IntentId> intentsByLink =
62 synchronizedSetMultimap(HashMultimap.<LinkKey, IntentId>create());
63
64 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
65 protected TopologyService topologyService;
66
67 private ExecutorService executorService =
68 newSingleThreadExecutor(namedThreads("onos-flowtracker"));
69
70 private TopologyListener listener = new InternalTopologyListener();
71 private TopologyChangeDelegate delegate;
72
73 @Activate
74 public void activate() {
75 topologyService.addListener(listener);
76 log.info("Started");
77 }
78
79 @Deactivate
80 public void deactivate() {
81 topologyService.removeListener(listener);
82 log.info("Stopped");
83 }
84
85 @Override
86 public void setDelegate(TopologyChangeDelegate delegate) {
87 checkNotNull(delegate, "Delegate cannot be null");
88 checkArgument(this.delegate == null || this.delegate == delegate,
89 "Another delegate already set");
90 this.delegate = delegate;
91 }
92
93 @Override
94 public void unsetDelegate(TopologyChangeDelegate delegate) {
95 checkArgument(this.delegate == delegate, "Not the current delegate");
96 this.delegate = null;
97 }
98
99 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700100 public void addTrackedResources(IntentId intentId,
101 Collection<NetworkResource> resources) {
102 for (NetworkResource resource : resources) {
103 if (resource instanceof Link) {
104 intentsByLink.put(linkKey((Link) resource), intentId);
105 }
tom95329eb2014-10-06 08:40:06 -0700106 }
107 }
108
109 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700110 public void removeTrackedResources(IntentId intentId,
111 Collection<NetworkResource> resources) {
112 for (NetworkResource resource : resources) {
113 if (resource instanceof Link) {
114 intentsByLink.remove(linkKey((Link) resource), intentId);
115 }
tom95329eb2014-10-06 08:40:06 -0700116 }
117 }
118
119 // Internal re-actor to topology change events.
120 private class InternalTopologyListener implements TopologyListener {
121 @Override
122 public void event(TopologyEvent event) {
123 executorService.execute(new TopologyChangeHandler(event));
124 }
125 }
126
127 // Re-dispatcher of topology change events.
128 private class TopologyChangeHandler implements Runnable {
129
130 private final TopologyEvent event;
131
132 TopologyChangeHandler(TopologyEvent event) {
133 this.event = event;
134 }
135
136 @Override
137 public void run() {
Thomas Vachuska7b652ad2014-10-30 14:10:51 -0700138 // If there is no delegate, why bother? Just bail.
139 if (delegate == null) {
140 return;
141 }
142
tom95329eb2014-10-06 08:40:06 -0700143 if (event.reasons() == null) {
tom1dd08e42014-10-07 11:40:00 -0700144 delegate.triggerCompile(new HashSet<IntentId>(), true);
tom85258ee2014-10-07 00:10:02 -0700145
tom95329eb2014-10-06 08:40:06 -0700146 } else {
tom85258ee2014-10-07 00:10:02 -0700147 Set<IntentId> toBeRecompiled = new HashSet<>();
148 boolean recompileOnly = true;
149
150 // Scan through the list of reasons and keep accruing all
151 // intents that need to be recompiled.
tom95329eb2014-10-06 08:40:06 -0700152 for (Event reason : event.reasons()) {
153 if (reason instanceof LinkEvent) {
154 LinkEvent linkEvent = (LinkEvent) reason;
tom85258ee2014-10-07 00:10:02 -0700155 if (linkEvent.type() == LINK_REMOVED) {
Yuta HIGUCHI56df70f2014-10-28 22:26:15 -0700156 final LinkKey linkKey = linkKey(linkEvent.subject());
157 Set<IntentId> intentIds = intentsByLink.get(linkKey);
158 log.debug("recompile triggered by LinkDown {} {}", linkKey, intentIds);
tom85258ee2014-10-07 00:10:02 -0700159 toBeRecompiled.addAll(intentIds);
160 }
161 recompileOnly = recompileOnly && linkEvent.type() == LINK_REMOVED;
tom95329eb2014-10-06 08:40:06 -0700162 }
163 }
tom85258ee2014-10-07 00:10:02 -0700164
165 delegate.triggerCompile(toBeRecompiled, !recompileOnly);
tom95329eb2014-10-06 08:40:06 -0700166 }
167 }
168 }
169
170}