blob: c984632669a25d2780904a21de8d0b46adc41f91 [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;
Praseed Balakrishnan00dd1f92014-11-19 17:12:36 -080048import static org.onlab.onos.net.link.LinkEvent.Type.LINK_UPDATED;
tom95329eb2014-10-06 08:40:06 -070049import static org.onlab.util.Tools.namedThreads;
50import static org.slf4j.LoggerFactory.getLogger;
51
52/**
53 * Entity responsible for tracking installed flows and for monitoring topology
54 * events to determine what flows are affected by topology changes.
55 */
56@Component
57@Service
tom85258ee2014-10-07 00:10:02 -070058public class ObjectiveTracker implements ObjectiveTrackerService {
tom95329eb2014-10-06 08:40:06 -070059
60 private final Logger log = getLogger(getClass());
61
62 private final SetMultimap<LinkKey, IntentId> intentsByLink =
63 synchronizedSetMultimap(HashMultimap.<LinkKey, IntentId>create());
64
65 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
66 protected TopologyService topologyService;
67
68 private ExecutorService executorService =
69 newSingleThreadExecutor(namedThreads("onos-flowtracker"));
70
71 private TopologyListener listener = new InternalTopologyListener();
72 private TopologyChangeDelegate delegate;
73
74 @Activate
75 public void activate() {
76 topologyService.addListener(listener);
77 log.info("Started");
78 }
79
80 @Deactivate
81 public void deactivate() {
82 topologyService.removeListener(listener);
83 log.info("Stopped");
84 }
85
86 @Override
87 public void setDelegate(TopologyChangeDelegate delegate) {
88 checkNotNull(delegate, "Delegate cannot be null");
89 checkArgument(this.delegate == null || this.delegate == delegate,
90 "Another delegate already set");
91 this.delegate = delegate;
92 }
93
94 @Override
95 public void unsetDelegate(TopologyChangeDelegate delegate) {
96 checkArgument(this.delegate == delegate, "Not the current delegate");
97 this.delegate = null;
98 }
99
100 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700101 public void addTrackedResources(IntentId intentId,
102 Collection<NetworkResource> resources) {
103 for (NetworkResource resource : resources) {
104 if (resource instanceof Link) {
105 intentsByLink.put(linkKey((Link) resource), intentId);
106 }
tom95329eb2014-10-06 08:40:06 -0700107 }
108 }
109
110 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700111 public void removeTrackedResources(IntentId intentId,
112 Collection<NetworkResource> resources) {
113 for (NetworkResource resource : resources) {
114 if (resource instanceof Link) {
115 intentsByLink.remove(linkKey((Link) resource), intentId);
116 }
tom95329eb2014-10-06 08:40:06 -0700117 }
118 }
119
120 // Internal re-actor to topology change events.
121 private class InternalTopologyListener implements TopologyListener {
122 @Override
123 public void event(TopologyEvent event) {
124 executorService.execute(new TopologyChangeHandler(event));
125 }
126 }
127
128 // Re-dispatcher of topology change events.
129 private class TopologyChangeHandler implements Runnable {
130
131 private final TopologyEvent event;
132
133 TopologyChangeHandler(TopologyEvent event) {
134 this.event = event;
135 }
136
137 @Override
138 public void run() {
Thomas Vachuska7b652ad2014-10-30 14:10:51 -0700139 // If there is no delegate, why bother? Just bail.
140 if (delegate == null) {
141 return;
142 }
143
tom95329eb2014-10-06 08:40:06 -0700144 if (event.reasons() == null) {
tom1dd08e42014-10-07 11:40:00 -0700145 delegate.triggerCompile(new HashSet<IntentId>(), true);
tom85258ee2014-10-07 00:10:02 -0700146
tom95329eb2014-10-06 08:40:06 -0700147 } else {
tom85258ee2014-10-07 00:10:02 -0700148 Set<IntentId> toBeRecompiled = new HashSet<>();
149 boolean recompileOnly = true;
150
151 // Scan through the list of reasons and keep accruing all
152 // intents that need to be recompiled.
tom95329eb2014-10-06 08:40:06 -0700153 for (Event reason : event.reasons()) {
154 if (reason instanceof LinkEvent) {
155 LinkEvent linkEvent = (LinkEvent) reason;
Praseed Balakrishnan00dd1f92014-11-19 17:12:36 -0800156 if (linkEvent.type() == LINK_REMOVED
157 || (linkEvent.type() == LINK_UPDATED &&
158 linkEvent.subject().isDurable())) {
Yuta HIGUCHI56df70f2014-10-28 22:26:15 -0700159 final LinkKey linkKey = linkKey(linkEvent.subject());
160 Set<IntentId> intentIds = intentsByLink.get(linkKey);
161 log.debug("recompile triggered by LinkDown {} {}", linkKey, intentIds);
tom85258ee2014-10-07 00:10:02 -0700162 toBeRecompiled.addAll(intentIds);
163 }
Praseed Balakrishnan00dd1f92014-11-19 17:12:36 -0800164 recompileOnly = recompileOnly &&
165 (linkEvent.type() == LINK_REMOVED ||
166 (linkEvent.type() == LINK_UPDATED &&
167 linkEvent.subject().isDurable()));
tom95329eb2014-10-06 08:40:06 -0700168 }
169 }
tom85258ee2014-10-07 00:10:02 -0700170
171 delegate.triggerCompile(toBeRecompiled, !recompileOnly);
tom95329eb2014-10-06 08:40:06 -0700172 }
173 }
174 }
175
176}