blob: 4c38d7ad9e886025b1721af425a45d7c69566cfc [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;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070024
alshabib1cc04f72014-09-16 16:09:58 -070025import org.apache.felix.scr.annotations.Activate;
26import org.apache.felix.scr.annotations.Component;
27import org.apache.felix.scr.annotations.Deactivate;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070028import org.apache.felix.scr.annotations.Modified;
29import org.apache.felix.scr.annotations.Property;
alshabib1cc04f72014-09-16 16:09:58 -070030import org.apache.felix.scr.annotations.Reference;
31import org.apache.felix.scr.annotations.ReferenceCardinality;
Thomas Vachuska75aaa672015-04-29 12:24:43 -070032import org.onosproject.cfg.ComponentConfigService;
Brian O'Connorabafb502014-12-02 22:26:20 -080033import org.onosproject.core.ApplicationId;
34import org.onosproject.net.DeviceId;
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;
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -070064import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
65import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
alshabib8f1cf4a2014-09-17 14:44:48 -070066import org.projectfloodlight.openflow.protocol.OFMessage;
67import org.projectfloodlight.openflow.protocol.OFPortStatus;
alshabib5c370ff2014-09-18 10:12:14 -070068import org.projectfloodlight.openflow.protocol.OFStatsReply;
sangho89bf6fb2015-02-09 09:33:13 -080069import org.projectfloodlight.openflow.protocol.OFStatsType;
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
ssyoon9030fbcd92015-08-17 10:42:07 +0900109 private static final int DEFAULT_POLL_FREQUENCY = 5;
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700110 @Property(name = "flowPollFrequency", intValue = DEFAULT_POLL_FREQUENCY,
111 label = "Frequency (in seconds) for polling flow statistics")
112 private int flowPollFrequency = DEFAULT_POLL_FREQUENCY;
113
ssyoon9030fbcd92015-08-17 10:42:07 +0900114 private static final boolean DEFAULT_ADAPTIVE_FLOW_SAMPLING = true;
115 @Property(name = "adaptiveFlowSampling", boolValue = DEFAULT_ADAPTIVE_FLOW_SAMPLING,
116 label = "Adaptive Flow Sampling is on or off")
117 private boolean adaptiveFlowSampling = DEFAULT_ADAPTIVE_FLOW_SAMPLING;
118
alshabib1cc04f72014-09-16 16:09:58 -0700119 private FlowRuleProviderService providerService;
120
alshabibeec3a062014-09-17 18:01:26 -0700121 private final InternalFlowProvider listener = new InternalFlowProvider();
122
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800123 private Cache<Long, InternalCacheEntry> pendingBatches;
alshabib193525b2014-10-08 18:58:03 -0700124
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700125 private final Timer timer = new Timer("onos-openflow-collector");
ssyoon9030fbcd92015-08-17 10:42:07 +0900126 private final Map<Dpid, FlowStatsCollector> simpleCollectors = Maps.newHashMap();
127
128 // NewAdaptiveFlowStatsCollector Set
129 private final Map<Dpid, NewAdaptiveFlowStatsCollector> afsCollectors = Maps.newHashMap();
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700130 private final Map<Dpid, FlowStatsCollector> collectors = Maps.newHashMap();
131 private final Map<Dpid, TableStatisticsCollector> tableStatsCollectors = Maps.newHashMap();
alshabib3d643ec2014-10-22 18:33:00 -0700132
alshabib1cc04f72014-09-16 16:09:58 -0700133 /**
134 * Creates an OpenFlow host provider.
135 */
136 public OpenFlowRuleProvider() {
Brian O'Connorabafb502014-12-02 22:26:20 -0800137 super(new ProviderId("of", "org.onosproject.provider.openflow"));
alshabib1cc04f72014-09-16 16:09:58 -0700138 }
139
140 @Activate
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700141 public void activate(ComponentContext context) {
142 cfgService.registerProperties(getClass());
alshabib1cc04f72014-09-16 16:09:58 -0700143 providerService = providerRegistry.register(this);
alshabibeec3a062014-09-17 18:01:26 -0700144 controller.addListener(listener);
145 controller.addEventListener(listener);
alshabib3d643ec2014-10-22 18:33:00 -0700146
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700147 pendingBatches = createBatchCache();
ssyoon9030fbcd92015-08-17 10:42:07 +0900148
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700149 createCollectors();
alshabib3d643ec2014-10-22 18:33:00 -0700150
ssyoon9030fbcd92015-08-17 10:42:07 +0900151 log.info("Started with flowPollFrequency = {}, adaptiveFlowSampling = {}",
152 flowPollFrequency, adaptiveFlowSampling);
alshabib1cc04f72014-09-16 16:09:58 -0700153 }
154
155 @Deactivate
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700156 public void deactivate(ComponentContext context) {
157 cfgService.unregisterProperties(getClass(), false);
158 stopCollectors();
alshabib1cc04f72014-09-16 16:09:58 -0700159 providerRegistry.unregister(this);
160 providerService = null;
161
162 log.info("Stopped");
163 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800164
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700165 @Modified
166 public void modified(ComponentContext context) {
167 Dictionary<?, ?> properties = context.getProperties();
168 int newFlowPollFrequency;
169 try {
170 String s = get(properties, "flowPollFrequency");
171 newFlowPollFrequency = isNullOrEmpty(s) ? flowPollFrequency : Integer.parseInt(s.trim());
172
173 } catch (NumberFormatException | ClassCastException e) {
174 newFlowPollFrequency = flowPollFrequency;
175 }
176
177 if (newFlowPollFrequency != flowPollFrequency) {
178 flowPollFrequency = newFlowPollFrequency;
179 adjustRate();
180 }
181
182 log.info("Settings: flowPollFrequency={}", flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900183
184 boolean newAdaptiveFlowSampling;
185 String s = get(properties, "adaptiveFlowSampling");
186 newAdaptiveFlowSampling = isNullOrEmpty(s) ? adaptiveFlowSampling : Boolean.parseBoolean(s.trim());
187
188 if (newAdaptiveFlowSampling != adaptiveFlowSampling) {
189 // stop previous collector
190 stopCollectors();
191 adaptiveFlowSampling = newAdaptiveFlowSampling;
192 // create new collectors
193 createCollectors();
194 }
195
196 log.info("Settings: adaptiveFlowSampling={}", adaptiveFlowSampling);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700197 }
198
199 private Cache<Long, InternalCacheEntry> createBatchCache() {
200 return CacheBuilder.newBuilder()
201 .expireAfterWrite(10, TimeUnit.SECONDS)
202 .removalListener((RemovalNotification<Long, InternalCacheEntry> notification) -> {
203 if (notification.getCause() == RemovalCause.EXPIRED) {
204 providerService.batchOperationCompleted(notification.getKey(),
205 notification.getValue().failedCompletion());
206 }
207 }).build();
208 }
209
210 private void createCollectors() {
211 controller.getSwitches().forEach(this::createCollector);
212 }
213
214 private void createCollector(OpenFlowSwitch sw) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900215 if (adaptiveFlowSampling) {
216 // NewAdaptiveFlowStatsCollector Constructor
217 NewAdaptiveFlowStatsCollector fsc = new NewAdaptiveFlowStatsCollector(sw, flowPollFrequency);
218 fsc.start();
219 afsCollectors.put(new Dpid(sw.getId()), fsc);
220 } else {
221 FlowStatsCollector fsc = new FlowStatsCollector(timer, sw, flowPollFrequency);
222 fsc.start();
223 simpleCollectors.put(new Dpid(sw.getId()), fsc);
224 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700225 TableStatisticsCollector tsc = new TableStatisticsCollector(timer, sw, flowPollFrequency);
226 tsc.start();
227 tableStatsCollectors.put(new Dpid(sw.getId()), tsc);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700228 }
229
230 private void stopCollectors() {
ssyoon9030fbcd92015-08-17 10:42:07 +0900231 if (adaptiveFlowSampling) {
232 // NewAdaptiveFlowStatsCollector Destructor
233 afsCollectors.values().forEach(NewAdaptiveFlowStatsCollector::stop);
234 afsCollectors.clear();
235 } else {
236 simpleCollectors.values().forEach(FlowStatsCollector::stop);
237 simpleCollectors.clear();
238 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700239 tableStatsCollectors.values().forEach(TableStatisticsCollector::stop);
240 tableStatsCollectors.clear();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700241 }
242
243 private void adjustRate() {
244 DefaultLoad.setPollInterval(flowPollFrequency);
ssyoon9030fbcd92015-08-17 10:42:07 +0900245 if (adaptiveFlowSampling) {
246 // NewAdaptiveFlowStatsCollector calAndPollInterval
247 afsCollectors.values().forEach(fsc -> fsc.adjustCalAndPollInterval(flowPollFrequency));
248 } else {
249 simpleCollectors.values().forEach(fsc -> fsc.adjustPollInterval(flowPollFrequency));
250 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700251 tableStatsCollectors.values().forEach(tsc -> tsc.adjustPollInterval(flowPollFrequency));
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700252 }
253
alshabib1cc04f72014-09-16 16:09:58 -0700254 @Override
255 public void applyFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800256 for (FlowRule flowRule : flowRules) {
257 applyRule(flowRule);
alshabib35edb1a2014-09-16 17:44:44 -0700258 }
alshabib1cc04f72014-09-16 16:09:58 -0700259 }
260
alshabib35edb1a2014-09-16 17:44:44 -0700261 private void applyRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900262 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
263 OpenFlowSwitch sw = controller.getSwitch(dpid);
264
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700265 FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
266 if (hasPayload(flowRuleExtPayLoad)) {
267 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800268 sw.sendMsg(msg);
269 return;
270 }
alshabibbdcbb102015-04-22 14:16:38 -0700271 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
jcc3d4e14a2015-04-21 11:32:05 +0800272 Optional.empty()).buildFlowAdd());
ssyoon9030fbcd92015-08-17 10:42:07 +0900273
274 if (adaptiveFlowSampling) {
275 // Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
276 afsCollectors.get(dpid).addWithFlowRule(flowRule);
277 }
alshabib35edb1a2014-09-16 17:44:44 -0700278 }
279
alshabib1cc04f72014-09-16 16:09:58 -0700280 @Override
281 public void removeFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800282 for (FlowRule flowRule : flowRules) {
283 removeRule(flowRule);
alshabib219ebaa2014-09-22 15:41:24 -0700284 }
alshabib1cc04f72014-09-16 16:09:58 -0700285 }
286
alshabib219ebaa2014-09-22 15:41:24 -0700287 private void removeRule(FlowRule flowRule) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900288 Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
289 OpenFlowSwitch sw = controller.getSwitch(dpid);
290
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700291 FlowRuleExtPayLoad flowRuleExtPayLoad = flowRule.payLoad();
292 if (hasPayload(flowRuleExtPayLoad)) {
293 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800294 sw.sendMsg(msg);
295 return;
296 }
alshabibbdcbb102015-04-22 14:16:38 -0700297 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
jcc3d4e14a2015-04-21 11:32:05 +0800298 Optional.empty()).buildFlowDel());
ssyoon9030fbcd92015-08-17 10:42:07 +0900299
300 if (adaptiveFlowSampling) {
301 // Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
302 afsCollectors.get(dpid).removeFlows(flowRule);
303 }
alshabib219ebaa2014-09-22 15:41:24 -0700304 }
305
alshabiba68eb962014-09-24 20:34:13 -0700306 @Override
307 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
308 // TODO: optimize using the ApplicationId
309 removeFlowRule(flowRules);
310 }
311
alshabib193525b2014-10-08 18:58:03 -0700312 @Override
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800313 public void executeBatch(FlowRuleBatchOperation batch) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900314 checkNotNull(batch);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800315
316 pendingBatches.put(batch.id(), new InternalCacheEntry(batch));
317
ssyoon9030fbcd92015-08-17 10:42:07 +0900318 Dpid dpid = Dpid.dpid(batch.deviceId().uri());
319 OpenFlowSwitch sw = controller.getSwitch(dpid);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800320 OFFlowMod mod;
alshabib193525b2014-10-08 18:58:03 -0700321 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
jcc3d4e14a2015-04-21 11:32:05 +0800322 // flow is the third party privacy flow
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700323
324 FlowRuleExtPayLoad flowRuleExtPayLoad = fbe.target().payLoad();
325 if (hasPayload(flowRuleExtPayLoad)) {
326 OFMessage msg = new ThirdPartyMessage(flowRuleExtPayLoad.payLoad());
jcc3d4e14a2015-04-21 11:32:05 +0800327 sw.sendMsg(msg);
328 continue;
329 }
330 FlowModBuilder builder = FlowModBuilder.builder(fbe.target(), sw
331 .factory(), Optional.of(batch.id()));
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800332 switch (fbe.operator()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700333 case ADD:
334 mod = builder.buildFlowAdd();
ssyoon9030fbcd92015-08-17 10:42:07 +0900335
336 if (adaptiveFlowSampling) {
337 // Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
338 afsCollectors.get(dpid).addWithFlowRule(fbe.target());
339 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700340 break;
341 case REMOVE:
342 mod = builder.buildFlowDel();
ssyoon9030fbcd92015-08-17 10:42:07 +0900343
344 if (adaptiveFlowSampling) {
345 // Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
346 afsCollectors.get(dpid).removeFlows(fbe.target());
347 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700348 break;
349 case MODIFY:
350 mod = builder.buildFlowMod();
ssyoon9030fbcd92015-08-17 10:42:07 +0900351
352 if (adaptiveFlowSampling) {
353 // Add or Update TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
354 // afsCollectors.get(dpid).addWithFlowRule(fbe.target()); //check if add is good or not
355 afsCollectors.get(dpid).addOrUpdateFlows((FlowEntry) fbe.target());
356 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700357 break;
358 default:
359 log.error("Unsupported batch operation {}; skipping flowmod {}",
ssyoon9030fbcd92015-08-17 10:42:07 +0900360 fbe.operator(), fbe);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700361 continue;
jcc3d4e14a2015-04-21 11:32:05 +0800362 }
Saurav Das3ea46622015-04-22 14:01:34 -0700363 sw.sendMsg(mod);
alshabib193525b2014-10-08 18:58:03 -0700364 }
jcc3d4e14a2015-04-21 11:32:05 +0800365 OFBarrierRequest.Builder builder = sw.factory().buildBarrierRequest()
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800366 .setXid(batch.id());
367 sw.sendMsg(builder.build());
alshabib193525b2014-10-08 18:58:03 -0700368 }
369
Thomas Vachuskaa6c0d042015-04-23 10:17:37 -0700370 private boolean hasPayload(FlowRuleExtPayLoad flowRuleExtPayLoad) {
371 return flowRuleExtPayLoad != null &&
372 flowRuleExtPayLoad.payLoad() != null &&
373 flowRuleExtPayLoad.payLoad().length > 0;
374 }
375
alshabib8f1cf4a2014-09-17 14:44:48 -0700376 private class InternalFlowProvider
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800377 implements OpenFlowSwitchListener, OpenFlowEventListener {
alshabib8f1cf4a2014-09-17 14:44:48 -0700378
alshabib8f1cf4a2014-09-17 14:44:48 -0700379 @Override
380 public void switchAdded(Dpid dpid) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900381
382 OpenFlowSwitch sw = controller.getSwitch(dpid);
383
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700384 createCollector(controller.getSwitch(dpid));
alshabib8f1cf4a2014-09-17 14:44:48 -0700385 }
386
387 @Override
388 public void switchRemoved(Dpid dpid) {
ssyoon9030fbcd92015-08-17 10:42:07 +0900389 if (adaptiveFlowSampling) {
390 NewAdaptiveFlowStatsCollector collector = afsCollectors.remove(dpid);
391 if (collector != null) {
392 collector.stop();
393 }
394 } else {
395 FlowStatsCollector collector = simpleCollectors.remove(dpid);
396 if (collector != null) {
397 collector.stop();
398 }
alshabibdfc7afb2014-10-21 20:13:27 -0700399 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700400 TableStatisticsCollector tsc = tableStatsCollectors.remove(dpid);
401 if (tsc != null) {
402 tsc.stop();
403 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700404 }
405
406 @Override
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700407 public void switchChanged(Dpid dpid) {
408 }
409
410 @Override
alshabib8f1cf4a2014-09-17 14:44:48 -0700411 public void portChanged(Dpid dpid, OFPortStatus status) {
jcc3d4e14a2015-04-21 11:32:05 +0800412 // TODO: Decide whether to evict flows internal store.
alshabib8f1cf4a2014-09-17 14:44:48 -0700413 }
414
415 @Override
416 public void handleMessage(Dpid dpid, OFMessage msg) {
alshabibda1644e2015-03-13 14:01:35 -0700417 OpenFlowSwitch sw = controller.getSwitch(dpid);
alshabib8f1cf4a2014-09-17 14:44:48 -0700418 switch (msg.getType()) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700419 case FLOW_REMOVED:
420 OFFlowRemoved removed = (OFFlowRemoved) msg;
alshabib6b5cfec2014-09-18 17:42:18 -0700421
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700422 FlowEntry fr = new FlowEntryBuilder(dpid, removed).build();
423 providerService.flowRemoved(fr);
ssyoon9030fbcd92015-08-17 10:42:07 +0900424
425 if (adaptiveFlowSampling) {
426 // Removed TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
427 afsCollectors.get(dpid).flowRemoved(fr);
428 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700429 break;
430 case STATS_REPLY:
431 if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW) {
432 pushFlowMetrics(dpid, (OFFlowStatsReply) msg);
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700433 } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.TABLE) {
434 pushTableStatistics(dpid, (OFTableStatsReply) msg);
sangho89bf6fb2015-02-09 09:33:13 -0800435 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700436 break;
437 case BARRIER_REPLY:
438 try {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700439 InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800440 if (entry != null) {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700441 providerService
442 .batchOperationCompleted(msg.getXid(),
443 entry.completed());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800444 } else {
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700445 log.warn("Received unknown Barrier Reply: {}",
446 msg.getXid());
447 }
448 } finally {
449 pendingBatches.invalidate(msg.getXid());
450 }
451 break;
452 case ERROR:
Thomas Vachuska3358af22015-05-19 18:40:34 -0700453 // TODO: This needs to get suppressed in a better way.
454 if (msg instanceof OFBadRequestErrorMsg &&
455 ((OFBadRequestErrorMsg) msg).getCode() == OFBadRequestCode.BAD_TYPE) {
456 log.debug("Received error message {} from {}", msg, dpid);
457 } else {
458 log.warn("Received error message {} from {}", msg, dpid);
459 }
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700460
461 OFErrorMsg error = (OFErrorMsg) msg;
462 if (error.getErrType() == OFErrorType.FLOW_MOD_FAILED) {
463 OFFlowModFailedErrorMsg fmFailed = (OFFlowModFailedErrorMsg) error;
464 if (fmFailed.getData().getParsedMessage().isPresent()) {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700465 OFMessage m = fmFailed.getData().getParsedMessage().get();
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700466 OFFlowMod fm = (OFFlowMod) m;
Thomas Vachuska3358af22015-05-19 18:40:34 -0700467 InternalCacheEntry entry =
468 pendingBatches.getIfPresent(msg.getXid());
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700469 if (entry != null) {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700470 entry.appendFailure(new FlowEntryBuilder(dpid, fm).build());
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700471 } else {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700472 log.error("No matching batch for this error: {}", error);
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700473 }
474 } else {
Thomas Vachuska3358af22015-05-19 18:40:34 -0700475 // FIXME: Potentially add flowtracking to avoid this message.
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700476 log.error("Flow installation failed but switch didn't"
477 + " tell us which one.");
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800478 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800479 }
ssyoon9030fbcd92015-08-17 10:42:07 +0900480
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700481 default:
482 log.debug("Unhandled message type: {}", msg.getType());
alshabib8f1cf4a2014-09-17 14:44:48 -0700483 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700484 }
485
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700486 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700487 public void receivedRoleReply(Dpid dpid, RoleState requested,
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800488 RoleState response) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700489 // Do nothing here for now.
490 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700491
sangho89bf6fb2015-02-09 09:33:13 -0800492 private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies) {
alshabib64def642014-12-02 23:27:37 -0800493
alshabib54ce5892014-09-23 17:50:51 -0700494 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
alshabib54ce5892014-09-23 17:50:51 -0700495
alshabib64def642014-12-02 23:27:37 -0800496 List<FlowEntry> flowEntries = replies.getEntries().stream()
alshabibbdcbb102015-04-22 14:16:38 -0700497 .map(entry -> new FlowEntryBuilder(dpid, entry).build())
alshabib64def642014-12-02 23:27:37 -0800498 .collect(Collectors.toList());
alshabib54ce5892014-09-23 17:50:51 -0700499
ssyoon9030fbcd92015-08-17 10:42:07 +0900500 if (adaptiveFlowSampling) {
501 NewAdaptiveFlowStatsCollector afsc = afsCollectors.get(dpid);
502
503 synchronized (afsc) {
504 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
505 log.debug("OpenFlowRuleProvider:pushFlowMetrics, flowMissingXid={}, "
506 + "OFFlowStatsReply Xid={}, for {}",
507 afsc.getFlowMissingXid(), replies.getXid(), dpid);
508 }
509
510 // Check that OFFlowStatsReply Xid is same with the one of OFFlowStatsRequest?
511 if (afsc.getFlowMissingXid() != NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID) {
512 if (afsc.getFlowMissingXid() == replies.getXid()) {
513 // call entire flow stats update with flowMissing synchronization.
514 // used existing pushFlowMetrics
515 providerService.pushFlowMetrics(did, flowEntries);
516 }
517 // reset flowMissingXid to NO_FLOW_MISSING_XID
518 afsc.setFlowMissingXid(NewAdaptiveFlowStatsCollector.NO_FLOW_MISSING_XID);
519
520 } else {
521 // call individual flow stats update
522 providerService.pushFlowMetricsWithoutFlowMissing(did, flowEntries);
523 }
524
525 // Update TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
526 afsc.pushFlowMetrics(flowEntries);
527 }
528 } else {
529 // call existing entire flow stats update with flowMissing synchronization
530 providerService.pushFlowMetrics(did, flowEntries);
531 }
alshabib5c370ff2014-09-18 10:12:14 -0700532 }
Srikanth Vavilapalli95810f52015-09-14 15:49:56 -0700533
534 private void pushTableStatistics(Dpid dpid, OFTableStatsReply replies) {
535
536 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
537 List<TableStatisticsEntry> tableStatsEntries = replies.getEntries().stream()
538 .map(entry -> buildTableStatistics(did, entry))
539 .filter(Objects::nonNull)
540 .collect(Collectors.toList());
541 providerService.pushTableStatistics(did, tableStatsEntries);
542 }
543
544 private TableStatisticsEntry buildTableStatistics(DeviceId deviceId,
545 OFTableStatsEntry ofEntry) {
546 TableStatisticsEntry entry = null;
547 if (ofEntry != null) {
548 entry = new DefaultTableStatisticsEntry(deviceId,
549 ofEntry.getTableId().getValue(),
550 ofEntry.getActiveCount(),
551 ofEntry.getLookupCount().getValue(),
552 ofEntry.getMatchedCount().getValue());
553 }
554
555 return entry;
556
557 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700558 }
alshabib1cc04f72014-09-16 16:09:58 -0700559
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800560 /**
jcc3d4e14a2015-04-21 11:32:05 +0800561 * The internal cache entry holding the original request as well as
562 * accumulating the any failures along the way.
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700563 * <p/>
jcc3d4e14a2015-04-21 11:32:05 +0800564 * If this entry is evicted from the cache then the entire operation is
565 * considered failed. Otherwise, only the failures reported by the device
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800566 * will be propagated up.
567 */
568 private class InternalCacheEntry {
alshabib902d41b2014-10-07 16:52:05 -0700569
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800570 private final FlowRuleBatchOperation operation;
571 private final Set<FlowRule> failures = Sets.newConcurrentHashSet();
alshabib193525b2014-10-08 18:58:03 -0700572
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800573 public InternalCacheEntry(FlowRuleBatchOperation operation) {
574 this.operation = operation;
alshabib902d41b2014-10-07 16:52:05 -0700575 }
576
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800577 /**
578 * Appends a failed rule to the set of failed items.
jcc3d4e14a2015-04-21 11:32:05 +0800579 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800580 * @param rule the failed rule
581 */
582 public void appendFailure(FlowRule rule) {
583 failures.add(rule);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800584 }
585
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800586 /**
587 * Fails the entire batch and returns the failed operation.
jcc3d4e14a2015-04-21 11:32:05 +0800588 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800589 * @return the failed operation
590 */
591 public CompletedBatchOperation failedCompletion() {
592 Set<FlowRule> fails = operation.getOperations().stream()
593 .map(op -> op.target()).collect(Collectors.toSet());
jcc3d4e14a2015-04-21 11:32:05 +0800594 return new CompletedBatchOperation(false,
595 Collections
596 .unmodifiableSet(fails),
597 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700598 }
599
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800600 /**
601 * Returns the completed operation and whether the batch suceeded.
jcc3d4e14a2015-04-21 11:32:05 +0800602 *
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800603 * @return the completed operation
604 */
605 public CompletedBatchOperation completed() {
jcc3d4e14a2015-04-21 11:32:05 +0800606 return new CompletedBatchOperation(
Thomas Vachuska75aaa672015-04-29 12:24:43 -0700607 failures.isEmpty(),
608 Collections
609 .unmodifiableSet(failures),
610 operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700611 }
alshabib902d41b2014-10-07 16:52:05 -0700612 }
alshabiba68eb962014-09-24 20:34:13 -0700613
alshabib1cc04f72014-09-16 16:09:58 -0700614}