blob: e617ae92a04b22e7f252cf5757fe928ad7ce191c [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;
45import java.util.concurrent.Executors;
46import java.util.concurrent.ScheduledExecutorService;
47import java.util.concurrent.ScheduledFuture;
48import java.util.concurrent.TimeUnit;
49
50import static com.google.common.collect.ImmutableSet.copyOf;
Carmelo Casconef4363a02016-06-02 09:45:47 -070051import static org.onosproject.net.device.DeviceEvent.Type.*;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080052import static org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation.*;
53
54/**
55 * Driver-based flow rule provider.
56 */
57class FlowRuleDriverProvider extends AbstractProvider implements FlowRuleProvider {
58
59 private final Logger log = LoggerFactory.getLogger(getClass());
60
61 // Perhaps to be extracted for better reuse as we deal with other.
62 public static final String SCHEME = "default";
63 public static final String PROVIDER_NAME = "org.onosproject.provider";
64
65 FlowRuleProviderService providerService;
66 private DeviceService deviceService;
67 private MastershipService mastershipService;
68
Carmelo Casconef4363a02016-06-02 09:45:47 -070069 private InternalDeviceListener deviceListener = new InternalDeviceListener();
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080070 private ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
71 private ScheduledFuture<?> poller = null;
72
73 /**
74 * Creates a new fallback flow rule provider.
75 */
76 FlowRuleDriverProvider() {
77 super(new ProviderId(SCHEME, PROVIDER_NAME));
78 }
79
80 /**
81 * Initializes the provider with necessary supporting services.
82 *
83 * @param providerService flow rule provider service
84 * @param deviceService device service
85 * @param mastershipService mastership service
86 * @param pollFrequency flow entry poll frequency
87 */
88 void init(FlowRuleProviderService providerService,
89 DeviceService deviceService, MastershipService mastershipService,
90 int pollFrequency) {
91 this.providerService = providerService;
92 this.deviceService = deviceService;
93 this.mastershipService = mastershipService;
94
Carmelo Casconef4363a02016-06-02 09:45:47 -070095 deviceService.addListener(deviceListener);
96
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080097 if (poller != null && !poller.isCancelled()) {
98 poller.cancel(false);
99 }
100
101 poller = executor.scheduleAtFixedRate(this::pollFlowEntries, pollFrequency,
102 pollFrequency, TimeUnit.SECONDS);
103 }
104
105 @Override
106 public void applyFlowRule(FlowRule... flowRules) {
107 rulesByDevice(flowRules).asMap().forEach(this::applyFlowRules);
108 }
109
110 @Override
111 public void removeFlowRule(FlowRule... flowRules) {
112 rulesByDevice(flowRules).asMap().forEach(this::removeFlowRules);
113 }
114
115 @Override
116 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
117 removeFlowRule(flowRules);
118 }
119
120 @Override
121 public void executeBatch(FlowRuleBatchOperation batch) {
122 ImmutableList.Builder<FlowRule> toAdd = ImmutableList.builder();
123 ImmutableList.Builder<FlowRule> toRemove = ImmutableList.builder();
124 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
125 if (fbe.operator() == ADD || fbe.operator() == MODIFY) {
126 toAdd.add(fbe.target());
127 } else if (fbe.operator() == REMOVE) {
128 toRemove.add(fbe.target());
129 }
130 }
131
132 ImmutableList<FlowRule> rulesToAdd = toAdd.build();
133 ImmutableList<FlowRule> rulesToRemove = toRemove.build();
134
135 Collection<FlowRule> added = applyFlowRules(batch.deviceId(), rulesToAdd);
136 Collection<FlowRule> removed = removeFlowRules(batch.deviceId(), rulesToRemove);
137
138 Set<FlowRule> failedRules = Sets.union(Sets.difference(copyOf(rulesToAdd), copyOf(added)),
139 Sets.difference(copyOf(rulesToRemove), copyOf(removed)));
140 CompletedBatchOperation status =
141 new CompletedBatchOperation(failedRules.isEmpty(), failedRules, batch.deviceId());
142 providerService.batchOperationCompleted(batch.id(), status);
143 }
144
145 private Multimap<DeviceId, FlowRule> rulesByDevice(FlowRule[] flowRules) {
146 // Sort the flow rules by device id
147 Multimap<DeviceId, FlowRule> rulesByDevice = LinkedListMultimap.create();
148 for (FlowRule rule : flowRules) {
149 rulesByDevice.put(rule.deviceId(), rule);
150 }
151 return rulesByDevice;
152 }
153
154 private Collection<FlowRule> applyFlowRules(DeviceId deviceId, Collection<FlowRule> flowRules) {
155 FlowRuleProgrammable programmer = getFlowRuleProgrammable(deviceId);
156 return programmer != null ? programmer.applyFlowRules(flowRules) : ImmutableList.of();
157 }
158
159 private Collection<FlowRule> removeFlowRules(DeviceId deviceId, Collection<FlowRule> flowRules) {
160 FlowRuleProgrammable programmer = getFlowRuleProgrammable(deviceId);
161 return programmer != null ? programmer.removeFlowRules(flowRules) : ImmutableList.of();
162 }
163
164 private FlowRuleProgrammable getFlowRuleProgrammable(DeviceId deviceId) {
Andrea Campanellae4273902016-02-08 13:43:30 -0800165 Device device = deviceService.getDevice(deviceId);
166 if (device.is(FlowRuleProgrammable.class)) {
167 return device.as(FlowRuleProgrammable.class);
168 } else {
Andrea Campanellafe1d4732016-02-08 16:45:27 -0800169 log.debug("Device {} is not flow rule programmable", deviceId);
Andrea Campanellae4273902016-02-08 13:43:30 -0800170 return null;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800171 }
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800172 }
173
Carmelo Casconef4363a02016-06-02 09:45:47 -0700174 private void pollDeviceFlowEntries(Device device) {
175 providerService.pushFlowMetrics(device.id(), device.as(FlowRuleProgrammable.class).getFlowEntries());
176 }
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800177
178 private void pollFlowEntries() {
179 deviceService.getAvailableDevices().forEach(device -> {
180 if (mastershipService.isLocalMaster(device.id()) && device.is(FlowRuleProgrammable.class)) {
Carmelo Casconef4363a02016-06-02 09:45:47 -0700181 pollDeviceFlowEntries(device);
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800182 }
183 });
184 }
185
Carmelo Casconef4363a02016-06-02 09:45:47 -0700186 private class InternalDeviceListener implements DeviceListener {
187
188 @Override
189 public void event(DeviceEvent event) {
Madan Jampani71c32ca2016-06-22 08:23:18 -0700190 executor.execute(() -> handleEvent(event));
Carmelo Casconef4363a02016-06-02 09:45:47 -0700191 }
192
Madan Jampani71c32ca2016-06-22 08:23:18 -0700193 private void handleEvent(DeviceEvent event) {
Carmelo Casconef4363a02016-06-02 09:45:47 -0700194 Device device = event.subject();
Madan Jampani71c32ca2016-06-22 08:23:18 -0700195 boolean isRelevant = mastershipService.isLocalMaster(device.id())
196 && device.is(FlowRuleProgrammable.class)
197 && (event.type() == DEVICE_ADDED ||
198 event.type() == DEVICE_UPDATED ||
199 (event.type() == DEVICE_AVAILABILITY_CHANGED && deviceService.isAvailable(device.id())));
200 if (isRelevant) {
201 pollDeviceFlowEntries(event.subject());
202 }
Carmelo Casconef4363a02016-06-02 09:45:47 -0700203 }
204 }
205
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800206}