diff --git a/apps/reactive-routing/pom.xml b/apps/reactive-routing/pom.xml index d7bde79ce0..a5059cab59 100644 --- a/apps/reactive-routing/pom.xml +++ b/apps/reactive-routing/pom.xml @@ -41,6 +41,11 @@ onos-app-routing ${project.version} + + + org.onosproject + onos-api + \ No newline at end of file diff --git a/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/SdnIpReactiveRouting.java b/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/SdnIpReactiveRouting.java index a74387fa4e..46f7fd9889 100644 --- a/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/SdnIpReactiveRouting.java +++ b/apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/SdnIpReactiveRouting.java @@ -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 = @@ -78,6 +86,9 @@ public class SdnIpReactiveRouting { TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); // TODO: to support IPv6 later selector.matchEthType(Ethernet.TYPE_IPV4); + packetService.requestPackets(selector.build(), + PacketPriority.REACTIVE, appId); + selector.matchEthType(Ethernet.TYPE_ARP); packetService.requestPackets(selector.build(), PacketPriority.REACTIVE, appId); @@ -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; } } } diff --git a/apps/routing-api/src/main/java/org/onosproject/routing/config/LocalIpPrefixEntry.java b/apps/routing-api/src/main/java/org/onosproject/routing/config/LocalIpPrefixEntry.java index a2f3c8c180..3f62db4f59 100644 --- a/apps/routing-api/src/main/java/org/onosproject/routing/config/LocalIpPrefixEntry.java +++ b/apps/routing-api/src/main/java/org/onosproject/routing/config/LocalIpPrefixEntry.java @@ -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; } /** @@ -78,6 +83,15 @@ public class LocalIpPrefixEntry { return type; } + /** + * 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. * diff --git a/apps/routing-api/src/main/java/org/onosproject/routing/config/RoutingConfigurationService.java b/apps/routing-api/src/main/java/org/onosproject/routing/config/RoutingConfigurationService.java index a30632866c..a500ff4c23 100644 --- a/apps/routing-api/src/main/java/org/onosproject/routing/config/RoutingConfigurationService.java +++ b/apps/routing-api/src/main/java/org/onosproject/routing/config/RoutingConfigurationService.java @@ -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; @@ -41,6 +42,21 @@ public interface RoutingConfigurationService { */ public Map 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. * diff --git a/apps/routing/src/main/java/org/onosproject/routing/config/impl/Configuration.java b/apps/routing/src/main/java/org/onosproject/routing/config/impl/Configuration.java index 76f1df0ba7..d5a9e29a39 100644 --- a/apps/routing/src/main/java/org/onosproject/routing/config/impl/Configuration.java +++ b/apps/routing/src/main/java/org/onosproject/routing/config/impl/Configuration.java @@ -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 bgpSpeakers; private List peers; + private MacAddress virtualGatewayMacAddress; // All IP prefixes from the configuration are local private List 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 */ @@ -86,6 +88,26 @@ public class Configuration { this.peers = peers; } + /** + * 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. diff --git a/apps/routing/src/main/java/org/onosproject/routing/config/impl/RoutingConfigurationImpl.java b/apps/routing/src/main/java/org/onosproject/routing/config/impl/RoutingConfigurationImpl.java index abb6a13290..c45d286b73 100644 --- a/apps/routing/src/main/java/org/onosproject/routing/config/impl/RoutingConfigurationImpl.java +++ b/apps/routing/src/main/java/org/onosproject/routing/config/impl/RoutingConfigurationImpl.java @@ -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 bgpSpeakers = new ConcurrentHashMap<>(); private Map bgpPeers = new ConcurrentHashMap<>(); + private Set gatewayIpAddresses = new HashSet<>(); private InvertedRadixTree 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; + } + } diff --git a/apps/sdnip/src/main/resources/config-examples/sdnip.json b/apps/sdnip/src/main/resources/config-examples/sdnip.json index 913687ee81..c51de68ae0 100644 --- a/apps/sdnip/src/main/resources/config-examples/sdnip.json +++ b/apps/sdnip/src/main/resources/config-examples/sdnip.json @@ -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" } diff --git a/core/api/src/main/java/org/onosproject/net/proxyarp/ProxyArpService.java b/core/api/src/main/java/org/onosproject/net/proxyarp/ProxyArpService.java index 920585eb2e..55c7247edd 100644 --- a/core/api/src/main/java/org/onosproject/net/proxyarp/ProxyArpService.java +++ b/core/api/src/main/java/org/onosproject/net/proxyarp/ProxyArpService.java @@ -61,5 +61,4 @@ public interface ProxyArpService { * @return true if handled, false otherwise. */ boolean handlePacket(PacketContext context); - } diff --git a/core/net/src/main/java/org/onosproject/net/proxyarp/impl/ProxyArpManager.java b/core/net/src/main/java/org/onosproject/net/proxyarp/impl/ProxyArpManager.java index 161518c957..27c97613bb 100644 --- a/core/net/src/main/java/org/onosproject/net/proxyarp/impl/ProxyArpManager.java +++ b/core/net/src/main/java/org/onosproject/net/proxyarp/impl/ProxyArpManager.java @@ -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. * @@ -481,41 +480,6 @@ public class ProxyArpManager implements ProxyArpService { return portNumbers; } - /** - * 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. * diff --git a/utils/misc/src/main/java/org/onlab/packet/ARP.java b/utils/misc/src/main/java/org/onlab/packet/ARP.java index 86fb289696..88e1d4ff49 100644 --- a/utils/misc/src/main/java/org/onlab/packet/ARP.java +++ b/utils/misc/src/main/java/org/onlab/packet/ARP.java @@ -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; + } }