Completed Deactivation method and implemented Session Deletion on CP reconnect
diff --git a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/FpcRpcManager.java b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/FpcRpcManager.java
index 3a8c2f9..f29b1a2 100644
--- a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/FpcRpcManager.java
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/FpcRpcManager.java
@@ -175,8 +175,16 @@
protected void deactivate() {
deviceService.removeListener(listener);
rpcRegistry.unregisterRpcService(this);
+
+ CLIENT_INFO.keySet().forEach(this::deleteSessions);
CLIENT_INFO.clear();
+ CLIENT_CONTEXTS_INFO.clear();
TENANT_INFO.clear();
+
+ deleteNode(connections);
+ deleteNode(fpcAgents);
+ deleteNode(tenants);
+
log.info("FPC RPC Service Stopped");
}
@@ -299,7 +307,7 @@
Ip4Address s1USgwIpv4Dl = Ip4Address.valueOf(context.dl().tunnelLocalAddress().toString()),
s1UEnodebIpv4Dl = Ip4Address.valueOf(context.dl().tunnelRemoteAddress().toString()),
- s1UEnodebIpv4Ul = Ip4Address.valueOf(context.ul().tunnelLocalAddress().toString()),
+ s1UEnodebIpv4Ul = Ip4Address.valueOf(context.ul().tunnelLocalAddress().toString()),
s1USgwIpv4Ul = Ip4Address.valueOf(context.ul().tunnelRemoteAddress().toString());
long clientId = clientInfo.clientId().fpcIdentity().union().int64(),
@@ -339,6 +347,11 @@
.build();
createNode(convertContext, modelObjectId);
cacheManager.contextsCache.put(convertContext.contextId(), Optional.of(convertContext));
+ HashSet<FpcContextId> contexts = CLIENT_CONTEXTS_INFO.getOrDefault(
+ clientInfo.clientId(),
+ Sets.newHashSet()
+ );
+ contexts.add(context.contextId());
}));
// FIXME why downlink is in session while uplink is not?
@@ -359,6 +372,11 @@
.build();
createNode(convertContext, modelObjectId);
cacheManager.contextsCache.put(convertContext.contextId(), Optional.of(convertContext));
+ HashSet<FpcContextId> contexts = CLIENT_CONTEXTS_INFO.getOrDefault(
+ clientInfo.clientId(),
+ Sets.newHashSet()
+ );
+ contexts.add(context.contextId());
}));
}
} else if (commands.contains("indirect-forward")) {
@@ -468,13 +486,13 @@
Ip4Address s1USgwIpv4Dl = Ip4Address.valueOf(context.dl().tunnelLocalAddress().toString()),
s1UEnodebIpv4Dl = Ip4Address.valueOf(context.dl().tunnelRemoteAddress().toString()),
- s1UEnodebIpv4Ul = Ip4Address.valueOf(context.ul().tunnelLocalAddress().toString()),
+ s1UEnodebIpv4Ul = Ip4Address.valueOf(context.ul().tunnelLocalAddress().toString()),
s1USgwIpv4Ul = Ip4Address.valueOf(context.ul().tunnelRemoteAddress().toString());
long s1UEnbGtpuTeidDl = ((ThreegppTunnel) context.dl().mobilityTunnelParameters()
.mobprofileParameters()).tunnelIdentifier(),
- s1UEnbGtpuTeidUl = ((ThreegppTunnel) context.ul().mobilityTunnelParameters()
- .mobprofileParameters()).tunnelIdentifier(),
+ s1UEnbGtpuTeidUl = ((ThreegppTunnel) context.ul().mobilityTunnelParameters()
+ .mobprofileParameters()).tunnelIdentifier(),
cId = clientInfo.clientId().fpcIdentity().union().int64(),
contextId = context.contextId().fpcIdentity().union().int64();
@@ -549,86 +567,67 @@
return configureOutput;
}
- @Override
- public DefaultConfigureOutput configureDelete(
- DeleteOrQuery delete,
- DefaultRegisterClientInput clientInfo,
- OpIdentifier operationId
- ) throws Exception {
- DefaultConfigureOutput configureOutput = new DefaultConfigureOutput();
+ public Collection<Callable<Object>> deleteSessions(ClientIdentifier clientIdentifier) {
Collection<Callable<Object>> tasks = new ArrayList<>();
- // get client's tenant.
- FpcIdentity tenantId = clientInfo.tenantId();
- // get cache for specific tenant.
- CacheManager cacheManager = CacheManager.getInstance(tenantId);
- DefaultDeleteSuccess defaultDeleteSuccess = new DefaultDeleteSuccess();
- for (Targets target : delete.targets()) {
- defaultDeleteSuccess.addToTargets(target);
- // parse context id.
- String targetStr = target.target().toString(),
- s = StringUtils.substringBetween(targetStr, "contexts=", "/"),
- trgt = s != null ? s : StringUtils.substringAfter(targetStr, "contexts=");
+ try {
+ FpcIdentity tenantId = CLIENT_INFO.get(clientIdentifier).tenantId();
+ CacheManager cacheManager = CacheManager.getInstance(tenantId);
- // find context that this target is about.
- FpcContextId fpcContextId = FpcContextId.of(FpcIdentity.fromString(trgt));
- Optional<DefaultContexts> defaultContexts = CacheManager.getInstance(tenantId)
- .contextsCache.get(fpcContextId);
- if (!defaultContexts.isPresent()) {
- throw new RuntimeException("Context doesn't exist. Please issue create operation..");
- }
+ for (FpcContextId fpcContextId : CLIENT_CONTEXTS_INFO.get(clientIdentifier)) {
+ Optional<DefaultContexts> defaultContexts = null;
- log.debug("handling configure-delete {}", targetStr);
+ defaultContexts = CacheManager.getInstance(tenantId).contextsCache.get(fpcContextId);
- DefaultContexts context = defaultContexts.get();
- for (Dpns dpn : context.dpns()) {
- Optional<DefaultDpns> optionalDpn = cacheManager.dpnsCache.get(dpn.dpnId());
- // check if dpns exists and if there is a DPN registered for the wanted identifier.
- if (!optionalDpn.isPresent()) {
- // throw exception if DPN ID is not registered.
- throw new RuntimeException("DPN ID is not registered to the topology.");
+ if (!defaultContexts.isPresent()) {
+ throw new RuntimeException("Context doesn't exist. Please issue create operation..");
}
- final DpnCommunicationService dpnCommunicationService;
- Class<? extends FpcDpnControlProtocol> controlProtocol = optionalDpn.get().controlProtocol();
- if (controlProtocol.isAssignableFrom(ZmqDpnControlProtocol.class)) {
- dpnCommunicationService = DpnNgicCommunicator.getInstance();
- } else if (controlProtocol.isAssignableFrom(P4DpnControlProtocol.class)) {
- DpnP4Communicator instance = DpnP4Communicator.getInstance();
- dpnCommunicationService = instance;
- instance.setDeviceId(
- DeviceId.deviceId(optionalDpn.get().dpnId().toString())
- );
- instance.setClientId(clientInfo.clientId());
- } else {
- throw new RuntimeException("Control Protocol is not supported.");
- }
+ DefaultContexts context = defaultContexts.get();
+ for (Dpns dpn : context.dpns()) {
+ Optional<DefaultDpns> optionalDpn = cacheManager.dpnsCache.get(dpn.dpnId());
+ // check if dpns exists and if there is a DPN registered for the wanted identifier.
+ if (!optionalDpn.isPresent()) {
+ // throw exception if DPN ID is not registered.
+ throw new RuntimeException("DPN ID is not registered to the topology.");
+ }
- // from DPN ID find the Network and Node Identifiers
- Optional<String> key = optionalDpn
- .map(node -> node.nodeId() + "/" + node.networkId());
- if (!key.isPresent()) {
- throw new RuntimeException("DPN does not have node and network ID defined.");
- }
+ final DpnCommunicationService dpnCommunicationService;
+ Class<? extends FpcDpnControlProtocol> controlProtocol = optionalDpn.get().controlProtocol();
+ if (controlProtocol.isAssignableFrom(ZmqDpnControlProtocol.class)) {
+ dpnCommunicationService = DpnNgicCommunicator.getInstance();
+ } else if (controlProtocol.isAssignableFrom(P4DpnControlProtocol.class)) {
+ DpnP4Communicator instance = DpnP4Communicator.getInstance();
+ dpnCommunicationService = instance;
+ instance.setDeviceId(
+ DeviceId.deviceId(optionalDpn.get().dpnId().toString())
+ );
+ instance.setClientId(clientIdentifier);
+ } else {
+ throw new RuntimeException("Control Protocol is not supported.");
+ }
- // find DPN Topic from Node/Network ID pair.
- byte topicId = getTopicFromNode(key.get());
- if (topicId == -1 && dpnCommunicationService instanceof ZmqDpnControlProtocol) {
- throw new RuntimeException("Could not find Topic ID");
- }
+ // from DPN ID find the Network and Node Identifiers
+ Optional<String> key = optionalDpn
+ .map(node -> node.nodeId() + "/" + node.networkId());
+ if (!key.isPresent()) {
+ throw new RuntimeException("DPN does not have node and network ID defined.");
+ }
- if (!(context.ul().mobilityTunnelParameters().mobprofileParameters() instanceof ThreegppTunnel)) {
- throw new RuntimeException("mobprofileParameters are not instance of ThreegppTunnel");
- }
+ // find DPN Topic from Node/Network ID pair.
+ byte topicId = getTopicFromNode(key.get());
+ if (topicId == -1 && dpnCommunicationService instanceof ZmqDpnControlProtocol) {
+ throw new RuntimeException("Could not find Topic ID");
+ }
- Long teid = ((ThreegppTunnel) context.ul().mobilityTunnelParameters()
- .mobprofileParameters()).tunnelIdentifier();
- long clientId = clientInfo.clientId().fpcIdentity().union().int64();
- BigInteger opId = operationId.uint64();
+ if (!(context.ul().mobilityTunnelParameters().mobprofileParameters() instanceof ThreegppTunnel)) {
+ throw new RuntimeException("mobprofileParameters are not instance of ThreegppTunnel");
+ }
- // TODO figure out what is going on.
- if (targetStr.endsWith("ul") || targetStr.endsWith("dl")) {
- // TODO delete bearer
- } else {
+ Long teid = ((ThreegppTunnel) context.ul().mobilityTunnelParameters()
+ .mobprofileParameters()).tunnelIdentifier();
+ long clientId = clientIdentifier.fpcIdentity().union().int64();
+ BigInteger opId = BigInteger.valueOf(-1);
+
tasks.add(Executors.callable(() -> {
dpnCommunicationService.deleteSession(
topicId,
@@ -647,9 +646,132 @@
dynamicConfigService.deleteNode(resourceVal);
cacheManager.contextsCache.put(context.contextId(), Optional.empty());
+ CLIENT_CONTEXTS_INFO.get(clientIdentifier).remove(fpcContextId);
}));
}
}
+ } catch (Exception e) {
+ log.error(ExceptionUtils.getFullStackTrace(e));
+ }
+ return tasks;
+ }
+
+ public Collection<Callable<Object>> deleteSession(
+ ClientIdentifier clientIdentifier,
+ FpcContextId fpcContextId,
+ OpIdentifier operationId
+ ) throws ExecutionException {
+ Collection<Callable<Object>> tasks = new ArrayList<>();
+
+ FpcIdentity tenantId = CLIENT_INFO.get(clientIdentifier).tenantId();
+ CacheManager cacheManager = CacheManager.getInstance(tenantId);
+
+ Optional<DefaultContexts> defaultContexts = null;
+
+ defaultContexts = CacheManager.getInstance(tenantId)
+ .contextsCache.get(fpcContextId);
+
+ if (!defaultContexts.isPresent()) {
+ throw new RuntimeException("Context doesn't exist. Please issue create operation..");
+ }
+
+ DefaultContexts context = defaultContexts.get();
+ for (Dpns dpn : context.dpns()) {
+ Optional<DefaultDpns> optionalDpn = cacheManager.dpnsCache.get(dpn.dpnId());
+ // check if dpns exists and if there is a DPN registered for the wanted identifier.
+ if (!optionalDpn.isPresent()) {
+ // throw exception if DPN ID is not registered.
+ throw new RuntimeException("DPN ID is not registered to the topology.");
+ }
+
+ final DpnCommunicationService dpnCommunicationService;
+ Class<? extends FpcDpnControlProtocol> controlProtocol = optionalDpn.get().controlProtocol();
+ if (controlProtocol.isAssignableFrom(ZmqDpnControlProtocol.class)) {
+ dpnCommunicationService = DpnNgicCommunicator.getInstance();
+ } else if (controlProtocol.isAssignableFrom(P4DpnControlProtocol.class)) {
+ DpnP4Communicator instance = DpnP4Communicator.getInstance();
+ dpnCommunicationService = instance;
+ instance.setDeviceId(
+ DeviceId.deviceId(optionalDpn.get().dpnId().toString())
+ );
+ instance.setClientId(clientIdentifier);
+ } else {
+ throw new RuntimeException("Control Protocol is not supported.");
+ }
+
+ // from DPN ID find the Network and Node Identifiers
+ Optional<String> key = optionalDpn
+ .map(node -> node.nodeId() + "/" + node.networkId());
+ if (!key.isPresent()) {
+ throw new RuntimeException("DPN does not have node and network ID defined.");
+ }
+
+ // find DPN Topic from Node/Network ID pair.
+ byte topicId = getTopicFromNode(key.get());
+ if (topicId == -1 && dpnCommunicationService instanceof ZmqDpnControlProtocol) {
+ throw new RuntimeException("Could not find Topic ID");
+ }
+
+ if (!(context.ul().mobilityTunnelParameters().mobprofileParameters() instanceof ThreegppTunnel)) {
+ throw new RuntimeException("mobprofileParameters are not instance of ThreegppTunnel");
+ }
+
+ Long teid = ((ThreegppTunnel) context.ul().mobilityTunnelParameters()
+ .mobprofileParameters()).tunnelIdentifier();
+ long clientId = clientIdentifier.fpcIdentity().union().int64();
+ BigInteger opId = operationId.uint64();
+
+ tasks.add(Executors.callable(() -> {
+ dpnCommunicationService.deleteSession(
+ topicId,
+ context.contextId().fpcIdentity().union().int64(),
+ clientId,
+ opId
+ );
+
+ ContextsKeys contextsKeys = new ContextsKeys();
+ contextsKeys.contextId(context.contextId());
+
+ ResourceId resourceVal = getResourceVal(tenantBuilder(tenantId)
+ .addChild(DefaultFpcMobility.class)
+ .addChild(DefaultContexts.class, contextsKeys)
+ .build());
+
+ dynamicConfigService.deleteNode(resourceVal);
+ cacheManager.contextsCache.put(context.contextId(), Optional.empty());
+ CLIENT_CONTEXTS_INFO.get(clientIdentifier).remove(fpcContextId);
+ }));
+ }
+
+ return tasks;
+ }
+
+ @Override
+ public DefaultConfigureOutput configureDelete(
+ DeleteOrQuery delete,
+ DefaultRegisterClientInput clientInfo,
+ OpIdentifier operationId
+ ) throws Exception {
+ Collection<Callable<Object>> tasks = new ArrayList<>();
+ DefaultConfigureOutput configureOutput = new DefaultConfigureOutput();
+ // get cache for specific tenant.
+ DefaultDeleteSuccess defaultDeleteSuccess = new DefaultDeleteSuccess();
+ for (Targets target : delete.targets()) {
+ defaultDeleteSuccess.addToTargets(target);
+ // parse context id.
+ String targetStr = target.target().toString(),
+ s = StringUtils.substringBetween(targetStr, "contexts=", "/"),
+ trgt = s != null ? s : StringUtils.substringAfter(targetStr, "contexts=");
+
+ log.debug("handling configure-delete {}", targetStr);
+
+ // TODO figure out what is going on.
+ if (targetStr.endsWith("ul") || targetStr.endsWith("dl")) {
+ // TODO delete bearer
+ } else {
+ FpcContextId fpcContextId = FpcContextId.of(FpcIdentity.fromString(trgt));
+ tasks = deleteSession(clientInfo.clientId(), fpcContextId, operationId);
+ }
}
// execute all tasks
@@ -984,7 +1106,11 @@
for (ModelObject modelObject : getModelObjects(rpcInput.data(), registerClient)) {
DefaultRegisterClientInput input = (DefaultRegisterClientInput) modelObject;
if (CLIENT_INFO.containsKey(input.clientId())) {
- throw new RuntimeException("Client already registered.");
+// throw new RuntimeException("Client already registered.");
+ log.error("Client already registered. Deleting previous contexts...");
+ deleteSessions(input.clientId());
+ CLIENT_INFO.remove(input.clientId());
+ CLIENT_CONTEXTS_INFO.remove(input.clientId());
}
// keep information for each client. this can be moved to the DC Store and use Cache.
CLIENT_INFO.put(input.clientId(), input);
@@ -1041,6 +1167,13 @@
if (!CLIENT_INFO.containsKey(input.clientId())) {
throw new RuntimeException("Client does not exist.");
}
+
+ for (HashSet<ClientIdentifier> clientIdentifiers : TENANT_INFO.values()) {
+ if (clientIdentifiers.remove(input.clientId())) {
+ break;
+ }
+ }
+
CLIENT_INFO.remove(input.clientId());
deregisterClientOutput.clientId(input.clientId());
@@ -1052,6 +1185,9 @@
ConnectionsKeys connectionsKeys = new ConnectionsKeys();
connectionsKeys.clientId(input.clientId().toString());
+ // delete all sessions associated with this client.
+ deleteSessions(input.clientId());
+
ResourceId resourceVal = getResourceVal(ModelObjectId.builder()
.addChild(DefaultConnectionInfo.class)
.addChild(DefaultConnections.class, connectionsKeys)
diff --git a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/FpcUtil.java b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/FpcUtil.java
index bccc8e8..23934b7 100644
--- a/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/FpcUtil.java
+++ b/apps/fpcagent/src/main/java/org/onosproject/fpcagent/util/FpcUtil.java
@@ -28,9 +28,11 @@
import org.onosproject.net.device.DeviceStore;
import org.onosproject.restconf.api.RestconfService;
import org.onosproject.restconf.utils.RestconfUtils;
+import org.onosproject.yang.gen.v1.fpc.rev20150105.fpc.DefaultConnectionInfo;
import org.onosproject.yang.gen.v1.fpc.rev20150105.fpc.registerclient.DefaultRegisterClientInput;
import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.ClientIdentifier;
import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.DefaultConfigResultNotification;
+import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.DefaultFpcAgentInfo;
import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.DefaultTenants;
import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.NotificationId;
import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.OpIdentifier;
@@ -42,6 +44,7 @@
import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.resultbody.resulttype.DefaultEmptyCase;
import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.DefaultTenant;
import org.onosproject.yang.gen.v1.ietfdmmfpcagent.rev20160803.ietfdmmfpcagent.tenants.TenantKeys;
+import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.FpcContextId;
import org.onosproject.yang.gen.v1.ietfdmmfpcbase.rev20160803.ietfdmmfpcbase.FpcIdentity;
import org.onosproject.yang.model.DataNode;
import org.onosproject.yang.model.DefaultModelObjectData;
@@ -74,6 +77,7 @@
public static final FpcIdentity DEFAULT_IDENTITY;
public static final ConcurrentMap<ClientIdentifier, DefaultRegisterClientInput> CLIENT_INFO;
public static final ConcurrentMap<FpcIdentity, HashSet<ClientIdentifier>> TENANT_INFO;
+ public static final ConcurrentMap<ClientIdentifier, HashSet<FpcContextId>> CLIENT_CONTEXTS_INFO;
private static final Logger log = LoggerFactory.getLogger(FpcUtil.class);
// Services
public static DynamicConfigService dynamicConfigService;
@@ -84,6 +88,8 @@
public static ResourceId configureDpn;
public static ResourceId configure;
public static ResourceId tenants;
+ public static ResourceId fpcAgents;
+ public static ResourceId connections;
public static ResourceId configureBundles;
public static ResourceId registerClient;
public static ResourceId deregisterClient;
@@ -96,6 +102,7 @@
DEFAULT_IDENTITY = FpcIdentity.fromString("default");
CLIENT_INFO = Maps.newConcurrentMap();
TENANT_INFO = Maps.newConcurrentMap();
+ CLIENT_CONTEXTS_INFO = Maps.newConcurrentMap();
}
private FpcUtil() {
@@ -127,6 +134,18 @@
tenants = getResourceVal(tenantsId);
+ ModelObjectId fpcAgentInfo = ModelObjectId.builder()
+ .addChild(DefaultFpcAgentInfo.class)
+ .build();
+
+ fpcAgents = getResourceVal(fpcAgentInfo);
+
+ ModelObjectId connectionInfo = ModelObjectId.builder()
+ .addChild(DefaultConnectionInfo.class)
+ .build();
+
+ connections = getResourceVal(connectionInfo);
+
configure = ResourceId.builder()
.addBranchPointSchema("/", null)
.addBranchPointSchema("configure", "urn:ietf:params:xml:ns:yang:fpcagent")
@@ -305,7 +324,11 @@
.build()
);
dataNode.dataNodes().forEach(
- node -> dynamicConfigService.createNode(dataNode.resourceId(), node)
+ node -> {
+ if (!dynamicConfigService.nodeExist(dataNode.resourceId())) {
+ dynamicConfigService.createNode(dataNode.resourceId(), node);
+ }
+ }
);
}
@@ -323,14 +346,29 @@
.build()
);
dataNode.dataNodes().forEach(
- node -> dynamicConfigService.updateNode(dataNode.resourceId(), node)
+ node -> {
+ if (!dynamicConfigService.nodeExist(dataNode.resourceId())) {
+ dynamicConfigService.updateNode(dataNode.resourceId(), node);
+ }
+ }
);
}
/**
+ * Deletes a Node based on provided resource Id.
+ *
+ * @param resourceId Resource Id
+ */
+ public static void deleteNode(ResourceId resourceId) {
+ if (dynamicConfigService.nodeExist(resourceId)) {
+ dynamicConfigService.deleteNode(resourceId);
+ }
+ }
+
+ /**
* Creates a Config Result Notification for SPGW-C.
*
- * @param opId operation identifier
+ * @param opId operation identifier
* @param cause cause id
* @return config result notification model
*/
@@ -354,7 +392,7 @@
* Sends to specified CP the notification object.
*
* @param clientId client identifier (CP)
- * @param notify notification object
+ * @param notify notification object
*/
public static void sendNotification(String clientId, ModelObject notify) {
try {