blob: abda2bfd15cacd58900a82eab28bcfd9ff3414a2 [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;
Madan Jampani71c32ca2016-06-22 08:23:18 -070023
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080024import org.onosproject.core.ApplicationId;
25import org.onosproject.mastership.MastershipService;
Andrea Campanellae4273902016-02-08 13:43:30 -080026import org.onosproject.net.Device;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080027import org.onosproject.net.DeviceId;
Carmelo Casconef4363a02016-06-02 09:45:47 -070028import org.onosproject.net.device.DeviceEvent;
29import org.onosproject.net.device.DeviceListener;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080030import org.onosproject.net.device.DeviceService;
31import org.onosproject.net.flow.CompletedBatchOperation;
32import org.onosproject.net.flow.FlowRule;
Ray Milkey7bf273c2017-09-27 16:15:15 -070033import org.onosproject.net.flow.oldbatch.FlowRuleBatchEntry;
34import org.onosproject.net.flow.oldbatch.FlowRuleBatchOperation;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080035import org.onosproject.net.flow.FlowRuleProgrammable;
36import org.onosproject.net.flow.FlowRuleProvider;
37import org.onosproject.net.flow.FlowRuleProviderService;
38import org.onosproject.net.provider.AbstractProvider;
39import org.onosproject.net.provider.ProviderId;
40import org.slf4j.Logger;
41import org.slf4j.LoggerFactory;
42
43import java.util.Collection;
44import java.util.Set;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080045import java.util.concurrent.ScheduledExecutorService;
46import java.util.concurrent.ScheduledFuture;
47import java.util.concurrent.TimeUnit;
48
49import static com.google.common.collect.ImmutableSet.copyOf;
Yuta HIGUCHI1624df12016-07-21 16:54:33 -070050import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
51import static org.onlab.util.Tools.groupedThreads;
Carmelo Casconef4363a02016-06-02 09:45:47 -070052import static org.onosproject.net.device.DeviceEvent.Type.*;
Ray Milkey7bf273c2017-09-27 16:15:15 -070053import static org.onosproject.net.flow.oldbatch.FlowRuleBatchEntry.FlowRuleOperation.*;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080054
55/**
56 * Driver-based flow rule provider.
57 */
58class FlowRuleDriverProvider extends AbstractProvider implements FlowRuleProvider {
59
60 private final Logger log = LoggerFactory.getLogger(getClass());
61
62 // Perhaps to be extracted for better reuse as we deal with other.
63 public static final String SCHEME = "default";
64 public static final String PROVIDER_NAME = "org.onosproject.provider";
65
66 FlowRuleProviderService providerService;
67 private DeviceService deviceService;
68 private MastershipService mastershipService;
69
Carmelo Casconef4363a02016-06-02 09:45:47 -070070 private InternalDeviceListener deviceListener = new InternalDeviceListener();
Yuta HIGUCHI1624df12016-07-21 16:54:33 -070071 private ScheduledExecutorService executor
72 = newSingleThreadScheduledExecutor(groupedThreads("FlowRuleDriverProvider", "%d", log));
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080073 private ScheduledFuture<?> poller = null;
74
75 /**
76 * Creates a new fallback flow rule provider.
77 */
78 FlowRuleDriverProvider() {
79 super(new ProviderId(SCHEME, PROVIDER_NAME));
80 }
81
82 /**
83 * Initializes the provider with necessary supporting services.
84 *
85 * @param providerService flow rule provider service
86 * @param deviceService device service
87 * @param mastershipService mastership service
88 * @param pollFrequency flow entry poll frequency
89 */
90 void init(FlowRuleProviderService providerService,
91 DeviceService deviceService, MastershipService mastershipService,
92 int pollFrequency) {
93 this.providerService = providerService;
94 this.deviceService = deviceService;
95 this.mastershipService = mastershipService;
96
Carmelo Casconef4363a02016-06-02 09:45:47 -070097 deviceService.addListener(deviceListener);
98
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080099 if (poller != null && !poller.isCancelled()) {
100 poller.cancel(false);
101 }
102
103 poller = executor.scheduleAtFixedRate(this::pollFlowEntries, pollFrequency,
104 pollFrequency, TimeUnit.SECONDS);
105 }
106
Andrea Campanella5a3c09c2017-12-01 13:57:48 +0100107 void terminate() {
108 deviceService.removeListener(deviceListener);
109 deviceService = null;
110 providerService = null;
111 mastershipService = null;
112 poller.cancel(true);
113 executor.shutdown();
114 }
115
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800116 @Override
117 public void applyFlowRule(FlowRule... flowRules) {
118 rulesByDevice(flowRules).asMap().forEach(this::applyFlowRules);
119 }
120
121 @Override
122 public void removeFlowRule(FlowRule... flowRules) {
123 rulesByDevice(flowRules).asMap().forEach(this::removeFlowRules);
124 }
125
126 @Override
127 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
128 removeFlowRule(flowRules);
129 }
130
131 @Override
132 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
199 private void pollFlowEntries() {
Yuta HIGUCHId4e08c42017-03-09 13:24:25 -0800200 try {
201 deviceService.getAvailableDevices().forEach(device -> {
202 if (mastershipService.isLocalMaster(device.id()) && device.is(FlowRuleProgrammable.class)) {
203 pollDeviceFlowEntries(device);
204 }
205 });
206 } catch (Exception e) {
207 log.warn("Exception thrown while polling flows", e);
208 }
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800209 }
210
Yuta HIGUCHI076a7882017-04-21 16:38:51 -0700211 // potentially positive device event
212 private static final Set<DeviceEvent.Type> POSITIVE_DEVICE_EVENT =
213 Sets.immutableEnumSet(DEVICE_ADDED,
214 DEVICE_AVAILABILITY_CHANGED);
215
Carmelo Casconef4363a02016-06-02 09:45:47 -0700216 private class InternalDeviceListener implements DeviceListener {
217
218 @Override
219 public void event(DeviceEvent event) {
Madan Jampani71c32ca2016-06-22 08:23:18 -0700220 executor.execute(() -> handleEvent(event));
Carmelo Casconef4363a02016-06-02 09:45:47 -0700221 }
222
Yuta HIGUCHI076a7882017-04-21 16:38:51 -0700223 @Override
224 public boolean isRelevant(DeviceEvent event) {
225 Device device = event.subject();
226 return POSITIVE_DEVICE_EVENT.contains(event.type()) &&
227 device.is(FlowRuleProgrammable.class);
228 }
229
Madan Jampani71c32ca2016-06-22 08:23:18 -0700230 private void handleEvent(DeviceEvent event) {
Carmelo Casconef4363a02016-06-02 09:45:47 -0700231 Device device = event.subject();
Yuta HIGUCHI076a7882017-04-21 16:38:51 -0700232 boolean isRelevant = mastershipService.isLocalMaster(device.id()) &&
233 deviceService.isAvailable(device.id());
234
Madan Jampani71c32ca2016-06-22 08:23:18 -0700235 if (isRelevant) {
Yuta HIGUCHI076a7882017-04-21 16:38:51 -0700236 pollDeviceFlowEntries(device);
Madan Jampani71c32ca2016-06-22 08:23:18 -0700237 }
Carmelo Casconef4363a02016-06-02 09:45:47 -0700238 }
239 }
240
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800241}