add a vBNG application

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

Change-Id: Ie78614a1703422a57f3c325540b927cc4ae603f4
diff --git a/apps/pom.xml b/apps/pom.xml
index f307e36..dbed6e7 100644
--- a/apps/pom.xml
+++ b/apps/pom.xml
@@ -43,6 +43,7 @@
         <module>routing</module>
         <module>routing-api</module>
         <module>reactive-routing</module>
+        <module>virtualbng</module>
         <module>bgprouter</module>
         <module>test</module>
         <module>segmentrouting</module>
diff --git a/apps/virtualbng/features.xml b/apps/virtualbng/features.xml
new file mode 100644
index 0000000..10fc32b
--- /dev/null
+++ b/apps/virtualbng/features.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+  ~ 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.
+  -->
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
+    <repository>mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features</repository>
+    <feature name="${project.artifactId}" version="${project.version}"
+             description="${project.description}">
+        <bundle>mvn:${project.groupId}/onos-app-virtualbng/${project.version}</bundle>
+        <feature>onos-thirdparty-web</feature>
+    </feature>
+</features>
diff --git a/apps/virtualbng/pom.xml b/apps/virtualbng/pom.xml
new file mode 100644
index 0000000..25d319a
--- /dev/null
+++ b/apps/virtualbng/pom.xml
@@ -0,0 +1,83 @@
+<?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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.onosproject</groupId>
+        <artifactId>onos-apps</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>onos-app-virtualbng</artifactId>
+    <packaging>bundle</packaging>
+
+    <description>A virtual Broadband Network Gateway(BNG) application</description>
+
+    <properties>
+        <onos.app.name>org.onosproject.virtualbng</onos.app.name>
+        <web.context>/onos/virtualbng</web.context>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-rest</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.ws.rs</groupId>
+            <artifactId>jsr311-api</artifactId>
+            <version>1.1.1</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <_wab>src/main/webapp/</_wab>
+                        <Bundle-SymbolicName>
+                            ${project.groupId}.${project.artifactId}
+                        </Bundle-SymbolicName>
+                        <Import-Package>
+                            org.slf4j,
+                            javax.ws.rs,
+                            com.sun.jersey.api.core,
+                            com.sun.jersey.spi.container.servlet,
+                            com.sun.jersey.server.impl.container.servlet,
+                            com.fasterxml.jackson.databind,
+                            com.google.common.*,
+                            org.onlab.packet.*,
+                            org.onlab.rest.*,
+                            org.onosproject.*
+                        </Import-Package>
+                        <Web-ContextPath>${web.context}</Web-ContextPath>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfiguration.java b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfiguration.java
new file mode 100644
index 0000000..31eae8b
--- /dev/null
+++ b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfiguration.java
@@ -0,0 +1,76 @@
+/*
+ * 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;
+
+/**
+ * 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;
+
+    /**
+     * Default constructor.
+     */
+    private VbngConfiguration() {
+        localPublicIpPrefixes = null;
+        nextHopIpAddress = null;
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param nextHopIpAddress the IP address of the next hop
+     * @param prefixes the public IP prefix list for local SDN network
+     */
+    @JsonCreator
+    public VbngConfiguration(@JsonProperty("localPublicIpPrefixes")
+                             List<IpPrefix> prefixes,
+                             @JsonProperty("nextHopIpAddress")
+                             IpAddress nextHopIpAddress) {
+        localPublicIpPrefixes = prefixes;
+        this.nextHopIpAddress = nextHopIpAddress;
+    }
+
+    /**
+     * 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;
+    }
+}
diff --git a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java
new file mode 100644
index 0000000..41ff0b4
--- /dev/null
+++ b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationManager.java
@@ -0,0 +1,192 @@
+/*
+ * 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.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.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;
+
+    @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();
+
+        } 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;
+    }
+
+    // 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 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;
+    }
+
+    /**
+     * 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/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationService.java b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationService.java
new file mode 100644
index 0000000..4a539f0
--- /dev/null
+++ b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngConfigurationService.java
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+/**
+ * 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
+     */
+    public IpAddress getNextHopIpAddress();
+
+    /**
+     * 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
+     */
+    public IpAddress getAvailablePublicIpAddress(IpAddress privateIpAddress);
+}
diff --git a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java
new file mode 100644
index 0000000..a84e3e1
--- /dev/null
+++ b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java
@@ -0,0 +1,305 @@
+/*
+ * 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 java.util.Map;
+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.Host;
+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.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 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;
+
+    @Activate
+    public void activate() {
+        appId = coreService.registerApplication(APP_NAME);
+        p2pIntentsFromHost = new ConcurrentHashMap<>();
+        p2pIntentsToHost = new ConcurrentHashMap<>();
+        log.info("vBNG Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        log.info("vBNG Stopped");
+    }
+
+    @Override
+    public IpAddress createVbng(IpAddress privateIpAddress) {
+
+        IpAddress nextHopIpAddress =
+                vbngConfigurationService.getNextHopIpAddress();
+        if (nextHopIpAddress == null) {
+            log.info("Did not find next hop IP address");
+            return null;
+        }
+
+        IpAddress publicIpAddress =
+                vbngConfigurationService.getAvailablePublicIpAddress(
+                                                     privateIpAddress);
+        if (publicIpAddress == null) {
+            log.info("Did not find an available public IP address to use.");
+            return null;
+        }
+        log.info("Private IP to Public IP mapping: {} --> {}",
+                 privateIpAddress, publicIpAddress);
+
+        // Setup paths between the host configured with private IP and
+        // next hop
+        setupForwardingPaths(privateIpAddress, publicIpAddress,
+                             nextHopIpAddress);
+        return publicIpAddress;
+    }
+
+    /**
+     * 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 nextHopIpAddress the next hop IP address outside local SDN network
+     */
+    private void setupForwardingPaths(IpAddress privateIp, IpAddress publicIp,
+                                      IpAddress nextHopIpAddress) {
+        checkNotNull(privateIp);
+        checkNotNull(publicIp);
+        checkNotNull(nextHopIpAddress);
+
+        // 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;
+        }
+
+        Host localHost = null;
+        Host nextHopHost = null;
+        if (!hostService.getHostsByIp(nextHopIpAddress).isEmpty()) {
+            nextHopHost = hostService.getHostsByIp(nextHopIpAddress)
+                    .iterator().next();
+        } else {
+            // TODO to write a new thread to install intents after ONOS
+            // discovers the next hop host
+            hostService.startMonitoringIp(nextHopIpAddress);
+            if (hostService.getHostsByIp(privateIp).isEmpty()) {
+                hostService.startMonitoringIp(privateIp);
+            }
+            return;
+        }
+
+        if (!hostService.getHostsByIp(privateIp).isEmpty()) {
+            localHost =
+                    hostService.getHostsByIp(privateIp).iterator().next();
+        } else {
+            // TODO to write a new thread to install intents after ONOS
+            // discovers the next hop host
+            hostService.startMonitoringIp(privateIp);
+            return;
+        }
+
+        ConnectPoint nextHopConnectPoint =
+                new ConnectPoint(nextHopHost.location().elementId(),
+                                 nextHopHost.location().port());
+        ConnectPoint localHostConnectPoint =
+                new ConnectPoint(localHost.location().elementId(),
+                                 localHost.location().port());
+
+        // 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,
+                                              localHost.mac(),
+                                              localHostConnectPoint,
+                                              nextHopConnectPoint);
+            p2pIntentsToHost.put(nextHopIpAddress, toLocalHostIntent);
+            intentService.submit(toLocalHostIntent);
+        }
+
+        return;
+    }
+
+    /**
+     * 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;
+    }
+
+
+}
diff --git a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngResource.java b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngResource.java
new file mode 100644
index 0000000..c38b7a7
--- /dev/null
+++ b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngResource.java
@@ -0,0 +1,61 @@
+/*
+ * 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 javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.rest.BaseResource;
+import org.slf4j.Logger;
+
+/**
+ * This class provides REST services to virtual BNG.
+ */
+@Path("privateip")
+public class VbngResource extends BaseResource {
+
+    private final Logger log = getLogger(getClass());
+
+    @POST
+    @Path("{privateip}")
+    public String privateIpNotification(@PathParam("privateip")
+            String privateIp) {
+        if (privateIp == null) {
+            log.info("Private IP address is null");
+            return "0";
+        }
+        log.info("Received a private IP address : {}", privateIp);
+        IpAddress privateIpAddress = IpAddress.valueOf(privateIp);
+
+        VbngService vbngService = get(VbngService.class);
+
+        IpAddress publicIpAddress = null;
+        synchronized (this) {
+            // Create a virtual BNG
+            publicIpAddress = vbngService.createVbng(privateIpAddress);
+        }
+
+        if (publicIpAddress != null) {
+            return publicIpAddress.toString();
+        } else {
+            return "0";
+        }
+    }
+}
\ No newline at end of file
diff --git a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngService.java b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngService.java
new file mode 100644
index 0000000..26e6e10
--- /dev/null
+++ b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngService.java
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+/**
+ * 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
+     * @return the public address if a virtual BGN is successfully created,
+     *         otherwise return null
+     */
+    public IpAddress createVbng(IpAddress privateIpAddress);
+
+}
diff --git a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/package-info.java b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/package-info.java
new file mode 100644
index 0000000..7648d8b
--- /dev/null
+++ b/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/apps/virtualbng/src/main/webapp/WEB-INF/web.xml b/apps/virtualbng/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..34c9a11
--- /dev/null
+++ b/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 Virual 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>