blob: b760168dcc0e0686408bcbd7b45b62d0939771bd [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present 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;
Jonathan Hart3c259162015-10-21 21:31:19 -070034import org.onosproject.net.driver.DriverService;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.net.flow.CompletedBatchOperation;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070036import org.onosproject.net.flow.DefaultTableStatisticsEntry;
Brian O'Connorabafb502014-12-02 22:26:20 -080037import org.onosproject.net.flow.FlowEntry;
38import org.onosproject.net.flow.FlowRule;
39import org.onosproject.net.flow.FlowRuleBatchEntry;
Brian O'Connor72cb19a2015-01-16 16:14:41 -080040import org.onosproject.net.flow.FlowRuleBatchOperation;
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -070041import org.onosproject.net.flow.FlowRuleExtPayLoad;
Brian O'Connorabafb502014-12-02 22:26:20 -080042import org.onosproject.net.flow.FlowRuleProvider;
43import org.onosproject.net.flow.FlowRuleProviderRegistry;
44import org.onosproject.net.flow.FlowRuleProviderService;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070045import org.onosproject.net.flow.TableStatisticsEntry;
Brian O'Connorabafb502014-12-02 22:26:20 -080046import org.onosproject.net.provider.AbstractProvider;
47import org.onosproject.net.provider.ProviderId;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070048import org.onosproject.net.statistic.DefaultLoad;
Brian O'Connorabafb502014-12-02 22:26:20 -080049import org.onosproject.openflow.controller.Dpid;
50import org.onosproject.openflow.controller.OpenFlowController;
51import org.onosproject.openflow.controller.OpenFlowEventListener;
52import org.onosproject.openflow.controller.OpenFlowSwitch;
53import org.onosproject.openflow.controller.OpenFlowSwitchListener;
54import org.onosproject.openflow.controller.RoleState;
jcc3d4e14a2015-04-21 11:32:05 +080055import org.onosproject.openflow.controller.ThirdPartyMessage;
Thomas Vachuska95caba32016-04-04 10:42:05 -070056import org.onosproject.provider.of.flow.util.FlowEntryBuilder;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070057import org.osgi.service.component.ComponentContext;
Thomas Vachuska3358af22015-05-19 18:40:34 -070058import org.projectfloodlight.openflow.protocol.OFBadRequestCode;
alshabib902d41b2014-10-07 16:52:05 -070059import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
60import org.projectfloodlight.openflow.protocol.OFErrorMsg;
Brian O'Connor72cb19a2015-01-16 16:14:41 -080061import org.projectfloodlight.openflow.protocol.OFErrorType;
alshabib193525b2014-10-08 18:58:03 -070062import org.projectfloodlight.openflow.protocol.OFFlowMod;
alshabib8f1cf4a2014-09-17 14:44:48 -070063import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
alshabib5c370ff2014-09-18 10:12:14 -070064import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
alshabib8f1cf4a2014-09-17 14:44:48 -070065import org.projectfloodlight.openflow.protocol.OFMessage;
66import org.projectfloodlight.openflow.protocol.OFPortStatus;
alshabib5c370ff2014-09-18 10:12:14 -070067import org.projectfloodlight.openflow.protocol.OFStatsReply;
sangho89bf6fb2015-02-09 09:33:13 -080068import org.projectfloodlight.openflow.protocol.OFStatsType;
Jonathan Hart3c259162015-10-21 21:31:19 -070069import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
70import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
Thomas Vachuska3358af22015-05-19 18:40:34 -070071import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
alshabib193525b2014-10-08 18:58:03 -070072import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
alshabib1cc04f72014-09-16 16:09:58 -070073import org.slf4j.Logger;
74
Thomas Vachuska75aaa672015-04-29 12:24:43 -070075import java.util.Collections;
76import java.util.Dictionary;
77import java.util.List;
78import java.util.Map;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070079import java.util.Objects;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070080import java.util.Optional;
81import java.util.Set;
82import java.util.Timer;
83import java.util.concurrent.TimeUnit;
84import java.util.stream.Collectors;
85
ssyoon9030fbcd92015-08-17 10:42:07 +090086import static com.google.common.base.Preconditions.checkNotNull;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070087import static com.google.common.base.Strings.isNullOrEmpty;
88import static org.onlab.util.Tools.get;
89import static org.slf4j.LoggerFactory.getLogger;
alshabibeec3a062014-09-17 18:01:26 -070090
alshabib1cc04f72014-09-16 16:09:58 -070091/**
jcc3d4e14a2015-04-21 11:32:05 +080092 * Provider which uses an OpenFlow controller to detect network end-station
93 * hosts.
alshabib1cc04f72014-09-16 16:09:58 -070094 */
95@Component(immediate = true)
jcc3d4e14a2015-04-21 11:32:05 +080096public class OpenFlowRuleProvider extends AbstractProvider
97 implements FlowRuleProvider {
alshabib1cc04f72014-09-16 16:09:58 -070098
99 private final Logger log = getLogger(getClass());
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 protected FlowRuleProviderRegistry providerRegistry;
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected OpenFlowController controller;
106
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected ComponentConfigService cfgService;
109
Jonathan Hart3c259162015-10-21 21:31:19 -0700110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected DriverService driverService;
112
ssyoon9030fbcd92015-08-17 10:42:07 +0900113 private static final int DEFAULT_POLL_FREQUENCY = 5;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700114 @Property(name = "flowPollFrequency", intValue = DEFAULT_POLL_FREQUENCY,
115 label = "Frequency (in seconds) for polling flow statistics")
116 private int flowPollFrequency = DEFAULT_POLL_FREQUENCY;
117
ssyoon9030fbcd92015-08-17 10:42:07 +0900118 private static final boolean DEFAULT_ADAPTIVE_FLOW_SAMPLING = true;
119 @Property(name = "adaptiveFlowSampling", boolValue = DEFAULT_ADAPTIVE_FLOW_SAMPLING,
120 label = "Adaptive Flow Sampling is on or off")
121 private boolean adaptiveFlowSampling = DEFAULT_ADAPTIVE_FLOW_SAMPLING;
122
alshabib1cc04f72014-09-16 16:09:58 -0700123 private FlowRuleProviderService providerService;
124
alshabibeec3a062014-09-17 18:01:26 -0700125 private final InternalFlowProvider listener = new InternalFlowProvider();
126
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800127 private Cache<Long, InternalCacheEntry> pendingBatches;
alshabib193525b2014-10-08 18:58:03 -0700128
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700129 private final Timer timer = new Timer("onos-openflow-collector");
ssyoon9030fbcd92015-08-17 10:42:07 +0900130 private final Map<Dpid, FlowStatsCollector> simpleCollectors = Maps.newHashMap();
131
132 // NewAdaptiveFlowStatsCollector Set
133 private final Map<Dpid, NewAdaptiveFlowStatsCollector> afsCollectors = Maps.newHashMap();
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700134 private final Map<Dpid, FlowStatsCollector> collectors = Maps.newHashMap();
135 private final Map<Dpid, TableStatisticsCollector> tableStatsCollectors = Maps.newHashMap();
alshabib3d643ec2014-10-22 18:33:00 -0700136
alshabib1cc04f72014-09-16 16:09:58 -0700137 /**
138 * Creates an OpenFlow host provider.
139 */
140 public OpenFlowRuleProvider() {
Brian O'Connorabafb502014-12-02 22:26:20 -0800141 super(new ProviderId("of", "org.onosproject.provider.openflow"));
alshabib1cc04f72014-09-16 16:09:58 -0700142 }
143
144 @Activate
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700145 public void activate(ComponentContext context) {
146 cfgService.registerProperties(getClass());
alshabib1cc04f72014-09-16 16:09:58 -0700147 providerService = providerRegistry.register(this);
alshabibeec3a062014-09-17 18:01:26 -0700148 controller.addListener(listener);
149 controller.addEventListener(listener);
alshabib3d643ec2014-10-22 18:33:00 -0700150
Antonio Marsico1c5ae1f2015-12-15 15:31:56 +0100151 modified(context);
152
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700153 pendingBatches = createBatchCache();
ssyoon9030fbcd92015-08-17 10:42:07 +0900154
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700155 createCollectors();
alshabib3d643ec2014-10-22 18:33:00 -0700156
ssyoon9030fbcd92015-08-17 10:42:07 +0900157 log.info("Started with flowPollFrequency = {}, adaptiveFlowSampling = {}",
158 flowPollFrequency, adaptiveFlowSampling);
alshabib1cc04f72014-09-16 16:09:58 -0700159 }
160
161 @Deactivate
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700162 public void deactivate(ComponentContext context) {
163 cfgService.unregisterProperties(getClass(), false);
164 stopCollectors();
alshabib1cc04f72014-09-16 16:09:58 -0700165 providerRegistry.unregister(this);
166 providerService = null;
167
168 log.info("Stopped");
169 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800170
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700171 @Modified
172 public void modified(ComponentContext context) {
173 Dictionary<?, ?> properties = context.getProperties();
174 int newFlowPollFrequency;
175 try {
176 String s = get(properties, "flowPollFrequency");
177 newFlowPollFrequency = isNullOrEmpty(s) ? flowPollFrequency : Integer.parseInt(s.trim());
178
179 } catch (NumberFormatException | ClassCastException e) {
180 newFlowPollFrequency = flowPollFrequency;
181 }
182
183 if (newFlowPollFrequency != flowPollFrequency) {
184 flowPollFrequency = newFlowPollFrequency;
185 adjustRate();
186 }
187
188 log.info("Settings: flowPollFrequency={}", flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900189
190 boolean newAdaptiveFlowSampling;
191 String s = get(properties, "adaptiveFlowSampling");
192 newAdaptiveFlowSampling = isNullOrEmpty(s) ? adaptiveFlowSampling : Boolean.parseBoolean(s.trim());
193
194 if (newAdaptiveFlowSampling != adaptiveFlowSampling) {
195 // stop previous collector
196 stopCollectors();
197 adaptiveFlowSampling = newAdaptiveFlowSampling;
198 // create new collectors
199 createCollectors();
200 }
201
202 log.info("Settings: adaptiveFlowSampling={}", adaptiveFlowSampling);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700203 }
204
205 private Cache<Long, InternalCacheEntry> createBatchCache() {
206 return CacheBuilder.newBuilder()
207 .expireAfterWrite(10, TimeUnit.SECONDS)
208 .removalListener((RemovalNotification<Long, InternalCacheEntry> notification) -> {
209 if (notification.getCause() == RemovalCause.EXPIRED) {
210 providerService.batchOperationCompleted(notification.getKey(),
211 notification.getValue().failedCompletion());
212 }
213 }).build();
214 }
215
216 private void createCollectors() {
217 controller.getSwitches().forEach(this::createCollector);
218 }
219
220 private void createCollector(OpenFlowSwitch sw) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900221 if (adaptiveFlowSampling) {
222 // NewAdaptiveFlowStatsCollector Constructor
Charles Chan14967c22015-12-07 11:11:50 -0800223 NewAdaptiveFlowStatsCollector fsc =
224 new NewAdaptiveFlowStatsCollector(driverService, sw, flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900225 fsc.start();
226 afsCollectors.put(new Dpid(sw.getId()), fsc);
227 } else {
228 FlowStatsCollector fsc = new FlowStatsCollector(timer, sw, flowPollFrequency);
229 fsc.start();
230 simpleCollectors.put(new Dpid(sw.getId()), fsc);
231 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700232 TableStatisticsCollector tsc = new TableStatisticsCollector(timer, sw, flowPollFrequency);
233 tsc.start();
234 tableStatsCollectors.put(new Dpid(sw.getId()), tsc);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700235 }
236
237 private void stopCollectors() {
ssyoon9030fbcd92015-08-17 10:42:07 +0900238 if (adaptiveFlowSampling) {
239 // NewAdaptiveFlowStatsCollector Destructor
240 afsCollectors.values().forEach(NewAdaptiveFlowStatsCollector::stop);
241 afsCollectors.clear();
242 } else {
243 simpleCollectors.values().forEach(FlowStatsCollector::stop);
244 simpleCollectors.clear();
245 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700246 tableStatsCollectors.values().forEach(TableStatisticsCollector::stop);
247 tableStatsCollectors.clear();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700248 }
249
250 private void adjustRate() {
251 DefaultLoad.setPollInterval(flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900252 if (adaptiveFlowSampling) {
253 // NewAdaptiveFlowStatsCollector calAndPollInterval
254 afsCollectors.values().forEach(fsc -> fsc.adjustCalAndPollInterval(flowPollFrequency));
255 } else {
256 simpleCollectors.values().forEach(fsc -> fsc.adjustPollInterval(flowPollFrequency));
257 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700258 tableStatsCollectors.values().forEach(tsc -> tsc.adjustPollInterval(flowPollFrequency));
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700259 }
260
alshabib1cc04f72014-09-16 16:09:58 -0700261 @Override
262 public void applyFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800263 for (FlowRule flowRule : flowRules) {
264 applyRule(flowRule);
alshabib35edb1a2014-09-16 17:44:44 -0700265 }
alshabib1cc04f72014-09-16 16:09:58 -0700266 }
267
alshabib35edb1a2014-09-16 17:44:44 -0700268 private void applyRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900269 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
270 OpenFlowSwitch sw = controller.getSwitch(dpid);
271
Ray Milkey0ae473d2016-04-04 10:56:47 -0700272 if (sw == null) {
273 return;
274 }
275
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700276 FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
277 if (hasPayload(flowRuleExtPayLoad)) {
278 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800279 sw.sendMsg(msg);
280 return;
281 }
alshabibbdcbb102015-04-22 14:16:38 -0700282 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Jonathan Hart3c259162015-10-21 21:31:19 -0700283 Optional.empty(), Optional.of(driverService)).buildFlowAdd());
ssyoon9030fbcd92015-08-17 10:42:07 +0900284
285 if (adaptiveFlowSampling) {
286 // Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700287 NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
288 if (collector != null) {
289 collector.addWithFlowRule(flowRule);
290 }
ssyoon9030fbcd92015-08-17 10:42:07 +0900291 }
alshabib35edb1a2014-09-16 17:44:44 -0700292 }
293
alshabib1cc04f72014-09-16 16:09:58 -0700294 @Override
295 public void removeFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800296 for (FlowRule flowRule : flowRules) {
297 removeRule(flowRule);
alshabib219ebaa2014-09-22 15:41:24 -0700298 }
alshabib1cc04f72014-09-16 16:09:58 -0700299 }
300
alshabib219ebaa2014-09-22 15:41:24 -0700301 private void removeRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900302 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
303 OpenFlowSwitch sw = controller.getSwitch(dpid);
304
Ray Milkey0ae473d2016-04-04 10:56:47 -0700305 if (sw == null) {
306 return;
307 }
308
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700309 FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
310 if (hasPayload(flowRuleExtPayLoad)) {
311 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800312 sw.sendMsg(msg);
313 return;
314 }
alshabibbdcbb102015-04-22 14:16:38 -0700315 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Jonathan Hart3c259162015-10-21 21:31:19 -0700316 Optional.empty(), Optional.of(driverService)).buildFlowDel());
ssyoon9030fbcd92015-08-17 10:42:07 +0900317
318 if (adaptiveFlowSampling) {
319 // Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700320 NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
321 if (collector != null) {
322 collector.removeFlows(flowRule);
323 }
ssyoon9030fbcd92015-08-17 10:42:07 +0900324 }
alshabib219ebaa2014-09-22 15:41:24 -0700325 }
326
alshabiba68eb962014-09-24 20:34:13 -0700327 @Override
328 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
329 // TODO: optimize using the ApplicationId
330 removeFlowRule(flowRules);
331 }
332
alshabib193525b2014-10-08 18:58:03 -0700333 @Override
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800334 public void executeBatch(FlowRuleBatchOperation batch) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900335 checkNotNull(batch);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800336
337 pendingBatches.put(batch.id(), new InternalCacheEntry(batch));
338
ssyoon9030fbcd92015-08-17 10:42:07 +0900339 Dpid dpid = Dpid.dpid(batch.deviceId().uri());
340 OpenFlowSwitch sw = controller.getSwitch(dpid);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800341 OFFlowMod mod;
alshabib193525b2014-10-08 18:58:03 -0700342 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
jcc3d4e14a2015-04-21 11:32:05 +0800343 // flow is the third party privacy flow
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700344
345 FlowRuleExtPayLoad flowRuleExtPayLoad = fbe.target().payLoad();
346 if (hasPayload(flowRuleExtPayLoad)) {
347 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800348 sw.sendMsg(msg);
349 continue;
350 }
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700351 FlowModBuilder builder =
Jonathan Hart3c259162015-10-21 21:31:19 -0700352 FlowModBuilder.builder(fbe.target(), sw.factory(),
353 Optional.of(batch.id()), Optional.of(driverService));
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700354 NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800355 switch (fbe.operator()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700356 case ADD:
357 mod = builder.buildFlowAdd();
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700358 if (adaptiveFlowSampling && collector != null) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900359 // Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700360 collector.addWithFlowRule(fbe.target());
ssyoon9030fbcd92015-08-17 10:42:07 +0900361 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700362 break;
363 case REMOVE:
364 mod = builder.buildFlowDel();
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700365 if (adaptiveFlowSampling && collector != null) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900366 // Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700367 collector.removeFlows(fbe.target());
ssyoon9030fbcd92015-08-17 10:42:07 +0900368 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700369 break;
370 case MODIFY:
371 mod = builder.buildFlowMod();
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700372 if (adaptiveFlowSampling && collector != null) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900373 // Add or Update TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
374 // afsCollectors.get(dpid).addWithFlowRule(fbe.target()); //check if add is good or not
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700375 collector.addOrUpdateFlows((FlowEntry) fbe.target());
ssyoon9030fbcd92015-08-17 10:42:07 +0900376 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700377 break;
378 default:
379 log.error("Unsupported batch operation {}; skipping flowmod {}",
ssyoon9030fbcd92015-08-17 10:42:07 +0900380 fbe.operator(), fbe);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700381 continue;
jcc3d4e14a2015-04-21 11:32:05 +0800382 }
Saurav Das3ea46622015-04-22 14:01:34 -0700383 sw.sendMsg(mod);
alshabib193525b2014-10-08 18:58:03 -0700384 }
jcc3d4e14a2015-04-21 11:32:05 +0800385 OFBarrierRequest.Builder builder = sw.factory().buildBarrierRequest()
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800386 .setXid(batch.id());
387 sw.sendMsg(builder.build());
alshabib193525b2014-10-08 18:58:03 -0700388 }
389
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700390 private boolean hasPayload(FlowRuleExtPayLoad flowRuleExtPayLoad) {
391 return flowRuleExtPayLoad != null &&
392 flowRuleExtPayLoad.payLoad() != null &&
393 flowRuleExtPayLoad.payLoad().length > 0;
394 }
395
alshabib8f1cf4a2014-09-17 14:44:48 -0700396 private class InternalFlowProvider
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800397 implements OpenFlowSwitchListener, OpenFlowEventListener {
alshabib8f1cf4a2014-09-17 14:44:48 -0700398
alshabib8f1cf4a2014-09-17 14:44:48 -0700399 @Override
400 public void switchAdded(Dpid dpid) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900401
402 OpenFlowSwitch sw = controller.getSwitch(dpid);
403
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700404 createCollector(controller.getSwitch(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700405 }
406
407 @Override
408 public void switchRemoved(Dpid dpid) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900409 if (adaptiveFlowSampling) {
410 NewAdaptiveFlowStatsCollector collector = afsCollectors.remove(dpid);
411 if (collector != null) {
412 collector.stop();
413 }
414 } else {
415 FlowStatsCollector collector = simpleCollectors.remove(dpid);
416 if (collector != null) {
417 collector.stop();
418 }
alshabibdfc7afb2014-10-21 20:13:27 -0700419 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700420 TableStatisticsCollector tsc = tableStatsCollectors.remove(dpid);
421 if (tsc != null) {
422 tsc.stop();
423 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700424 }
425
426 @Override
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700427 public void switchChanged(Dpid dpid) {
428 }
429
430 @Override
alshabib8f1cf4a2014-09-17 14:44:48 -0700431 public void portChanged(Dpid dpid, OFPortStatus status) {
jcc3d4e14a2015-04-21 11:32:05 +0800432 // TODO: Decide whether to evict flows internal store.
alshabib8f1cf4a2014-09-17 14:44:48 -0700433 }
434
435 @Override
436 public void handleMessage(Dpid dpid, OFMessage msg) {
Ray Milkeyada9e2d2016-04-05 16:42:35 -0700437 if (providerService == null) {
438 // We are shutting down, nothing to be done
439 return;
440 }
Jonathan Harte4e74f02016-03-03 12:57:40 -0800441 DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700442 switch (msg.getType()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700443 case FLOW_REMOVED:
444 OFFlowRemoved removed = (OFFlowRemoved) msg;
alshabib6b5cfec2014-09-18 17:42:18 -0700445
Jonathan Harte4e74f02016-03-03 12:57:40 -0800446 FlowEntry fr = new FlowEntryBuilder(deviceId, removed, driverService).build();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700447 providerService.flowRemoved(fr);
ssyoon9030fbcd92015-08-17 10:42:07 +0900448
449 if (adaptiveFlowSampling) {
450 // Removed TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700451 NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
452 if (collector != null) {
453 collector.flowRemoved(fr);
454 }
ssyoon9030fbcd92015-08-17 10:42:07 +0900455 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700456 break;
457 case STATS_REPLY:
458 if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW) {
459 pushFlowMetrics(dpid, (OFFlowStatsReply) msg);
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700460 } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.TABLE) {
461 pushTableStatistics(dpid, (OFTableStatsReply) msg);
sangho89bf6fb2015-02-09 09:33:13 -0800462 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700463 break;
464 case BARRIER_REPLY:
465 try {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700466 InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800467 if (entry != null) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700468 providerService
469 .batchOperationCompleted(msg.getXid(),
470 entry.completed());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800471 } else {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700472 log.warn("Received unknown Barrier Reply: {}",
473 msg.getXid());
474 }
475 } finally {
476 pendingBatches.invalidate(msg.getXid());
477 }
478 break;
479 case ERROR:
Thomas Vachuska3358af22015-05-19 18:40:34 -0700480 // TODO: This needs to get suppressed in a better way.
481 if (msg instanceof OFBadRequestErrorMsg &&
482 ((OFBadRequestErrorMsg) msg).getCode() == OFBadRequestCode.BAD_TYPE) {
483 log.debug("Received error message {} from {}", msg, dpid);
484 } else {
485 log.warn("Received error message {} from {}", msg, dpid);
486 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700487
488 OFErrorMsg error = (OFErrorMsg) msg;
489 if (error.getErrType() == OFErrorType.FLOW_MOD_FAILED) {
490 OFFlowModFailedErrorMsg fmFailed = (OFFlowModFailedErrorMsg) error;
491 if (fmFailed.getData().getParsedMessage().isPresent()) {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700492 OFMessage m = fmFailed.getData().getParsedMessage().get();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700493 OFFlowMod fm = (OFFlowMod) m;
Thomas Vachuska3358af22015-05-19 18:40:34 -0700494 InternalCacheEntry entry =
495 pendingBatches.getIfPresent(msg.getXid());
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700496 if (entry != null) {
Jonathan Harte4e74f02016-03-03 12:57:40 -0800497 entry.appendFailure(new FlowEntryBuilder(deviceId, fm, driverService).build());
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700498 } else {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700499 log.error("No matching batch for this error: {}", error);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700500 }
501 } else {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700502 // FIXME: Potentially add flowtracking to avoid this message.
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700503 log.error("Flow installation failed but switch didn't"
504 + " tell us which one.");
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800505 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800506 }
Ray Milkey4fd3ceb2015-12-10 14:43:08 -0800507 break;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700508 default:
509 log.debug("Unhandled message type: {}", msg.getType());
alshabib8f1cf4a2014-09-17 14:44:48 -0700510 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700511 }
512
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700513 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700514 public void receivedRoleReply(Dpid dpid, RoleState requested,
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800515 RoleState response) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700516 // Do nothing here for now.
517 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700518
sangho89bf6fb2015-02-09 09:33:13 -0800519 private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies) {
alshabib64def642014-12-02 23:27:37 -0800520
alshabib54ce5892014-09-23 17:50:51 -0700521 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
alshabib54ce5892014-09-23 17:50:51 -0700522
alshabib64def642014-12-02 23:27:37 -0800523 List<FlowEntry> flowEntries = replies.getEntries().stream()
Jonathan Harte4e74f02016-03-03 12:57:40 -0800524 .map(entry -> new FlowEntryBuilder(did, entry, driverService).build())
alshabib64def642014-12-02 23:27:37 -0800525 .collect(Collectors.toList());
alshabib54ce5892014-09-23 17:50:51 -0700526
ssyoon9030fbcd92015-08-17 10:42:07 +0900527 if (adaptiveFlowSampling) {
528 NewAdaptiveFlowStatsCollector afsc = afsCollectors.get(dpid);
529
530 synchronized (afsc) {
531 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
532 log.debug("OpenFlowRuleProvider:pushFlowMetrics, flowMissingXid={}, "
533 + "OFFlowStatsReply Xid={}, for {}",
534 afsc.getFlowMissingXid(), replies.getXid(), dpid);
535 }
536
537 // Check that OFFlowStatsReply Xid is same with the one of OFFlowStatsRequest?
538 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
539 if (afsc.getFlowMissingXid() == replies.getXid()) {
540 // call entire flow stats update with flowMissing synchronization.
541 // used existing pushFlowMetrics
542 providerService.pushFlowMetrics(did, flowEntries);
543 }
544 // reset flowMissingXid to NO_FLOW_MISSING_XID
545 afsc.setFlowMissingXid(NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID);
546
547 } else {
548 // call individual flow stats update
549 providerService.pushFlowMetricsWithoutFlowMissing(did, flowEntries);
550 }
551
552 // Update TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
553 afsc.pushFlowMetrics(flowEntries);
554 }
555 } else {
556 // call existing entire flow stats update with flowMissing synchronization
557 providerService.pushFlowMetrics(did, flowEntries);
558 }
alshabib5c370ff2014-09-18 10:12:14 -0700559 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700560
561 private void pushTableStatistics(Dpid dpid, OFTableStatsReply replies) {
562
563 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
564 List<TableStatisticsEntry> tableStatsEntries = replies.getEntries().stream()
565 .map(entry -> buildTableStatistics(did, entry))
566 .filter(Objects::nonNull)
567 .collect(Collectors.toList());
568 providerService.pushTableStatistics(did, tableStatsEntries);
569 }
570
571 private TableStatisticsEntry buildTableStatistics(DeviceId deviceId,
572 OFTableStatsEntry ofEntry) {
573 TableStatisticsEntry entry = null;
574 if (ofEntry != null) {
575 entry = new DefaultTableStatisticsEntry(deviceId,
576 ofEntry.getTableId().getValue(),
577 ofEntry.getActiveCount(),
578 ofEntry.getLookupCount().getValue(),
579 ofEntry.getMatchedCount().getValue());
580 }
581
582 return entry;
583
584 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700585 }
alshabib1cc04f72014-09-16 16:09:58 -0700586
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800587 /**
jcc3d4e14a2015-04-21 11:32:05 +0800588 * The internal cache entry holding the original request as well as
589 * accumulating the any failures along the way.
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700590 * <p/>
jcc3d4e14a2015-04-21 11:32:05 +0800591 * If this entry is evicted from the cache then the entire operation is
592 * considered failed. Otherwise, only the failures reported by the device
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800593 * will be propagated up.
594 */
595 private class InternalCacheEntry {
alshabib902d41b2014-10-07 16:52:05 -0700596
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800597 private final FlowRuleBatchOperation operation;
598 private final Set<FlowRule> failures = Sets.newConcurrentHashSet();
alshabib193525b2014-10-08 18:58:03 -0700599
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800600 public InternalCacheEntry(FlowRuleBatchOperation operation) {
601 this.operation = operation;
alshabib902d41b2014-10-07 16:52:05 -0700602 }
603
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800604 /**
605 * Appends a failed rule to the set of failed items.
jcc3d4e14a2015-04-21 11:32:05 +0800606 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800607 * @param rule the failed rule
608 */
609 public void appendFailure(FlowRule rule) {
610 failures.add(rule);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800611 }
612
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800613 /**
614 * Fails the entire batch and returns the failed operation.
jcc3d4e14a2015-04-21 11:32:05 +0800615 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800616 * @return the failed operation
617 */
618 public CompletedBatchOperation failedCompletion() {
619 Set<FlowRule> fails = operation.getOperations().stream()
620 .map(op -> op.target()).collect(Collectors.toSet());
jcc3d4e14a2015-04-21 11:32:05 +0800621 return new CompletedBatchOperation(false,
622 Collections
623 .unmodifiableSet(fails),
624 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700625 }
626
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800627 /**
628 * Returns the completed operation and whether the batch suceeded.
jcc3d4e14a2015-04-21 11:32:05 +0800629 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800630 * @return the completed operation
631 */
632 public CompletedBatchOperation completed() {
jcc3d4e14a2015-04-21 11:32:05 +0800633 return new CompletedBatchOperation(
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700634 failures.isEmpty(),
635 Collections
636 .unmodifiableSet(failures),
637 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700638 }
alshabib902d41b2014-10-07 16:52:05 -0700639 }
alshabiba68eb962014-09-24 20:34:13 -0700640
alshabib1cc04f72014-09-16 16:09:58 -0700641}