blob: 9e22997cc5d4d374b70573ae7fb7d5b2e5778aef [file] [log] [blame]
/*
* Copyright 2015 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.cordvtn;
import org.onlab.packet.Ip4Address;
import org.onlab.util.ItemNotFoundException;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Port;
import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
import org.onosproject.net.driver.DefaultDriverData;
import org.onosproject.net.driver.DefaultDriverHandler;
import org.onosproject.net.driver.Driver;
import org.onosproject.net.driver.DriverHandler;
import org.onosproject.net.driver.DriverService;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.instructions.ExtensionPropertyException;
import org.onosproject.net.flow.instructions.ExtensionTreatment;
import org.onosproject.net.flowobjective.DefaultForwardingObjective;
import org.onosproject.net.flowobjective.FlowObjectiveService;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.slf4j.Logger;
import java.util.List;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Populates rules for virtual tenant network.
*/
public final class CordVtnRuleInstaller {
protected final Logger log = getLogger(getClass());
private static final int DEFAULT_PRIORITY = 5000;
private final ApplicationId appId;
private final FlowObjectiveService flowObjectiveService;
private final DriverService driverService;
private final String tunnelType;
/**
* Creates a new rule installer.
*
* @param appId application id
* @param flowObjectiveService flow objective service
* @param driverService driver service
* @param tunnelType tunnel type
*/
public CordVtnRuleInstaller(ApplicationId appId,
FlowObjectiveService flowObjectiveService,
DriverService driverService,
String tunnelType) {
this.appId = appId;
this.flowObjectiveService = flowObjectiveService;
this.driverService = driverService;
this.tunnelType = checkNotNull(tunnelType);
}
/**
* Installs flow rules for tunnel in traffic.
*
* @param deviceId device id to install flow rules
* @param inPort in port
* @param dstInfos list of destination info
*/
public void installFlowRulesTunnelIn(DeviceId deviceId, Port inPort, List<DestinationInfo> dstInfos) {
dstInfos.stream().forEach(dstInfo -> {
ForwardingObjective.Builder fBuilder = vtnRulesSameNode(inPort, dstInfo);
if (fBuilder != null) {
flowObjectiveService.forward(deviceId, fBuilder.add());
}
});
}
/**
* Installs flow rules for local in traffic.
*
* @param deviceId device id to install flow rules
* @param inPort in port
* @param dstInfos list of destination info
*/
public void installFlowRulesLocalIn(DeviceId deviceId, Port inPort, List<DestinationInfo> dstInfos) {
dstInfos.stream().forEach(dstInfo -> {
ForwardingObjective.Builder fBuilder = isTunnelPort(dstInfo.output()) ?
vtnRulesRemoteNode(deviceId, inPort, dstInfo) : vtnRulesSameNode(inPort, dstInfo);
if (fBuilder != null) {
flowObjectiveService.forward(deviceId, fBuilder.add());
}
});
}
/**
* Uninstalls flow rules associated with a given port from a given device.
*
* @param deviceId device id
* @param inPort port associated with removed host
* @param dstInfos list of destination info
*/
public void uninstallFlowRules(DeviceId deviceId, Port inPort, List<DestinationInfo> dstInfos) {
dstInfos.stream().forEach(dstInfo -> {
ForwardingObjective.Builder fBuilder = isTunnelPort(dstInfo.output()) ?
vtnRulesRemoteNode(deviceId, inPort, dstInfo) : vtnRulesSameNode(inPort, dstInfo);
if (fBuilder != null) {
flowObjectiveService.forward(deviceId, fBuilder.remove());
}
});
}
/**
* Returns forwarding objective builder to provision basic virtual tenant network.
* This method cares for the traffics whose source and destination device is the same.
*
* @param inPort in port
* @param dstInfo destination information
* @return forwarding objective builder
*/
private ForwardingObjective.Builder vtnRulesSameNode(Port inPort, DestinationInfo dstInfo) {
checkArgument(inPort.element().id().equals(dstInfo.output().element().id()));
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sBuilder.matchInPort(inPort.number())
.matchEthDst(dstInfo.mac());
if (isTunnelPort(inPort)) {
sBuilder.matchTunnelId(dstInfo.tunnelId());
}
tBuilder.setOutput(dstInfo.output().number());
return DefaultForwardingObjective.builder()
.withSelector(sBuilder.build())
.withTreatment(tBuilder.build())
.withPriority(DEFAULT_PRIORITY)
.withFlag(ForwardingObjective.Flag.VERSATILE)
.fromApp(appId)
.makePermanent();
}
/**
* Returns forwarding objective builder to provision basic virtual tenant network.
* This method cares for the traffics whose source and destination is not the same.
*
* @param deviceId device id to install flow rules
* @param inPort in port
* @param dstInfo destination information
* @return forwarding objective, or null if it fails to build it
*/
private ForwardingObjective.Builder vtnRulesRemoteNode(DeviceId deviceId, Port inPort, DestinationInfo dstInfo) {
checkArgument(isTunnelPort(dstInfo.output()));
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
ExtensionTreatment extTreatment =
getTunnelDstInstruction(deviceId, dstInfo.remoteIp().getIp4Address());
if (extTreatment == null) {
return null;
}
sBuilder.matchInPort(inPort.number())
.matchEthDst(dstInfo.mac());
tBuilder.extension(extTreatment, deviceId)
.setTunnelId(dstInfo.tunnelId())
.setOutput(dstInfo.output().number());
return DefaultForwardingObjective.builder()
.withSelector(sBuilder.build())
.withTreatment(tBuilder.build())
.withPriority(DEFAULT_PRIORITY)
.withFlag(ForwardingObjective.Flag.VERSATILE)
.fromApp(appId)
.makePermanent();
}
/**
* Checks if a given port is tunnel interface or not.
* It assumes the tunnel interface contains tunnelType string in its name.
*
* @param port port
* @return true if the port is tunnel interface, false otherwise.
*/
private boolean isTunnelPort(Port port) {
return port.annotations().value("portName").contains(tunnelType);
}
/**
* Returns extension instruction to set tunnel destination.
*
* @param deviceId device id
* @param remoteIp tunnel destination address
* @return extension treatment or null if it fails to get instruction
*/
private ExtensionTreatment getTunnelDstInstruction(DeviceId deviceId, Ip4Address remoteIp) {
try {
Driver driver = driverService.getDriver(deviceId);
DriverHandler handler = new DefaultDriverHandler(new DefaultDriverData(driver, deviceId));
ExtensionTreatmentResolver resolver = handler.behaviour(ExtensionTreatmentResolver.class);
ExtensionTreatment treatment = resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
treatment.setPropertyValue("tunnelDst", remoteIp);
return treatment;
} catch (ItemNotFoundException | UnsupportedOperationException | ExtensionPropertyException e) {
log.error("Failed to get extension instruction to set tunnel dst {}", deviceId);
return null;
}
}
}