add Mac and hostname to POST url

This commit is to handle the case:
We receive a DELETE to delete a vBNG, and then receive
a POST with the same private IP address to create vBNG.

At this moment, if the old vCPE is not down, and the new
vCPE is not up yet, onos will use the host with old
vCPE mac address to create the intent, which is not
correct, and hard to solve. Since onos does not know
the host in the system is old vCPE or new vCPE.

Thus, we change to ask XOS to post us host MAC
and hostname together with the private IP address.

Change-Id: I011924aada589ea81d80a479aefa41753fa2e223
diff --git a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java
index 37b61a7..775cff4 100644
--- a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java
+++ b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngManager.java
@@ -17,11 +17,10 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import com.google.common.collect.Sets;
+import com.google.common.collect.Maps;
 
-import java.util.Iterator;
 import java.util.Map;
-import java.util.Set;
+import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.felix.scr.annotations.Activate;
@@ -37,7 +36,9 @@
 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;
@@ -84,19 +85,28 @@
     private Map<IpAddress, PointToPointIntent> p2pIntentsFromHost;
     private Map<IpAddress, PointToPointIntent> p2pIntentsToHost;
 
-    // This set stores all the private IP addresses we failed to create vBNGs
-    // for the first time.
-    private Set<IpAddress> privateIpAddressSet;
+    // 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<>();
-        privateIpAddressSet = Sets.newConcurrentHashSet();
+        privateIpAddressMap = new ConcurrentHashMap<>();
+
+        setupMap();
 
         nextHopIpAddress = vbngConfigurationService.getNextHopIpAddress();
         hostListener = new InternalHostListener();
@@ -111,8 +121,25 @@
         log.info("vBNG Stopped");
     }
 
+    /**
+     * 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)));
+    }
+
     @Override
-    public IpAddress createVbng(IpAddress privateIpAddress) {
+    public IpAddress createVbng(IpAddress privateIpAddress,
+                                MacAddress hostMacAddress,
+                                String hostName) {
 
         IpAddress publicIpAddress =
                 vbngConfigurationService.getAvailablePublicIpAddress(
@@ -126,8 +153,10 @@
 
         // Setup paths between the host configured with private IP and
         // next hop
-        if (!setupForwardingPaths(privateIpAddress, publicIpAddress)) {
-            privateIpAddressSet.add(privateIpAddress);
+        if (!setupForwardingPaths(privateIpAddress, publicIpAddress,
+                                  hostMacAddress, hostName)) {
+            privateIpAddressMap.put(privateIpAddress,
+                                    new VcpeHost(hostMacAddress, hostName));
         }
         return publicIpAddress;
     }
@@ -143,8 +172,8 @@
             return null;
         }
 
-        // Remove the private IP address from privateIpAddressSet
-        privateIpAddressSet.remove(privateIpAddress);
+        // Remove the private IP address from privateIpAddressMap
+        privateIpAddressMap.remove(privateIpAddress);
 
         // Remove intents
         removeForwardingPaths(privateIpAddress);
@@ -179,10 +208,17 @@
      *
      * @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) {
+    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");
@@ -196,7 +232,6 @@
             return true;
         }
 
-        Host localHost = null;
         Host nextHopHost = null;
         if (!hostService.getHostsByIp(nextHopIpAddress).isEmpty()) {
             nextHopHost = hostService.getHostsByIp(nextHopIpAddress)
@@ -209,20 +244,10 @@
             return false;
         }
 
-        if (!hostService.getHostsByIp(privateIp).isEmpty()) {
-            localHost =
-                    hostService.getHostsByIp(privateIp).iterator().next();
-        } else {
-            hostService.startMonitoringIp(privateIp);
-            return false;
-        }
-
         ConnectPoint nextHopConnectPoint =
                 new ConnectPoint(nextHopHost.location().elementId(),
                                  nextHopHost.location().port());
-        ConnectPoint localHostConnectPoint =
-                new ConnectPoint(localHost.location().elementId(),
-                                 localHost.location().port());
+        ConnectPoint localHostConnectPoint = nodeToPort.get(hostName);
 
         // Generate and install intent for traffic from host configured with
         // private IP
@@ -244,7 +269,7 @@
             PointToPointIntent toLocalHostIntent
                     = dstMatchIntentGenerator(publicIp,
                                               privateIp,
-                                              localHost.mac(),
+                                              hostMacAddress,
                                               localHostConnectPoint,
                                               nextHopConnectPoint);
             p2pIntentsToHost.put(privateIp, toLocalHostIntent);
@@ -268,18 +293,21 @@
             }
 
             for (IpAddress ipAddress: host.ipAddresses()) {
-                if (privateIpAddressSet.contains(ipAddress)) {
+                // 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)) {
-                    Iterator<IpAddress> ipAddresses =
-                            privateIpAddressSet.iterator();
-                    while (ipAddresses.hasNext()) {
-                        IpAddress privateIpAddress = ipAddresses.next();
-                        createVbngAgain(privateIpAddress);
+
+                    for (Entry<IpAddress, VcpeHost> entry:
+                        privateIpAddressMap.entrySet()) {
+                        createVbngAgain(entry.getKey());
                     }
+
                 }
             }
         }
@@ -287,8 +315,7 @@
 
     /**
      * Tries to create vBNG again after receiving a host event if the IP
-     * address of the host is a private IP address or the next hop IP
-     * address.
+     * address of the host is the next hop IP address.
      *
      * @param privateIpAddress the private IP address
      */
@@ -301,16 +328,14 @@
             // 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 set.
-            privateIpAddressSet.remove(privateIpAddress);
+            // IP address map.
+            privateIpAddressMap.remove(privateIpAddress);
             return;
         }
-        if (setupForwardingPaths(privateIpAddress, publicIpAddress)) {
-            // At this moment it is still possible to fail to create a vBNG,
-            // because creating a vBNG needs two hosts, one is the local host
-            // configured with private IP address, the other is the next hop
-            // host.
-            privateIpAddressSet.remove(privateIpAddress);
+        VcpeHost vcpeHost = privateIpAddressMap.get(privateIpAddress);
+        if (setupForwardingPaths(privateIpAddress, publicIpAddress,
+                                 vcpeHost.macAddress, vcpeHost.hostName)) {
+            privateIpAddressMap.remove(privateIpAddress);
         }
     }
 
@@ -413,4 +438,16 @@
 
         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/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngResource.java b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngResource.java
index 41bc5cc..36f8832 100644
--- a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngResource.java
+++ b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngResource.java
@@ -32,6 +32,7 @@
 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;
 
@@ -44,21 +45,30 @@
     private final Logger log = getLogger(getClass());
 
     @POST
-    @Path("{privateip}")
+    @Path("{privateip}/{mac}/{hostname}")
     public String privateIpAddNotification(@PathParam("privateip")
-            String privateIp) {
-        if (privateIp == null) {
-            log.info("Private IP address to add is null");
+            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";
         }
-        log.info("Received a private IP address : {} to add", privateIp);
+
         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);
+        publicIpAddress = vbngService.createVbng(privateIpAddress,
+                                                 hostMacAddress,
+                                                 hostName);
 
         if (publicIpAddress != null) {
             return publicIpAddress.toString();
diff --git a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngService.java b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngService.java
index c27f86f..051469e 100644
--- a/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngService.java
+++ b/apps/virtualbng/src/main/java/org/onosproject/virtualbng/VbngService.java
@@ -16,6 +16,7 @@
 package org.onosproject.virtualbng;
 
 import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
 
 /**
  * Provides service of the virtual BNG.
@@ -31,10 +32,13 @@
      * </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);
+    IpAddress createVbng(IpAddress privateIpAddress, MacAddress hostMacAddress,
+                         String hostName);
 
     /**
      * Deletes a virtual BNG.