blob: 5f2713b574d2c835d342ed2280dc7a909271c454 [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;
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -070026import io.netty.buffer.ByteBuf;
27import io.netty.buffer.Unpooled;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070028import org.onosproject.cfg.ComponentConfigService;
Brian O'Connorabafb502014-12-02 22:26:20 -080029import org.onosproject.net.DeviceId;
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -030030import org.onosproject.net.driver.DefaultDriverData;
31import org.onosproject.net.driver.DefaultDriverHandler;
32import org.onosproject.net.driver.Driver;
33import org.onosproject.net.driver.DriverHandler;
Jonathan Hart3c259162015-10-21 21:31:19 -070034import org.onosproject.net.driver.DriverService;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.net.flow.CompletedBatchOperation;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070036import org.onosproject.net.flow.DefaultTableStatisticsEntry;
Brian O'Connorabafb502014-12-02 22:26:20 -080037import org.onosproject.net.flow.FlowEntry;
38import org.onosproject.net.flow.FlowRule;
Brian O'Connorabafb502014-12-02 22:26:20 -080039import org.onosproject.net.flow.FlowRuleProvider;
40import org.onosproject.net.flow.FlowRuleProviderRegistry;
41import org.onosproject.net.flow.FlowRuleProviderService;
hjtsao1a4333c2018-10-22 11:02:00 -070042import org.onosproject.net.flow.IndexTableId;
Ray Milkey17801b42019-02-22 14:18:00 -080043import org.onosproject.net.flow.TableStatisticsEntry;
44import org.onosproject.net.flow.oldbatch.FlowRuleBatchEntry;
45import org.onosproject.net.flow.oldbatch.FlowRuleBatchOperation;
Brian O'Connorabafb502014-12-02 22:26:20 -080046import org.onosproject.net.provider.AbstractProvider;
47import org.onosproject.net.provider.ProviderId;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070048import org.onosproject.net.statistic.DefaultLoad;
Brian O'Connorabafb502014-12-02 22:26:20 -080049import org.onosproject.openflow.controller.Dpid;
50import org.onosproject.openflow.controller.OpenFlowController;
51import org.onosproject.openflow.controller.OpenFlowEventListener;
52import org.onosproject.openflow.controller.OpenFlowSwitch;
53import org.onosproject.openflow.controller.OpenFlowSwitchListener;
54import org.onosproject.openflow.controller.RoleState;
Thomas Vachuska95caba32016-04-04 10:42:05 -070055import org.onosproject.provider.of.flow.util.FlowEntryBuilder;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070056import org.osgi.service.component.ComponentContext;
Ray Milkey17801b42019-02-22 14:18:00 -080057import org.osgi.service.component.annotations.Activate;
58import org.osgi.service.component.annotations.Component;
59import org.osgi.service.component.annotations.Deactivate;
60import org.osgi.service.component.annotations.Modified;
61import org.osgi.service.component.annotations.Reference;
62import org.osgi.service.component.annotations.ReferenceCardinality;
Thomas Vachuska3358af22015-05-19 18:40:34 -070063import org.projectfloodlight.openflow.protocol.OFBadRequestCode;
alshabib902d41b2014-10-07 16:52:05 -070064import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
Laszlo Pappedadbe22017-12-14 20:05:49 +000065import org.projectfloodlight.openflow.protocol.OFCapabilities;
alshabib902d41b2014-10-07 16:52:05 -070066import org.projectfloodlight.openflow.protocol.OFErrorMsg;
Cem Türker3baff672017-10-12 15:09:01 +030067import org.projectfloodlight.openflow.protocol.OFFlowLightweightStatsReply;
alshabib193525b2014-10-08 18:58:03 -070068import org.projectfloodlight.openflow.protocol.OFFlowMod;
alshabib8f1cf4a2014-09-17 14:44:48 -070069import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
alshabib5c370ff2014-09-18 10:12:14 -070070import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
alshabib8f1cf4a2014-09-17 14:44:48 -070071import org.projectfloodlight.openflow.protocol.OFMessage;
72import org.projectfloodlight.openflow.protocol.OFPortStatus;
alshabib5c370ff2014-09-18 10:12:14 -070073import org.projectfloodlight.openflow.protocol.OFStatsReply;
sangho89bf6fb2015-02-09 09:33:13 -080074import org.projectfloodlight.openflow.protocol.OFStatsType;
Jonathan Hart3c259162015-10-21 21:31:19 -070075import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
76import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
Prince Pereira141ed812016-09-02 19:03:18 +053077import org.projectfloodlight.openflow.protocol.OFType;
78import org.projectfloodlight.openflow.protocol.OFVersion;
Prince Pereira788797e2016-08-10 11:24:14 +053079import org.projectfloodlight.openflow.protocol.errormsg.OFBadActionErrorMsg;
80import org.projectfloodlight.openflow.protocol.errormsg.OFBadInstructionErrorMsg;
81import org.projectfloodlight.openflow.protocol.errormsg.OFBadMatchErrorMsg;
Thomas Vachuska3358af22015-05-19 18:40:34 -070082import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
alshabib193525b2014-10-08 18:58:03 -070083import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
Prince Pereira141ed812016-09-02 19:03:18 +053084import org.projectfloodlight.openflow.types.U16;
85import org.projectfloodlight.openflow.types.U64;
alshabib1cc04f72014-09-16 16:09:58 -070086import org.slf4j.Logger;
87
Thomas Vachuska75aaa672015-04-29 12:24:43 -070088import java.util.Collections;
89import java.util.Dictionary;
90import java.util.List;
91import java.util.Map;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070092import java.util.Objects;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070093import java.util.Optional;
94import java.util.Set;
95import java.util.Timer;
96import java.util.concurrent.TimeUnit;
97import java.util.stream.Collectors;
98
ssyoon9030fbcd92015-08-17 10:42:07 +090099import static com.google.common.base.Preconditions.checkNotNull;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700100import static com.google.common.base.Strings.isNullOrEmpty;
101import static org.onlab.util.Tools.get;
Ray Milkey17801b42019-02-22 14:18:00 -0800102import static org.onosproject.provider.of.flow.impl.OsgiPropertyConstants.ADAPTIVE_FLOW_SAMPLING;
103import static org.onosproject.provider.of.flow.impl.OsgiPropertyConstants.ADAPTIVE_FLOW_SAMPLING_DEFAULT;
104import static org.onosproject.provider.of.flow.impl.OsgiPropertyConstants.POLL_FREQUENCY;
105import static org.onosproject.provider.of.flow.impl.OsgiPropertyConstants.POLL_FREQUENCY_DEFAULT;
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
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700137 /** Frequency (in seconds) for polling flow statistics. */
Thomas Vachuska4167c3f2018-10-16 07:16:31 -0700138 private int flowPollFrequency = POLL_FREQUENCY_DEFAULT;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700139
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700140 /** Adaptive Flow Sampling is on or off. */
Thomas Vachuska4167c3f2018-10-16 07:16:31 -0700141 private boolean adaptiveFlowSampling = ADAPTIVE_FLOW_SAMPLING_DEFAULT;
ssyoon9030fbcd92015-08-17 10:42:07 +0900142
alshabib1cc04f72014-09-16 16:09:58 -0700143 private FlowRuleProviderService providerService;
144
alshabibeec3a062014-09-17 18:01:26 -0700145 private final InternalFlowProvider listener = new InternalFlowProvider();
146
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800147 private Cache<Long, InternalCacheEntry> pendingBatches;
alshabib193525b2014-10-08 18:58:03 -0700148
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900149 private final Timer timer = new Timer("onos-openflow-collector");
150
Cem Türker3baff672017-10-12 15:09:01 +0300151
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900152 // Old simple collector set
Madan Jampani6b266102016-06-23 00:56:36 -0700153 private final Map<Dpid, FlowStatsCollector> simpleCollectors = Maps.newConcurrentMap();
ssyoon9030fbcd92015-08-17 10:42:07 +0900154
155 // NewAdaptiveFlowStatsCollector Set
Madan Jampani6b266102016-06-23 00:56:36 -0700156 private final Map<Dpid, NewAdaptiveFlowStatsCollector> afsCollectors = Maps.newConcurrentMap();
157 private final Map<Dpid, TableStatisticsCollector> tableStatsCollectors = Maps.newConcurrentMap();
alshabib3d643ec2014-10-22 18:33:00 -0700158
alshabib1cc04f72014-09-16 16:09:58 -0700159 /**
160 * Creates an OpenFlow host provider.
161 */
162 public OpenFlowRuleProvider() {
Brian O'Connorabafb502014-12-02 22:26:20 -0800163 super(new ProviderId("of", "org.onosproject.provider.openflow"));
alshabib1cc04f72014-09-16 16:09:58 -0700164 }
165
166 @Activate
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700167 protected void activate(ComponentContext context) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700168 cfgService.registerProperties(getClass());
alshabib1cc04f72014-09-16 16:09:58 -0700169 providerService = providerRegistry.register(this);
alshabibeec3a062014-09-17 18:01:26 -0700170 controller.addListener(listener);
171 controller.addEventListener(listener);
alshabib3d643ec2014-10-22 18:33:00 -0700172
Antonio Marsico1c5ae1f2015-12-15 15:31:56 +0100173 modified(context);
174
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700175 pendingBatches = createBatchCache();
ssyoon9030fbcd92015-08-17 10:42:07 +0900176
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700177 createCollectors();
alshabib3d643ec2014-10-22 18:33:00 -0700178
ssyoon9030fbcd92015-08-17 10:42:07 +0900179 log.info("Started with flowPollFrequency = {}, adaptiveFlowSampling = {}",
180 flowPollFrequency, adaptiveFlowSampling);
alshabib1cc04f72014-09-16 16:09:58 -0700181 }
182
183 @Deactivate
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700184 protected void deactivate(ComponentContext context) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700185 cfgService.unregisterProperties(getClass(), false);
186 stopCollectors();
alshabib1cc04f72014-09-16 16:09:58 -0700187 providerRegistry.unregister(this);
188 providerService = null;
189
190 log.info("Stopped");
191 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800192
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700193 @Modified
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700194 protected void modified(ComponentContext context) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700195 Dictionary<?, ?> properties = context.getProperties();
196 int newFlowPollFrequency;
197 try {
Thomas Vachuska4167c3f2018-10-16 07:16:31 -0700198 String s = get(properties, POLL_FREQUENCY);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700199 newFlowPollFrequency = isNullOrEmpty(s) ? flowPollFrequency : Integer.parseInt(s.trim());
200
201 } catch (NumberFormatException | ClassCastException e) {
202 newFlowPollFrequency = flowPollFrequency;
203 }
204
205 if (newFlowPollFrequency != flowPollFrequency) {
206 flowPollFrequency = newFlowPollFrequency;
207 adjustRate();
208 }
209
210 log.info("Settings: flowPollFrequency={}", flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900211
212 boolean newAdaptiveFlowSampling;
Thomas Vachuska4167c3f2018-10-16 07:16:31 -0700213 String s = get(properties, ADAPTIVE_FLOW_SAMPLING);
ssyoon9030fbcd92015-08-17 10:42:07 +0900214 newAdaptiveFlowSampling = isNullOrEmpty(s) ? adaptiveFlowSampling : Boolean.parseBoolean(s.trim());
215
216 if (newAdaptiveFlowSampling != adaptiveFlowSampling) {
217 // stop previous collector
218 stopCollectors();
219 adaptiveFlowSampling = newAdaptiveFlowSampling;
220 // create new collectors
221 createCollectors();
222 }
223
224 log.info("Settings: adaptiveFlowSampling={}", adaptiveFlowSampling);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700225 }
226
227 private Cache<Long, InternalCacheEntry> createBatchCache() {
228 return CacheBuilder.newBuilder()
229 .expireAfterWrite(10, TimeUnit.SECONDS)
230 .removalListener((RemovalNotification<Long, InternalCacheEntry> notification) -> {
231 if (notification.getCause() == RemovalCause.EXPIRED) {
232 providerService.batchOperationCompleted(notification.getKey(),
233 notification.getValue().failedCompletion());
234 }
235 }).build();
236 }
237
238 private void createCollectors() {
239 controller.getSwitches().forEach(this::createCollector);
240 }
241
242 private void createCollector(OpenFlowSwitch sw) {
Kavitha Alagesan6704df32016-08-18 15:15:31 +0530243 if (sw == null) {
244 return;
245 }
Laszlo Papp58174812018-01-16 13:29:47 +0000246 if (sw.features().getCapabilities().contains(OFCapabilities.FLOW_STATS)) {
247 if (adaptiveFlowSampling) {
248 // NewAdaptiveFlowStatsCollector Constructor
249 NewAdaptiveFlowStatsCollector fsc =
250 new NewAdaptiveFlowStatsCollector(driverService, sw, flowPollFrequency);
251 stopCollectorIfNeeded(afsCollectors.put(new Dpid(sw.getId()), fsc));
252 fsc.start();
253 } else {
254 FlowStatsCollector fsc = new FlowStatsCollector(timer, sw, flowPollFrequency);
255 stopCollectorIfNeeded(simpleCollectors.put(new Dpid(sw.getId()), fsc));
256 fsc.start();
257 }
ssyoon9030fbcd92015-08-17 10:42:07 +0900258 }
Laszlo Pappedadbe22017-12-14 20:05:49 +0000259 if (sw.features().getCapabilities().contains(OFCapabilities.TABLE_STATS)) {
260 TableStatisticsCollector tsc = new TableStatisticsCollector(timer, sw, flowPollFrequency);
261 stopCollectorIfNeeded(tableStatsCollectors.put(new Dpid(sw.getId()), tsc));
262 tsc.start();
263 }
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700264 }
265
266 private void stopCollectorIfNeeded(SwitchDataCollector collector) {
267 if (collector != null) {
268 collector.stop();
269 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700270 }
271
272 private void stopCollectors() {
ssyoon9030fbcd92015-08-17 10:42:07 +0900273 if (adaptiveFlowSampling) {
274 // NewAdaptiveFlowStatsCollector Destructor
275 afsCollectors.values().forEach(NewAdaptiveFlowStatsCollector::stop);
276 afsCollectors.clear();
277 } else {
278 simpleCollectors.values().forEach(FlowStatsCollector::stop);
279 simpleCollectors.clear();
280 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700281 tableStatsCollectors.values().forEach(TableStatisticsCollector::stop);
282 tableStatsCollectors.clear();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700283 }
284
285 private void adjustRate() {
286 DefaultLoad.setPollInterval(flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900287 if (adaptiveFlowSampling) {
288 // NewAdaptiveFlowStatsCollector calAndPollInterval
289 afsCollectors.values().forEach(fsc -> fsc.adjustCalAndPollInterval(flowPollFrequency));
290 } else {
291 simpleCollectors.values().forEach(fsc -> fsc.adjustPollInterval(flowPollFrequency));
292 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700293 tableStatsCollectors.values().forEach(tsc -> tsc.adjustPollInterval(flowPollFrequency));
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700294 }
295
Jordan Haltermandf4b08a2019-03-05 18:44:03 -0800296 private void resetEvents(Dpid dpid) {
297 SwitchDataCollector collector;
298 if (adaptiveFlowSampling) {
299 collector = afsCollectors.get(dpid);
300 } else {
301 collector = simpleCollectors.get(dpid);
302 }
303 if (collector != null) {
304 collector.resetEvents();
305 }
306 }
307
308 private void recordEvent(Dpid dpid) {
309 recordEvents(dpid, 1);
310 }
311
312 private void recordEvents(Dpid dpid, int events) {
313 SwitchDataCollector collector;
314 if (adaptiveFlowSampling) {
315 collector = afsCollectors.get(dpid);
316 } else {
317 collector = simpleCollectors.get(dpid);
318 }
319 if (collector != null) {
320 collector.recordEvents(events);
321 }
322 }
323
alshabib1cc04f72014-09-16 16:09:58 -0700324 @Override
325 public void applyFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800326 for (FlowRule flowRule : flowRules) {
327 applyRule(flowRule);
alshabib35edb1a2014-09-16 17:44:44 -0700328 }
alshabib1cc04f72014-09-16 16:09:58 -0700329 }
330
alshabib35edb1a2014-09-16 17:44:44 -0700331 private void applyRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900332 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
333 OpenFlowSwitch sw = controller.getSwitch(dpid);
334
Ray Milkey0ae473d2016-04-04 10:56:47 -0700335 if (sw == null) {
336 return;
337 }
338
alshabibbdcbb102015-04-22 14:16:38 -0700339 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Jonathan Hart3c259162015-10-21 21:31:19 -0700340 Optional.empty(), Optional.of(driverService)).buildFlowAdd());
Jordan Haltermandf4b08a2019-03-05 18:44:03 -0800341
342 recordEvent(dpid);
alshabib35edb1a2014-09-16 17:44:44 -0700343 }
344
alshabib1cc04f72014-09-16 16:09:58 -0700345 @Override
346 public void removeFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800347 for (FlowRule flowRule : flowRules) {
348 removeRule(flowRule);
alshabib219ebaa2014-09-22 15:41:24 -0700349 }
alshabib1cc04f72014-09-16 16:09:58 -0700350 }
351
alshabib219ebaa2014-09-22 15:41:24 -0700352 private void removeRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900353 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
354 OpenFlowSwitch sw = controller.getSwitch(dpid);
355
Ray Milkey0ae473d2016-04-04 10:56:47 -0700356 if (sw == null) {
357 return;
358 }
359
alshabibbdcbb102015-04-22 14:16:38 -0700360 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Jonathan Hart3c259162015-10-21 21:31:19 -0700361 Optional.empty(), Optional.of(driverService)).buildFlowDel());
Jordan Haltermandf4b08a2019-03-05 18:44:03 -0800362
363 recordEvent(dpid);
alshabib219ebaa2014-09-22 15:41:24 -0700364 }
365
alshabiba68eb962014-09-24 20:34:13 -0700366 @Override
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800367 public void executeBatch(FlowRuleBatchOperation batch) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900368 checkNotNull(batch);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800369
ssyoon9030fbcd92015-08-17 10:42:07 +0900370 Dpid dpid = Dpid.dpid(batch.deviceId().uri());
371 OpenFlowSwitch sw = controller.getSwitch(dpid);
Madan Jampani84382b92016-06-22 08:26:49 -0700372
373 // If switch no longer exists, simply return.
374 if (sw == null) {
375 Set<FlowRule> failures = ImmutableSet.copyOf(Lists.transform(batch.getOperations(), e -> e.target()));
376 providerService.batchOperationCompleted(batch.id(),
377 new CompletedBatchOperation(false, failures, batch.deviceId()));
378 return;
379 }
380 pendingBatches.put(batch.id(), new InternalCacheEntry(batch));
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800381 OFFlowMod mod;
alshabib193525b2014-10-08 18:58:03 -0700382 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700383 FlowModBuilder builder =
Jonathan Hart3c259162015-10-21 21:31:19 -0700384 FlowModBuilder.builder(fbe.target(), sw.factory(),
385 Optional.of(batch.id()), Optional.of(driverService));
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800386 switch (fbe.operator()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700387 case ADD:
388 mod = builder.buildFlowAdd();
389 break;
390 case REMOVE:
391 mod = builder.buildFlowDel();
392 break;
393 case MODIFY:
394 mod = builder.buildFlowMod();
395 break;
396 default:
397 log.error("Unsupported batch operation {}; skipping flowmod {}",
ssyoon9030fbcd92015-08-17 10:42:07 +0900398 fbe.operator(), fbe);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700399 continue;
jcc3d4e14a2015-04-21 11:32:05 +0800400 }
Saurav Das3ea46622015-04-22 14:01:34 -0700401 sw.sendMsg(mod);
alshabib193525b2014-10-08 18:58:03 -0700402 }
jcc3d4e14a2015-04-21 11:32:05 +0800403 OFBarrierRequest.Builder builder = sw.factory().buildBarrierRequest()
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800404 .setXid(batch.id());
405 sw.sendMsg(builder.build());
Jordan Haltermandf4b08a2019-03-05 18:44:03 -0800406
407 recordEvents(dpid, batch.getOperations().size());
alshabib193525b2014-10-08 18:58:03 -0700408 }
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) {
Jordan Haltermandf4b08a2019-03-05 18:44:03 -0800453 // Let's unblock first the collector
454 SwitchDataCollector collector;
455 if (adaptiveFlowSampling) {
456 collector = afsCollectors.get(dpid);
457 } else {
458 collector = simpleCollectors.get(dpid);
459 }
460 if (collector != null) {
461 collector.received();
462 }
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300463 pushFlowMetrics(dpid, (OFFlowStatsReply) msg, getDriver(deviceId));
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700464 } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.TABLE) {
465 pushTableStatistics(dpid, (OFTableStatsReply) msg);
Cem Türker3baff672017-10-12 15:09:01 +0300466 } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW_LIGHTWEIGHT) {
467 pushFlowLightWeightMetrics(dpid, (OFFlowLightweightStatsReply) msg);
sangho89bf6fb2015-02-09 09:33:13 -0800468 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700469 break;
470 case BARRIER_REPLY:
471 try {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700472 InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800473 if (entry != null) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700474 providerService
475 .batchOperationCompleted(msg.getXid(),
476 entry.completed());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800477 } else {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700478 log.warn("Received unknown Barrier Reply: {}",
479 msg.getXid());
480 }
481 } finally {
482 pendingBatches.invalidate(msg.getXid());
483 }
484 break;
485 case ERROR:
Thomas Vachuska3358af22015-05-19 18:40:34 -0700486 // TODO: This needs to get suppressed in a better way.
487 if (msg instanceof OFBadRequestErrorMsg &&
488 ((OFBadRequestErrorMsg) msg).getCode() == OFBadRequestCode.BAD_TYPE) {
489 log.debug("Received error message {} from {}", msg, dpid);
490 } else {
491 log.warn("Received error message {} from {}", msg, dpid);
492 }
Prince Pereira788797e2016-08-10 11:24:14 +0530493 handleErrorMsg(deviceId, msg);
Ray Milkey4fd3ceb2015-12-10 14:43:08 -0800494 break;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700495 default:
496 log.debug("Unhandled message type: {}", msg.getType());
alshabib8f1cf4a2014-09-17 14:44:48 -0700497 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700498 }
499
Prince Pereira788797e2016-08-10 11:24:14 +0530500 private void handleErrorMsg(DeviceId deviceId, OFMessage msg) {
Prince Pereira141ed812016-09-02 19:03:18 +0530501 InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
Prince Pereira788797e2016-08-10 11:24:14 +0530502 OFErrorMsg error = (OFErrorMsg) msg;
503 OFMessage ofMessage = null;
504 switch (error.getErrType()) {
505 case BAD_ACTION:
506 OFBadActionErrorMsg baErrorMsg = (OFBadActionErrorMsg) error;
507 if (baErrorMsg.getData().getParsedMessage().isPresent()) {
508 ofMessage = baErrorMsg.getData().getParsedMessage().get();
509 }
510 break;
511 case BAD_INSTRUCTION:
512 OFBadInstructionErrorMsg biErrorMsg = (OFBadInstructionErrorMsg) error;
513 if (biErrorMsg.getData().getParsedMessage().isPresent()) {
514 ofMessage = biErrorMsg.getData().getParsedMessage().get();
515 }
516 break;
517 case BAD_MATCH:
518 OFBadMatchErrorMsg bmErrorMsg = (OFBadMatchErrorMsg) error;
519 if (bmErrorMsg.getData().getParsedMessage().isPresent()) {
520 ofMessage = bmErrorMsg.getData().getParsedMessage().get();
521 }
522 break;
523 case FLOW_MOD_FAILED:
524 OFFlowModFailedErrorMsg fmFailed = (OFFlowModFailedErrorMsg) error;
525 if (fmFailed.getData().getParsedMessage().isPresent()) {
526 ofMessage = fmFailed.getData().getParsedMessage().get();
527 }
528 break;
529 default:
530 // Do nothing.
531 return;
532 }
Prince Pereira141ed812016-09-02 19:03:18 +0530533
Prince Pereira788797e2016-08-10 11:24:14 +0530534 if (ofMessage != null) {
Prince Pereira141ed812016-09-02 19:03:18 +0530535
Prince Pereira788797e2016-08-10 11:24:14 +0530536 if (entry != null) {
537 OFFlowMod ofFlowMod = (OFFlowMod) ofMessage;
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300538 entry.appendFailure(new FlowEntryBuilder(deviceId, ofFlowMod, getDriver(deviceId)).build());
Prince Pereira788797e2016-08-10 11:24:14 +0530539 } else {
540 log.error("No matching batch for this error: {}", error);
541 }
Prince Pereira141ed812016-09-02 19:03:18 +0530542
Prince Pereira788797e2016-08-10 11:24:14 +0530543 } else {
Prince Pereira141ed812016-09-02 19:03:18 +0530544
545 U64 cookieId = readCookieIdFromOFErrorMsg(error, msg.getVersion());
546
547 if (cookieId != null) {
548 long flowId = cookieId.getValue();
549
550 if (entry != null) {
551 for (FlowRuleBatchEntry fbEntry : entry.operation.getOperations()) {
552 if (fbEntry.target().id().value() == flowId) {
553 entry.appendFailure(fbEntry.target());
554 break;
555 }
556 }
557 } else {
558 log.error("No matching batch for this error: {}", error);
559 }
560
561 } else {
562 log.error("Flow installation failed but switch " +
563 "didn't tell us which one.");
564 }
Prince Pereira788797e2016-08-10 11:24:14 +0530565 }
566 }
567
Prince Pereira141ed812016-09-02 19:03:18 +0530568 /**
569 * Reading cookieId from OFErrorMsg.
570 *
571 * Loxigen OpenFlow API failed in parsing error messages because of
572 * 64 byte data truncation based on OpenFlow specs. The method written
573 * is a workaround to extract the cookieId from the packet till the
574 * issue is resolved in Loxigen OpenFlow code.
575 * Ref: https://groups.google.com/a/onosproject.org/forum/#!topic
576 * /onos-dev/_KwlHZDllLE
577 *
578 * @param msg OF error message
579 * @param ofVersion Openflow version
580 * @return cookieId
581 */
582 private U64 readCookieIdFromOFErrorMsg(OFErrorMsg msg,
583 OFVersion ofVersion) {
584
585 if (ofVersion.wireVersion < OFVersion.OF_13.wireVersion) {
586 log.debug("Unhandled error msg with OF version {} " +
587 "which is less than {}",
588 ofVersion, OFVersion.OF_13);
589 return null;
590 }
591
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700592 ByteBuf bb = Unpooled.wrappedBuffer(msg.getData().getData());
Prince Pereira141ed812016-09-02 19:03:18 +0530593
594 if (bb.readableBytes() < MIN_EXPECTED_BYTE_LEN) {
595 log.debug("Wrong length: Expected to be >= {}, was: {}",
596 MIN_EXPECTED_BYTE_LEN, bb.readableBytes());
597 return null;
598 }
599
600 byte ofVer = bb.readByte();
601
602 if (ofVer != ofVersion.wireVersion) {
603 log.debug("Wrong version: Expected={}, got={}",
604 ofVersion.wireVersion, ofVer);
605 return null;
606 }
607
608 byte type = bb.readByte();
609
610 if (type != OFType.FLOW_MOD.ordinal()) {
611 log.debug("Wrong type: Expected={}, got={}",
612 OFType.FLOW_MOD.ordinal(), type);
613 return null;
614 }
615
616 int length = U16.f(bb.readShort());
617
618 if (length < MIN_EXPECTED_BYTE_LEN) {
619 log.debug("Wrong length: Expected to be >= {}, was: {}",
620 MIN_EXPECTED_BYTE_LEN, length);
621 return null;
622 }
623
624 bb.skipBytes(SKIP_BYTES);
625 return U64.ofRaw(bb.readLong());
626 }
627
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700628 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700629 public void receivedRoleReply(Dpid dpid, RoleState requested,
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800630 RoleState response) {
Jordan Haltermandf4b08a2019-03-05 18:44:03 -0800631 if (response == RoleState.MASTER) {
632 resetEvents(dpid);
633 }
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700634 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700635
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300636 private DriverHandler getDriver(DeviceId devId) {
637 Driver driver = driverService.getDriver(devId);
638 DriverHandler handler = new DefaultDriverHandler(new DefaultDriverData(driver, devId));
639 return handler;
640 }
641
642 private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies, DriverHandler handler) {
alshabib64def642014-12-02 23:27:37 -0800643
alshabib54ce5892014-09-23 17:50:51 -0700644 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900645 NewAdaptiveFlowStatsCollector afsc = afsCollectors.get(dpid);
alshabib54ce5892014-09-23 17:50:51 -0700646
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900647 if (adaptiveFlowSampling && afsc != null) {
648 List<FlowEntry> flowEntries = replies.getEntries().stream()
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300649 .map(entry -> new FlowEntryBuilder(did, entry, handler).withSetAfsc(afsc).build())
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900650 .collect(Collectors.toList());
alshabib54ce5892014-09-23 17:50:51 -0700651
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900652 // Check that OFFlowStatsReply Xid is same with the one of OFFlowStatsRequest?
653 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
654 log.debug("OpenFlowRuleProvider:pushFlowMetrics, flowMissingXid={}, "
655 + "OFFlowStatsReply Xid={}, for {}",
656 afsc.getFlowMissingXid(), replies.getXid(), dpid);
657 if (afsc.getFlowMissingXid() == replies.getXid()) {
658 // call entire flow stats update with flowMissing synchronization.
659 // used existing pushFlowMetrics
660 providerService.pushFlowMetrics(did, flowEntries);
ssyoon9030fbcd92015-08-17 10:42:07 +0900661 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900662 // reset flowMissingXid to NO_FLOW_MISSING_XID
663 afsc.setFlowMissingXid(NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID);
664 } else {
665 // call individual flow stats update
666 providerService.pushFlowMetricsWithoutFlowMissing(did, flowEntries);
ssyoon9030fbcd92015-08-17 10:42:07 +0900667 }
668 } else {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900669 List<FlowEntry> flowEntries = replies.getEntries().stream()
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300670 .map(entry -> new FlowEntryBuilder(did, entry, handler).build())
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900671 .collect(Collectors.toList());
672
ssyoon9030fbcd92015-08-17 10:42:07 +0900673 // call existing entire flow stats update with flowMissing synchronization
674 providerService.pushFlowMetrics(did, flowEntries);
675 }
alshabib5c370ff2014-09-18 10:12:14 -0700676 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700677
678 private void pushTableStatistics(Dpid dpid, OFTableStatsReply replies) {
679
680 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
681 List<TableStatisticsEntry> tableStatsEntries = replies.getEntries().stream()
682 .map(entry -> buildTableStatistics(did, entry))
683 .filter(Objects::nonNull)
684 .collect(Collectors.toList());
685 providerService.pushTableStatistics(did, tableStatsEntries);
686 }
687
Cem Türker3baff672017-10-12 15:09:01 +0300688 private void pushFlowLightWeightMetrics(Dpid dpid, OFFlowLightweightStatsReply replies) {
689
690 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
691 NewAdaptiveFlowStatsCollector afsc = afsCollectors.get(dpid);
692 if (adaptiveFlowSampling && afsc != null) {
693 List<FlowEntry> flowEntries = replies.getEntries().stream()
694 .map(entry -> new FlowEntryBuilder(did, entry, driverService).withSetAfsc(afsc).build())
695 .collect(Collectors.toList());
696
697 // Check that OFFlowStatsReply Xid is same with the one of OFFlowStatsRequest?
698 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
699 log.debug("OpenFlowRuleProvider:pushFlowMetrics, flowMissingXid={}, "
700 + "OFFlowStatsReply Xid={}, for {}",
701 afsc.getFlowMissingXid(), replies.getXid(), dpid);
702 if (afsc.getFlowMissingXid() == replies.getXid()) {
703 // call entire flow stats update with flowMissing synchronization.
704 // used existing pushFlowMetrics
705 providerService.pushFlowMetrics(did, flowEntries);
706 }
707 // reset flowMissingXid to NO_FLOW_MISSING_XID
708 afsc.setFlowMissingXid(NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID);
709 } else {
710 // call individual flow stats update
711 providerService.pushFlowMetricsWithoutFlowMissing(did, flowEntries);
712 }
713 } else {
714 List<FlowEntry> flowEntries = replies.getEntries().stream()
715 .map(entry -> new FlowEntryBuilder(did, entry, driverService).build())
716 .collect(Collectors.toList());
717 // call existing entire flow stats update with flowMissing synchronization
718 providerService.pushFlowMetrics(did, flowEntries);
719 }
720 }
721
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700722 private TableStatisticsEntry buildTableStatistics(DeviceId deviceId,
723 OFTableStatsEntry ofEntry) {
724 TableStatisticsEntry entry = null;
725 if (ofEntry != null) {
hjtsao1a4333c2018-10-22 11:02:00 -0700726 IndexTableId tid = IndexTableId.of(ofEntry.getTableId().getValue());
727
728 try {
729 entry = DefaultTableStatisticsEntry.builder()
730 .withDeviceId(deviceId)
731 .withTableId(tid)
732 .withActiveFlowEntries(ofEntry.getActiveCount())
733 .withPacketsLookedUpCount(ofEntry.getLookupCount().getValue())
734 .withPacketsMatchedCount(ofEntry.getMatchedCount().getValue())
735 .withMaxSize(ofEntry.getMaxEntries()).build();
736 } catch (UnsupportedOperationException e) {
737 // The exception "UnsupportedOperationException" is thrown by "getMaxEntries()".
738 entry = DefaultTableStatisticsEntry.builder()
739 .withDeviceId(deviceId)
740 .withTableId(tid)
741 .withActiveFlowEntries(ofEntry.getActiveCount())
742 .withPacketsLookedUpCount(ofEntry.getLookupCount().getValue())
743 .withPacketsMatchedCount(ofEntry.getMatchedCount().getValue()).build();
744 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700745 }
746
747 return entry;
748
749 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700750 }
alshabib1cc04f72014-09-16 16:09:58 -0700751
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800752 /**
jcc3d4e14a2015-04-21 11:32:05 +0800753 * The internal cache entry holding the original request as well as
754 * accumulating the any failures along the way.
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700755 * <p/>
jcc3d4e14a2015-04-21 11:32:05 +0800756 * If this entry is evicted from the cache then the entire operation is
757 * considered failed. Otherwise, only the failures reported by the device
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800758 * will be propagated up.
759 */
760 private class InternalCacheEntry {
alshabib902d41b2014-10-07 16:52:05 -0700761
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800762 private final FlowRuleBatchOperation operation;
763 private final Set<FlowRule> failures = Sets.newConcurrentHashSet();
alshabib193525b2014-10-08 18:58:03 -0700764
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800765 public InternalCacheEntry(FlowRuleBatchOperation operation) {
766 this.operation = operation;
alshabib902d41b2014-10-07 16:52:05 -0700767 }
768
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800769 /**
770 * Appends a failed rule to the set of failed items.
jcc3d4e14a2015-04-21 11:32:05 +0800771 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800772 * @param rule the failed rule
773 */
774 public void appendFailure(FlowRule rule) {
775 failures.add(rule);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800776 }
777
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800778 /**
779 * Fails the entire batch and returns the failed operation.
jcc3d4e14a2015-04-21 11:32:05 +0800780 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800781 * @return the failed operation
782 */
783 public CompletedBatchOperation failedCompletion() {
784 Set<FlowRule> fails = operation.getOperations().stream()
785 .map(op -> op.target()).collect(Collectors.toSet());
jcc3d4e14a2015-04-21 11:32:05 +0800786 return new CompletedBatchOperation(false,
787 Collections
788 .unmodifiableSet(fails),
789 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700790 }
791
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800792 /**
793 * Returns the completed operation and whether the batch suceeded.
jcc3d4e14a2015-04-21 11:32:05 +0800794 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800795 * @return the completed operation
796 */
797 public CompletedBatchOperation completed() {
jcc3d4e14a2015-04-21 11:32:05 +0800798 return new CompletedBatchOperation(
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700799 failures.isEmpty(),
800 Collections
801 .unmodifiableSet(failures),
802 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700803 }
alshabib902d41b2014-10-07 16:52:05 -0700804 }
alshabiba68eb962014-09-24 20:34:13 -0700805
Jordan Haltermandf4b08a2019-03-05 18:44:03 -0800806}