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>
......
......@@ -15,6 +15,8 @@
*/
package org.onosproject.cordvtn;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
......@@ -23,6 +25,7 @@ import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.util.ItemNotFoundException;
import org.onlab.packet.IpAddress;
import org.onlab.util.KryoNamespace;
import org.onosproject.cluster.ClusterService;
import org.onosproject.core.ApplicationId;
......@@ -31,9 +34,11 @@ import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
import org.onosproject.net.HostId;
import org.onosproject.net.Port;
import org.onosproject.net.behaviour.BridgeConfig;
import org.onosproject.net.behaviour.BridgeName;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.behaviour.ControllerInfo;
import org.onosproject.net.behaviour.DefaultTunnelDescription;
import org.onosproject.net.behaviour.TunnelConfig;
......@@ -45,9 +50,13 @@ import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.driver.DriverHandler;
import org.onosproject.net.driver.DriverService;
import org.onosproject.net.flowobjective.FlowObjectiveService;
import org.onosproject.net.host.HostEvent;
import org.onosproject.net.host.HostListener;
import org.onosproject.net.host.HostService;
import org.onosproject.openstackswitching.OpenstackNetwork;
import org.onosproject.openstackswitching.OpenstackPort;
import org.onosproject.openstackswitching.OpenstackSwitchingService;
import org.onosproject.ovsdb.controller.OvsdbClientService;
import org.onosproject.ovsdb.controller.OvsdbController;
import org.onosproject.ovsdb.controller.OvsdbNodeId;
......@@ -62,8 +71,10 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onlab.util.Tools.groupedThreads;
......@@ -72,8 +83,8 @@ import static org.onosproject.net.behaviour.TunnelDescription.Type.VXLAN;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Provides initial setup or cleanup for provisioning virtual tenant networks
* on ovsdb, integration bridge and vm when they are added or deleted.
* Provisions virtual tenant networks with service chaining capability
* in OpenStack environment.
*/
@Component(immediate = true)
@Service
......@@ -86,7 +97,8 @@ public class CordVtn implements CordVtnService {
.register(KryoNamespaces.API)
.register(CordVtnNode.class)
.register(NodeState.class);
private static final String DEFAULT_BRIDGE_NAME = "br-int";
private static final String DEFAULT_BRIDGE = "br-int";
private static final String VPORT_PREFIX = "tap";
private static final String DEFAULT_TUNNEL = "vxlan";
private static final Map<String, String> DEFAULT_TUNNEL_OPTIONS = new HashMap<String, String>() {
{
......@@ -116,11 +128,17 @@ public class CordVtn implements CordVtnService {
protected DeviceAdminService adminService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowObjectiveService flowObjectiveService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected OvsdbController controller;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ClusterService clusterService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected OpenstackSwitchingService openstackService;
private final ExecutorService eventExecutor = Executors
.newFixedThreadPool(NUM_THREADS, groupedThreads("onos/cordvtn", "event-handler"));
......@@ -132,6 +150,8 @@ public class CordVtn implements CordVtnService {
private final VmHandler vmHandler = new VmHandler();
private ConsistentMap<CordVtnNode, NodeState> nodeStore;
private Map<HostId, String> hostNetworkMap = Maps.newHashMap();
private CordVtnRuleInstaller ruleInstaller;
private enum NodeState {
......@@ -185,6 +205,8 @@ public class CordVtn implements CordVtnService {
.withApplicationId(appId)
.build();
ruleInstaller = new CordVtnRuleInstaller(appId, flowObjectiveService,
driverService, DEFAULT_TUNNEL);
deviceService.addListener(deviceListener);
hostService.addListener(hostListener);
......@@ -314,11 +336,27 @@ public class CordVtn implements CordVtnService {
/**
* Performs tasks after node initialization.
* First disconnect unnecessary OVSDB connection and then installs flow rules
* for existing VMs if there are any.
*
* @param node cordvtn node
*/
private void postInit(CordVtnNode node) {
disconnect(node);
Set<OpenstackNetwork> vNets = Sets.newHashSet();
hostService.getConnectedHosts(node.intBrId())
.stream()
.forEach(host -> {
OpenstackNetwork vNet = getOpenstackNetworkByHost(host);
if (vNet != null) {
log.info("VM {} is detected", host.id());
hostNetworkMap.put(host.id(), vNet.id());
vNets.add(vNet);
}
});
vNets.stream().forEach(this::installFlowRules);
}
/**
......@@ -443,7 +481,7 @@ public class CordVtn implements CordVtnService {
}
List<ControllerInfo> controllers = new ArrayList<>();
Sets.newHashSet(clusterService.getNodes())
Sets.newHashSet(clusterService.getNodes()).stream()
.forEach(controller -> {
ControllerInfo ctrlInfo = new ControllerInfo(controller.ip(), OFPORT, "tcp");
controllers.add(ctrlInfo);
......@@ -453,7 +491,7 @@ public class CordVtn implements CordVtnService {
try {
DriverHandler handler = driverService.createHandler(node.ovsdbId());
BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class);
bridgeConfig.addBridge(BridgeName.bridgeName(DEFAULT_BRIDGE_NAME), dpid, controllers);
bridgeConfig.addBridge(BridgeName.bridgeName(DEFAULT_BRIDGE), dpid, controllers);
} catch (ItemNotFoundException e) {
log.warn("Failed to create integration bridge on {}", node.ovsdbId());
}
......@@ -474,13 +512,12 @@ public class CordVtn implements CordVtnService {
optionBuilder.set(key, DEFAULT_TUNNEL_OPTIONS.get(key));
}
TunnelDescription description =
new DefaultTunnelDescription(null, null, VXLAN,
TunnelName.tunnelName(DEFAULT_TUNNEL),
new DefaultTunnelDescription(null, null, VXLAN, TunnelName.tunnelName(DEFAULT_TUNNEL),
optionBuilder.build());
try {
DriverHandler handler = driverService.createHandler(node.ovsdbId());
TunnelConfig tunnelConfig = handler.behaviour(TunnelConfig.class);
tunnelConfig.createTunnelInterface(BridgeName.bridgeName(DEFAULT_BRIDGE_NAME), description);
tunnelConfig.createTunnelInterface(BridgeName.bridgeName(DEFAULT_BRIDGE), description);
} catch (ItemNotFoundException e) {
log.warn("Failed to create tunnel interface on {}", node.ovsdbId());
}
......@@ -516,6 +553,212 @@ public class CordVtn implements CordVtnService {
}
}
/**
* Returns tunnel port of the device.
*
* @param bridgeId device id
* @return port, null if no tunnel port exists on a given device
*/
private Port getTunnelPort(DeviceId bridgeId) {
try {
return deviceService.getPorts(bridgeId).stream()
.filter(p -> p.annotations().value("portName").contains(DEFAULT_TUNNEL)
&& p.isEnabled())
.findFirst().get();
} catch (NoSuchElementException e) {
return null;
}
}
/**
* Returns remote ip address for tunneling.
*
* @param bridgeId device id
* @return ip address, null if no such device exists
*/
private IpAddress getRemoteIp(DeviceId bridgeId) {
CordVtnNode node = getNodeByBridgeId(bridgeId);
if (node != null) {
// TODO get data plane IP for tunneling
return node.ovsdbIp();
} else {
return null;
}
}
/**
* Returns destination information of all ports associated with a given
* OpenStack network. Output of the destination information is set to local
* port or tunnel port according to a given device id.
*
* @param deviceId device id to install flow rules
* @param vNet OpenStack network
* @return list of flow information, empty list if no flow information exists
*/
private List<DestinationInfo> getSameNetworkPortsInfo(DeviceId deviceId, OpenstackNetwork vNet) {
List<DestinationInfo> dstInfos = Lists.newArrayList();
long tunnelId = Long.valueOf(vNet.segmentId());
for (OpenstackPort vPort : openstackService.ports(vNet.id())) {
ConnectPoint cp = getConnectPoint(vPort);
if (cp == null) {
log.debug("Couldn't find connection point for OpenStack port {}", vPort.id());
continue;
}
DestinationInfo.Builder dBuilder = cp.deviceId().equals(deviceId) ?
DestinationInfo.builder(deviceService.getPort(cp.deviceId(), cp.port())) :
DestinationInfo.builder(getTunnelPort(deviceId))
.setRemoteIp(getRemoteIp(cp.deviceId()));
dBuilder.setMac(vPort.macAddress())
.setTunnelId(tunnelId);
dstInfos.add(dBuilder.build());
}
return dstInfos;
}
/**
* Returns local ports associated with a given OpenStack network.
*
* @param bridgeId device id
* @param vNet OpenStack network
* @return port list, empty list if no port exists
*/
private List<Port> getLocalSameNetworkPorts(DeviceId bridgeId, OpenstackNetwork vNet) {
List<Port> ports = new ArrayList<>();
openstackService.ports(vNet.id()).stream().forEach(port -> {
ConnectPoint cp = getConnectPoint(port);
if (cp != null && cp.deviceId().equals(bridgeId)) {
ports.add(deviceService.getPort(cp.deviceId(), cp.port()));
}
});
return ports;
}
/**
* Returns OpenStack port associated with a given host.
*
* @param host host
* @return OpenStack port, or null if no port has been found
*/
private OpenstackPort getOpenstackPortByHost(Host host) {
Port port = deviceService.getPort(host.location().deviceId(),
host.location().port());
return openstackService.port(port);
}
/**
* Returns OpenStack network associated with a given host.
*
* @param host host
* @return OpenStack network, or null if no network has been found
*/
private OpenstackNetwork getOpenstackNetworkByHost(Host host) {
OpenstackPort vPort = getOpenstackPortByHost(host);
if (vPort != null) {
return openstackService.network(vPort.networkId());
} else {
return null;
}
}
/**
* Returns port name with OpenStack port information.
*
* @param vPort OpenStack port
* @return port name
*/
private String getPortName(OpenstackPort vPort) {
checkNotNull(vPort);
return VPORT_PREFIX + vPort.id().substring(0, 10);
}
/**
* Returns connect point of a given OpenStack port.
* It assumes there's only one physical port associated with an OpenStack port.
*
* @param vPort openstack port
* @return connect point, null if no such port exists
*/
private ConnectPoint getConnectPoint(OpenstackPort vPort) {
try {
Host host = hostService.getHostsByMac(vPort.macAddress())
.stream()
.findFirst()
.get();
return new ConnectPoint(host.location().deviceId(), host.location().port());
} catch (NoSuchElementException e) {
log.debug("Not a valid host with {}", vPort.macAddress());
return null;
}
}
/**
* Installs flow rules for a given OpenStack network.
*
* @param vNet OpenStack network
*/
private void installFlowRules(OpenstackNetwork vNet) {
checkNotNull(vNet, "Tenant network should not be null");
for (Device device : deviceService.getAvailableDevices(SWITCH)) {
List<DestinationInfo> dstInfos = getSameNetworkPortsInfo(device.id(), vNet);
for (Port inPort : getLocalSameNetworkPorts(device.id(), vNet)) {
List<DestinationInfo> localInInfos = dstInfos.stream()
.filter(info -> !info.output().equals(inPort))
.collect(Collectors.toList());
ruleInstaller.installFlowRulesLocalIn(device.id(), inPort, localInInfos);
}
Port tunPort = getTunnelPort(device.id());
List<DestinationInfo> tunnelInInfos = dstInfos.stream()
.filter(info -> !info.output().equals(tunPort))
.collect(Collectors.toList());
ruleInstaller.installFlowRulesTunnelIn(device.id(), tunPort, tunnelInInfos);
}
}
/**
* Uninstalls flow rules associated with a given host for a given OpenStack network.
*
* @param vNet OpenStack network
* @param host removed host
*/
private void uninstallFlowRules(OpenstackNetwork vNet, Host host) {
checkNotNull(vNet, "Tenant network should not be null");
Port removedPort = deviceService.getPort(host.location().deviceId(),
host.location().port());
for (Device device : deviceService.getAvailableDevices(SWITCH)) {
List<DestinationInfo> dstInfos = getSameNetworkPortsInfo(device.id(), vNet);
for (Port inPort : getLocalSameNetworkPorts(device.id(), vNet)) {
List<DestinationInfo> localInInfos = Lists.newArrayList(
DestinationInfo.builder(getTunnelPort(device.id()))
.setTunnelId(Long.valueOf(vNet.segmentId()))
.setMac(host.mac())
.setRemoteIp(getRemoteIp(host.location().deviceId()))
.build());
ruleInstaller.uninstallFlowRules(device.id(), inPort, localInInfos);
}
if (device.id().equals(host.location().deviceId())) {
Port tunPort = getTunnelPort(device.id());
List<DestinationInfo> tunnelInInfo = Lists.newArrayList(
DestinationInfo.builder(removedPort)
.setTunnelId(Long.valueOf(vNet.segmentId()))
.setMac(host.mac())
.build());
ruleInstaller.uninstallFlowRules(device.id(), tunPort, tunnelInInfo);
ruleInstaller.uninstallFlowRules(device.id(), removedPort, dstInfos);
}
}
}
private class InternalDeviceListener implements DeviceListener {
@Override
......@@ -644,12 +887,40 @@ public class CordVtn implements CordVtnService {
@Override
public void connected(Host host) {
CordVtnNode node = getNodeByBridgeId(host.location().deviceId());
if (node == null || !getNodeState(node).equals(NodeState.COMPLETE)) {
// do nothing for the host on unregistered or unprepared device
return;
}
OpenstackNetwork vNet = getOpenstackNetworkByHost(host);
if (vNet == null) {
return;
}
log.info("VM {} is detected", host.id());
hostNetworkMap.put(host.id(), vNet.id());
installFlowRules(vNet);
}
@Override
public void disconnected(Host host) {
CordVtnNode node = getNodeByBridgeId(host.location().deviceId());
if (node == null || !getNodeState(node).equals(NodeState.COMPLETE)) {
// do nothing for the host on unregistered or unprepared device
return;
}
OpenstackNetwork vNet = openstackService.network(hostNetworkMap.get(host.id()));
if (vNet == null) {
return;
}
log.info("VM {} is vanished", host.id());
uninstallFlowRules(vNet, host);
hostNetworkMap.remove(host.id());
}
}
}
......
/*
* 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;
}
}