blob: 22b524634a15b380928712895fd9fb6766026d67 [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;
hjtsao1a4333c2018-10-22 11:02:00 -070054import org.onosproject.net.flow.IndexTableId;
Brian O'Connorabafb502014-12-02 22:26:20 -080055import org.onosproject.net.provider.AbstractProvider;
56import org.onosproject.net.provider.ProviderId;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070057import org.onosproject.net.statistic.DefaultLoad;
Brian O'Connorabafb502014-12-02 22:26:20 -080058import org.onosproject.openflow.controller.Dpid;
59import org.onosproject.openflow.controller.OpenFlowController;
60import org.onosproject.openflow.controller.OpenFlowEventListener;
61import org.onosproject.openflow.controller.OpenFlowSwitch;
62import org.onosproject.openflow.controller.OpenFlowSwitchListener;
63import org.onosproject.openflow.controller.RoleState;
jcc3d4e14a2015-04-21 11:32:05 +080064import org.onosproject.openflow.controller.ThirdPartyMessage;
Thomas Vachuska95caba32016-04-04 10:42:05 -070065import org.onosproject.provider.of.flow.util.FlowEntryBuilder;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070066import org.osgi.service.component.ComponentContext;
Thomas Vachuska3358af22015-05-19 18:40:34 -070067import org.projectfloodlight.openflow.protocol.OFBadRequestCode;
alshabib902d41b2014-10-07 16:52:05 -070068import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
Laszlo Pappedadbe22017-12-14 20:05:49 +000069import org.projectfloodlight.openflow.protocol.OFCapabilities;
alshabib902d41b2014-10-07 16:52:05 -070070import org.projectfloodlight.openflow.protocol.OFErrorMsg;
Cem Türker3baff672017-10-12 15:09:01 +030071import org.projectfloodlight.openflow.protocol.OFFlowLightweightStatsReply;
alshabib193525b2014-10-08 18:58:03 -070072import org.projectfloodlight.openflow.protocol.OFFlowMod;
alshabib8f1cf4a2014-09-17 14:44:48 -070073import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
alshabib5c370ff2014-09-18 10:12:14 -070074import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
alshabib8f1cf4a2014-09-17 14:44:48 -070075import org.projectfloodlight.openflow.protocol.OFMessage;
76import org.projectfloodlight.openflow.protocol.OFPortStatus;
alshabib5c370ff2014-09-18 10:12:14 -070077import org.projectfloodlight.openflow.protocol.OFStatsReply;
sangho89bf6fb2015-02-09 09:33:13 -080078import org.projectfloodlight.openflow.protocol.OFStatsType;
Jonathan Hart3c259162015-10-21 21:31:19 -070079import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
80import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
Prince Pereira141ed812016-09-02 19:03:18 +053081import org.projectfloodlight.openflow.protocol.OFType;
82import org.projectfloodlight.openflow.protocol.OFVersion;
Prince Pereira788797e2016-08-10 11:24:14 +053083import org.projectfloodlight.openflow.protocol.errormsg.OFBadActionErrorMsg;
84import org.projectfloodlight.openflow.protocol.errormsg.OFBadInstructionErrorMsg;
85import org.projectfloodlight.openflow.protocol.errormsg.OFBadMatchErrorMsg;
Thomas Vachuska3358af22015-05-19 18:40:34 -070086import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
alshabib193525b2014-10-08 18:58:03 -070087import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
Prince Pereira141ed812016-09-02 19:03:18 +053088import org.projectfloodlight.openflow.types.U16;
89import org.projectfloodlight.openflow.types.U64;
alshabib1cc04f72014-09-16 16:09:58 -070090import org.slf4j.Logger;
91
Thomas Vachuska75aaa672015-04-29 12:24:43 -070092import java.util.Collections;
93import java.util.Dictionary;
94import java.util.List;
95import java.util.Map;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070096import java.util.Objects;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070097import java.util.Optional;
98import java.util.Set;
99import java.util.Timer;
100import java.util.concurrent.TimeUnit;
101import java.util.stream.Collectors;
102
ssyoon9030fbcd92015-08-17 10:42:07 +0900103import static com.google.common.base.Preconditions.checkNotNull;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700104import static com.google.common.base.Strings.isNullOrEmpty;
105import static org.onlab.util.Tools.get;
Thomas Vachuska4167c3f2018-10-16 07:16:31 -0700106import static org.onosproject.provider.of.flow.impl.OsgiPropertyConstants.*;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700107import static org.slf4j.LoggerFactory.getLogger;
alshabibeec3a062014-09-17 18:01:26 -0700108
alshabib1cc04f72014-09-16 16:09:58 -0700109/**
jcc3d4e14a2015-04-21 11:32:05 +0800110 * Provider which uses an OpenFlow controller to detect network end-station
111 * hosts.
alshabib1cc04f72014-09-16 16:09:58 -0700112 */
Thomas Vachuska4167c3f2018-10-16 07:16:31 -0700113@Component(immediate = true,
114 property = {
115 POLL_FREQUENCY + ":Integer=" + POLL_FREQUENCY_DEFAULT,
116 ADAPTIVE_FLOW_SAMPLING + ":Boolean=" + ADAPTIVE_FLOW_SAMPLING_DEFAULT,
117 })
jcc3d4e14a2015-04-21 11:32:05 +0800118public class OpenFlowRuleProvider extends AbstractProvider
119 implements FlowRuleProvider {
alshabib1cc04f72014-09-16 16:09:58 -0700120
121 private final Logger log = getLogger(getClass());
122
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700123 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib1cc04f72014-09-16 16:09:58 -0700124 protected FlowRuleProviderRegistry providerRegistry;
125
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700126 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib1cc04f72014-09-16 16:09:58 -0700127 protected OpenFlowController controller;
128
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700129 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700130 protected ComponentConfigService cfgService;
131
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700132 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart3c259162015-10-21 21:31:19 -0700133 protected DriverService driverService;
134
Prince Pereira141ed812016-09-02 19:03:18 +0530135 private static final int MIN_EXPECTED_BYTE_LEN = 56;
136 private static final int SKIP_BYTES = 4;
Prince Pereira141ed812016-09-02 19:03:18 +0530137
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700138 //@Property(name = "flowPollFrequency", intValue = DEFAULT_POLL_FREQUENCY,
139 // label = "Frequency (in seconds) for polling flow statistics")
Thomas Vachuska4167c3f2018-10-16 07:16:31 -0700140 private int flowPollFrequency = POLL_FREQUENCY_DEFAULT;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700141
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700142 //@Property(name = "adaptiveFlowSampling", boolValue = DEFAULT_ADAPTIVE_FLOW_SAMPLING,
143 // label = "Adaptive Flow Sampling is on or off")
Thomas Vachuska4167c3f2018-10-16 07:16:31 -0700144 private boolean adaptiveFlowSampling = ADAPTIVE_FLOW_SAMPLING_DEFAULT;
ssyoon9030fbcd92015-08-17 10:42:07 +0900145
alshabib1cc04f72014-09-16 16:09:58 -0700146 private FlowRuleProviderService providerService;
147
alshabibeec3a062014-09-17 18:01:26 -0700148 private final InternalFlowProvider listener = new InternalFlowProvider();
149
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800150 private Cache<Long, InternalCacheEntry> pendingBatches;
alshabib193525b2014-10-08 18:58:03 -0700151
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900152 private final Timer timer = new Timer("onos-openflow-collector");
153
Cem Türker3baff672017-10-12 15:09:01 +0300154
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900155 // Old simple collector set
Madan Jampani6b266102016-06-23 00:56:36 -0700156 private final Map<Dpid, FlowStatsCollector> simpleCollectors = Maps.newConcurrentMap();
ssyoon9030fbcd92015-08-17 10:42:07 +0900157
158 // NewAdaptiveFlowStatsCollector Set
Madan Jampani6b266102016-06-23 00:56:36 -0700159 private final Map<Dpid, NewAdaptiveFlowStatsCollector> afsCollectors = Maps.newConcurrentMap();
160 private final Map<Dpid, TableStatisticsCollector> tableStatsCollectors = Maps.newConcurrentMap();
alshabib3d643ec2014-10-22 18:33:00 -0700161
alshabib1cc04f72014-09-16 16:09:58 -0700162 /**
163 * Creates an OpenFlow host provider.
164 */
165 public OpenFlowRuleProvider() {
Brian O'Connorabafb502014-12-02 22:26:20 -0800166 super(new ProviderId("of", "org.onosproject.provider.openflow"));
alshabib1cc04f72014-09-16 16:09:58 -0700167 }
168
169 @Activate
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700170 protected void activate(ComponentContext context) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700171 cfgService.registerProperties(getClass());
alshabib1cc04f72014-09-16 16:09:58 -0700172 providerService = providerRegistry.register(this);
alshabibeec3a062014-09-17 18:01:26 -0700173 controller.addListener(listener);
174 controller.addEventListener(listener);
alshabib3d643ec2014-10-22 18:33:00 -0700175
Antonio Marsico1c5ae1f2015-12-15 15:31:56 +0100176 modified(context);
177
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700178 pendingBatches = createBatchCache();
ssyoon9030fbcd92015-08-17 10:42:07 +0900179
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700180 createCollectors();
alshabib3d643ec2014-10-22 18:33:00 -0700181
ssyoon9030fbcd92015-08-17 10:42:07 +0900182 log.info("Started with flowPollFrequency = {}, adaptiveFlowSampling = {}",
183 flowPollFrequency, adaptiveFlowSampling);
alshabib1cc04f72014-09-16 16:09:58 -0700184 }
185
186 @Deactivate
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700187 protected void deactivate(ComponentContext context) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700188 cfgService.unregisterProperties(getClass(), false);
189 stopCollectors();
alshabib1cc04f72014-09-16 16:09:58 -0700190 providerRegistry.unregister(this);
191 providerService = null;
192
193 log.info("Stopped");
194 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800195
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700196 @Modified
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700197 protected void modified(ComponentContext context) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700198 Dictionary<?, ?> properties = context.getProperties();
199 int newFlowPollFrequency;
200 try {
Thomas Vachuska4167c3f2018-10-16 07:16:31 -0700201 String s = get(properties, POLL_FREQUENCY);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700202 newFlowPollFrequency = isNullOrEmpty(s) ? flowPollFrequency : Integer.parseInt(s.trim());
203
204 } catch (NumberFormatException | ClassCastException e) {
205 newFlowPollFrequency = flowPollFrequency;
206 }
207
208 if (newFlowPollFrequency != flowPollFrequency) {
209 flowPollFrequency = newFlowPollFrequency;
210 adjustRate();
211 }
212
213 log.info("Settings: flowPollFrequency={}", flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900214
215 boolean newAdaptiveFlowSampling;
Thomas Vachuska4167c3f2018-10-16 07:16:31 -0700216 String s = get(properties, ADAPTIVE_FLOW_SAMPLING);
ssyoon9030fbcd92015-08-17 10:42:07 +0900217 newAdaptiveFlowSampling = isNullOrEmpty(s) ? adaptiveFlowSampling : Boolean.parseBoolean(s.trim());
218
219 if (newAdaptiveFlowSampling != adaptiveFlowSampling) {
220 // stop previous collector
221 stopCollectors();
222 adaptiveFlowSampling = newAdaptiveFlowSampling;
223 // create new collectors
224 createCollectors();
225 }
226
227 log.info("Settings: adaptiveFlowSampling={}", adaptiveFlowSampling);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700228 }
229
230 private Cache<Long, InternalCacheEntry> createBatchCache() {
231 return CacheBuilder.newBuilder()
232 .expireAfterWrite(10, TimeUnit.SECONDS)
233 .removalListener((RemovalNotification<Long, InternalCacheEntry> notification) -> {
234 if (notification.getCause() == RemovalCause.EXPIRED) {
235 providerService.batchOperationCompleted(notification.getKey(),
236 notification.getValue().failedCompletion());
237 }
238 }).build();
239 }
240
241 private void createCollectors() {
242 controller.getSwitches().forEach(this::createCollector);
243 }
244
245 private void createCollector(OpenFlowSwitch sw) {
Kavitha Alagesan6704df32016-08-18 15:15:31 +0530246 if (sw == null) {
247 return;
248 }
Laszlo Papp58174812018-01-16 13:29:47 +0000249 if (sw.features().getCapabilities().contains(OFCapabilities.FLOW_STATS)) {
250 if (adaptiveFlowSampling) {
251 // NewAdaptiveFlowStatsCollector Constructor
252 NewAdaptiveFlowStatsCollector fsc =
253 new NewAdaptiveFlowStatsCollector(driverService, sw, flowPollFrequency);
254 stopCollectorIfNeeded(afsCollectors.put(new Dpid(sw.getId()), fsc));
255 fsc.start();
256 } else {
257 FlowStatsCollector fsc = new FlowStatsCollector(timer, sw, flowPollFrequency);
258 stopCollectorIfNeeded(simpleCollectors.put(new Dpid(sw.getId()), fsc));
259 fsc.start();
260 }
ssyoon9030fbcd92015-08-17 10:42:07 +0900261 }
Laszlo Pappedadbe22017-12-14 20:05:49 +0000262 if (sw.features().getCapabilities().contains(OFCapabilities.TABLE_STATS)) {
263 TableStatisticsCollector tsc = new TableStatisticsCollector(timer, sw, flowPollFrequency);
264 stopCollectorIfNeeded(tableStatsCollectors.put(new Dpid(sw.getId()), tsc));
265 tsc.start();
266 }
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700267 }
268
269 private void stopCollectorIfNeeded(SwitchDataCollector collector) {
270 if (collector != null) {
271 collector.stop();
272 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700273 }
274
275 private void stopCollectors() {
ssyoon9030fbcd92015-08-17 10:42:07 +0900276 if (adaptiveFlowSampling) {
277 // NewAdaptiveFlowStatsCollector Destructor
278 afsCollectors.values().forEach(NewAdaptiveFlowStatsCollector::stop);
279 afsCollectors.clear();
280 } else {
281 simpleCollectors.values().forEach(FlowStatsCollector::stop);
282 simpleCollectors.clear();
283 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700284 tableStatsCollectors.values().forEach(TableStatisticsCollector::stop);
285 tableStatsCollectors.clear();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700286 }
287
288 private void adjustRate() {
289 DefaultLoad.setPollInterval(flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900290 if (adaptiveFlowSampling) {
291 // NewAdaptiveFlowStatsCollector calAndPollInterval
292 afsCollectors.values().forEach(fsc -> fsc.adjustCalAndPollInterval(flowPollFrequency));
293 } else {
294 simpleCollectors.values().forEach(fsc -> fsc.adjustPollInterval(flowPollFrequency));
295 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700296 tableStatsCollectors.values().forEach(tsc -> tsc.adjustPollInterval(flowPollFrequency));
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700297 }
298
alshabib1cc04f72014-09-16 16:09:58 -0700299 @Override
300 public void applyFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800301 for (FlowRule flowRule : flowRules) {
302 applyRule(flowRule);
alshabib35edb1a2014-09-16 17:44:44 -0700303 }
alshabib1cc04f72014-09-16 16:09:58 -0700304 }
305
alshabib35edb1a2014-09-16 17:44:44 -0700306 private void applyRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900307 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
308 OpenFlowSwitch sw = controller.getSwitch(dpid);
309
Ray Milkey0ae473d2016-04-04 10:56:47 -0700310 if (sw == null) {
311 return;
312 }
313
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700314 FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
315 if (hasPayload(flowRuleExtPayLoad)) {
316 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800317 sw.sendMsg(msg);
318 return;
319 }
alshabibbdcbb102015-04-22 14:16:38 -0700320 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Jonathan Hart3c259162015-10-21 21:31:19 -0700321 Optional.empty(), Optional.of(driverService)).buildFlowAdd());
alshabib35edb1a2014-09-16 17:44:44 -0700322 }
323
alshabib1cc04f72014-09-16 16:09:58 -0700324 @Override
325 public void removeFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800326 for (FlowRule flowRule : flowRules) {
327 removeRule(flowRule);
alshabib219ebaa2014-09-22 15:41:24 -0700328 }
alshabib1cc04f72014-09-16 16:09:58 -0700329 }
330
alshabib219ebaa2014-09-22 15:41:24 -0700331 private void removeRule(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
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700339 FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
340 if (hasPayload(flowRuleExtPayLoad)) {
341 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800342 sw.sendMsg(msg);
343 return;
344 }
alshabibbdcbb102015-04-22 14:16:38 -0700345 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Jonathan Hart3c259162015-10-21 21:31:19 -0700346 Optional.empty(), Optional.of(driverService)).buildFlowDel());
alshabib219ebaa2014-09-22 15:41:24 -0700347 }
348
alshabiba68eb962014-09-24 20:34:13 -0700349 @Override
350 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
351 // TODO: optimize using the ApplicationId
352 removeFlowRule(flowRules);
353 }
354
alshabib193525b2014-10-08 18:58:03 -0700355 @Override
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800356 public void executeBatch(FlowRuleBatchOperation batch) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900357 checkNotNull(batch);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800358
ssyoon9030fbcd92015-08-17 10:42:07 +0900359 Dpid dpid = Dpid.dpid(batch.deviceId().uri());
360 OpenFlowSwitch sw = controller.getSwitch(dpid);
Madan Jampani84382b92016-06-22 08:26:49 -0700361
362 // If switch no longer exists, simply return.
363 if (sw == null) {
364 Set<FlowRule> failures = ImmutableSet.copyOf(Lists.transform(batch.getOperations(), e -> e.target()));
365 providerService.batchOperationCompleted(batch.id(),
366 new CompletedBatchOperation(false, failures, batch.deviceId()));
367 return;
368 }
369 pendingBatches.put(batch.id(), new InternalCacheEntry(batch));
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800370 OFFlowMod mod;
alshabib193525b2014-10-08 18:58:03 -0700371 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
jcc3d4e14a2015-04-21 11:32:05 +0800372 // flow is the third party privacy flow
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700373
374 FlowRuleExtPayLoad flowRuleExtPayLoad = fbe.target().payLoad();
375 if (hasPayload(flowRuleExtPayLoad)) {
376 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800377 sw.sendMsg(msg);
378 continue;
379 }
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700380 FlowModBuilder builder =
Jonathan Hart3c259162015-10-21 21:31:19 -0700381 FlowModBuilder.builder(fbe.target(), sw.factory(),
382 Optional.of(batch.id()), Optional.of(driverService));
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800383 switch (fbe.operator()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700384 case ADD:
385 mod = builder.buildFlowAdd();
386 break;
387 case REMOVE:
388 mod = builder.buildFlowDel();
389 break;
390 case MODIFY:
391 mod = builder.buildFlowMod();
392 break;
393 default:
394 log.error("Unsupported batch operation {}; skipping flowmod {}",
ssyoon9030fbcd92015-08-17 10:42:07 +0900395 fbe.operator(), fbe);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700396 continue;
jcc3d4e14a2015-04-21 11:32:05 +0800397 }
Saurav Das3ea46622015-04-22 14:01:34 -0700398 sw.sendMsg(mod);
alshabib193525b2014-10-08 18:58:03 -0700399 }
jcc3d4e14a2015-04-21 11:32:05 +0800400 OFBarrierRequest.Builder builder = sw.factory().buildBarrierRequest()
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800401 .setXid(batch.id());
402 sw.sendMsg(builder.build());
alshabib193525b2014-10-08 18:58:03 -0700403 }
404
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700405 private boolean hasPayload(FlowRuleExtPayLoad flowRuleExtPayLoad) {
406 return flowRuleExtPayLoad != null &&
407 flowRuleExtPayLoad.payLoad() != null &&
408 flowRuleExtPayLoad.payLoad().length > 0;
409 }
410
alshabib8f1cf4a2014-09-17 14:44:48 -0700411 private class InternalFlowProvider
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800412 implements OpenFlowSwitchListener, OpenFlowEventListener {
alshabib8f1cf4a2014-09-17 14:44:48 -0700413
alshabib8f1cf4a2014-09-17 14:44:48 -0700414 @Override
415 public void switchAdded(Dpid dpid) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700416 createCollector(controller.getSwitch(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700417 }
418
419 @Override
420 public void switchRemoved(Dpid dpid) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900421 if (adaptiveFlowSampling) {
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700422 stopCollectorIfNeeded(afsCollectors.remove(dpid));
ssyoon9030fbcd92015-08-17 10:42:07 +0900423 } else {
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700424 stopCollectorIfNeeded(simpleCollectors.remove(dpid));
alshabibdfc7afb2014-10-21 20:13:27 -0700425 }
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700426 stopCollectorIfNeeded(tableStatsCollectors.remove(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700427 }
428
429 @Override
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700430 public void switchChanged(Dpid dpid) {
431 }
432
433 @Override
alshabib8f1cf4a2014-09-17 14:44:48 -0700434 public void portChanged(Dpid dpid, OFPortStatus status) {
jcc3d4e14a2015-04-21 11:32:05 +0800435 // TODO: Decide whether to evict flows internal store.
alshabib8f1cf4a2014-09-17 14:44:48 -0700436 }
437
438 @Override
439 public void handleMessage(Dpid dpid, OFMessage msg) {
Ray Milkeyada9e2d2016-04-05 16:42:35 -0700440 if (providerService == null) {
441 // We are shutting down, nothing to be done
442 return;
443 }
Jonathan Harte4e74f02016-03-03 12:57:40 -0800444 DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700445 switch (msg.getType()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700446 case FLOW_REMOVED:
447 OFFlowRemoved removed = (OFFlowRemoved) msg;
alshabib6b5cfec2014-09-18 17:42:18 -0700448
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300449 FlowEntry fr = new FlowEntryBuilder(deviceId, removed, getDriver(deviceId)).build();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700450 providerService.flowRemoved(fr);
451 break;
452 case STATS_REPLY:
453 if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW) {
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300454 pushFlowMetrics(dpid, (OFFlowStatsReply) msg, getDriver(deviceId));
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700455 } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.TABLE) {
456 pushTableStatistics(dpid, (OFTableStatsReply) msg);
Cem Türker3baff672017-10-12 15:09:01 +0300457 } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW_LIGHTWEIGHT) {
458 pushFlowLightWeightMetrics(dpid, (OFFlowLightweightStatsReply) msg);
sangho89bf6fb2015-02-09 09:33:13 -0800459 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700460 break;
461 case BARRIER_REPLY:
462 try {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700463 InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800464 if (entry != null) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700465 providerService
466 .batchOperationCompleted(msg.getXid(),
467 entry.completed());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800468 } else {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700469 log.warn("Received unknown Barrier Reply: {}",
470 msg.getXid());
471 }
472 } finally {
473 pendingBatches.invalidate(msg.getXid());
474 }
475 break;
476 case ERROR:
Thomas Vachuska3358af22015-05-19 18:40:34 -0700477 // TODO: This needs to get suppressed in a better way.
478 if (msg instanceof OFBadRequestErrorMsg &&
479 ((OFBadRequestErrorMsg) msg).getCode() == OFBadRequestCode.BAD_TYPE) {
480 log.debug("Received error message {} from {}", msg, dpid);
481 } else {
482 log.warn("Received error message {} from {}", msg, dpid);
483 }
Prince Pereira788797e2016-08-10 11:24:14 +0530484 handleErrorMsg(deviceId, msg);
Ray Milkey4fd3ceb2015-12-10 14:43:08 -0800485 break;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700486 default:
487 log.debug("Unhandled message type: {}", msg.getType());
alshabib8f1cf4a2014-09-17 14:44:48 -0700488 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700489 }
490
Prince Pereira788797e2016-08-10 11:24:14 +0530491 private void handleErrorMsg(DeviceId deviceId, OFMessage msg) {
Prince Pereira141ed812016-09-02 19:03:18 +0530492 InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
Prince Pereira788797e2016-08-10 11:24:14 +0530493 OFErrorMsg error = (OFErrorMsg) msg;
494 OFMessage ofMessage = null;
495 switch (error.getErrType()) {
496 case BAD_ACTION:
497 OFBadActionErrorMsg baErrorMsg = (OFBadActionErrorMsg) error;
498 if (baErrorMsg.getData().getParsedMessage().isPresent()) {
499 ofMessage = baErrorMsg.getData().getParsedMessage().get();
500 }
501 break;
502 case BAD_INSTRUCTION:
503 OFBadInstructionErrorMsg biErrorMsg = (OFBadInstructionErrorMsg) error;
504 if (biErrorMsg.getData().getParsedMessage().isPresent()) {
505 ofMessage = biErrorMsg.getData().getParsedMessage().get();
506 }
507 break;
508 case BAD_MATCH:
509 OFBadMatchErrorMsg bmErrorMsg = (OFBadMatchErrorMsg) error;
510 if (bmErrorMsg.getData().getParsedMessage().isPresent()) {
511 ofMessage = bmErrorMsg.getData().getParsedMessage().get();
512 }
513 break;
514 case FLOW_MOD_FAILED:
515 OFFlowModFailedErrorMsg fmFailed = (OFFlowModFailedErrorMsg) error;
516 if (fmFailed.getData().getParsedMessage().isPresent()) {
517 ofMessage = fmFailed.getData().getParsedMessage().get();
518 }
519 break;
520 default:
521 // Do nothing.
522 return;
523 }
Prince Pereira141ed812016-09-02 19:03:18 +0530524
Prince Pereira788797e2016-08-10 11:24:14 +0530525 if (ofMessage != null) {
Prince Pereira141ed812016-09-02 19:03:18 +0530526
Prince Pereira788797e2016-08-10 11:24:14 +0530527 if (entry != null) {
528 OFFlowMod ofFlowMod = (OFFlowMod) ofMessage;
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300529 entry.appendFailure(new FlowEntryBuilder(deviceId, ofFlowMod, getDriver(deviceId)).build());
Prince Pereira788797e2016-08-10 11:24:14 +0530530 } else {
531 log.error("No matching batch for this error: {}", error);
532 }
Prince Pereira141ed812016-09-02 19:03:18 +0530533
Prince Pereira788797e2016-08-10 11:24:14 +0530534 } else {
Prince Pereira141ed812016-09-02 19:03:18 +0530535
536 U64 cookieId = readCookieIdFromOFErrorMsg(error, msg.getVersion());
537
538 if (cookieId != null) {
539 long flowId = cookieId.getValue();
540
541 if (entry != null) {
542 for (FlowRuleBatchEntry fbEntry : entry.operation.getOperations()) {
543 if (fbEntry.target().id().value() == flowId) {
544 entry.appendFailure(fbEntry.target());
545 break;
546 }
547 }
548 } else {
549 log.error("No matching batch for this error: {}", error);
550 }
551
552 } else {
553 log.error("Flow installation failed but switch " +
554 "didn't tell us which one.");
555 }
Prince Pereira788797e2016-08-10 11:24:14 +0530556 }
557 }
558
Prince Pereira141ed812016-09-02 19:03:18 +0530559 /**
560 * Reading cookieId from OFErrorMsg.
561 *
562 * Loxigen OpenFlow API failed in parsing error messages because of
563 * 64 byte data truncation based on OpenFlow specs. The method written
564 * is a workaround to extract the cookieId from the packet till the
565 * issue is resolved in Loxigen OpenFlow code.
566 * Ref: https://groups.google.com/a/onosproject.org/forum/#!topic
567 * /onos-dev/_KwlHZDllLE
568 *
569 * @param msg OF error message
570 * @param ofVersion Openflow version
571 * @return cookieId
572 */
573 private U64 readCookieIdFromOFErrorMsg(OFErrorMsg msg,
574 OFVersion ofVersion) {
575
576 if (ofVersion.wireVersion < OFVersion.OF_13.wireVersion) {
577 log.debug("Unhandled error msg with OF version {} " +
578 "which is less than {}",
579 ofVersion, OFVersion.OF_13);
580 return null;
581 }
582
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700583 ByteBuf bb = Unpooled.wrappedBuffer(msg.getData().getData());
Prince Pereira141ed812016-09-02 19:03:18 +0530584
585 if (bb.readableBytes() < MIN_EXPECTED_BYTE_LEN) {
586 log.debug("Wrong length: Expected to be >= {}, was: {}",
587 MIN_EXPECTED_BYTE_LEN, bb.readableBytes());
588 return null;
589 }
590
591 byte ofVer = bb.readByte();
592
593 if (ofVer != ofVersion.wireVersion) {
594 log.debug("Wrong version: Expected={}, got={}",
595 ofVersion.wireVersion, ofVer);
596 return null;
597 }
598
599 byte type = bb.readByte();
600
601 if (type != OFType.FLOW_MOD.ordinal()) {
602 log.debug("Wrong type: Expected={}, got={}",
603 OFType.FLOW_MOD.ordinal(), type);
604 return null;
605 }
606
607 int length = U16.f(bb.readShort());
608
609 if (length < MIN_EXPECTED_BYTE_LEN) {
610 log.debug("Wrong length: Expected to be >= {}, was: {}",
611 MIN_EXPECTED_BYTE_LEN, length);
612 return null;
613 }
614
615 bb.skipBytes(SKIP_BYTES);
616 return U64.ofRaw(bb.readLong());
617 }
618
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700619 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700620 public void receivedRoleReply(Dpid dpid, RoleState requested,
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800621 RoleState response) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700622 // Do nothing here for now.
623 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700624
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300625 private DriverHandler getDriver(DeviceId devId) {
626 Driver driver = driverService.getDriver(devId);
627 DriverHandler handler = new DefaultDriverHandler(new DefaultDriverData(driver, devId));
628 return handler;
629 }
630
631 private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies, DriverHandler handler) {
alshabib64def642014-12-02 23:27:37 -0800632
alshabib54ce5892014-09-23 17:50:51 -0700633 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900634 NewAdaptiveFlowStatsCollector afsc = afsCollectors.get(dpid);
alshabib54ce5892014-09-23 17:50:51 -0700635
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900636 if (adaptiveFlowSampling && afsc != null) {
637 List<FlowEntry> flowEntries = replies.getEntries().stream()
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300638 .map(entry -> new FlowEntryBuilder(did, entry, handler).withSetAfsc(afsc).build())
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900639 .collect(Collectors.toList());
alshabib54ce5892014-09-23 17:50:51 -0700640
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900641 // Check that OFFlowStatsReply Xid is same with the one of OFFlowStatsRequest?
642 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
643 log.debug("OpenFlowRuleProvider:pushFlowMetrics, flowMissingXid={}, "
644 + "OFFlowStatsReply Xid={}, for {}",
645 afsc.getFlowMissingXid(), replies.getXid(), dpid);
646 if (afsc.getFlowMissingXid() == replies.getXid()) {
647 // call entire flow stats update with flowMissing synchronization.
648 // used existing pushFlowMetrics
649 providerService.pushFlowMetrics(did, flowEntries);
ssyoon9030fbcd92015-08-17 10:42:07 +0900650 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900651 // reset flowMissingXid to NO_FLOW_MISSING_XID
652 afsc.setFlowMissingXid(NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID);
653 } else {
654 // call individual flow stats update
655 providerService.pushFlowMetricsWithoutFlowMissing(did, flowEntries);
ssyoon9030fbcd92015-08-17 10:42:07 +0900656 }
657 } else {
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900658 List<FlowEntry> flowEntries = replies.getEntries().stream()
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300659 .map(entry -> new FlowEntryBuilder(did, entry, handler).build())
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900660 .collect(Collectors.toList());
661
ssyoon9030fbcd92015-08-17 10:42:07 +0900662 // call existing entire flow stats update with flowMissing synchronization
663 providerService.pushFlowMetrics(did, flowEntries);
664 }
alshabib5c370ff2014-09-18 10:12:14 -0700665 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700666
667 private void pushTableStatistics(Dpid dpid, OFTableStatsReply replies) {
668
669 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
670 List<TableStatisticsEntry> tableStatsEntries = replies.getEntries().stream()
671 .map(entry -> buildTableStatistics(did, entry))
672 .filter(Objects::nonNull)
673 .collect(Collectors.toList());
674 providerService.pushTableStatistics(did, tableStatsEntries);
675 }
676
Cem Türker3baff672017-10-12 15:09:01 +0300677 private void pushFlowLightWeightMetrics(Dpid dpid, OFFlowLightweightStatsReply replies) {
678
679 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
680 NewAdaptiveFlowStatsCollector afsc = afsCollectors.get(dpid);
681 if (adaptiveFlowSampling && afsc != null) {
682 List<FlowEntry> flowEntries = replies.getEntries().stream()
683 .map(entry -> new FlowEntryBuilder(did, entry, driverService).withSetAfsc(afsc).build())
684 .collect(Collectors.toList());
685
686 // Check that OFFlowStatsReply Xid is same with the one of OFFlowStatsRequest?
687 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
688 log.debug("OpenFlowRuleProvider:pushFlowMetrics, flowMissingXid={}, "
689 + "OFFlowStatsReply Xid={}, for {}",
690 afsc.getFlowMissingXid(), replies.getXid(), dpid);
691 if (afsc.getFlowMissingXid() == replies.getXid()) {
692 // call entire flow stats update with flowMissing synchronization.
693 // used existing pushFlowMetrics
694 providerService.pushFlowMetrics(did, flowEntries);
695 }
696 // reset flowMissingXid to NO_FLOW_MISSING_XID
697 afsc.setFlowMissingXid(NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID);
698 } else {
699 // call individual flow stats update
700 providerService.pushFlowMetricsWithoutFlowMissing(did, flowEntries);
701 }
702 } else {
703 List<FlowEntry> flowEntries = replies.getEntries().stream()
704 .map(entry -> new FlowEntryBuilder(did, entry, driverService).build())
705 .collect(Collectors.toList());
706 // call existing entire flow stats update with flowMissing synchronization
707 providerService.pushFlowMetrics(did, flowEntries);
708 }
709 }
710
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700711 private TableStatisticsEntry buildTableStatistics(DeviceId deviceId,
712 OFTableStatsEntry ofEntry) {
713 TableStatisticsEntry entry = null;
714 if (ofEntry != null) {
hjtsao1a4333c2018-10-22 11:02:00 -0700715 IndexTableId tid = IndexTableId.of(ofEntry.getTableId().getValue());
716
717 try {
718 entry = DefaultTableStatisticsEntry.builder()
719 .withDeviceId(deviceId)
720 .withTableId(tid)
721 .withActiveFlowEntries(ofEntry.getActiveCount())
722 .withPacketsLookedUpCount(ofEntry.getLookupCount().getValue())
723 .withPacketsMatchedCount(ofEntry.getMatchedCount().getValue())
724 .withMaxSize(ofEntry.getMaxEntries()).build();
725 } catch (UnsupportedOperationException e) {
726 // The exception "UnsupportedOperationException" is thrown by "getMaxEntries()".
727 entry = DefaultTableStatisticsEntry.builder()
728 .withDeviceId(deviceId)
729 .withTableId(tid)
730 .withActiveFlowEntries(ofEntry.getActiveCount())
731 .withPacketsLookedUpCount(ofEntry.getLookupCount().getValue())
732 .withPacketsMatchedCount(ofEntry.getMatchedCount().getValue()).build();
733 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700734 }
735
736 return entry;
737
738 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700739 }
alshabib1cc04f72014-09-16 16:09:58 -0700740
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800741 /**
jcc3d4e14a2015-04-21 11:32:05 +0800742 * The internal cache entry holding the original request as well as
743 * accumulating the any failures along the way.
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700744 * <p/>
jcc3d4e14a2015-04-21 11:32:05 +0800745 * If this entry is evicted from the cache then the entire operation is
746 * considered failed. Otherwise, only the failures reported by the device
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800747 * will be propagated up.
748 */
749 private class InternalCacheEntry {
alshabib902d41b2014-10-07 16:52:05 -0700750
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800751 private final FlowRuleBatchOperation operation;
752 private final Set<FlowRule> failures = Sets.newConcurrentHashSet();
alshabib193525b2014-10-08 18:58:03 -0700753
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800754 public InternalCacheEntry(FlowRuleBatchOperation operation) {
755 this.operation = operation;
alshabib902d41b2014-10-07 16:52:05 -0700756 }
757
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800758 /**
759 * Appends a failed rule to the set of failed items.
jcc3d4e14a2015-04-21 11:32:05 +0800760 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800761 * @param rule the failed rule
762 */
763 public void appendFailure(FlowRule rule) {
764 failures.add(rule);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800765 }
766
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800767 /**
768 * Fails the entire batch and returns the failed operation.
jcc3d4e14a2015-04-21 11:32:05 +0800769 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800770 * @return the failed operation
771 */
772 public CompletedBatchOperation failedCompletion() {
773 Set<FlowRule> fails = operation.getOperations().stream()
774 .map(op -> op.target()).collect(Collectors.toSet());
jcc3d4e14a2015-04-21 11:32:05 +0800775 return new CompletedBatchOperation(false,
776 Collections
777 .unmodifiableSet(fails),
778 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700779 }
780
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800781 /**
782 * Returns the completed operation and whether the batch suceeded.
jcc3d4e14a2015-04-21 11:32:05 +0800783 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800784 * @return the completed operation
785 */
786 public CompletedBatchOperation completed() {
jcc3d4e14a2015-04-21 11:32:05 +0800787 return new CompletedBatchOperation(
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700788 failures.isEmpty(),
789 Collections
790 .unmodifiableSet(failures),
791 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700792 }
alshabib902d41b2014-10-07 16:52:05 -0700793 }
alshabiba68eb962014-09-24 20:34:13 -0700794
hjtsao1a4333c2018-10-22 11:02:00 -0700795}