diff --git a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfiguration.java b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfiguration.java index 31eae8b9aa..6957db0bcb 100644 --- a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfiguration.java +++ b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfiguration.java @@ -23,6 +23,7 @@ import java.util.List; import org.onlab.packet.IpAddress; import org.onlab.packet.IpPrefix; +import org.onlab.packet.MacAddress; /** * Contains the configuration data for virtual BNG that has been read from a @@ -32,6 +33,7 @@ public final class VbngConfiguration { private final List localPublicIpPrefixes; private final IpAddress nextHopIpAddress; + private final MacAddress publicFacingMac; /** * Default constructor. @@ -39,6 +41,7 @@ public final class VbngConfiguration { private VbngConfiguration() { localPublicIpPrefixes = null; nextHopIpAddress = null; + publicFacingMac = null; } /** @@ -46,14 +49,19 @@ public final class VbngConfiguration { * * @param nextHopIpAddress the IP address of the next hop * @param prefixes the public IP prefix list for local SDN network + * @param publicFacingMac the MAC address configured for all local + * public IP addresses */ @JsonCreator public VbngConfiguration(@JsonProperty("localPublicIpPrefixes") List prefixes, @JsonProperty("nextHopIpAddress") - IpAddress nextHopIpAddress) { + IpAddress nextHopIpAddress, + @JsonProperty("publicFacingMac") + MacAddress publicFacingMac) { localPublicIpPrefixes = prefixes; this.nextHopIpAddress = nextHopIpAddress; + this.publicFacingMac = publicFacingMac; } /** @@ -73,4 +81,13 @@ public final class VbngConfiguration { public IpAddress getNextHopIpAddress() { return nextHopIpAddress; } + + /** + * Gets the MAC address configured for all the public IP addresses. + * + * @return the MAC address + */ + public MacAddress getPublicFacingMac() { + return publicFacingMac; + } } diff --git a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java index c65bf6b7aa..3a8dacebde 100644 --- a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java +++ b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java @@ -31,6 +31,7 @@ import org.apache.felix.scr.annotations.Deactivate; import org.apache.felix.scr.annotations.Service; import org.onlab.packet.IpAddress; import org.onlab.packet.IpPrefix; +import org.onlab.packet.MacAddress; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,6 +59,7 @@ public class VbngConfigurationManager implements VbngConfigurationService { new ConcurrentHashMap<>(); private IpAddress nextHopIpAddress; + private MacAddress macOfPublicIpAddresses; @Activate public void activate() { @@ -96,6 +98,7 @@ public class VbngConfigurationManager implements VbngConfigurationService { localPublicIpPrefixes.put(prefix, true); } nextHopIpAddress = config.getNextHopIpAddress(); + macOfPublicIpAddresses = config.getPublicFacingMac(); } catch (FileNotFoundException e) { log.warn("Configuration file not found: {}", configFileName); @@ -109,6 +112,11 @@ public class VbngConfigurationManager implements VbngConfigurationService { return nextHopIpAddress; } + @Override + public MacAddress getPublicFacingMac() { + return macOfPublicIpAddresses; + } + // TODO handle the case: the number of public IP addresses is not enough // for 1:1 mapping from public IP to private IP. @Override @@ -169,6 +177,11 @@ public class VbngConfigurationManager implements VbngConfigurationService { return ipAddressMap.get(privateIpAddress); } + @Override + public boolean isAssignedPublicIpAddress(IpAddress ipAddress) { + return ipAddressMap.containsValue(ipAddress); + } + /** * Generates a new IP address base on a given IP address plus a number to * increase. diff --git a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationService.java b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationService.java index 644c22972e..382f5224f1 100644 --- a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationService.java +++ b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationService.java @@ -16,6 +16,7 @@ package org.onosproject.virtualbng; import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; /** * Provides information about the virtual BNG configuration. @@ -29,6 +30,22 @@ public interface VbngConfigurationService { */ public IpAddress getNextHopIpAddress(); + /** + * Gets the MAC address configured for all the public IP addresses. + * + * @return the MAC address + */ + public MacAddress getPublicFacingMac(); + + /** + * Evaluates whether an IP address is an assigned public IP address. + * + * @param ipAddress the IP address to evaluate + * @return true if the input IP address is an assigned public IP address, + * otherwise false + */ + public boolean isAssignedPublicIpAddress(IpAddress ipAddress); + /** * Gets an available public IP address from local public IP prefixes. * diff --git a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VirtualPublicHosts.java b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VirtualPublicHosts.java new file mode 100644 index 0000000000..35a9d81e19 --- /dev/null +++ b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VirtualPublicHosts.java @@ -0,0 +1,151 @@ +/* + * 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.virtualbng; + +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.Ip4Address; +import org.onlab.packet.MacAddress; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.ConnectPoint; +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.packet.DefaultOutboundPacket; +import org.onosproject.net.packet.InboundPacket; +import org.onosproject.net.packet.PacketContext; +import org.onosproject.net.packet.PacketPriority; +import org.onosproject.net.packet.PacketProcessor; +import org.onosproject.net.packet.PacketService; +import org.slf4j.Logger; + +/** + * When the upstream gateway which is outside local SDN network wants to send + * packets to our local public IP addresses, it will send out ARP requests to + * get the MAC address of each public IP address. Actually, there are no hosts + * configured with those public IP addresses, so this class is to emulate the + * behavior of the non-existed hosts and return ARP replies. + *

+ * Since we will rewrite the destination MAC address in the switch before + * traffic packets go to the destination, so the MAC address can be any number. + * We manually configured a random MAC address for this purpose in the vBNG + * configuration file. + *

+ */ +@Component(immediate = true) +public class VirtualPublicHosts { + private final Logger log = getLogger(getClass()); + + private static final String APP_NAME = + "org.onosproject.virtualbng.VirtualPublicHosts"; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected PacketService packetService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected VbngConfigurationService vbngConfigService; + + private ApplicationId appId; + private ArpRequestProcessor processor = new ArpRequestProcessor(); + + @Activate + public void activate() { + appId = coreService.registerApplication(APP_NAME); + + packetService.addProcessor(processor, + PacketProcessor.ADVISOR_MAX + 6); + + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + // Only IPv4 is supported in current vBNG. + selector.matchEthType(Ethernet.TYPE_ARP); + packetService.requestPackets(selector.build(), + PacketPriority.REACTIVE, appId); + + log.info("vBNG virtual public hosts started"); + } + + @Deactivate + public void deactivate() { + packetService.removeProcessor(processor); + processor = null; + log.info("vBNG virtual public hosts Stopped"); + } + + /** + * This class filters out the ARP request packets, generates the ARP + * reply packets, and emits those packets. + */ + private class ArpRequestProcessor implements PacketProcessor { + @Override + public void process(PacketContext context) { + + InboundPacket pkt = context.inPacket(); + Ethernet ethPkt = pkt.parsed(); + + // Only handle the ARP packets + if (ethPkt == null || ethPkt.getEtherType() != Ethernet.TYPE_ARP) { + return; + } + ARP arpPacket = (ARP) ethPkt.getPayload(); + // Only handle ARP request packets + if (arpPacket.getOpCode() != ARP.OP_REQUEST) { + return; + } + + Ip4Address targetIpAddress = Ip4Address + .valueOf(arpPacket.getTargetProtocolAddress()); + + // Only handle an ARP request when the target IP address inside is + // an assigned public IP address + if (!vbngConfigService.isAssignedPublicIpAddress(targetIpAddress)) { + return; + } + + MacAddress virtualHostMac = + vbngConfigService.getPublicFacingMac(); + if (virtualHostMac == null) { + return; + } + + ConnectPoint srcConnectPoint = pkt.receivedFrom(); + Ethernet eth = ARP.buildArpReply(targetIpAddress, + virtualHostMac, + ethPkt); + + TrafficTreatment.Builder builder = + DefaultTrafficTreatment.builder(); + builder.setOutput(srcConnectPoint.port()); + packetService.emit(new DefaultOutboundPacket( + srcConnectPoint.deviceId(), + builder.build(), + ByteBuffer.wrap(eth.serialize()))); + } + } +}