blob: 9415e3a43ed6e4b70484cd5316154ae706a30ca1 [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;
Madan Jampani84382b92016-06-22 08:26:49 -070022import com.google.common.collect.ImmutableSet;
23import com.google.common.collect.Lists;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070024import com.google.common.collect.Maps;
25import com.google.common.collect.Sets;
Madan Jampani84382b92016-06-22 08:26:49 -070026
alshabib1cc04f72014-09-16 16:09:58 -070027import org.apache.felix.scr.annotations.Activate;
28import org.apache.felix.scr.annotations.Component;
29import org.apache.felix.scr.annotations.Deactivate;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070030import org.apache.felix.scr.annotations.Modified;
31import org.apache.felix.scr.annotations.Property;
alshabib1cc04f72014-09-16 16:09:58 -070032import org.apache.felix.scr.annotations.Reference;
33import org.apache.felix.scr.annotations.ReferenceCardinality;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070034import org.onosproject.cfg.ComponentConfigService;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.core.ApplicationId;
36import org.onosproject.net.DeviceId;
Jonathan Hart3c259162015-10-21 21:31:19 -070037import org.onosproject.net.driver.DriverService;
Brian O'Connorabafb502014-12-02 22:26:20 -080038import org.onosproject.net.flow.CompletedBatchOperation;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070039import org.onosproject.net.flow.DefaultTableStatisticsEntry;
Brian O'Connorabafb502014-12-02 22:26:20 -080040import org.onosproject.net.flow.FlowEntry;
41import org.onosproject.net.flow.FlowRule;
42import org.onosproject.net.flow.FlowRuleBatchEntry;
Brian O'Connor72cb19a2015-01-16 16:14:41 -080043import org.onosproject.net.flow.FlowRuleBatchOperation;
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -070044import org.onosproject.net.flow.FlowRuleExtPayLoad;
Brian O'Connorabafb502014-12-02 22:26:20 -080045import org.onosproject.net.flow.FlowRuleProvider;
46import org.onosproject.net.flow.FlowRuleProviderRegistry;
47import org.onosproject.net.flow.FlowRuleProviderService;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070048import org.onosproject.net.flow.TableStatisticsEntry;
Brian O'Connorabafb502014-12-02 22:26:20 -080049import org.onosproject.net.provider.AbstractProvider;
50import org.onosproject.net.provider.ProviderId;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070051import org.onosproject.net.statistic.DefaultLoad;
Brian O'Connorabafb502014-12-02 22:26:20 -080052import org.onosproject.openflow.controller.Dpid;
53import org.onosproject.openflow.controller.OpenFlowController;
54import org.onosproject.openflow.controller.OpenFlowEventListener;
55import org.onosproject.openflow.controller.OpenFlowSwitch;
56import org.onosproject.openflow.controller.OpenFlowSwitchListener;
57import org.onosproject.openflow.controller.RoleState;
jcc3d4e14a2015-04-21 11:32:05 +080058import org.onosproject.openflow.controller.ThirdPartyMessage;
Thomas Vachuska95caba32016-04-04 10:42:05 -070059import org.onosproject.provider.of.flow.util.FlowEntryBuilder;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070060import org.osgi.service.component.ComponentContext;
Thomas Vachuska3358af22015-05-19 18:40:34 -070061import org.projectfloodlight.openflow.protocol.OFBadRequestCode;
alshabib902d41b2014-10-07 16:52:05 -070062import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
63import org.projectfloodlight.openflow.protocol.OFErrorMsg;
alshabib193525b2014-10-08 18:58:03 -070064import org.projectfloodlight.openflow.protocol.OFFlowMod;
alshabib8f1cf4a2014-09-17 14:44:48 -070065import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
alshabib5c370ff2014-09-18 10:12:14 -070066import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
alshabib8f1cf4a2014-09-17 14:44:48 -070067import org.projectfloodlight.openflow.protocol.OFMessage;
68import org.projectfloodlight.openflow.protocol.OFPortStatus;
alshabib5c370ff2014-09-18 10:12:14 -070069import org.projectfloodlight.openflow.protocol.OFStatsReply;
sangho89bf6fb2015-02-09 09:33:13 -080070import org.projectfloodlight.openflow.protocol.OFStatsType;
Jonathan Hart3c259162015-10-21 21:31:19 -070071import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
72import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
Prince Pereira788797e2016-08-10 11:24:14 +053073import org.projectfloodlight.openflow.protocol.errormsg.OFBadActionErrorMsg;
74import org.projectfloodlight.openflow.protocol.errormsg.OFBadInstructionErrorMsg;
75import org.projectfloodlight.openflow.protocol.errormsg.OFBadMatchErrorMsg;
Thomas Vachuska3358af22015-05-19 18:40:34 -070076import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
alshabib193525b2014-10-08 18:58:03 -070077import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
alshabib1cc04f72014-09-16 16:09:58 -070078import org.slf4j.Logger;
79
Thomas Vachuska75aaa672015-04-29 12:24:43 -070080import java.util.Collections;
81import java.util.Dictionary;
82import java.util.List;
83import java.util.Map;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070084import java.util.Objects;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070085import java.util.Optional;
86import java.util.Set;
87import java.util.Timer;
88import java.util.concurrent.TimeUnit;
89import java.util.stream.Collectors;
90
ssyoon9030fbcd92015-08-17 10:42:07 +090091import static com.google.common.base.Preconditions.checkNotNull;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070092import static com.google.common.base.Strings.isNullOrEmpty;
93import static org.onlab.util.Tools.get;
94import static org.slf4j.LoggerFactory.getLogger;
alshabibeec3a062014-09-17 18:01:26 -070095
alshabib1cc04f72014-09-16 16:09:58 -070096/**
jcc3d4e14a2015-04-21 11:32:05 +080097 * Provider which uses an OpenFlow controller to detect network end-station
98 * hosts.
alshabib1cc04f72014-09-16 16:09:58 -070099 */
100@Component(immediate = true)
jcc3d4e14a2015-04-21 11:32:05 +0800101public class OpenFlowRuleProvider extends AbstractProvider
102 implements FlowRuleProvider {
alshabib1cc04f72014-09-16 16:09:58 -0700103
104 private final Logger log = getLogger(getClass());
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected FlowRuleProviderRegistry providerRegistry;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected OpenFlowController controller;
111
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected ComponentConfigService cfgService;
114
Jonathan Hart3c259162015-10-21 21:31:19 -0700115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected DriverService driverService;
117
ssyoon9030fbcd92015-08-17 10:42:07 +0900118 private static final int DEFAULT_POLL_FREQUENCY = 5;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700119 @Property(name = "flowPollFrequency", intValue = DEFAULT_POLL_FREQUENCY,
120 label = "Frequency (in seconds) for polling flow statistics")
121 private int flowPollFrequency = DEFAULT_POLL_FREQUENCY;
122
Madan Jampani7a3ba962016-04-07 20:16:16 -0700123 private static final boolean DEFAULT_ADAPTIVE_FLOW_SAMPLING = false;
ssyoon9030fbcd92015-08-17 10:42:07 +0900124 @Property(name = "adaptiveFlowSampling", boolValue = DEFAULT_ADAPTIVE_FLOW_SAMPLING,
125 label = "Adaptive Flow Sampling is on or off")
126 private boolean adaptiveFlowSampling = DEFAULT_ADAPTIVE_FLOW_SAMPLING;
127
alshabib1cc04f72014-09-16 16:09:58 -0700128 private FlowRuleProviderService providerService;
129
alshabibeec3a062014-09-17 18:01:26 -0700130 private final InternalFlowProvider listener = new InternalFlowProvider();
131
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800132 private Cache<Long, InternalCacheEntry> pendingBatches;
alshabib193525b2014-10-08 18:58:03 -0700133
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700134 private final Timer timer = new Timer("onos-openflow-collector");
Madan Jampani6b266102016-06-23 00:56:36 -0700135 private final Map<Dpid, FlowStatsCollector> simpleCollectors = Maps.newConcurrentMap();
ssyoon9030fbcd92015-08-17 10:42:07 +0900136
137 // NewAdaptiveFlowStatsCollector Set
Madan Jampani6b266102016-06-23 00:56:36 -0700138 private final Map<Dpid, NewAdaptiveFlowStatsCollector> afsCollectors = Maps.newConcurrentMap();
139 private final Map<Dpid, TableStatisticsCollector> tableStatsCollectors = Maps.newConcurrentMap();
alshabib3d643ec2014-10-22 18:33:00 -0700140
alshabib1cc04f72014-09-16 16:09:58 -0700141 /**
142 * Creates an OpenFlow host provider.
143 */
144 public OpenFlowRuleProvider() {
Brian O'Connorabafb502014-12-02 22:26:20 -0800145 super(new ProviderId("of", "org.onosproject.provider.openflow"));
alshabib1cc04f72014-09-16 16:09:58 -0700146 }
147
148 @Activate
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700149 protected void activate(ComponentContext context) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700150 cfgService.registerProperties(getClass());
alshabib1cc04f72014-09-16 16:09:58 -0700151 providerService = providerRegistry.register(this);
alshabibeec3a062014-09-17 18:01:26 -0700152 controller.addListener(listener);
153 controller.addEventListener(listener);
alshabib3d643ec2014-10-22 18:33:00 -0700154
Antonio Marsico1c5ae1f2015-12-15 15:31:56 +0100155 modified(context);
156
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700157 pendingBatches = createBatchCache();
ssyoon9030fbcd92015-08-17 10:42:07 +0900158
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700159 createCollectors();
alshabib3d643ec2014-10-22 18:33:00 -0700160
ssyoon9030fbcd92015-08-17 10:42:07 +0900161 log.info("Started with flowPollFrequency = {}, adaptiveFlowSampling = {}",
162 flowPollFrequency, adaptiveFlowSampling);
alshabib1cc04f72014-09-16 16:09:58 -0700163 }
164
165 @Deactivate
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700166 protected void deactivate(ComponentContext context) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700167 cfgService.unregisterProperties(getClass(), false);
168 stopCollectors();
alshabib1cc04f72014-09-16 16:09:58 -0700169 providerRegistry.unregister(this);
170 providerService = null;
171
172 log.info("Stopped");
173 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800174
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700175 @Modified
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700176 protected void modified(ComponentContext context) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700177 Dictionary<?, ?> properties = context.getProperties();
178 int newFlowPollFrequency;
179 try {
180 String s = get(properties, "flowPollFrequency");
181 newFlowPollFrequency = isNullOrEmpty(s) ? flowPollFrequency : Integer.parseInt(s.trim());
182
183 } catch (NumberFormatException | ClassCastException e) {
184 newFlowPollFrequency = flowPollFrequency;
185 }
186
187 if (newFlowPollFrequency != flowPollFrequency) {
188 flowPollFrequency = newFlowPollFrequency;
189 adjustRate();
190 }
191
192 log.info("Settings: flowPollFrequency={}", flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900193
194 boolean newAdaptiveFlowSampling;
195 String s = get(properties, "adaptiveFlowSampling");
196 newAdaptiveFlowSampling = isNullOrEmpty(s) ? adaptiveFlowSampling : Boolean.parseBoolean(s.trim());
197
198 if (newAdaptiveFlowSampling != adaptiveFlowSampling) {
199 // stop previous collector
200 stopCollectors();
201 adaptiveFlowSampling = newAdaptiveFlowSampling;
202 // create new collectors
203 createCollectors();
204 }
205
206 log.info("Settings: adaptiveFlowSampling={}", adaptiveFlowSampling);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700207 }
208
209 private Cache<Long, InternalCacheEntry> createBatchCache() {
210 return CacheBuilder.newBuilder()
211 .expireAfterWrite(10, TimeUnit.SECONDS)
212 .removalListener((RemovalNotification<Long, InternalCacheEntry> notification) -> {
213 if (notification.getCause() == RemovalCause.EXPIRED) {
214 providerService.batchOperationCompleted(notification.getKey(),
215 notification.getValue().failedCompletion());
216 }
217 }).build();
218 }
219
220 private void createCollectors() {
221 controller.getSwitches().forEach(this::createCollector);
222 }
223
224 private void createCollector(OpenFlowSwitch sw) {
Kavitha Alagesan6704df32016-08-18 15:15:31 +0530225 if (sw == null) {
226 return;
227 }
ssyoon9030fbcd92015-08-17 10:42:07 +0900228 if (adaptiveFlowSampling) {
229 // NewAdaptiveFlowStatsCollector Constructor
Charles Chan14967c22015-12-07 11:11:50 -0800230 NewAdaptiveFlowStatsCollector fsc =
231 new NewAdaptiveFlowStatsCollector(driverService, sw, flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900232 fsc.start();
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700233 stopCollectorIfNeeded(afsCollectors.put(new Dpid(sw.getId()), fsc));
ssyoon9030fbcd92015-08-17 10:42:07 +0900234 } else {
235 FlowStatsCollector fsc = new FlowStatsCollector(timer, sw, flowPollFrequency);
236 fsc.start();
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700237 stopCollectorIfNeeded(simpleCollectors.put(new Dpid(sw.getId()), fsc));
ssyoon9030fbcd92015-08-17 10:42:07 +0900238 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700239 TableStatisticsCollector tsc = new TableStatisticsCollector(timer, sw, flowPollFrequency);
240 tsc.start();
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700241 stopCollectorIfNeeded(tableStatsCollectors.put(new Dpid(sw.getId()), tsc));
242 }
243
244 private void stopCollectorIfNeeded(SwitchDataCollector collector) {
245 if (collector != null) {
246 collector.stop();
247 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700248 }
249
250 private void stopCollectors() {
ssyoon9030fbcd92015-08-17 10:42:07 +0900251 if (adaptiveFlowSampling) {
252 // NewAdaptiveFlowStatsCollector Destructor
253 afsCollectors.values().forEach(NewAdaptiveFlowStatsCollector::stop);
254 afsCollectors.clear();
255 } else {
256 simpleCollectors.values().forEach(FlowStatsCollector::stop);
257 simpleCollectors.clear();
258 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700259 tableStatsCollectors.values().forEach(TableStatisticsCollector::stop);
260 tableStatsCollectors.clear();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700261 }
262
263 private void adjustRate() {
264 DefaultLoad.setPollInterval(flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900265 if (adaptiveFlowSampling) {
266 // NewAdaptiveFlowStatsCollector calAndPollInterval
267 afsCollectors.values().forEach(fsc -> fsc.adjustCalAndPollInterval(flowPollFrequency));
268 } else {
269 simpleCollectors.values().forEach(fsc -> fsc.adjustPollInterval(flowPollFrequency));
270 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700271 tableStatsCollectors.values().forEach(tsc -> tsc.adjustPollInterval(flowPollFrequency));
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700272 }
273
alshabib1cc04f72014-09-16 16:09:58 -0700274 @Override
275 public void applyFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800276 for (FlowRule flowRule : flowRules) {
277 applyRule(flowRule);
alshabib35edb1a2014-09-16 17:44:44 -0700278 }
alshabib1cc04f72014-09-16 16:09:58 -0700279 }
280
alshabib35edb1a2014-09-16 17:44:44 -0700281 private void applyRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900282 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
283 OpenFlowSwitch sw = controller.getSwitch(dpid);
284
Ray Milkey0ae473d2016-04-04 10:56:47 -0700285 if (sw == null) {
286 return;
287 }
288
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700289 FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
290 if (hasPayload(flowRuleExtPayLoad)) {
291 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800292 sw.sendMsg(msg);
293 return;
294 }
alshabibbdcbb102015-04-22 14:16:38 -0700295 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Jonathan Hart3c259162015-10-21 21:31:19 -0700296 Optional.empty(), Optional.of(driverService)).buildFlowAdd());
ssyoon9030fbcd92015-08-17 10:42:07 +0900297
298 if (adaptiveFlowSampling) {
299 // Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700300 NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
301 if (collector != null) {
302 collector.addWithFlowRule(flowRule);
303 }
ssyoon9030fbcd92015-08-17 10:42:07 +0900304 }
alshabib35edb1a2014-09-16 17:44:44 -0700305 }
306
alshabib1cc04f72014-09-16 16:09:58 -0700307 @Override
308 public void removeFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800309 for (FlowRule flowRule : flowRules) {
310 removeRule(flowRule);
alshabib219ebaa2014-09-22 15:41:24 -0700311 }
alshabib1cc04f72014-09-16 16:09:58 -0700312 }
313
alshabib219ebaa2014-09-22 15:41:24 -0700314 private void removeRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900315 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
316 OpenFlowSwitch sw = controller.getSwitch(dpid);
317
Ray Milkey0ae473d2016-04-04 10:56:47 -0700318 if (sw == null) {
319 return;
320 }
321
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700322 FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
323 if (hasPayload(flowRuleExtPayLoad)) {
324 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800325 sw.sendMsg(msg);
326 return;
327 }
alshabibbdcbb102015-04-22 14:16:38 -0700328 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Jonathan Hart3c259162015-10-21 21:31:19 -0700329 Optional.empty(), Optional.of(driverService)).buildFlowDel());
ssyoon9030fbcd92015-08-17 10:42:07 +0900330
331 if (adaptiveFlowSampling) {
332 // Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700333 NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
334 if (collector != null) {
335 collector.removeFlows(flowRule);
336 }
ssyoon9030fbcd92015-08-17 10:42:07 +0900337 }
alshabib219ebaa2014-09-22 15:41:24 -0700338 }
339
alshabiba68eb962014-09-24 20:34:13 -0700340 @Override
341 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
342 // TODO: optimize using the ApplicationId
343 removeFlowRule(flowRules);
344 }
345
alshabib193525b2014-10-08 18:58:03 -0700346 @Override
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800347 public void executeBatch(FlowRuleBatchOperation batch) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900348 checkNotNull(batch);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800349
ssyoon9030fbcd92015-08-17 10:42:07 +0900350 Dpid dpid = Dpid.dpid(batch.deviceId().uri());
351 OpenFlowSwitch sw = controller.getSwitch(dpid);
Madan Jampani84382b92016-06-22 08:26:49 -0700352
353 // If switch no longer exists, simply return.
354 if (sw == null) {
355 Set<FlowRule> failures = ImmutableSet.copyOf(Lists.transform(batch.getOperations(), e -> e.target()));
356 providerService.batchOperationCompleted(batch.id(),
357 new CompletedBatchOperation(false, failures, batch.deviceId()));
358 return;
359 }
360 pendingBatches.put(batch.id(), new InternalCacheEntry(batch));
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800361 OFFlowMod mod;
alshabib193525b2014-10-08 18:58:03 -0700362 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
jcc3d4e14a2015-04-21 11:32:05 +0800363 // flow is the third party privacy flow
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700364
365 FlowRuleExtPayLoad flowRuleExtPayLoad = fbe.target().payLoad();
366 if (hasPayload(flowRuleExtPayLoad)) {
367 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800368 sw.sendMsg(msg);
369 continue;
370 }
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700371 FlowModBuilder builder =
Jonathan Hart3c259162015-10-21 21:31:19 -0700372 FlowModBuilder.builder(fbe.target(), sw.factory(),
373 Optional.of(batch.id()), Optional.of(driverService));
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700374 NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800375 switch (fbe.operator()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700376 case ADD:
377 mod = builder.buildFlowAdd();
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700378 if (adaptiveFlowSampling && collector != null) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900379 // Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700380 collector.addWithFlowRule(fbe.target());
ssyoon9030fbcd92015-08-17 10:42:07 +0900381 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700382 break;
383 case REMOVE:
384 mod = builder.buildFlowDel();
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700385 if (adaptiveFlowSampling && collector != null) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900386 // Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700387 collector.removeFlows(fbe.target());
ssyoon9030fbcd92015-08-17 10:42:07 +0900388 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700389 break;
390 case MODIFY:
391 mod = builder.buildFlowMod();
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700392 if (adaptiveFlowSampling && collector != null) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900393 // Add or Update TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
394 // afsCollectors.get(dpid).addWithFlowRule(fbe.target()); //check if add is good or not
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700395 collector.addOrUpdateFlows((FlowEntry) fbe.target());
ssyoon9030fbcd92015-08-17 10:42:07 +0900396 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700397 break;
398 default:
399 log.error("Unsupported batch operation {}; skipping flowmod {}",
ssyoon9030fbcd92015-08-17 10:42:07 +0900400 fbe.operator(), fbe);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700401 continue;
jcc3d4e14a2015-04-21 11:32:05 +0800402 }
Saurav Das3ea46622015-04-22 14:01:34 -0700403 sw.sendMsg(mod);
alshabib193525b2014-10-08 18:58:03 -0700404 }
jcc3d4e14a2015-04-21 11:32:05 +0800405 OFBarrierRequest.Builder builder = sw.factory().buildBarrierRequest()
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800406 .setXid(batch.id());
407 sw.sendMsg(builder.build());
alshabib193525b2014-10-08 18:58:03 -0700408 }
409
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700410 private boolean hasPayload(FlowRuleExtPayLoad flowRuleExtPayLoad) {
411 return flowRuleExtPayLoad != null &&
412 flowRuleExtPayLoad.payLoad() != null &&
413 flowRuleExtPayLoad.payLoad().length > 0;
414 }
415
alshabib8f1cf4a2014-09-17 14:44:48 -0700416 private class InternalFlowProvider
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800417 implements OpenFlowSwitchListener, OpenFlowEventListener {
alshabib8f1cf4a2014-09-17 14:44:48 -0700418
alshabib8f1cf4a2014-09-17 14:44:48 -0700419 @Override
420 public void switchAdded(Dpid dpid) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700421 createCollector(controller.getSwitch(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700422 }
423
424 @Override
425 public void switchRemoved(Dpid dpid) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900426 if (adaptiveFlowSampling) {
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700427 stopCollectorIfNeeded(afsCollectors.remove(dpid));
ssyoon9030fbcd92015-08-17 10:42:07 +0900428 } else {
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700429 stopCollectorIfNeeded(simpleCollectors.remove(dpid));
alshabibdfc7afb2014-10-21 20:13:27 -0700430 }
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700431 stopCollectorIfNeeded(tableStatsCollectors.remove(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700432 }
433
434 @Override
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700435 public void switchChanged(Dpid dpid) {
436 }
437
438 @Override
alshabib8f1cf4a2014-09-17 14:44:48 -0700439 public void portChanged(Dpid dpid, OFPortStatus status) {
jcc3d4e14a2015-04-21 11:32:05 +0800440 // TODO: Decide whether to evict flows internal store.
alshabib8f1cf4a2014-09-17 14:44:48 -0700441 }
442
443 @Override
444 public void handleMessage(Dpid dpid, OFMessage msg) {
Ray Milkeyada9e2d2016-04-05 16:42:35 -0700445 if (providerService == null) {
446 // We are shutting down, nothing to be done
447 return;
448 }
Jonathan Harte4e74f02016-03-03 12:57:40 -0800449 DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700450 switch (msg.getType()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700451 case FLOW_REMOVED:
452 OFFlowRemoved removed = (OFFlowRemoved) msg;
alshabib6b5cfec2014-09-18 17:42:18 -0700453
Jonathan Harte4e74f02016-03-03 12:57:40 -0800454 FlowEntry fr = new FlowEntryBuilder(deviceId, removed, driverService).build();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700455 providerService.flowRemoved(fr);
ssyoon9030fbcd92015-08-17 10:42:07 +0900456
457 if (adaptiveFlowSampling) {
458 // Removed TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700459 NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
460 if (collector != null) {
461 collector.flowRemoved(fr);
462 }
ssyoon9030fbcd92015-08-17 10:42:07 +0900463 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700464 break;
465 case STATS_REPLY:
466 if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW) {
467 pushFlowMetrics(dpid, (OFFlowStatsReply) msg);
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700468 } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.TABLE) {
469 pushTableStatistics(dpid, (OFTableStatsReply) msg);
sangho89bf6fb2015-02-09 09:33:13 -0800470 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700471 break;
472 case BARRIER_REPLY:
473 try {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700474 InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800475 if (entry != null) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700476 providerService
477 .batchOperationCompleted(msg.getXid(),
478 entry.completed());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800479 } else {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700480 log.warn("Received unknown Barrier Reply: {}",
481 msg.getXid());
482 }
483 } finally {
484 pendingBatches.invalidate(msg.getXid());
485 }
486 break;
487 case ERROR:
Thomas Vachuska3358af22015-05-19 18:40:34 -0700488 // TODO: This needs to get suppressed in a better way.
489 if (msg instanceof OFBadRequestErrorMsg &&
490 ((OFBadRequestErrorMsg) msg).getCode() == OFBadRequestCode.BAD_TYPE) {
491 log.debug("Received error message {} from {}", msg, dpid);
492 } else {
493 log.warn("Received error message {} from {}", msg, dpid);
494 }
Prince Pereira788797e2016-08-10 11:24:14 +0530495 handleErrorMsg(deviceId, msg);
Ray Milkey4fd3ceb2015-12-10 14:43:08 -0800496 break;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700497 default:
498 log.debug("Unhandled message type: {}", msg.getType());
alshabib8f1cf4a2014-09-17 14:44:48 -0700499 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700500 }
501
Prince Pereira788797e2016-08-10 11:24:14 +0530502 private void handleErrorMsg(DeviceId deviceId, OFMessage msg) {
503 OFErrorMsg error = (OFErrorMsg) msg;
504 OFMessage ofMessage = null;
505 switch (error.getErrType()) {
506 case BAD_ACTION:
507 OFBadActionErrorMsg baErrorMsg = (OFBadActionErrorMsg) error;
508 if (baErrorMsg.getData().getParsedMessage().isPresent()) {
509 ofMessage = baErrorMsg.getData().getParsedMessage().get();
510 }
511 break;
512 case BAD_INSTRUCTION:
513 OFBadInstructionErrorMsg biErrorMsg = (OFBadInstructionErrorMsg) error;
514 if (biErrorMsg.getData().getParsedMessage().isPresent()) {
515 ofMessage = biErrorMsg.getData().getParsedMessage().get();
516 }
517 break;
518 case BAD_MATCH:
519 OFBadMatchErrorMsg bmErrorMsg = (OFBadMatchErrorMsg) error;
520 if (bmErrorMsg.getData().getParsedMessage().isPresent()) {
521 ofMessage = bmErrorMsg.getData().getParsedMessage().get();
522 }
523 break;
524 case FLOW_MOD_FAILED:
525 OFFlowModFailedErrorMsg fmFailed = (OFFlowModFailedErrorMsg) error;
526 if (fmFailed.getData().getParsedMessage().isPresent()) {
527 ofMessage = fmFailed.getData().getParsedMessage().get();
528 }
529 break;
530 default:
531 // Do nothing.
532 return;
533 }
534 if (ofMessage != null) {
535 InternalCacheEntry entry =
536 pendingBatches.getIfPresent(msg.getXid());
537 if (entry != null) {
538 OFFlowMod ofFlowMod = (OFFlowMod) ofMessage;
539 entry.appendFailure(new FlowEntryBuilder(deviceId, ofFlowMod, driverService).build());
540 } else {
541 log.error("No matching batch for this error: {}", error);
542 }
543 } else {
544 log.error("Flow installation failed but switch didn't"
545 + " tell us which one.");
546 }
547 }
548
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700549 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700550 public void receivedRoleReply(Dpid dpid, RoleState requested,
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800551 RoleState response) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700552 // Do nothing here for now.
553 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700554
sangho89bf6fb2015-02-09 09:33:13 -0800555 private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies) {
alshabib64def642014-12-02 23:27:37 -0800556
alshabib54ce5892014-09-23 17:50:51 -0700557 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
alshabib54ce5892014-09-23 17:50:51 -0700558
alshabib64def642014-12-02 23:27:37 -0800559 List<FlowEntry> flowEntries = replies.getEntries().stream()
Jonathan Harte4e74f02016-03-03 12:57:40 -0800560 .map(entry -> new FlowEntryBuilder(did, entry, driverService).build())
alshabib64def642014-12-02 23:27:37 -0800561 .collect(Collectors.toList());
alshabib54ce5892014-09-23 17:50:51 -0700562
ssyoon9030fbcd92015-08-17 10:42:07 +0900563 if (adaptiveFlowSampling) {
564 NewAdaptiveFlowStatsCollector afsc = afsCollectors.get(dpid);
565
566 synchronized (afsc) {
567 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
568 log.debug("OpenFlowRuleProvider:pushFlowMetrics, flowMissingXid={}, "
569 + "OFFlowStatsReply Xid={}, for {}",
570 afsc.getFlowMissingXid(), replies.getXid(), dpid);
571 }
572
573 // Check that OFFlowStatsReply Xid is same with the one of OFFlowStatsRequest?
574 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
575 if (afsc.getFlowMissingXid() == replies.getXid()) {
576 // call entire flow stats update with flowMissing synchronization.
577 // used existing pushFlowMetrics
578 providerService.pushFlowMetrics(did, flowEntries);
579 }
580 // reset flowMissingXid to NO_FLOW_MISSING_XID
581 afsc.setFlowMissingXid(NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID);
582
583 } else {
584 // call individual flow stats update
585 providerService.pushFlowMetricsWithoutFlowMissing(did, flowEntries);
586 }
587
588 // Update TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
589 afsc.pushFlowMetrics(flowEntries);
590 }
591 } else {
592 // call existing entire flow stats update with flowMissing synchronization
593 providerService.pushFlowMetrics(did, flowEntries);
594 }
alshabib5c370ff2014-09-18 10:12:14 -0700595 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700596
597 private void pushTableStatistics(Dpid dpid, OFTableStatsReply replies) {
598
599 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
600 List<TableStatisticsEntry> tableStatsEntries = replies.getEntries().stream()
601 .map(entry -> buildTableStatistics(did, entry))
602 .filter(Objects::nonNull)
603 .collect(Collectors.toList());
604 providerService.pushTableStatistics(did, tableStatsEntries);
605 }
606
607 private TableStatisticsEntry buildTableStatistics(DeviceId deviceId,
608 OFTableStatsEntry ofEntry) {
609 TableStatisticsEntry entry = null;
610 if (ofEntry != null) {
611 entry = new DefaultTableStatisticsEntry(deviceId,
612 ofEntry.getTableId().getValue(),
613 ofEntry.getActiveCount(),
614 ofEntry.getLookupCount().getValue(),
615 ofEntry.getMatchedCount().getValue());
616 }
617
618 return entry;
619
620 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700621 }
alshabib1cc04f72014-09-16 16:09:58 -0700622
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800623 /**
jcc3d4e14a2015-04-21 11:32:05 +0800624 * The internal cache entry holding the original request as well as
625 * accumulating the any failures along the way.
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700626 * <p/>
jcc3d4e14a2015-04-21 11:32:05 +0800627 * If this entry is evicted from the cache then the entire operation is
628 * considered failed. Otherwise, only the failures reported by the device
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800629 * will be propagated up.
630 */
631 private class InternalCacheEntry {
alshabib902d41b2014-10-07 16:52:05 -0700632
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800633 private final FlowRuleBatchOperation operation;
634 private final Set<FlowRule> failures = Sets.newConcurrentHashSet();
alshabib193525b2014-10-08 18:58:03 -0700635
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800636 public InternalCacheEntry(FlowRuleBatchOperation operation) {
637 this.operation = operation;
alshabib902d41b2014-10-07 16:52:05 -0700638 }
639
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800640 /**
641 * Appends a failed rule to the set of failed items.
jcc3d4e14a2015-04-21 11:32:05 +0800642 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800643 * @param rule the failed rule
644 */
645 public void appendFailure(FlowRule rule) {
646 failures.add(rule);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800647 }
648
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800649 /**
650 * Fails the entire batch and returns the failed operation.
jcc3d4e14a2015-04-21 11:32:05 +0800651 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800652 * @return the failed operation
653 */
654 public CompletedBatchOperation failedCompletion() {
655 Set<FlowRule> fails = operation.getOperations().stream()
656 .map(op -> op.target()).collect(Collectors.toSet());
jcc3d4e14a2015-04-21 11:32:05 +0800657 return new CompletedBatchOperation(false,
658 Collections
659 .unmodifiableSet(fails),
660 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700661 }
662
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800663 /**
664 * Returns the completed operation and whether the batch suceeded.
jcc3d4e14a2015-04-21 11:32:05 +0800665 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800666 * @return the completed operation
667 */
668 public CompletedBatchOperation completed() {
jcc3d4e14a2015-04-21 11:32:05 +0800669 return new CompletedBatchOperation(
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700670 failures.isEmpty(),
671 Collections
672 .unmodifiableSet(failures),
673 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700674 }
alshabib902d41b2014-10-07 16:52:05 -0700675 }
alshabiba68eb962014-09-24 20:34:13 -0700676
alshabib1cc04f72014-09-16 16:09:58 -0700677}