Hyunsun Moon
Committed by Gerrit Code Review

CORD-305 Added basic VTN rules for VMs with openstackswitching

Change-Id: I3eebc3c396b6657457363c183ca8c260b6bb8db4
......@@ -33,6 +33,10 @@
<properties>
<onos.app.name>org.onosproject.cordvtn</onos.app.name>
<onos.app.requires>
org.onosproject.ovsdb,
org.onosproject.openstackswitching
</onos.app.requires>
</properties>
<dependencies>
......@@ -64,6 +68,11 @@
<artifactId>org.apache.karaf.shell.console</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-app-openstackswitching-api</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
......
/*
* 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;
}
}
}
/*
* Copyright 2014-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.IpAddress;
import org.onlab.packet.MacAddress;
import org.onosproject.net.Port;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Contains destination information.
*/
public final class DestinationInfo {
private final Port output;
private final List<IpAddress> ip;
private final MacAddress mac;
private final IpAddress remoteIp;
private final long tunnelId;
/**
* Creates a new destination information.
*
* @param output output port
* @param ip destination ip address
* @param mac destination mac address
* @param remoteIp tunnel remote ip address
* @param tunnelId segment id
*/
public DestinationInfo(Port output, List<IpAddress> ip, MacAddress mac,
IpAddress remoteIp, long tunnelId) {
this.output = checkNotNull(output);
this.ip = ip;
this.mac = mac;
this.remoteIp = remoteIp;
this.tunnelId = tunnelId;
}
/**
* Returns output port.
*
* @return port
*/
public Port output() {
return output;
}
/**
* Returns destination ip addresses.
*
* @return list of ip address
*/
public List<IpAddress> ip() {
return ip;
}
/**
* Returns destination mac address.
*
* @return mac address
*/
public MacAddress mac() {
return mac;
}
/**
* Returns tunnel remote ip address.
*
* @return ip address
*/
public IpAddress remoteIp() {
return remoteIp;
}
/**
* Returns tunnel id.
*
* @return tunnel id
*/
public long tunnelId() {
return tunnelId;
}
/**
* Returns a new destination info builder.
*
* @return destination info builder
*/
public static DestinationInfo.Builder builder(Port output) {
return new Builder(output);
}
/**
* DestinationInfo builder class.
*/
public static final class Builder {
private final Port output;
private List<IpAddress> ip;
private MacAddress mac;
private IpAddress remoteIp;
private long tunnelId;
/**
* Creates a new destination information builder.
*
* @param output output port
*/
public Builder(Port output) {
this.output = checkNotNull(output, "Output port cannot be null");
}
/**
* Sets the destination ip address.
*
* @param ip ip address
* @return destination info builder
*/
public Builder setIp(List<IpAddress> ip) {
this.ip = checkNotNull(ip, "IP cannot be null");
return this;
}
/**
* Sets the destination mac address.
*
* @param mac mac address
* @return destination info builder
*/
public Builder setMac(MacAddress mac) {
this.mac = checkNotNull(mac, "MAC address cannot be null");
return this;
}
/**
* Sets the tunnel remote ip address.
*
* @param remoteIp ip address
* @return destination info builder
*/
public Builder setRemoteIp(IpAddress remoteIp) {
this.remoteIp = checkNotNull(remoteIp, "Remote IP address cannot be null");
return this;
}
/**
* Sets the tunnel id.
*
* @param tunnelId tunnel id
* @return destination info builder
*/
public Builder setTunnelId(long tunnelId) {
this.tunnelId = checkNotNull(tunnelId, "Tunnel ID cannot be null");
return this;
}
/**
* Build a destination information.
*
* @return destination info object
*/
public DestinationInfo build() {
return new DestinationInfo(this);
}
}
private DestinationInfo(Builder builder) {
output = builder.output;
ip = builder.ip;
mac = builder.mac;
remoteIp = builder.remoteIp;
tunnelId = builder.tunnelId;
}
}