blob: d226f2af522ae46c8e194a87b38ca37f59f3903c [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;
alshabib1cc04f72014-09-16 16:09:58 -070029import org.apache.felix.scr.annotations.Activate;
30import org.apache.felix.scr.annotations.Component;
31import org.apache.felix.scr.annotations.Deactivate;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070032import org.apache.felix.scr.annotations.Modified;
33import org.apache.felix.scr.annotations.Property;
alshabib1cc04f72014-09-16 16:09:58 -070034import org.apache.felix.scr.annotations.Reference;
35import org.apache.felix.scr.annotations.ReferenceCardinality;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070036import org.onosproject.cfg.ComponentConfigService;
Brian O'Connorabafb502014-12-02 22:26:20 -080037import org.onosproject.core.ApplicationId;
38import org.onosproject.net.DeviceId;
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -030039import org.onosproject.net.driver.DefaultDriverData;
40import org.onosproject.net.driver.DefaultDriverHandler;
41import org.onosproject.net.driver.Driver;
42import org.onosproject.net.driver.DriverHandler;
Jonathan Hart3c259162015-10-21 21:31:19 -070043import org.onosproject.net.driver.DriverService;
Brian O'Connorabafb502014-12-02 22:26:20 -080044import org.onosproject.net.flow.CompletedBatchOperation;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070045import org.onosproject.net.flow.DefaultTableStatisticsEntry;
Brian O'Connorabafb502014-12-02 22:26:20 -080046import org.onosproject.net.flow.FlowEntry;
47import org.onosproject.net.flow.FlowRule;
Ray Milkey7bf273c2017-09-27 16:15:15 -070048import org.onosproject.net.flow.oldbatch.FlowRuleBatchEntry;
49import org.onosproject.net.flow.oldbatch.FlowRuleBatchOperation;
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -070050import org.onosproject.net.flow.FlowRuleExtPayLoad;
Brian O'Connorabafb502014-12-02 22:26:20 -080051import org.onosproject.net.flow.FlowRuleProvider;
52import org.onosproject.net.flow.FlowRuleProviderRegistry;
53import org.onosproject.net.flow.FlowRuleProviderService;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070054import org.onosproject.net.flow.TableStatisticsEntry;
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;
69import 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;
105import static org.slf4j.LoggerFactory.getLogger;
alshabibeec3a062014-09-17 18:01:26 -0700106
alshabib1cc04f72014-09-16 16:09:58 -0700107/**
jcc3d4e14a2015-04-21 11:32:05 +0800108 * Provider which uses an OpenFlow controller to detect network end-station
109 * hosts.
alshabib1cc04f72014-09-16 16:09:58 -0700110 */
111@Component(immediate = true)
jcc3d4e14a2015-04-21 11:32:05 +0800112public class OpenFlowRuleProvider extends AbstractProvider
113 implements FlowRuleProvider {
alshabib1cc04f72014-09-16 16:09:58 -0700114
115 private final Logger log = getLogger(getClass());
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected FlowRuleProviderRegistry providerRegistry;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected OpenFlowController controller;
122
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected ComponentConfigService cfgService;
125
Jonathan Hart3c259162015-10-21 21:31:19 -0700126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
127 protected DriverService driverService;
128
ssyoon9030fbcd92015-08-17 10:42:07 +0900129 private static final int DEFAULT_POLL_FREQUENCY = 5;
Prince Pereira141ed812016-09-02 19:03:18 +0530130 private static final int MIN_EXPECTED_BYTE_LEN = 56;
131 private static final int SKIP_BYTES = 4;
132 private static final boolean DEFAULT_ADAPTIVE_FLOW_SAMPLING = false;
133
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700134 @Property(name = "flowPollFrequency", intValue = DEFAULT_POLL_FREQUENCY,
135 label = "Frequency (in seconds) for polling flow statistics")
136 private int flowPollFrequency = DEFAULT_POLL_FREQUENCY;
137
ssyoon9030fbcd92015-08-17 10:42:07 +0900138 @Property(name = "adaptiveFlowSampling", boolValue = DEFAULT_ADAPTIVE_FLOW_SAMPLING,
139 label = "Adaptive Flow Sampling is on or off")
140 private boolean adaptiveFlowSampling = DEFAULT_ADAPTIVE_FLOW_SAMPLING;
141
alshabib1cc04f72014-09-16 16:09:58 -0700142 private FlowRuleProviderService providerService;
143
alshabibeec3a062014-09-17 18:01:26 -0700144 private final InternalFlowProvider listener = new InternalFlowProvider();
145
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800146 private Cache<Long, InternalCacheEntry> pendingBatches;
alshabib193525b2014-10-08 18:58:03 -0700147
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900148 private final Timer timer = new Timer("onos-openflow-collector");
149
Cem Türker3baff672017-10-12 15:09:01 +0300150
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900151 // Old simple collector set
Madan Jampani6b266102016-06-23 00:56:36 -0700152 private final Map<Dpid, FlowStatsCollector> simpleCollectors = Maps.newConcurrentMap();
ssyoon9030fbcd92015-08-17 10:42:07 +0900153
154 // NewAdaptiveFlowStatsCollector Set
Madan Jampani6b266102016-06-23 00:56:36 -0700155 private final Map<Dpid, NewAdaptiveFlowStatsCollector> afsCollectors = Maps.newConcurrentMap();
156 private final Map<Dpid, TableStatisticsCollector> tableStatsCollectors = Maps.newConcurrentMap();
alshabib3d643ec2014-10-22 18:33:00 -0700157
alshabib1cc04f72014-09-16 16:09:58 -0700158 /**
159 * Creates an OpenFlow host provider.
160 */
161 public OpenFlowRuleProvider() {
Brian O'Connorabafb502014-12-02 22:26:20 -0800162 super(new ProviderId("of", "org.onosproject.provider.openflow"));
alshabib1cc04f72014-09-16 16:09:58 -0700163 }
164
165 @Activate
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700166 protected void activate(ComponentContext context) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700167 cfgService.registerProperties(getClass());
alshabib1cc04f72014-09-16 16:09:58 -0700168 providerService = providerRegistry.register(this);
alshabibeec3a062014-09-17 18:01:26 -0700169 controller.addListener(listener);
170 controller.addEventListener(listener);
alshabib3d643ec2014-10-22 18:33:00 -0700171
Antonio Marsico1c5ae1f2015-12-15 15:31:56 +0100172 modified(context);
173
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700174 pendingBatches = createBatchCache();
ssyoon9030fbcd92015-08-17 10:42:07 +0900175
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700176 createCollectors();
alshabib3d643ec2014-10-22 18:33:00 -0700177
ssyoon9030fbcd92015-08-17 10:42:07 +0900178 log.info("Started with flowPollFrequency = {}, adaptiveFlowSampling = {}",
179 flowPollFrequency, adaptiveFlowSampling);
alshabib1cc04f72014-09-16 16:09:58 -0700180 }
181
182 @Deactivate
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700183 protected void deactivate(ComponentContext context) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700184 cfgService.unregisterProperties(getClass(), false);
185 stopCollectors();
alshabib1cc04f72014-09-16 16:09:58 -0700186 providerRegistry.unregister(this);
187 providerService = null;
188
189 log.info("Stopped");
190 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800191
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700192 @Modified
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700193 protected void modified(ComponentContext context) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700194 Dictionary<?, ?> properties = context.getProperties();
195 int newFlowPollFrequency;
196 try {
197 String s = get(properties, "flowPollFrequency");
198 newFlowPollFrequency = isNullOrEmpty(s) ? flowPollFrequency : Integer.parseInt(s.trim());
199
200 } catch (NumberFormatException | ClassCastException e) {
201 newFlowPollFrequency = flowPollFrequency;
202 }
203
204 if (newFlowPollFrequency != flowPollFrequency) {
205 flowPollFrequency = newFlowPollFrequency;
206 adjustRate();
207 }
208
209 log.info("Settings: flowPollFrequency={}", flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900210
211 boolean newAdaptiveFlowSampling;
212 String s = get(properties, "adaptiveFlowSampling");
213 newAdaptiveFlowSampling = isNullOrEmpty(s) ? adaptiveFlowSampling : Boolean.parseBoolean(s.trim());
214
215 if (newAdaptiveFlowSampling != adaptiveFlowSampling) {
216 // stop previous collector
217 stopCollectors();
218 adaptiveFlowSampling = newAdaptiveFlowSampling;
219 // create new collectors
220 createCollectors();
221 }
222
223 log.info("Settings: adaptiveFlowSampling={}", adaptiveFlowSampling);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700224 }
225
226 private Cache<Long, InternalCacheEntry> createBatchCache() {
227 return CacheBuilder.newBuilder()
228 .expireAfterWrite(10, TimeUnit.SECONDS)
229 .removalListener((RemovalNotification<Long, InternalCacheEntry> notification) -> {
230 if (notification.getCause() == RemovalCause.EXPIRED) {
231 providerService.batchOperationCompleted(notification.getKey(),
232 notification.getValue().failedCompletion());
233 }
234 }).build();
235 }
236
237 private void createCollectors() {
238 controller.getSwitches().forEach(this::createCollector);
239 }
240
241 private void createCollector(OpenFlowSwitch sw) {
Kavitha Alagesan6704df32016-08-18 15:15:31 +0530242 if (sw == null) {
243 return;
244 }
ssyoon9030fbcd92015-08-17 10:42:07 +0900245 if (adaptiveFlowSampling) {
246 // NewAdaptiveFlowStatsCollector Constructor
Charles Chan14967c22015-12-07 11:11:50 -0800247 NewAdaptiveFlowStatsCollector fsc =
248 new NewAdaptiveFlowStatsCollector(driverService, sw, flowPollFrequency);
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700249 stopCollectorIfNeeded(afsCollectors.put(new Dpid(sw.getId()), fsc));
Palash Kalaa439afe2017-05-16 14:53:15 +0900250 fsc.start();
ssyoon9030fbcd92015-08-17 10:42:07 +0900251 } else {
252 FlowStatsCollector fsc = new FlowStatsCollector(timer, sw, flowPollFrequency);
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700253 stopCollectorIfNeeded(simpleCollectors.put(new Dpid(sw.getId()), fsc));
Palash Kalaa439afe2017-05-16 14:53:15 +0900254 fsc.start();
ssyoon9030fbcd92015-08-17 10:42:07 +0900255 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700256 TableStatisticsCollector tsc = new TableStatisticsCollector(timer, sw, flowPollFrequency);
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700257 stopCollectorIfNeeded(tableStatsCollectors.put(new Dpid(sw.getId()), tsc));
Palash Kalaa439afe2017-05-16 14:53:15 +0900258 tsc.start();
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700259 }
260
261 private void stopCollectorIfNeeded(SwitchDataCollector collector) {
262 if (collector != null) {
263 collector.stop();
264 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700265 }
266
267 private void stopCollectors() {
ssyoon9030fbcd92015-08-17 10:42:07 +0900268 if (adaptiveFlowSampling) {
269 // NewAdaptiveFlowStatsCollector Destructor
270 afsCollectors.values().forEach(NewAdaptiveFlowStatsCollector::stop);
271 afsCollectors.clear();
272 } else {
273 simpleCollectors.values().forEach(FlowStatsCollector::stop);
274 simpleCollectors.clear();
275 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700276 tableStatsCollectors.values().forEach(TableStatisticsCollector::stop);
277 tableStatsCollectors.clear();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700278 }
279
280 private void adjustRate() {
281 DefaultLoad.setPollInterval(flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900282 if (adaptiveFlowSampling) {
283 // NewAdaptiveFlowStatsCollector calAndPollInterval
284 afsCollectors.values().forEach(fsc -> fsc.adjustCalAndPollInterval(flowPollFrequency));
285 } else {
286 simpleCollectors.values().forEach(fsc -> fsc.adjustPollInterval(flowPollFrequency));
287 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700288 tableStatsCollectors.values().forEach(tsc -> tsc.adjustPollInterval(flowPollFrequency));
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700289 }
290
Jordan Halterman3af217c2019-03-05 18:44:03 -0800291 private void resetEvents(Dpid dpid) {
292 SwitchDataCollector collector;
293 if (adaptiveFlowSampling) {
294 collector = afsCollectors.get(dpid);
295 } else {
296 collector = simpleCollectors.get(dpid);
297 }
298 if (collector != null) {
299 collector.resetEvents();
300 }
301 }
302
303 private void recordEvent(Dpid dpid) {
304 recordEvents(dpid, 1);
305 }
306
307 private void recordEvents(Dpid dpid, int events) {
308 SwitchDataCollector collector;
309 if (adaptiveFlowSampling) {
310 collector = afsCollectors.get(dpid);
311 } else {
312 collector = simpleCollectors.get(dpid);
313 }
314 if (collector != null) {
315 collector.recordEvents(events);
316 }
317 }
318
alshabib1cc04f72014-09-16 16:09:58 -0700319 @Override
320 public void applyFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800321 for (FlowRule flowRule : flowRules) {
322 applyRule(flowRule);
alshabib35edb1a2014-09-16 17:44:44 -0700323 }
alshabib1cc04f72014-09-16 16:09:58 -0700324 }
325
alshabib35edb1a2014-09-16 17:44:44 -0700326 private void applyRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900327 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
328 OpenFlowSwitch sw = controller.getSwitch(dpid);
329
Ray Milkey0ae473d2016-04-04 10:56:47 -0700330 if (sw == null) {
331 return;
332 }
333
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700334 FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
335 if (hasPayload(flowRuleExtPayLoad)) {
336 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800337 sw.sendMsg(msg);
338 return;
339 }
alshabibbdcbb102015-04-22 14:16:38 -0700340 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Jonathan Hart3c259162015-10-21 21:31:19 -0700341 Optional.empty(), Optional.of(driverService)).buildFlowAdd());
Jordan Halterman3af217c2019-03-05 18:44:03 -0800342
343 recordEvent(dpid);
alshabib35edb1a2014-09-16 17:44:44 -0700344 }
345
alshabib1cc04f72014-09-16 16:09:58 -0700346 @Override
347 public void removeFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800348 for (FlowRule flowRule : flowRules) {
349 removeRule(flowRule);
alshabib219ebaa2014-09-22 15:41:24 -0700350 }
alshabib1cc04f72014-09-16 16:09:58 -0700351 }
352
alshabib219ebaa2014-09-22 15:41:24 -0700353 private void removeRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900354 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
355 OpenFlowSwitch sw = controller.getSwitch(dpid);
356
Ray Milkey0ae473d2016-04-04 10:56:47 -0700357 if (sw == null) {
358 return;
359 }
360
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700361 FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
362 if (hasPayload(flowRuleExtPayLoad)) {
363 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800364 sw.sendMsg(msg);
365 return;
366 }
alshabibbdcbb102015-04-22 14:16:38 -0700367 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Jonathan Hart3c259162015-10-21 21:31:19 -0700368 Optional.empty(), Optional.of(driverService)).buildFlowDel());
Jordan Halterman3af217c2019-03-05 18:44:03 -0800369
370 recordEvent(dpid);
alshabib219ebaa2014-09-22 15:41:24 -0700371 }
372
alshabiba68eb962014-09-24 20:34:13 -0700373 @Override
374 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
375 // TODO: optimize using the ApplicationId
376 removeFlowRule(flowRules);
377 }
378
alshabib193525b2014-10-08 18:58:03 -0700379 @Override
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800380 public void executeBatch(FlowRuleBatchOperation batch) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900381 checkNotNull(batch);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800382
ssyoon9030fbcd92015-08-17 10:42:07 +0900383 Dpid dpid = Dpid.dpid(batch.deviceId().uri());
384 OpenFlowSwitch sw = controller.getSwitch(dpid);
Madan Jampani84382b92016-06-22 08:26:49 -0700385
386 // If switch no longer exists, simply return.
387 if (sw == null) {
388 Set<FlowRule> failures = ImmutableSet.copyOf(Lists.transform(batch.getOperations(), e -> e.target()));
389 providerService.batchOperationCompleted(batch.id(),
390 new CompletedBatchOperation(false, failures, batch.deviceId()));
391 return;
392 }
393 pendingBatches.put(batch.id(), new InternalCacheEntry(batch));
pier7d146412019-10-24 13:56:58 +0200394 // Build a batch of flow mods - to reduce the number i/o asked to the SO
395 Set<OFFlowMod> mods = Sets.newHashSet();
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800396 OFFlowMod mod;
alshabib193525b2014-10-08 18:58:03 -0700397 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
jcc3d4e14a2015-04-21 11:32:05 +0800398 // flow is the third party privacy flow
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700399 FlowRuleExtPayLoad flowRuleExtPayLoad = fbe.target().payLoad();
400 if (hasPayload(flowRuleExtPayLoad)) {
401 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800402 sw.sendMsg(msg);
403 continue;
404 }
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700405 FlowModBuilder builder =
Jonathan Hart3c259162015-10-21 21:31:19 -0700406 FlowModBuilder.builder(fbe.target(), sw.factory(),
407 Optional.of(batch.id()), Optional.of(driverService));
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700408 NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800409 switch (fbe.operator()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700410 case ADD:
411 mod = builder.buildFlowAdd();
412 break;
413 case REMOVE:
414 mod = builder.buildFlowDel();
415 break;
416 case MODIFY:
417 mod = builder.buildFlowMod();
418 break;
419 default:
420 log.error("Unsupported batch operation {}; skipping flowmod {}",
ssyoon9030fbcd92015-08-17 10:42:07 +0900421 fbe.operator(), fbe);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700422 continue;
jcc3d4e14a2015-04-21 11:32:05 +0800423 }
pier7d146412019-10-24 13:56:58 +0200424 mods.add(mod);
alshabib193525b2014-10-08 18:58:03 -0700425 }
pier7d146412019-10-24 13:56:58 +0200426 // Build a list to mantain the order
427 List<OFMessage> modsTosend = Lists.newArrayList(mods);
jcc3d4e14a2015-04-21 11:32:05 +0800428 OFBarrierRequest.Builder builder = sw.factory().buildBarrierRequest()
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800429 .setXid(batch.id());
pier7d146412019-10-24 13:56:58 +0200430 // Adds finally the barrier request
431 modsTosend.add(builder.build());
432 sw.sendMsg(modsTosend);
433 // Take into account also the barrier request
434 recordEvents(dpid, (batch.getOperations().size() + 1));
alshabib193525b2014-10-08 18:58:03 -0700435 }
436
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700437 private boolean hasPayload(FlowRuleExtPayLoad flowRuleExtPayLoad) {
438 return flowRuleExtPayLoad != null &&
439 flowRuleExtPayLoad.payLoad() != null &&
440 flowRuleExtPayLoad.payLoad().length > 0;
441 }
442
alshabib8f1cf4a2014-09-17 14:44:48 -0700443 private class InternalFlowProvider
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800444 implements OpenFlowSwitchListener, OpenFlowEventListener {
alshabib8f1cf4a2014-09-17 14:44:48 -0700445
alshabib8f1cf4a2014-09-17 14:44:48 -0700446 @Override
447 public void switchAdded(Dpid dpid) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700448 createCollector(controller.getSwitch(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700449 }
450
451 @Override
452 public void switchRemoved(Dpid dpid) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900453 if (adaptiveFlowSampling) {
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700454 stopCollectorIfNeeded(afsCollectors.remove(dpid));
ssyoon9030fbcd92015-08-17 10:42:07 +0900455 } else {
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700456 stopCollectorIfNeeded(simpleCollectors.remove(dpid));
alshabibdfc7afb2014-10-21 20:13:27 -0700457 }
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700458 stopCollectorIfNeeded(tableStatsCollectors.remove(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700459 }
460
461 @Override
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700462 public void switchChanged(Dpid dpid) {
463 }
464
465 @Override
alshabib8f1cf4a2014-09-17 14:44:48 -0700466 public void portChanged(Dpid dpid, OFPortStatus status) {
jcc3d4e14a2015-04-21 11:32:05 +0800467 // TODO: Decide whether to evict flows internal store.
alshabib8f1cf4a2014-09-17 14:44:48 -0700468 }
469
470 @Override
471 public void handleMessage(Dpid dpid, OFMessage msg) {
Ray Milkeyada9e2d2016-04-05 16:42:35 -0700472 if (providerService == null) {
473 // We are shutting down, nothing to be done
474 return;
475 }
Jonathan Harte4e74f02016-03-03 12:57:40 -0800476 DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700477 switch (msg.getType()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700478 case FLOW_REMOVED:
479 OFFlowRemoved removed = (OFFlowRemoved) msg;
alshabib6b5cfec2014-09-18 17:42:18 -0700480
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300481 FlowEntry fr = new FlowEntryBuilder(deviceId, removed, getDriver(deviceId)).build();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700482 providerService.flowRemoved(fr);
483 break;
484 case STATS_REPLY:
485 if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW) {
Jordan Halterman3af217c2019-03-05 18:44:03 -0800486 // Let's unblock first the collector
487 SwitchDataCollector collector;
488 if (adaptiveFlowSampling) {
489 collector = afsCollectors.get(dpid);
490 } else {
491 collector = simpleCollectors.get(dpid);
492 }
493 if (collector != null) {
494 collector.received();
495 }
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300496 pushFlowMetrics(dpid, (OFFlowStatsReply) msg, getDriver(deviceId));
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700497 } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.TABLE) {
498 pushTableStatistics(dpid, (OFTableStatsReply) msg);
Cem Türker3baff672017-10-12 15:09:01 +0300499 } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW_LIGHTWEIGHT) {
500 pushFlowLightWeightMetrics(dpid, (OFFlowLightweightStatsReply) msg);
sangho89bf6fb2015-02-09 09:33:13 -0800501 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700502 break;
503 case BARRIER_REPLY:
504 try {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700505 InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800506 if (entry != null) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700507 providerService
508 .batchOperationCompleted(msg.getXid(),
509 entry.completed());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800510 } else {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700511 log.warn("Received unknown Barrier Reply: {}",
512 msg.getXid());
513 }
514 } finally {
515 pendingBatches.invalidate(msg.getXid());
516 }
517 break;
518 case ERROR:
Thomas Vachuska3358af22015-05-19 18:40:34 -0700519 // TODO: This needs to get suppressed in a better way.
520 if (msg instanceof OFBadRequestErrorMsg &&
521 ((OFBadRequestErrorMsg) msg).getCode() == OFBadRequestCode.BAD_TYPE) {
522 log.debug("Received error message {} from {}", msg, dpid);
523 } else {
524 log.warn("Received error message {} from {}", msg, dpid);
525 }
Prince Pereira788797e2016-08-10 11:24:14 +0530526 handleErrorMsg(deviceId, msg);
Ray Milkey4fd3ceb2015-12-10 14:43:08 -0800527 break;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700528 default:
529 log.debug("Unhandled message type: {}", msg.getType());
alshabib8f1cf4a2014-09-17 14:44:48 -0700530 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700531 }
532
Prince Pereira788797e2016-08-10 11:24:14 +0530533 private void handleErrorMsg(DeviceId deviceId, OFMessage msg) {
Prince Pereira141ed812016-09-02 19:03:18 +0530534 InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
Prince Pereira788797e2016-08-10 11:24:14 +0530535 OFErrorMsg error = (OFErrorMsg) msg;
536 OFMessage ofMessage = null;
537 switch (error.getErrType()) {
538 case BAD_ACTION:
539 OFBadActionErrorMsg baErrorMsg = (OFBadActionErrorMsg) error;
540 if (baErrorMsg.getData().getParsedMessage().isPresent()) {
541 ofMessage = baErrorMsg.getData().getParsedMessage().get();
542 }
543 break;
544 case BAD_INSTRUCTION:
545 OFBadInstructionErrorMsg biErrorMsg = (OFBadInstructionErrorMsg) error;
546 if (biErrorMsg.getData().getParsedMessage().isPresent()) {
547 ofMessage = biErrorMsg.getData().getParsedMessage().get();
548 }
549 break;
550 case BAD_MATCH:
551 OFBadMatchErrorMsg bmErrorMsg = (OFBadMatchErrorMsg) error;
552 if (bmErrorMsg.getData().getParsedMessage().isPresent()) {
553 ofMessage = bmErrorMsg.getData().getParsedMessage().get();
554 }
555 break;
556 case FLOW_MOD_FAILED:
557 OFFlowModFailedErrorMsg fmFailed = (OFFlowModFailedErrorMsg) error;
558 if (fmFailed.getData().getParsedMessage().isPresent()) {
559 ofMessage = fmFailed.getData().getParsedMessage().get();
560 }
561 break;
562 default:
563 // Do nothing.
564 return;
565 }
Prince Pereira141ed812016-09-02 19:03:18 +0530566
Prince Pereira788797e2016-08-10 11:24:14 +0530567 if (ofMessage != null) {
Prince Pereira141ed812016-09-02 19:03:18 +0530568
Prince Pereira788797e2016-08-10 11:24:14 +0530569 if (entry != null) {
570 OFFlowMod ofFlowMod = (OFFlowMod) ofMessage;
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300571 entry.appendFailure(new FlowEntryBuilder(deviceId, ofFlowMod, getDriver(deviceId)).build());
Prince Pereira788797e2016-08-10 11:24:14 +0530572 } else {
573 log.error("No matching batch for this error: {}", error);
574 }
Prince Pereira141ed812016-09-02 19:03:18 +0530575
Prince Pereira788797e2016-08-10 11:24:14 +0530576 } else {
Prince Pereira141ed812016-09-02 19:03:18 +0530577
578 U64 cookieId = readCookieIdFromOFErrorMsg(error, msg.getVersion());
579
580 if (cookieId != null) {
581 long flowId = cookieId.getValue();
582
583 if (entry != null) {
584 for (FlowRuleBatchEntry fbEntry : entry.operation.getOperations()) {
585 if (fbEntry.target().id().value() == flowId) {
586 entry.appendFailure(fbEntry.target());
587 break;
588 }
589 }
590 } else {
591 log.error("No matching batch for this error: {}", error);
592 }
593
594 } else {
595 log.error("Flow installation failed but switch " +
596 "didn't tell us which one.");
597 }
Prince Pereira788797e2016-08-10 11:24:14 +0530598 }
599 }
600
Prince Pereira141ed812016-09-02 19:03:18 +0530601 /**
602 * Reading cookieId from OFErrorMsg.
603 *
604 * Loxigen OpenFlow API failed in parsing error messages because of
605 * 64 byte data truncation based on OpenFlow specs. The method written
606 * is a workaround to extract the cookieId from the packet till the
607 * issue is resolved in Loxigen OpenFlow code.
608 * Ref: https://groups.google.com/a/onosproject.org/forum/#!topic
609 * /onos-dev/_KwlHZDllLE
610 *
611 * @param msg OF error message
612 * @param ofVersion Openflow version
613 * @return cookieId
614 */
615 private U64 readCookieIdFromOFErrorMsg(OFErrorMsg msg,
616 OFVersion ofVersion) {
617
618 if (ofVersion.wireVersion < OFVersion.OF_13.wireVersion) {
619 log.debug("Unhandled error msg with OF version {} " +
620 "which is less than {}",
621 ofVersion, OFVersion.OF_13);
622 return null;
623 }
624
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700625 ByteBuf bb = Unpooled.wrappedBuffer(msg.getData().getData());
Prince Pereira141ed812016-09-02 19:03:18 +0530626
627 if (bb.readableBytes() < MIN_EXPECTED_BYTE_LEN) {
628 log.debug("Wrong length: Expected to be >= {}, was: {}",
629 MIN_EXPECTED_BYTE_LEN, bb.readableBytes());
630 return null;
631 }
632
633 byte ofVer = bb.readByte();
634
635 if (ofVer != ofVersion.wireVersion) {
636 log.debug("Wrong version: Expected={}, got={}",
637 ofVersion.wireVersion, ofVer);
638 return null;
639 }
640
641 byte type = bb.readByte();
642
643 if (type != OFType.FLOW_MOD.ordinal()) {
644 log.debug("Wrong type: Expected={}, got={}",
645 OFType.FLOW_MOD.ordinal(), type);
646 return null;
647 }
648
649 int length = U16.f(bb.readShort());
650
651 if (length < MIN_EXPECTED_BYTE_LEN) {
652 log.debug("Wrong length: Expected to be >= {}, was: {}",
653 MIN_EXPECTED_BYTE_LEN, length);
654 return null;
655 }
656
657 bb.skipBytes(SKIP_BYTES);
658 return U64.ofRaw(bb.readLong());
659 }
660
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700661 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700662 public void receivedRoleReply(Dpid dpid, RoleState requested,
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800663 RoleState response) {
Jordan Halterman3af217c2019-03-05 18:44:03 -0800664 if (response == RoleState.MASTER) {
665 resetEvents(dpid);
666 }
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700667 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700668
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300669 private DriverHandler getDriver(DeviceId devId) {
670 Driver driver = driverService.getDriver(devId);
671 DriverHandler handler = new DefaultDriverHandler(new DefaultDriverData(driver, devId));
672 return handler;
673 }
674
675 private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies, DriverHandler handler) {
alshabib64def642014-12-02 23:27:37 -0800676
alshabib54ce5892014-09-23 17:50:51 -0700677 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900678 NewAdaptiveFlowStatsCollector afsc = afsCollectors.get(dpid);
alshabib54ce5892014-09-23 17:50:51 -0700679
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900680 if (adaptiveFlowSampling && afsc != null) {
pier39c9f792019-12-19 16:04:23 +0100681 Set<FlowEntry> flowEntries = replies.getEntries().stream()
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300682 .map(entry -> new FlowEntryBuilder(did, entry, handler).withSetAfsc(afsc).build())
pier39c9f792019-12-19 16:04:23 +0100683 .collect(Collectors.toSet());
alshabib54ce5892014-09-23 17:50:51 -0700684
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900685 // 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);
ssyoon9030fbcd92015-08-17 10:42:07 +0900694 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900695 // 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);
ssyoon9030fbcd92015-08-17 10:42:07 +0900700 }
701 } else {
pier39c9f792019-12-19 16:04:23 +0100702 Set<FlowEntry> flowEntries = replies.getEntries().stream()
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300703 .map(entry -> new FlowEntryBuilder(did, entry, handler).build())
pier39c9f792019-12-19 16:04:23 +0100704 .collect(Collectors.toSet());
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900705
ssyoon9030fbcd92015-08-17 10:42:07 +0900706 // call existing entire flow stats update with flowMissing synchronization
707 providerService.pushFlowMetrics(did, flowEntries);
708 }
alshabib5c370ff2014-09-18 10:12:14 -0700709 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700710
711 private void pushTableStatistics(Dpid dpid, OFTableStatsReply replies) {
712
713 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
714 List<TableStatisticsEntry> tableStatsEntries = replies.getEntries().stream()
715 .map(entry -> buildTableStatistics(did, entry))
716 .filter(Objects::nonNull)
pier39c9f792019-12-19 16:04:23 +0100717 .distinct()
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700718 .collect(Collectors.toList());
719 providerService.pushTableStatistics(did, tableStatsEntries);
720 }
721
Cem Türker3baff672017-10-12 15:09:01 +0300722 private void pushFlowLightWeightMetrics(Dpid dpid, OFFlowLightweightStatsReply replies) {
723
724 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
725 NewAdaptiveFlowStatsCollector afsc = afsCollectors.get(dpid);
726 if (adaptiveFlowSampling && afsc != null) {
pier39c9f792019-12-19 16:04:23 +0100727 Set<FlowEntry> flowEntries = replies.getEntries().stream()
Cem Türker3baff672017-10-12 15:09:01 +0300728 .map(entry -> new FlowEntryBuilder(did, entry, driverService).withSetAfsc(afsc).build())
pier39c9f792019-12-19 16:04:23 +0100729 .collect(Collectors.toSet());
Cem Türker3baff672017-10-12 15:09:01 +0300730
731 // Check that OFFlowStatsReply Xid is same with the one of OFFlowStatsRequest?
732 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
733 log.debug("OpenFlowRuleProvider:pushFlowMetrics, flowMissingXid={}, "
734 + "OFFlowStatsReply Xid={}, for {}",
735 afsc.getFlowMissingXid(), replies.getXid(), dpid);
736 if (afsc.getFlowMissingXid() == replies.getXid()) {
737 // call entire flow stats update with flowMissing synchronization.
738 // used existing pushFlowMetrics
739 providerService.pushFlowMetrics(did, flowEntries);
740 }
741 // reset flowMissingXid to NO_FLOW_MISSING_XID
742 afsc.setFlowMissingXid(NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID);
743 } else {
744 // call individual flow stats update
745 providerService.pushFlowMetricsWithoutFlowMissing(did, flowEntries);
746 }
747 } else {
pier39c9f792019-12-19 16:04:23 +0100748 Set<FlowEntry> flowEntries = replies.getEntries().stream()
Cem Türker3baff672017-10-12 15:09:01 +0300749 .map(entry -> new FlowEntryBuilder(did, entry, driverService).build())
pier39c9f792019-12-19 16:04:23 +0100750 .collect(Collectors.toSet());
Cem Türker3baff672017-10-12 15:09:01 +0300751 // call existing entire flow stats update with flowMissing synchronization
752 providerService.pushFlowMetrics(did, flowEntries);
753 }
754 }
755
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700756 private TableStatisticsEntry buildTableStatistics(DeviceId deviceId,
757 OFTableStatsEntry ofEntry) {
758 TableStatisticsEntry entry = null;
759 if (ofEntry != null) {
760 entry = new DefaultTableStatisticsEntry(deviceId,
761 ofEntry.getTableId().getValue(),
762 ofEntry.getActiveCount(),
763 ofEntry.getLookupCount().getValue(),
764 ofEntry.getMatchedCount().getValue());
765 }
766
767 return entry;
768
769 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700770 }
alshabib1cc04f72014-09-16 16:09:58 -0700771
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800772 /**
jcc3d4e14a2015-04-21 11:32:05 +0800773 * The internal cache entry holding the original request as well as
774 * accumulating the any failures along the way.
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700775 * <p/>
jcc3d4e14a2015-04-21 11:32:05 +0800776 * If this entry is evicted from the cache then the entire operation is
777 * considered failed. Otherwise, only the failures reported by the device
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800778 * will be propagated up.
779 */
780 private class InternalCacheEntry {
alshabib902d41b2014-10-07 16:52:05 -0700781
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800782 private final FlowRuleBatchOperation operation;
783 private final Set<FlowRule> failures = Sets.newConcurrentHashSet();
alshabib193525b2014-10-08 18:58:03 -0700784
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800785 public InternalCacheEntry(FlowRuleBatchOperation operation) {
786 this.operation = operation;
alshabib902d41b2014-10-07 16:52:05 -0700787 }
788
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800789 /**
790 * Appends a failed rule to the set of failed items.
jcc3d4e14a2015-04-21 11:32:05 +0800791 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800792 * @param rule the failed rule
793 */
794 public void appendFailure(FlowRule rule) {
795 failures.add(rule);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800796 }
797
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800798 /**
799 * Fails the entire batch and returns the failed operation.
jcc3d4e14a2015-04-21 11:32:05 +0800800 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800801 * @return the failed operation
802 */
803 public CompletedBatchOperation failedCompletion() {
804 Set<FlowRule> fails = operation.getOperations().stream()
805 .map(op -> op.target()).collect(Collectors.toSet());
jcc3d4e14a2015-04-21 11:32:05 +0800806 return new CompletedBatchOperation(false,
807 Collections
808 .unmodifiableSet(fails),
809 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700810 }
811
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800812 /**
813 * Returns the completed operation and whether the batch suceeded.
jcc3d4e14a2015-04-21 11:32:05 +0800814 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800815 * @return the completed operation
816 */
817 public CompletedBatchOperation completed() {
jcc3d4e14a2015-04-21 11:32:05 +0800818 return new CompletedBatchOperation(
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700819 failures.isEmpty(),
820 Collections
821 .unmodifiableSet(failures),
822 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700823 }
alshabib902d41b2014-10-07 16:52:05 -0700824 }
alshabiba68eb962014-09-24 20:34:13 -0700825
alshabib1cc04f72014-09-16 16:09:58 -0700826}