CORD-800 Use new interface vlan config for VLAN assignment

In addition
  - Change the name and type of INTERNAL_VLAN

Change-Id: I48bb89cc1cb1fe4155b4d889b1e7384c8bf673fa
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index 8cd657b..0c30cef 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -26,7 +26,6 @@
 import org.onlab.packet.ICMP6;
 import org.onlab.packet.IPv4;
 import org.onlab.packet.IPv6;
-import org.onlab.packet.Ip4Prefix;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.VlanId;
 import org.onlab.util.KryoNamespace;
@@ -88,7 +87,7 @@
 import org.onosproject.segmentrouting.storekey.NeighborSetNextObjectiveStoreKey;
 import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
 import org.onosproject.segmentrouting.storekey.SubnetAssignedVidStoreKey;
-import org.onosproject.segmentrouting.storekey.SubnetNextObjectiveStoreKey;
+import org.onosproject.segmentrouting.storekey.VlanNextObjectiveStoreKey;
 import org.onosproject.segmentrouting.storekey.XConnectStoreKey;
 import org.onosproject.segmentrouting.pwaas.L2TunnelHandler;
 import org.onosproject.store.serializers.KryoNamespaces;
@@ -102,8 +101,6 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Collections;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -113,7 +110,6 @@
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
 
 import static com.google.common.base.Preconditions.checkState;
 import static org.onlab.packet.Ethernet.TYPE_ARP;
@@ -224,17 +220,14 @@
     /**
      * Per device next objective ID store with (device id + subnet) as key.
      */
-    public EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
-            subnetNextObjStore = null;
+    public EventuallyConsistentMap<VlanNextObjectiveStoreKey, Integer>
+            vlanNextObjStore = null;
     /**
      * Per device next objective ID store with (device id + port) as key.
      */
     public EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
             portNextObjStore = null;
-    // Per device, per-subnet assigned-vlans store, with (device id + subnet
-    // IPv4 prefix) as key
-    private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
-            subnetVidStore = null;
+
     private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
     private EventuallyConsistentMap<String, Policy> policyStore = null;
 
@@ -298,14 +291,11 @@
      * Segment Routing App ID.
      */
     public static final String APP_NAME = "org.onosproject.segmentrouting";
-    /**
-     * The starting value of per-subnet VLAN ID assignment.
-     */
-    private static final short ASSIGNED_VLAN_START = 4093;
+
     /**
      * The default VLAN ID assigned to the interfaces without subnet config.
      */
-    public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
+    public static final VlanId INTERNAL_VLAN = VlanId.vlanId((short) 4094);
 
     @Activate
     protected void activate() {
@@ -321,11 +311,11 @@
                 .build();
         log.trace("Current size {}", nsNextObjStore.size());
 
-        log.debug("Creating EC map subnetnextobjectivestore");
-        EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
-                subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
-        subnetNextObjStore = subnetNextObjMapBuilder
-                .withName("subnetnextobjectivestore")
+        log.debug("Creating EC map vlannextobjectivestore");
+        EventuallyConsistentMapBuilder<VlanNextObjectiveStoreKey, Integer>
+                vlanNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
+        vlanNextObjStore = vlanNextObjMapBuilder
+                .withName("vlannextobjectivestore")
                 .withSerializer(createSerializer())
                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
                 .build();
@@ -355,14 +345,6 @@
                 .withTimestampProvider((k, v) -> new WallClockTimestamp())
                 .build();
 
-        EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
-            subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
-        subnetVidStore = subnetVidStoreMapBuilder
-                .withName("subnetvidstore")
-                .withSerializer(createSerializer())
-                .withTimestampProvider((k, v) -> new WallClockTimestamp())
-                .build();
-
         compCfgService.preSetProperty("org.onosproject.net.group.impl.GroupManager",
                                       "purgeOnDisconnection", "true");
         compCfgService.preSetProperty("org.onosproject.net.flow.impl.FlowRuleManager",
@@ -413,7 +395,7 @@
         return new KryoNamespace.Builder()
                 .register(KryoNamespaces.API)
                 .register(NeighborSetNextObjectiveStoreKey.class,
-                        SubnetNextObjectiveStoreKey.class,
+                        VlanNextObjectiveStoreKey.class,
                         SubnetAssignedVidStoreKey.class,
                         NeighborSet.class,
                         Tunnel.class,
@@ -450,11 +432,10 @@
         groupHandlerMap.clear();
 
         nsNextObjStore.destroy();
-        subnetNextObjStore.destroy();
+        vlanNextObjStore.destroy();
         portNextObjStore.destroy();
         tunnelStore.destroy();
         policyStore.destroy();
-        subnetVidStore.destroy();
         log.info("Stopped");
     }
 
@@ -539,69 +520,16 @@
     }
 
     /**
-     * Returns the vlan-id assigned to the subnet configured for a device.
-     * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
-     * if and only if this controller instance is the master for the device.
-     * <p>
-     * USAGE: The assigned vlans are meant to be applied to untagged packets on those
-     * switches/pipelines that need this functionality. These vids are meant
-     * to be used internally within a switch, and thus need to be unique only
-     * on a switch level. Note that packets never go out on the wire with these
-     * vlans. Currently, vlan ids are assigned from value 4093 down.
-     * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
-     * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
-     * per subnet.
+     * Returns untagged VLAN configured on given connect point.
      *
-     * @param deviceId switch dpid
-     * @param subnet IP prefix for which assigned vlan is desired
-     * @return VlanId assigned for the subnet on the device, or
-     *         null if no vlan assignment was found and this instance is not
-     *         the master for the device.
+     * @param connectPoint connect point
+     * @return untagged VLAN or null if not configured
      */
-    // TODO: We should avoid assigning VLAN IDs that are used by VLAN cross-connection.
-    public VlanId getSubnetAssignedVlanId(DeviceId deviceId, IpPrefix subnet) {
-        VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
-                                                        deviceId, subnet));
-        if (assignedVid != null) {
-            log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
-                    + "{}", subnet, deviceId, assignedVid);
-            return assignedVid;
-        }
-        //check mastership for the right to assign a vlan
-        if (!mastershipService.isLocalMaster(deviceId)) {
-            log.warn("This controller instance is not the master for device {}. "
-                    + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
-            return null;
-        }
-        // vlan assignment is expensive but done only once
-        // FIXME for now we will do assignment considering only the ipv4 subnet.
-        Set<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId)
-                .stream()
-                .filter(IpPrefix::isIp4)
-                .map(IpPrefix::getIp4Prefix)
-                .collect(Collectors.toSet());
-        Set<Short> assignedVlans = new HashSet<>();
-        Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
-        for (Ip4Prefix sub : configuredSubnets) {
-            VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
-                                                                        sub));
-            if (v != null) {
-                assignedVlans.add(v.toShort());
-            } else {
-                unassignedSubnets.add(sub);
-            }
-        }
-        short nextAssignedVlan = ASSIGNED_VLAN_START;
-        if (!assignedVlans.isEmpty()) {
-            nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
-        }
-        for (Ip4Prefix unsub : unassignedSubnets) {
-            subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
-                    VlanId.vlanId(nextAssignedVlan--));
-            log.info("Assigned vlan: {} to subnet: {} on device: {}",
-                    nextAssignedVlan + 1, unsub, deviceId);
-        }
-        return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
+    public VlanId getUntaggedVlanId(ConnectPoint connectPoint) {
+        return interfaceService.getInterfacesByPort(connectPoint).stream()
+                .filter(intf -> !intf.vlanUntagged().equals(VlanId.NONE))
+                .map(Interface::vlanUntagged)
+                .findFirst().orElse(null);
     }
 
     /**
@@ -648,19 +576,19 @@
 
     /**
      * Returns the next objective ID for the given subnet prefix. It is expected
+     * Returns the next objective ID for the given vlan id. It is expected
      * that the next-objective has been pre-created from configuration.
      *
      * @param deviceId Device ID
-     * @param prefix Subnet
+     * @param vlanId VLAN ID
      * @return next objective ID or -1 if it was not found
      */
-    public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
+    public int getVlanNextObjectiveId(DeviceId deviceId, VlanId vlanId) {
         if (groupHandlerMap.get(deviceId) != null) {
-            log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
-            return groupHandlerMap
-                    .get(deviceId).getSubnetNextObjectiveId(prefix);
+            log.trace("getVlanNextObjectiveId query in device {}", deviceId);
+            return groupHandlerMap.get(deviceId).getVlanNextObjectiveId(vlanId);
         } else {
-            log.warn("getSubnetNextObjectiveId query - groupHandler for "
+            log.warn("getVlanNextObjectiveId query - groupHandler for "
                     + "device {} not found", deviceId);
             return -1;
         }
@@ -963,7 +891,7 @@
             xConnectHandler.init(deviceId);
             cordConfigHandler.init(deviceId);
             DefaultGroupHandler groupHandler = groupHandlerMap.get(deviceId);
-            groupHandler.createGroupsFromSubnetConfig();
+            groupHandler.createGroupsFromVlanConfig();
             routingRulePopulator.populateSubnetBroadcastRule(deviceId);
         }
 
@@ -977,21 +905,16 @@
                 .forEach(entry -> {
                     nsNextObjStore.remove(entry.getKey());
                 });
-        subnetNextObjStore.entrySet().stream()
+        vlanNextObjStore.entrySet().stream()
                 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
                 .forEach(entry -> {
-                    subnetNextObjStore.remove(entry.getKey());
+                    vlanNextObjStore.remove(entry.getKey());
                 });
         portNextObjStore.entrySet().stream()
                 .filter(entry -> entry.getKey().deviceId().equals(device.id()))
                 .forEach(entry -> {
                     portNextObjStore.remove(entry.getKey());
                 });
-        subnetVidStore.entrySet().stream()
-                .filter(entry -> entry.getKey().deviceId().equals(device.id()))
-                .forEach(entry -> {
-                    subnetVidStore.remove(entry.getKey());
-                });
         groupHandlerMap.remove(device.id());
         defaultRoutingHandler.purgeEcmpGraph(device.id());
         mcastHandler.removeDevice(device.id());
@@ -1028,29 +951,30 @@
         // to switch ports, link-events should take care of any re-routing or
         // group editing necessary for port up/down. Here we only process edge ports
         // that are already configured.
-        Ip4Prefix configuredSubnet = deviceConfiguration.getPortIPv4Subnet(device.id(),
-                                                                           port.number());
-        if (configuredSubnet == null) {
+        VlanId untaggedVlan = getUntaggedVlanId(new ConnectPoint(device.id(), port.number()));
+        VlanId vlanId = (untaggedVlan != null) ? untaggedVlan : INTERNAL_VLAN;
+
+        if (vlanId.equals(INTERNAL_VLAN)) {
             log.debug("Not handling port updated event for unconfigured port "
                     + "dev/port: {}/{}", device.id(), port.number());
             return;
         }
-        processEdgePort(device, port, configuredSubnet);
+        processEdgePort(device, port, vlanId);
     }
 
-    private void processEdgePort(Device device, Port port, Ip4Prefix subnet) {
+    private void processEdgePort(Device device, Port port, VlanId vlanId) {
         boolean portUp = port.isEnabled();
         if (portUp) {
             log.info("Device:EdgePort {}:{} is enabled in subnet: {}", device.id(),
-                     port.number(), subnet);
+                     port.number(), vlanId);
         } else {
             log.info("Device:EdgePort {}:{} is disabled in subnet: {}", device.id(),
-                     port.number(), subnet);
+                     port.number(), vlanId);
         }
 
         DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
         if (groupHandler != null) {
-            groupHandler.processEdgePort(port.number(), subnet, portUp);
+            groupHandler.processEdgePort(port.number(), vlanId, portUp);
         } else {
             log.warn("Group handler not found for dev:{}. Not handling edge port"
                     + " {} event for port:{}", device.id(),