blob: d2cdf9d3659a495c3ebc024aa8d8b83602ff6f0b [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;
23import org.onosproject.core.ApplicationId;
24import org.onosproject.mastership.MastershipService;
Andrea Campanellae4273902016-02-08 13:43:30 -080025import org.onosproject.net.Device;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080026import org.onosproject.net.DeviceId;
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;
32import org.onosproject.net.flow.FlowRuleBatchEntry;
33import org.onosproject.net.flow.FlowRuleBatchOperation;
34import org.onosproject.net.flow.FlowRuleProgrammable;
35import org.onosproject.net.flow.FlowRuleProvider;
36import org.onosproject.net.flow.FlowRuleProviderService;
37import org.onosproject.net.provider.AbstractProvider;
38import org.onosproject.net.provider.ProviderId;
39import org.slf4j.Logger;
40import org.slf4j.LoggerFactory;
41
42import java.util.Collection;
43import java.util.Set;
44import java.util.concurrent.Executors;
45import java.util.concurrent.ScheduledExecutorService;
46import java.util.concurrent.ScheduledFuture;
47import java.util.concurrent.TimeUnit;
48
49import static com.google.common.collect.ImmutableSet.copyOf;
Carmelo Casconef4363a02016-06-02 09:45:47 -070050import static org.onosproject.net.device.DeviceEvent.Type.*;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080051import static org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation.*;
52
53/**
54 * Driver-based flow rule provider.
55 */
56class FlowRuleDriverProvider extends AbstractProvider implements FlowRuleProvider {
57
58 private final Logger log = LoggerFactory.getLogger(getClass());
59
60 // Perhaps to be extracted for better reuse as we deal with other.
61 public static final String SCHEME = "default";
62 public static final String PROVIDER_NAME = "org.onosproject.provider";
63
64 FlowRuleProviderService providerService;
65 private DeviceService deviceService;
66 private MastershipService mastershipService;
67
Carmelo Casconef4363a02016-06-02 09:45:47 -070068 private InternalDeviceListener deviceListener = new InternalDeviceListener();
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080069 private ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
70 private ScheduledFuture<?> poller = null;
71
72 /**
73 * Creates a new fallback flow rule provider.
74 */
75 FlowRuleDriverProvider() {
76 super(new ProviderId(SCHEME, PROVIDER_NAME));
77 }
78
79 /**
80 * Initializes the provider with necessary supporting services.
81 *
82 * @param providerService flow rule provider service
83 * @param deviceService device service
84 * @param mastershipService mastership service
85 * @param pollFrequency flow entry poll frequency
86 */
87 void init(FlowRuleProviderService providerService,
88 DeviceService deviceService, MastershipService mastershipService,
89 int pollFrequency) {
90 this.providerService = providerService;
91 this.deviceService = deviceService;
92 this.mastershipService = mastershipService;
93
Carmelo Casconef4363a02016-06-02 09:45:47 -070094 deviceService.addListener(deviceListener);
95
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080096 if (poller != null && !poller.isCancelled()) {
97 poller.cancel(false);
98 }
99
100 poller = executor.scheduleAtFixedRate(this::pollFlowEntries, pollFrequency,
101 pollFrequency, TimeUnit.SECONDS);
102 }
103
104 @Override
105 public void applyFlowRule(FlowRule... flowRules) {
106 rulesByDevice(flowRules).asMap().forEach(this::applyFlowRules);
107 }
108
109 @Override
110 public void removeFlowRule(FlowRule... flowRules) {
111 rulesByDevice(flowRules).asMap().forEach(this::removeFlowRules);
112 }
113
114 @Override
115 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
116 removeFlowRule(flowRules);
117 }
118
119 @Override
120 public void executeBatch(FlowRuleBatchOperation batch) {
121 ImmutableList.Builder<FlowRule> toAdd = ImmutableList.builder();
122 ImmutableList.Builder<FlowRule> toRemove = ImmutableList.builder();
123 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
124 if (fbe.operator() == ADD || fbe.operator() == MODIFY) {
125 toAdd.add(fbe.target());
126 } else if (fbe.operator() == REMOVE) {
127 toRemove.add(fbe.target());
128 }
129 }
130
131 ImmutableList<FlowRule> rulesToAdd = toAdd.build();
132 ImmutableList<FlowRule> rulesToRemove = toRemove.build();
133
134 Collection<FlowRule> added = applyFlowRules(batch.deviceId(), rulesToAdd);
135 Collection<FlowRule> removed = removeFlowRules(batch.deviceId(), rulesToRemove);
136
137 Set<FlowRule> failedRules = Sets.union(Sets.difference(copyOf(rulesToAdd), copyOf(added)),
138 Sets.difference(copyOf(rulesToRemove), copyOf(removed)));
139 CompletedBatchOperation status =
140 new CompletedBatchOperation(failedRules.isEmpty(), failedRules, batch.deviceId());
141 providerService.batchOperationCompleted(batch.id(), status);
142 }
143
144 private Multimap<DeviceId, FlowRule> rulesByDevice(FlowRule[] flowRules) {
145 // Sort the flow rules by device id
146 Multimap<DeviceId, FlowRule> rulesByDevice = LinkedListMultimap.create();
147 for (FlowRule rule : flowRules) {
148 rulesByDevice.put(rule.deviceId(), rule);
149 }
150 return rulesByDevice;
151 }
152
153 private Collection<FlowRule> applyFlowRules(DeviceId deviceId, Collection<FlowRule> flowRules) {
154 FlowRuleProgrammable programmer = getFlowRuleProgrammable(deviceId);
155 return programmer != null ? programmer.applyFlowRules(flowRules) : ImmutableList.of();
156 }
157
158 private Collection<FlowRule> removeFlowRules(DeviceId deviceId, Collection<FlowRule> flowRules) {
159 FlowRuleProgrammable programmer = getFlowRuleProgrammable(deviceId);
160 return programmer != null ? programmer.removeFlowRules(flowRules) : ImmutableList.of();
161 }
162
163 private FlowRuleProgrammable getFlowRuleProgrammable(DeviceId deviceId) {
Andrea Campanellae4273902016-02-08 13:43:30 -0800164 Device device = deviceService.getDevice(deviceId);
165 if (device.is(FlowRuleProgrammable.class)) {
166 return device.as(FlowRuleProgrammable.class);
167 } else {
Andrea Campanellafe1d4732016-02-08 16:45:27 -0800168 log.debug("Device {} is not flow rule programmable", deviceId);
Andrea Campanellae4273902016-02-08 13:43:30 -0800169 return null;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800170 }
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800171 }
172
Carmelo Casconef4363a02016-06-02 09:45:47 -0700173 private void pollDeviceFlowEntries(Device device) {
174 providerService.pushFlowMetrics(device.id(), device.as(FlowRuleProgrammable.class).getFlowEntries());
175 }
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800176
177 private void pollFlowEntries() {
178 deviceService.getAvailableDevices().forEach(device -> {
179 if (mastershipService.isLocalMaster(device.id()) && device.is(FlowRuleProgrammable.class)) {
Carmelo Casconef4363a02016-06-02 09:45:47 -0700180 pollDeviceFlowEntries(device);
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800181 }
182 });
183 }
184
Carmelo Casconef4363a02016-06-02 09:45:47 -0700185 private class InternalDeviceListener implements DeviceListener {
186
187 @Override
188 public void event(DeviceEvent event) {
189 executor.schedule(() -> pollDeviceFlowEntries(event.subject()), 0, TimeUnit.SECONDS);
190 }
191
192 @Override
193 public boolean isRelevant(DeviceEvent event) {
194 Device device = event.subject();
195 return mastershipService.isLocalMaster(device.id()) && device.is(FlowRuleProgrammable.class) &&
196 (event.type() == DEVICE_ADDED ||
197 event.type() == DEVICE_UPDATED ||
198 (event.type() == DEVICE_AVAILABILITY_CHANGED && deviceService.isAvailable(device.id())));
199 }
200 }
201
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800202}