Pingping Lin
Committed by Jonathan Hart

add a virtual gateway for reactive routing

  There is no physical gateway in SDN network.
  However a host needs a gateway when it tries to communicate with a remote host.
  So we designed a virtual gateway for SDN network.
  The virtual gateway can have multiple IP addresses.
  Each IP address is used as the default gateway address of an IP prefix.
  We only configure one MAC address to the virtual gateway.
  You can choose any MAC address from the BGP speakers as the virtual gateway MAC address.
  We configure this MAC address staticly in the sdnip.json configuration file.

Change-Id: I2a72bef797fc55d25bb5473e8fca624ad659e1d1
......@@ -41,6 +41,11 @@
<artifactId>onos-app-routing</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-api</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
......
......@@ -16,13 +16,17 @@
package org.onosproject.reactive.routing;
import static org.slf4j.LoggerFactory.getLogger;
import java.nio.ByteBuffer;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.ARP;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onosproject.core.ApplicationId;
......@@ -40,6 +44,7 @@ import org.onosproject.net.packet.PacketPriority;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
import org.onosproject.routing.RoutingService;
import org.onosproject.routing.config.RoutingConfigurationService;
import org.slf4j.Logger;
/**
......@@ -64,6 +69,9 @@ public class SdnIpReactiveRouting {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected RoutingService routingService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected RoutingConfigurationService config;
private ApplicationId appId;
private ReactiveRoutingProcessor processor =
......@@ -80,6 +88,9 @@ public class SdnIpReactiveRouting {
selector.matchEthType(Ethernet.TYPE_IPV4);
packetService.requestPackets(selector.build(),
PacketPriority.REACTIVE, appId);
selector.matchEthType(Ethernet.TYPE_ARP);
packetService.requestPackets(selector.build(),
PacketPriority.REACTIVE, appId);
log.info("SDN-IP Reactive Routing Started");
}
......@@ -100,31 +111,56 @@ public class SdnIpReactiveRouting {
if (ethPkt == null) {
return;
}
// In theory, we do not need to check whether it is Ethernet
// TYPE_IPV4. However, due to the current implementation of the
// packetService, we will receive all packets from all subscribers.
// Hence, we have to check the Ethernet type again here.
if (ethPkt.getEtherType() != Ethernet.TYPE_IPV4) {
return;
}
// Parse packet
IPv4 ipv4Packet = (IPv4) ethPkt.getPayload();
IpAddress dstIp =
IpAddress.valueOf(ipv4Packet.getDestinationAddress());
IpAddress srcIp =
IpAddress.valueOf(ipv4Packet.getSourceAddress());
ConnectPoint srcConnectPoint = pkt.receivedFrom();
MacAddress srcMac = ethPkt.getSourceMAC();
routingService.packetReactiveProcessor(dstIp, srcIp,
srcConnectPoint, srcMac);
// TODO emit packet first or packetReactiveProcessor first
ConnectPoint egressConnectPoint = null;
egressConnectPoint = routingService.getEgressConnectPoint(dstIp);
if (egressConnectPoint != null) {
forwardPacketToDst(context, egressConnectPoint);
switch (ethPkt.getEtherType()) {
case Ethernet.TYPE_ARP:
ARP arpPacket = (ARP) ethPkt.getPayload();
Ip4Address targetIpAddress = Ip4Address
.valueOf(arpPacket.getTargetProtocolAddress());
// Only when it is an ARP request packet and the target IP
// address is a virtual gateway IP address, then it will be
// processed.
if (arpPacket.getOpCode() == ARP.OP_REQUEST
&& config.isVirtualGatewayIpAddress(targetIpAddress)) {
MacAddress gatewayMacAddress =
config.getVirtualGatewayMacAddress();
if (gatewayMacAddress == null) {
break;
}
Ethernet eth = ARP.buildArpReply(targetIpAddress,
gatewayMacAddress,
ethPkt);
TrafficTreatment.Builder builder =
DefaultTrafficTreatment.builder();
builder.setOutput(srcConnectPoint.port());
packetService.emit(new DefaultOutboundPacket(
srcConnectPoint.deviceId(),
builder.build(),
ByteBuffer.wrap(eth.serialize())));
}
break;
case Ethernet.TYPE_IPV4:
// Parse packet
IPv4 ipv4Packet = (IPv4) ethPkt.getPayload();
IpAddress dstIp =
IpAddress.valueOf(ipv4Packet.getDestinationAddress());
IpAddress srcIp =
IpAddress.valueOf(ipv4Packet.getSourceAddress());
MacAddress srcMac = ethPkt.getSourceMAC();
routingService.packetReactiveProcessor(dstIp, srcIp,
srcConnectPoint, srcMac);
// TODO emit packet first or packetReactiveProcessor first
ConnectPoint egressConnectPoint = null;
egressConnectPoint = routingService.getEgressConnectPoint(dstIp);
if (egressConnectPoint != null) {
forwardPacketToDst(context, egressConnectPoint);
}
break;
default:
break;
}
}
}
......
......@@ -20,6 +20,7 @@ import com.google.common.base.MoreObjects;
import java.util.Objects;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
/**
......@@ -28,6 +29,7 @@ import org.onlab.packet.IpPrefix;
public class LocalIpPrefixEntry {
private final IpPrefix ipPrefix;
private final IpPrefixType type;
private final IpAddress gatewayIpAddress;
/**
* Specifies the type of local IP prefix.
......@@ -55,9 +57,12 @@ public class LocalIpPrefixEntry {
* @param type an IP prefix type as an IpPrefixType
*/
public LocalIpPrefixEntry(@JsonProperty("ipPrefix") String ipPrefix,
@JsonProperty("type") IpPrefixType type) {
@JsonProperty("type") IpPrefixType type,
@JsonProperty("gatewayIp") IpAddress
gatewayIpAddress) {
this.ipPrefix = IpPrefix.valueOf(ipPrefix);
this.type = type;
this.gatewayIpAddress = gatewayIpAddress;
}
/**
......@@ -79,6 +84,15 @@ public class LocalIpPrefixEntry {
}
/**
* Gets the gateway IP address of the IP prefix entry.
*
* @return the gateway IP address
*/
public IpAddress getGatewayIpAddress() {
return gatewayIpAddress;
}
/**
* Tests whether the IP version of this entry is IPv4.
*
* @return true if the IP version of this entry is IPv4, otherwise false.
......
......@@ -17,6 +17,7 @@ package org.onosproject.routing.config;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onosproject.net.ConnectPoint;
import java.util.Map;
......@@ -42,6 +43,21 @@ public interface RoutingConfigurationService {
public Map<IpAddress, BgpPeer> getBgpPeers();
/**
* Gets the MAC address configured for virtual gateway in SDN network.
*
* @return the MAC address of virtual gateway
*/
public MacAddress getVirtualGatewayMacAddress();
/**
* Evaluates whether an IP address is a virtual gateway IP address.
*
* @param ipAddress the IP address to evaluate
* @return true if the IP address is a virtual gateway address, otherwise false
*/
public boolean isVirtualGatewayIpAddress(IpAddress ipAddress);
/**
* Evaluates whether an IP address belongs to local SDN network.
*
* @param ipAddress the IP address to evaluate
......
......@@ -17,6 +17,7 @@ package org.onosproject.routing.config.impl;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.onlab.packet.MacAddress;
import org.onosproject.routing.config.BgpPeer;
import org.onosproject.routing.config.BgpSpeaker;
import org.onosproject.routing.config.LocalIpPrefixEntry;
......@@ -33,6 +34,7 @@ public class Configuration {
// the BGP routers outside our SDN network the BGP peers.
private List<BgpSpeaker> bgpSpeakers;
private List<BgpPeer> peers;
private MacAddress virtualGatewayMacAddress;
// All IP prefixes from the configuration are local
private List<LocalIpPrefixEntry> localIp4PrefixEntries =
......@@ -77,7 +79,7 @@ public class Configuration {
}
/**
* Sets a list of BGP peers we are configured to peer with.
* Sets a list of BGP peers we configured to peer with.
*
* @param peers the list of BGP peers
*/
......@@ -87,6 +89,26 @@ public class Configuration {
}
/**
* Gets the MAC address we configured for virtual gateway
* in SDN network.
*
* @return the MAC address of virtual gateway
*/
public MacAddress getVirtualGatewayMacAddress() {
return virtualGatewayMacAddress;
}
/**
* Sets the MAC address for virtual gateway in SDN network.
*
* @param virtualGatewayMacAddress the MAC address of virtual gateway
*/
@JsonProperty("virtualGatewayMacAddress")
public void setVirtualGatewayMacAddress(MacAddress virtualGatewayMacAddress) {
this.virtualGatewayMacAddress = virtualGatewayMacAddress;
}
/**
* Gets a list of local IPv4 prefix entries configured for local
* SDN network.
* <p>
......
......@@ -29,6 +29,7 @@ import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip6Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.host.HostService;
import org.onosproject.routing.config.BgpPeer;
......@@ -43,6 +44,7 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
......@@ -68,6 +70,7 @@ public class RoutingConfigurationImpl implements RoutingConfigurationService {
private Map<String, BgpSpeaker> bgpSpeakers = new ConcurrentHashMap<>();
private Map<IpAddress, BgpPeer> bgpPeers = new ConcurrentHashMap<>();
private Set<IpAddress> gatewayIpAddresses = new HashSet<>();
private InvertedRadixTree<LocalIpPrefixEntry>
localPrefixTable4 = new ConcurrentInvertedRadixTree<>(
......@@ -76,6 +79,7 @@ public class RoutingConfigurationImpl implements RoutingConfigurationService {
localPrefixTable6 = new ConcurrentInvertedRadixTree<>(
new DefaultByteArrayNodeFactory());
private MacAddress virtualGatewayMacAddress;
private HostToInterfaceAdaptor hostAdaptor;
@Activate
......@@ -109,12 +113,16 @@ public class RoutingConfigurationImpl implements RoutingConfigurationService {
for (LocalIpPrefixEntry entry : config.getLocalIp4PrefixEntries()) {
localPrefixTable4.put(createBinaryString(entry.ipPrefix()),
entry);
gatewayIpAddresses.add(entry.getGatewayIpAddress());
}
for (LocalIpPrefixEntry entry : config.getLocalIp6PrefixEntries()) {
localPrefixTable6.put(createBinaryString(entry.ipPrefix()),
entry);
gatewayIpAddresses.add(entry.getGatewayIpAddress());
}
virtualGatewayMacAddress = config.getVirtualGatewayMacAddress();
} catch (FileNotFoundException e) {
log.warn("Configuration file not found: {}", configFileName);
} catch (IOException e) {
......@@ -178,4 +186,14 @@ public class RoutingConfigurationImpl implements RoutingConfigurationService {
createBinaryString(ipPrefix)) != null);
}
@Override
public boolean isVirtualGatewayIpAddress(IpAddress ipAddress) {
return gatewayIpAddresses.contains(ipAddress);
}
@Override
public MacAddress getVirtualGatewayMacAddress() {
return virtualGatewayMacAddress;
}
}
......
......@@ -66,17 +66,21 @@
"ip4LocalPrefixes" : [
{
"ipPrefix" : "100.0.0.0/24",
"type" : "PUBLIC"
"type" : "PUBLIC",
"gatewayIp" : "100.0.0.1"
},
{
"ipPrefix" : "200.0.0.0/8",
"type" : "PUBLIC"
"type" : "PUBLIC",
"gatewayIp" : "200.0.0.3"
},
{
"ipPrefix" : "192.0.0.0/24",
"type" : "PRIVATE"
"type" : "PRIVATE",
"gatewayIp" : "192.0.0.254"
}
],
"ip6LocalPrefixes" : [
]
],
"virtualGatewayMacAddress" : "00:00:00:00:00:01"
}
......
......@@ -61,5 +61,4 @@ public interface ProxyArpService {
* @return true if handled, false otherwise.
*/
boolean handlePacket(PacketContext context);
}
......
......@@ -156,7 +156,7 @@ public class ProxyArpManager implements ProxyArpService {
for (InterfaceIpAddress ia : addresses.ipAddresses()) {
if (ia.ipAddress().equals(targetAddress)) {
Ethernet arpReply =
buildArpReply(targetAddress, addresses.mac(), eth);
ARP.buildArpReply(targetAddress, addresses.mac(), eth);
sendTo(arpReply, inPort);
}
}
......@@ -181,7 +181,7 @@ public class ProxyArpManager implements ProxyArpService {
if (src != null && dst != null) {
// We know the target host so we can respond
Ethernet arpReply = buildArpReply(targetAddress, dst.mac(), eth);
Ethernet arpReply = ARP.buildArpReply(targetAddress, dst.mac(), eth);
sendTo(arpReply, inPort);
return;
}
......@@ -296,7 +296,6 @@ public class ProxyArpManager implements ProxyArpService {
sendTo(ndpReply, inPort);
}
/**
* Outputs the given packet out the given port.
*
......@@ -482,41 +481,6 @@ public class ProxyArpManager implements ProxyArpService {
}
/**
* Builds an ARP reply based on a request.
*
* @param srcIp the IP address to use as the reply source
* @param srcMac the MAC address to use as the reply source
* @param request the ARP request we got
* @return an Ethernet frame containing the ARP reply
*/
private Ethernet buildArpReply(Ip4Address srcIp, MacAddress srcMac,
Ethernet request) {
Ethernet eth = new Ethernet();
eth.setDestinationMACAddress(request.getSourceMAC());
eth.setSourceMACAddress(srcMac);
eth.setEtherType(Ethernet.TYPE_ARP);
eth.setVlanID(request.getVlanID());
ARP arp = new ARP();
arp.setOpCode(ARP.OP_REPLY);
arp.setProtocolType(ARP.PROTO_TYPE_IP);
arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
arp.setSenderHardwareAddress(srcMac.toBytes());
arp.setTargetHardwareAddress(request.getSourceMACAddress());
arp.setTargetProtocolAddress(((ARP) request.getPayload())
.getSenderProtocolAddress());
arp.setSenderProtocolAddress(srcIp.toInt());
eth.setPayload(arp);
return eth;
}
/**
* Builds an Neighbor Discovery reply based on a request.
*
* @param srcIp the IP address to use as the reply source
......
......@@ -357,4 +357,39 @@ public class ARP extends BasePacket {
+ ", targetProtocolAddress="
+ Arrays.toString(this.targetProtocolAddress) + "]";
}
/**
* Builds an ARP reply based on a request.
*
* @param srcIp the IP address to use as the reply source
* @param srcMac the MAC address to use as the reply source
* @param request the ARP request we got
* @return an Ethernet frame containing the ARP reply
*/
public static Ethernet buildArpReply(Ip4Address srcIp, MacAddress srcMac,
Ethernet request) {
Ethernet eth = new Ethernet();
eth.setDestinationMACAddress(request.getSourceMAC());
eth.setSourceMACAddress(srcMac);
eth.setEtherType(Ethernet.TYPE_ARP);
eth.setVlanID(request.getVlanID());
ARP arp = new ARP();
arp.setOpCode(ARP.OP_REPLY);
arp.setProtocolType(ARP.PROTO_TYPE_IP);
arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
arp.setSenderHardwareAddress(srcMac.toBytes());
arp.setTargetHardwareAddress(request.getSourceMACAddress());
arp.setTargetProtocolAddress(((ARP) request.getPayload())
.getSenderProtocolAddress());
arp.setSenderProtocolAddress(srcIp.toInt());
eth.setPayload(arp);
return eth;
}
}
......