blob: 949c65766c27b6a4f636546e76887b04a6c5a06d [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
ssyoon9030fbcd92015-08-17 10:42:07 +09002 * Copyright 2015 Open Networking Laboratory
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.provider.of.flow.impl;
alshabib1cc04f72014-09-16 16:09:58 -070017
Thomas Vachuska75aaa672015-04-29 12:24:43 -070018import com.google.common.cache.Cache;
19import com.google.common.cache.CacheBuilder;
20import com.google.common.cache.RemovalCause;
21import com.google.common.cache.RemovalNotification;
22import com.google.common.collect.Maps;
23import com.google.common.collect.Sets;
alshabib1cc04f72014-09-16 16:09:58 -070024import org.apache.felix.scr.annotations.Activate;
25import org.apache.felix.scr.annotations.Component;
26import org.apache.felix.scr.annotations.Deactivate;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070027import org.apache.felix.scr.annotations.Modified;
28import org.apache.felix.scr.annotations.Property;
alshabib1cc04f72014-09-16 16:09:58 -070029import org.apache.felix.scr.annotations.Reference;
30import org.apache.felix.scr.annotations.ReferenceCardinality;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070031import org.onosproject.cfg.ComponentConfigService;
Brian O'Connorabafb502014-12-02 22:26:20 -080032import org.onosproject.core.ApplicationId;
33import org.onosproject.net.DeviceId;
Brian O'Connorabafb502014-12-02 22:26:20 -080034import org.onosproject.net.flow.CompletedBatchOperation;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.net.flow.FlowEntry;
36import org.onosproject.net.flow.FlowRule;
37import org.onosproject.net.flow.FlowRuleBatchEntry;
Brian O'Connor72cb19a2015-01-16 16:14:41 -080038import org.onosproject.net.flow.FlowRuleBatchOperation;
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -070039import org.onosproject.net.flow.FlowRuleExtPayLoad;
Brian O'Connorabafb502014-12-02 22:26:20 -080040import org.onosproject.net.flow.FlowRuleProvider;
41import org.onosproject.net.flow.FlowRuleProviderRegistry;
42import org.onosproject.net.flow.FlowRuleProviderService;
43import org.onosproject.net.provider.AbstractProvider;
44import org.onosproject.net.provider.ProviderId;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070045import org.onosproject.net.statistic.DefaultLoad;
Brian O'Connorabafb502014-12-02 22:26:20 -080046import org.onosproject.openflow.controller.Dpid;
47import org.onosproject.openflow.controller.OpenFlowController;
48import org.onosproject.openflow.controller.OpenFlowEventListener;
49import org.onosproject.openflow.controller.OpenFlowSwitch;
50import org.onosproject.openflow.controller.OpenFlowSwitchListener;
51import org.onosproject.openflow.controller.RoleState;
jcc3d4e14a2015-04-21 11:32:05 +080052import org.onosproject.openflow.controller.ThirdPartyMessage;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070053import org.osgi.service.component.ComponentContext;
Thomas Vachuska3358af22015-05-19 18:40:34 -070054import org.projectfloodlight.openflow.protocol.OFBadRequestCode;
alshabib902d41b2014-10-07 16:52:05 -070055import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
56import org.projectfloodlight.openflow.protocol.OFErrorMsg;
Brian O'Connor72cb19a2015-01-16 16:14:41 -080057import org.projectfloodlight.openflow.protocol.OFErrorType;
alshabib193525b2014-10-08 18:58:03 -070058import org.projectfloodlight.openflow.protocol.OFFlowMod;
alshabib8f1cf4a2014-09-17 14:44:48 -070059import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
alshabib5c370ff2014-09-18 10:12:14 -070060import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
alshabib8f1cf4a2014-09-17 14:44:48 -070061import org.projectfloodlight.openflow.protocol.OFMessage;
62import org.projectfloodlight.openflow.protocol.OFPortStatus;
alshabib5c370ff2014-09-18 10:12:14 -070063import org.projectfloodlight.openflow.protocol.OFStatsReply;
sangho89bf6fb2015-02-09 09:33:13 -080064import org.projectfloodlight.openflow.protocol.OFStatsType;
Thomas Vachuska3358af22015-05-19 18:40:34 -070065import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
alshabib193525b2014-10-08 18:58:03 -070066import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
alshabib1cc04f72014-09-16 16:09:58 -070067import org.slf4j.Logger;
68
Thomas Vachuska75aaa672015-04-29 12:24:43 -070069import java.util.Collections;
70import java.util.Dictionary;
71import java.util.List;
72import java.util.Map;
73import java.util.Optional;
74import java.util.Set;
75import java.util.Timer;
76import java.util.concurrent.TimeUnit;
77import java.util.stream.Collectors;
78
ssyoon9030fbcd92015-08-17 10:42:07 +090079import static com.google.common.base.Preconditions.checkNotNull;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070080import static com.google.common.base.Strings.isNullOrEmpty;
81import static org.onlab.util.Tools.get;
82import static org.slf4j.LoggerFactory.getLogger;
alshabibeec3a062014-09-17 18:01:26 -070083
alshabib1cc04f72014-09-16 16:09:58 -070084/**
jcc3d4e14a2015-04-21 11:32:05 +080085 * Provider which uses an OpenFlow controller to detect network end-station
86 * hosts.
alshabib1cc04f72014-09-16 16:09:58 -070087 */
88@Component(immediate = true)
jcc3d4e14a2015-04-21 11:32:05 +080089public class OpenFlowRuleProvider extends AbstractProvider
90 implements FlowRuleProvider {
alshabib1cc04f72014-09-16 16:09:58 -070091
92 private final Logger log = getLogger(getClass());
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected FlowRuleProviderRegistry providerRegistry;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected OpenFlowController controller;
99
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected ComponentConfigService cfgService;
102
ssyoon9030fbcd92015-08-17 10:42:07 +0900103 private static final int DEFAULT_POLL_FREQUENCY = 5;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700104 @Property(name = "flowPollFrequency", intValue = DEFAULT_POLL_FREQUENCY,
105 label = "Frequency (in seconds) for polling flow statistics")
106 private int flowPollFrequency = DEFAULT_POLL_FREQUENCY;
107
ssyoon9030fbcd92015-08-17 10:42:07 +0900108 private static final boolean DEFAULT_ADAPTIVE_FLOW_SAMPLING = true;
109 @Property(name = "adaptiveFlowSampling", boolValue = DEFAULT_ADAPTIVE_FLOW_SAMPLING,
110 label = "Adaptive Flow Sampling is on or off")
111 private boolean adaptiveFlowSampling = DEFAULT_ADAPTIVE_FLOW_SAMPLING;
112
alshabib1cc04f72014-09-16 16:09:58 -0700113 private FlowRuleProviderService providerService;
114
alshabibeec3a062014-09-17 18:01:26 -0700115 private final InternalFlowProvider listener = new InternalFlowProvider();
116
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800117 private Cache<Long, InternalCacheEntry> pendingBatches;
alshabib193525b2014-10-08 18:58:03 -0700118
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700119 private final Timer timer = new Timer("onos-openflow-collector");
ssyoon9030fbcd92015-08-17 10:42:07 +0900120 private final Map<Dpid, FlowStatsCollector> simpleCollectors = Maps.newHashMap();
121
122 // NewAdaptiveFlowStatsCollector Set
123 private final Map<Dpid, NewAdaptiveFlowStatsCollector> afsCollectors = Maps.newHashMap();
alshabib3d643ec2014-10-22 18:33:00 -0700124
alshabib1cc04f72014-09-16 16:09:58 -0700125 /**
126 * Creates an OpenFlow host provider.
127 */
128 public OpenFlowRuleProvider() {
Brian O'Connorabafb502014-12-02 22:26:20 -0800129 super(new ProviderId("of", "org.onosproject.provider.openflow"));
alshabib1cc04f72014-09-16 16:09:58 -0700130 }
131
132 @Activate
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700133 public void activate(ComponentContext context) {
134 cfgService.registerProperties(getClass());
alshabib1cc04f72014-09-16 16:09:58 -0700135 providerService = providerRegistry.register(this);
alshabibeec3a062014-09-17 18:01:26 -0700136 controller.addListener(listener);
137 controller.addEventListener(listener);
alshabib3d643ec2014-10-22 18:33:00 -0700138
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700139 pendingBatches = createBatchCache();
ssyoon9030fbcd92015-08-17 10:42:07 +0900140
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700141 createCollectors();
alshabib3d643ec2014-10-22 18:33:00 -0700142
ssyoon9030fbcd92015-08-17 10:42:07 +0900143 log.info("Started with flowPollFrequency = {}, adaptiveFlowSampling = {}",
144 flowPollFrequency, adaptiveFlowSampling);
alshabib1cc04f72014-09-16 16:09:58 -0700145 }
146
147 @Deactivate
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700148 public void deactivate(ComponentContext context) {
149 cfgService.unregisterProperties(getClass(), false);
150 stopCollectors();
alshabib1cc04f72014-09-16 16:09:58 -0700151 providerRegistry.unregister(this);
152 providerService = null;
153
154 log.info("Stopped");
155 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800156
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700157 @Modified
158 public void modified(ComponentContext context) {
159 Dictionary<?, ?> properties = context.getProperties();
160 int newFlowPollFrequency;
161 try {
162 String s = get(properties, "flowPollFrequency");
163 newFlowPollFrequency = isNullOrEmpty(s) ? flowPollFrequency : Integer.parseInt(s.trim());
164
165 } catch (NumberFormatException | ClassCastException e) {
166 newFlowPollFrequency = flowPollFrequency;
167 }
168
169 if (newFlowPollFrequency != flowPollFrequency) {
170 flowPollFrequency = newFlowPollFrequency;
171 adjustRate();
172 }
173
174 log.info("Settings: flowPollFrequency={}", flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900175
176 boolean newAdaptiveFlowSampling;
177 String s = get(properties, "adaptiveFlowSampling");
178 newAdaptiveFlowSampling = isNullOrEmpty(s) ? adaptiveFlowSampling : Boolean.parseBoolean(s.trim());
179
180 if (newAdaptiveFlowSampling != adaptiveFlowSampling) {
181 // stop previous collector
182 stopCollectors();
183 adaptiveFlowSampling = newAdaptiveFlowSampling;
184 // create new collectors
185 createCollectors();
186 }
187
188 log.info("Settings: adaptiveFlowSampling={}", adaptiveFlowSampling);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700189 }
190
191 private Cache<Long, InternalCacheEntry> createBatchCache() {
192 return CacheBuilder.newBuilder()
193 .expireAfterWrite(10, TimeUnit.SECONDS)
194 .removalListener((RemovalNotification<Long, InternalCacheEntry> notification) -> {
195 if (notification.getCause() == RemovalCause.EXPIRED) {
196 providerService.batchOperationCompleted(notification.getKey(),
197 notification.getValue().failedCompletion());
198 }
199 }).build();
200 }
201
202 private void createCollectors() {
203 controller.getSwitches().forEach(this::createCollector);
204 }
205
206 private void createCollector(OpenFlowSwitch sw) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900207 if (adaptiveFlowSampling) {
208 // NewAdaptiveFlowStatsCollector Constructor
209 NewAdaptiveFlowStatsCollector fsc = new NewAdaptiveFlowStatsCollector(sw, flowPollFrequency);
210 fsc.start();
211 afsCollectors.put(new Dpid(sw.getId()), fsc);
212 } else {
213 FlowStatsCollector fsc = new FlowStatsCollector(timer, sw, flowPollFrequency);
214 fsc.start();
215 simpleCollectors.put(new Dpid(sw.getId()), fsc);
216 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700217 }
218
219 private void stopCollectors() {
ssyoon9030fbcd92015-08-17 10:42:07 +0900220 if (adaptiveFlowSampling) {
221 // NewAdaptiveFlowStatsCollector Destructor
222 afsCollectors.values().forEach(NewAdaptiveFlowStatsCollector::stop);
223 afsCollectors.clear();
224 } else {
225 simpleCollectors.values().forEach(FlowStatsCollector::stop);
226 simpleCollectors.clear();
227 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700228 }
229
230 private void adjustRate() {
231 DefaultLoad.setPollInterval(flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900232
233 if (adaptiveFlowSampling) {
234 // NewAdaptiveFlowStatsCollector calAndPollInterval
235 afsCollectors.values().forEach(fsc -> fsc.adjustCalAndPollInterval(flowPollFrequency));
236 } else {
237 simpleCollectors.values().forEach(fsc -> fsc.adjustPollInterval(flowPollFrequency));
238 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700239 }
240
alshabib1cc04f72014-09-16 16:09:58 -0700241 @Override
242 public void applyFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800243 for (FlowRule flowRule : flowRules) {
244 applyRule(flowRule);
alshabib35edb1a2014-09-16 17:44:44 -0700245 }
alshabib1cc04f72014-09-16 16:09:58 -0700246 }
247
alshabib35edb1a2014-09-16 17:44:44 -0700248 private void applyRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900249 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
250 OpenFlowSwitch sw = controller.getSwitch(dpid);
251
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700252 FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
253 if (hasPayload(flowRuleExtPayLoad)) {
254 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800255 sw.sendMsg(msg);
256 return;
257 }
alshabibbdcbb102015-04-22 14:16:38 -0700258 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
jcc3d4e14a2015-04-21 11:32:05 +0800259 Optional.empty()).buildFlowAdd());
ssyoon9030fbcd92015-08-17 10:42:07 +0900260
261 if (adaptiveFlowSampling) {
262 // Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
263 afsCollectors.get(dpid).addWithFlowRule(flowRule);
264 }
alshabib35edb1a2014-09-16 17:44:44 -0700265 }
266
alshabib1cc04f72014-09-16 16:09:58 -0700267 @Override
268 public void removeFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800269 for (FlowRule flowRule : flowRules) {
270 removeRule(flowRule);
alshabib219ebaa2014-09-22 15:41:24 -0700271 }
alshabib1cc04f72014-09-16 16:09:58 -0700272 }
273
alshabib219ebaa2014-09-22 15:41:24 -0700274 private void removeRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900275 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
276 OpenFlowSwitch sw = controller.getSwitch(dpid);
277
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700278 FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
279 if (hasPayload(flowRuleExtPayLoad)) {
280 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800281 sw.sendMsg(msg);
282 return;
283 }
alshabibbdcbb102015-04-22 14:16:38 -0700284 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
jcc3d4e14a2015-04-21 11:32:05 +0800285 Optional.empty()).buildFlowDel());
ssyoon9030fbcd92015-08-17 10:42:07 +0900286
287 if (adaptiveFlowSampling) {
288 // Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
289 afsCollectors.get(dpid).removeFlows(flowRule);
290 }
alshabib219ebaa2014-09-22 15:41:24 -0700291 }
292
alshabiba68eb962014-09-24 20:34:13 -0700293 @Override
294 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
295 // TODO: optimize using the ApplicationId
296 removeFlowRule(flowRules);
297 }
298
alshabib193525b2014-10-08 18:58:03 -0700299 @Override
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800300 public void executeBatch(FlowRuleBatchOperation batch) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900301 checkNotNull(batch);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800302
303 pendingBatches.put(batch.id(), new InternalCacheEntry(batch));
304
ssyoon9030fbcd92015-08-17 10:42:07 +0900305 Dpid dpid = Dpid.dpid(batch.deviceId().uri());
306 OpenFlowSwitch sw = controller.getSwitch(dpid);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800307 OFFlowMod mod;
alshabib193525b2014-10-08 18:58:03 -0700308 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
jcc3d4e14a2015-04-21 11:32:05 +0800309 // flow is the third party privacy flow
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700310
311 FlowRuleExtPayLoad flowRuleExtPayLoad = fbe.target().payLoad();
312 if (hasPayload(flowRuleExtPayLoad)) {
313 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800314 sw.sendMsg(msg);
315 continue;
316 }
317 FlowModBuilder builder = FlowModBuilder.builder(fbe.target(), sw
318 .factory(), Optional.of(batch.id()));
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800319 switch (fbe.operator()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700320 case ADD:
321 mod = builder.buildFlowAdd();
ssyoon9030fbcd92015-08-17 10:42:07 +0900322
323 if (adaptiveFlowSampling) {
324 // Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
325 afsCollectors.get(dpid).addWithFlowRule(fbe.target());
326 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700327 break;
328 case REMOVE:
329 mod = builder.buildFlowDel();
ssyoon9030fbcd92015-08-17 10:42:07 +0900330
331 if (adaptiveFlowSampling) {
332 // Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
333 afsCollectors.get(dpid).removeFlows(fbe.target());
334 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700335 break;
336 case MODIFY:
337 mod = builder.buildFlowMod();
ssyoon9030fbcd92015-08-17 10:42:07 +0900338
339 if (adaptiveFlowSampling) {
340 // Add or Update TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
341 // afsCollectors.get(dpid).addWithFlowRule(fbe.target()); //check if add is good or not
342 afsCollectors.get(dpid).addOrUpdateFlows((FlowEntry) fbe.target());
343 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700344 break;
345 default:
346 log.error("Unsupported batch operation {}; skipping flowmod {}",
ssyoon9030fbcd92015-08-17 10:42:07 +0900347 fbe.operator(), fbe);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700348 continue;
jcc3d4e14a2015-04-21 11:32:05 +0800349 }
Saurav Das3ea46622015-04-22 14:01:34 -0700350 sw.sendMsg(mod);
alshabib193525b2014-10-08 18:58:03 -0700351 }
jcc3d4e14a2015-04-21 11:32:05 +0800352 OFBarrierRequest.Builder builder = sw.factory().buildBarrierRequest()
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800353 .setXid(batch.id());
354 sw.sendMsg(builder.build());
alshabib193525b2014-10-08 18:58:03 -0700355 }
356
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700357 private boolean hasPayload(FlowRuleExtPayLoad flowRuleExtPayLoad) {
358 return flowRuleExtPayLoad != null &&
359 flowRuleExtPayLoad.payLoad() != null &&
360 flowRuleExtPayLoad.payLoad().length > 0;
361 }
362
alshabib8f1cf4a2014-09-17 14:44:48 -0700363 private class InternalFlowProvider
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800364 implements OpenFlowSwitchListener, OpenFlowEventListener {
alshabib8f1cf4a2014-09-17 14:44:48 -0700365
alshabib8f1cf4a2014-09-17 14:44:48 -0700366 @Override
367 public void switchAdded(Dpid dpid) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900368
369 OpenFlowSwitch sw = controller.getSwitch(dpid);
370
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700371 createCollector(controller.getSwitch(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700372 }
373
374 @Override
375 public void switchRemoved(Dpid dpid) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900376 if (adaptiveFlowSampling) {
377 NewAdaptiveFlowStatsCollector collector = afsCollectors.remove(dpid);
378 if (collector != null) {
379 collector.stop();
380 }
381 } else {
382 FlowStatsCollector collector = simpleCollectors.remove(dpid);
383 if (collector != null) {
384 collector.stop();
385 }
alshabibdfc7afb2014-10-21 20:13:27 -0700386 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700387 }
388
389 @Override
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700390 public void switchChanged(Dpid dpid) {
391 }
392
393 @Override
alshabib8f1cf4a2014-09-17 14:44:48 -0700394 public void portChanged(Dpid dpid, OFPortStatus status) {
jcc3d4e14a2015-04-21 11:32:05 +0800395 // TODO: Decide whether to evict flows internal store.
alshabib8f1cf4a2014-09-17 14:44:48 -0700396 }
397
398 @Override
399 public void handleMessage(Dpid dpid, OFMessage msg) {
alshabibda1644e2015-03-13 14:01:35 -0700400 OpenFlowSwitch sw = controller.getSwitch(dpid);
alshabib8f1cf4a2014-09-17 14:44:48 -0700401 switch (msg.getType()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700402 case FLOW_REMOVED:
403 OFFlowRemoved removed = (OFFlowRemoved) msg;
alshabib6b5cfec2014-09-18 17:42:18 -0700404
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700405 FlowEntry fr = new FlowEntryBuilder(dpid, removed).build();
406 providerService.flowRemoved(fr);
ssyoon9030fbcd92015-08-17 10:42:07 +0900407
408 if (adaptiveFlowSampling) {
409 // Removed TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
410 afsCollectors.get(dpid).flowRemoved(fr);
411 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700412 break;
413 case STATS_REPLY:
414 if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW) {
415 pushFlowMetrics(dpid, (OFFlowStatsReply) msg);
sangho89bf6fb2015-02-09 09:33:13 -0800416 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700417 break;
418 case BARRIER_REPLY:
419 try {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700420 InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800421 if (entry != null) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700422 providerService
423 .batchOperationCompleted(msg.getXid(),
424 entry.completed());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800425 } else {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700426 log.warn("Received unknown Barrier Reply: {}",
427 msg.getXid());
428 }
429 } finally {
430 pendingBatches.invalidate(msg.getXid());
431 }
432 break;
433 case ERROR:
Thomas Vachuska3358af22015-05-19 18:40:34 -0700434 // TODO: This needs to get suppressed in a better way.
435 if (msg instanceof OFBadRequestErrorMsg &&
436 ((OFBadRequestErrorMsg) msg).getCode() == OFBadRequestCode.BAD_TYPE) {
437 log.debug("Received error message {} from {}", msg, dpid);
438 } else {
439 log.warn("Received error message {} from {}", msg, dpid);
440 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700441
442 OFErrorMsg error = (OFErrorMsg) msg;
443 if (error.getErrType() == OFErrorType.FLOW_MOD_FAILED) {
444 OFFlowModFailedErrorMsg fmFailed = (OFFlowModFailedErrorMsg) error;
445 if (fmFailed.getData().getParsedMessage().isPresent()) {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700446 OFMessage m = fmFailed.getData().getParsedMessage().get();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700447 OFFlowMod fm = (OFFlowMod) m;
Thomas Vachuska3358af22015-05-19 18:40:34 -0700448 InternalCacheEntry entry =
449 pendingBatches.getIfPresent(msg.getXid());
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700450 if (entry != null) {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700451 entry.appendFailure(new FlowEntryBuilder(dpid, fm).build());
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700452 } else {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700453 log.error("No matching batch for this error: {}", error);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700454 }
455 } else {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700456 // FIXME: Potentially add flowtracking to avoid this message.
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700457 log.error("Flow installation failed but switch didn't"
458 + " tell us which one.");
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800459 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800460 }
ssyoon9030fbcd92015-08-17 10:42:07 +0900461
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700462 default:
463 log.debug("Unhandled message type: {}", msg.getType());
alshabib8f1cf4a2014-09-17 14:44:48 -0700464 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700465 }
466
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700467 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700468 public void receivedRoleReply(Dpid dpid, RoleState requested,
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800469 RoleState response) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700470 // Do nothing here for now.
471 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700472
sangho89bf6fb2015-02-09 09:33:13 -0800473 private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies) {
alshabib64def642014-12-02 23:27:37 -0800474
alshabib54ce5892014-09-23 17:50:51 -0700475 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
Saurav Dasfa2fa932015-03-03 11:29:48 -0800476 OpenFlowSwitch sw = controller.getSwitch(dpid);
alshabib54ce5892014-09-23 17:50:51 -0700477
alshabib64def642014-12-02 23:27:37 -0800478 List<FlowEntry> flowEntries = replies.getEntries().stream()
alshabibbdcbb102015-04-22 14:16:38 -0700479 .map(entry -> new FlowEntryBuilder(dpid, entry).build())
alshabib64def642014-12-02 23:27:37 -0800480 .collect(Collectors.toList());
alshabib54ce5892014-09-23 17:50:51 -0700481
ssyoon9030fbcd92015-08-17 10:42:07 +0900482 if (adaptiveFlowSampling) {
483 NewAdaptiveFlowStatsCollector afsc = afsCollectors.get(dpid);
484
485 synchronized (afsc) {
486 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
487 log.debug("OpenFlowRuleProvider:pushFlowMetrics, flowMissingXid={}, "
488 + "OFFlowStatsReply Xid={}, for {}",
489 afsc.getFlowMissingXid(), replies.getXid(), dpid);
490 }
491
492 // Check that OFFlowStatsReply Xid is same with the one of OFFlowStatsRequest?
493 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
494 if (afsc.getFlowMissingXid() == replies.getXid()) {
495 // call entire flow stats update with flowMissing synchronization.
496 // used existing pushFlowMetrics
497 providerService.pushFlowMetrics(did, flowEntries);
498 }
499 // reset flowMissingXid to NO_FLOW_MISSING_XID
500 afsc.setFlowMissingXid(NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID);
501
502 } else {
503 // call individual flow stats update
504 providerService.pushFlowMetricsWithoutFlowMissing(did, flowEntries);
505 }
506
507 // Update TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
508 afsc.pushFlowMetrics(flowEntries);
509 }
510 } else {
511 // call existing entire flow stats update with flowMissing synchronization
512 providerService.pushFlowMetrics(did, flowEntries);
513 }
alshabib5c370ff2014-09-18 10:12:14 -0700514 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700515 }
alshabib1cc04f72014-09-16 16:09:58 -0700516
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800517 /**
jcc3d4e14a2015-04-21 11:32:05 +0800518 * The internal cache entry holding the original request as well as
519 * accumulating the any failures along the way.
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700520 * <p/>
jcc3d4e14a2015-04-21 11:32:05 +0800521 * If this entry is evicted from the cache then the entire operation is
522 * considered failed. Otherwise, only the failures reported by the device
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800523 * will be propagated up.
524 */
525 private class InternalCacheEntry {
alshabib902d41b2014-10-07 16:52:05 -0700526
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800527 private final FlowRuleBatchOperation operation;
528 private final Set<FlowRule> failures = Sets.newConcurrentHashSet();
alshabib193525b2014-10-08 18:58:03 -0700529
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800530 public InternalCacheEntry(FlowRuleBatchOperation operation) {
531 this.operation = operation;
alshabib902d41b2014-10-07 16:52:05 -0700532 }
533
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800534 /**
535 * Appends a failed rule to the set of failed items.
jcc3d4e14a2015-04-21 11:32:05 +0800536 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800537 * @param rule the failed rule
538 */
539 public void appendFailure(FlowRule rule) {
540 failures.add(rule);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800541 }
542
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800543 /**
544 * Fails the entire batch and returns the failed operation.
jcc3d4e14a2015-04-21 11:32:05 +0800545 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800546 * @return the failed operation
547 */
548 public CompletedBatchOperation failedCompletion() {
549 Set<FlowRule> fails = operation.getOperations().stream()
550 .map(op -> op.target()).collect(Collectors.toSet());
jcc3d4e14a2015-04-21 11:32:05 +0800551 return new CompletedBatchOperation(false,
552 Collections
553 .unmodifiableSet(fails),
554 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700555 }
556
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800557 /**
558 * Returns the completed operation and whether the batch suceeded.
jcc3d4e14a2015-04-21 11:32:05 +0800559 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800560 * @return the completed operation
561 */
562 public CompletedBatchOperation completed() {
jcc3d4e14a2015-04-21 11:32:05 +0800563 return new CompletedBatchOperation(
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700564 failures.isEmpty(),
565 Collections
566 .unmodifiableSet(failures),
567 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700568 }
alshabib902d41b2014-10-07 16:52:05 -0700569 }
alshabiba68eb962014-09-24 20:34:13 -0700570
alshabib1cc04f72014-09-16 16:09:58 -0700571}