blob: 7bf5878ce90da7b47132c59406c53060ede57290 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
ssyoon9030fbcd92015-08-17 10:42:07 +09002 * Copyright 2015 Open Networking Laboratory
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;
22import com.google.common.collect.Maps;
23import com.google.common.collect.Sets;
alshabib1cc04f72014-09-16 16:09:58 -070024import org.apache.felix.scr.annotations.Activate;
25import org.apache.felix.scr.annotations.Component;
26import org.apache.felix.scr.annotations.Deactivate;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070027import org.apache.felix.scr.annotations.Modified;
28import org.apache.felix.scr.annotations.Property;
alshabib1cc04f72014-09-16 16:09:58 -070029import org.apache.felix.scr.annotations.Reference;
30import org.apache.felix.scr.annotations.ReferenceCardinality;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070031import org.onosproject.cfg.ComponentConfigService;
Brian O'Connorabafb502014-12-02 22:26:20 -080032import org.onosproject.core.ApplicationId;
33import org.onosproject.net.DeviceId;
Jonathan Hart3c259162015-10-21 21:31:19 -070034import org.onosproject.net.driver.DriverService;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.net.flow.CompletedBatchOperation;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070036import org.onosproject.net.flow.DefaultTableStatisticsEntry;
Brian O'Connorabafb502014-12-02 22:26:20 -080037import org.onosproject.net.flow.FlowEntry;
38import org.onosproject.net.flow.FlowRule;
39import org.onosproject.net.flow.FlowRuleBatchEntry;
Brian O'Connor72cb19a2015-01-16 16:14:41 -080040import org.onosproject.net.flow.FlowRuleBatchOperation;
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -070041import org.onosproject.net.flow.FlowRuleExtPayLoad;
Brian O'Connorabafb502014-12-02 22:26:20 -080042import org.onosproject.net.flow.FlowRuleProvider;
43import org.onosproject.net.flow.FlowRuleProviderRegistry;
44import org.onosproject.net.flow.FlowRuleProviderService;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070045import org.onosproject.net.flow.TableStatisticsEntry;
Brian O'Connorabafb502014-12-02 22:26:20 -080046import org.onosproject.net.provider.AbstractProvider;
47import org.onosproject.net.provider.ProviderId;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070048import org.onosproject.net.statistic.DefaultLoad;
Brian O'Connorabafb502014-12-02 22:26:20 -080049import org.onosproject.openflow.controller.Dpid;
50import org.onosproject.openflow.controller.OpenFlowController;
51import org.onosproject.openflow.controller.OpenFlowEventListener;
52import org.onosproject.openflow.controller.OpenFlowSwitch;
53import org.onosproject.openflow.controller.OpenFlowSwitchListener;
54import org.onosproject.openflow.controller.RoleState;
jcc3d4e14a2015-04-21 11:32:05 +080055import org.onosproject.openflow.controller.ThirdPartyMessage;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070056import org.osgi.service.component.ComponentContext;
Thomas Vachuska3358af22015-05-19 18:40:34 -070057import org.projectfloodlight.openflow.protocol.OFBadRequestCode;
alshabib902d41b2014-10-07 16:52:05 -070058import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
59import org.projectfloodlight.openflow.protocol.OFErrorMsg;
Brian O'Connor72cb19a2015-01-16 16:14:41 -080060import org.projectfloodlight.openflow.protocol.OFErrorType;
alshabib193525b2014-10-08 18:58:03 -070061import org.projectfloodlight.openflow.protocol.OFFlowMod;
alshabib8f1cf4a2014-09-17 14:44:48 -070062import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
alshabib5c370ff2014-09-18 10:12:14 -070063import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
alshabib8f1cf4a2014-09-17 14:44:48 -070064import org.projectfloodlight.openflow.protocol.OFMessage;
65import org.projectfloodlight.openflow.protocol.OFPortStatus;
alshabib5c370ff2014-09-18 10:12:14 -070066import org.projectfloodlight.openflow.protocol.OFStatsReply;
sangho89bf6fb2015-02-09 09:33:13 -080067import org.projectfloodlight.openflow.protocol.OFStatsType;
Jonathan Hart3c259162015-10-21 21:31:19 -070068import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
69import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
Thomas Vachuska3358af22015-05-19 18:40:34 -070070import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
alshabib193525b2014-10-08 18:58:03 -070071import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
alshabib1cc04f72014-09-16 16:09:58 -070072import org.slf4j.Logger;
73
Thomas Vachuska75aaa672015-04-29 12:24:43 -070074import java.util.Collections;
75import java.util.Dictionary;
76import java.util.List;
77import java.util.Map;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070078import java.util.Objects;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070079import java.util.Optional;
80import java.util.Set;
81import java.util.Timer;
82import java.util.concurrent.TimeUnit;
83import java.util.stream.Collectors;
84
ssyoon9030fbcd92015-08-17 10:42:07 +090085import static com.google.common.base.Preconditions.checkNotNull;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070086import static com.google.common.base.Strings.isNullOrEmpty;
87import static org.onlab.util.Tools.get;
88import static org.slf4j.LoggerFactory.getLogger;
alshabibeec3a062014-09-17 18:01:26 -070089
alshabib1cc04f72014-09-16 16:09:58 -070090/**
jcc3d4e14a2015-04-21 11:32:05 +080091 * Provider which uses an OpenFlow controller to detect network end-station
92 * hosts.
alshabib1cc04f72014-09-16 16:09:58 -070093 */
94@Component(immediate = true)
jcc3d4e14a2015-04-21 11:32:05 +080095public class OpenFlowRuleProvider extends AbstractProvider
96 implements FlowRuleProvider {
alshabib1cc04f72014-09-16 16:09:58 -070097
98 private final Logger log = getLogger(getClass());
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected FlowRuleProviderRegistry providerRegistry;
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected OpenFlowController controller;
105
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected ComponentConfigService cfgService;
108
Jonathan Hart3c259162015-10-21 21:31:19 -0700109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected DriverService driverService;
111
ssyoon9030fbcd92015-08-17 10:42:07 +0900112 private static final int DEFAULT_POLL_FREQUENCY = 5;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700113 @Property(name = "flowPollFrequency", intValue = DEFAULT_POLL_FREQUENCY,
114 label = "Frequency (in seconds) for polling flow statistics")
115 private int flowPollFrequency = DEFAULT_POLL_FREQUENCY;
116
ssyoon9030fbcd92015-08-17 10:42:07 +0900117 private static final boolean DEFAULT_ADAPTIVE_FLOW_SAMPLING = true;
118 @Property(name = "adaptiveFlowSampling", boolValue = DEFAULT_ADAPTIVE_FLOW_SAMPLING,
119 label = "Adaptive Flow Sampling is on or off")
120 private boolean adaptiveFlowSampling = DEFAULT_ADAPTIVE_FLOW_SAMPLING;
121
alshabib1cc04f72014-09-16 16:09:58 -0700122 private FlowRuleProviderService providerService;
123
alshabibeec3a062014-09-17 18:01:26 -0700124 private final InternalFlowProvider listener = new InternalFlowProvider();
125
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800126 private Cache<Long, InternalCacheEntry> pendingBatches;
alshabib193525b2014-10-08 18:58:03 -0700127
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700128 private final Timer timer = new Timer("onos-openflow-collector");
ssyoon9030fbcd92015-08-17 10:42:07 +0900129 private final Map<Dpid, FlowStatsCollector> simpleCollectors = Maps.newHashMap();
130
131 // NewAdaptiveFlowStatsCollector Set
132 private final Map<Dpid, NewAdaptiveFlowStatsCollector> afsCollectors = Maps.newHashMap();
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700133 private final Map<Dpid, FlowStatsCollector> collectors = Maps.newHashMap();
134 private final Map<Dpid, TableStatisticsCollector> tableStatsCollectors = Maps.newHashMap();
alshabib3d643ec2014-10-22 18:33:00 -0700135
alshabib1cc04f72014-09-16 16:09:58 -0700136 /**
137 * Creates an OpenFlow host provider.
138 */
139 public OpenFlowRuleProvider() {
Brian O'Connorabafb502014-12-02 22:26:20 -0800140 super(new ProviderId("of", "org.onosproject.provider.openflow"));
alshabib1cc04f72014-09-16 16:09:58 -0700141 }
142
143 @Activate
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700144 public void activate(ComponentContext context) {
145 cfgService.registerProperties(getClass());
alshabib1cc04f72014-09-16 16:09:58 -0700146 providerService = providerRegistry.register(this);
alshabibeec3a062014-09-17 18:01:26 -0700147 controller.addListener(listener);
148 controller.addEventListener(listener);
alshabib3d643ec2014-10-22 18:33:00 -0700149
Antonio Marsico1c5ae1f2015-12-15 15:31:56 +0100150 modified(context);
151
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700152 pendingBatches = createBatchCache();
ssyoon9030fbcd92015-08-17 10:42:07 +0900153
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700154 createCollectors();
alshabib3d643ec2014-10-22 18:33:00 -0700155
ssyoon9030fbcd92015-08-17 10:42:07 +0900156 log.info("Started with flowPollFrequency = {}, adaptiveFlowSampling = {}",
157 flowPollFrequency, adaptiveFlowSampling);
alshabib1cc04f72014-09-16 16:09:58 -0700158 }
159
160 @Deactivate
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700161 public void deactivate(ComponentContext context) {
162 cfgService.unregisterProperties(getClass(), false);
163 stopCollectors();
alshabib1cc04f72014-09-16 16:09:58 -0700164 providerRegistry.unregister(this);
165 providerService = null;
166
167 log.info("Stopped");
168 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800169
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700170 @Modified
171 public void modified(ComponentContext context) {
172 Dictionary<?, ?> properties = context.getProperties();
173 int newFlowPollFrequency;
174 try {
175 String s = get(properties, "flowPollFrequency");
176 newFlowPollFrequency = isNullOrEmpty(s) ? flowPollFrequency : Integer.parseInt(s.trim());
177
178 } catch (NumberFormatException | ClassCastException e) {
179 newFlowPollFrequency = flowPollFrequency;
180 }
181
182 if (newFlowPollFrequency != flowPollFrequency) {
183 flowPollFrequency = newFlowPollFrequency;
184 adjustRate();
185 }
186
187 log.info("Settings: flowPollFrequency={}", flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900188
189 boolean newAdaptiveFlowSampling;
190 String s = get(properties, "adaptiveFlowSampling");
191 newAdaptiveFlowSampling = isNullOrEmpty(s) ? adaptiveFlowSampling : Boolean.parseBoolean(s.trim());
192
193 if (newAdaptiveFlowSampling != adaptiveFlowSampling) {
194 // stop previous collector
195 stopCollectors();
196 adaptiveFlowSampling = newAdaptiveFlowSampling;
197 // create new collectors
198 createCollectors();
199 }
200
201 log.info("Settings: adaptiveFlowSampling={}", adaptiveFlowSampling);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700202 }
203
204 private Cache<Long, InternalCacheEntry> createBatchCache() {
205 return CacheBuilder.newBuilder()
206 .expireAfterWrite(10, TimeUnit.SECONDS)
207 .removalListener((RemovalNotification<Long, InternalCacheEntry> notification) -> {
208 if (notification.getCause() == RemovalCause.EXPIRED) {
209 providerService.batchOperationCompleted(notification.getKey(),
210 notification.getValue().failedCompletion());
211 }
212 }).build();
213 }
214
215 private void createCollectors() {
216 controller.getSwitches().forEach(this::createCollector);
217 }
218
219 private void createCollector(OpenFlowSwitch sw) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900220 if (adaptiveFlowSampling) {
221 // NewAdaptiveFlowStatsCollector Constructor
Charles Chan14967c22015-12-07 11:11:50 -0800222 NewAdaptiveFlowStatsCollector fsc =
223 new NewAdaptiveFlowStatsCollector(driverService, sw, flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900224 fsc.start();
225 afsCollectors.put(new Dpid(sw.getId()), fsc);
226 } else {
227 FlowStatsCollector fsc = new FlowStatsCollector(timer, sw, flowPollFrequency);
228 fsc.start();
229 simpleCollectors.put(new Dpid(sw.getId()), fsc);
230 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700231 TableStatisticsCollector tsc = new TableStatisticsCollector(timer, sw, flowPollFrequency);
232 tsc.start();
233 tableStatsCollectors.put(new Dpid(sw.getId()), tsc);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700234 }
235
236 private void stopCollectors() {
ssyoon9030fbcd92015-08-17 10:42:07 +0900237 if (adaptiveFlowSampling) {
238 // NewAdaptiveFlowStatsCollector Destructor
239 afsCollectors.values().forEach(NewAdaptiveFlowStatsCollector::stop);
240 afsCollectors.clear();
241 } else {
242 simpleCollectors.values().forEach(FlowStatsCollector::stop);
243 simpleCollectors.clear();
244 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700245 tableStatsCollectors.values().forEach(TableStatisticsCollector::stop);
246 tableStatsCollectors.clear();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700247 }
248
249 private void adjustRate() {
250 DefaultLoad.setPollInterval(flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900251 if (adaptiveFlowSampling) {
252 // NewAdaptiveFlowStatsCollector calAndPollInterval
253 afsCollectors.values().forEach(fsc -> fsc.adjustCalAndPollInterval(flowPollFrequency));
254 } else {
255 simpleCollectors.values().forEach(fsc -> fsc.adjustPollInterval(flowPollFrequency));
256 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700257 tableStatsCollectors.values().forEach(tsc -> tsc.adjustPollInterval(flowPollFrequency));
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700258 }
259
alshabib1cc04f72014-09-16 16:09:58 -0700260 @Override
261 public void applyFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800262 for (FlowRule flowRule : flowRules) {
263 applyRule(flowRule);
alshabib35edb1a2014-09-16 17:44:44 -0700264 }
alshabib1cc04f72014-09-16 16:09:58 -0700265 }
266
alshabib35edb1a2014-09-16 17:44:44 -0700267 private void applyRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900268 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
269 OpenFlowSwitch sw = controller.getSwitch(dpid);
270
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700271 FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
272 if (hasPayload(flowRuleExtPayLoad)) {
273 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800274 sw.sendMsg(msg);
275 return;
276 }
alshabibbdcbb102015-04-22 14:16:38 -0700277 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Jonathan Hart3c259162015-10-21 21:31:19 -0700278 Optional.empty(), Optional.of(driverService)).buildFlowAdd());
ssyoon9030fbcd92015-08-17 10:42:07 +0900279
280 if (adaptiveFlowSampling) {
281 // Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700282 NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
283 if (collector != null) {
284 collector.addWithFlowRule(flowRule);
285 }
ssyoon9030fbcd92015-08-17 10:42:07 +0900286 }
alshabib35edb1a2014-09-16 17:44:44 -0700287 }
288
alshabib1cc04f72014-09-16 16:09:58 -0700289 @Override
290 public void removeFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800291 for (FlowRule flowRule : flowRules) {
292 removeRule(flowRule);
alshabib219ebaa2014-09-22 15:41:24 -0700293 }
alshabib1cc04f72014-09-16 16:09:58 -0700294 }
295
alshabib219ebaa2014-09-22 15:41:24 -0700296 private void removeRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900297 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
298 OpenFlowSwitch sw = controller.getSwitch(dpid);
299
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700300 FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
301 if (hasPayload(flowRuleExtPayLoad)) {
302 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800303 sw.sendMsg(msg);
304 return;
305 }
alshabibbdcbb102015-04-22 14:16:38 -0700306 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
Jonathan Hart3c259162015-10-21 21:31:19 -0700307 Optional.empty(), Optional.of(driverService)).buildFlowDel());
ssyoon9030fbcd92015-08-17 10:42:07 +0900308
309 if (adaptiveFlowSampling) {
310 // Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700311 NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
312 if (collector != null) {
313 collector.removeFlows(flowRule);
314 }
ssyoon9030fbcd92015-08-17 10:42:07 +0900315 }
alshabib219ebaa2014-09-22 15:41:24 -0700316 }
317
alshabiba68eb962014-09-24 20:34:13 -0700318 @Override
319 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
320 // TODO: optimize using the ApplicationId
321 removeFlowRule(flowRules);
322 }
323
alshabib193525b2014-10-08 18:58:03 -0700324 @Override
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800325 public void executeBatch(FlowRuleBatchOperation batch) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900326 checkNotNull(batch);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800327
328 pendingBatches.put(batch.id(), new InternalCacheEntry(batch));
329
ssyoon9030fbcd92015-08-17 10:42:07 +0900330 Dpid dpid = Dpid.dpid(batch.deviceId().uri());
331 OpenFlowSwitch sw = controller.getSwitch(dpid);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800332 OFFlowMod mod;
alshabib193525b2014-10-08 18:58:03 -0700333 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
jcc3d4e14a2015-04-21 11:32:05 +0800334 // flow is the third party privacy flow
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700335
336 FlowRuleExtPayLoad flowRuleExtPayLoad = fbe.target().payLoad();
337 if (hasPayload(flowRuleExtPayLoad)) {
338 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800339 sw.sendMsg(msg);
340 continue;
341 }
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700342 FlowModBuilder builder =
Jonathan Hart3c259162015-10-21 21:31:19 -0700343 FlowModBuilder.builder(fbe.target(), sw.factory(),
344 Optional.of(batch.id()), Optional.of(driverService));
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700345 NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800346 switch (fbe.operator()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700347 case ADD:
348 mod = builder.buildFlowAdd();
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700349 if (adaptiveFlowSampling && collector != null) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900350 // Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700351 collector.addWithFlowRule(fbe.target());
ssyoon9030fbcd92015-08-17 10:42:07 +0900352 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700353 break;
354 case REMOVE:
355 mod = builder.buildFlowDel();
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700356 if (adaptiveFlowSampling && collector != null) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900357 // Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700358 collector.removeFlows(fbe.target());
ssyoon9030fbcd92015-08-17 10:42:07 +0900359 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700360 break;
361 case MODIFY:
362 mod = builder.buildFlowMod();
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700363 if (adaptiveFlowSampling && collector != null) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900364 // Add or Update TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
365 // afsCollectors.get(dpid).addWithFlowRule(fbe.target()); //check if add is good or not
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700366 collector.addOrUpdateFlows((FlowEntry) fbe.target());
ssyoon9030fbcd92015-08-17 10:42:07 +0900367 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700368 break;
369 default:
370 log.error("Unsupported batch operation {}; skipping flowmod {}",
ssyoon9030fbcd92015-08-17 10:42:07 +0900371 fbe.operator(), fbe);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700372 continue;
jcc3d4e14a2015-04-21 11:32:05 +0800373 }
Saurav Das3ea46622015-04-22 14:01:34 -0700374 sw.sendMsg(mod);
alshabib193525b2014-10-08 18:58:03 -0700375 }
jcc3d4e14a2015-04-21 11:32:05 +0800376 OFBarrierRequest.Builder builder = sw.factory().buildBarrierRequest()
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800377 .setXid(batch.id());
378 sw.sendMsg(builder.build());
alshabib193525b2014-10-08 18:58:03 -0700379 }
380
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700381 private boolean hasPayload(FlowRuleExtPayLoad flowRuleExtPayLoad) {
382 return flowRuleExtPayLoad != null &&
383 flowRuleExtPayLoad.payLoad() != null &&
384 flowRuleExtPayLoad.payLoad().length > 0;
385 }
386
alshabib8f1cf4a2014-09-17 14:44:48 -0700387 private class InternalFlowProvider
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800388 implements OpenFlowSwitchListener, OpenFlowEventListener {
alshabib8f1cf4a2014-09-17 14:44:48 -0700389
alshabib8f1cf4a2014-09-17 14:44:48 -0700390 @Override
391 public void switchAdded(Dpid dpid) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900392
393 OpenFlowSwitch sw = controller.getSwitch(dpid);
394
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700395 createCollector(controller.getSwitch(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700396 }
397
398 @Override
399 public void switchRemoved(Dpid dpid) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900400 if (adaptiveFlowSampling) {
401 NewAdaptiveFlowStatsCollector collector = afsCollectors.remove(dpid);
402 if (collector != null) {
403 collector.stop();
404 }
405 } else {
406 FlowStatsCollector collector = simpleCollectors.remove(dpid);
407 if (collector != null) {
408 collector.stop();
409 }
alshabibdfc7afb2014-10-21 20:13:27 -0700410 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700411 TableStatisticsCollector tsc = tableStatsCollectors.remove(dpid);
412 if (tsc != null) {
413 tsc.stop();
414 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700415 }
416
417 @Override
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700418 public void switchChanged(Dpid dpid) {
419 }
420
421 @Override
alshabib8f1cf4a2014-09-17 14:44:48 -0700422 public void portChanged(Dpid dpid, OFPortStatus status) {
jcc3d4e14a2015-04-21 11:32:05 +0800423 // TODO: Decide whether to evict flows internal store.
alshabib8f1cf4a2014-09-17 14:44:48 -0700424 }
425
426 @Override
427 public void handleMessage(Dpid dpid, OFMessage msg) {
Jonathan Harte4e74f02016-03-03 12:57:40 -0800428 DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700429 switch (msg.getType()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700430 case FLOW_REMOVED:
431 OFFlowRemoved removed = (OFFlowRemoved) msg;
alshabib6b5cfec2014-09-18 17:42:18 -0700432
Jonathan Harte4e74f02016-03-03 12:57:40 -0800433 FlowEntry fr = new FlowEntryBuilder(deviceId, removed, driverService).build();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700434 providerService.flowRemoved(fr);
ssyoon9030fbcd92015-08-17 10:42:07 +0900435
436 if (adaptiveFlowSampling) {
437 // Removed TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
Thomas Vachuskad07c0922015-10-06 14:48:06 -0700438 NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
439 if (collector != null) {
440 collector.flowRemoved(fr);
441 }
ssyoon9030fbcd92015-08-17 10:42:07 +0900442 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700443 break;
444 case STATS_REPLY:
445 if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW) {
446 pushFlowMetrics(dpid, (OFFlowStatsReply) msg);
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700447 } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.TABLE) {
448 pushTableStatistics(dpid, (OFTableStatsReply) msg);
sangho89bf6fb2015-02-09 09:33:13 -0800449 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700450 break;
451 case BARRIER_REPLY:
452 try {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700453 InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800454 if (entry != null) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700455 providerService
456 .batchOperationCompleted(msg.getXid(),
457 entry.completed());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800458 } else {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700459 log.warn("Received unknown Barrier Reply: {}",
460 msg.getXid());
461 }
462 } finally {
463 pendingBatches.invalidate(msg.getXid());
464 }
465 break;
466 case ERROR:
Thomas Vachuska3358af22015-05-19 18:40:34 -0700467 // TODO: This needs to get suppressed in a better way.
468 if (msg instanceof OFBadRequestErrorMsg &&
469 ((OFBadRequestErrorMsg) msg).getCode() == OFBadRequestCode.BAD_TYPE) {
470 log.debug("Received error message {} from {}", msg, dpid);
471 } else {
472 log.warn("Received error message {} from {}", msg, dpid);
473 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700474
475 OFErrorMsg error = (OFErrorMsg) msg;
476 if (error.getErrType() == OFErrorType.FLOW_MOD_FAILED) {
477 OFFlowModFailedErrorMsg fmFailed = (OFFlowModFailedErrorMsg) error;
478 if (fmFailed.getData().getParsedMessage().isPresent()) {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700479 OFMessage m = fmFailed.getData().getParsedMessage().get();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700480 OFFlowMod fm = (OFFlowMod) m;
Thomas Vachuska3358af22015-05-19 18:40:34 -0700481 InternalCacheEntry entry =
482 pendingBatches.getIfPresent(msg.getXid());
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700483 if (entry != null) {
Jonathan Harte4e74f02016-03-03 12:57:40 -0800484 entry.appendFailure(new FlowEntryBuilder(deviceId, fm, driverService).build());
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700485 } else {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700486 log.error("No matching batch for this error: {}", error);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700487 }
488 } else {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700489 // FIXME: Potentially add flowtracking to avoid this message.
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700490 log.error("Flow installation failed but switch didn't"
491 + " tell us which one.");
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800492 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800493 }
Ray Milkey4fd3ceb2015-12-10 14:43:08 -0800494 break;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700495 default:
496 log.debug("Unhandled message type: {}", msg.getType());
alshabib8f1cf4a2014-09-17 14:44:48 -0700497 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700498 }
499
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700500 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700501 public void receivedRoleReply(Dpid dpid, RoleState requested,
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800502 RoleState response) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700503 // Do nothing here for now.
504 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700505
sangho89bf6fb2015-02-09 09:33:13 -0800506 private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies) {
alshabib64def642014-12-02 23:27:37 -0800507
alshabib54ce5892014-09-23 17:50:51 -0700508 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
alshabib54ce5892014-09-23 17:50:51 -0700509
alshabib64def642014-12-02 23:27:37 -0800510 List<FlowEntry> flowEntries = replies.getEntries().stream()
Jonathan Harte4e74f02016-03-03 12:57:40 -0800511 .map(entry -> new FlowEntryBuilder(did, entry, driverService).build())
alshabib64def642014-12-02 23:27:37 -0800512 .collect(Collectors.toList());
alshabib54ce5892014-09-23 17:50:51 -0700513
ssyoon9030fbcd92015-08-17 10:42:07 +0900514 if (adaptiveFlowSampling) {
515 NewAdaptiveFlowStatsCollector afsc = afsCollectors.get(dpid);
516
517 synchronized (afsc) {
518 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
519 log.debug("OpenFlowRuleProvider:pushFlowMetrics, flowMissingXid={}, "
520 + "OFFlowStatsReply Xid={}, for {}",
521 afsc.getFlowMissingXid(), replies.getXid(), dpid);
522 }
523
524 // Check that OFFlowStatsReply Xid is same with the one of OFFlowStatsRequest?
525 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
526 if (afsc.getFlowMissingXid() == replies.getXid()) {
527 // call entire flow stats update with flowMissing synchronization.
528 // used existing pushFlowMetrics
529 providerService.pushFlowMetrics(did, flowEntries);
530 }
531 // reset flowMissingXid to NO_FLOW_MISSING_XID
532 afsc.setFlowMissingXid(NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID);
533
534 } else {
535 // call individual flow stats update
536 providerService.pushFlowMetricsWithoutFlowMissing(did, flowEntries);
537 }
538
539 // Update TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
540 afsc.pushFlowMetrics(flowEntries);
541 }
542 } else {
543 // call existing entire flow stats update with flowMissing synchronization
544 providerService.pushFlowMetrics(did, flowEntries);
545 }
alshabib5c370ff2014-09-18 10:12:14 -0700546 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700547
548 private void pushTableStatistics(Dpid dpid, OFTableStatsReply replies) {
549
550 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
551 List<TableStatisticsEntry> tableStatsEntries = replies.getEntries().stream()
552 .map(entry -> buildTableStatistics(did, entry))
553 .filter(Objects::nonNull)
554 .collect(Collectors.toList());
555 providerService.pushTableStatistics(did, tableStatsEntries);
556 }
557
558 private TableStatisticsEntry buildTableStatistics(DeviceId deviceId,
559 OFTableStatsEntry ofEntry) {
560 TableStatisticsEntry entry = null;
561 if (ofEntry != null) {
562 entry = new DefaultTableStatisticsEntry(deviceId,
563 ofEntry.getTableId().getValue(),
564 ofEntry.getActiveCount(),
565 ofEntry.getLookupCount().getValue(),
566 ofEntry.getMatchedCount().getValue());
567 }
568
569 return entry;
570
571 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700572 }
alshabib1cc04f72014-09-16 16:09:58 -0700573
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800574 /**
jcc3d4e14a2015-04-21 11:32:05 +0800575 * The internal cache entry holding the original request as well as
576 * accumulating the any failures along the way.
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700577 * <p/>
jcc3d4e14a2015-04-21 11:32:05 +0800578 * If this entry is evicted from the cache then the entire operation is
579 * considered failed. Otherwise, only the failures reported by the device
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800580 * will be propagated up.
581 */
582 private class InternalCacheEntry {
alshabib902d41b2014-10-07 16:52:05 -0700583
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800584 private final FlowRuleBatchOperation operation;
585 private final Set<FlowRule> failures = Sets.newConcurrentHashSet();
alshabib193525b2014-10-08 18:58:03 -0700586
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800587 public InternalCacheEntry(FlowRuleBatchOperation operation) {
588 this.operation = operation;
alshabib902d41b2014-10-07 16:52:05 -0700589 }
590
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800591 /**
592 * Appends a failed rule to the set of failed items.
jcc3d4e14a2015-04-21 11:32:05 +0800593 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800594 * @param rule the failed rule
595 */
596 public void appendFailure(FlowRule rule) {
597 failures.add(rule);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800598 }
599
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800600 /**
601 * Fails the entire batch and returns the failed operation.
jcc3d4e14a2015-04-21 11:32:05 +0800602 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800603 * @return the failed operation
604 */
605 public CompletedBatchOperation failedCompletion() {
606 Set<FlowRule> fails = operation.getOperations().stream()
607 .map(op -> op.target()).collect(Collectors.toSet());
jcc3d4e14a2015-04-21 11:32:05 +0800608 return new CompletedBatchOperation(false,
609 Collections
610 .unmodifiableSet(fails),
611 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700612 }
613
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800614 /**
615 * Returns the completed operation and whether the batch suceeded.
jcc3d4e14a2015-04-21 11:32:05 +0800616 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800617 * @return the completed operation
618 */
619 public CompletedBatchOperation completed() {
jcc3d4e14a2015-04-21 11:32:05 +0800620 return new CompletedBatchOperation(
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700621 failures.isEmpty(),
622 Collections
623 .unmodifiableSet(failures),
624 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700625 }
alshabib902d41b2014-10-07 16:52:05 -0700626 }
alshabiba68eb962014-09-24 20:34:13 -0700627
alshabib1cc04f72014-09-16 16:09:58 -0700628}