blob: c058ab6762a8c6afea9fcd4d4afee892c8d310da [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
107 @Override
108 public void applyFlowRule(FlowRule... flowRules) {
109 rulesByDevice(flowRules).asMap().forEach(this::applyFlowRules);
110 }
111
112 @Override
113 public void removeFlowRule(FlowRule... flowRules) {
114 rulesByDevice(flowRules).asMap().forEach(this::removeFlowRules);
115 }
116
117 @Override
118 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
119 removeFlowRule(flowRules);
120 }
121
122 @Override
123 public void executeBatch(FlowRuleBatchOperation batch) {
124 ImmutableList.Builder<FlowRule> toAdd = ImmutableList.builder();
125 ImmutableList.Builder<FlowRule> toRemove = ImmutableList.builder();
126 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
127 if (fbe.operator() == ADD || fbe.operator() == MODIFY) {
128 toAdd.add(fbe.target());
129 } else if (fbe.operator() == REMOVE) {
130 toRemove.add(fbe.target());
131 }
132 }
133
134 ImmutableList<FlowRule> rulesToAdd = toAdd.build();
135 ImmutableList<FlowRule> rulesToRemove = toRemove.build();
136
Yuta HIGUCHI660aedf2017-05-01 20:23:25 -0700137 Collection<FlowRule> added = ImmutableList.of();
138 if (!rulesToAdd.isEmpty()) {
139 added = applyFlowRules(batch.deviceId(), rulesToAdd);
140 }
141 Collection<FlowRule> removed = ImmutableList.of();
142 if (!rulesToRemove.isEmpty()) {
143 removed = removeFlowRules(batch.deviceId(), rulesToRemove);
144 }
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800145
146 Set<FlowRule> failedRules = Sets.union(Sets.difference(copyOf(rulesToAdd), copyOf(added)),
147 Sets.difference(copyOf(rulesToRemove), copyOf(removed)));
148 CompletedBatchOperation status =
149 new CompletedBatchOperation(failedRules.isEmpty(), failedRules, batch.deviceId());
150 providerService.batchOperationCompleted(batch.id(), status);
151 }
152
153 private Multimap<DeviceId, FlowRule> rulesByDevice(FlowRule[] flowRules) {
154 // Sort the flow rules by device id
155 Multimap<DeviceId, FlowRule> rulesByDevice = LinkedListMultimap.create();
156 for (FlowRule rule : flowRules) {
157 rulesByDevice.put(rule.deviceId(), rule);
158 }
159 return rulesByDevice;
160 }
161
162 private Collection<FlowRule> applyFlowRules(DeviceId deviceId, Collection<FlowRule> flowRules) {
163 FlowRuleProgrammable programmer = getFlowRuleProgrammable(deviceId);
164 return programmer != null ? programmer.applyFlowRules(flowRules) : ImmutableList.of();
165 }
166
167 private Collection<FlowRule> removeFlowRules(DeviceId deviceId, Collection<FlowRule> flowRules) {
168 FlowRuleProgrammable programmer = getFlowRuleProgrammable(deviceId);
169 return programmer != null ? programmer.removeFlowRules(flowRules) : ImmutableList.of();
170 }
171
172 private FlowRuleProgrammable getFlowRuleProgrammable(DeviceId deviceId) {
Andrea Campanellae4273902016-02-08 13:43:30 -0800173 Device device = deviceService.getDevice(deviceId);
174 if (device.is(FlowRuleProgrammable.class)) {
175 return device.as(FlowRuleProgrammable.class);
176 } else {
Andrea Campanellafe1d4732016-02-08 16:45:27 -0800177 log.debug("Device {} is not flow rule programmable", deviceId);
Andrea Campanellae4273902016-02-08 13:43:30 -0800178 return null;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800179 }
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800180 }
181
Carmelo Casconef4363a02016-06-02 09:45:47 -0700182 private void pollDeviceFlowEntries(Device device) {
Yuta HIGUCHId4e08c42017-03-09 13:24:25 -0800183 try {
184 providerService.pushFlowMetrics(device.id(), device.as(FlowRuleProgrammable.class).getFlowEntries());
185 } catch (Exception e) {
186 log.warn("Exception thrown while polling {}", device.id(), e);
187 }
Carmelo Casconef4363a02016-06-02 09:45:47 -0700188 }
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800189
190 private void pollFlowEntries() {
Yuta HIGUCHId4e08c42017-03-09 13:24:25 -0800191 try {
192 deviceService.getAvailableDevices().forEach(device -> {
193 if (mastershipService.isLocalMaster(device.id()) && device.is(FlowRuleProgrammable.class)) {
194 pollDeviceFlowEntries(device);
195 }
196 });
197 } catch (Exception e) {
198 log.warn("Exception thrown while polling flows", e);
199 }
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800200 }
201
Yuta HIGUCHI076a7882017-04-21 16:38:51 -0700202 // potentially positive device event
203 private static final Set<DeviceEvent.Type> POSITIVE_DEVICE_EVENT =
204 Sets.immutableEnumSet(DEVICE_ADDED,
205 DEVICE_AVAILABILITY_CHANGED);
206
Carmelo Casconef4363a02016-06-02 09:45:47 -0700207 private class InternalDeviceListener implements DeviceListener {
208
209 @Override
210 public void event(DeviceEvent event) {
Madan Jampani71c32ca2016-06-22 08:23:18 -0700211 executor.execute(() -> handleEvent(event));
Carmelo Casconef4363a02016-06-02 09:45:47 -0700212 }
213
Yuta HIGUCHI076a7882017-04-21 16:38:51 -0700214 @Override
215 public boolean isRelevant(DeviceEvent event) {
216 Device device = event.subject();
217 return POSITIVE_DEVICE_EVENT.contains(event.type()) &&
218 device.is(FlowRuleProgrammable.class);
219 }
220
Madan Jampani71c32ca2016-06-22 08:23:18 -0700221 private void handleEvent(DeviceEvent event) {
Carmelo Casconef4363a02016-06-02 09:45:47 -0700222 Device device = event.subject();
Yuta HIGUCHI076a7882017-04-21 16:38:51 -0700223 boolean isRelevant = mastershipService.isLocalMaster(device.id()) &&
224 deviceService.isAvailable(device.id());
225
Madan Jampani71c32ca2016-06-22 08:23:18 -0700226 if (isRelevant) {
Yuta HIGUCHI076a7882017-04-21 16:38:51 -0700227 pollDeviceFlowEntries(device);
Madan Jampani71c32ca2016-06-22 08:23:18 -0700228 }
Carmelo Casconef4363a02016-06-02 09:45:47 -0700229 }
230 }
231
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800232}