blob: 8040cea8124dc13cf4c76f5bda3972b2f8659296 [file] [log] [blame]
/*
* Copyright 2015-present Open Networking Foundation
*
* 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.xran.controller;
import com.google.common.collect.Sets;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.sctp.SctpMessage;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.packet.IpAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.config.Config;
import org.onosproject.net.config.ConfigFactory;
import org.onosproject.net.config.NetworkConfigEvent;
import org.onosproject.net.config.NetworkConfigListener;
import org.onosproject.net.config.NetworkConfigRegistry;
import org.onosproject.net.config.NetworkConfigService;
import org.onosproject.net.config.basics.SubjectFactories;
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.host.HostEvent;
import org.onosproject.net.host.HostListener;
import org.onosproject.net.host.HostService;
import org.onosproject.xran.XranStore;
import org.onosproject.xran.codecs.api.CRNTI;
import org.onosproject.xran.codecs.api.ECGI;
import org.onosproject.xran.codecs.api.ERABID;
import org.onosproject.xran.codecs.api.ERABParams;
import org.onosproject.xran.codecs.api.ERABParamsItem;
import org.onosproject.xran.codecs.api.PCIARFCN;
import org.onosproject.xran.codecs.api.PropScell;
import org.onosproject.xran.codecs.api.RSRPRange;
import org.onosproject.xran.codecs.api.RSRQRange;
import org.onosproject.xran.codecs.api.RXSigReport;
import org.onosproject.xran.codecs.api.RadioRepPerServCell;
import org.onosproject.xran.codecs.api.SchedMeasRepPerServCell;
import org.onosproject.xran.codecs.api.TrafficSplitPercentage;
import org.onosproject.xran.codecs.ber.types.BerInteger;
import org.onosproject.xran.codecs.pdu.BearerAdmissionRequest;
import org.onosproject.xran.codecs.pdu.BearerAdmissionResponse;
import org.onosproject.xran.codecs.pdu.BearerAdmissionStatus;
import org.onosproject.xran.codecs.pdu.BearerReleaseInd;
import org.onosproject.xran.codecs.pdu.CellConfigReport;
import org.onosproject.xran.codecs.pdu.CellConfigRequest;
import org.onosproject.xran.codecs.pdu.HOComplete;
import org.onosproject.xran.codecs.pdu.HOFailure;
import org.onosproject.xran.codecs.pdu.HORequest;
import org.onosproject.xran.codecs.pdu.L2MeasConfig;
import org.onosproject.xran.codecs.pdu.PDCPMeasReportPerUe;
import org.onosproject.xran.codecs.pdu.RRMConfig;
import org.onosproject.xran.codecs.pdu.RRMConfigStatus;
import org.onosproject.xran.codecs.pdu.RXSigMeasConfig;
import org.onosproject.xran.codecs.pdu.RXSigMeasReport;
import org.onosproject.xran.codecs.pdu.RadioMeasReportPerCell;
import org.onosproject.xran.codecs.pdu.RadioMeasReportPerUE;
import org.onosproject.xran.codecs.pdu.ScellAdd;
import org.onosproject.xran.codecs.pdu.ScellAddStatus;
import org.onosproject.xran.codecs.pdu.ScellDelete;
import org.onosproject.xran.codecs.pdu.SchedMeasReportPerCell;
import org.onosproject.xran.codecs.pdu.SchedMeasReportPerUE;
import org.onosproject.xran.codecs.pdu.TrafficSplitConfig;
import org.onosproject.xran.codecs.pdu.UEAdmissionRequest;
import org.onosproject.xran.codecs.pdu.UEAdmissionResponse;
import org.onosproject.xran.codecs.pdu.UEAdmissionStatus;
import org.onosproject.xran.codecs.pdu.UECapabilityEnquiry;
import org.onosproject.xran.codecs.pdu.UECapabilityInfo;
import org.onosproject.xran.codecs.pdu.UEContextUpdate;
import org.onosproject.xran.codecs.pdu.UEReconfigInd;
import org.onosproject.xran.codecs.pdu.UEReleaseInd;
import org.onosproject.xran.codecs.pdu.XICICConfig;
import org.onosproject.xran.codecs.pdu.XrancPdu;
import org.onosproject.xran.entities.RnibCell;
import org.onosproject.xran.entities.RnibLink;
import org.onosproject.xran.entities.RnibUe;
import org.onosproject.xran.identifiers.ContextUpdateHandler;
import org.onosproject.xran.identifiers.EcgiCrntiPair;
import org.onosproject.xran.identifiers.LinkId;
import org.onosproject.xran.impl.XranConfig;
import org.onosproject.xran.providers.XranDeviceListener;
import org.onosproject.xran.providers.XranHostListener;
import org.onosproject.xran.wrapper.CellMap;
import org.onosproject.xran.wrapper.LinkMap;
import org.onosproject.xran.wrapper.UeMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.stream.Collectors;
import static org.onosproject.net.DeviceId.deviceId;
import static org.onosproject.xran.controller.XranChannelHandler.getSctpMessage;
import static org.onosproject.xran.entities.RnibCell.decodeDeviceId;
import static org.onosproject.xran.entities.RnibCell.uri;
import static org.onosproject.xran.entities.RnibUe.hostIdtoUEId;
/**
* Created by dimitris on 7/20/17.
*/
@Component(immediate = true)
@Service
public class XranControllerImpl implements XranController {
private static final String XRAN_APP_ID = "org.onosproject.xran";
private static final Class<XranConfig> CONFIG_CLASS = XranConfig.class;
private static final Logger log =
LoggerFactory.getLogger(XranControllerImpl.class);
/* CONFIG */
private final InternalNetworkConfigListener configListener =
new InternalNetworkConfigListener();
/* VARIABLES */
private final Controller controller = new Controller();
private XranConfig xranConfig;
private ApplicationId appId;
private int northboundTimeout;
/* Services */
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private HostService hostService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private NetworkConfigRegistry registry;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private NetworkConfigService configService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private XranStore xranStore;
private ConfigFactory<ApplicationId, XranConfig> xranConfigFactory =
new ConfigFactory<ApplicationId, XranConfig>(
SubjectFactories.APP_SUBJECT_FACTORY, CONFIG_CLASS, "xran") {
@Override
public XranConfig createConfig() {
return new XranConfig();
}
};
/* WRAPPERS */
private CellMap cellMap;
private UeMap ueMap;
private LinkMap linkMap;
/* MAPS */
private ConcurrentMap<IpAddress, ECGI> legitCells = new ConcurrentHashMap<>();
private ConcurrentMap<ECGI, SynchronousQueue<String>> hoMap = new ConcurrentHashMap<>();
private ConcurrentMap<ECGI, SynchronousQueue<String>> rrmcellMap = new ConcurrentHashMap<>();
private ConcurrentMap<CRNTI, SynchronousQueue<String>> scellAddMap = new ConcurrentHashMap<>();
private ConcurrentMap<EcgiCrntiPair, ContextUpdateHandler> contextUpdateMap = new ConcurrentHashMap<>();
/* QUEUE */
private BlockingQueue<Long> ueIdQueue = new LinkedBlockingQueue<>();
/* AGENTS */
private InternalXranDeviceAgent deviceAgent = new InternalXranDeviceAgent();
private InternalXranHostAgent hostAgent = new InternalXranHostAgent();
private InternalXranPacketAgent packetAgent = new InternalXranPacketAgent();
/* LISTENERS */
private Set<XranDeviceListener> xranDeviceListeners = new CopyOnWriteArraySet<>();
private Set<XranHostListener> xranHostListeners = new CopyOnWriteArraySet<>();
private InternalDeviceListener deviceListener = new InternalDeviceListener();
private InternalHostListener hostListener = new InternalHostListener();
@Activate
public void activate() {
appId = coreService.registerApplication(XRAN_APP_ID);
configService.addListener(configListener);
registry.registerConfigFactory(xranConfigFactory);
deviceService.addListener(deviceListener);
hostService.addListener(hostListener);
cellMap = new CellMap(xranStore);
ueMap = new UeMap(xranStore);
linkMap = new LinkMap(xranStore, ueMap);
xranStore.setController(this);
log.info("XRAN Controller Started");
}
@Deactivate
public void deactivate() {
controller.stop();
deviceService.removeListener(deviceListener);
hostService.removeListener(hostListener);
legitCells.clear();
configService.removeListener(configListener);
registry.unregisterConfigFactory(xranConfigFactory);
log.info("XRAN Controller Stopped");
}
@Override
public SynchronousQueue<String> sendHORequest(RnibLink linkT, RnibLink linkS) throws InterruptedException {
ECGI ecgiT = linkT.getLinkId().getEcgi(),
ecgiS = linkS.getLinkId().getEcgi();
CRNTI crnti = linkMap.getCrnti(linkT.getLinkId().getUeId());
ChannelHandlerContext ctxT = cellMap.getCtx(ecgiT),
ctxS = cellMap.getCtx(ecgiS);
SynchronousQueue<String> queue = new SynchronousQueue<>();
try {
XrancPdu xrancPdu = HORequest.constructPacket(crnti, ecgiS, ecgiT);
// temporary map that has ECGI source of a handoff to a queue waiting for REST response.
hoMap.put(ecgiS, queue);
ctxT.writeAndFlush(getSctpMessage(xrancPdu));
ctxS.writeAndFlush(getSctpMessage(xrancPdu));
// FIXME: only works for one HO at a time.
ueIdQueue.put(linkT.getLinkId().getUeId());
} catch (IOException e) {
e.printStackTrace();
}
return queue;
}
@Override
public void addListener(XranDeviceListener listener) {
xranDeviceListeners.add(listener);
}
@Override
public void addListener(XranHostListener listener) {
xranHostListeners.add(listener);
}
@Override
public void removeListener(XranDeviceListener listener) {
xranDeviceListeners.remove(listener);
}
@Override
public void removeListener(XranHostListener listener) {
xranHostListeners.remove(listener);
}
@Override
public int getNorthboundTimeout() {
return northboundTimeout;
}
@Override
public SynchronousQueue<String> sendmodifiedrrmconf(RRMConfig rrmConfig, boolean xicic) {
ECGI ecgi = rrmConfig.getEcgi();
ChannelHandlerContext ctx = cellMap.getCtx(ecgi);
try {
XrancPdu pdu;
if (xicic) {
CellConfigReport cellConfigReport = cellMap.get(ecgi).getConf();
if (cellConfigReport != null) {
pdu = XICICConfig.constructPacket(rrmConfig, cellConfigReport);
ctx.writeAndFlush(getSctpMessage(pdu));
}
} else {
pdu = RRMConfig.constructPacket(rrmConfig);
ctx.writeAndFlush(getSctpMessage(pdu));
SynchronousQueue<String> queue = new SynchronousQueue<>();
rrmcellMap.put(ecgi, queue);
return queue;
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
public SynchronousQueue<String> sendScellAdd(RnibLink link) {
RnibCell secondaryCell = link.getLinkId().getCell(),
primaryCell = linkMap.getPrimaryCell(link.getLinkId().getUe());
ECGI primaryEcgi = primaryCell.getEcgi();
ChannelHandlerContext ctx = cellMap.getCtx(primaryEcgi);
CRNTI crnti = linkMap.getCrnti(link.getLinkId().getUeId());
CellConfigReport cellReport = secondaryCell.getConf();
if (cellReport != null) {
PCIARFCN pciarfcn = new PCIARFCN();
pciarfcn.setPci(cellReport.getPci());
pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
PropScell propScell = new PropScell();
propScell.setPciArfcn(pciarfcn);
XrancPdu pdu = ScellAdd.constructPacket(primaryEcgi, crnti, propScell);
try {
ctx.writeAndFlush(getSctpMessage(pdu));
SynchronousQueue<String> queue = new SynchronousQueue<>();
scellAddMap.put(crnti, queue);
return queue;
} catch (IOException e) {
log.error(ExceptionUtils.getFullStackTrace(e));
e.printStackTrace();
}
}
return null;
}
@Override
public boolean sendScellDelete(RnibLink link) {
RnibCell secondaryCell = link.getLinkId().getCell(),
primaryCell = linkMap.getPrimaryCell(link.getLinkId().getUe());
ECGI primaryEcgi = primaryCell.getEcgi();
ChannelHandlerContext ctx = cellMap.getCtx(primaryEcgi);
CRNTI crnti = linkMap.getCrnti(link.getLinkId().getUeId());
CellConfigReport cellReport = secondaryCell.getConf();
if (cellReport != null) {
PCIARFCN pciarfcn = new PCIARFCN();
pciarfcn.setPci(cellReport.getPci());
pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
XrancPdu pdu = ScellDelete.constructPacket(primaryEcgi, crnti, pciarfcn);
try {
ctx.writeAndFlush(getSctpMessage(pdu));
link.setType(RnibLink.Type.NON_SERVING);
return true;
} catch (IOException e) {
log.error(ExceptionUtils.getFullStackTrace(e));
e.printStackTrace();
}
}
return false;
}
/**
* Timer to delete UE after being IDLE.
*
* @param ue UE entity
*/
private void restartTimer(RnibUe ue) {
Timer timer = new Timer();
ue.setTimer(timer);
timer.schedule(new TimerTask() {
@Override
public void run() {
if (ue.getState() == RnibUe.State.IDLE) {
hostAgent.removeConnectedHost(ue);
log.info("UE is removed after {} ms of IDLE", xranConfig.getIdleUeRemoval());
} else {
log.info("UE not removed cause its ACTIVE");
}
}
}, xranConfig.getIdleUeRemoval());
}
/**
* Timer to delete LINK after not receiving measurements.
*
* @param link LINK entity
*/
private void restartTimer(RnibLink link) {
Timer timer = new Timer();
link.setTimer(timer);
timer.schedule(new TimerTask() {
@Override
public void run() {
LinkId linkId = link.getLinkId();
xranStore.removeLink(linkId);
log.info("Link is removed after not receiving Meas Reports for {} ms",
xranConfig.getNoMeasLinkRemoval());
}
}, xranConfig.getNoMeasLinkRemoval());
}
/**
* Request measurement configuration field of specified UE.
*
* @param primary primary CELL
* @param ue UE entity
*/
private void populateMeasConfig(RnibCell primary, RnibUe ue) {
try {
ChannelHandlerContext ctx = cellMap.getCtx(primary.getEcgi());
RXSigMeasConfig.MeasCells measCells = new RXSigMeasConfig.MeasCells();
xranStore.getcellnodes().forEach(cell -> {
CellConfigReport cellReport = ((RnibCell) cell).getConf();
if (cellReport != null) {
PCIARFCN pciarfcn = new PCIARFCN();
pciarfcn.setPci(cellReport.getPci());
pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
measCells.setPCIARFCN(pciarfcn);
}
});
XrancPdu xrancPdu = RXSigMeasConfig.constructPacket(
primary.getEcgi(),
ue.getCrnti(),
measCells,
xranConfig.getRxSignalInterval()
);
ue.setMeasConfig(xrancPdu.getBody().getRXSigMeasConfig());
ctx.writeAndFlush(getSctpMessage(xrancPdu));
} catch (IOException e) {
log.warn(ExceptionUtils.getFullStackTrace(e));
e.printStackTrace();
}
}
/**
* Internal device listener.
*/
class InternalDeviceListener implements DeviceListener {
@Override
public void event(DeviceEvent event) {
log.info("Device Event {}", event);
switch (event.type()) {
case DEVICE_ADDED: {
try {
ECGI ecgi = decodeDeviceId(event.subject().id());
RnibCell cell = cellMap.get(ecgi);
if (cell != null) {
Timer timer = new Timer();
timer.scheduleAtFixedRate(
new TimerTask() {
@Override
public void run() {
CellConfigReport conf = cell.getConf();
if (conf == null) {
try {
ChannelHandlerContext ctx = cellMap.getCtx(ecgi);
XrancPdu xrancPdu = CellConfigRequest.constructPacket(ecgi);
ctx.writeAndFlush(getSctpMessage(xrancPdu));
} catch (IOException e) {
log.error(ExceptionUtils.getFullStackTrace(e));
e.printStackTrace();
}
} else {
List<Object> ueNodes = xranStore.getuenodes();
ueNodes.forEach(object -> {
RnibUe ue = (RnibUe) object;
try {
ECGI primaryEcgi = linkMap.getPrimaryCell(ue).getEcgi();
ChannelHandlerContext ctx = cellMap.getCtx(primaryEcgi);
RXSigMeasConfig.MeasCells measCells =
new RXSigMeasConfig.MeasCells();
xranStore.getcellnodes().forEach(cell -> {
CellConfigReport cellReport = ((RnibCell) cell).getConf();
if (cellReport != null) {
PCIARFCN pciarfcn = new PCIARFCN();
pciarfcn.setPci(cellReport.getPci());
pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
measCells.setPCIARFCN(pciarfcn);
}
});
XrancPdu xrancPdu = RXSigMeasConfig.constructPacket(
primaryEcgi,
ue.getCrnti(),
measCells,
xranConfig.getRxSignalInterval()
);
ue.setMeasConfig(xrancPdu.getBody().getRXSigMeasConfig());
ctx.writeAndFlush(getSctpMessage(xrancPdu));
} catch (IOException e) {
log.warn(ExceptionUtils.getFullStackTrace(e));
e.printStackTrace();
}
});
try {
ChannelHandlerContext ctx = cellMap.getCtx(ecgi);
XrancPdu xrancPdu = L2MeasConfig
.constructPacket(ecgi, xranConfig.getL2MeasInterval());
cell.setMeasConfig(xrancPdu.getBody().getL2MeasConfig());
SctpMessage sctpMessage = getSctpMessage(xrancPdu);
ctx.writeAndFlush(sctpMessage);
} catch (IOException e) {
log.error(ExceptionUtils.getFullStackTrace(e));
e.printStackTrace();
}
timer.cancel();
timer.purge();
}
}
},
0,
xranConfig.getConfigRequestInterval() * 1000
);
}
} catch (IOException e) {
log.error(ExceptionUtils.getFullStackTrace(e));
e.printStackTrace();
}
break;
}
default: {
break;
}
}
}
}
/**
* Internal host listener.
*/
class InternalHostListener implements HostListener {
@Override
public void event(HostEvent event) {
log.info("Host Event {}", event);
switch (event.type()) {
case HOST_ADDED:
case HOST_MOVED: {
RnibUe ue = ueMap.get(hostIdtoUEId(event.subject().id()));
if (ue != null) {
ECGI ecgiPrimary = linkMap.getPrimaryCell(ue).getEcgi();
RnibCell primary = cellMap.get(ecgiPrimary);
ue.setMeasConfig(null);
if (primary != null) {
Timer timer = new Timer();
timer.scheduleAtFixedRate(
new TimerTask() {
@Override
public void run() {
if (ue.getCapability() == null && primary.getVersion() >= 3) {
try {
ChannelHandlerContext ctx = cellMap.getCtx(primary.getEcgi());
XrancPdu xrancPdu = UECapabilityEnquiry.constructPacket(
primary.getEcgi(),
ue.getCrnti());
ctx.writeAndFlush(getSctpMessage(xrancPdu));
} catch (IOException e) {
log.warn(ExceptionUtils.getFullStackTrace(e));
e.printStackTrace();
}
} else {
timer.cancel();
timer.purge();
}
}
},
0,
xranConfig.getConfigRequestInterval() * 1000
);
if (ue.getMeasConfig() == null) {
populateMeasConfig(primary, ue);
}
}
}
break;
}
default: {
break;
}
}
}
}
/**
* Internal xran device agent.
*/
public class InternalXranDeviceAgent implements XranDeviceAgent {
private final Logger log = LoggerFactory.getLogger(InternalXranDeviceAgent.class);
@Override
public boolean addConnectedCell(String host, ChannelHandlerContext ctx) {
ECGI ecgi = legitCells.get(IpAddress.valueOf(host));
if (ecgi == null) {
log.error("Device is not a legit source; ignoring...");
} else {
log.info("Device exists in configuration; registering...");
RnibCell storeCell = cellMap.get(ecgi);
if (storeCell == null) {
storeCell = new RnibCell();
storeCell.setEcgi(ecgi);
cellMap.put(storeCell, ctx);
for (XranDeviceListener l : xranDeviceListeners) {
l.deviceAdded(storeCell);
}
return true;
} else {
log.error("Device already registered; ignoring...");
}
}
ctx.close();
return false;
}
@Override
public boolean removeConnectedCell(String host) {
ECGI ecgi = legitCells.get(IpAddress.valueOf(host));
List<RnibLink> linksbyecgi = xranStore.getlinksbyecgi(ecgi);
linksbyecgi.forEach(rnibLink -> xranStore.removeLink(rnibLink.getLinkId()));
if (cellMap.remove(ecgi)) {
for (XranDeviceListener l : xranDeviceListeners) {
l.deviceRemoved(deviceId(uri(ecgi)));
}
return true;
}
return false;
}
}
/**
* Internal xran host agent.
*/
public class InternalXranHostAgent implements XranHostAgent {
@Override
public boolean addConnectedHost(RnibUe ue, RnibCell cell, ChannelHandlerContext ctx) {
if (ue.getId() != null && ueMap.get(ue.getId()) != null) {
linkMap.putPrimaryLink(cell, ue);
Set<ECGI> ecgiSet = Sets.newConcurrentHashSet();
xranStore.getlinksbyueid(ue.getId())
.stream()
.filter(l -> l.getType().equals(RnibLink.Type.SERVING_PRIMARY))
.findFirst()
.ifPresent(l -> ecgiSet.add(l.getLinkId().getEcgi()));
for (XranHostListener l : xranHostListeners) {
l.hostAdded(ue, ecgiSet);
}
return true;
} else {
ueMap.put(cell, ue);
linkMap.putPrimaryLink(cell, ue);
Set<ECGI> ecgiSet = Sets.newConcurrentHashSet();
ecgiSet.add(cell.getEcgi());
for (XranHostListener l : xranHostListeners) {
l.hostAdded(ue, ecgiSet);
}
return true;
}
}
@Override
public boolean removeConnectedHost(RnibUe ue) {
List<RnibLink> links = xranStore.getlinksbyueid(ue.getId());
links.forEach(rnibLink -> xranStore.removeLink(rnibLink.getLinkId()));
if (ueMap.remove(ue.getId())) {
for (XranHostListener l : xranHostListeners) {
l.hostRemoved(ue.getHostId());
}
return true;
}
return false;
}
}
public class InternalXranPacketAgent implements XranPacketProcessor {
@Override
public void handlePacket(XrancPdu recvPdu, ChannelHandlerContext ctx)
throws IOException, InterruptedException {
XrancPdu sendPdu;
int apiID = recvPdu.getHdr().getApiId().intValue();
log.debug("Received message: {}", recvPdu);
switch (apiID) {
case 1: {
// Decode Cell config report.
CellConfigReport report = recvPdu.getBody().getCellConfigReport();
handleCellconfigreport(report, recvPdu.getHdr().getVer().toString());
break;
}
case 2: {
// Decode UE Admission Request.
UEAdmissionRequest ueAdmissionRequest = recvPdu.getBody().getUEAdmissionRequest();
handleUeadmissionrequest(ueAdmissionRequest, ctx);
break;
}
case 4: {
// Decode UE Admission Status.
UEAdmissionStatus ueAdmissionStatus = recvPdu.getBody().getUEAdmissionStatus();
handleAdmissionstatus(ueAdmissionStatus, ctx);
break;
}
case 5: {
// Decode UE Context Update.
UEContextUpdate ueContextUpdate = recvPdu.getBody().getUEContextUpdate();
handleUecontextupdate(ueContextUpdate, ctx);
break;
}
case 6: {
// Decode UE Reconfig_Ind.
UEReconfigInd ueReconfigInd = recvPdu.getBody().getUEReconfigInd();
handleUereconfigind(ueReconfigInd);
break;
}
case 7: {
// If xRANc wants to deactivate UE, we pass UEReleaseInd from xRANc to eNB.
// Decode UE Release_Ind.
UEReleaseInd ueReleaseInd = recvPdu.getBody().getUEReleaseInd();
handleUereleaseind(ueReleaseInd);
break;
}
case 8: {
// Decode Bearer Adm Request
BearerAdmissionRequest bearerAdmissionRequest = recvPdu.getBody().getBearerAdmissionRequest();
handleBeareradmissionrequest(bearerAdmissionRequest, ctx);
break;
}
case 10: {
//Decode Bearer Admission Status
BearerAdmissionStatus bearerAdmissionStatus = recvPdu.getBody().getBearerAdmissionStatus();
break;
}
case 11: {
//Decode Bearer Release Ind
BearerReleaseInd bearerReleaseInd = recvPdu.getBody().getBearerReleaseInd();
handleBearerreleaseind(bearerReleaseInd);
break;
}
case 13: {
HOFailure hoFailure = recvPdu.getBody().getHOFailure();
handleHofailure(hoFailure);
break;
}
case 14: {
HOComplete hoComplete = recvPdu.getBody().getHOComplete();
handleHocomplete(hoComplete, ctx);
break;
}
case 16: {
// Decode Rx Sig Meas Report.
RXSigMeasReport rxSigMeasReport = recvPdu.getBody().getRXSigMeasReport();
handleRxsigmeasreport(rxSigMeasReport);
break;
}
case 18: {
RadioMeasReportPerUE radioMeasReportPerUE = recvPdu.getBody().getRadioMeasReportPerUE();
handleRadionmeasreportperue(radioMeasReportPerUE);
break;
}
case 19: {
RadioMeasReportPerCell radioMeasReportPerCell = recvPdu.getBody().getRadioMeasReportPerCell();
break;
}
case 20: {
SchedMeasReportPerUE schedMeasReportPerUE = recvPdu.getBody().getSchedMeasReportPerUE();
handleSchedmeasreportperue(schedMeasReportPerUE);
break;
}
case 21: {
SchedMeasReportPerCell schedMeasReportPerCell = recvPdu.getBody().getSchedMeasReportPerCell();
handleSchedmeasreportpercell(schedMeasReportPerCell);
break;
}
case 22: {
PDCPMeasReportPerUe pdcpMeasReportPerUe = recvPdu.getBody().getPDCPMeasReportPerUe();
handlePdcpmeasreportperue(pdcpMeasReportPerUe);
break;
}
case 24: {
// Decode UE Capability Info
UECapabilityInfo capabilityInfo = recvPdu.getBody().getUECapabilityInfo();
handleCapabilityinfo(capabilityInfo);
break;
}
case 25: {
// Don't know what will invoke sending UE CAPABILITY ENQUIRY
// Encode and send UE CAPABILITY ENQUIRY
UECapabilityEnquiry ueCapabilityEnquiry = recvPdu.getBody().getUECapabilityEnquiry();
handleUecapabilityenquiry(ueCapabilityEnquiry, ctx);
break;
}
case 27: {
//Decode ScellAddStatus
ScellAddStatus scellAddStatus = recvPdu.getBody().getScellAddStatus();
handleScelladdstatus(scellAddStatus);
break;
}
case 30: {
// Decode RRMConfig Status
RRMConfigStatus rrmConfigStatus = recvPdu.getBody().getRRMConfigStatus();
handleRrmconfigstatus(rrmConfigStatus);
break;
}
//TODO Case 31: SeNBAdd 32: SeNBAddStatus 33: SeNBDelete
case 34: {
TrafficSplitConfig trafficSplitConfig = recvPdu.getBody().getTrafficSplitConfig();
handleTrafficSplitConfig(trafficSplitConfig);
break;
}
default: {
log.warn("Wrong API ID: {}", recvPdu);
break;
}
}
}
/**
* Handle Cellconfigreport.
* @param report CellConfigReport
* @param version String version ID
*/
private void handleCellconfigreport(CellConfigReport report, String version) {
ECGI ecgi = report.getEcgi();
RnibCell cell = xranStore.getCell(ecgi);
cell.setVersion(version);
cell.setConf(report);
cellMap.putPciArfcn(cell);
}
/**
* Handle Ueadmissionrequest.
* @param ueAdmissionRequest UEAdmissionRequest
* @param ctx ChannelHandlerContext
* @throws IOException IO Exception
*/
private void handleUeadmissionrequest(UEAdmissionRequest ueAdmissionRequest, ChannelHandlerContext ctx)
throws IOException {
ECGI ecgi = ueAdmissionRequest.getEcgi();
if (xranStore.getCell(ecgi) != null) {
CRNTI crnti = ueAdmissionRequest.getCrnti();
XrancPdu sendPdu = UEAdmissionResponse.constructPacket(ecgi, crnti, xranConfig.admissionFlag());
ctx.writeAndFlush(getSctpMessage(sendPdu));
} else {
log.warn("Could not find ECGI in registered cells: {}", ecgi);
}
}
/**
* Handle UEAdmissionStatus.
* @param ueAdmissionStatus UEAdmissionStatus
* @param ctx ChannelHandlerContext
*/
private void handleAdmissionstatus(UEAdmissionStatus ueAdmissionStatus, ChannelHandlerContext ctx) {
RnibUe ue = ueMap.get(ueAdmissionStatus.getEcgi(), ueAdmissionStatus.getCrnti());
if (ue != null) {
if (ueAdmissionStatus.getAdmEstStatus().value.intValue() == 0) {
ue.setState(RnibUe.State.ACTIVE);
} else {
ue.setState(RnibUe.State.IDLE);
}
}
if (ueAdmissionStatus.getAdmEstStatus().value.intValue() == 0) {
EcgiCrntiPair ecgiCrntiPair = EcgiCrntiPair
.valueOf(ueAdmissionStatus.getEcgi(), ueAdmissionStatus.getCrnti());
contextUpdateMap.compute(ecgiCrntiPair, (k, v) -> {
if (v == null) {
v = new ContextUpdateHandler();
}
if (v.setAdmissionStatus(ueAdmissionStatus)) {
handleContextUpdate(v.getContextUpdate(), ctx, false);
}
return v;
});
}
}
/**
* Handle UEContextUpdate.
* @param ueContextUpdate UEContextUpdate
* @param ctx ChannelHandlerContext
*/
private void handleUecontextupdate(UEContextUpdate ueContextUpdate, ChannelHandlerContext ctx) {
EcgiCrntiPair ecgiCrntiPair = EcgiCrntiPair
.valueOf(ueContextUpdate.getEcgi(), ueContextUpdate.getCrnti());
contextUpdateMap.compute(ecgiCrntiPair, (k, v) -> {
if (v == null) {
v = new ContextUpdateHandler();
}
if (v.setContextUpdate(ueContextUpdate)) {
HOComplete hoComplete = v.getHoComplete();
handleContextUpdate(ueContextUpdate, ctx, hoComplete != null);
if (hoComplete != null) {
try {
hoMap.get(hoComplete.getEcgiS()).put("Hand Over Completed");
} catch (InterruptedException e) {
log.error(ExceptionUtils.getFullStackTrace(e));
e.printStackTrace();
} finally {
hoMap.remove(hoComplete.getEcgiS());
}
}
}
return v;
});
}
/**
* Handle UEReconfigInd.
* @param ueReconfigInd UEReconfigInd
*/
private void handleUereconfigind(UEReconfigInd ueReconfigInd) {
RnibUe ue = ueMap.get(ueReconfigInd.getEcgi(), ueReconfigInd.getCrntiOld());
RnibCell cell = cellMap.get(ueReconfigInd.getEcgi());
if (ue != null && cell != null) {
ue.setCrnti(ueReconfigInd.getCrntiNew());
ueMap.putCrnti(cell, ue);
} else {
log.warn("Could not find UE with this CRNTI: {}", ueReconfigInd.getCrntiOld());
}
}
/**
* Handle UEReleaseInd.
* @param ueReleaseInd UEReleaseInd
*/
private void handleUereleaseind(UEReleaseInd ueReleaseInd) {
ECGI ecgi = ueReleaseInd.getEcgi();
CRNTI crnti = ueReleaseInd.getCrnti();
RnibUe ue = ueMap.get(ecgi, crnti);
// Check if there is an ongoing handoff and only remove if ue is not part of the handoff.
Long peek = ueIdQueue.peek();
if (peek != null) {
EcgiCrntiPair ecgiCrntiPair = ueMap.getCrntUe().inverse().get(peek);
if (ecgiCrntiPair != null && ecgiCrntiPair.equals(EcgiCrntiPair.valueOf(ecgi, crnti))) {
return;
}
}
if (ue != null) {
ue.setState(RnibUe.State.IDLE);
restartTimer(ue);
} else {
log.warn("Cannot release UE from non primary link.");
}
}
/**
* Handle BearerAdmissionRequest.
* @param bearerAdmissionRequest BearerAdmissionRequest
* @param ctx ChannelHandlerContext
* @throws IOException IO Exception
*/
private void handleBeareradmissionrequest(BearerAdmissionRequest bearerAdmissionRequest,
ChannelHandlerContext ctx) throws IOException {
ECGI ecgi = bearerAdmissionRequest.getEcgi();
CRNTI crnti = bearerAdmissionRequest.getCrnti();
ERABParams erabParams = bearerAdmissionRequest.getErabParams();
RnibLink link = linkMap.get(ecgi, crnti);
if (link != null) {
link.setBearerParameters(erabParams);
} else {
log.warn("Could not find link between {}-{}", ecgi, crnti);
}
BerInteger numErabs = bearerAdmissionRequest.getNumErabs();
// Encode and send Bearer Admission Response
XrancPdu sendPdu = BearerAdmissionResponse
.constructPacket(ecgi, crnti, erabParams, numErabs, xranConfig.bearerFlag());
ctx.writeAndFlush(getSctpMessage(sendPdu));
}
/**
* Handle BearerReleaseInd.
* @param bearerReleaseInd
*/
private void handleBearerreleaseind(BearerReleaseInd bearerReleaseInd) {
ECGI ecgi = bearerReleaseInd.getEcgi();
CRNTI crnti = bearerReleaseInd.getCrnti();
RnibLink link = linkMap.get(ecgi, crnti);
List<ERABID> erabidsRelease = bearerReleaseInd.getErabIds().getERABID();
List<ERABParamsItem> erabParamsItem = link.getBearerParameters().getERABParamsItem();
List<ERABParamsItem> unreleased = erabParamsItem
.stream()
.filter(item -> {
Optional<ERABID> any = erabidsRelease.stream()
.filter(id -> id.equals(item.getId())).findAny();
return !any.isPresent();
}).collect(Collectors.toList());
link.getBearerParameters().setERABParamsItem(new ArrayList<>(unreleased));
}
/**
* Handle HOFailure.
* @param hoFailure HOFailure
* @throws InterruptedException ueIdQueue interruption
*/
private void handleHofailure(HOFailure hoFailure) throws InterruptedException {
try {
hoMap.get(hoFailure.getEcgi())
.put("Hand Over Failed with cause: " + hoFailure.getCause());
} catch (InterruptedException e) {
log.error(ExceptionUtils.getFullStackTrace(e));
e.printStackTrace();
} finally {
hoMap.remove(hoFailure.getEcgi());
ueIdQueue.take();
}
}
/**
* Handle HOComplete.
* @param hoComplete HOComplete
* @param ctx ChannelHandlerContext
*/
private void handleHocomplete(HOComplete hoComplete, ChannelHandlerContext ctx) {
EcgiCrntiPair ecgiCrntiPair = EcgiCrntiPair.valueOf(hoComplete.getEcgiT(),
hoComplete.getCrntiNew());
contextUpdateMap.compute(ecgiCrntiPair, (k, v) -> {
if (v == null) {
v = new ContextUpdateHandler();
}
if (v.setHoComplete(hoComplete)) {
handleContextUpdate(v.getContextUpdate(), ctx, true);
try {
hoMap.get(hoComplete.getEcgiS()).put("Hand Over Completed");
} catch (InterruptedException e) {
log.error(ExceptionUtils.getFullStackTrace(e));
e.printStackTrace();
} finally {
hoMap.remove(hoComplete.getEcgiS());
}
}
return v;
});
}
/**
* Handle RXSigMeasReport.
* @param rxSigMeasReport RXSigMeasReport
*/
private void handleRxsigmeasreport(RXSigMeasReport rxSigMeasReport) {
List<RXSigReport> rxSigReportList = rxSigMeasReport.getCellMeasReports().getRXSigReport();
RnibUe ue = ueMap.get(rxSigMeasReport.getEcgi(), rxSigMeasReport.getCrnti());
if (ue != null) {
Long ueId = ue.getId();
if (!rxSigReportList.isEmpty()) {
rxSigReportList.forEach(rxSigReport -> {
RnibCell cell = cellMap.get(rxSigReport.getPciArfcn());
if (cell != null) {
ECGI ecgi = cell.getEcgi();
RnibLink link = linkMap.get(ecgi, ueId);
if (link == null) {
log.warn("Could not find link between: {}-{} | Creating non-serving link..",
ecgi, ueId);
link = linkMap.putNonServingLink(cell, ueId);
}
if (link != null) {
if (link.getType().equals(RnibLink.Type.NON_SERVING)) {
restartTimer(link);
}
RSRQRange rsrq = rxSigReport.getRsrq();
RSRPRange rsrp = rxSigReport.getRsrp();
RnibLink.LinkQuality quality = link.getQuality();
quality.setRx(new RnibLink.LinkQuality.Rx(
rsrp.value.intValue() - 140,
(rsrq.value.intValue() * 0.5) - 19.5
));
}
} else {
log.warn("case 16: Could not find cell with PCI-ARFCN: {}",
rxSigReport.getPciArfcn());
}
});
}
}
}
/**
* Handle RadioMeasReportPerUE.
* @param radioMeasReportPerUE RadioMeasReportPerUE
*/
private void handleRadionmeasreportperue(RadioMeasReportPerUE radioMeasReportPerUE) {
RnibUe ue = ueMap.get(radioMeasReportPerUE.getEcgi(), radioMeasReportPerUE.getCrnti());
if (ue != null) {
Long ueId = ue.getId();
List<RadioRepPerServCell> servCells = radioMeasReportPerUE.getRadioReportServCells()
.getRadioRepPerServCell();
servCells.forEach(servCell -> {
RnibCell cell = cellMap.get(servCell.getPciArfcn());
if (cell != null) {
RnibLink link = linkMap.get(cell.getEcgi(), ueId);
if (link != null) {
RadioRepPerServCell.CqiHist cqiHist = servCell.getCqiHist();
RnibLink.LinkQuality quality = link.getQuality();
final double[] values = {0, 0, 0};
final int[] i = {1};
cqiHist.getBerInteger().forEach(value -> {
values[0] = Math.max(values[0], value.intValue());
values[1] += i[0] * value.intValue();
values[2] += value.intValue();
i[0]++;
});
quality.setCqi(new RnibLink.LinkQuality.Cqi(
cqiHist,
values[0],
values[1] / values[0]
));
} else {
log.warn("Could not find link between: {}-{}", cell.getEcgi(), ueId);
}
} else {
log.warn("case 18: Could not find cell with PCI-ARFCN: {}", servCell.getPciArfcn());
}
});
}
}
/**
* Handle SchedMeasReportPerUE.
* @param schedMeasReportPerUE SchedMeasReportPerUE
*/
private void handleSchedmeasreportperue(SchedMeasReportPerUE schedMeasReportPerUE) {
RnibUe ue = ueMap.get(schedMeasReportPerUE.getEcgi(), schedMeasReportPerUE.getCrnti());
if (ue != null) {
Long ueId = ue.getId();
List<SchedMeasRepPerServCell> servCells = schedMeasReportPerUE.getSchedReportServCells()
.getSchedMeasRepPerServCell();
servCells.forEach(servCell -> {
RnibCell cell = cellMap.get(servCell.getPciArfcn());
if (cell != null) {
RnibLink link = linkMap.get(cell.getEcgi(), ueId);
if (link != null) {
link.getQuality().setMcs(new RnibLink.LinkQuality.Mcs(
servCell.getMcsDl(),
servCell.getMcsUl()
));
link.setResourceUsage(new RnibLink.ResourceUsage(
servCell.getPrbUsage().getPrbUsageDl(),
servCell.getPrbUsage().getPrbUsageUl()
));
} else {
log.warn("Could not find link between: {}-{}", cell.getEcgi(), ueId);
}
} else {
log.warn("case 20: Could not find cell with PCI-ARFCN: {}", servCell.getPciArfcn());
}
});
}
}
/**
* Handle SchedMeasReportPerCell.
* @param schedMeasReportPerCell SchedMeasReportPerCell
*/
private void handleSchedmeasreportpercell(SchedMeasReportPerCell schedMeasReportPerCell) {
RnibCell cell = cellMap.get(schedMeasReportPerCell.getEcgi());
if (cell != null) {
cell.setPrbUsage(new RnibCell.PrbUsageContainer(
schedMeasReportPerCell.getPrbUsagePcell(),
schedMeasReportPerCell.getPrbUsageScell()
));
cell.setQci(schedMeasReportPerCell.getQciVals());
} else {
log.warn("Could not find cell with ECGI: {}", schedMeasReportPerCell.getEcgi());
}
}
/**
* Handle PDCPMeasReportPerUe.
* @param pdcpMeasReportPerUe PDCPMeasReportPerUe
*/
private void handlePdcpmeasreportperue(PDCPMeasReportPerUe pdcpMeasReportPerUe) {
RnibUe ue = ueMap.get(pdcpMeasReportPerUe.getEcgi(), pdcpMeasReportPerUe.getCrnti());
if (ue != null) {
Long ueId = ue.getId();
RnibLink link = linkMap.get(pdcpMeasReportPerUe.getEcgi(), ueId);
if (link != null) {
link.setPdcpThroughput(new RnibLink.PdcpThroughput(
pdcpMeasReportPerUe.getThroughputDl(),
pdcpMeasReportPerUe.getThroughputUl()
));
link.setPdcpPackDelay(new RnibLink.PdcpPacketdelay(
pdcpMeasReportPerUe.getPktDelayDl(),
pdcpMeasReportPerUe.getPktDelayUl()
));
} else {
log.warn("Could not find link between: {}-{}", pdcpMeasReportPerUe.getEcgi(), ueId);
}
}
}
/**
* Handle UECapabilityInfo.
* @param capabilityInfo UECapabilityInfo
*/
private void handleCapabilityinfo(UECapabilityInfo capabilityInfo) {
RnibUe ue = ueMap.get(capabilityInfo.getEcgi(), capabilityInfo.getCrnti());
if (ue != null) {
ue.setCapability(capabilityInfo);
} else {
log.warn("Could not find UE with this CRNTI: {}", capabilityInfo.getCrnti());
}
}
/**
* Handle UECapabilityEnquiry.
* @param ueCapabilityEnquiry UECapabilityEnquiry
* @param ctx ChannelHandlerContext
* @throws IOException IO Exception
*/
private void handleUecapabilityenquiry(UECapabilityEnquiry ueCapabilityEnquiry, ChannelHandlerContext ctx)
throws IOException {
XrancPdu xrancPdu = UECapabilityEnquiry.constructPacket(ueCapabilityEnquiry.getEcgi(),
ueCapabilityEnquiry.getCrnti());
ctx.writeAndFlush(getSctpMessage(xrancPdu));
}
/**
* Handle ScellAddStatus.
* @param scellAddStatus ScellAddStatus
*/
private void handleScelladdstatus(ScellAddStatus scellAddStatus) {
RnibUe ue = ueMap.get(scellAddStatus.getEcgi(), scellAddStatus.getCrnti());
if (ue != null) {
Long ueId = ue.getId();
try {
scellAddMap.get(scellAddStatus.getCrnti()).put("Scell's status: " +
scellAddStatus.getStatus());
final int[] i = {0};
scellAddStatus.getScellsInd().getPCIARFCN().forEach(
pciarfcn -> {
if (scellAddStatus.getStatus().getBerEnum().get(i[0]).value.intValue() == 0) {
RnibCell cell = cellMap.get(pciarfcn);
RnibLink link = linkMap.get(cell.getEcgi(), ueId);
link.setType(RnibLink.Type.SERVING_SECONDARY_CA);
}
i[0]++;
}
);
} catch (InterruptedException e) {
log.error(ExceptionUtils.getFullStackTrace(e));
e.printStackTrace();
} finally {
scellAddMap.remove(scellAddStatus.getCrnti());
}
}
}
/**
* Handle RRMConfigStatus.
* @param rrmConfigStatus RRMConfigStatus
*/
private void handleRrmconfigstatus(RRMConfigStatus rrmConfigStatus) {
try {
rrmcellMap.get(rrmConfigStatus.getEcgi())
.put("RRM Config's status: " + rrmConfigStatus.getStatus());
} catch (InterruptedException e) {
log.error(ExceptionUtils.getFullStackTrace(e));
e.printStackTrace();
} finally {
rrmcellMap.remove(rrmConfigStatus.getEcgi());
}
}
/**
* Handle TrafficSplitConfig.
* @param trafficSplitConfig TrafficSplitConfig
*/
private void handleTrafficSplitConfig(TrafficSplitConfig trafficSplitConfig) {
RnibUe ue = ueMap.get(trafficSplitConfig.getEcgi(), trafficSplitConfig.getCrnti());
if (ue != null) {
Long ueId = ue.getId();
List<TrafficSplitPercentage> splitPercentages = trafficSplitConfig
.getTrafficSplitPercent().getTrafficSplitPercentage();
splitPercentages.forEach(trafficSplitPercentage -> {
RnibCell cell = cellMap.get(trafficSplitPercentage.getEcgi());
if (cell != null) {
RnibLink link = linkMap.get(cell.getEcgi(), ueId);
if (link != null) {
link.setTrafficPercent(trafficSplitPercentage);
} else {
log.warn("Could not find link between: {}-{}", cell.getEcgi(), ueId);
}
} else {
log.warn("Could not find cell with ECGI: {}", trafficSplitConfig.getEcgi());
}
});
}
}
/**
* Handle context update depending if its handoff or not.
*
* @param contextUpdate context update packet
* @param ctx channel context for the CELL
* @param handoff true if we handle a Hand Off
*/
private void handleContextUpdate(UEContextUpdate contextUpdate, ChannelHandlerContext ctx, boolean handoff) {
RnibUe ue;
RnibCell cell = xranStore.getCell(contextUpdate.getEcgi());
if (handoff) {
try {
ue = ueMap.get(ueIdQueue.take());
} catch (InterruptedException e) {
e.printStackTrace();
log.error(ExceptionUtils.getFullStackTrace(e));
ue = new RnibUe();
}
} else {
ue = new RnibUe();
}
ue.setMmeS1apId(contextUpdate.getMMEUES1APID());
ue.setEnbS1apId(contextUpdate.getENBUES1APID());
ue.setCrnti(contextUpdate.getCrnti());
hostAgent.addConnectedHost(ue, cell, ctx);
}
}
/**
* Internal class for NetworkConfigListener.
*/
class InternalNetworkConfigListener implements NetworkConfigListener {
@Override
public void event(NetworkConfigEvent event) {
switch (event.type()) {
case CONFIG_REGISTERED:
break;
case CONFIG_UNREGISTERED:
break;
case CONFIG_ADDED:
case CONFIG_UPDATED:
if (event.configClass() == CONFIG_CLASS) {
handleConfigEvent(event.config());
}
break;
case CONFIG_REMOVED:
break;
default:
break;
}
}
/**
* Handle config event.
*
* @param config
*/
private void handleConfigEvent(Optional<Config> config) {
if (!config.isPresent()) {
return;
}
xranConfig = (XranConfig) config.get();
northboundTimeout = xranConfig.getNorthBoundTimeout();
legitCells.putAll(xranConfig.activeCellSet());
controller.start(deviceAgent, hostAgent, packetAgent, xranConfig.getXrancPort());
}
}
}