ONOS-685: Network Configuration Manager support for Segment Routing application

Change-Id: Ia15bfd24559dd5542633c8b76d500b2d31362340
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
index 17cfd96..0dfb3fd 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
@@ -1,171 +1,218 @@
 package org.onosproject.segmentrouting;
 
 import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
-import org.onosproject.grouphandler.DeviceProperties;
+import org.onosproject.segmentrouting.grouphandler.DeviceProperties;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.segmentrouting.config.NetworkConfig.SwitchConfig;
+import org.onosproject.segmentrouting.config.NetworkConfigManager;
+import org.onosproject.segmentrouting.config.SegmentRouterConfig;
+import org.onosproject.segmentrouting.config.SegmentRouterConfig.Subnet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Arrays;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+/**
+ * Segment Routing configuration component that reads the
+ * segment routing related configuration from Network Configuration Manager
+ * component and organizes in more accessible formats.
+ *
+ * TODO: Merge multiple Segment Routing configuration wrapper classes into one.
+ */
 public class DeviceConfiguration implements DeviceProperties {
 
     private static final Logger log = LoggerFactory
             .getLogger(DeviceConfiguration.class);
-    private final List<Integer> allSegmentIds =
-            Arrays.asList(101, 102, 103, 104, 105, 106);
-    private HashMap<DeviceId, Integer> deviceSegmentIdMap =
-            new HashMap<DeviceId, Integer>() {
-                {
-                    put(DeviceId.deviceId("of:0000000000000001"), 101);
-                    put(DeviceId.deviceId("of:0000000000000002"), 102);
-                    put(DeviceId.deviceId("of:0000000000000003"), 103);
-                    put(DeviceId.deviceId("of:0000000000000004"), 104);
-                    put(DeviceId.deviceId("of:0000000000000005"), 105);
-                    put(DeviceId.deviceId("of:0000000000000006"), 106);
-                }
-            };
-    private final HashMap<DeviceId, MacAddress> deviceMacMap =
-            new HashMap<DeviceId, MacAddress>() {
-                {
-                    put(DeviceId.deviceId("of:0000000000000001"),
-                            MacAddress.valueOf("00:00:00:00:00:01"));
-                    put(DeviceId.deviceId("of:0000000000000002"),
-                            MacAddress.valueOf("00:00:00:00:00:02"));
-                    put(DeviceId.deviceId("of:0000000000000003"),
-                            MacAddress.valueOf("00:00:00:00:00:03"));
-                    put(DeviceId.deviceId("of:0000000000000004"),
-                            MacAddress.valueOf("00:00:00:00:00:04"));
-                    put(DeviceId.deviceId("of:0000000000000005"),
-                            MacAddress.valueOf("00:00:00:00:00:05"));
-                    put(DeviceId.deviceId("of:0000000000000006"),
-                            MacAddress.valueOf("00:00:00:00:00:06"));
-                }
-            };
+    private final List<Integer> allSegmentIds = new ArrayList<Integer>();
+    private final HashMap<DeviceId, SegmentRouterInfo> deviceConfigMap = new HashMap<>();
+    private final NetworkConfigManager configService;
 
-    private final HashMap<DeviceId, Ip4Address> deviceIpMap =
-            new HashMap<DeviceId, Ip4Address>() {
-                {
-                    put(DeviceId.deviceId("of:0000000000000001"),
-                            Ip4Address.valueOf("192.168.0.1"));
-                    put(DeviceId.deviceId("of:0000000000000002"),
-                            Ip4Address.valueOf("192.168.0.2"));
-                    put(DeviceId.deviceId("of:0000000000000003"),
-                            Ip4Address.valueOf("192.168.0.3"));
-                    put(DeviceId.deviceId("of:0000000000000004"),
-                            Ip4Address.valueOf("192.168.0.4"));
-                    put(DeviceId.deviceId("of:0000000000000005"),
-                            Ip4Address.valueOf("192.168.0.5"));
-                    put(DeviceId.deviceId("of:0000000000000006"),
-                            Ip4Address.valueOf("192.168.0.6"));
-                }
-            };
+    private class SegmentRouterInfo {
+        int nodeSid;
+        DeviceId deviceId;
+        Ip4Address ip;
+        MacAddress mac;
+        boolean isEdge;
+        HashMap<PortNumber, Ip4Address> gatewayIps;
+        HashMap<PortNumber, Ip4Prefix> subnets;
+    }
 
+    /**
+     * Constructor. Reads all the configuration for all devices of type
+     * Segment Router and organizes into various maps for easier access.
+     *
+     * @param configService handle to network configuration manager
+     * component from where the relevant configuration is retrieved.
+     */
+    public DeviceConfiguration(NetworkConfigManager configService) {
+        this.configService = checkNotNull(configService);
+        List<SwitchConfig> allSwitchCfg =
+                this.configService.getConfiguredAllowedSwitches();
+        for (SwitchConfig cfg : allSwitchCfg) {
+            if (!(cfg instanceof SegmentRouterConfig)) {
+                continue;
+            }
+            SegmentRouterInfo info = new SegmentRouterInfo();
+            info.nodeSid = ((SegmentRouterConfig) cfg).getNodeSid();
+            info.deviceId = ((SegmentRouterConfig) cfg).getDpid();
+            info.mac = MacAddress.valueOf(((
+                    SegmentRouterConfig) cfg).getRouterMac());
+            String routerIp = ((SegmentRouterConfig) cfg).getRouterIp();
+            Ip4Prefix prefix = checkNotNull(IpPrefix.valueOf(routerIp).getIp4Prefix());
+            info.ip = prefix.address();
+            info.isEdge = ((SegmentRouterConfig) cfg).isEdgeRouter();
+            info.subnets = new HashMap<>();
+            info.gatewayIps = new HashMap<PortNumber, Ip4Address>();
+            for (Subnet s: ((SegmentRouterConfig) cfg).getSubnets()) {
+                info.subnets.put(PortNumber.portNumber(s.getPortNo()),
+                                 Ip4Prefix.valueOf(s.getSubnetIp()));
+                String gatewayIp = s.getSubnetIp().
+                        substring(0, s.getSubnetIp().indexOf('/'));
+                info.gatewayIps.put(PortNumber.portNumber(s.getPortNo()),
+                                    Ip4Address.valueOf(gatewayIp));
+            }
+            this.deviceConfigMap.put(info.deviceId, info);
+            this.allSegmentIds.add(info.nodeSid);
+        }
+    }
+
+    /**
+     * Returns the segment id of a segment router.
+     *
+     * @param deviceId device identifier
+     * @return segment id
+     */
     @Override
     public int getSegmentId(DeviceId deviceId) {
-        if (deviceSegmentIdMap.get(deviceId) != null) {
+        if (deviceConfigMap.get(deviceId) != null) {
             log.debug("getSegmentId for device{} is {}",
                     deviceId,
-                    deviceSegmentIdMap.get(deviceId));
-            return deviceSegmentIdMap.get(deviceId);
+                    deviceConfigMap.get(deviceId).nodeSid);
+            return deviceConfigMap.get(deviceId).nodeSid;
         } else {
             throw new IllegalStateException();
         }
     }
 
+    /**
+     * Returns the segment id of a segment router given its mac address.
+     *
+     * @param routerMac router mac address
+     * @return segment id
+     */
+    public int getSegmentId(MacAddress routerMac) {
+        for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
+                    deviceConfigMap.entrySet()) {
+            if (entry.getValue().mac.equals(routerMac)) {
+                return entry.getValue().nodeSid;
+            }
+        }
 
+        return -1;
+    }
+
+    /**
+     * Returns the segment id of a segment router given its router ip address.
+     *
+     * @param routerAddress router ip address
+     * @return segment id
+     */
+    public int getSegmentId(Ip4Address routerAddress) {
+        for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
+            deviceConfigMap.entrySet()) {
+            if (entry.getValue().ip.equals(routerAddress)) {
+                return entry.getValue().nodeSid;
+            }
+        }
+
+        return -1;
+    }
+
+    /**
+     * Returns the router mac of a segment router.
+     *
+     * @param deviceId device identifier
+     * @return router mac address
+     */
     @Override
     public MacAddress getDeviceMac(DeviceId deviceId) {
-        if (deviceMacMap.get(deviceId) != null) {
+        if (deviceConfigMap.get(deviceId) != null) {
             log.debug("getDeviceMac for device{} is {}",
                     deviceId,
-                    deviceMacMap.get(deviceId));
-            return deviceMacMap.get(deviceId);
+                    deviceConfigMap.get(deviceId).mac);
+            return deviceConfigMap.get(deviceId).mac;
         } else {
             throw new IllegalStateException();
         }
     }
 
-
-    @Override
-    public boolean isEdgeDevice(DeviceId deviceId) {
-        if (deviceId.equals(DeviceId.deviceId("of:0000000000000001"))
-                || deviceId.equals(DeviceId.deviceId("of:0000000000000006"))) {
-            return true;
+    /**
+     * Returns the router ip address of a segment router.
+     *
+     * @param deviceId device identifier
+     * @return router ip address
+     */
+    public Ip4Address getRouterIp(DeviceId deviceId) {
+        if (deviceConfigMap.get(deviceId) != null) {
+            log.debug("getDeviceIp for device{} is {}",
+                    deviceId,
+                    deviceConfigMap.get(deviceId).ip);
+            return deviceConfigMap.get(deviceId).ip;
+        } else {
+            throw new IllegalStateException();
         }
-
-        return false;
     }
 
+    /**
+     * Indicates if the segment router is a edge router or
+     * a transit/back bone router.
+     *
+     * @param deviceId device identifier
+     * @return boolean
+     */
+    @Override
+    public boolean isEdgeDevice(DeviceId deviceId) {
+        if (deviceConfigMap.get(deviceId) != null) {
+            log.debug("isEdgeDevice for device{} is {}",
+                    deviceId,
+                    deviceConfigMap.get(deviceId).isEdge);
+            return deviceConfigMap.get(deviceId).isEdge;
+        } else {
+            throw new IllegalStateException();
+        }
+    }
+
+    /**
+     * Returns the segment ids of all configured segment routers.
+     *
+     * @return list of segment ids
+     */
     @Override
     public List<Integer> getAllDeviceSegmentIds() {
         return allSegmentIds;
     }
 
-
     /**
-     * Returns Segment ID for the router with the MAC address given.
+     * Returns the device identifier or data plane identifier (dpid)
+     * of a segment router given its segment id.
      *
-     * @param targetMac Mac address for the router
-     * @return Segment ID for the router with the MAC address
-     */
-    public int getSegmentId(MacAddress targetMac) {
-        for (Map.Entry<DeviceId, MacAddress> entry: deviceMacMap.entrySet()) {
-            if (entry.getValue().equals(targetMac)) {
-                return deviceSegmentIdMap.get(entry.getKey());
-            }
-        }
-
-        return -1;
-    }
-
-    /**
-     * Returns Segment ID for the router withe IP address given.
-     *
-     * @param targetAddress IP address of the router
-     * @return Segment ID for the router with the IP address
-     */
-    public int getSegmentId(Ip4Address targetAddress) {
-        for (Map.Entry<DeviceId, Ip4Address> entry: deviceIpMap.entrySet()) {
-            if (entry.getValue().equals(targetAddress)) {
-                return deviceSegmentIdMap.get(entry.getKey());
-            }
-        }
-
-        return -1;
-    }
-
-    /**
-     * Returns Router IP address for the router with the device ID given.
-     *
-     * @param deviceId device ID of the router
-     * @return IP address of the router
-     */
-    public Ip4Address getRouterIp(DeviceId deviceId) {
-        if (deviceIpMap.get(deviceId) != null) {
-            log.debug("getDeviceIp for device{} is {}",
-                    deviceId,
-                    deviceIpMap.get(deviceId));
-            return deviceIpMap.get(deviceId);
-        } else {
-            throw new IllegalStateException();
-        }
-    }
-
-    /**
-     * Returns the Device ID of the router with the Segment ID given.
-     *
-     * @param sid Segment ID of the router
-     * @return Device ID of the router
+     * @param sid segment id
+     * @return deviceId device identifier
      */
     public DeviceId getDeviceId(int sid) {
-        for (Map.Entry<DeviceId, Integer> entry: deviceSegmentIdMap.entrySet()) {
-            if (entry.getValue() == sid) {
-                return entry.getKey();
+        for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
+            deviceConfigMap.entrySet()) {
+            if (entry.getValue().nodeSid == sid) {
+                return entry.getValue().deviceId;
             }
         }
 
@@ -173,18 +220,97 @@
     }
 
     /**
-     * Returns the Device ID of the router with the IP address given.
+     * Returns the device identifier or data plane identifier (dpid)
+     * of a segment router given its router ip address.
      *
-     * @param ipAddress IP address of the router
-     * @return Device ID of the router
+     * @param ipAddress router ip address
+     * @return deviceId device identifier
      */
     public DeviceId getDeviceId(Ip4Address ipAddress) {
-        for (Map.Entry<DeviceId, Ip4Address> entry: deviceIpMap.entrySet()) {
-            if (entry.getValue().equals(ipAddress)) {
-                return entry.getKey();
+        for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
+            deviceConfigMap.entrySet()) {
+            if (entry.getValue().ip.equals(ipAddress)) {
+                return entry.getValue().deviceId;
             }
         }
 
         return null;
     }
+
+    /**
+     * Returns the configured subnet gateway ip addresses for a segment router.
+     *
+     * @param deviceId device identifier
+     * @return list of ip addresses
+     */
+    public List<Ip4Address> getSubnetGatewayIps(DeviceId deviceId) {
+        if (deviceConfigMap.get(deviceId) != null) {
+            log.debug("getSubnetGatewayIps for device{} is {}",
+                    deviceId,
+                    deviceConfigMap.get(deviceId).gatewayIps.values());
+            return new ArrayList<Ip4Address>(deviceConfigMap.
+                    get(deviceId).gatewayIps.values());
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Returns the configured subnet prefixes for a segment router.
+     *
+     * @param deviceId device identifier
+     * @return list of ip prefixes
+     */
+    public List<Ip4Prefix> getSubnets(DeviceId deviceId) {
+        if (deviceConfigMap.get(deviceId) != null) {
+            log.debug("getSubnets for device{} is {}",
+                    deviceId,
+                    deviceConfigMap.get(deviceId).subnets.values());
+            return new ArrayList<Ip4Prefix>(deviceConfigMap.
+                    get(deviceId).subnets.values());
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Returns the router ip address of segment router that has the
+     * specified ip address in its subnets.
+     *
+     * @param destIpAddress target ip address
+     * @return router ip address
+     */
+    public Ip4Address getRouterIpAddressForASubnetHost(Ip4Address destIpAddress) {
+        for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
+                    deviceConfigMap.entrySet()) {
+            for (Ip4Prefix prefix:entry.getValue().subnets.values()) {
+                if (prefix.contains(destIpAddress)) {
+                    return entry.getValue().ip;
+                }
+            }
+        }
+
+        log.debug("No router was found for {}", destIpAddress);
+        return null;
+    }
+
+    /**
+     * Returns the router mac address of segment router that has the
+     * specified ip address as one of its subnet gateway ip address.
+     *
+     * @param gatewayIpAddress router gateway ip address
+     * @return router mac address
+     */
+    public MacAddress getRouterMacForAGatewayIp(Ip4Address gatewayIpAddress) {
+        for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
+                deviceConfigMap.entrySet()) {
+            if (entry.getValue().gatewayIps.
+                    values().contains(gatewayIpAddress)) {
+                return entry.getValue().mac;
+            }
+        }
+
+        log.debug("Cannot find a router for {}", gatewayIpAddress);
+        return null;
+    }
 }