blob: 1482addb2a6b19dcb3aeaaae0202d4e1dd932cfb [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;
Brian O'Connor72cb19a2015-01-16 16:14:41 -080064import org.projectfloodlight.openflow.protocol.OFErrorType;
alshabib193525b2014-10-08 18:58:03 -070065import org.projectfloodlight.openflow.protocol.OFFlowMod;
alshabib8f1cf4a2014-09-17 14:44:48 -070066import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
alshabib5c370ff2014-09-18 10:12:14 -070067import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
alshabib8f1cf4a2014-09-17 14:44:48 -070068import org.projectfloodlight.openflow.protocol.OFMessage;
69import org.projectfloodlight.openflow.protocol.OFPortStatus;
alshabib5c370ff2014-09-18 10:12:14 -070070import org.projectfloodlight.openflow.protocol.OFStatsReply;
sangho89bf6fb2015-02-09 09:33:13 -080071import org.projectfloodlight.openflow.protocol.OFStatsType;
Jonathan Hart3c259162015-10-21 21:31:19 -070072import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
73import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
Thomas Vachuska3358af22015-05-19 18:40:34 -070074import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
alshabib193525b2014-10-08 18:58:03 -070075import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
alshabib1cc04f72014-09-16 16:09:58 -070076import org.slf4j.Logger;
77
Thomas Vachuska75aaa672015-04-29 12:24:43 -070078import java.util.Collections;
79import java.util.Dictionary;
80import java.util.List;
81import java.util.Map;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070082import java.util.Objects;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070083import java.util.Optional;
84import java.util.Set;
85import java.util.Timer;
86import java.util.concurrent.TimeUnit;
87import java.util.stream.Collectors;
88
ssyoon9030fbcd92015-08-17 10:42:07 +090089import static com.google.common.base.Preconditions.checkNotNull;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070090import static com.google.common.base.Strings.isNullOrEmpty;
91import static org.onlab.util.Tools.get;
92import static org.slf4j.LoggerFactory.getLogger;
alshabibeec3a062014-09-17 18:01:26 -070093
alshabib1cc04f72014-09-16 16:09:58 -070094/**
jcc3d4e14a2015-04-21 11:32:05 +080095 * Provider which uses an OpenFlow controller to detect network end-station
96 * hosts.
alshabib1cc04f72014-09-16 16:09:58 -070097 */
98@Component(immediate = true)
jcc3d4e14a2015-04-21 11:32:05 +080099public class OpenFlowRuleProvider extends AbstractProvider
100 implements FlowRuleProvider {
alshabib1cc04f72014-09-16 16:09:58 -0700101
102 private final Logger log = getLogger(getClass());
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected FlowRuleProviderRegistry providerRegistry;
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected OpenFlowController controller;
109
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected ComponentConfigService cfgService;
112
Jonathan Hart3c259162015-10-21 21:31:19 -0700113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected DriverService driverService;
115
ssyoon9030fbcd92015-08-17 10:42:07 +0900116 private static final int DEFAULT_POLL_FREQUENCY = 5;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700117 @Property(name = "flowPollFrequency", intValue = DEFAULT_POLL_FREQUENCY,
118 label = "Frequency (in seconds) for polling flow statistics")
119 private int flowPollFrequency = DEFAULT_POLL_FREQUENCY;
120
Madan Jampani7a3ba962016-04-07 20:16:16 -0700121 private static final boolean DEFAULT_ADAPTIVE_FLOW_SAMPLING = false;
ssyoon9030fbcd92015-08-17 10:42:07 +0900122 @Property(name = "adaptiveFlowSampling", boolValue = DEFAULT_ADAPTIVE_FLOW_SAMPLING,
123 label = "Adaptive Flow Sampling is on or off")
124 private boolean adaptiveFlowSampling = DEFAULT_ADAPTIVE_FLOW_SAMPLING;
125
alshabib1cc04f72014-09-16 16:09:58 -0700126 private FlowRuleProviderService providerService;
127
alshabibeec3a062014-09-17 18:01:26 -0700128 private final InternalFlowProvider listener = new InternalFlowProvider();
129
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800130 private Cache<Long, InternalCacheEntry> pendingBatches;
alshabib193525b2014-10-08 18:58:03 -0700131
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700132 private final Timer timer = new Timer("onos-openflow-collector");
ssyoon9030fbcd92015-08-17 10:42:07 +0900133 private final Map<Dpid, FlowStatsCollector> simpleCollectors = Maps.newHashMap();
134
135 // NewAdaptiveFlowStatsCollector Set
136 private final Map<Dpid, NewAdaptiveFlowStatsCollector> afsCollectors = Maps.newHashMap();
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700137 private final Map<Dpid, TableStatisticsCollector> tableStatsCollectors = Maps.newHashMap();
alshabib3d643ec2014-10-22 18:33:00 -0700138
alshabib1cc04f72014-09-16 16:09:58 -0700139 /**
140 * Creates an OpenFlow host provider.
141 */
142 public OpenFlowRuleProvider() {
Brian O'Connorabafb502014-12-02 22:26:20 -0800143 super(new ProviderId("of", "org.onosproject.provider.openflow"));
alshabib1cc04f72014-09-16 16:09:58 -0700144 }
145
146 @Activate
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700147 protected void activate(ComponentContext context) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700148 cfgService.registerProperties(getClass());
alshabib1cc04f72014-09-16 16:09:58 -0700149 providerService = providerRegistry.register(this);
alshabibeec3a062014-09-17 18:01:26 -0700150 controller.addListener(listener);
151 controller.addEventListener(listener);
alshabib3d643ec2014-10-22 18:33:00 -0700152
Antonio Marsico1c5ae1f2015-12-15 15:31:56 +0100153 modified(context);
154
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700155 pendingBatches = createBatchCache();
ssyoon9030fbcd92015-08-17 10:42:07 +0900156
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700157 createCollectors();
alshabib3d643ec2014-10-22 18:33:00 -0700158
ssyoon9030fbcd92015-08-17 10:42:07 +0900159 log.info("Started with flowPollFrequency = {}, adaptiveFlowSampling = {}",
160 flowPollFrequency, adaptiveFlowSampling);
alshabib1cc04f72014-09-16 16:09:58 -0700161 }
162
163 @Deactivate
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700164 protected void deactivate(ComponentContext context) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700165 cfgService.unregisterProperties(getClass(), false);
166 stopCollectors();
alshabib1cc04f72014-09-16 16:09:58 -0700167 providerRegistry.unregister(this);
168 providerService = null;
169
170 log.info("Stopped");
171 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800172
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700173 @Modified
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700174 protected void modified(ComponentContext context) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700175 Dictionary<?, ?> properties = context.getProperties();
176 int newFlowPollFrequency;
177 try {
178 String s = get(properties, "flowPollFrequency");
179 newFlowPollFrequency = isNullOrEmpty(s) ? flowPollFrequency : Integer.parseInt(s.trim());
180
181 } catch (NumberFormatException | ClassCastException e) {
182 newFlowPollFrequency = flowPollFrequency;
183 }
184
185 if (newFlowPollFrequency != flowPollFrequency) {
186 flowPollFrequency = newFlowPollFrequency;
187 adjustRate();
188 }
189
190 log.info("Settings: flowPollFrequency={}", flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900191
192 boolean newAdaptiveFlowSampling;
193 String s = get(properties, "adaptiveFlowSampling");
194 newAdaptiveFlowSampling = isNullOrEmpty(s) ? adaptiveFlowSampling : Boolean.parseBoolean(s.trim());
195
196 if (newAdaptiveFlowSampling != adaptiveFlowSampling) {
197 // stop previous collector
198 stopCollectors();
199 adaptiveFlowSampling = newAdaptiveFlowSampling;
200 // create new collectors
201 createCollectors();
202 }
203
204 log.info("Settings: adaptiveFlowSampling={}", adaptiveFlowSampling);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700205 }
206
207 private Cache<Long, InternalCacheEntry> createBatchCache() {
208 return CacheBuilder.newBuilder()
209 .expireAfterWrite(10, TimeUnit.SECONDS)
210 .removalListener((RemovalNotification<Long, InternalCacheEntry> notification) -> {
211 if (notification.getCause() == RemovalCause.EXPIRED) {
212 providerService.batchOperationCompleted(notification.getKey(),
213 notification.getValue().failedCompletion());
214 }
215 }).build();
216 }
217
218 private void createCollectors() {
219 controller.getSwitches().forEach(this::createCollector);
220 }
221
222 private void createCollector(OpenFlowSwitch sw) {
Madan Jampani84382b92016-06-22 08:26:49 -0700223 checkNotNull(sw, "Null switch");
ssyoon9030fbcd92015-08-17 10:42:07 +0900224 if (adaptiveFlowSampling) {
225 // NewAdaptiveFlowStatsCollector Constructor
Charles Chan14967c22015-12-07 11:11:50 -0800226 NewAdaptiveFlowStatsCollector fsc =
227 new NewAdaptiveFlowStatsCollector(driverService, sw, flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900228 fsc.start();
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700229 stopCollectorIfNeeded(afsCollectors.put(new Dpid(sw.getId()), fsc));
ssyoon9030fbcd92015-08-17 10:42:07 +0900230 } else {
231 FlowStatsCollector fsc = new FlowStatsCollector(timer, sw, flowPollFrequency);
232 fsc.start();
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700233 stopCollectorIfNeeded(simpleCollectors.put(new Dpid(sw.getId()), fsc));
ssyoon9030fbcd92015-08-17 10:42:07 +0900234 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700235 TableStatisticsCollector tsc = new TableStatisticsCollector(timer, sw, flowPollFrequency);
236 tsc.start();
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700237 stopCollectorIfNeeded(tableStatsCollectors.put(new Dpid(sw.getId()), tsc));
238 }
239
240 private void stopCollectorIfNeeded(SwitchDataCollector collector) {
241 if (collector != null) {
242 collector.stop();
243 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700244 }
245
246 private void stopCollectors() {
ssyoon9030fbcd92015-08-17 10:42:07 +0900247 if (adaptiveFlowSampling) {
248 // NewAdaptiveFlowStatsCollector Destructor
249 afsCollectors.values().forEach(NewAdaptiveFlowStatsCollector::stop);
250 afsCollectors.clear();
251 } else {
252 simpleCollectors.values().forEach(FlowStatsCollector::stop);
253 simpleCollectors.clear();
254 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700255 tableStatsCollectors.values().forEach(TableStatisticsCollector::stop);
256 tableStatsCollectors.clear();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700257 }
258
259 private void adjustRate() {
260 DefaultLoad.setPollInterval(flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900261 if (adaptiveFlowSampling) {
262 // NewAdaptiveFlowStatsCollector calAndPollInterval
263 afsCollectors.values().forEach(fsc -> fsc.adjustCalAndPollInterval(flowPollFrequency));
264 } else {
265 simpleCollectors.values().forEach(fsc -> fsc.adjustPollInterval(flowPollFrequency));
266 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700267 tableStatsCollectors.values().forEach(tsc -> tsc.adjustPollInterval(flowPollFrequency));
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700268 }
269
alshabib1cc04f72014-09-16 16:09:58 -0700270 @Override
271 public void applyFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800272 for (FlowRule flowRule : flowRules) {
273 applyRule(flowRule);
alshabib35edb1a2014-09-16 17:44:44 -0700274 }
alshabib1cc04f72014-09-16 16:09:58 -0700275 }
276
alshabib35edb1a2014-09-16 17:44:44 -0700277 private void applyRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900278 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
279 OpenFlowSwitch sw = controller.getSwitch(dpid);
280
Ray Milkey0ae473d2016-04-04 10:56:47 -0700281 if (sw == null) {
282 return;
283 }
284
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700285 FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
286 if (hasPayload(flowRuleExtPayLoad)) {
287 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800288 sw.sendMsg(msg);
289 return;
290 }
alshabibbdcbb102015-04-22 14:16:38 -0700291 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Jonathan Hart3c259162015-10-21 21:31:19 -0700292 Optional.empty(), Optional.of(driverService)).buildFlowAdd());
ssyoon9030fbcd92015-08-17 10:42:07 +0900293
294 if (adaptiveFlowSampling) {
295 // Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700296 NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
297 if (collector != null) {
298 collector.addWithFlowRule(flowRule);
299 }
ssyoon9030fbcd92015-08-17 10:42:07 +0900300 }
alshabib35edb1a2014-09-16 17:44:44 -0700301 }
302
alshabib1cc04f72014-09-16 16:09:58 -0700303 @Override
304 public void removeFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800305 for (FlowRule flowRule : flowRules) {
306 removeRule(flowRule);
alshabib219ebaa2014-09-22 15:41:24 -0700307 }
alshabib1cc04f72014-09-16 16:09:58 -0700308 }
309
alshabib219ebaa2014-09-22 15:41:24 -0700310 private void removeRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900311 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
312 OpenFlowSwitch sw = controller.getSwitch(dpid);
313
Ray Milkey0ae473d2016-04-04 10:56:47 -0700314 if (sw == null) {
315 return;
316 }
317
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700318 FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
319 if (hasPayload(flowRuleExtPayLoad)) {
320 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800321 sw.sendMsg(msg);
322 return;
323 }
alshabibbdcbb102015-04-22 14:16:38 -0700324 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Jonathan Hart3c259162015-10-21 21:31:19 -0700325 Optional.empty(), Optional.of(driverService)).buildFlowDel());
ssyoon9030fbcd92015-08-17 10:42:07 +0900326
327 if (adaptiveFlowSampling) {
328 // Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700329 NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
330 if (collector != null) {
331 collector.removeFlows(flowRule);
332 }
ssyoon9030fbcd92015-08-17 10:42:07 +0900333 }
alshabib219ebaa2014-09-22 15:41:24 -0700334 }
335
alshabiba68eb962014-09-24 20:34:13 -0700336 @Override
337 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
338 // TODO: optimize using the ApplicationId
339 removeFlowRule(flowRules);
340 }
341
alshabib193525b2014-10-08 18:58:03 -0700342 @Override
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800343 public void executeBatch(FlowRuleBatchOperation batch) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900344 checkNotNull(batch);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800345
ssyoon9030fbcd92015-08-17 10:42:07 +0900346 Dpid dpid = Dpid.dpid(batch.deviceId().uri());
347 OpenFlowSwitch sw = controller.getSwitch(dpid);
Madan Jampani84382b92016-06-22 08:26:49 -0700348
349 // If switch no longer exists, simply return.
350 if (sw == null) {
351 Set<FlowRule> failures = ImmutableSet.copyOf(Lists.transform(batch.getOperations(), e -> e.target()));
352 providerService.batchOperationCompleted(batch.id(),
353 new CompletedBatchOperation(false, failures, batch.deviceId()));
354 return;
355 }
356 pendingBatches.put(batch.id(), new InternalCacheEntry(batch));
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800357 OFFlowMod mod;
alshabib193525b2014-10-08 18:58:03 -0700358 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
jcc3d4e14a2015-04-21 11:32:05 +0800359 // flow is the third party privacy flow
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700360
361 FlowRuleExtPayLoad flowRuleExtPayLoad = fbe.target().payLoad();
362 if (hasPayload(flowRuleExtPayLoad)) {
363 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800364 sw.sendMsg(msg);
365 continue;
366 }
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700367 FlowModBuilder builder =
Jonathan Hart3c259162015-10-21 21:31:19 -0700368 FlowModBuilder.builder(fbe.target(), sw.factory(),
369 Optional.of(batch.id()), Optional.of(driverService));
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700370 NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800371 switch (fbe.operator()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700372 case ADD:
373 mod = builder.buildFlowAdd();
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700374 if (adaptiveFlowSampling && collector != null) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900375 // Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700376 collector.addWithFlowRule(fbe.target());
ssyoon9030fbcd92015-08-17 10:42:07 +0900377 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700378 break;
379 case REMOVE:
380 mod = builder.buildFlowDel();
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700381 if (adaptiveFlowSampling && collector != null) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900382 // Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700383 collector.removeFlows(fbe.target());
ssyoon9030fbcd92015-08-17 10:42:07 +0900384 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700385 break;
386 case MODIFY:
387 mod = builder.buildFlowMod();
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700388 if (adaptiveFlowSampling && collector != null) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900389 // Add or Update TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
390 // afsCollectors.get(dpid).addWithFlowRule(fbe.target()); //check if add is good or not
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700391 collector.addOrUpdateFlows((FlowEntry) fbe.target());
ssyoon9030fbcd92015-08-17 10:42:07 +0900392 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700393 break;
394 default:
395 log.error("Unsupported batch operation {}; skipping flowmod {}",
ssyoon9030fbcd92015-08-17 10:42:07 +0900396 fbe.operator(), fbe);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700397 continue;
jcc3d4e14a2015-04-21 11:32:05 +0800398 }
Saurav Das3ea46622015-04-22 14:01:34 -0700399 sw.sendMsg(mod);
alshabib193525b2014-10-08 18:58:03 -0700400 }
jcc3d4e14a2015-04-21 11:32:05 +0800401 OFBarrierRequest.Builder builder = sw.factory().buildBarrierRequest()
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800402 .setXid(batch.id());
403 sw.sendMsg(builder.build());
alshabib193525b2014-10-08 18:58:03 -0700404 }
405
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700406 private boolean hasPayload(FlowRuleExtPayLoad flowRuleExtPayLoad) {
407 return flowRuleExtPayLoad != null &&
408 flowRuleExtPayLoad.payLoad() != null &&
409 flowRuleExtPayLoad.payLoad().length > 0;
410 }
411
alshabib8f1cf4a2014-09-17 14:44:48 -0700412 private class InternalFlowProvider
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800413 implements OpenFlowSwitchListener, OpenFlowEventListener {
alshabib8f1cf4a2014-09-17 14:44:48 -0700414
alshabib8f1cf4a2014-09-17 14:44:48 -0700415 @Override
416 public void switchAdded(Dpid dpid) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700417 createCollector(controller.getSwitch(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700418 }
419
420 @Override
421 public void switchRemoved(Dpid dpid) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900422 if (adaptiveFlowSampling) {
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700423 stopCollectorIfNeeded(afsCollectors.remove(dpid));
ssyoon9030fbcd92015-08-17 10:42:07 +0900424 } else {
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700425 stopCollectorIfNeeded(simpleCollectors.remove(dpid));
alshabibdfc7afb2014-10-21 20:13:27 -0700426 }
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700427 stopCollectorIfNeeded(tableStatsCollectors.remove(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700428 }
429
430 @Override
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700431 public void switchChanged(Dpid dpid) {
432 }
433
434 @Override
alshabib8f1cf4a2014-09-17 14:44:48 -0700435 public void portChanged(Dpid dpid, OFPortStatus status) {
jcc3d4e14a2015-04-21 11:32:05 +0800436 // TODO: Decide whether to evict flows internal store.
alshabib8f1cf4a2014-09-17 14:44:48 -0700437 }
438
439 @Override
440 public void handleMessage(Dpid dpid, OFMessage msg) {
Ray Milkeyada9e2d2016-04-05 16:42:35 -0700441 if (providerService == null) {
442 // We are shutting down, nothing to be done
443 return;
444 }
Jonathan Harte4e74f02016-03-03 12:57:40 -0800445 DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700446 switch (msg.getType()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700447 case FLOW_REMOVED:
448 OFFlowRemoved removed = (OFFlowRemoved) msg;
alshabib6b5cfec2014-09-18 17:42:18 -0700449
Jonathan Harte4e74f02016-03-03 12:57:40 -0800450 FlowEntry fr = new FlowEntryBuilder(deviceId, removed, driverService).build();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700451 providerService.flowRemoved(fr);
ssyoon9030fbcd92015-08-17 10:42:07 +0900452
453 if (adaptiveFlowSampling) {
454 // Removed TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700455 NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
456 if (collector != null) {
457 collector.flowRemoved(fr);
458 }
ssyoon9030fbcd92015-08-17 10:42:07 +0900459 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700460 break;
461 case STATS_REPLY:
462 if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW) {
463 pushFlowMetrics(dpid, (OFFlowStatsReply) msg);
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700464 } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.TABLE) {
465 pushTableStatistics(dpid, (OFTableStatsReply) msg);
sangho89bf6fb2015-02-09 09:33:13 -0800466 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700467 break;
468 case BARRIER_REPLY:
469 try {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700470 InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800471 if (entry != null) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700472 providerService
473 .batchOperationCompleted(msg.getXid(),
474 entry.completed());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800475 } else {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700476 log.warn("Received unknown Barrier Reply: {}",
477 msg.getXid());
478 }
479 } finally {
480 pendingBatches.invalidate(msg.getXid());
481 }
482 break;
483 case ERROR:
Thomas Vachuska3358af22015-05-19 18:40:34 -0700484 // TODO: This needs to get suppressed in a better way.
485 if (msg instanceof OFBadRequestErrorMsg &&
486 ((OFBadRequestErrorMsg) msg).getCode() == OFBadRequestCode.BAD_TYPE) {
487 log.debug("Received error message {} from {}", msg, dpid);
488 } else {
489 log.warn("Received error message {} from {}", msg, dpid);
490 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700491
492 OFErrorMsg error = (OFErrorMsg) msg;
493 if (error.getErrType() == OFErrorType.FLOW_MOD_FAILED) {
494 OFFlowModFailedErrorMsg fmFailed = (OFFlowModFailedErrorMsg) error;
495 if (fmFailed.getData().getParsedMessage().isPresent()) {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700496 OFMessage m = fmFailed.getData().getParsedMessage().get();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700497 OFFlowMod fm = (OFFlowMod) m;
Thomas Vachuska3358af22015-05-19 18:40:34 -0700498 InternalCacheEntry entry =
499 pendingBatches.getIfPresent(msg.getXid());
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700500 if (entry != null) {
Jonathan Harte4e74f02016-03-03 12:57:40 -0800501 entry.appendFailure(new FlowEntryBuilder(deviceId, fm, driverService).build());
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700502 } else {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700503 log.error("No matching batch for this error: {}", error);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700504 }
505 } else {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700506 // FIXME: Potentially add flowtracking to avoid this message.
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700507 log.error("Flow installation failed but switch didn't"
508 + " tell us which one.");
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800509 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800510 }
Ray Milkey4fd3ceb2015-12-10 14:43:08 -0800511 break;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700512 default:
513 log.debug("Unhandled message type: {}", msg.getType());
alshabib8f1cf4a2014-09-17 14:44:48 -0700514 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700515 }
516
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700517 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700518 public void receivedRoleReply(Dpid dpid, RoleState requested,
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800519 RoleState response) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700520 // Do nothing here for now.
521 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700522
sangho89bf6fb2015-02-09 09:33:13 -0800523 private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies) {
alshabib64def642014-12-02 23:27:37 -0800524
alshabib54ce5892014-09-23 17:50:51 -0700525 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
alshabib54ce5892014-09-23 17:50:51 -0700526
alshabib64def642014-12-02 23:27:37 -0800527 List<FlowEntry> flowEntries = replies.getEntries().stream()
Jonathan Harte4e74f02016-03-03 12:57:40 -0800528 .map(entry -> new FlowEntryBuilder(did, entry, driverService).build())
alshabib64def642014-12-02 23:27:37 -0800529 .collect(Collectors.toList());
alshabib54ce5892014-09-23 17:50:51 -0700530
ssyoon9030fbcd92015-08-17 10:42:07 +0900531 if (adaptiveFlowSampling) {
532 NewAdaptiveFlowStatsCollector afsc = afsCollectors.get(dpid);
533
534 synchronized (afsc) {
535 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
536 log.debug("OpenFlowRuleProvider:pushFlowMetrics, flowMissingXid={}, "
537 + "OFFlowStatsReply Xid={}, for {}",
538 afsc.getFlowMissingXid(), replies.getXid(), dpid);
539 }
540
541 // Check that OFFlowStatsReply Xid is same with the one of OFFlowStatsRequest?
542 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
543 if (afsc.getFlowMissingXid() == replies.getXid()) {
544 // call entire flow stats update with flowMissing synchronization.
545 // used existing pushFlowMetrics
546 providerService.pushFlowMetrics(did, flowEntries);
547 }
548 // reset flowMissingXid to NO_FLOW_MISSING_XID
549 afsc.setFlowMissingXid(NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID);
550
551 } else {
552 // call individual flow stats update
553 providerService.pushFlowMetricsWithoutFlowMissing(did, flowEntries);
554 }
555
556 // Update TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
557 afsc.pushFlowMetrics(flowEntries);
558 }
559 } else {
560 // call existing entire flow stats update with flowMissing synchronization
561 providerService.pushFlowMetrics(did, flowEntries);
562 }
alshabib5c370ff2014-09-18 10:12:14 -0700563 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700564
565 private void pushTableStatistics(Dpid dpid, OFTableStatsReply replies) {
566
567 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
568 List<TableStatisticsEntry> tableStatsEntries = replies.getEntries().stream()
569 .map(entry -> buildTableStatistics(did, entry))
570 .filter(Objects::nonNull)
571 .collect(Collectors.toList());
572 providerService.pushTableStatistics(did, tableStatsEntries);
573 }
574
575 private TableStatisticsEntry buildTableStatistics(DeviceId deviceId,
576 OFTableStatsEntry ofEntry) {
577 TableStatisticsEntry entry = null;
578 if (ofEntry != null) {
579 entry = new DefaultTableStatisticsEntry(deviceId,
580 ofEntry.getTableId().getValue(),
581 ofEntry.getActiveCount(),
582 ofEntry.getLookupCount().getValue(),
583 ofEntry.getMatchedCount().getValue());
584 }
585
586 return entry;
587
588 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700589 }
alshabib1cc04f72014-09-16 16:09:58 -0700590
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800591 /**
jcc3d4e14a2015-04-21 11:32:05 +0800592 * The internal cache entry holding the original request as well as
593 * accumulating the any failures along the way.
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700594 * <p/>
jcc3d4e14a2015-04-21 11:32:05 +0800595 * If this entry is evicted from the cache then the entire operation is
596 * considered failed. Otherwise, only the failures reported by the device
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800597 * will be propagated up.
598 */
599 private class InternalCacheEntry {
alshabib902d41b2014-10-07 16:52:05 -0700600
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800601 private final FlowRuleBatchOperation operation;
602 private final Set<FlowRule> failures = Sets.newConcurrentHashSet();
alshabib193525b2014-10-08 18:58:03 -0700603
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800604 public InternalCacheEntry(FlowRuleBatchOperation operation) {
605 this.operation = operation;
alshabib902d41b2014-10-07 16:52:05 -0700606 }
607
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800608 /**
609 * Appends a failed rule to the set of failed items.
jcc3d4e14a2015-04-21 11:32:05 +0800610 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800611 * @param rule the failed rule
612 */
613 public void appendFailure(FlowRule rule) {
614 failures.add(rule);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800615 }
616
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800617 /**
618 * Fails the entire batch and returns the failed operation.
jcc3d4e14a2015-04-21 11:32:05 +0800619 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800620 * @return the failed operation
621 */
622 public CompletedBatchOperation failedCompletion() {
623 Set<FlowRule> fails = operation.getOperations().stream()
624 .map(op -> op.target()).collect(Collectors.toSet());
jcc3d4e14a2015-04-21 11:32:05 +0800625 return new CompletedBatchOperation(false,
626 Collections
627 .unmodifiableSet(fails),
628 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700629 }
630
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800631 /**
632 * Returns the completed operation and whether the batch suceeded.
jcc3d4e14a2015-04-21 11:32:05 +0800633 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800634 * @return the completed operation
635 */
636 public CompletedBatchOperation completed() {
jcc3d4e14a2015-04-21 11:32:05 +0800637 return new CompletedBatchOperation(
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700638 failures.isEmpty(),
639 Collections
640 .unmodifiableSet(failures),
641 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700642 }
alshabib902d41b2014-10-07 16:52:05 -0700643 }
alshabiba68eb962014-09-24 20:34:13 -0700644
alshabib1cc04f72014-09-16 16:09:58 -0700645}