blob: e2e743af7e59dda360e5ae89d5fa93a875549453 [file] [log] [blame]
Claudine Chiu70222ad2016-11-17 22:29:20 -05001/*
Thomas Vachuska52f2cd12018-11-08 21:20:04 -08002 * Copyright 2018-present Open Networking Foundation
Claudine Chiu70222ad2016-11-17 22:29:20 -05003 *
4 * 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
7 *
8 * 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.
15 */
16
17package org.onosproject.incubator.net.virtual.impl;
18
yoonseon6b972c32016-12-06 16:45:03 -080019import com.google.common.collect.ArrayListMultimap;
20import com.google.common.collect.Iterables;
21import com.google.common.collect.Lists;
22import com.google.common.collect.Maps;
23import com.google.common.collect.Multimap;
24import com.google.common.collect.Sets;
Claudine Chiu70222ad2016-11-17 22:29:20 -050025import org.onosproject.core.ApplicationId;
yoonseon6b972c32016-12-06 16:45:03 -080026import org.onosproject.core.CoreService;
27import org.onosproject.core.IdGenerator;
yoonseonc6a69272017-01-12 18:22:20 -080028import org.onosproject.incubator.net.virtual.NetworkId;
yoonseon6b972c32016-12-06 16:45:03 -080029import org.onosproject.incubator.net.virtual.VirtualNetworkFlowRuleStore;
yoonseonc6a69272017-01-12 18:22:20 -080030import org.onosproject.incubator.net.virtual.VirtualNetworkService;
31import org.onosproject.incubator.net.virtual.event.AbstractVirtualListenerManager;
yoonseon6b972c32016-12-06 16:45:03 -080032import org.onosproject.incubator.net.virtual.provider.AbstractVirtualProviderService;
33import org.onosproject.incubator.net.virtual.provider.VirtualFlowRuleProvider;
34import org.onosproject.incubator.net.virtual.provider.VirtualFlowRuleProviderService;
35import org.onosproject.incubator.net.virtual.provider.VirtualProviderRegistryService;
36import org.onosproject.net.Device;
Claudine Chiu70222ad2016-11-17 22:29:20 -050037import org.onosproject.net.DeviceId;
yoonseon6b972c32016-12-06 16:45:03 -080038import org.onosproject.net.device.DeviceService;
39import org.onosproject.net.flow.CompletedBatchOperation;
40import org.onosproject.net.flow.DefaultFlowEntry;
Claudine Chiu70222ad2016-11-17 22:29:20 -050041import org.onosproject.net.flow.FlowEntry;
42import org.onosproject.net.flow.FlowRule;
Ray Milkey7bf273c2017-09-27 16:15:15 -070043import org.onosproject.net.flow.oldbatch.FlowRuleBatchEntry;
44import org.onosproject.net.flow.oldbatch.FlowRuleBatchEvent;
45import org.onosproject.net.flow.oldbatch.FlowRuleBatchOperation;
46import org.onosproject.net.flow.oldbatch.FlowRuleBatchRequest;
Claudine Chiu70222ad2016-11-17 22:29:20 -050047import org.onosproject.net.flow.FlowRuleEvent;
48import org.onosproject.net.flow.FlowRuleListener;
yoonseon6b972c32016-12-06 16:45:03 -080049import org.onosproject.net.flow.FlowRuleOperation;
Claudine Chiu70222ad2016-11-17 22:29:20 -050050import org.onosproject.net.flow.FlowRuleOperations;
51import org.onosproject.net.flow.FlowRuleService;
yoonseonbd8a93d2016-12-07 15:51:21 -080052import org.onosproject.net.flow.FlowRuleStoreDelegate;
Claudine Chiu70222ad2016-11-17 22:29:20 -050053import org.onosproject.net.flow.TableStatisticsEntry;
yoonseonbd8a93d2016-12-07 15:51:21 -080054import org.onosproject.net.provider.ProviderId;
yoonseon6b972c32016-12-06 16:45:03 -080055import org.slf4j.Logger;
56import org.slf4j.LoggerFactory;
57
58import java.util.Collections;
59import java.util.HashSet;
60import java.util.List;
61import java.util.Map;
62import java.util.Set;
63import java.util.concurrent.ConcurrentHashMap;
64import java.util.concurrent.ExecutorService;
65import java.util.concurrent.Executors;
Claudine Chiu70222ad2016-11-17 22:29:20 -050066
67import static com.google.common.base.Preconditions.checkNotNull;
yoonseon6b972c32016-12-06 16:45:03 -080068import static org.onlab.util.Tools.groupedThreads;
yoonseonbd8a93d2016-12-07 15:51:21 -080069import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_ADD_REQUESTED;
70import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_REMOVE_REQUESTED;
Claudine Chiu70222ad2016-11-17 22:29:20 -050071
72/**
73 * Flow rule service implementation built on the virtual network service.
74 */
yoonseon6b972c32016-12-06 16:45:03 -080075public class VirtualNetworkFlowRuleManager
yoonseonc6a69272017-01-12 18:22:20 -080076 extends AbstractVirtualListenerManager<FlowRuleEvent, FlowRuleListener>
77 implements FlowRuleService {
Claudine Chiu70222ad2016-11-17 22:29:20 -050078
yoonseon6b972c32016-12-06 16:45:03 -080079 private static final String VIRTUAL_FLOW_OP_TOPIC = "virtual-flow-ops-ids";
80 private static final String THREAD_GROUP_NAME = "onos/virtual-flowservice";
81 private static final String DEVICE_INSTALLER_PATTERN = "device-installer-%d";
82 private static final String OPERATION_PATTERN = "operations-%d";
83 public static final String FLOW_RULE_NULL = "FlowRule cannot be null";
84
85 private final Logger log = LoggerFactory.getLogger(getClass());
86
yoonseon6b972c32016-12-06 16:45:03 -080087 private final VirtualNetworkFlowRuleStore store;
88 private final DeviceService deviceService;
89
90 protected ExecutorService deviceInstallers =
91 Executors.newFixedThreadPool(32,
92 groupedThreads(THREAD_GROUP_NAME,
93 DEVICE_INSTALLER_PATTERN, log));
94 protected ExecutorService operationsService =
95 Executors.newFixedThreadPool(32,
96 groupedThreads(THREAD_GROUP_NAME,
97 OPERATION_PATTERN, log));
98 private IdGenerator idGenerator;
99
100 private final Map<Long, FlowOperationsProcessor> pendingFlowOperations = new ConcurrentHashMap<>();
101
102 private VirtualProviderRegistryService providerRegistryService = null;
103 private InternalFlowRuleProviderService innerProviderService = null;
104
yoonseonbd8a93d2016-12-07 15:51:21 -0800105 private final FlowRuleStoreDelegate storeDelegate;
106
Claudine Chiu70222ad2016-11-17 22:29:20 -0500107 /**
108 * Creates a new VirtualNetworkFlowRuleService object.
109 *
110 * @param virtualNetworkManager virtual network manager service
yoonseonc6a69272017-01-12 18:22:20 -0800111 * @param networkId a virtual network identifier
Claudine Chiu70222ad2016-11-17 22:29:20 -0500112 */
yoonseonc6a69272017-01-12 18:22:20 -0800113 public VirtualNetworkFlowRuleManager(VirtualNetworkService virtualNetworkManager,
114 NetworkId networkId) {
Yoonseon Hanb14461b2017-03-07 14:08:01 +0900115 super(virtualNetworkManager, networkId, FlowRuleEvent.class);
yoonseon6b972c32016-12-06 16:45:03 -0800116
yoonseon6b972c32016-12-06 16:45:03 -0800117 store = serviceDirectory.get(VirtualNetworkFlowRuleStore.class);
yoonseonbd8a93d2016-12-07 15:51:21 -0800118
yoonseon6b972c32016-12-06 16:45:03 -0800119 idGenerator = serviceDirectory.get(CoreService.class)
yoonseonc6a69272017-01-12 18:22:20 -0800120 .getIdGenerator(VIRTUAL_FLOW_OP_TOPIC + networkId().toString());
yoonseon6b972c32016-12-06 16:45:03 -0800121 providerRegistryService =
122 serviceDirectory.get(VirtualProviderRegistryService.class);
123 innerProviderService = new InternalFlowRuleProviderService();
yoonseonc6a69272017-01-12 18:22:20 -0800124 providerRegistryService.registerProviderService(networkId(), innerProviderService);
yoonseon6b972c32016-12-06 16:45:03 -0800125
yoonseonbd8a93d2016-12-07 15:51:21 -0800126 this.deviceService = manager.get(networkId, DeviceService.class);
127 this.storeDelegate = new InternalStoreDelegate();
128 store.setDelegate(networkId, this.storeDelegate);
Claudine Chiu70222ad2016-11-17 22:29:20 -0500129 }
130
131 @Override
132 public int getFlowRuleCount() {
yoonseonc6a69272017-01-12 18:22:20 -0800133 return store.getFlowRuleCount(networkId());
Claudine Chiu70222ad2016-11-17 22:29:20 -0500134 }
135
136 @Override
David Glantz0a5779c2021-09-22 14:34:14 -0500137 public FlowEntry getFlowEntry(FlowRule flowRule) {
138 return store.getFlowEntry(networkId(), flowRule);
139 }
140
141 @Override
Claudine Chiu70222ad2016-11-17 22:29:20 -0500142 public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
yoonseonc6a69272017-01-12 18:22:20 -0800143 return store.getFlowEntries(networkId(), deviceId);
Claudine Chiu70222ad2016-11-17 22:29:20 -0500144 }
145
146 @Override
147 public void applyFlowRules(FlowRule... flowRules) {
yoonseon6b972c32016-12-06 16:45:03 -0800148 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
149 for (FlowRule flowRule : flowRules) {
150 builder.add(flowRule);
151 }
152 apply(builder.build());
Claudine Chiu70222ad2016-11-17 22:29:20 -0500153 }
154
155 @Override
156 public void purgeFlowRules(DeviceId deviceId) {
yoonseonc6a69272017-01-12 18:22:20 -0800157 store.purgeFlowRule(networkId(), deviceId);
Claudine Chiu70222ad2016-11-17 22:29:20 -0500158 }
159
160 @Override
161 public void removeFlowRules(FlowRule... flowRules) {
yoonseon6b972c32016-12-06 16:45:03 -0800162 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
163 for (FlowRule flowRule : flowRules) {
164 builder.remove(flowRule);
165 }
166 apply(builder.build());
Claudine Chiu70222ad2016-11-17 22:29:20 -0500167 }
168
169 @Override
yoonseon6b972c32016-12-06 16:45:03 -0800170 public void removeFlowRulesById(ApplicationId id) {
yoonseon6b972c32016-12-06 16:45:03 -0800171 Set<FlowRule> flowEntries = Sets.newHashSet();
172 for (Device d : deviceService.getDevices()) {
yoonseonc6a69272017-01-12 18:22:20 -0800173 for (FlowEntry flowEntry : store.getFlowEntries(networkId(), d.id())) {
yoonseon6b972c32016-12-06 16:45:03 -0800174 if (flowEntry.appId() == id.id()) {
175 flowEntries.add(flowEntry);
176 }
177 }
178 }
Ray Milkey4f7e3632019-02-19 15:35:20 -0800179 removeFlowRules(Iterables.toArray(flowEntries, FlowRule.class));
Claudine Chiu70222ad2016-11-17 22:29:20 -0500180 }
181
182 @Override
183 public Iterable<FlowEntry> getFlowEntriesById(ApplicationId id) {
yoonseonc6a69272017-01-12 18:22:20 -0800184 DeviceService deviceService = manager.get(networkId(), DeviceService.class);
yoonseon6b972c32016-12-06 16:45:03 -0800185
186 Set<FlowEntry> flowEntries = Sets.newHashSet();
187 for (Device d : deviceService.getDevices()) {
yoonseonc6a69272017-01-12 18:22:20 -0800188 for (FlowEntry flowEntry : store.getFlowEntries(networkId(), d.id())) {
yoonseon6b972c32016-12-06 16:45:03 -0800189 if (flowEntry.appId() == id.id()) {
190 flowEntries.add(flowEntry);
191 }
192 }
193 }
194 return flowEntries;
Claudine Chiu70222ad2016-11-17 22:29:20 -0500195 }
196
197 @Override
198 public Iterable<FlowRule> getFlowRulesByGroupId(ApplicationId appId, short groupId) {
yoonseonc6a69272017-01-12 18:22:20 -0800199 DeviceService deviceService = manager.get(networkId(), DeviceService.class);
yoonseon6b972c32016-12-06 16:45:03 -0800200
201 Set<FlowRule> matches = Sets.newHashSet();
202 long toLookUp = ((long) appId.id() << 16) | groupId;
203 for (Device d : deviceService.getDevices()) {
yoonseonc6a69272017-01-12 18:22:20 -0800204 for (FlowEntry flowEntry : store.getFlowEntries(networkId(), d.id())) {
yoonseon6b972c32016-12-06 16:45:03 -0800205 if ((flowEntry.id().value() >>> 32) == toLookUp) {
206 matches.add(flowEntry);
207 }
208 }
209 }
210 return matches;
Claudine Chiu70222ad2016-11-17 22:29:20 -0500211 }
212
213 @Override
214 public void apply(FlowRuleOperations ops) {
yoonseon6b972c32016-12-06 16:45:03 -0800215 operationsService.execute(new FlowOperationsProcessor(ops));
Claudine Chiu70222ad2016-11-17 22:29:20 -0500216 }
217
218 @Override
219 public Iterable<TableStatisticsEntry> getFlowTableStatistics(DeviceId deviceId) {
yoonseonc6a69272017-01-12 18:22:20 -0800220 return store.getTableStatistics(networkId(), deviceId);
yoonseon6b972c32016-12-06 16:45:03 -0800221 }
222
223 private static FlowRuleBatchEntry.FlowRuleOperation mapOperationType(FlowRuleOperation.Type input) {
224 switch (input) {
225 case ADD:
226 return FlowRuleBatchEntry.FlowRuleOperation.ADD;
227 case MODIFY:
228 return FlowRuleBatchEntry.FlowRuleOperation.MODIFY;
229 case REMOVE:
230 return FlowRuleBatchEntry.FlowRuleOperation.REMOVE;
231 default:
232 throw new UnsupportedOperationException("Unknown flow rule type " + input);
233 }
Claudine Chiu70222ad2016-11-17 22:29:20 -0500234 }
235
yoonseon6b972c32016-12-06 16:45:03 -0800236 private class FlowOperationsProcessor implements Runnable {
237 // Immutable
238 private final FlowRuleOperations fops;
239
240 // Mutable
241 private final List<Set<FlowRuleOperation>> stages;
242 private final Set<DeviceId> pendingDevices = new HashSet<>();
243 private boolean hasFailed = false;
244
245 FlowOperationsProcessor(FlowRuleOperations ops) {
246 this.stages = Lists.newArrayList(ops.stages());
247 this.fops = ops;
248 }
249
250 @Override
251 public synchronized void run() {
Jon Hallcbd1b392017-01-18 20:15:44 -0800252 if (!stages.isEmpty()) {
yoonseon6b972c32016-12-06 16:45:03 -0800253 process(stages.remove(0));
254 } else if (!hasFailed) {
255 fops.callback().onSuccess(fops);
256 }
257 }
258
259 private void process(Set<FlowRuleOperation> ops) {
260 Multimap<DeviceId, FlowRuleBatchEntry> perDeviceBatches = ArrayListMultimap.create();
261
262 for (FlowRuleOperation op : ops) {
263 perDeviceBatches.put(op.rule().deviceId(),
264 new FlowRuleBatchEntry(mapOperationType(op.type()), op.rule()));
265 }
266 pendingDevices.addAll(perDeviceBatches.keySet());
267
268 for (DeviceId deviceId : perDeviceBatches.keySet()) {
269 long id = idGenerator.getNewId();
270 final FlowRuleBatchOperation b = new FlowRuleBatchOperation(perDeviceBatches.get(deviceId),
271 deviceId, id);
272 pendingFlowOperations.put(id, this);
yoonseonc6a69272017-01-12 18:22:20 -0800273 deviceInstallers.execute(() -> store.storeBatch(networkId(), b));
yoonseon6b972c32016-12-06 16:45:03 -0800274 }
275 }
276
277 synchronized void satisfy(DeviceId devId) {
278 pendingDevices.remove(devId);
279 if (pendingDevices.isEmpty()) {
280 operationsService.execute(this);
281 }
282 }
283
284 synchronized void fail(DeviceId devId, Set<? extends FlowRule> failures) {
285 hasFailed = true;
286 pendingDevices.remove(devId);
287 if (pendingDevices.isEmpty()) {
288 operationsService.execute(this);
289 }
290
291 FlowRuleOperations.Builder failedOpsBuilder = FlowRuleOperations.builder();
292 failures.forEach(failedOpsBuilder::add);
293
294 fops.callback().onError(failedOpsBuilder.build());
295 }
296 }
297
yoonseonbd8a93d2016-12-07 15:51:21 -0800298 private final class InternalFlowRuleProviderService
yoonseon6b972c32016-12-06 16:45:03 -0800299 extends AbstractVirtualProviderService<VirtualFlowRuleProvider>
300 implements VirtualFlowRuleProviderService {
301
302 final Map<FlowEntry, Long> firstSeen = Maps.newConcurrentMap();
303 final Map<FlowEntry, Long> lastSeen = Maps.newConcurrentMap();
304
yoonseonbd8a93d2016-12-07 15:51:21 -0800305 private InternalFlowRuleProviderService() {
306 //TODO: find a proper virtual provider.
307 Set<ProviderId> providerIds =
308 providerRegistryService.getProvidersByService(this);
309 ProviderId providerId = providerIds.stream().findFirst().get();
310 VirtualFlowRuleProvider provider = (VirtualFlowRuleProvider)
311 providerRegistryService.getProvider(providerId);
312 setProvider(provider);
313 }
314
yoonseon6b972c32016-12-06 16:45:03 -0800315 @Override
316 public void flowRemoved(FlowEntry flowEntry) {
317 checkNotNull(flowEntry, FLOW_RULE_NULL);
318 checkValidity();
319
320 lastSeen.remove(flowEntry);
321 firstSeen.remove(flowEntry);
yoonseonc6a69272017-01-12 18:22:20 -0800322 FlowEntry stored = store.getFlowEntry(networkId(), flowEntry);
yoonseon6b972c32016-12-06 16:45:03 -0800323 if (stored == null) {
324 log.debug("Rule already evicted from store: {}", flowEntry);
325 return;
326 }
327 if (flowEntry.reason() == FlowEntry.FlowRemoveReason.HARD_TIMEOUT) {
328 ((DefaultFlowEntry) stored).setState(FlowEntry.FlowEntryState.REMOVED);
329 }
yoonseon6b972c32016-12-06 16:45:03 -0800330
331 //FIXME: obtains provider from devices providerId()
332 FlowRuleEvent event = null;
333 switch (stored.state()) {
334 case ADDED:
335 case PENDING_ADD:
yoonseonc6a69272017-01-12 18:22:20 -0800336 provider().applyFlowRule(networkId(), stored);
yoonseon6b972c32016-12-06 16:45:03 -0800337 break;
338 case PENDING_REMOVE:
339 case REMOVED:
yoonseonc6a69272017-01-12 18:22:20 -0800340 event = store.removeFlowRule(networkId(), stored);
yoonseon6b972c32016-12-06 16:45:03 -0800341 break;
342 default:
343 break;
344
345 }
346 if (event != null) {
347 log.debug("Flow {} removed", flowEntry);
348 post(event);
349 }
350 }
351
yoonseon6b972c32016-12-06 16:45:03 -0800352 private void flowMissing(FlowEntry flowRule) {
353 checkNotNull(flowRule, FLOW_RULE_NULL);
354 checkValidity();
355
356 FlowRuleEvent event = null;
357 switch (flowRule.state()) {
358 case PENDING_REMOVE:
359 case REMOVED:
yoonseonc6a69272017-01-12 18:22:20 -0800360 event = store.removeFlowRule(networkId(), flowRule);
yoonseon6b972c32016-12-06 16:45:03 -0800361 break;
362 case ADDED:
363 case PENDING_ADD:
yoonseonc6a69272017-01-12 18:22:20 -0800364 event = store.pendingFlowRule(networkId(), flowRule);
yoonseonbd8a93d2016-12-07 15:51:21 -0800365
yoonseon6b972c32016-12-06 16:45:03 -0800366 try {
yoonseonc6a69272017-01-12 18:22:20 -0800367 provider().applyFlowRule(networkId(), flowRule);
yoonseon6b972c32016-12-06 16:45:03 -0800368 } catch (UnsupportedOperationException e) {
369 log.warn(e.getMessage());
370 if (flowRule instanceof DefaultFlowEntry) {
371 //FIXME modification of "stored" flow entry outside of store
372 ((DefaultFlowEntry) flowRule).setState(FlowEntry.FlowEntryState.FAILED);
373 }
374 }
375 break;
376 default:
377 log.debug("Flow {} has not been installed.", flowRule);
378 }
379
380 if (event != null) {
381 log.debug("Flow {} removed", flowRule);
382 post(event);
383 }
384 }
385
386 private void extraneousFlow(FlowRule flowRule) {
387 checkNotNull(flowRule, FLOW_RULE_NULL);
388 checkValidity();
389
yoonseonc6a69272017-01-12 18:22:20 -0800390 provider().removeFlowRule(networkId(), flowRule);
yoonseon6b972c32016-12-06 16:45:03 -0800391 log.debug("Flow {} is on switch but not in store.", flowRule);
392 }
393
394 private void flowAdded(FlowEntry flowEntry) {
395 checkNotNull(flowEntry, FLOW_RULE_NULL);
396
yoonseonc6a69272017-01-12 18:22:20 -0800397 if (checkRuleLiveness(flowEntry, store.getFlowEntry(networkId(), flowEntry))) {
398 FlowRuleEvent event = store.addOrUpdateFlowRule(networkId(), flowEntry);
yoonseon6b972c32016-12-06 16:45:03 -0800399 if (event == null) {
400 log.debug("No flow store event generated.");
401 } else {
402 log.trace("Flow {} {}", flowEntry, event.type());
403 post(event);
404 }
405 } else {
406 log.debug("Removing flow rules....");
407 removeFlowRules(flowEntry);
408 }
409 }
410
411 private boolean checkRuleLiveness(FlowEntry swRule, FlowEntry storedRule) {
412 if (storedRule == null) {
413 return false;
414 }
415 if (storedRule.isPermanent()) {
416 return true;
417 }
418
Ray Milkey3717e602018-02-01 13:49:47 -0800419 final long timeout = storedRule.timeout() * 1000L;
yoonseon6b972c32016-12-06 16:45:03 -0800420 final long currentTime = System.currentTimeMillis();
421
422 // Checking flow with hardTimeout
423 if (storedRule.hardTimeout() != 0) {
424 if (!firstSeen.containsKey(storedRule)) {
425 // First time rule adding
426 firstSeen.put(storedRule, currentTime);
427 } else {
428 Long first = firstSeen.get(storedRule);
Ray Milkey3717e602018-02-01 13:49:47 -0800429 final long hardTimeout = storedRule.hardTimeout() * 1000L;
yoonseon6b972c32016-12-06 16:45:03 -0800430 if ((currentTime - first) > hardTimeout) {
431 return false;
432 }
433 }
434 }
435
436 if (storedRule.packets() != swRule.packets()) {
437 lastSeen.put(storedRule, currentTime);
438 return true;
439 }
440 if (!lastSeen.containsKey(storedRule)) {
441 // checking for the first time
442 lastSeen.put(storedRule, storedRule.lastSeen());
443 // Use following if lastSeen attr. was removed.
444 //lastSeen.put(storedRule, currentTime);
445 }
446 Long last = lastSeen.get(storedRule);
447
448 // concurrently removed? let the liveness check fail
449 return last != null && (currentTime - last) <= timeout;
450 }
451
452 @Override
453 public void pushFlowMetrics(DeviceId deviceId, Iterable<FlowEntry> flowEntries) {
454 pushFlowMetricsInternal(deviceId, flowEntries, true);
455 }
456
457 @Override
458 public void pushFlowMetricsWithoutFlowMissing(DeviceId deviceId, Iterable<FlowEntry> flowEntries) {
459 pushFlowMetricsInternal(deviceId, flowEntries, false);
460 }
461
462 private void pushFlowMetricsInternal(DeviceId deviceId, Iterable<FlowEntry> flowEntries,
463 boolean useMissingFlow) {
464 Map<FlowEntry, FlowEntry> storedRules = Maps.newHashMap();
yoonseonc6a69272017-01-12 18:22:20 -0800465 store.getFlowEntries(networkId(), deviceId).forEach(f -> storedRules.put(f, f));
yoonseon6b972c32016-12-06 16:45:03 -0800466
467 for (FlowEntry rule : flowEntries) {
468 try {
469 FlowEntry storedRule = storedRules.remove(rule);
470 if (storedRule != null) {
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900471 if (storedRule.id().equals(rule.id())) {
yoonseon6b972c32016-12-06 16:45:03 -0800472 // we both have the rule, let's update some info then.
473 flowAdded(rule);
474 } else {
475 // the two rules are not an exact match - remove the
476 // switch's rule and install our rule
477 extraneousFlow(rule);
478 flowMissing(storedRule);
479 }
480 }
481 } catch (Exception e) {
482 log.debug("Can't process added or extra rule {}", e.getMessage());
483 }
484 }
485
486 // DO NOT reinstall
487 if (useMissingFlow) {
488 for (FlowEntry rule : storedRules.keySet()) {
489 try {
490 // there are rules in the store that aren't on the switch
491 log.debug("Adding rule in store, but not on switch {}", rule);
492 flowMissing(rule);
493 } catch (Exception e) {
494 log.debug("Can't add missing flow rule:", e);
495 }
496 }
497 }
498 }
499
500 public void batchOperationCompleted(long batchId, CompletedBatchOperation operation) {
yoonseonc6a69272017-01-12 18:22:20 -0800501 store.batchOperationComplete(networkId(), FlowRuleBatchEvent.completed(
yoonseon6b972c32016-12-06 16:45:03 -0800502 new FlowRuleBatchRequest(batchId, Collections.emptySet()),
503 operation
504 ));
505 }
506
507 @Override
508 public void pushTableStatistics(DeviceId deviceId,
509 List<TableStatisticsEntry> tableStats) {
yoonseonc6a69272017-01-12 18:22:20 -0800510 store.updateTableStatistics(networkId(), deviceId, tableStats);
yoonseon6b972c32016-12-06 16:45:03 -0800511 }
Claudine Chiu70222ad2016-11-17 22:29:20 -0500512 }
yoonseonbd8a93d2016-12-07 15:51:21 -0800513
514 // Store delegate to re-post events emitted from the store.
515 private class InternalStoreDelegate implements FlowRuleStoreDelegate {
516
517 // TODO: Right now we only dispatch events at individual flowEntry level.
518 // It may be more efficient for also dispatch events as a batch.
519 @Override
520 public void notify(FlowRuleBatchEvent event) {
521 final FlowRuleBatchRequest request = event.subject();
522 switch (event.type()) {
523 case BATCH_OPERATION_REQUESTED:
524 // Request has been forwarded to MASTER Node, and was
525 request.ops().forEach(
526 op -> {
527 switch (op.operator()) {
528 case ADD:
529 post(new FlowRuleEvent(RULE_ADD_REQUESTED, op.target()));
530 break;
531 case REMOVE:
532 post(new FlowRuleEvent(RULE_REMOVE_REQUESTED, op.target()));
533 break;
534 case MODIFY:
535 //TODO: do something here when the time comes.
536 break;
537 default:
538 log.warn("Unknown flow operation operator: {}", op.operator());
539 }
540 }
541 );
542
543 DeviceId deviceId = event.deviceId();
544 FlowRuleBatchOperation batchOperation = request.asBatchOperation(deviceId);
545
546 VirtualFlowRuleProvider provider = innerProviderService.provider();
547 if (provider != null) {
548 provider.executeBatch(networkId, batchOperation);
549 }
550
551 break;
552
553 case BATCH_OPERATION_COMPLETED:
Yoonseon Hanc8089db2017-03-22 20:22:12 +0900554 FlowOperationsProcessor fops = pendingFlowOperations.remove(
555 event.subject().batchId());
556 if (fops == null) {
557 return;
558 }
559
560 if (event.result().isSuccess()) {
561 fops.satisfy(event.deviceId());
562 } else {
563 fops.fail(event.deviceId(), event.result().failedItems());
564 }
yoonseonbd8a93d2016-12-07 15:51:21 -0800565 break;
566
567 default:
568 break;
569 }
570 }
571 }
Claudine Chiu70222ad2016-11-17 22:29:20 -0500572}