blob: bc06fe66a861a34c2869daf8d7f90396066a6a5b [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2014-present Open Networking Foundation
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
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -070027import io.netty.buffer.ByteBuf;
28import io.netty.buffer.Unpooled;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070029import org.osgi.service.component.annotations.Activate;
30import org.osgi.service.component.annotations.Component;
31import org.osgi.service.component.annotations.Deactivate;
32import org.osgi.service.component.annotations.Modified;
33import org.osgi.service.component.annotations.Reference;
34import org.osgi.service.component.annotations.ReferenceCardinality;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070035import org.onosproject.cfg.ComponentConfigService;
Brian O'Connorabafb502014-12-02 22:26:20 -080036import org.onosproject.core.ApplicationId;
37import org.onosproject.net.DeviceId;
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -030038import org.onosproject.net.driver.DefaultDriverData;
39import org.onosproject.net.driver.DefaultDriverHandler;
40import org.onosproject.net.driver.Driver;
41import org.onosproject.net.driver.DriverHandler;
Jonathan Hart3c259162015-10-21 21:31:19 -070042import org.onosproject.net.driver.DriverService;
Brian O'Connorabafb502014-12-02 22:26:20 -080043import org.onosproject.net.flow.CompletedBatchOperation;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070044import org.onosproject.net.flow.DefaultTableStatisticsEntry;
Brian O'Connorabafb502014-12-02 22:26:20 -080045import org.onosproject.net.flow.FlowEntry;
46import org.onosproject.net.flow.FlowRule;
Ray Milkey7bf273c2017-09-27 16:15:15 -070047import org.onosproject.net.flow.oldbatch.FlowRuleBatchEntry;
48import org.onosproject.net.flow.oldbatch.FlowRuleBatchOperation;
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -070049import org.onosproject.net.flow.FlowRuleExtPayLoad;
Brian O'Connorabafb502014-12-02 22:26:20 -080050import org.onosproject.net.flow.FlowRuleProvider;
51import org.onosproject.net.flow.FlowRuleProviderRegistry;
52import org.onosproject.net.flow.FlowRuleProviderService;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070053import org.onosproject.net.flow.TableStatisticsEntry;
Brian O'Connorabafb502014-12-02 22:26:20 -080054import org.onosproject.net.provider.AbstractProvider;
55import org.onosproject.net.provider.ProviderId;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070056import org.onosproject.net.statistic.DefaultLoad;
Brian O'Connorabafb502014-12-02 22:26:20 -080057import org.onosproject.openflow.controller.Dpid;
58import org.onosproject.openflow.controller.OpenFlowController;
59import org.onosproject.openflow.controller.OpenFlowEventListener;
60import org.onosproject.openflow.controller.OpenFlowSwitch;
61import org.onosproject.openflow.controller.OpenFlowSwitchListener;
62import org.onosproject.openflow.controller.RoleState;
jcc3d4e14a2015-04-21 11:32:05 +080063import org.onosproject.openflow.controller.ThirdPartyMessage;
Thomas Vachuska95caba32016-04-04 10:42:05 -070064import org.onosproject.provider.of.flow.util.FlowEntryBuilder;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070065import org.osgi.service.component.ComponentContext;
Thomas Vachuska3358af22015-05-19 18:40:34 -070066import org.projectfloodlight.openflow.protocol.OFBadRequestCode;
alshabib902d41b2014-10-07 16:52:05 -070067import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
Laszlo Pappedadbe22017-12-14 20:05:49 +000068import org.projectfloodlight.openflow.protocol.OFCapabilities;
alshabib902d41b2014-10-07 16:52:05 -070069import org.projectfloodlight.openflow.protocol.OFErrorMsg;
Cem Türker3baff672017-10-12 15:09:01 +030070import org.projectfloodlight.openflow.protocol.OFFlowLightweightStatsReply;
alshabib193525b2014-10-08 18:58:03 -070071import org.projectfloodlight.openflow.protocol.OFFlowMod;
alshabib8f1cf4a2014-09-17 14:44:48 -070072import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
alshabib5c370ff2014-09-18 10:12:14 -070073import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
alshabib8f1cf4a2014-09-17 14:44:48 -070074import org.projectfloodlight.openflow.protocol.OFMessage;
75import org.projectfloodlight.openflow.protocol.OFPortStatus;
alshabib5c370ff2014-09-18 10:12:14 -070076import org.projectfloodlight.openflow.protocol.OFStatsReply;
sangho89bf6fb2015-02-09 09:33:13 -080077import org.projectfloodlight.openflow.protocol.OFStatsType;
Jonathan Hart3c259162015-10-21 21:31:19 -070078import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
79import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
Prince Pereira141ed812016-09-02 19:03:18 +053080import org.projectfloodlight.openflow.protocol.OFType;
81import org.projectfloodlight.openflow.protocol.OFVersion;
Prince Pereira788797e2016-08-10 11:24:14 +053082import org.projectfloodlight.openflow.protocol.errormsg.OFBadActionErrorMsg;
83import org.projectfloodlight.openflow.protocol.errormsg.OFBadInstructionErrorMsg;
84import org.projectfloodlight.openflow.protocol.errormsg.OFBadMatchErrorMsg;
Thomas Vachuska3358af22015-05-19 18:40:34 -070085import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
alshabib193525b2014-10-08 18:58:03 -070086import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
Prince Pereira141ed812016-09-02 19:03:18 +053087import org.projectfloodlight.openflow.types.U16;
88import org.projectfloodlight.openflow.types.U64;
alshabib1cc04f72014-09-16 16:09:58 -070089import org.slf4j.Logger;
90
Thomas Vachuska75aaa672015-04-29 12:24:43 -070091import java.util.Collections;
92import java.util.Dictionary;
93import java.util.List;
94import java.util.Map;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070095import java.util.Objects;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070096import java.util.Optional;
97import java.util.Set;
98import java.util.Timer;
99import java.util.concurrent.TimeUnit;
100import java.util.stream.Collectors;
101
ssyoon9030fbcd92015-08-17 10:42:07 +0900102import static com.google.common.base.Preconditions.checkNotNull;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700103import static com.google.common.base.Strings.isNullOrEmpty;
104import static org.onlab.util.Tools.get;
Thomas Vachuska4167c3f2018-10-16 07:16:31 -0700105import static org.onosproject.provider.of.flow.impl.OsgiPropertyConstants.*;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700106import static org.slf4j.LoggerFactory.getLogger;
alshabibeec3a062014-09-17 18:01:26 -0700107
alshabib1cc04f72014-09-16 16:09:58 -0700108/**
jcc3d4e14a2015-04-21 11:32:05 +0800109 * Provider which uses an OpenFlow controller to detect network end-station
110 * hosts.
alshabib1cc04f72014-09-16 16:09:58 -0700111 */
Thomas Vachuska4167c3f2018-10-16 07:16:31 -0700112@Component(immediate = true,
113 property = {
114 POLL_FREQUENCY + ":Integer=" + POLL_FREQUENCY_DEFAULT,
115 ADAPTIVE_FLOW_SAMPLING + ":Boolean=" + ADAPTIVE_FLOW_SAMPLING_DEFAULT,
116 })
jcc3d4e14a2015-04-21 11:32:05 +0800117public class OpenFlowRuleProvider extends AbstractProvider
118 implements FlowRuleProvider {
alshabib1cc04f72014-09-16 16:09:58 -0700119
120 private final Logger log = getLogger(getClass());
121
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700122 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib1cc04f72014-09-16 16:09:58 -0700123 protected FlowRuleProviderRegistry providerRegistry;
124
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700125 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib1cc04f72014-09-16 16:09:58 -0700126 protected OpenFlowController controller;
127
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700128 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700129 protected ComponentConfigService cfgService;
130
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700131 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart3c259162015-10-21 21:31:19 -0700132 protected DriverService driverService;
133
Prince Pereira141ed812016-09-02 19:03:18 +0530134 private static final int MIN_EXPECTED_BYTE_LEN = 56;
135 private static final int SKIP_BYTES = 4;
Prince Pereira141ed812016-09-02 19:03:18 +0530136
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700137 //@Property(name = "flowPollFrequency", intValue = DEFAULT_POLL_FREQUENCY,
138 // label = "Frequency (in seconds) for polling flow statistics")
Thomas Vachuska4167c3f2018-10-16 07:16:31 -0700139 private int flowPollFrequency = POLL_FREQUENCY_DEFAULT;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700140
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700141 //@Property(name = "adaptiveFlowSampling", boolValue = DEFAULT_ADAPTIVE_FLOW_SAMPLING,
142 // label = "Adaptive Flow Sampling is on or off")
Thomas Vachuska4167c3f2018-10-16 07:16:31 -0700143 private boolean adaptiveFlowSampling = ADAPTIVE_FLOW_SAMPLING_DEFAULT;
ssyoon9030fbcd92015-08-17 10:42:07 +0900144
alshabib1cc04f72014-09-16 16:09:58 -0700145 private FlowRuleProviderService providerService;
146
alshabibeec3a062014-09-17 18:01:26 -0700147 private final InternalFlowProvider listener = new InternalFlowProvider();
148
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800149 private Cache<Long, InternalCacheEntry> pendingBatches;
alshabib193525b2014-10-08 18:58:03 -0700150
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900151 private final Timer timer = new Timer("onos-openflow-collector");
152
Cem Türker3baff672017-10-12 15:09:01 +0300153
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900154 // Old simple collector set
Madan Jampani6b266102016-06-23 00:56:36 -0700155 private final Map<Dpid, FlowStatsCollector> simpleCollectors = Maps.newConcurrentMap();
ssyoon9030fbcd92015-08-17 10:42:07 +0900156
157 // NewAdaptiveFlowStatsCollector Set
Madan Jampani6b266102016-06-23 00:56:36 -0700158 private final Map<Dpid, NewAdaptiveFlowStatsCollector> afsCollectors = Maps.newConcurrentMap();
159 private final Map<Dpid, TableStatisticsCollector> tableStatsCollectors = Maps.newConcurrentMap();
alshabib3d643ec2014-10-22 18:33:00 -0700160
alshabib1cc04f72014-09-16 16:09:58 -0700161 /**
162 * Creates an OpenFlow host provider.
163 */
164 public OpenFlowRuleProvider() {
Brian O'Connorabafb502014-12-02 22:26:20 -0800165 super(new ProviderId("of", "org.onosproject.provider.openflow"));
alshabib1cc04f72014-09-16 16:09:58 -0700166 }
167
168 @Activate
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700169 protected void activate(ComponentContext context) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700170 cfgService.registerProperties(getClass());
alshabib1cc04f72014-09-16 16:09:58 -0700171 providerService = providerRegistry.register(this);
alshabibeec3a062014-09-17 18:01:26 -0700172 controller.addListener(listener);
173 controller.addEventListener(listener);
alshabib3d643ec2014-10-22 18:33:00 -0700174
Antonio Marsico1c5ae1f2015-12-15 15:31:56 +0100175 modified(context);
176
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700177 pendingBatches = createBatchCache();
ssyoon9030fbcd92015-08-17 10:42:07 +0900178
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700179 createCollectors();
alshabib3d643ec2014-10-22 18:33:00 -0700180
ssyoon9030fbcd92015-08-17 10:42:07 +0900181 log.info("Started with flowPollFrequency = {}, adaptiveFlowSampling = {}",
182 flowPollFrequency, adaptiveFlowSampling);
alshabib1cc04f72014-09-16 16:09:58 -0700183 }
184
185 @Deactivate
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700186 protected void deactivate(ComponentContext context) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700187 cfgService.unregisterProperties(getClass(), false);
188 stopCollectors();
alshabib1cc04f72014-09-16 16:09:58 -0700189 providerRegistry.unregister(this);
190 providerService = null;
191
192 log.info("Stopped");
193 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800194
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700195 @Modified
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700196 protected void modified(ComponentContext context) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700197 Dictionary<?, ?> properties = context.getProperties();
198 int newFlowPollFrequency;
199 try {
Thomas Vachuska4167c3f2018-10-16 07:16:31 -0700200 String s = get(properties, POLL_FREQUENCY);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700201 newFlowPollFrequency = isNullOrEmpty(s) ? flowPollFrequency : Integer.parseInt(s.trim());
202
203 } catch (NumberFormatException | ClassCastException e) {
204 newFlowPollFrequency = flowPollFrequency;
205 }
206
207 if (newFlowPollFrequency != flowPollFrequency) {
208 flowPollFrequency = newFlowPollFrequency;
209 adjustRate();
210 }
211
212 log.info("Settings: flowPollFrequency={}", flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900213
214 boolean newAdaptiveFlowSampling;
Thomas Vachuska4167c3f2018-10-16 07:16:31 -0700215 String s = get(properties, ADAPTIVE_FLOW_SAMPLING);
ssyoon9030fbcd92015-08-17 10:42:07 +0900216 newAdaptiveFlowSampling = isNullOrEmpty(s) ? adaptiveFlowSampling : Boolean.parseBoolean(s.trim());
217
218 if (newAdaptiveFlowSampling != adaptiveFlowSampling) {
219 // stop previous collector
220 stopCollectors();
221 adaptiveFlowSampling = newAdaptiveFlowSampling;
222 // create new collectors
223 createCollectors();
224 }
225
226 log.info("Settings: adaptiveFlowSampling={}", adaptiveFlowSampling);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700227 }
228
229 private Cache<Long, InternalCacheEntry> createBatchCache() {
230 return CacheBuilder.newBuilder()
231 .expireAfterWrite(10, TimeUnit.SECONDS)
232 .removalListener((RemovalNotification<Long, InternalCacheEntry> notification) -> {
233 if (notification.getCause() == RemovalCause.EXPIRED) {
234 providerService.batchOperationCompleted(notification.getKey(),
235 notification.getValue().failedCompletion());
236 }
237 }).build();
238 }
239
240 private void createCollectors() {
241 controller.getSwitches().forEach(this::createCollector);
242 }
243
244 private void createCollector(OpenFlowSwitch sw) {
Kavitha Alagesan6704df32016-08-18 15:15:31 +0530245 if (sw == null) {
246 return;
247 }
Laszlo Papp58174812018-01-16 13:29:47 +0000248 if (sw.features().getCapabilities().contains(OFCapabilities.FLOW_STATS)) {
249 if (adaptiveFlowSampling) {
250 // NewAdaptiveFlowStatsCollector Constructor
251 NewAdaptiveFlowStatsCollector fsc =
252 new NewAdaptiveFlowStatsCollector(driverService, sw, flowPollFrequency);
253 stopCollectorIfNeeded(afsCollectors.put(new Dpid(sw.getId()), fsc));
254 fsc.start();
255 } else {
256 FlowStatsCollector fsc = new FlowStatsCollector(timer, sw, flowPollFrequency);
257 stopCollectorIfNeeded(simpleCollectors.put(new Dpid(sw.getId()), fsc));
258 fsc.start();
259 }
ssyoon9030fbcd92015-08-17 10:42:07 +0900260 }
Laszlo Pappedadbe22017-12-14 20:05:49 +0000261 if (sw.features().getCapabilities().contains(OFCapabilities.TABLE_STATS)) {
262 TableStatisticsCollector tsc = new TableStatisticsCollector(timer, sw, flowPollFrequency);
263 stopCollectorIfNeeded(tableStatsCollectors.put(new Dpid(sw.getId()), tsc));
264 tsc.start();
265 }
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700266 }
267
268 private void stopCollectorIfNeeded(SwitchDataCollector collector) {
269 if (collector != null) {
270 collector.stop();
271 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700272 }
273
274 private void stopCollectors() {
ssyoon9030fbcd92015-08-17 10:42:07 +0900275 if (adaptiveFlowSampling) {
276 // NewAdaptiveFlowStatsCollector Destructor
277 afsCollectors.values().forEach(NewAdaptiveFlowStatsCollector::stop);
278 afsCollectors.clear();
279 } else {
280 simpleCollectors.values().forEach(FlowStatsCollector::stop);
281 simpleCollectors.clear();
282 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700283 tableStatsCollectors.values().forEach(TableStatisticsCollector::stop);
284 tableStatsCollectors.clear();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700285 }
286
287 private void adjustRate() {
288 DefaultLoad.setPollInterval(flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900289 if (adaptiveFlowSampling) {
290 // NewAdaptiveFlowStatsCollector calAndPollInterval
291 afsCollectors.values().forEach(fsc -> fsc.adjustCalAndPollInterval(flowPollFrequency));
292 } else {
293 simpleCollectors.values().forEach(fsc -> fsc.adjustPollInterval(flowPollFrequency));
294 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700295 tableStatsCollectors.values().forEach(tsc -> tsc.adjustPollInterval(flowPollFrequency));
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700296 }
297
alshabib1cc04f72014-09-16 16:09:58 -0700298 @Override
299 public void applyFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800300 for (FlowRule flowRule : flowRules) {
301 applyRule(flowRule);
alshabib35edb1a2014-09-16 17:44:44 -0700302 }
alshabib1cc04f72014-09-16 16:09:58 -0700303 }
304
alshabib35edb1a2014-09-16 17:44:44 -0700305 private void applyRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900306 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
307 OpenFlowSwitch sw = controller.getSwitch(dpid);
308
Ray Milkey0ae473d2016-04-04 10:56:47 -0700309 if (sw == null) {
310 return;
311 }
312
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700313 FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
314 if (hasPayload(flowRuleExtPayLoad)) {
315 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800316 sw.sendMsg(msg);
317 return;
318 }
alshabibbdcbb102015-04-22 14:16:38 -0700319 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Jonathan Hart3c259162015-10-21 21:31:19 -0700320 Optional.empty(), Optional.of(driverService)).buildFlowAdd());
alshabib35edb1a2014-09-16 17:44:44 -0700321 }
322
alshabib1cc04f72014-09-16 16:09:58 -0700323 @Override
324 public void removeFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800325 for (FlowRule flowRule : flowRules) {
326 removeRule(flowRule);
alshabib219ebaa2014-09-22 15:41:24 -0700327 }
alshabib1cc04f72014-09-16 16:09:58 -0700328 }
329
alshabib219ebaa2014-09-22 15:41:24 -0700330 private void removeRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900331 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
332 OpenFlowSwitch sw = controller.getSwitch(dpid);
333
Ray Milkey0ae473d2016-04-04 10:56:47 -0700334 if (sw == null) {
335 return;
336 }
337
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700338 FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
339 if (hasPayload(flowRuleExtPayLoad)) {
340 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800341 sw.sendMsg(msg);
342 return;
343 }
alshabibbdcbb102015-04-22 14:16:38 -0700344 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Jonathan Hart3c259162015-10-21 21:31:19 -0700345 Optional.empty(), Optional.of(driverService)).buildFlowDel());
alshabib219ebaa2014-09-22 15:41:24 -0700346 }
347
alshabiba68eb962014-09-24 20:34:13 -0700348 @Override
349 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
350 // TODO: optimize using the ApplicationId
351 removeFlowRule(flowRules);
352 }
353
alshabib193525b2014-10-08 18:58:03 -0700354 @Override
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800355 public void executeBatch(FlowRuleBatchOperation batch) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900356 checkNotNull(batch);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800357
ssyoon9030fbcd92015-08-17 10:42:07 +0900358 Dpid dpid = Dpid.dpid(batch.deviceId().uri());
359 OpenFlowSwitch sw = controller.getSwitch(dpid);
Madan Jampani84382b92016-06-22 08:26:49 -0700360
361 // If switch no longer exists, simply return.
362 if (sw == null) {
363 Set<FlowRule> failures = ImmutableSet.copyOf(Lists.transform(batch.getOperations(), e -> e.target()));
364 providerService.batchOperationCompleted(batch.id(),
365 new CompletedBatchOperation(false, failures, batch.deviceId()));
366 return;
367 }
368 pendingBatches.put(batch.id(), new InternalCacheEntry(batch));
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800369 OFFlowMod mod;
alshabib193525b2014-10-08 18:58:03 -0700370 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
jcc3d4e14a2015-04-21 11:32:05 +0800371 // flow is the third party privacy flow
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700372
373 FlowRuleExtPayLoad flowRuleExtPayLoad = fbe.target().payLoad();
374 if (hasPayload(flowRuleExtPayLoad)) {
375 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800376 sw.sendMsg(msg);
377 continue;
378 }
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700379 FlowModBuilder builder =
Jonathan Hart3c259162015-10-21 21:31:19 -0700380 FlowModBuilder.builder(fbe.target(), sw.factory(),
381 Optional.of(batch.id()), Optional.of(driverService));
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800382 switch (fbe.operator()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700383 case ADD:
384 mod = builder.buildFlowAdd();
385 break;
386 case REMOVE:
387 mod = builder.buildFlowDel();
388 break;
389 case MODIFY:
390 mod = builder.buildFlowMod();
391 break;
392 default:
393 log.error("Unsupported batch operation {}; skipping flowmod {}",
ssyoon9030fbcd92015-08-17 10:42:07 +0900394 fbe.operator(), fbe);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700395 continue;
jcc3d4e14a2015-04-21 11:32:05 +0800396 }
Saurav Das3ea46622015-04-22 14:01:34 -0700397 sw.sendMsg(mod);
alshabib193525b2014-10-08 18:58:03 -0700398 }
jcc3d4e14a2015-04-21 11:32:05 +0800399 OFBarrierRequest.Builder builder = sw.factory().buildBarrierRequest()
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800400 .setXid(batch.id());
401 sw.sendMsg(builder.build());
alshabib193525b2014-10-08 18:58:03 -0700402 }
403
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700404 private boolean hasPayload(FlowRuleExtPayLoad flowRuleExtPayLoad) {
405 return flowRuleExtPayLoad != null &&
406 flowRuleExtPayLoad.payLoad() != null &&
407 flowRuleExtPayLoad.payLoad().length > 0;
408 }
409
alshabib8f1cf4a2014-09-17 14:44:48 -0700410 private class InternalFlowProvider
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800411 implements OpenFlowSwitchListener, OpenFlowEventListener {
alshabib8f1cf4a2014-09-17 14:44:48 -0700412
alshabib8f1cf4a2014-09-17 14:44:48 -0700413 @Override
414 public void switchAdded(Dpid dpid) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700415 createCollector(controller.getSwitch(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700416 }
417
418 @Override
419 public void switchRemoved(Dpid dpid) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900420 if (adaptiveFlowSampling) {
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700421 stopCollectorIfNeeded(afsCollectors.remove(dpid));
ssyoon9030fbcd92015-08-17 10:42:07 +0900422 } else {
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700423 stopCollectorIfNeeded(simpleCollectors.remove(dpid));
alshabibdfc7afb2014-10-21 20:13:27 -0700424 }
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700425 stopCollectorIfNeeded(tableStatsCollectors.remove(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700426 }
427
428 @Override
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700429 public void switchChanged(Dpid dpid) {
430 }
431
432 @Override
alshabib8f1cf4a2014-09-17 14:44:48 -0700433 public void portChanged(Dpid dpid, OFPortStatus status) {
jcc3d4e14a2015-04-21 11:32:05 +0800434 // TODO: Decide whether to evict flows internal store.
alshabib8f1cf4a2014-09-17 14:44:48 -0700435 }
436
437 @Override
438 public void handleMessage(Dpid dpid, OFMessage msg) {
Ray Milkeyada9e2d2016-04-05 16:42:35 -0700439 if (providerService == null) {
440 // We are shutting down, nothing to be done
441 return;
442 }
Jonathan Harte4e74f02016-03-03 12:57:40 -0800443 DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700444 switch (msg.getType()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700445 case FLOW_REMOVED:
446 OFFlowRemoved removed = (OFFlowRemoved) msg;
alshabib6b5cfec2014-09-18 17:42:18 -0700447
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300448 FlowEntry fr = new FlowEntryBuilder(deviceId, removed, getDriver(deviceId)).build();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700449 providerService.flowRemoved(fr);
450 break;
451 case STATS_REPLY:
452 if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW) {
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300453 pushFlowMetrics(dpid, (OFFlowStatsReply) msg, getDriver(deviceId));
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700454 } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.TABLE) {
455 pushTableStatistics(dpid, (OFTableStatsReply) msg);
Cem Türker3baff672017-10-12 15:09:01 +0300456 } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW_LIGHTWEIGHT) {
457 pushFlowLightWeightMetrics(dpid, (OFFlowLightweightStatsReply) msg);
sangho89bf6fb2015-02-09 09:33:13 -0800458 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700459 break;
460 case BARRIER_REPLY:
461 try {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700462 InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800463 if (entry != null) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700464 providerService
465 .batchOperationCompleted(msg.getXid(),
466 entry.completed());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800467 } else {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700468 log.warn("Received unknown Barrier Reply: {}",
469 msg.getXid());
470 }
471 } finally {
472 pendingBatches.invalidate(msg.getXid());
473 }
474 break;
475 case ERROR:
Thomas Vachuska3358af22015-05-19 18:40:34 -0700476 // TODO: This needs to get suppressed in a better way.
477 if (msg instanceof OFBadRequestErrorMsg &&
478 ((OFBadRequestErrorMsg) msg).getCode() == OFBadRequestCode.BAD_TYPE) {
479 log.debug("Received error message {} from {}", msg, dpid);
480 } else {
481 log.warn("Received error message {} from {}", msg, dpid);
482 }
Prince Pereira788797e2016-08-10 11:24:14 +0530483 handleErrorMsg(deviceId, msg);
Ray Milkey4fd3ceb2015-12-10 14:43:08 -0800484 break;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700485 default:
486 log.debug("Unhandled message type: {}", msg.getType());
alshabib8f1cf4a2014-09-17 14:44:48 -0700487 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700488 }
489
Prince Pereira788797e2016-08-10 11:24:14 +0530490 private void handleErrorMsg(DeviceId deviceId, OFMessage msg) {
Prince Pereira141ed812016-09-02 19:03:18 +0530491 InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
Prince Pereira788797e2016-08-10 11:24:14 +0530492 OFErrorMsg error = (OFErrorMsg) msg;
493 OFMessage ofMessage = null;
494 switch (error.getErrType()) {
495 case BAD_ACTION:
496 OFBadActionErrorMsg baErrorMsg = (OFBadActionErrorMsg) error;
497 if (baErrorMsg.getData().getParsedMessage().isPresent()) {
498 ofMessage = baErrorMsg.getData().getParsedMessage().get();
499 }
500 break;
501 case BAD_INSTRUCTION:
502 OFBadInstructionErrorMsg biErrorMsg = (OFBadInstructionErrorMsg) error;
503 if (biErrorMsg.getData().getParsedMessage().isPresent()) {
504 ofMessage = biErrorMsg.getData().getParsedMessage().get();
505 }
506 break;
507 case BAD_MATCH:
508 OFBadMatchErrorMsg bmErrorMsg = (OFBadMatchErrorMsg) error;
509 if (bmErrorMsg.getData().getParsedMessage().isPresent()) {
510 ofMessage = bmErrorMsg.getData().getParsedMessage().get();
511 }
512 break;
513 case FLOW_MOD_FAILED:
514 OFFlowModFailedErrorMsg fmFailed = (OFFlowModFailedErrorMsg) error;
515 if (fmFailed.getData().getParsedMessage().isPresent()) {
516 ofMessage = fmFailed.getData().getParsedMessage().get();
517 }
518 break;
519 default:
520 // Do nothing.
521 return;
522 }
Prince Pereira141ed812016-09-02 19:03:18 +0530523
Prince Pereira788797e2016-08-10 11:24:14 +0530524 if (ofMessage != null) {
Prince Pereira141ed812016-09-02 19:03:18 +0530525
Prince Pereira788797e2016-08-10 11:24:14 +0530526 if (entry != null) {
527 OFFlowMod ofFlowMod = (OFFlowMod) ofMessage;
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300528 entry.appendFailure(new FlowEntryBuilder(deviceId, ofFlowMod, getDriver(deviceId)).build());
Prince Pereira788797e2016-08-10 11:24:14 +0530529 } else {
530 log.error("No matching batch for this error: {}", error);
531 }
Prince Pereira141ed812016-09-02 19:03:18 +0530532
Prince Pereira788797e2016-08-10 11:24:14 +0530533 } else {
Prince Pereira141ed812016-09-02 19:03:18 +0530534
535 U64 cookieId = readCookieIdFromOFErrorMsg(error, msg.getVersion());
536
537 if (cookieId != null) {
538 long flowId = cookieId.getValue();
539
540 if (entry != null) {
541 for (FlowRuleBatchEntry fbEntry : entry.operation.getOperations()) {
542 if (fbEntry.target().id().value() == flowId) {
543 entry.appendFailure(fbEntry.target());
544 break;
545 }
546 }
547 } else {
548 log.error("No matching batch for this error: {}", error);
549 }
550
551 } else {
552 log.error("Flow installation failed but switch " +
553 "didn't tell us which one.");
554 }
Prince Pereira788797e2016-08-10 11:24:14 +0530555 }
556 }
557
Prince Pereira141ed812016-09-02 19:03:18 +0530558 /**
559 * Reading cookieId from OFErrorMsg.
560 *
561 * Loxigen OpenFlow API failed in parsing error messages because of
562 * 64 byte data truncation based on OpenFlow specs. The method written
563 * is a workaround to extract the cookieId from the packet till the
564 * issue is resolved in Loxigen OpenFlow code.
565 * Ref: https://groups.google.com/a/onosproject.org/forum/#!topic
566 * /onos-dev/_KwlHZDllLE
567 *
568 * @param msg OF error message
569 * @param ofVersion Openflow version
570 * @return cookieId
571 */
572 private U64 readCookieIdFromOFErrorMsg(OFErrorMsg msg,
573 OFVersion ofVersion) {
574
575 if (ofVersion.wireVersion < OFVersion.OF_13.wireVersion) {
576 log.debug("Unhandled error msg with OF version {} " +
577 "which is less than {}",
578 ofVersion, OFVersion.OF_13);
579 return null;
580 }
581
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700582 ByteBuf bb = Unpooled.wrappedBuffer(msg.getData().getData());
Prince Pereira141ed812016-09-02 19:03:18 +0530583
584 if (bb.readableBytes() < MIN_EXPECTED_BYTE_LEN) {
585 log.debug("Wrong length: Expected to be >= {}, was: {}",
586 MIN_EXPECTED_BYTE_LEN, bb.readableBytes());
587 return null;
588 }
589
590 byte ofVer = bb.readByte();
591
592 if (ofVer != ofVersion.wireVersion) {
593 log.debug("Wrong version: Expected={}, got={}",
594 ofVersion.wireVersion, ofVer);
595 return null;
596 }
597
598 byte type = bb.readByte();
599
600 if (type != OFType.FLOW_MOD.ordinal()) {
601 log.debug("Wrong type: Expected={}, got={}",
602 OFType.FLOW_MOD.ordinal(), type);
603 return null;
604 }
605
606 int length = U16.f(bb.readShort());
607
608 if (length < MIN_EXPECTED_BYTE_LEN) {
609 log.debug("Wrong length: Expected to be >= {}, was: {}",
610 MIN_EXPECTED_BYTE_LEN, length);
611 return null;
612 }
613
614 bb.skipBytes(SKIP_BYTES);
615 return U64.ofRaw(bb.readLong());
616 }
617
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700618 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700619 public void receivedRoleReply(Dpid dpid, RoleState requested,
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800620 RoleState response) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700621 // Do nothing here for now.
622 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700623
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300624 private DriverHandler getDriver(DeviceId devId) {
625 Driver driver = driverService.getDriver(devId);
626 DriverHandler handler = new DefaultDriverHandler(new DefaultDriverData(driver, devId));
627 return handler;
628 }
629
630 private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies, DriverHandler handler) {
alshabib64def642014-12-02 23:27:37 -0800631
alshabib54ce5892014-09-23 17:50:51 -0700632 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900633 NewAdaptiveFlowStatsCollector afsc = afsCollectors.get(dpid);
alshabib54ce5892014-09-23 17:50:51 -0700634
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900635 if (adaptiveFlowSampling && afsc != null) {
636 List<FlowEntry> flowEntries = replies.getEntries().stream()
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300637 .map(entry -> new FlowEntryBuilder(did, entry, handler).withSetAfsc(afsc).build())
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900638 .collect(Collectors.toList());
alshabib54ce5892014-09-23 17:50:51 -0700639
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900640 // Check that OFFlowStatsReply Xid is same with the one of OFFlowStatsRequest?
641 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
642 log.debug("OpenFlowRuleProvider:pushFlowMetrics, flowMissingXid={}, "
643 + "OFFlowStatsReply Xid={}, for {}",
644 afsc.getFlowMissingXid(), replies.getXid(), dpid);
645 if (afsc.getFlowMissingXid() == replies.getXid()) {
646 // call entire flow stats update with flowMissing synchronization.
647 // used existing pushFlowMetrics
648 providerService.pushFlowMetrics(did, flowEntries);
ssyoon9030fbcd92015-08-17 10:42:07 +0900649 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900650 // reset flowMissingXid to NO_FLOW_MISSING_XID
651 afsc.setFlowMissingXid(NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID);
652 } else {
653 // call individual flow stats update
654 providerService.pushFlowMetricsWithoutFlowMissing(did, flowEntries);
ssyoon9030fbcd92015-08-17 10:42:07 +0900655 }
656 } else {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900657 List<FlowEntry> flowEntries = replies.getEntries().stream()
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300658 .map(entry -> new FlowEntryBuilder(did, entry, handler).build())
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900659 .collect(Collectors.toList());
660
ssyoon9030fbcd92015-08-17 10:42:07 +0900661 // call existing entire flow stats update with flowMissing synchronization
662 providerService.pushFlowMetrics(did, flowEntries);
663 }
alshabib5c370ff2014-09-18 10:12:14 -0700664 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700665
666 private void pushTableStatistics(Dpid dpid, OFTableStatsReply replies) {
667
668 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
669 List<TableStatisticsEntry> tableStatsEntries = replies.getEntries().stream()
670 .map(entry -> buildTableStatistics(did, entry))
671 .filter(Objects::nonNull)
672 .collect(Collectors.toList());
673 providerService.pushTableStatistics(did, tableStatsEntries);
674 }
675
Cem Türker3baff672017-10-12 15:09:01 +0300676 private void pushFlowLightWeightMetrics(Dpid dpid, OFFlowLightweightStatsReply replies) {
677
678 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
679 NewAdaptiveFlowStatsCollector afsc = afsCollectors.get(dpid);
680 if (adaptiveFlowSampling && afsc != null) {
681 List<FlowEntry> flowEntries = replies.getEntries().stream()
682 .map(entry -> new FlowEntryBuilder(did, entry, driverService).withSetAfsc(afsc).build())
683 .collect(Collectors.toList());
684
685 // Check that OFFlowStatsReply Xid is same with the one of OFFlowStatsRequest?
686 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
687 log.debug("OpenFlowRuleProvider:pushFlowMetrics, flowMissingXid={}, "
688 + "OFFlowStatsReply Xid={}, for {}",
689 afsc.getFlowMissingXid(), replies.getXid(), dpid);
690 if (afsc.getFlowMissingXid() == replies.getXid()) {
691 // call entire flow stats update with flowMissing synchronization.
692 // used existing pushFlowMetrics
693 providerService.pushFlowMetrics(did, flowEntries);
694 }
695 // reset flowMissingXid to NO_FLOW_MISSING_XID
696 afsc.setFlowMissingXid(NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID);
697 } else {
698 // call individual flow stats update
699 providerService.pushFlowMetricsWithoutFlowMissing(did, flowEntries);
700 }
701 } else {
702 List<FlowEntry> flowEntries = replies.getEntries().stream()
703 .map(entry -> new FlowEntryBuilder(did, entry, driverService).build())
704 .collect(Collectors.toList());
705 // call existing entire flow stats update with flowMissing synchronization
706 providerService.pushFlowMetrics(did, flowEntries);
707 }
708 }
709
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700710 private TableStatisticsEntry buildTableStatistics(DeviceId deviceId,
711 OFTableStatsEntry ofEntry) {
712 TableStatisticsEntry entry = null;
713 if (ofEntry != null) {
714 entry = new DefaultTableStatisticsEntry(deviceId,
715 ofEntry.getTableId().getValue(),
716 ofEntry.getActiveCount(),
717 ofEntry.getLookupCount().getValue(),
718 ofEntry.getMatchedCount().getValue());
719 }
720
721 return entry;
722
723 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700724 }
alshabib1cc04f72014-09-16 16:09:58 -0700725
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800726 /**
jcc3d4e14a2015-04-21 11:32:05 +0800727 * The internal cache entry holding the original request as well as
728 * accumulating the any failures along the way.
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700729 * <p/>
jcc3d4e14a2015-04-21 11:32:05 +0800730 * If this entry is evicted from the cache then the entire operation is
731 * considered failed. Otherwise, only the failures reported by the device
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800732 * will be propagated up.
733 */
734 private class InternalCacheEntry {
alshabib902d41b2014-10-07 16:52:05 -0700735
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800736 private final FlowRuleBatchOperation operation;
737 private final Set<FlowRule> failures = Sets.newConcurrentHashSet();
alshabib193525b2014-10-08 18:58:03 -0700738
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800739 public InternalCacheEntry(FlowRuleBatchOperation operation) {
740 this.operation = operation;
alshabib902d41b2014-10-07 16:52:05 -0700741 }
742
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800743 /**
744 * Appends a failed rule to the set of failed items.
jcc3d4e14a2015-04-21 11:32:05 +0800745 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800746 * @param rule the failed rule
747 */
748 public void appendFailure(FlowRule rule) {
749 failures.add(rule);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800750 }
751
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800752 /**
753 * Fails the entire batch and returns the failed operation.
jcc3d4e14a2015-04-21 11:32:05 +0800754 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800755 * @return the failed operation
756 */
757 public CompletedBatchOperation failedCompletion() {
758 Set<FlowRule> fails = operation.getOperations().stream()
759 .map(op -> op.target()).collect(Collectors.toSet());
jcc3d4e14a2015-04-21 11:32:05 +0800760 return new CompletedBatchOperation(false,
761 Collections
762 .unmodifiableSet(fails),
763 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700764 }
765
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800766 /**
767 * Returns the completed operation and whether the batch suceeded.
jcc3d4e14a2015-04-21 11:32:05 +0800768 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800769 * @return the completed operation
770 */
771 public CompletedBatchOperation completed() {
jcc3d4e14a2015-04-21 11:32:05 +0800772 return new CompletedBatchOperation(
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700773 failures.isEmpty(),
774 Collections
775 .unmodifiableSet(failures),
776 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700777 }
alshabib902d41b2014-10-07 16:52:05 -0700778 }
alshabiba68eb962014-09-24 20:34:13 -0700779
alshabib1cc04f72014-09-16 16:09:58 -0700780}