blob: 262f2f62b183ab622b53d955739377ccb93393c5 [file] [log] [blame]
/*
* Copyright 2016-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.net.flow.impl;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import org.onosproject.core.ApplicationId;
import org.onosproject.mastership.MastershipService;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.flow.CompletedBatchOperation;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleBatchEntry;
import org.onosproject.net.flow.FlowRuleBatchOperation;
import org.onosproject.net.flow.FlowRuleProgrammable;
import org.onosproject.net.flow.FlowRuleProvider;
import org.onosproject.net.flow.FlowRuleProviderService;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import static com.google.common.collect.ImmutableSet.copyOf;
import static org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation.*;
/**
* Driver-based flow rule provider.
*/
class FlowRuleDriverProvider extends AbstractProvider implements FlowRuleProvider {
private final Logger log = LoggerFactory.getLogger(getClass());
// Perhaps to be extracted for better reuse as we deal with other.
public static final String SCHEME = "default";
public static final String PROVIDER_NAME = "org.onosproject.provider";
FlowRuleProviderService providerService;
private DeviceService deviceService;
private MastershipService mastershipService;
private ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture<?> poller = null;
/**
* Creates a new fallback flow rule provider.
*/
FlowRuleDriverProvider() {
super(new ProviderId(SCHEME, PROVIDER_NAME));
}
/**
* Initializes the provider with necessary supporting services.
*
* @param providerService flow rule provider service
* @param deviceService device service
* @param mastershipService mastership service
* @param pollFrequency flow entry poll frequency
*/
void init(FlowRuleProviderService providerService,
DeviceService deviceService, MastershipService mastershipService,
int pollFrequency) {
this.providerService = providerService;
this.deviceService = deviceService;
this.mastershipService = mastershipService;
if (poller != null && !poller.isCancelled()) {
poller.cancel(false);
}
poller = executor.scheduleAtFixedRate(this::pollFlowEntries, pollFrequency,
pollFrequency, TimeUnit.SECONDS);
}
@Override
public void applyFlowRule(FlowRule... flowRules) {
rulesByDevice(flowRules).asMap().forEach(this::applyFlowRules);
}
@Override
public void removeFlowRule(FlowRule... flowRules) {
rulesByDevice(flowRules).asMap().forEach(this::removeFlowRules);
}
@Override
public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
removeFlowRule(flowRules);
}
@Override
public void executeBatch(FlowRuleBatchOperation batch) {
ImmutableList.Builder<FlowRule> toAdd = ImmutableList.builder();
ImmutableList.Builder<FlowRule> toRemove = ImmutableList.builder();
for (FlowRuleBatchEntry fbe : batch.getOperations()) {
if (fbe.operator() == ADD || fbe.operator() == MODIFY) {
toAdd.add(fbe.target());
} else if (fbe.operator() == REMOVE) {
toRemove.add(fbe.target());
}
}
ImmutableList<FlowRule> rulesToAdd = toAdd.build();
ImmutableList<FlowRule> rulesToRemove = toRemove.build();
Collection<FlowRule> added = applyFlowRules(batch.deviceId(), rulesToAdd);
Collection<FlowRule> removed = removeFlowRules(batch.deviceId(), rulesToRemove);
Set<FlowRule> failedRules = Sets.union(Sets.difference(copyOf(rulesToAdd), copyOf(added)),
Sets.difference(copyOf(rulesToRemove), copyOf(removed)));
CompletedBatchOperation status =
new CompletedBatchOperation(failedRules.isEmpty(), failedRules, batch.deviceId());
providerService.batchOperationCompleted(batch.id(), status);
}
private Multimap<DeviceId, FlowRule> rulesByDevice(FlowRule[] flowRules) {
// Sort the flow rules by device id
Multimap<DeviceId, FlowRule> rulesByDevice = LinkedListMultimap.create();
for (FlowRule rule : flowRules) {
rulesByDevice.put(rule.deviceId(), rule);
}
return rulesByDevice;
}
private Collection<FlowRule> applyFlowRules(DeviceId deviceId, Collection<FlowRule> flowRules) {
FlowRuleProgrammable programmer = getFlowRuleProgrammable(deviceId);
return programmer != null ? programmer.applyFlowRules(flowRules) : ImmutableList.of();
}
private Collection<FlowRule> removeFlowRules(DeviceId deviceId, Collection<FlowRule> flowRules) {
FlowRuleProgrammable programmer = getFlowRuleProgrammable(deviceId);
return programmer != null ? programmer.removeFlowRules(flowRules) : ImmutableList.of();
}
private FlowRuleProgrammable getFlowRuleProgrammable(DeviceId deviceId) {
Device device = deviceService.getDevice(deviceId);
if (device.is(FlowRuleProgrammable.class)) {
return device.as(FlowRuleProgrammable.class);
} else {
log.debug("Device {} is not flow rule programmable", deviceId);
return null;
}
}
private void pollFlowEntries() {
deviceService.getAvailableDevices().forEach(device -> {
if (mastershipService.isLocalMaster(device.id()) && device.is(FlowRuleProgrammable.class)) {
providerService.pushFlowMetrics(device.id(),
device.as(FlowRuleProgrammable.class).getFlowEntries());
}
});
}
}