blob: caeacd72ac3a255f364989b96b0700492547f95a [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;
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;
pier809fd4d2020-01-09 13:10:04 +010099import java.util.concurrent.ScheduledExecutorService;
100import java.util.concurrent.ScheduledThreadPoolExecutor;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700101import java.util.concurrent.TimeUnit;
102import java.util.stream.Collectors;
103
ssyoon9030fbcd92015-08-17 10:42:07 +0900104import static com.google.common.base.Preconditions.checkNotNull;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700105import static com.google.common.base.Strings.isNullOrEmpty;
pier809fd4d2020-01-09 13:10:04 +0100106import static java.util.concurrent.Executors.newScheduledThreadPool;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700107import static org.onlab.util.Tools.get;
pier809fd4d2020-01-09 13:10:04 +0100108import static org.onlab.util.Tools.groupedThreads;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700109import static org.slf4j.LoggerFactory.getLogger;
alshabibeec3a062014-09-17 18:01:26 -0700110
alshabib1cc04f72014-09-16 16:09:58 -0700111/**
jcc3d4e14a2015-04-21 11:32:05 +0800112 * Provider which uses an OpenFlow controller to detect network end-station
113 * hosts.
alshabib1cc04f72014-09-16 16:09:58 -0700114 */
115@Component(immediate = true)
jcc3d4e14a2015-04-21 11:32:05 +0800116public class OpenFlowRuleProvider extends AbstractProvider
117 implements FlowRuleProvider {
alshabib1cc04f72014-09-16 16:09:58 -0700118
119 private final Logger log = getLogger(getClass());
120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
122 protected FlowRuleProviderRegistry providerRegistry;
123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected OpenFlowController controller;
126
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
128 protected ComponentConfigService cfgService;
129
Jonathan Hart3c259162015-10-21 21:31:19 -0700130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
131 protected DriverService driverService;
132
ssyoon9030fbcd92015-08-17 10:42:07 +0900133 private static final int DEFAULT_POLL_FREQUENCY = 5;
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;
136 private static final boolean DEFAULT_ADAPTIVE_FLOW_SAMPLING = false;
137
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700138 @Property(name = "flowPollFrequency", intValue = DEFAULT_POLL_FREQUENCY,
139 label = "Frequency (in seconds) for polling flow statistics")
140 private int flowPollFrequency = DEFAULT_POLL_FREQUENCY;
141
ssyoon9030fbcd92015-08-17 10:42:07 +0900142 @Property(name = "adaptiveFlowSampling", boolValue = DEFAULT_ADAPTIVE_FLOW_SAMPLING,
143 label = "Adaptive Flow Sampling is on or off")
144 private boolean adaptiveFlowSampling = DEFAULT_ADAPTIVE_FLOW_SAMPLING;
145
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
pier809fd4d2020-01-09 13:10:04 +0100152 private ScheduledExecutorService executorService = newScheduledThreadPool(1,
153 groupedThreads("onos/of", "collector-%d", log));
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);
pier809fd4d2020-01-09 13:10:04 +0100175 // Evicts the tasks if cancelled
176 ((ScheduledThreadPoolExecutor) executorService).setRemoveOnCancelPolicy(true);
alshabib3d643ec2014-10-22 18:33:00 -0700177
Antonio Marsico1c5ae1f2015-12-15 15:31:56 +0100178 modified(context);
179
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700180 pendingBatches = createBatchCache();
ssyoon9030fbcd92015-08-17 10:42:07 +0900181
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700182 createCollectors();
alshabib3d643ec2014-10-22 18:33:00 -0700183
ssyoon9030fbcd92015-08-17 10:42:07 +0900184 log.info("Started with flowPollFrequency = {}, adaptiveFlowSampling = {}",
185 flowPollFrequency, adaptiveFlowSampling);
alshabib1cc04f72014-09-16 16:09:58 -0700186 }
187
188 @Deactivate
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700189 protected void deactivate(ComponentContext context) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700190 cfgService.unregisterProperties(getClass(), false);
191 stopCollectors();
alshabib1cc04f72014-09-16 16:09:58 -0700192 providerRegistry.unregister(this);
193 providerService = null;
pier809fd4d2020-01-09 13:10:04 +0100194 executorService.shutdown();
alshabib1cc04f72014-09-16 16:09:58 -0700195
196 log.info("Stopped");
197 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800198
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700199 @Modified
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700200 protected void modified(ComponentContext context) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700201 Dictionary<?, ?> properties = context.getProperties();
202 int newFlowPollFrequency;
203 try {
204 String s = get(properties, "flowPollFrequency");
205 newFlowPollFrequency = isNullOrEmpty(s) ? flowPollFrequency : Integer.parseInt(s.trim());
206
207 } catch (NumberFormatException | ClassCastException e) {
208 newFlowPollFrequency = flowPollFrequency;
209 }
210
211 if (newFlowPollFrequency != flowPollFrequency) {
212 flowPollFrequency = newFlowPollFrequency;
213 adjustRate();
214 }
215
216 log.info("Settings: flowPollFrequency={}", flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900217
218 boolean newAdaptiveFlowSampling;
219 String s = get(properties, "adaptiveFlowSampling");
220 newAdaptiveFlowSampling = isNullOrEmpty(s) ? adaptiveFlowSampling : Boolean.parseBoolean(s.trim());
221
222 if (newAdaptiveFlowSampling != adaptiveFlowSampling) {
223 // stop previous collector
224 stopCollectors();
225 adaptiveFlowSampling = newAdaptiveFlowSampling;
226 // create new collectors
227 createCollectors();
228 }
229
230 log.info("Settings: adaptiveFlowSampling={}", adaptiveFlowSampling);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700231 }
232
233 private Cache<Long, InternalCacheEntry> createBatchCache() {
234 return CacheBuilder.newBuilder()
235 .expireAfterWrite(10, TimeUnit.SECONDS)
236 .removalListener((RemovalNotification<Long, InternalCacheEntry> notification) -> {
237 if (notification.getCause() == RemovalCause.EXPIRED) {
238 providerService.batchOperationCompleted(notification.getKey(),
239 notification.getValue().failedCompletion());
240 }
241 }).build();
242 }
243
244 private void createCollectors() {
245 controller.getSwitches().forEach(this::createCollector);
246 }
247
248 private void createCollector(OpenFlowSwitch sw) {
Kavitha Alagesan6704df32016-08-18 15:15:31 +0530249 if (sw == null) {
250 return;
251 }
Laszlo Papp58174812018-01-16 13:29:47 +0000252 if (sw.features().getCapabilities().contains(OFCapabilities.FLOW_STATS)) {
253 if (adaptiveFlowSampling) {
254 // NewAdaptiveFlowStatsCollector Constructor
255 NewAdaptiveFlowStatsCollector fsc =
256 new NewAdaptiveFlowStatsCollector(driverService, sw, flowPollFrequency);
257 stopCollectorIfNeeded(afsCollectors.put(new Dpid(sw.getId()), fsc));
258 fsc.start();
259 } else {
pier809fd4d2020-01-09 13:10:04 +0100260 FlowStatsCollector fsc = new FlowStatsCollector(executorService, sw, flowPollFrequency);
Laszlo Papp58174812018-01-16 13:29:47 +0000261 stopCollectorIfNeeded(simpleCollectors.put(new Dpid(sw.getId()), fsc));
262 fsc.start();
263 }
ssyoon9030fbcd92015-08-17 10:42:07 +0900264 }
Laszlo Pappedadbe22017-12-14 20:05:49 +0000265 if (sw.features().getCapabilities().contains(OFCapabilities.TABLE_STATS)) {
pier809fd4d2020-01-09 13:10:04 +0100266 TableStatisticsCollector tsc = new TableStatisticsCollector(executorService, sw, flowPollFrequency);
Laszlo Pappedadbe22017-12-14 20:05:49 +0000267 stopCollectorIfNeeded(tableStatsCollectors.put(new Dpid(sw.getId()), tsc));
268 tsc.start();
269 }
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700270 }
271
272 private void stopCollectorIfNeeded(SwitchDataCollector collector) {
273 if (collector != null) {
274 collector.stop();
275 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700276 }
277
278 private void stopCollectors() {
ssyoon9030fbcd92015-08-17 10:42:07 +0900279 if (adaptiveFlowSampling) {
280 // NewAdaptiveFlowStatsCollector Destructor
281 afsCollectors.values().forEach(NewAdaptiveFlowStatsCollector::stop);
282 afsCollectors.clear();
283 } else {
284 simpleCollectors.values().forEach(FlowStatsCollector::stop);
285 simpleCollectors.clear();
286 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700287 tableStatsCollectors.values().forEach(TableStatisticsCollector::stop);
288 tableStatsCollectors.clear();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700289 }
290
291 private void adjustRate() {
292 DefaultLoad.setPollInterval(flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900293 if (adaptiveFlowSampling) {
294 // NewAdaptiveFlowStatsCollector calAndPollInterval
295 afsCollectors.values().forEach(fsc -> fsc.adjustCalAndPollInterval(flowPollFrequency));
296 } else {
297 simpleCollectors.values().forEach(fsc -> fsc.adjustPollInterval(flowPollFrequency));
298 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700299 tableStatsCollectors.values().forEach(tsc -> tsc.adjustPollInterval(flowPollFrequency));
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700300 }
301
Jordan Halterman6de47ff2019-03-05 18:44:03 -0800302 private void resetEvents(Dpid dpid) {
303 SwitchDataCollector collector;
304 if (adaptiveFlowSampling) {
305 collector = afsCollectors.get(dpid);
306 } else {
307 collector = simpleCollectors.get(dpid);
308 }
309 if (collector != null) {
310 collector.resetEvents();
311 }
312 }
313
314 private void recordEvent(Dpid dpid) {
315 recordEvents(dpid, 1);
316 }
317
318 private void recordEvents(Dpid dpid, int events) {
319 SwitchDataCollector collector;
320 if (adaptiveFlowSampling) {
321 collector = afsCollectors.get(dpid);
322 } else {
323 collector = simpleCollectors.get(dpid);
324 }
325 if (collector != null) {
326 collector.recordEvents(events);
327 }
328 }
329
alshabib1cc04f72014-09-16 16:09:58 -0700330 @Override
331 public void applyFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800332 for (FlowRule flowRule : flowRules) {
333 applyRule(flowRule);
alshabib35edb1a2014-09-16 17:44:44 -0700334 }
alshabib1cc04f72014-09-16 16:09:58 -0700335 }
336
alshabib35edb1a2014-09-16 17:44:44 -0700337 private void applyRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900338 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
339 OpenFlowSwitch sw = controller.getSwitch(dpid);
340
Ray Milkey0ae473d2016-04-04 10:56:47 -0700341 if (sw == null) {
342 return;
343 }
344
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700345 FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
346 if (hasPayload(flowRuleExtPayLoad)) {
347 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800348 sw.sendMsg(msg);
349 return;
350 }
alshabibbdcbb102015-04-22 14:16:38 -0700351 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Jonathan Hart3c259162015-10-21 21:31:19 -0700352 Optional.empty(), Optional.of(driverService)).buildFlowAdd());
Jordan Halterman6de47ff2019-03-05 18:44:03 -0800353
354 recordEvent(dpid);
alshabib35edb1a2014-09-16 17:44:44 -0700355 }
356
alshabib1cc04f72014-09-16 16:09:58 -0700357 @Override
358 public void removeFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800359 for (FlowRule flowRule : flowRules) {
360 removeRule(flowRule);
alshabib219ebaa2014-09-22 15:41:24 -0700361 }
alshabib1cc04f72014-09-16 16:09:58 -0700362 }
363
alshabib219ebaa2014-09-22 15:41:24 -0700364 private void removeRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900365 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
366 OpenFlowSwitch sw = controller.getSwitch(dpid);
367
Ray Milkey0ae473d2016-04-04 10:56:47 -0700368 if (sw == null) {
369 return;
370 }
371
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700372 FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
373 if (hasPayload(flowRuleExtPayLoad)) {
374 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800375 sw.sendMsg(msg);
376 return;
377 }
alshabibbdcbb102015-04-22 14:16:38 -0700378 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Jonathan Hart3c259162015-10-21 21:31:19 -0700379 Optional.empty(), Optional.of(driverService)).buildFlowDel());
Jordan Halterman6de47ff2019-03-05 18:44:03 -0800380
381 recordEvent(dpid);
alshabib219ebaa2014-09-22 15:41:24 -0700382 }
383
alshabiba68eb962014-09-24 20:34:13 -0700384 @Override
385 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
386 // TODO: optimize using the ApplicationId
387 removeFlowRule(flowRules);
388 }
389
alshabib193525b2014-10-08 18:58:03 -0700390 @Override
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800391 public void executeBatch(FlowRuleBatchOperation batch) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900392 checkNotNull(batch);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800393
ssyoon9030fbcd92015-08-17 10:42:07 +0900394 Dpid dpid = Dpid.dpid(batch.deviceId().uri());
395 OpenFlowSwitch sw = controller.getSwitch(dpid);
Madan Jampani84382b92016-06-22 08:26:49 -0700396
397 // If switch no longer exists, simply return.
398 if (sw == null) {
399 Set<FlowRule> failures = ImmutableSet.copyOf(Lists.transform(batch.getOperations(), e -> e.target()));
400 providerService.batchOperationCompleted(batch.id(),
401 new CompletedBatchOperation(false, failures, batch.deviceId()));
402 return;
403 }
404 pendingBatches.put(batch.id(), new InternalCacheEntry(batch));
pierb673adc2019-10-24 13:56:58 +0200405 // Build a batch of flow mods - to reduce the number i/o asked to the SO
406 Set<OFFlowMod> mods = Sets.newHashSet();
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800407 OFFlowMod mod;
alshabib193525b2014-10-08 18:58:03 -0700408 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
jcc3d4e14a2015-04-21 11:32:05 +0800409 // flow is the third party privacy flow
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700410 FlowRuleExtPayLoad flowRuleExtPayLoad = fbe.target().payLoad();
411 if (hasPayload(flowRuleExtPayLoad)) {
412 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800413 sw.sendMsg(msg);
414 continue;
415 }
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700416 FlowModBuilder builder =
Jonathan Hart3c259162015-10-21 21:31:19 -0700417 FlowModBuilder.builder(fbe.target(), sw.factory(),
418 Optional.of(batch.id()), Optional.of(driverService));
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800419 switch (fbe.operator()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700420 case ADD:
421 mod = builder.buildFlowAdd();
422 break;
423 case REMOVE:
424 mod = builder.buildFlowDel();
425 break;
426 case MODIFY:
427 mod = builder.buildFlowMod();
428 break;
429 default:
430 log.error("Unsupported batch operation {}; skipping flowmod {}",
ssyoon9030fbcd92015-08-17 10:42:07 +0900431 fbe.operator(), fbe);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700432 continue;
jcc3d4e14a2015-04-21 11:32:05 +0800433 }
pierb673adc2019-10-24 13:56:58 +0200434 mods.add(mod);
alshabib193525b2014-10-08 18:58:03 -0700435 }
pierb673adc2019-10-24 13:56:58 +0200436 // Build a list to mantain the order
437 List<OFMessage> modsTosend = Lists.newArrayList(mods);
jcc3d4e14a2015-04-21 11:32:05 +0800438 OFBarrierRequest.Builder builder = sw.factory().buildBarrierRequest()
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800439 .setXid(batch.id());
pierb673adc2019-10-24 13:56:58 +0200440 // Adds finally the barrier request
441 modsTosend.add(builder.build());
442 sw.sendMsg(modsTosend);
443 // Take into account also the barrier request
444 recordEvents(dpid, (batch.getOperations().size() + 1));
alshabib193525b2014-10-08 18:58:03 -0700445 }
446
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700447 private boolean hasPayload(FlowRuleExtPayLoad flowRuleExtPayLoad) {
448 return flowRuleExtPayLoad != null &&
449 flowRuleExtPayLoad.payLoad() != null &&
450 flowRuleExtPayLoad.payLoad().length > 0;
451 }
452
alshabib8f1cf4a2014-09-17 14:44:48 -0700453 private class InternalFlowProvider
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800454 implements OpenFlowSwitchListener, OpenFlowEventListener {
alshabib8f1cf4a2014-09-17 14:44:48 -0700455
alshabib8f1cf4a2014-09-17 14:44:48 -0700456 @Override
457 public void switchAdded(Dpid dpid) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700458 createCollector(controller.getSwitch(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700459 }
460
461 @Override
462 public void switchRemoved(Dpid dpid) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900463 if (adaptiveFlowSampling) {
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700464 stopCollectorIfNeeded(afsCollectors.remove(dpid));
ssyoon9030fbcd92015-08-17 10:42:07 +0900465 } else {
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700466 stopCollectorIfNeeded(simpleCollectors.remove(dpid));
alshabibdfc7afb2014-10-21 20:13:27 -0700467 }
Thomas Vachuskaa394b952016-06-14 15:02:09 -0700468 stopCollectorIfNeeded(tableStatsCollectors.remove(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700469 }
470
471 @Override
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700472 public void switchChanged(Dpid dpid) {
473 }
474
475 @Override
alshabib8f1cf4a2014-09-17 14:44:48 -0700476 public void portChanged(Dpid dpid, OFPortStatus status) {
jcc3d4e14a2015-04-21 11:32:05 +0800477 // TODO: Decide whether to evict flows internal store.
alshabib8f1cf4a2014-09-17 14:44:48 -0700478 }
479
480 @Override
481 public void handleMessage(Dpid dpid, OFMessage msg) {
Ray Milkeyada9e2d2016-04-05 16:42:35 -0700482 if (providerService == null) {
483 // We are shutting down, nothing to be done
484 return;
485 }
Jonathan Harte4e74f02016-03-03 12:57:40 -0800486 DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700487 switch (msg.getType()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700488 case FLOW_REMOVED:
489 OFFlowRemoved removed = (OFFlowRemoved) msg;
alshabib6b5cfec2014-09-18 17:42:18 -0700490
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300491 FlowEntry fr = new FlowEntryBuilder(deviceId, removed, getDriver(deviceId)).build();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700492 providerService.flowRemoved(fr);
493 break;
494 case STATS_REPLY:
495 if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW) {
Jordan Halterman6de47ff2019-03-05 18:44:03 -0800496 // Let's unblock first the collector
497 SwitchDataCollector collector;
498 if (adaptiveFlowSampling) {
499 collector = afsCollectors.get(dpid);
500 } else {
501 collector = simpleCollectors.get(dpid);
502 }
503 if (collector != null) {
504 collector.received();
505 }
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300506 pushFlowMetrics(dpid, (OFFlowStatsReply) msg, getDriver(deviceId));
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700507 } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.TABLE) {
508 pushTableStatistics(dpid, (OFTableStatsReply) msg);
Cem Türker3baff672017-10-12 15:09:01 +0300509 } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW_LIGHTWEIGHT) {
510 pushFlowLightWeightMetrics(dpid, (OFFlowLightweightStatsReply) msg);
sangho89bf6fb2015-02-09 09:33:13 -0800511 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700512 break;
513 case BARRIER_REPLY:
514 try {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700515 InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800516 if (entry != null) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700517 providerService
518 .batchOperationCompleted(msg.getXid(),
519 entry.completed());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800520 } else {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700521 log.warn("Received unknown Barrier Reply: {}",
522 msg.getXid());
523 }
524 } finally {
525 pendingBatches.invalidate(msg.getXid());
526 }
527 break;
528 case ERROR:
Thomas Vachuska3358af22015-05-19 18:40:34 -0700529 // TODO: This needs to get suppressed in a better way.
530 if (msg instanceof OFBadRequestErrorMsg &&
531 ((OFBadRequestErrorMsg) msg).getCode() == OFBadRequestCode.BAD_TYPE) {
532 log.debug("Received error message {} from {}", msg, dpid);
533 } else {
534 log.warn("Received error message {} from {}", msg, dpid);
535 }
Prince Pereira788797e2016-08-10 11:24:14 +0530536 handleErrorMsg(deviceId, msg);
Ray Milkey4fd3ceb2015-12-10 14:43:08 -0800537 break;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700538 default:
539 log.debug("Unhandled message type: {}", msg.getType());
alshabib8f1cf4a2014-09-17 14:44:48 -0700540 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700541 }
542
Prince Pereira788797e2016-08-10 11:24:14 +0530543 private void handleErrorMsg(DeviceId deviceId, OFMessage msg) {
Prince Pereira141ed812016-09-02 19:03:18 +0530544 InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
Prince Pereira788797e2016-08-10 11:24:14 +0530545 OFErrorMsg error = (OFErrorMsg) msg;
546 OFMessage ofMessage = null;
547 switch (error.getErrType()) {
548 case BAD_ACTION:
549 OFBadActionErrorMsg baErrorMsg = (OFBadActionErrorMsg) error;
550 if (baErrorMsg.getData().getParsedMessage().isPresent()) {
551 ofMessage = baErrorMsg.getData().getParsedMessage().get();
552 }
553 break;
554 case BAD_INSTRUCTION:
555 OFBadInstructionErrorMsg biErrorMsg = (OFBadInstructionErrorMsg) error;
556 if (biErrorMsg.getData().getParsedMessage().isPresent()) {
557 ofMessage = biErrorMsg.getData().getParsedMessage().get();
558 }
559 break;
560 case BAD_MATCH:
561 OFBadMatchErrorMsg bmErrorMsg = (OFBadMatchErrorMsg) error;
562 if (bmErrorMsg.getData().getParsedMessage().isPresent()) {
563 ofMessage = bmErrorMsg.getData().getParsedMessage().get();
564 }
565 break;
566 case FLOW_MOD_FAILED:
567 OFFlowModFailedErrorMsg fmFailed = (OFFlowModFailedErrorMsg) error;
568 if (fmFailed.getData().getParsedMessage().isPresent()) {
569 ofMessage = fmFailed.getData().getParsedMessage().get();
570 }
571 break;
572 default:
573 // Do nothing.
574 return;
575 }
Prince Pereira141ed812016-09-02 19:03:18 +0530576
Prince Pereira788797e2016-08-10 11:24:14 +0530577 if (ofMessage != null) {
Prince Pereira141ed812016-09-02 19:03:18 +0530578
Prince Pereira788797e2016-08-10 11:24:14 +0530579 if (entry != null) {
580 OFFlowMod ofFlowMod = (OFFlowMod) ofMessage;
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300581 entry.appendFailure(new FlowEntryBuilder(deviceId, ofFlowMod, getDriver(deviceId)).build());
Prince Pereira788797e2016-08-10 11:24:14 +0530582 } else {
583 log.error("No matching batch for this error: {}", error);
584 }
Prince Pereira141ed812016-09-02 19:03:18 +0530585
Prince Pereira788797e2016-08-10 11:24:14 +0530586 } else {
Prince Pereira141ed812016-09-02 19:03:18 +0530587
588 U64 cookieId = readCookieIdFromOFErrorMsg(error, msg.getVersion());
589
590 if (cookieId != null) {
591 long flowId = cookieId.getValue();
592
593 if (entry != null) {
594 for (FlowRuleBatchEntry fbEntry : entry.operation.getOperations()) {
595 if (fbEntry.target().id().value() == flowId) {
596 entry.appendFailure(fbEntry.target());
597 break;
598 }
599 }
600 } else {
601 log.error("No matching batch for this error: {}", error);
602 }
603
604 } else {
605 log.error("Flow installation failed but switch " +
606 "didn't tell us which one.");
607 }
Prince Pereira788797e2016-08-10 11:24:14 +0530608 }
609 }
610
Prince Pereira141ed812016-09-02 19:03:18 +0530611 /**
612 * Reading cookieId from OFErrorMsg.
613 *
614 * Loxigen OpenFlow API failed in parsing error messages because of
615 * 64 byte data truncation based on OpenFlow specs. The method written
616 * is a workaround to extract the cookieId from the packet till the
617 * issue is resolved in Loxigen OpenFlow code.
618 * Ref: https://groups.google.com/a/onosproject.org/forum/#!topic
619 * /onos-dev/_KwlHZDllLE
620 *
621 * @param msg OF error message
622 * @param ofVersion Openflow version
623 * @return cookieId
624 */
625 private U64 readCookieIdFromOFErrorMsg(OFErrorMsg msg,
626 OFVersion ofVersion) {
627
628 if (ofVersion.wireVersion < OFVersion.OF_13.wireVersion) {
629 log.debug("Unhandled error msg with OF version {} " +
630 "which is less than {}",
631 ofVersion, OFVersion.OF_13);
632 return null;
633 }
634
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700635 ByteBuf bb = Unpooled.wrappedBuffer(msg.getData().getData());
Prince Pereira141ed812016-09-02 19:03:18 +0530636
637 if (bb.readableBytes() < MIN_EXPECTED_BYTE_LEN) {
638 log.debug("Wrong length: Expected to be >= {}, was: {}",
639 MIN_EXPECTED_BYTE_LEN, bb.readableBytes());
640 return null;
641 }
642
643 byte ofVer = bb.readByte();
644
645 if (ofVer != ofVersion.wireVersion) {
646 log.debug("Wrong version: Expected={}, got={}",
647 ofVersion.wireVersion, ofVer);
648 return null;
649 }
650
651 byte type = bb.readByte();
652
653 if (type != OFType.FLOW_MOD.ordinal()) {
654 log.debug("Wrong type: Expected={}, got={}",
655 OFType.FLOW_MOD.ordinal(), type);
656 return null;
657 }
658
659 int length = U16.f(bb.readShort());
660
661 if (length < MIN_EXPECTED_BYTE_LEN) {
662 log.debug("Wrong length: Expected to be >= {}, was: {}",
663 MIN_EXPECTED_BYTE_LEN, length);
664 return null;
665 }
666
667 bb.skipBytes(SKIP_BYTES);
668 return U64.ofRaw(bb.readLong());
669 }
670
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700671 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700672 public void receivedRoleReply(Dpid dpid, RoleState requested,
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800673 RoleState response) {
Jordan Halterman6de47ff2019-03-05 18:44:03 -0800674 if (response == RoleState.MASTER) {
675 resetEvents(dpid);
676 }
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700677 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700678
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300679 private DriverHandler getDriver(DeviceId devId) {
680 Driver driver = driverService.getDriver(devId);
681 DriverHandler handler = new DefaultDriverHandler(new DefaultDriverData(driver, devId));
682 return handler;
683 }
684
685 private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies, DriverHandler handler) {
alshabib64def642014-12-02 23:27:37 -0800686
alshabib54ce5892014-09-23 17:50:51 -0700687 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900688 NewAdaptiveFlowStatsCollector afsc = afsCollectors.get(dpid);
alshabib54ce5892014-09-23 17:50:51 -0700689
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900690 if (adaptiveFlowSampling && afsc != null) {
pier7aceddf2019-12-19 16:04:23 +0100691 Set<FlowEntry> flowEntries = replies.getEntries().stream()
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300692 .map(entry -> new FlowEntryBuilder(did, entry, handler).withSetAfsc(afsc).build())
pier7aceddf2019-12-19 16:04:23 +0100693 .collect(Collectors.toSet());
alshabib54ce5892014-09-23 17:50:51 -0700694
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900695 // Check that OFFlowStatsReply Xid is same with the one of OFFlowStatsRequest?
696 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
697 log.debug("OpenFlowRuleProvider:pushFlowMetrics, flowMissingXid={}, "
698 + "OFFlowStatsReply Xid={}, for {}",
699 afsc.getFlowMissingXid(), replies.getXid(), dpid);
700 if (afsc.getFlowMissingXid() == replies.getXid()) {
701 // call entire flow stats update with flowMissing synchronization.
702 // used existing pushFlowMetrics
703 providerService.pushFlowMetrics(did, flowEntries);
ssyoon9030fbcd92015-08-17 10:42:07 +0900704 }
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900705 // reset flowMissingXid to NO_FLOW_MISSING_XID
706 afsc.setFlowMissingXid(NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID);
707 } else {
708 // call individual flow stats update
709 providerService.pushFlowMetricsWithoutFlowMissing(did, flowEntries);
ssyoon9030fbcd92015-08-17 10:42:07 +0900710 }
711 } else {
pier7aceddf2019-12-19 16:04:23 +0100712 Set<FlowEntry> flowEntries = replies.getEntries().stream()
Rodrigo Duarte Sousae37d1292017-08-29 17:01:24 -0300713 .map(entry -> new FlowEntryBuilder(did, entry, handler).build())
pier7aceddf2019-12-19 16:04:23 +0100714 .collect(Collectors.toSet());
Sangsik Yoonb1b823f2016-05-16 18:55:39 +0900715
ssyoon9030fbcd92015-08-17 10:42:07 +0900716 // call existing entire flow stats update with flowMissing synchronization
717 providerService.pushFlowMetrics(did, flowEntries);
718 }
alshabib5c370ff2014-09-18 10:12:14 -0700719 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700720
721 private void pushTableStatistics(Dpid dpid, OFTableStatsReply replies) {
722
723 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
724 List<TableStatisticsEntry> tableStatsEntries = replies.getEntries().stream()
725 .map(entry -> buildTableStatistics(did, entry))
726 .filter(Objects::nonNull)
pier7aceddf2019-12-19 16:04:23 +0100727 .distinct()
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700728 .collect(Collectors.toList());
729 providerService.pushTableStatistics(did, tableStatsEntries);
730 }
731
Cem Türker3baff672017-10-12 15:09:01 +0300732 private void pushFlowLightWeightMetrics(Dpid dpid, OFFlowLightweightStatsReply replies) {
733
734 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
735 NewAdaptiveFlowStatsCollector afsc = afsCollectors.get(dpid);
736 if (adaptiveFlowSampling && afsc != null) {
pier7aceddf2019-12-19 16:04:23 +0100737 Set<FlowEntry> flowEntries = replies.getEntries().stream()
Cem Türker3baff672017-10-12 15:09:01 +0300738 .map(entry -> new FlowEntryBuilder(did, entry, driverService).withSetAfsc(afsc).build())
pier7aceddf2019-12-19 16:04:23 +0100739 .collect(Collectors.toSet());
Cem Türker3baff672017-10-12 15:09:01 +0300740
741 // Check that OFFlowStatsReply Xid is same with the one of OFFlowStatsRequest?
742 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
743 log.debug("OpenFlowRuleProvider:pushFlowMetrics, flowMissingXid={}, "
744 + "OFFlowStatsReply Xid={}, for {}",
745 afsc.getFlowMissingXid(), replies.getXid(), dpid);
746 if (afsc.getFlowMissingXid() == replies.getXid()) {
747 // call entire flow stats update with flowMissing synchronization.
748 // used existing pushFlowMetrics
749 providerService.pushFlowMetrics(did, flowEntries);
750 }
751 // reset flowMissingXid to NO_FLOW_MISSING_XID
752 afsc.setFlowMissingXid(NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID);
753 } else {
754 // call individual flow stats update
755 providerService.pushFlowMetricsWithoutFlowMissing(did, flowEntries);
756 }
757 } else {
pier7aceddf2019-12-19 16:04:23 +0100758 Set<FlowEntry> flowEntries = replies.getEntries().stream()
Cem Türker3baff672017-10-12 15:09:01 +0300759 .map(entry -> new FlowEntryBuilder(did, entry, driverService).build())
pier7aceddf2019-12-19 16:04:23 +0100760 .collect(Collectors.toSet());
Cem Türker3baff672017-10-12 15:09:01 +0300761 // call existing entire flow stats update with flowMissing synchronization
762 providerService.pushFlowMetrics(did, flowEntries);
763 }
764 }
765
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700766 private TableStatisticsEntry buildTableStatistics(DeviceId deviceId,
767 OFTableStatsEntry ofEntry) {
768 TableStatisticsEntry entry = null;
769 if (ofEntry != null) {
770 entry = new DefaultTableStatisticsEntry(deviceId,
771 ofEntry.getTableId().getValue(),
772 ofEntry.getActiveCount(),
773 ofEntry.getLookupCount().getValue(),
774 ofEntry.getMatchedCount().getValue());
775 }
776
777 return entry;
778
779 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700780 }
alshabib1cc04f72014-09-16 16:09:58 -0700781
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800782 /**
jcc3d4e14a2015-04-21 11:32:05 +0800783 * The internal cache entry holding the original request as well as
784 * accumulating the any failures along the way.
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700785 * <p/>
jcc3d4e14a2015-04-21 11:32:05 +0800786 * If this entry is evicted from the cache then the entire operation is
787 * considered failed. Otherwise, only the failures reported by the device
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800788 * will be propagated up.
789 */
790 private class InternalCacheEntry {
alshabib902d41b2014-10-07 16:52:05 -0700791
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800792 private final FlowRuleBatchOperation operation;
793 private final Set<FlowRule> failures = Sets.newConcurrentHashSet();
alshabib193525b2014-10-08 18:58:03 -0700794
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800795 public InternalCacheEntry(FlowRuleBatchOperation operation) {
796 this.operation = operation;
alshabib902d41b2014-10-07 16:52:05 -0700797 }
798
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800799 /**
800 * Appends a failed rule to the set of failed items.
jcc3d4e14a2015-04-21 11:32:05 +0800801 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800802 * @param rule the failed rule
803 */
804 public void appendFailure(FlowRule rule) {
805 failures.add(rule);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800806 }
807
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800808 /**
809 * Fails the entire batch and returns the failed operation.
jcc3d4e14a2015-04-21 11:32:05 +0800810 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800811 * @return the failed operation
812 */
813 public CompletedBatchOperation failedCompletion() {
814 Set<FlowRule> fails = operation.getOperations().stream()
815 .map(op -> op.target()).collect(Collectors.toSet());
jcc3d4e14a2015-04-21 11:32:05 +0800816 return new CompletedBatchOperation(false,
817 Collections
818 .unmodifiableSet(fails),
819 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700820 }
821
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800822 /**
823 * Returns the completed operation and whether the batch suceeded.
jcc3d4e14a2015-04-21 11:32:05 +0800824 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800825 * @return the completed operation
826 */
827 public CompletedBatchOperation completed() {
jcc3d4e14a2015-04-21 11:32:05 +0800828 return new CompletedBatchOperation(
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700829 failures.isEmpty(),
830 Collections
831 .unmodifiableSet(failures),
832 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700833 }
alshabib902d41b2014-10-07 16:52:05 -0700834 }
alshabiba68eb962014-09-24 20:34:13 -0700835
alshabib1cc04f72014-09-16 16:09:58 -0700836}