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());
+ }
+}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/HostHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/HostHandler.java
index d5c93fd..c82b675 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/HostHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/HostHandler.java
@@ -71,15 +71,15 @@
if (!deviceId.equals(devId)) {
return;
}
- processHostAddedEventInternal(host);
+ processHostAdded(host);
});
}
protected void processHostAddedEvent(HostEvent event) {
- processHostAddedEventInternal(event.subject());
+ processHostAdded(event.subject());
}
- private void processHostAddedEventInternal(Host host) {
+ protected void processHostAdded(Host host) {
MacAddress mac = host.mac();
VlanId vlanId = host.vlan();
HostLocation location = host.location();
@@ -116,15 +116,19 @@
}
protected void processHostRemoveEvent(HostEvent event) {
- MacAddress mac = event.subject().mac();
- VlanId vlanId = event.subject().vlan();
- HostLocation location = event.subject().location();
+ processHostRemoved(event.subject());
+ }
+
+ protected void processHostRemoved(Host host) {
+ MacAddress mac = host.mac();
+ VlanId vlanId = host.vlan();
+ HostLocation location = host.location();
DeviceId deviceId = location.deviceId();
PortNumber port = location.port();
- Set<IpAddress> ips = event.subject().ipAddresses();
+ Set<IpAddress> ips = host.ipAddresses();
log.debug("Host {}/{} is removed from {}:{}", mac, vlanId, deviceId, port);
- if (accepted(event.subject())) {
+ if (accepted(host)) {
// Revoke bridging table entry
ForwardingObjective.Builder fob =
hostFwdObjBuilder(deviceId, mac, vlanId, port);
@@ -133,9 +137,9 @@
return;
}
ObjectiveContext context = new DefaultObjectiveContext(
- (objective) -> log.debug("Host rule for {} revoked", event.subject()),
+ (objective) -> log.debug("Host rule for {} revoked", host),
(objective, error) ->
- log.warn("Failed to revoke host rule for {}: {}", event.subject(), error));
+ log.warn("Failed to revoke host rule for {}: {}", host, error));
flowObjectiveService.forward(deviceId, fob.remove(context));
// Revoke IP table entry
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 2b87fca..c115704 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -82,6 +82,9 @@
import org.onosproject.store.service.EventuallyConsistentMapBuilder;
import org.onosproject.store.service.StorageService;
import org.onosproject.store.service.WallClockTimestamp;
+import org.opencord.cordconfig.CordConfigEvent;
+import org.opencord.cordconfig.CordConfigListener;
+import org.opencord.cordconfig.CordConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -147,6 +150,9 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected TopologyService topologyService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CordConfigService cordConfigService;
+
protected ArpHandler arpHandler = null;
protected IcmpHandler icmpHandler = null;
protected IpHandler ipHandler = null;
@@ -163,11 +169,13 @@
private AppConfigHandler appCfgHandler = null;
protected XConnectHandler xConnectHandler = null;
private McastHandler mcastHandler = null;
- private HostHandler hostHandler = null;
+ protected HostHandler hostHandler = null;
+ private CordConfigHandler cordConfigHandler = null;
private InternalEventHandler eventHandler = new InternalEventHandler();
private final InternalHostListener hostListener = new InternalHostListener();
private final InternalConfigListener cfgListener = new InternalConfigListener(this);
private final InternalMcastListener mcastListener = new InternalMcastListener();
+ private final InternalCordConfigListener cordConfigListener = new InternalCordConfigListener();
private ScheduledExecutorService executorService = Executors
.newScheduledThreadPool(1);
@@ -324,6 +332,7 @@
xConnectHandler = new XConnectHandler(this);
mcastHandler = new McastHandler(this);
hostHandler = new HostHandler(this);
+ cordConfigHandler = new CordConfigHandler(this);
cfgService.addListener(cfgListener);
cfgService.registerConfigFactory(deviceConfigFactory);
@@ -335,6 +344,7 @@
linkService.addListener(linkListener);
deviceService.addListener(deviceListener);
multicastRouteService.addListener(mcastListener);
+ cordConfigService.addListener(cordConfigListener);
// Request ARP packet-in
TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
@@ -379,6 +389,7 @@
linkService.removeListener(linkListener);
deviceService.removeListener(deviceListener);
multicastRouteService.removeListener(mcastListener);
+ cordConfigService.removeListener(cordConfigListener);
processor = null;
linkListener = null;
@@ -394,7 +405,6 @@
log.info("Stopped");
}
-
@Override
public List<Tunnel> getTunnels() {
return tunnelHandler.getTunnels();
@@ -818,6 +828,7 @@
if (mastershipService.isLocalMaster(deviceId)) {
hostHandler.readInitialHosts(deviceId);
xConnectHandler.init(deviceId);
+ cordConfigHandler.init(deviceId);
DefaultGroupHandler groupHandler = groupHandlerMap.get(deviceId);
groupHandler.createGroupsFromSubnetConfig();
routingRulePopulator.populateSubnetBroadcastRule(deviceId);
@@ -1000,4 +1011,26 @@
}
}
}
+
+ private class InternalCordConfigListener implements CordConfigListener {
+ @Override
+ public void event(CordConfigEvent event) {
+ switch (event.type()) {
+ case ACCESS_AGENT_ADDED:
+ cordConfigHandler.processAccessAgentAddedEvent(event);
+ break;
+ case ACCESS_AGENT_UPDATED:
+ cordConfigHandler.processAccessAgentUpdatedEvent(event);
+ break;
+ case ACCESS_AGENT_REMOVED:
+ cordConfigHandler.processAccessAgentRemovedEvent(event);
+ break;
+ case ACCESS_DEVICE_ADDED:
+ case ACCESS_DEVICE_UPDATED:
+ case ACCESS_DEVICE_REMOVED:
+ default:
+ break;
+ }
+ }
+ }
}