add an ARP reply emulator for public IP to vBNG
Change-Id: Id142ef278363d39330e1c1f061f33d23e6b5e790
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 31eae8b..6957db0 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 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 @@
private final List<IpPrefix> localPublicIpPrefixes;
private final IpAddress nextHopIpAddress;
+ private final MacAddress publicFacingMac;
/**
* Default constructor.
@@ -39,6 +41,7 @@
private VbngConfiguration() {
localPublicIpPrefixes = null;
nextHopIpAddress = null;
+ publicFacingMac = null;
}
/**
@@ -46,14 +49,19 @@
*
* @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<IpPrefix> prefixes,
@JsonProperty("nextHopIpAddress")
- IpAddress nextHopIpAddress) {
+ IpAddress nextHopIpAddress,
+ @JsonProperty("publicFacingMac")
+ MacAddress publicFacingMac) {
localPublicIpPrefixes = prefixes;
this.nextHopIpAddress = nextHopIpAddress;
+ this.publicFacingMac = publicFacingMac;
}
/**
@@ -73,4 +81,13 @@
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 c65bf6b..3a8dace 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.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 @@
new ConcurrentHashMap<>();
private IpAddress nextHopIpAddress;
+ private MacAddress macOfPublicIpAddresses;
@Activate
public void activate() {
@@ -96,6 +98,7 @@
localPublicIpPrefixes.put(prefix, true);
}
nextHopIpAddress = config.getNextHopIpAddress();
+ macOfPublicIpAddresses = config.getPublicFacingMac();
} catch (FileNotFoundException e) {
log.warn("Configuration file not found: {}", configFileName);
@@ -109,6 +112,11 @@
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 @@
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 644c229..382f522 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.
@@ -30,6 +31,22 @@
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.
*
* @param privateIpAddress a private IP address
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 0000000..35a9d81
--- /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.
+ * <p>
+ * 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.
+ * </p>
+ */
+@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())));
+ }
+ }
+}