aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/apps/virtualbng/src
diff options
context:
space:
mode:
authorAshlee Young <ashlee@onosfw.com>2015-09-09 22:15:21 -0700
committerAshlee Young <ashlee@onosfw.com>2015-09-09 22:15:21 -0700
commit13d05bc8458758ee39cb829098241e89616717ee (patch)
tree22a4d1ce65f15952f07a3df5af4b462b4697cb3a /framework/src/onos/apps/virtualbng/src
parent6139282e1e93c2322076de4b91b1c85d0bc4a8b3 (diff)
ONOS checkin based on commit tag e796610b1f721d02f9b0e213cf6f7790c10ecd60
Change-Id: Ife8810491034fe7becdba75dda20de4267bd15cd
Diffstat (limited to 'framework/src/onos/apps/virtualbng/src')
-rw-r--r--framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/IpAddressMapEntryCodec.java42
-rw-r--r--framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/RestClient.java92
-rw-r--r--framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfiguration.java123
-rw-r--r--framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java308
-rw-r--r--framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationService.java110
-rw-r--r--framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java532
-rw-r--r--framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngResource.java141
-rw-r--r--framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngService.java52
-rw-r--r--framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VirtualPublicHosts.java167
-rw-r--r--framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/cli/MappingListCommand.java66
-rw-r--r--framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/cli/package-info.java20
-rw-r--r--framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/package-info.java20
-rw-r--r--framework/src/onos/apps/virtualbng/src/main/resources/OSGI-INF/blueprint/shell-config.xml23
-rw-r--r--framework/src/onos/apps/virtualbng/src/main/webapp/WEB-INF/web.xml44
14 files changed, 1740 insertions, 0 deletions
diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/IpAddressMapEntryCodec.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/IpAddressMapEntryCodec.java
new file mode 100644
index 00000000..b2096b7e
--- /dev/null
+++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/IpAddressMapEntryCodec.java
@@ -0,0 +1,42 @@
+/*
+ * 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 com.google.common.base.Preconditions.checkNotNull;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import java.util.Map.Entry;
+
+import org.onlab.packet.IpAddress;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+
+/**
+ * Codec for encoding a IP address mapping entry to JSON.
+ */
+public final class IpAddressMapEntryCodec extends JsonCodec<Entry<IpAddress, IpAddress>> {
+
+ @Override
+ public ObjectNode encode(Entry<IpAddress, IpAddress> entry, CodecContext context) {
+ checkNotNull(entry, "IP address map entry cannot be null");
+ final ObjectNode result = context.mapper().createObjectNode()
+ .put(entry.getKey().toString(), entry.getValue().toString());
+
+ return result;
+ }
+}
diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/RestClient.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/RestClient.java
new file mode 100644
index 00000000..e779fe78
--- /dev/null
+++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/RestClient.java
@@ -0,0 +1,92 @@
+/*
+ * 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 com.google.common.net.MediaType.JSON_UTF_8;
+import static java.net.HttpURLConnection.HTTP_OK;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+
+import java.io.IOException;
+
+import org.onlab.packet.IpAddress;
+import org.slf4j.Logger;
+
+public class RestClient {
+ private final Logger log = getLogger(getClass());
+ private static final String UTF_8 = JSON_UTF_8.toString();
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+ private final String url;
+
+ /**
+ * Constructor.
+ *
+ * @param xosServerIpAddress the IP address of the XOS server
+ * @param xosServerPort the port for the REST service on XOS server
+ */
+ RestClient(IpAddress xosServerIpAddress, int xosServerPort) {
+ this.url = "http://" + xosServerIpAddress.toString() + ":"
+ + xosServerPort + "/xoslib/rs/vbng_mapping/";
+ }
+ /**
+ * Gets a client web resource builder.
+ *
+ * @param url the URL to access remote resource
+ * @return web resource builder
+ */
+ public WebResource.Builder getClientBuilder(String url) {
+ log.info("URL: {}", url);
+ Client client = Client.create();
+ WebResource resource = client.resource(url);
+ return resource.accept(UTF_8).type(UTF_8);
+ }
+
+ /**
+ * Builds a REST client and fetches XOS mapping data in JSON format.
+ *
+ * @return the vBNG map if REST GET succeeds, otherwise return null
+ */
+ public ObjectNode getRest() {
+ WebResource.Builder builder = getClientBuilder(url);
+ ClientResponse response = builder.get(ClientResponse.class);
+
+ if (response.getStatus() != HTTP_OK) {
+ log.info("REST GET request returned error code {}",
+ response.getStatus());
+ return null;
+ }
+
+ String jsonString = response.getEntity(String.class);
+ log.info("Fetched JSON string: {}", jsonString);
+
+ JsonNode node;
+ try {
+ node = MAPPER.readTree(jsonString);
+ } catch (IOException e) {
+ log.error("Failed to read JSON string", e);
+ return null;
+ }
+
+ return (ObjectNode) node;
+ }
+}
diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfiguration.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfiguration.java
new file mode 100644
index 00000000..ee2cbeaa
--- /dev/null
+++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfiguration.java
@@ -0,0 +1,123 @@
+/*
+ * 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 com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.Collections;
+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
+ * JSON-formatted configuration file.
+ */
+public final class VbngConfiguration {
+
+ private final List<IpPrefix> localPublicIpPrefixes;
+ private final IpAddress nextHopIpAddress;
+ private final MacAddress publicFacingMac;
+ private final IpAddress xosIpAddress;
+ private final int xosRestPort;
+
+ /**
+ * Default constructor.
+ */
+ private VbngConfiguration() {
+ localPublicIpPrefixes = null;
+ nextHopIpAddress = null;
+ publicFacingMac = null;
+ xosIpAddress = null;
+ xosRestPort = 0;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @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
+ * @param xosIpAddress the XOS server IP address
+ * @param xosRestPort the port of the XOS server for REST
+ */
+ @JsonCreator
+ public VbngConfiguration(@JsonProperty("localPublicIpPrefixes")
+ List<IpPrefix> prefixes,
+ @JsonProperty("nextHopIpAddress")
+ IpAddress nextHopIpAddress,
+ @JsonProperty("publicFacingMac")
+ MacAddress publicFacingMac,
+ @JsonProperty("xosIpAddress")
+ IpAddress xosIpAddress,
+ @JsonProperty("xosRestPort")
+ int xosRestPort) {
+ localPublicIpPrefixes = prefixes;
+ this.nextHopIpAddress = nextHopIpAddress;
+ this.publicFacingMac = publicFacingMac;
+ this.xosIpAddress = xosIpAddress;
+ this.xosRestPort = xosRestPort;
+ }
+
+ /**
+ * Gets a list of public IP prefixes configured for local SDN network.
+ *
+ * @return the list of public IP prefixes
+ */
+ public List<IpPrefix> getLocalPublicIpPrefixes() {
+ return Collections.unmodifiableList(localPublicIpPrefixes);
+ }
+
+ /**
+ * Gets the IP address configured for the next hop (upstream gateway).
+ *
+ * @return the IP address of the next hop
+ */
+ 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;
+ }
+
+ /**
+ * Gets the IP address configured for XOS server.
+ *
+ * @return the IP address configured for the XOS server
+ */
+ public IpAddress getXosIpAddress() {
+ return xosIpAddress;
+ }
+
+ /**
+ * Gets the REST communication port configured for XOS server.
+ *
+ * @return the REST communication port configured for XOS server
+ */
+ public int getXosRestPort() {
+ return xosRestPort;
+ }
+}
diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java
new file mode 100644
index 00000000..d27d6904
--- /dev/null
+++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java
@@ -0,0 +1,308 @@
+/*
+ * 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 com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+
+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.Service;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of ConfigurationService which reads virtual BNG
+ * configuration from a file.
+ */
+@Component(immediate = true)
+@Service
+public class VbngConfigurationManager implements VbngConfigurationService {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ private static final String CONFIG_DIR = "../config";
+ private static final String DEFAULT_CONFIG_FILE = "virtualbng.json";
+ private String configFileName = DEFAULT_CONFIG_FILE;
+
+ // If all the IP addresses of one IP prefix are assigned, then we
+ // mark the value of this IP prefix as false, otherwise as true.
+ private Map<IpPrefix, Boolean> localPublicIpPrefixes =
+ new ConcurrentHashMap<>();
+
+ // Map from private IP address to public IP address
+ private Map<IpAddress, IpAddress> ipAddressMap =
+ new ConcurrentHashMap<>();
+
+ private IpAddress nextHopIpAddress;
+ private MacAddress macOfPublicIpAddresses;
+ private IpAddress xosIpAddress;
+ private int xosRestPort;
+
+ @Activate
+ public void activate() {
+ readConfiguration();
+ log.info("vBNG configuration service started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ log.info("vBNG configuration service stopped");
+ }
+
+ /**
+ * Instructs the configuration reader to read the configuration from the
+ * file.
+ */
+ public void readConfiguration() {
+ readConfiguration(configFileName);
+ }
+
+ /**
+ * Reads virtual BNG information contained in configuration file.
+ *
+ * @param configFilename the name of the configuration file for the virtual
+ * BNG application
+ */
+ private void readConfiguration(String configFilename) {
+ File configFile = new File(CONFIG_DIR, configFilename);
+ ObjectMapper mapper = new ObjectMapper();
+
+ try {
+ log.info("Loading config: {}", configFile.getAbsolutePath());
+ VbngConfiguration config = mapper.readValue(configFile,
+ VbngConfiguration.class);
+ for (IpPrefix prefix : config.getLocalPublicIpPrefixes()) {
+ localPublicIpPrefixes.put(prefix, true);
+ }
+ nextHopIpAddress = config.getNextHopIpAddress();
+ macOfPublicIpAddresses = config.getPublicFacingMac();
+ xosIpAddress = config.getXosIpAddress();
+ xosRestPort = config.getXosRestPort();
+
+ } catch (FileNotFoundException e) {
+ log.warn("Configuration file not found: {}", configFileName);
+ } catch (IOException e) {
+ log.error("Error loading configuration", e);
+ }
+ }
+
+ @Override
+ public IpAddress getNextHopIpAddress() {
+ return nextHopIpAddress;
+ }
+
+ @Override
+ public MacAddress getPublicFacingMac() {
+ return macOfPublicIpAddresses;
+ }
+
+ @Override
+ public IpAddress getXosIpAddress() {
+ return xosIpAddress;
+ }
+
+ @Override
+ public int getXosRestPort() {
+ return xosRestPort;
+ }
+
+ // TODO handle the case: the number of public IP addresses is not enough
+ // for 1:1 mapping from public IP to private IP.
+ @Override
+ public synchronized IpAddress getAvailablePublicIpAddress(IpAddress
+ privateIpAddress) {
+ // If there is already a mapping entry for the private IP address,
+ // then fetch the public IP address in the mapping entry and return it.
+ IpAddress publicIpAddress = ipAddressMap.get(privateIpAddress);
+ if (publicIpAddress != null) {
+ return publicIpAddress;
+ }
+ // There is no mapping for the private IP address.
+ Iterator<Entry<IpPrefix, Boolean>> prefixes =
+ localPublicIpPrefixes.entrySet().iterator();
+ while (prefixes.hasNext()) {
+ Entry<IpPrefix, Boolean> prefix = prefixes.next();
+ if (!prefix.getValue()) {
+ continue;
+ }
+
+ if (prefix.getKey().prefixLength() == 32) {
+ updateIpPrefixStatus(prefix.getKey(), false);
+ publicIpAddress = prefix.getKey().address();
+ ipAddressMap.put(privateIpAddress, publicIpAddress);
+ return publicIpAddress;
+ }
+
+ int prefixLen = prefix.getKey().prefixLength();
+ int availableIpNum = (int) Math.pow(2,
+ IpPrefix.MAX_INET_MASK_LENGTH - prefixLen) - 1;
+ for (int i = 1; i <= availableIpNum; i++) {
+ publicIpAddress =
+ increaseIpAddress(prefix.getKey().address(), i);
+ if (publicIpAddress == null) {
+ return null;
+ }
+ if (ipAddressMap.values().contains(publicIpAddress)) {
+ continue;
+ } else if (i == availableIpNum) {
+ // All the IP addresses are assigned out
+ // Update this IP prefix status to false
+ // Note: in this version we do not consider the
+ // IP recycling issue.
+ updateIpPrefixStatus(prefix.getKey(), false);
+ ipAddressMap.put(privateIpAddress, publicIpAddress);
+ return publicIpAddress;
+ } else {
+ ipAddressMap.put(privateIpAddress, publicIpAddress);
+ return publicIpAddress;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public IpAddress getAssignedPublicIpAddress(IpAddress privateIpAddress) {
+ return ipAddressMap.get(privateIpAddress);
+ }
+
+ @Override
+ public boolean isAssignedPublicIpAddress(IpAddress ipAddress) {
+ return ipAddressMap.containsValue(ipAddress);
+ }
+
+ @Override
+ public synchronized IpAddress recycleAssignedPublicIpAddress(IpAddress
+ privateIpAddress) {
+ IpAddress publicIpAddress = ipAddressMap.remove(privateIpAddress);
+ if (publicIpAddress == null) {
+ return null;
+ }
+
+ Iterator<Entry<IpPrefix, Boolean>> prefixes =
+ localPublicIpPrefixes.entrySet().iterator();
+ while (prefixes.hasNext()) {
+ Entry<IpPrefix, Boolean> prefixEntry = prefixes.next();
+ if (prefixEntry.getKey().contains(publicIpAddress)
+ && !prefixEntry.getValue()) {
+ updateIpPrefixStatus(prefixEntry.getKey(), true);
+ }
+ }
+ log.info("[DELETE] Private IP to Public IP mapping: {} --> {}",
+ privateIpAddress, publicIpAddress);
+ return publicIpAddress;
+ }
+
+ @Override
+ public Map<IpAddress, IpAddress> getIpAddressMappings() {
+ return Collections.unmodifiableMap(ipAddressMap);
+ }
+
+ @Override
+ public synchronized boolean assignSpecifiedPublicIp(IpAddress publicIpAddress,
+ IpAddress privateIpAddress) {
+
+ // Judge whether this public IP address is in our public IP
+ // prefix/address list.
+ boolean isPublicIpExist = false;
+ for (Entry<IpPrefix, Boolean> prefix: localPublicIpPrefixes.entrySet()) {
+ if (prefix.getKey().contains(publicIpAddress)) {
+ isPublicIpExist = true;
+
+ // Judge whether this public IP address is already assigned
+ if (!prefix.getValue() ||
+ isAssignedPublicIpAddress(publicIpAddress)) {
+ log.info("The public IP address {} is already assigned, "
+ + "and not available.", publicIpAddress);
+ return false;
+ }
+
+ // The public IP address is still available
+ // Store the mapping from private IP address to public IP address
+ ipAddressMap.put(privateIpAddress, publicIpAddress);
+
+ // Update the prefix status
+ if (prefix.getKey().prefixLength() == 32) {
+ updateIpPrefixStatus(prefix.getKey(), false);
+ return true;
+ }
+
+ // Judge whether the prefix of this public IP address is used
+ // up, if so, update the IP prefix status.
+ int prefixLen = prefix.getKey().prefixLength();
+ int availableIpNum = (int) Math.pow(2,
+ IpPrefix.MAX_INET_MASK_LENGTH - prefixLen) - 1;
+ int usedIpNum = 0;
+ for (Entry<IpAddress, IpAddress> ipAddressMapEntry:
+ ipAddressMap.entrySet()) {
+ if (prefix.getKey().contains(ipAddressMapEntry.getValue())) {
+ usedIpNum = usedIpNum + 1;
+ }
+ }
+ if (usedIpNum == availableIpNum) {
+ updateIpPrefixStatus(prefix.getKey(), false);
+ }
+
+ return true;
+ }
+ }
+ if (!isPublicIpExist) {
+ log.info("The public IP address {} retrieved from XOS mapping does "
+ + "not exist", publicIpAddress);
+ }
+ return false;
+ }
+
+ /**
+ * Generates a new IP address base on a given IP address plus a number to
+ * increase.
+ *
+ * @param ipAddress the IP address to increase
+ * @param num the number for ipAddress to add
+ * @return the new IP address after increase
+ */
+ private IpAddress increaseIpAddress(IpAddress ipAddress, int num) {
+ if (ipAddress.isIp6()) {
+ log.info("vBNG currently does not handle IPv6");
+ return null;
+ }
+ return IpAddress.valueOf(ipAddress.getIp4Address().toInt() + num);
+ }
+
+ /**
+ * Updates the IP prefix status in the local public IP prefix table.
+ *
+ * @param ipPprefix the IP prefix to update
+ * @param b the new value for the IP prefix
+ */
+ private void updateIpPrefixStatus(IpPrefix ipPprefix, boolean b) {
+ localPublicIpPrefixes.replace(ipPprefix, b);
+ }
+
+}
diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationService.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationService.java
new file mode 100644
index 00000000..ef8698a0
--- /dev/null
+++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationService.java
@@ -0,0 +1,110 @@
+/*
+ * 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 java.util.Map;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+
+/**
+ * Provides information about the virtual BNG configuration.
+ */
+public interface VbngConfigurationService {
+
+ /**
+ * Gets the IP address configured for the next hop.
+ *
+ * @return the IP address of next hop
+ */
+ IpAddress getNextHopIpAddress();
+
+ /**
+ * Gets the MAC address configured for all the public IP addresses.
+ *
+ * @return the MAC address
+ */
+ MacAddress getPublicFacingMac();
+
+ /**
+ * Gets the IP address configured for XOS server.
+ *
+ * @return the IP address configured for the XOS server
+ */
+ IpAddress getXosIpAddress();
+
+ /**
+ * Gets the REST communication port configured for XOS server.
+ *
+ * @return the REST communication port configured for XOS server
+ */
+ int getXosRestPort();
+
+ /**
+ * 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
+ */
+ boolean isAssignedPublicIpAddress(IpAddress ipAddress);
+
+ /**
+ * Gets an available public IP address from local public IP prefixes.
+ *
+ * @param privateIpAddress a private IP address
+ * @return an available public IP address if it exists, otherwise null
+ */
+ IpAddress getAvailablePublicIpAddress(IpAddress privateIpAddress);
+
+ /**
+ * Gets the public IP address already assigned for a private IP address.
+ *
+ * @param privateIpAddress a private IP address
+ * @return the assigned public IP address if it exists, otherwise null
+ */
+ IpAddress getAssignedPublicIpAddress(IpAddress privateIpAddress);
+
+ /**
+ * Recycles the public IP address assigned for a private IP address, and
+ * at the same time deletes the mapping entry from this private IP address
+ * to the public IP address.
+ *
+ * @param privateIpAddress a private IP address
+ * @return the assigned public IP address if it exists, otherwise null
+ */
+ IpAddress recycleAssignedPublicIpAddress(IpAddress privateIpAddress);
+
+ /**
+ * Gets all the mapping entries from private IP address to public IP
+ * address.
+ *
+ * @return the address map from private IP address to public IP address
+ */
+ Map<IpAddress, IpAddress> getIpAddressMappings();
+
+ /**
+ * Tries to assign a given public IP address to a private IP address. If
+ * success, then sets up the mapping from this private IP address to the
+ * public IP address, and stores the mapping.
+ *
+ * @param publicIpAddress the public IP address try to assign
+ * @param privateIpAddress a private IP address
+ * @return true if this public IP address is available, otherwise false
+ */
+ boolean assignSpecifiedPublicIp(IpAddress publicIpAddress,
+ IpAddress privateIpAddress);
+}
diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java
new file mode 100644
index 00000000..5e82b7e8
--- /dev/null
+++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java
@@ -0,0 +1,532 @@
+/*
+ * 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 com.google.common.base.Preconditions.checkNotNull;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Maps;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+
+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.apache.felix.scr.annotations.Service;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.PortNumber;
+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.host.HostEvent;
+import org.onosproject.net.host.HostListener;
+import org.onosproject.net.host.HostService;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.PointToPointIntent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is a virtual Broadband Network Gateway (BNG) application. It mainly
+ * has 3 functions:
+ * (1) assigns and replies a public IP address to a REST request with a private
+ * IP address
+ * (2) maintains the mapping from the private IP address to the public IP address
+ * (3) installs point to point intents for the host configured with private IP
+ * address to access Internet
+ */
+@Component(immediate = true)
+@Service
+public class VbngManager implements VbngService {
+
+ private static final String APP_NAME = "org.onosproject.virtualbng";
+ private static final String VBNG_MAP_NAME = "vbng_mapping";
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected HostService hostService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected IntentService intentService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected VbngConfigurationService vbngConfigurationService;
+
+ private ApplicationId appId;
+ private Map<IpAddress, PointToPointIntent> p2pIntentsFromHost;
+ private Map<IpAddress, PointToPointIntent> p2pIntentsToHost;
+
+ // This map stores the mapping from the private IP addresses to VcpeHost.
+ // The IP addresses in this map are all the private IP addresses we failed
+ // to create vBNGs due to the next hop host was not in ONOS.
+ private Map<IpAddress, VcpeHost> privateIpAddressMap;
+
+ // Store the mapping from hostname to connect point
+ private Map<String, ConnectPoint> nodeToPort;
+
+ private HostListener hostListener;
+ private IpAddress nextHopIpAddress;
+
+ private static final DeviceId FABRIC_DEVICE_ID =
+ DeviceId.deviceId("of:8f0e486e73000187");
+
+ @Activate
+ public void activate() {
+ appId = coreService.registerApplication(APP_NAME);
+ p2pIntentsFromHost = new ConcurrentHashMap<>();
+ p2pIntentsToHost = new ConcurrentHashMap<>();
+ privateIpAddressMap = new ConcurrentHashMap<>();
+
+ setupMap();
+
+ nextHopIpAddress = vbngConfigurationService.getNextHopIpAddress();
+ hostListener = new InternalHostListener();
+ hostService.addListener(hostListener);
+
+ log.info("vBNG Started");
+
+ // Recover the status before vBNG restarts
+ statusRecovery();
+ }
+
+ @Deactivate
+ public void deactivate() {
+ hostService.removeListener(hostListener);
+ log.info("vBNG Stopped");
+ }
+
+ /**
+ * Recovers from XOS record. Re-sets up the mapping between private IP
+ * address and public IP address, re-calculates intents and re-installs
+ * those intents.
+ */
+ private void statusRecovery() {
+ log.info("vBNG starts to recover from XOS record......");
+ RestClient restClient =
+ new RestClient(vbngConfigurationService.getXosIpAddress(),
+ vbngConfigurationService.getXosRestPort());
+ ObjectNode map = restClient.getRest();
+ if (map == null) {
+ log.info("Stop to recover vBNG status due to the vBNG map "
+ + "is null!");
+ return;
+ }
+
+ log.info("Get record from XOS: {}", map);
+
+ ArrayNode array = (ArrayNode) map.get(VBNG_MAP_NAME);
+ Iterator<JsonNode> entries = array.elements();
+ while (entries.hasNext()) {
+ ObjectNode entry = (ObjectNode) entries.next();
+
+ IpAddress hostIpAdddress =
+ IpAddress.valueOf(entry.get("private_ip").asText());
+ IpAddress publicIpAddress =
+ IpAddress.valueOf(entry.get("routeable_subnet").asText());
+ MacAddress macAddress =
+ MacAddress.valueOf(entry.get("mac").asText());
+ String hostName = entry.get("hostname").asText();
+
+ // Create vBNG
+ createVbng(hostIpAdddress, publicIpAddress, macAddress, hostName);
+
+ }
+ }
+
+ /**
+ * Sets up mapping from hostname to connect point.
+ */
+ private void setupMap() {
+ nodeToPort = Maps.newHashMap();
+
+ nodeToPort.put("cordcompute01.onlab.us",
+ new ConnectPoint(FABRIC_DEVICE_ID,
+ PortNumber.portNumber(48)));
+
+ nodeToPort.put("cordcompute02.onlab.us",
+ new ConnectPoint(FABRIC_DEVICE_ID,
+ PortNumber.portNumber(47)));
+ }
+
+ /**
+ * Creates a new vBNG.
+ *
+ * @param privateIpAddress a private IP address
+ * @param publicIpAddress the public IP address for the private IP address
+ * @param hostMacAddress the MAC address for the private IP address
+ * @param hostName the host name for the private IP address
+ */
+ private void createVbng(IpAddress privateIpAddress,
+ IpAddress publicIpAddress,
+ MacAddress hostMacAddress,
+ String hostName) {
+ boolean result = vbngConfigurationService
+ .assignSpecifiedPublicIp(publicIpAddress, privateIpAddress);
+ if (!result) {
+ log.info("Assign public IP address {} for private IP address {} "
+ + "failed!", publicIpAddress, privateIpAddress);
+ log.info("Failed to create vBNG for private IP address {}",
+ privateIpAddress);
+ return;
+ }
+ log.info("[ADD] Private IP to Public IP mapping: {} --> {}",
+ privateIpAddress, publicIpAddress);
+
+ // Setup paths between the host configured with private IP and
+ // next hop
+ if (!setupForwardingPaths(privateIpAddress, publicIpAddress,
+ hostMacAddress, hostName)) {
+ privateIpAddressMap.put(privateIpAddress,
+ new VcpeHost(hostMacAddress, hostName));
+ }
+ }
+
+ @Override
+ public IpAddress createVbng(IpAddress privateIpAddress,
+ MacAddress hostMacAddress,
+ String hostName) {
+
+ IpAddress publicIpAddress =
+ vbngConfigurationService.getAvailablePublicIpAddress(
+ privateIpAddress);
+ if (publicIpAddress == null) {
+ log.info("Did not find an available public IP address to use.");
+ return null;
+ }
+ log.info("[ADD] Private IP to Public IP mapping: {} --> {}",
+ privateIpAddress, publicIpAddress);
+
+ // Setup paths between the host configured with private IP and
+ // next hop
+ if (!setupForwardingPaths(privateIpAddress, publicIpAddress,
+ hostMacAddress, hostName)) {
+ privateIpAddressMap.put(privateIpAddress,
+ new VcpeHost(hostMacAddress, hostName));
+ }
+ return publicIpAddress;
+ }
+
+ @Override
+ public IpAddress deleteVbng(IpAddress privateIpAddress) {
+ // Recycle the public IP address assigned to this private IP address.
+ // Recycling will also delete the mapping entry from the private IP
+ // address to public IP address.
+ IpAddress assignedPublicIpAddress = vbngConfigurationService
+ .recycleAssignedPublicIpAddress(privateIpAddress);
+ if (assignedPublicIpAddress == null) {
+ return null;
+ }
+
+ // Remove the private IP address from privateIpAddressMap
+ privateIpAddressMap.remove(privateIpAddress);
+
+ // Remove intents
+ removeForwardingPaths(privateIpAddress);
+
+ return assignedPublicIpAddress;
+ }
+
+ /**
+ * Removes the forwarding paths in both two directions between host
+ * configured with private IP and next hop.
+ *
+ * @param privateIp the private IP address of a local host
+ */
+ private void removeForwardingPaths(IpAddress privateIp) {
+ PointToPointIntent toNextHopIntent =
+ p2pIntentsFromHost.remove(privateIp);
+ if (toNextHopIntent != null) {
+ intentService.withdraw(toNextHopIntent);
+ //intentService.purge(toNextHopIntent);
+ }
+ PointToPointIntent toLocalHostIntent =
+ p2pIntentsToHost.remove(privateIp);
+ if (toLocalHostIntent != null) {
+ intentService.withdraw(toLocalHostIntent);
+ //intentService.purge(toLocalHostIntent);
+ }
+ }
+
+ /**
+ * Sets up forwarding paths in both two directions between host configured
+ * with private IP and next hop.
+ *
+ * @param privateIp the private IP address of a local host
+ * @param publicIp the public IP address assigned for the private IP address
+ * @param hostMacAddress the MAC address for the IP address
+ * @param hostName the host name for the IP address
+ */
+ private boolean setupForwardingPaths(IpAddress privateIp,
+ IpAddress publicIp,
+ MacAddress hostMacAddress,
+ String hostName) {
+ checkNotNull(privateIp);
+ checkNotNull(publicIp);
+ checkNotNull(hostMacAddress);
+ checkNotNull(hostName);
+
+ if (nextHopIpAddress == null) {
+ log.warn("Did not find next hop IP address");
+ return false;
+ }
+
+ // If there are already intents for private IP address in the system,
+ // we will do nothing and directly return.
+ if (p2pIntentsFromHost.containsKey(privateIp)
+ && p2pIntentsToHost.containsKey(privateIp)) {
+ return true;
+ }
+
+ Host nextHopHost = null;
+ if (!hostService.getHostsByIp(nextHopIpAddress).isEmpty()) {
+ nextHopHost = hostService.getHostsByIp(nextHopIpAddress)
+ .iterator().next();
+ } else {
+ hostService.startMonitoringIp(nextHopIpAddress);
+ if (hostService.getHostsByIp(privateIp).isEmpty()) {
+ hostService.startMonitoringIp(privateIp);
+ }
+ return false;
+ }
+
+ ConnectPoint nextHopConnectPoint =
+ new ConnectPoint(nextHopHost.location().elementId(),
+ nextHopHost.location().port());
+ ConnectPoint localHostConnectPoint = nodeToPort.get(hostName);
+
+ // Generate and install intent for traffic from host configured with
+ // private IP
+ if (!p2pIntentsFromHost.containsKey(privateIp)) {
+ PointToPointIntent toNextHopIntent
+ = srcMatchIntentGenerator(privateIp,
+ publicIp,
+ nextHopHost.mac(),
+ nextHopConnectPoint,
+ localHostConnectPoint
+ );
+ p2pIntentsFromHost.put(privateIp, toNextHopIntent);
+ intentService.submit(toNextHopIntent);
+ }
+
+ // Generate and install intent for traffic to host configured with
+ // private IP
+ if (!p2pIntentsToHost.containsKey(privateIp)) {
+ PointToPointIntent toLocalHostIntent
+ = dstMatchIntentGenerator(publicIp,
+ privateIp,
+ hostMacAddress,
+ localHostConnectPoint,
+ nextHopConnectPoint);
+ p2pIntentsToHost.put(privateIp, toLocalHostIntent);
+ intentService.submit(toLocalHostIntent);
+ }
+
+ return true;
+ }
+
+ /**
+ * Listener for host events.
+ */
+ private class InternalHostListener implements HostListener {
+ @Override
+ public void event(HostEvent event) {
+ log.debug("Received HostEvent {}", event);
+
+ Host host = event.subject();
+ if (event.type() != HostEvent.Type.HOST_ADDED) {
+ return;
+ }
+
+ for (IpAddress ipAddress: host.ipAddresses()) {
+ // The POST method from XOS gives us MAC and host name, so we
+ // do not need to do anything after receive a vCPE host event
+ // for now.
+ /*if (privateIpAddressSet.contains(ipAddress)) {
+ createVbngAgain(ipAddress);
+ }*/
+
+ if (nextHopIpAddress != null &&
+ ipAddress.equals(nextHopIpAddress)) {
+
+ for (Entry<IpAddress, VcpeHost> entry:
+ privateIpAddressMap.entrySet()) {
+ createVbngAgain(entry.getKey());
+ }
+
+ }
+ }
+ }
+ }
+
+ /**
+ * Tries to create vBNG again after receiving a host event if the IP
+ * address of the host is the next hop IP address.
+ *
+ * @param privateIpAddress the private IP address
+ */
+ private void createVbngAgain(IpAddress privateIpAddress) {
+ IpAddress publicIpAddress = vbngConfigurationService
+ .getAssignedPublicIpAddress(privateIpAddress);
+ if (publicIpAddress == null) {
+ // We only need to handle the private IP addresses for which we
+ // already returned the REST replies with assigned public IP
+ // addresses. If a private IP addresses does not have an assigned
+ // public IP address, we should not get it an available public IP
+ // address here, and we should delete it in the unhandled private
+ // IP address map.
+ privateIpAddressMap.remove(privateIpAddress);
+ return;
+ }
+ VcpeHost vcpeHost = privateIpAddressMap.get(privateIpAddress);
+ if (setupForwardingPaths(privateIpAddress, publicIpAddress,
+ vcpeHost.macAddress, vcpeHost.hostName)) {
+ privateIpAddressMap.remove(privateIpAddress);
+ }
+ }
+
+ /**
+ * PointToPointIntent Generator.
+ * <p>
+ * The intent will match the source IP address in packet, rewrite the
+ * source IP address, and rewrite the destination MAC address.
+ * </p>
+ *
+ * @param srcIpAddress the source IP address in packet to match
+ * @param newSrcIpAddress the new source IP address to set
+ * @param dstMacAddress the destination MAC address to set
+ * @param dstConnectPoint the egress point
+ * @param srcConnectPoint the ingress point
+ * @return a PointToPointIntent
+ */
+ private PointToPointIntent srcMatchIntentGenerator(
+ IpAddress srcIpAddress,
+ IpAddress newSrcIpAddress,
+ MacAddress dstMacAddress,
+ ConnectPoint dstConnectPoint,
+ ConnectPoint srcConnectPoint) {
+ checkNotNull(srcIpAddress);
+ checkNotNull(newSrcIpAddress);
+ checkNotNull(dstMacAddress);
+ checkNotNull(dstConnectPoint);
+ checkNotNull(srcConnectPoint);
+
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ selector.matchEthType(Ethernet.TYPE_IPV4);
+ selector.matchIPSrc(IpPrefix.valueOf(srcIpAddress,
+ IpPrefix.MAX_INET_MASK_LENGTH));
+
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+ treatment.setEthDst(dstMacAddress);
+ treatment.setIpSrc(newSrcIpAddress);
+
+ Key key = Key.of(srcIpAddress.toString() + "MatchSrc", appId);
+ PointToPointIntent intent = PointToPointIntent.builder()
+ .appId(appId)
+ .key(key)
+ .selector(selector.build())
+ .treatment(treatment.build())
+ .egressPoint(dstConnectPoint)
+ .ingressPoint(srcConnectPoint)
+ .build();
+
+ log.info("Generated a PointToPointIntent for traffic from local host "
+ + ": {}", intent);
+ return intent;
+ }
+
+ /**
+ * PointToPointIntent Generator.
+ * <p>
+ * The intent will match the destination IP address in packet, rewrite the
+ * destination IP address, and rewrite the destination MAC address.
+ * </p>
+ *
+ * @param dstIpAddress the destination IP address in packet to match
+ * @param newDstIpAddress the new destination IP address to set
+ * @param dstMacAddress the destination MAC address to set
+ * @param dstConnectPoint the egress point
+ * @param srcConnectPoint the ingress point
+ * @return a PointToPointIntent
+ */
+ private PointToPointIntent dstMatchIntentGenerator(
+ IpAddress dstIpAddress,
+ IpAddress newDstIpAddress,
+ MacAddress dstMacAddress,
+ ConnectPoint dstConnectPoint,
+ ConnectPoint srcConnectPoint) {
+ checkNotNull(dstIpAddress);
+ checkNotNull(newDstIpAddress);
+ checkNotNull(dstMacAddress);
+ checkNotNull(dstConnectPoint);
+ checkNotNull(srcConnectPoint);
+
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ selector.matchEthType(Ethernet.TYPE_IPV4);
+ selector.matchIPDst(IpPrefix.valueOf(dstIpAddress,
+ IpPrefix.MAX_INET_MASK_LENGTH));
+
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+ treatment.setEthDst(dstMacAddress);
+ treatment.setIpDst(newDstIpAddress);
+
+ Key key = Key.of(newDstIpAddress.toString() + "MatchDst", appId);
+ PointToPointIntent intent = PointToPointIntent.builder()
+ .appId(appId)
+ .key(key)
+ .selector(selector.build())
+ .treatment(treatment.build())
+ .egressPoint(dstConnectPoint)
+ .ingressPoint(srcConnectPoint)
+ .build();
+ log.info("Generated a PointToPointIntent for traffic to local host "
+ + ": {}", intent);
+
+ return intent;
+ }
+
+ /**
+ * Constructor to store the a vCPE host info.
+ */
+ private class VcpeHost {
+ MacAddress macAddress;
+ String hostName;
+ public VcpeHost(MacAddress macAddress, String hostName) {
+ this.macAddress = macAddress;
+ this.hostName = hostName;
+ }
+ }
+}
diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngResource.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngResource.java
new file mode 100644
index 00000000..c6a9c9b3
--- /dev/null
+++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngResource.java
@@ -0,0 +1,141 @@
+/*
+ * 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 com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import java.util.Map;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onosproject.rest.AbstractWebResource;
+import org.slf4j.Logger;
+
+/**
+ * REST services to interact with the virtual BNG.
+ */
+@Path("privateip")
+public class VbngResource extends AbstractWebResource {
+
+ private final Logger log = getLogger(getClass());
+
+ /**
+ * Create a new virtual BNG connection.
+ *
+ * @param privateIp IP Address for the BNG private network
+ * @param mac MAC address for the host
+ * @param hostName name of the host
+ * @return public IP address for the new connection
+ */
+ @POST
+ @Path("{privateip}/{mac}/{hostname}")
+ public String privateIpAddNotification(@PathParam("privateip")
+ String privateIp, @PathParam("mac") String mac,
+ @PathParam("hostname") String hostName) {
+
+ log.info("Received creating vBNG request, "
+ + "privateIp= {}, mac={}, hostName= {}",
+ privateIp, mac, hostName);
+
+ if (privateIp == null || mac == null || hostName == null) {
+ log.info("Parameters can not be null");
+ return "0";
+ }
+
+ IpAddress privateIpAddress = IpAddress.valueOf(privateIp);
+ MacAddress hostMacAddress = MacAddress.valueOf(mac);
+
+ VbngService vbngService = get(VbngService.class);
+
+ IpAddress publicIpAddress = null;
+ // Create a virtual BNG
+ publicIpAddress = vbngService.createVbng(privateIpAddress,
+ hostMacAddress,
+ hostName);
+
+ if (publicIpAddress != null) {
+ return publicIpAddress.toString();
+ } else {
+ return "0";
+ }
+ }
+
+ /**
+ * Delete a virtual BNG connection.
+ *
+ * @param privateIp IP Address for the BNG private network
+ * @return public IP address for the new connection
+ */
+ @DELETE
+ @Path("{privateip}")
+ public String privateIpDeleteNotification(@PathParam("privateip")
+ String privateIp) {
+ if (privateIp == null) {
+ log.info("Private IP address to delete is null");
+ return "0";
+ }
+ log.info("Received a private IP address : {} to delete", privateIp);
+ IpAddress privateIpAddress = IpAddress.valueOf(privateIp);
+
+ VbngService vbngService = get(VbngService.class);
+
+ IpAddress assignedPublicIpAddress = null;
+ // Delete a virtual BNG
+ assignedPublicIpAddress = vbngService.deleteVbng(privateIpAddress);
+
+ if (assignedPublicIpAddress != null) {
+ return assignedPublicIpAddress.toString();
+ } else {
+ return "0";
+ }
+ }
+
+ /**
+ * Query virtual BNG map.
+ *
+ * @return IP Address map
+ */
+ @GET
+ @Path("map")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response privateIpDeleteNotification() {
+
+ log.info("Received vBNG IP address map request");
+
+ VbngConfigurationService vbngConfigurationService =
+ get(VbngConfigurationService.class);
+
+ Map<IpAddress, IpAddress> map =
+ vbngConfigurationService.getIpAddressMappings();
+ ObjectNode result = new ObjectMapper().createObjectNode();
+
+ result.set("map", new IpAddressMapEntryCodec().encode(map.entrySet(), this));
+
+ return ok(result.toString()).build();
+ }
+}
diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngService.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngService.java
new file mode 100644
index 00000000..051469ea
--- /dev/null
+++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngService.java
@@ -0,0 +1,52 @@
+/*
+ * 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 org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+
+/**
+ * Provides service of the virtual BNG.
+ */
+public interface VbngService {
+
+ /**
+ * Creates a virtual BNG.
+ * <p>
+ * It firstly finds out an available local public IP address. Then, it
+ * sets up paths between the host configured with private IP and
+ * next hop. Finally it returns the public IP address.
+ * </p>
+ *
+ * @param privateIpAddress the private IP address
+ * @param hostMacAddress the MAC address for the IP address
+ * @param hostName the host name for the IP address
+ * @return the public address if a virtual BGN is successfully created,
+ * otherwise return null
+ */
+ IpAddress createVbng(IpAddress privateIpAddress, MacAddress hostMacAddress,
+ String hostName);
+
+ /**
+ * Deletes a virtual BNG.
+ *
+ * @param privateIpAddress a private IP address
+ * @return the public address assigned for this private IP address if the
+ * virtual BGN exists and is deleted, otherwise return null if
+ * there is no vBNG for this private IP address
+ */
+ IpAddress deleteVbng(IpAddress privateIpAddress);
+}
diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VirtualPublicHosts.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VirtualPublicHosts.java
new file mode 100644
index 00000000..5ab650bc
--- /dev/null
+++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VirtualPublicHosts.java
@@ -0,0 +1,167 @@
+/*
+ * 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.director(6));
+ requestIntercepts();
+ log.info("vBNG virtual public hosts started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ withdrawIntercepts();
+ packetService.removeProcessor(processor);
+ processor = null;
+ log.info("vBNG virtual public hosts Stopped");
+ }
+
+ /**
+ * Request packet in via PacketService.
+ */
+ private void requestIntercepts() {
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ // Only IPv4 is supported in current vBNG.
+ selector.matchEthType(Ethernet.TYPE_ARP);
+ packetService.requestPackets(selector.build(),
+ PacketPriority.REACTIVE, appId);
+ }
+
+ /**
+ * Cancel request for packet in via PacketService.
+ */
+ private void withdrawIntercepts() {
+ TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+ // Only IPv4 is supported in current vBNG.
+ selector.matchEthType(Ethernet.TYPE_ARP);
+ packetService.cancelPackets(selector.build(),
+ PacketPriority.REACTIVE, appId);
+ }
+
+ /**
+ * 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())));
+ }
+ }
+}
diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/cli/MappingListCommand.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/cli/MappingListCommand.java
new file mode 100644
index 00000000..e8308376
--- /dev/null
+++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/cli/MappingListCommand.java
@@ -0,0 +1,66 @@
+/*
+ * 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.cli;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.IpAddress;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.virtualbng.VbngConfigurationService;
+
+/**
+ * Command to show the list of vBNG IP address mapping entries.
+ */
+@Command(scope = "onos", name = "vbngs",
+ description = "Lists all vBNG IP address mapping entries")
+public class MappingListCommand extends AbstractShellCommand {
+
+ private static final String FORMAT_HEADER =
+ " Private IP - Public IP";
+ private static final String FORMAT_MAPPING =
+ " %s - %s";
+
+ @Override
+ protected void execute() {
+
+ VbngConfigurationService service =
+ AbstractShellCommand.get(VbngConfigurationService.class);
+
+ // Print all mapping entries
+ printMappingEntries(service.getIpAddressMappings());
+ }
+
+ /**
+ * Prints all vBNG IP address mapping entries.
+ *
+ * @param map the map from private IP address to public address
+ */
+ private void printMappingEntries(Map<IpAddress, IpAddress> map) {
+ print(FORMAT_HEADER);
+
+ Iterator<Entry<IpAddress, IpAddress>> entries =
+ map.entrySet().iterator();
+ while (entries.hasNext()) {
+ Entry<IpAddress, IpAddress> entry = entries.next();
+ print(FORMAT_MAPPING, entry.getKey(), entry.getValue());
+ }
+
+ print("");
+ }
+} \ No newline at end of file
diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/cli/package-info.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/cli/package-info.java
new file mode 100644
index 00000000..9cb53efb
--- /dev/null
+++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/cli/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * The CLI of vBNG application.
+ */
+package org.onosproject.virtualbng.cli;
diff --git a/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/package-info.java b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/package-info.java
new file mode 100644
index 00000000..7648d8bc
--- /dev/null
+++ b/framework/src/onos/apps/virtualbng/src/main/java/org/onosproject/virtualbng/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * A virtual Broadband Network Gateway (BNG) application.
+ */
+package org.onosproject.virtualbng;
diff --git a/framework/src/onos/apps/virtualbng/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/framework/src/onos/apps/virtualbng/src/main/resources/OSGI-INF/blueprint/shell-config.xml
new file mode 100644
index 00000000..48532b3f
--- /dev/null
+++ b/framework/src/onos/apps/virtualbng/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -0,0 +1,23 @@
+<!--
+ ~ 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.
+ -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+ <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
+ <command>
+ <action class="org.onosproject.virtualbng.cli.MappingListCommand"/>
+ </command>
+ </command-bundle>
+</blueprint>
diff --git a/framework/src/onos/apps/virtualbng/src/main/webapp/WEB-INF/web.xml b/framework/src/onos/apps/virtualbng/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 00000000..e8e0071f
--- /dev/null
+++ b/framework/src/onos/apps/virtualbng/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+ id="ONOS" version="2.5">
+ <display-name>ONOS Virtual BNG APP REST API</display-name>
+
+ <servlet>
+ <servlet-name>JAX-RS Service</servlet-name>
+ <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+ <init-param>
+ <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
+ <param-value>com.sun.jersey.api.core.ClassNamesResourceConfig</param-value>
+ </init-param>
+ <init-param>
+ <param-name>com.sun.jersey.config.property.classnames</param-name>
+ <param-value>
+ org.onosproject.virtualbng.VbngResource
+ </param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>JAX-RS Service</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+
+</web-app>