blob: 1b18452a86f54004a22ff015a3558ebb9a9a4fde [file] [log] [blame]
Thomas Vachuskac4ee7372016-02-02 16:10:09 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Thomas Vachuskac4ee7372016-02-02 16:10:09 -08003 *
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.net.flow.impl;
18
19import com.google.common.collect.ImmutableList;
20import com.google.common.collect.LinkedListMultimap;
21import com.google.common.collect.Multimap;
22import com.google.common.collect.Sets;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080023import org.onosproject.mastership.MastershipService;
Andrea Campanellae4273902016-02-08 13:43:30 -080024import org.onosproject.net.Device;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080025import org.onosproject.net.DeviceId;
hjtsao1e8a1bd2018-10-22 11:02:00 -070026import org.onosproject.net.behaviour.TableStatisticsDiscovery;
Carmelo Casconef4363a02016-06-02 09:45:47 -070027import org.onosproject.net.device.DeviceEvent;
28import org.onosproject.net.device.DeviceListener;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080029import org.onosproject.net.device.DeviceService;
30import org.onosproject.net.flow.CompletedBatchOperation;
31import org.onosproject.net.flow.FlowRule;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080032import org.onosproject.net.flow.FlowRuleProgrammable;
33import org.onosproject.net.flow.FlowRuleProvider;
34import org.onosproject.net.flow.FlowRuleProviderService;
hjtsao1e8a1bd2018-10-22 11:02:00 -070035import org.onosproject.net.flow.TableStatisticsEntry;
Ray Milkey17801b42019-02-22 14:18:00 -080036import org.onosproject.net.flow.oldbatch.FlowRuleBatchEntry;
37import org.onosproject.net.flow.oldbatch.FlowRuleBatchOperation;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080038import org.onosproject.net.provider.AbstractProvider;
39import org.onosproject.net.provider.ProviderId;
40import org.slf4j.Logger;
41import org.slf4j.LoggerFactory;
42
43import java.util.Collection;
Ray Milkey17801b42019-02-22 14:18:00 -080044import java.util.List;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080045import java.util.Set;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080046import java.util.concurrent.ScheduledExecutorService;
47import java.util.concurrent.ScheduledFuture;
48import java.util.concurrent.TimeUnit;
49
50import static com.google.common.collect.ImmutableSet.copyOf;
Ray Milkey17801b42019-02-22 14:18:00 -080051import static com.google.common.collect.Lists.newArrayList;
Yuta HIGUCHI1624df12016-07-21 16:54:33 -070052import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
53import static org.onlab.util.Tools.groupedThreads;
Ray Milkey17801b42019-02-22 14:18:00 -080054import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
55import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED;
56import static org.onosproject.net.flow.oldbatch.FlowRuleBatchEntry.FlowRuleOperation.ADD;
57import static org.onosproject.net.flow.oldbatch.FlowRuleBatchEntry.FlowRuleOperation.MODIFY;
58import static org.onosproject.net.flow.oldbatch.FlowRuleBatchEntry.FlowRuleOperation.REMOVE;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080059
60/**
61 * Driver-based flow rule provider.
62 */
63class FlowRuleDriverProvider extends AbstractProvider implements FlowRuleProvider {
64
65 private final Logger log = LoggerFactory.getLogger(getClass());
66
67 // Perhaps to be extracted for better reuse as we deal with other.
68 public static final String SCHEME = "default";
69 public static final String PROVIDER_NAME = "org.onosproject.provider";
70
71 FlowRuleProviderService providerService;
72 private DeviceService deviceService;
73 private MastershipService mastershipService;
74
Carmelo Casconef4363a02016-06-02 09:45:47 -070075 private InternalDeviceListener deviceListener = new InternalDeviceListener();
Yuta HIGUCHI1624df12016-07-21 16:54:33 -070076 private ScheduledExecutorService executor
77 = newSingleThreadScheduledExecutor(groupedThreads("FlowRuleDriverProvider", "%d", log));
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080078 private ScheduledFuture<?> poller = null;
79
80 /**
81 * Creates a new fallback flow rule provider.
82 */
83 FlowRuleDriverProvider() {
84 super(new ProviderId(SCHEME, PROVIDER_NAME));
85 }
86
87 /**
88 * Initializes the provider with necessary supporting services.
89 *
90 * @param providerService flow rule provider service
91 * @param deviceService device service
92 * @param mastershipService mastership service
93 * @param pollFrequency flow entry poll frequency
94 */
95 void init(FlowRuleProviderService providerService,
96 DeviceService deviceService, MastershipService mastershipService,
97 int pollFrequency) {
98 this.providerService = providerService;
99 this.deviceService = deviceService;
100 this.mastershipService = mastershipService;
101
Carmelo Casconef4363a02016-06-02 09:45:47 -0700102 deviceService.addListener(deviceListener);
103
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800104 if (poller != null && !poller.isCancelled()) {
105 poller.cancel(false);
106 }
107
108 poller = executor.scheduleAtFixedRate(this::pollFlowEntries, pollFrequency,
109 pollFrequency, TimeUnit.SECONDS);
110 }
111
Andrea Campanella5a3c09c2017-12-01 13:57:48 +0100112 void terminate() {
113 deviceService.removeListener(deviceListener);
114 deviceService = null;
115 providerService = null;
116 mastershipService = null;
117 poller.cancel(true);
118 executor.shutdown();
119 }
120
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800121 @Override
122 public void applyFlowRule(FlowRule... flowRules) {
123 rulesByDevice(flowRules).asMap().forEach(this::applyFlowRules);
124 }
125
126 @Override
127 public void removeFlowRule(FlowRule... flowRules) {
128 rulesByDevice(flowRules).asMap().forEach(this::removeFlowRules);
129 }
130
131 @Override
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800132 public void executeBatch(FlowRuleBatchOperation batch) {
133 ImmutableList.Builder<FlowRule> toAdd = ImmutableList.builder();
134 ImmutableList.Builder<FlowRule> toRemove = ImmutableList.builder();
135 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
136 if (fbe.operator() == ADD || fbe.operator() == MODIFY) {
137 toAdd.add(fbe.target());
138 } else if (fbe.operator() == REMOVE) {
139 toRemove.add(fbe.target());
140 }
141 }
142
143 ImmutableList<FlowRule> rulesToAdd = toAdd.build();
144 ImmutableList<FlowRule> rulesToRemove = toRemove.build();
145
Yuta HIGUCHI660aedf2017-05-01 20:23:25 -0700146 Collection<FlowRule> added = ImmutableList.of();
147 if (!rulesToAdd.isEmpty()) {
148 added = applyFlowRules(batch.deviceId(), rulesToAdd);
149 }
150 Collection<FlowRule> removed = ImmutableList.of();
151 if (!rulesToRemove.isEmpty()) {
152 removed = removeFlowRules(batch.deviceId(), rulesToRemove);
153 }
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800154
155 Set<FlowRule> failedRules = Sets.union(Sets.difference(copyOf(rulesToAdd), copyOf(added)),
156 Sets.difference(copyOf(rulesToRemove), copyOf(removed)));
157 CompletedBatchOperation status =
158 new CompletedBatchOperation(failedRules.isEmpty(), failedRules, batch.deviceId());
159 providerService.batchOperationCompleted(batch.id(), status);
160 }
161
162 private Multimap<DeviceId, FlowRule> rulesByDevice(FlowRule[] flowRules) {
163 // Sort the flow rules by device id
164 Multimap<DeviceId, FlowRule> rulesByDevice = LinkedListMultimap.create();
165 for (FlowRule rule : flowRules) {
166 rulesByDevice.put(rule.deviceId(), rule);
167 }
168 return rulesByDevice;
169 }
170
171 private Collection<FlowRule> applyFlowRules(DeviceId deviceId, Collection<FlowRule> flowRules) {
172 FlowRuleProgrammable programmer = getFlowRuleProgrammable(deviceId);
173 return programmer != null ? programmer.applyFlowRules(flowRules) : ImmutableList.of();
174 }
175
176 private Collection<FlowRule> removeFlowRules(DeviceId deviceId, Collection<FlowRule> flowRules) {
177 FlowRuleProgrammable programmer = getFlowRuleProgrammable(deviceId);
178 return programmer != null ? programmer.removeFlowRules(flowRules) : ImmutableList.of();
179 }
180
181 private FlowRuleProgrammable getFlowRuleProgrammable(DeviceId deviceId) {
Andrea Campanellae4273902016-02-08 13:43:30 -0800182 Device device = deviceService.getDevice(deviceId);
183 if (device.is(FlowRuleProgrammable.class)) {
184 return device.as(FlowRuleProgrammable.class);
185 } else {
Andrea Campanellafe1d4732016-02-08 16:45:27 -0800186 log.debug("Device {} is not flow rule programmable", deviceId);
Andrea Campanellae4273902016-02-08 13:43:30 -0800187 return null;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800188 }
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800189 }
190
Carmelo Casconef4363a02016-06-02 09:45:47 -0700191 private void pollDeviceFlowEntries(Device device) {
Yuta HIGUCHId4e08c42017-03-09 13:24:25 -0800192 try {
193 providerService.pushFlowMetrics(device.id(), device.as(FlowRuleProgrammable.class).getFlowEntries());
194 } catch (Exception e) {
195 log.warn("Exception thrown while polling {}", device.id(), e);
196 }
Carmelo Casconef4363a02016-06-02 09:45:47 -0700197 }
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800198
hjtsao1e8a1bd2018-10-22 11:02:00 -0700199 private void pollTableStatistics(Device device) {
200 try {
201 List<TableStatisticsEntry> tableStatsList = newArrayList(device.as(TableStatisticsDiscovery.class)
202 .getTableStatistics());
203 providerService.pushTableStatistics(device.id(), tableStatsList);
204 } catch (Exception e) {
205 log.warn("Exception thrown while polling table statistics for {}", device.id(), e);
206 }
207 }
208
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800209 private void pollFlowEntries() {
Yuta HIGUCHId4e08c42017-03-09 13:24:25 -0800210 try {
211 deviceService.getAvailableDevices().forEach(device -> {
212 if (mastershipService.isLocalMaster(device.id()) && device.is(FlowRuleProgrammable.class)) {
213 pollDeviceFlowEntries(device);
214 }
hjtsao1e8a1bd2018-10-22 11:02:00 -0700215 if (mastershipService.isLocalMaster(device.id()) && device.is(TableStatisticsDiscovery.class)) {
216 pollTableStatistics(device);
217 }
Yuta HIGUCHId4e08c42017-03-09 13:24:25 -0800218 });
219 } catch (Exception e) {
220 log.warn("Exception thrown while polling flows", e);
221 }
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800222 }
223
Yuta HIGUCHI076a7882017-04-21 16:38:51 -0700224 // potentially positive device event
225 private static final Set<DeviceEvent.Type> POSITIVE_DEVICE_EVENT =
226 Sets.immutableEnumSet(DEVICE_ADDED,
227 DEVICE_AVAILABILITY_CHANGED);
228
Carmelo Casconef4363a02016-06-02 09:45:47 -0700229 private class InternalDeviceListener implements DeviceListener {
230
231 @Override
232 public void event(DeviceEvent event) {
Madan Jampani71c32ca2016-06-22 08:23:18 -0700233 executor.execute(() -> handleEvent(event));
Carmelo Casconef4363a02016-06-02 09:45:47 -0700234 }
235
Yuta HIGUCHI076a7882017-04-21 16:38:51 -0700236 @Override
237 public boolean isRelevant(DeviceEvent event) {
238 Device device = event.subject();
239 return POSITIVE_DEVICE_EVENT.contains(event.type()) &&
240 device.is(FlowRuleProgrammable.class);
241 }
242
Madan Jampani71c32ca2016-06-22 08:23:18 -0700243 private void handleEvent(DeviceEvent event) {
Carmelo Casconef4363a02016-06-02 09:45:47 -0700244 Device device = event.subject();
Yuta HIGUCHI076a7882017-04-21 16:38:51 -0700245 boolean isRelevant = mastershipService.isLocalMaster(device.id()) &&
246 deviceService.isAvailable(device.id());
247
Madan Jampani71c32ca2016-06-22 08:23:18 -0700248 if (isRelevant) {
Yuta HIGUCHI076a7882017-04-21 16:38:51 -0700249 pollDeviceFlowEntries(device);
Madan Jampani71c32ca2016-06-22 08:23:18 -0700250 }
Carmelo Casconef4363a02016-06-02 09:45:47 -0700251 }
252 }
253
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800254}