CORD-77 Dynamic Access Agent Config

This commit depends on https://gerrit.opencord.org/#/c/56/

Change-Id: I6084621c36046ae8b6262cab52c49825d3e0d0d1
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/CordConfigHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/CordConfigHandler.java
new file mode 100644
index 0000000..6710330
--- /dev/null
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/CordConfigHandler.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2016-present 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.segmentrouting;
+
+import com.google.common.collect.ImmutableSet;
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultHost;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.provider.ProviderId;
+import org.opencord.cordconfig.CordConfigEvent;
+import org.opencord.cordconfig.access.AccessAgentData;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Optional;
+
+/**
+ * Handles access agent config event which is required for CORD integration.
+ */
+public class CordConfigHandler {
+    private static Logger log = LoggerFactory.getLogger(CordConfigHandler.class);
+    private final SegmentRoutingManager srManager;
+
+    /**
+     * Constructs the CordConfigHandler.
+     *
+     * @param srManager Segment Routing manager
+     */
+    public CordConfigHandler(SegmentRoutingManager srManager) {
+        this.srManager = srManager;
+    }
+
+    /**
+     * Read initial access agent config for given device.
+     *
+     * @param deviceId ID of the device to be initialized
+     */
+    public void init(DeviceId deviceId) {
+        // Try to read access agent config
+        Optional<AccessAgentData> accessAgent =
+                srManager.cordConfigService.getAccessAgent(deviceId);
+
+        if (!accessAgent.isPresent()) {
+            log.debug("No access agent config on {}. Skip.", deviceId);
+            return;
+        }
+
+        processAccessAgentAdded(accessAgent.get());
+    }
+
+    // TODO javadoc
+    protected void processAccessAgentAddedEvent(CordConfigEvent event) {
+        log.debug("processAccessAgentAdded: {}, {}", event.subject(), event.prevSubject());
+        processAccessAgentAdded((AccessAgentData) event.subject());
+    }
+
+    protected void processAccessAgentUpdatedEvent(CordConfigEvent event) {
+        log.debug("processAccessAgentUpdated: {}, {}", event.subject(), event.prevSubject());
+        processAccessAgentRemoved((AccessAgentData) event.prevSubject());
+        processAccessAgentAdded((AccessAgentData) event.subject());
+    }
+
+    protected void processAccessAgentRemovedEvent(CordConfigEvent event) {
+        log.debug("processAccessAgentRemoved: {}, {}", event.subject(), event.prevSubject());
+        processAccessAgentRemoved((AccessAgentData) event.prevSubject());
+    }
+
+    protected void processAccessAgentAdded(AccessAgentData accessAgentData) {
+        if (!srManager.mastershipService.isLocalMaster(accessAgentData.deviceId())) {
+            log.debug("Not the master of {}. Abort.", accessAgentData.deviceId());
+            return;
+        }
+
+        // Do not proceed if vtn location is missing
+        if (!accessAgentData.getVtnLocation().isPresent()) {
+            log.warn("accessAgentData does not contain vtn location. Abort.");
+            return;
+        }
+
+        MacAddress agentMac = accessAgentData.getAgentMac();
+        ConnectPoint agentLocation = accessAgentData.getVtnLocation().get();
+
+        // Do not proceed if agent port doesn't have subnet configured
+        Ip4Prefix agentSubnet = srManager.deviceConfiguration
+                .getPortSubnet(agentLocation.deviceId(), agentLocation.port());
+        if (agentSubnet == null) {
+            log.warn("Agent port does not have subnet configuration. Abort.");
+            return;
+        }
+
+        // Add host information for agent
+        log.info("push host info for agent {}", agentMac);
+        srManager.hostHandler.processHostAdded(createHost(agentMac, agentLocation));
+
+        accessAgentData.getOltMacInfo().forEach((connectPoint, macAddress) -> {
+            // Do not proceed if olt port has subnet configured
+            Ip4Prefix oltSubnet = srManager.deviceConfiguration
+                    .getPortSubnet(connectPoint.deviceId(), connectPoint.port());
+            if (oltSubnet != null) {
+                log.warn("OLT port has subnet configuration. Abort.");
+                return;
+            }
+
+            // Add olt to the subnet of agent
+            log.info("push subnet for olt {}", agentSubnet);
+            srManager.deviceConfiguration.addSubnet(connectPoint, agentSubnet);
+            srManager.routingRulePopulator.populateRouterMacVlanFilters(connectPoint.deviceId());
+
+            // Add host information for olt
+            log.info("push host info for olt {}", macAddress);
+            srManager.hostHandler.processHostAdded(createHost(macAddress, connectPoint));
+        });
+    }
+
+    protected void processAccessAgentRemoved(AccessAgentData accessAgentData) {
+        if (!srManager.mastershipService.isLocalMaster(accessAgentData.deviceId())) {
+            log.debug("Not the master of {}. Abort.", accessAgentData.deviceId());
+            return;
+        }
+
+        // Do not proceed if vtn location is missing
+        if (!accessAgentData.getVtnLocation().isPresent()) {
+            log.warn("accessAgentData does not contain vtn location. Abort.");
+            return;
+        }
+
+        MacAddress agentMac = accessAgentData.getAgentMac();
+        ConnectPoint agentLocation = accessAgentData.getVtnLocation().get();
+
+        // Do not proceed if olt port doesn't have subnet configured
+        Ip4Prefix agentSubnet = srManager.deviceConfiguration
+                .getPortSubnet(agentLocation.deviceId(), agentLocation.port());
+        if (agentSubnet == null) {
+            log.warn("Agent port does not have subnet configuration. Abort.");
+            return;
+        }
+
+        // Remove host information for agent
+        log.info("delete host info for agent {}", agentMac);
+        srManager.hostHandler.processHostRemoved(createHost(agentMac, agentLocation));
+
+        accessAgentData.getOltMacInfo().forEach((connectPoint, macAddress) -> {
+            // Do not proceed if agent port doesn't have subnet configured
+            Ip4Prefix oltSubnet = srManager.deviceConfiguration
+                    .getPortSubnet(connectPoint.deviceId(), connectPoint.port());
+            if (oltSubnet == null) {
+                log.warn("OLT port does not have subnet configuration. Abort.");
+                return;
+            }
+
+            // Remove host information for olt
+            log.info("delete host info for olt {}", macAddress);
+            srManager.hostHandler.processHostRemoved(createHost(macAddress, connectPoint));
+
+            // Remove olt to the subnet of agent
+            log.info("delete subnet for olt {}", agentSubnet);
+            srManager.deviceConfiguration.removeSubnet(connectPoint, agentSubnet);
+            srManager.routingRulePopulator.populateRouterMacVlanFilters(connectPoint.deviceId());
+        });
+    }
+
+    private Host createHost(MacAddress macAddress, ConnectPoint location) {
+        return new DefaultHost(
+                new ProviderId("host", "org.onosproject.segmentrouting"),
+                HostId.hostId(macAddress),
+                macAddress,
+                VlanId.NONE,
+                new HostLocation(location, System.currentTimeMillis()),
+                ImmutableSet.of());
+    }
+}