Initial implementation of managing IPs for kubevirt spawned VMIs

Change-Id: I68127e1fe42a142765e7696d8ce80de16d3d94a9
diff --git a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/Constants.java b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/Constants.java
index 9f8201a..7a5d873 100644
--- a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/Constants.java
+++ b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/Constants.java
@@ -59,6 +59,7 @@
     public static final int CLI_NAME_LENGTH = 30;
     public static final int CLI_IP_ADDRESSES_LENGTH = 50;
     public static final int CLI_IP_ADDRESS_LENGTH = 25;
+    public static final int CLI_IP_ADDRESS_AVAILABILITY = 15;
     public static final int CLI_MAC_ADDRESS_LENGTH = 25;
     public static final int CLI_PORTS_LENGTH = 20;
     public static final int CLI_NAMESPACE_LENGTH = 15;
diff --git a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtPort.java b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtPort.java
index 049a336..410c098 100644
--- a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtPort.java
+++ b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtPort.java
@@ -32,6 +32,7 @@
 
     private static final String NOT_NULL_MSG = "Port % cannot be null";
 
+    private final String networkId;
     private final MacAddress macAddress;
     private final IpAddress ipAddress;
     private final DeviceId deviceId;
@@ -40,13 +41,15 @@
     /**
      * Default constructor.
      *
+     * @param networkId         network identifier
      * @param macAddress        MAC address
      * @param ipAddress         IP address
      * @param deviceId          device identifier
      * @param portNumber        port number
      */
-    public DefaultKubevirtPort(MacAddress macAddress, IpAddress ipAddress,
+    public DefaultKubevirtPort(String networkId, MacAddress macAddress, IpAddress ipAddress,
                                DeviceId deviceId, PortNumber portNumber) {
+        this.networkId = networkId;
         this.macAddress = macAddress;
         this.ipAddress = ipAddress;
         this.deviceId = deviceId;
@@ -54,6 +57,11 @@
     }
 
     @Override
+    public String networkId() {
+        return networkId;
+    }
+
+    @Override
     public MacAddress macAddress() {
         return macAddress;
     }
@@ -92,18 +100,20 @@
             return false;
         }
         DefaultKubevirtPort that = (DefaultKubevirtPort) o;
-        return macAddress.equals(that.macAddress) && ipAddress.equals(that.ipAddress) &&
-                deviceId.equals(that.deviceId) && portNumber.equals(that.portNumber);
+        return networkId.equals(that.networkId) && macAddress.equals(that.macAddress) &&
+                ipAddress.equals(that.ipAddress) && deviceId.equals(that.deviceId) &&
+                portNumber.equals(that.portNumber);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(macAddress, ipAddress, deviceId, portNumber);
+        return Objects.hash(networkId, macAddress, ipAddress, deviceId, portNumber);
     }
 
     @Override
     public String toString() {
         return MoreObjects.toStringHelper(this)
+                .add("networkId", networkId)
                 .add("macAddress", macAddress)
                 .add("ipAddress", ipAddress)
                 .add("deviceId", deviceId)
@@ -125,6 +135,7 @@
      */
     public static final class Builder implements KubevirtPort.Builder {
 
+        private String networkId;
         private MacAddress macAddress;
         private IpAddress ipAddress;
         private DeviceId deviceId;
@@ -136,10 +147,18 @@
 
         @Override
         public KubevirtPort build() {
+            checkArgument(networkId != null, NOT_NULL_MSG, "networkId");
             checkArgument(macAddress != null, NOT_NULL_MSG, "macAddress");
             checkArgument(ipAddress != null, NOT_NULL_MSG, "ipAddress");
 
-            return new DefaultKubevirtPort(macAddress, ipAddress, deviceId, portNumber);
+            return new DefaultKubevirtPort(networkId, macAddress, ipAddress,
+                    deviceId, portNumber);
+        }
+
+        @Override
+        public Builder networkId(String networkId) {
+            this.networkId = networkId;
+            return this;
         }
 
         @Override
diff --git a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtIpPool.java b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtIpPool.java
index 64874fd..fb2906e 100644
--- a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtIpPool.java
+++ b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtIpPool.java
@@ -16,9 +16,19 @@
 package org.onosproject.kubevirtnetworking.api;
 
 import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableSet;
+import inet.ipaddr.AddressStringException;
+import inet.ipaddr.IPAddress;
+import inet.ipaddr.IPAddressSeqRange;
+import inet.ipaddr.IPAddressString;
 import org.onlab.packet.IpAddress;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * Kubevirt IP Pool.
@@ -27,16 +37,25 @@
 
     private final IpAddress start;
     private final IpAddress end;
+    private final Set<IpAddress> allocatedIps;
+    private final Set<IpAddress> availableIps;
 
     /**
      * Default constructor.
      *
-     * @param start     start address of IP pool
-     * @param end       end address of IP pool
+     * @param start             start address of IP pool
+     * @param end               end address of IP pool
      */
     public KubevirtIpPool(IpAddress start, IpAddress end) {
         this.start = start;
         this.end = end;
+        this.allocatedIps = new HashSet<>();
+        this.availableIps = new HashSet<>();
+        try {
+            this.availableIps.addAll(getRangedIps(start.toString(), end.toString()));
+        } catch (AddressStringException e) {
+            e.printStackTrace();
+        }
     }
 
     /**
@@ -57,6 +76,61 @@
         return end;
     }
 
+    /**
+     * Returns the set of IP addresses that have been allocated.
+     *
+     * @return set of IP addresses that have been allocated
+     */
+    public Set<IpAddress> allocatedIps() {
+        return ImmutableSet.copyOf(allocatedIps);
+    }
+
+    /**
+     * Returns the set of IP addresses for allocation.
+     *
+     * @return set of IP addresses for allocation.
+     */
+    public Set<IpAddress> availableIps() {
+        return ImmutableSet.copyOf(availableIps);
+    }
+
+    /**
+     * Allocates a random IP address.
+     *
+     * @return allocated IP address
+     * @throws Exception exception
+     */
+    public synchronized IpAddress allocateIp() throws Exception {
+        if (availableIps.size() <= 0) {
+            throw new Exception("No IP address is available for allocation.");
+        }
+
+        List<IpAddress> sortedList = new ArrayList<>(availableIps);
+        Collections.sort(sortedList);
+
+        IpAddress ip = sortedList.get(0);
+
+        availableIps.remove(ip);
+        allocatedIps.add(ip);
+
+        return ip;
+    }
+
+    /**
+     * Releases the given IP address.
+     *
+     * @param ip IP address to be released
+     * @throws Exception exception
+     */
+    public synchronized void releaseIp(IpAddress ip) throws Exception {
+        if (!allocatedIps.contains(ip)) {
+            throw new Exception("The given IP address is not able to be released.");
+        }
+
+        allocatedIps.remove(ip);
+        availableIps.add(ip);
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) {
@@ -81,4 +155,24 @@
                 .add("end", end)
                 .toString();
     }
+
+    /**
+     * Obtains the IP address list from the given start and end range.
+     *
+     * @param start start range
+     * @param end   end range
+     * @return IP address list from the given start and end range
+     * @throws AddressStringException exception
+     */
+    public Set<IpAddress> getRangedIps(String start, String end) throws AddressStringException {
+        Set<IpAddress> ips = new HashSet<>();
+        IPAddress lower = new IPAddressString(start).toAddress();
+        IPAddress upper = new IPAddressString(end).toAddress();
+        IPAddressSeqRange range = lower.toSequentialRange(upper);
+        for (IPAddress addr : range.getIterable()) {
+            ips.add(IpAddress.valueOf(addr.toString()));
+        }
+
+        return ips;
+    }
 }
diff --git a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtPort.java b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtPort.java
index d7c1ff2..a7ae75e 100644
--- a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtPort.java
+++ b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtPort.java
@@ -26,6 +26,13 @@
 public interface KubevirtPort {
 
     /**
+     * Returns the network identifier associated with the port.
+     *
+     * @return network identifier
+     */
+    String networkId();
+
+    /**
      * Returns the MAC address of the port.
      *
      * @return MAC address
@@ -82,6 +89,14 @@
         KubevirtPort build();
 
         /**
+         * Returns port builder with supplied network identifier.
+         *
+         * @param networkId network identifier
+         * @return port builder
+         */
+        Builder networkId(String networkId);
+
+        /**
          * Returns port builder with supplied MAC address.
          *
          * @param macAddress MAC address