blob: a0ad43989f2c00bbde0b4bc09e73a79023f5d7da [file] [log] [blame]
Thomas Vachuskac4ee7372016-02-02 16:10:09 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
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;
33import org.onosproject.net.flow.FlowRuleBatchEntry;
34import org.onosproject.net.flow.FlowRuleBatchOperation;
35import 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.*;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080053import static org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation.*;
54
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
137 Collection<FlowRule> added = applyFlowRules(batch.deviceId(), rulesToAdd);
138 Collection<FlowRule> removed = removeFlowRules(batch.deviceId(), rulesToRemove);
139
140 Set<FlowRule> failedRules = Sets.union(Sets.difference(copyOf(rulesToAdd), copyOf(added)),
141 Sets.difference(copyOf(rulesToRemove), copyOf(removed)));
142 CompletedBatchOperation status =
143 new CompletedBatchOperation(failedRules.isEmpty(), failedRules, batch.deviceId());
144 providerService.batchOperationCompleted(batch.id(), status);
145 }
146
147 private Multimap<DeviceId, FlowRule> rulesByDevice(FlowRule[] flowRules) {
148 // Sort the flow rules by device id
149 Multimap<DeviceId, FlowRule> rulesByDevice = LinkedListMultimap.create();
150 for (FlowRule rule : flowRules) {
151 rulesByDevice.put(rule.deviceId(), rule);
152 }
153 return rulesByDevice;
154 }
155
156 private Collection<FlowRule> applyFlowRules(DeviceId deviceId, Collection<FlowRule> flowRules) {
157 FlowRuleProgrammable programmer = getFlowRuleProgrammable(deviceId);
158 return programmer != null ? programmer.applyFlowRules(flowRules) : ImmutableList.of();
159 }
160
161 private Collection<FlowRule> removeFlowRules(DeviceId deviceId, Collection<FlowRule> flowRules) {
162 FlowRuleProgrammable programmer = getFlowRuleProgrammable(deviceId);
163 return programmer != null ? programmer.removeFlowRules(flowRules) : ImmutableList.of();
164 }
165
166 private FlowRuleProgrammable getFlowRuleProgrammable(DeviceId deviceId) {
Andrea Campanellae4273902016-02-08 13:43:30 -0800167 Device device = deviceService.getDevice(deviceId);
168 if (device.is(FlowRuleProgrammable.class)) {
169 return device.as(FlowRuleProgrammable.class);
170 } else {
Andrea Campanellafe1d4732016-02-08 16:45:27 -0800171 log.debug("Device {} is not flow rule programmable", deviceId);
Andrea Campanellae4273902016-02-08 13:43:30 -0800172 return null;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800173 }
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800174 }
175
Carmelo Casconef4363a02016-06-02 09:45:47 -0700176 private void pollDeviceFlowEntries(Device device) {
177 providerService.pushFlowMetrics(device.id(), device.as(FlowRuleProgrammable.class).getFlowEntries());
178 }
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800179
180 private void pollFlowEntries() {
181 deviceService.getAvailableDevices().forEach(device -> {
182 if (mastershipService.isLocalMaster(device.id()) && device.is(FlowRuleProgrammable.class)) {
Carmelo Casconef4363a02016-06-02 09:45:47 -0700183 pollDeviceFlowEntries(device);
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800184 }
185 });
186 }
187
Carmelo Casconef4363a02016-06-02 09:45:47 -0700188 private class InternalDeviceListener implements DeviceListener {
189
190 @Override
191 public void event(DeviceEvent event) {
Madan Jampani71c32ca2016-06-22 08:23:18 -0700192 executor.execute(() -> handleEvent(event));
Carmelo Casconef4363a02016-06-02 09:45:47 -0700193 }
194
Madan Jampani71c32ca2016-06-22 08:23:18 -0700195 private void handleEvent(DeviceEvent event) {
Carmelo Casconef4363a02016-06-02 09:45:47 -0700196 Device device = event.subject();
Madan Jampani71c32ca2016-06-22 08:23:18 -0700197 boolean isRelevant = mastershipService.isLocalMaster(device.id())
198 && device.is(FlowRuleProgrammable.class)
199 && (event.type() == DEVICE_ADDED ||
200 event.type() == DEVICE_UPDATED ||
201 (event.type() == DEVICE_AVAILABILITY_CHANGED && deviceService.isAvailable(device.id())));
202 if (isRelevant) {
203 pollDeviceFlowEntries(event.subject());
204 }
Carmelo Casconef4363a02016-06-02 09:45:47 -0700205 }
206 }
207
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800208}