blob: 14b93af2b8767811bbde193201528172c3445dbc [file] [log] [blame]
/*
* Copyright 2017-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.impl;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Lists;
import io.netty.channel.ChannelHandlerContext;
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.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.core.IdGenerator;
import org.onosproject.store.AbstractStore;
import org.onosproject.xran.XranService;
import org.onosproject.xran.XranStore;
import org.onosproject.xran.asn1lib.api.CRNTI;
import org.onosproject.xran.asn1lib.api.ECGI;
import org.onosproject.xran.asn1lib.api.EUTRANCellIdentifier;
import org.onosproject.xran.asn1lib.api.PCIARFCN;
import org.onosproject.xran.impl.entities.RnibCell;
import org.onosproject.xran.impl.entities.RnibLink;
import org.onosproject.xran.impl.entities.RnibSlice;
import org.onosproject.xran.impl.entities.RnibUe;
import org.onosproject.xran.impl.identifiers.EcgiCrntiPair;
import org.onosproject.xran.impl.identifiers.LinkId;
import org.slf4j.Logger;
import javax.xml.bind.DatatypeConverter;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Default xran store.
*/
@Component(immediate = true)
@Service
public class DefaultXranStore extends AbstractStore implements XranStore {
private static final String XRAN_APP_ID = "org.onosproject.xran";
private final Logger log = getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
protected ConcurrentMap<LinkId, RnibLink> linkMap = new ConcurrentHashMap<>();
private ConcurrentMap<ECGI, RnibCell> cellMap = new ConcurrentHashMap<>();
private ConcurrentMap<Long, RnibUe> ueMap = new ConcurrentHashMap<>();
private ConcurrentMap<Object, RnibSlice> sliceMap = new ConcurrentHashMap<>();
private XranService controller;
private IdGenerator ueIdGenerator;
// map to get the context channel based on ecgi
private ConcurrentMap<ECGI, ChannelHandlerContext> ctxMap = new ConcurrentHashMap<>();
// pci-arfcn to ecgi bimap
private BiMap<PCIARFCN, ECGI> pciarfcnMap = HashBiMap.create();
// ECGI, CRNTI pair of primary cell for specified UE.
private BiMap<EcgiCrntiPair, Long> crntiMap = HashBiMap.create();
@Activate
public void activate() {
ApplicationId appId = coreService.getAppId(XRAN_APP_ID);
// create ue id generator
ueIdGenerator = coreService.getIdGenerator("xran-ue-id");
log.info("XRAN Default Store Started");
}
@Deactivate
public void deactivate() {
linkMap.clear();
cellMap.clear();
ueMap.clear();
sliceMap.clear();
controller = null;
ueIdGenerator = null;
log.info("XRAN Default Store Stopped");
}
@Override
public List<RnibLink> getLinks() {
List<RnibLink> list = Lists.newArrayList();
list.addAll(linkMap.values());
return list;
}
@Override
public List<RnibLink> getLinks(ECGI ecgi) {
List<RnibLink> list = Lists.newArrayList();
list.addAll(
linkMap.keySet()
.stream()
.filter(k -> k.getEcgi().equals(ecgi))
.map(v -> linkMap.get(v))
.collect(Collectors.toList()));
return list;
}
@Override
public List<RnibLink> getLinks(String eciHex) {
List<RnibLink> list = Lists.newArrayList();
EUTRANCellIdentifier eci = hexToEci(eciHex);
list.addAll(
linkMap.keySet()
.stream()
.filter(k -> k.getEcgi().getEUTRANcellIdentifier().equals(eci))
.map(v -> linkMap.get(v))
.collect(Collectors.toList()));
return list;
}
@Override
public List<RnibLink> getLinks(long euId) {
List<RnibLink> list = Lists.newArrayList();
list.addAll(
linkMap.keySet()
.stream()
.filter(k -> k.getUeId().equals(euId))
.map(v -> linkMap.get(v))
.collect(Collectors.toList()));
return list;
}
@Override
public Optional<RnibLink> getLink(String eciHex, long euId) {
EUTRANCellIdentifier eci = hexToEci(eciHex);
Optional<LinkId> first = linkMap.keySet()
.stream()
.filter(linkId -> linkId.getEcgi().getEUTRANcellIdentifier().equals(eci) &&
linkId.getUeId().equals(euId))
.findFirst();
return first.map(linkId -> linkMap.get(linkId));
}
@Override
public void storeLink(RnibLink link) {
synchronized (this) {
if (link.getLinkId() != null) {
// if we add a primary link then change the primary to non serving
if (link.getType().equals(RnibLink.Type.SERVING_PRIMARY)) {
RnibUe ue = link.getLinkId().getUe();
getLinks(ue.getId())
.stream()
.filter(l -> l.getType().equals(RnibLink.Type.SERVING_PRIMARY))
.forEach(l -> l.setType(RnibLink.Type.NON_SERVING));
}
linkMap.put(link.getLinkId(), link);
}
}
}
@Override
public boolean removeLink(LinkId link) {
return linkMap.remove(link) != null;
}
@Override
public Optional<RnibLink> getLink(ECGI ecgi, Long ueId) {
LinkId linkId = LinkId.valueOf(ecgi, ueId);
return Optional.ofNullable(linkMap.get(linkId));
}
@Override
public Optional<RnibLink> getLink(ECGI src, CRNTI dst) {
return getUe(src, dst).flatMap(ue -> getLink(src, ue.getId()));
}
@Override
public void modifyLinkRrmConf(RnibLink link, JsonNode rrmConf) {
link.modifyRrmParameters(rrmConf);
}
@Override
public List<Object> getNodes() {
List<Object> list = Lists.newArrayList();
list.addAll(cellMap.values());
list.addAll(ueMap.values());
return list;
}
@Override
public List<RnibCell> getCellNodes() {
List<RnibCell> list = Lists.newArrayList();
list.addAll(cellMap.values());
return list;
}
@Override
public List<RnibUe> getUeNodes() {
List<RnibUe> list = Lists.newArrayList();
list.addAll(ueMap.values());
return list;
}
@Override
public Optional<Object> getNode(String nodeId) {
try {
return Optional.ofNullable(getCell(nodeId));
} catch (Exception ignored) {
}
return Optional.ofNullable(getUe(Long.parseLong(nodeId)));
}
@Override
public void storeCell(RnibCell cell) {
if (cell.getEcgi() != null) {
cellMap.putIfAbsent(cell.getEcgi(), cell);
}
}
@Override
public boolean removeCell(ECGI ecgi) {
pciarfcnMap.inverse().remove(ecgi);
ctxMap.remove(ecgi);
return cellMap.remove(ecgi) != null;
}
@Override
public boolean removeCell(PCIARFCN pciarfcn) {
return removeCell(pciarfcnMap.get(pciarfcn));
}
@Override
public Optional<RnibCell> getCell(String hexeci) {
EUTRANCellIdentifier eci = hexToEci(hexeci);
Optional<ECGI> first = cellMap.keySet()
.stream()
.filter(ecgi -> ecgi.getEUTRANcellIdentifier().equals(eci))
.findFirst();
return first.map(ecgi -> cellMap.get(ecgi));
}
@Override
public Optional<RnibCell> getCell(ECGI ecgi) {
return Optional.ofNullable(cellMap.get(ecgi));
}
@Override
public Optional<RnibCell> getCell(PCIARFCN id) {
ECGI ecgi;
ecgi = pciarfcnMap.get(id);
return getCell(ecgi);
}
@Override
public void modifyCellRrmConf(RnibCell cell, JsonNode rrmConf) throws Exception {
List<RnibLink> linkList = getLinks(cell.getEcgi());
List<RnibUe> ueList = linkList.stream()
.map(link -> link.getLinkId().getUe())
.collect(Collectors.toList());
cell.modifyRrmConfig(rrmConf, ueList);
}
@Override
public Optional<RnibSlice> getSlice(long sliceId) {
return Optional.ofNullable(sliceMap.get(sliceId));
}
@Override
public boolean createSlice(ObjectNode attributes) {
return false;
}
@Override
public boolean removeCell(long sliceId) {
return sliceMap.remove(sliceId) != null;
}
@Override
public Optional<XranService> getController() {
return Optional.ofNullable(controller);
}
@Override
public void setController(XranService controller) {
this.controller = controller;
}
@Override
public void storeUe(RnibUe ue) {
long newId;
if (ue.getId() == null) {
newId = ueIdGenerator.getNewId();
ue.setId(newId);
} else {
newId = ue.getId();
}
ueMap.put(newId, ue);
}
@Override
public void storeUe(RnibCell cell, RnibUe ue) {
storeUe(ue);
storeCrnti(cell, ue);
}
@Override
public boolean removeUe(long ueId) {
log.info("removing ue {} {}", ueId, ueMap);
crntiMap.inverse().remove(ueId);
return ueMap.remove(ueId) != null;
}
@Override
public void storePciArfcn(RnibCell value) {
value.getOptConf().ifPresent(cfg -> {
PCIARFCN pciarfcn = new PCIARFCN();
pciarfcn.setPci(cfg.getPci());
pciarfcn.setEarfcnDl(cfg.getEarfcnDl());
pciarfcnMap.put(pciarfcn, value.getEcgi());
});
}
@Override
public void storeCtx(RnibCell value, ChannelHandlerContext ctx) {
if (value.getEcgi() != null) {
ctxMap.put(value.getEcgi(), ctx);
storeCell(value);
}
}
@Override
public Optional<ChannelHandlerContext> getCtx(ECGI ecgi) {
return Optional.ofNullable(ctxMap.get(ecgi));
}
@Override
public BiMap<EcgiCrntiPair, Long> getCrnti() {
return crntiMap;
}
@Override
public void storeCrnti(RnibCell cell, RnibUe ue) {
CRNTI crnti = ue.getCrnti();
ECGI ecgi = cell.getEcgi();
if (crnti != null && ecgi != null) {
// check if there is an ecgi, crnti pair for this UE id.
EcgiCrntiPair oldPair = crntiMap.inverse().get(ue.getId()),
newPair = EcgiCrntiPair.valueOf(cell.getEcgi(), ue.getCrnti());
if (oldPair == null) {
crntiMap.put(newPair, ue.getId());
} else {
// remove old pair and add the new pair which corresponds to the primary cell.
crntiMap.inverse().remove(ue.getId());
crntiMap.put(newPair, ue.getId());
}
}
}
@Override
public void putPrimaryLink(RnibCell cell, RnibUe ue) {
RnibLink link = new RnibLink(cell, ue);
// set link to primary before storing
link.setType(RnibLink.Type.SERVING_PRIMARY);
storeLink(link);
storeCrnti(cell, ue);
}
@Override
public Optional<RnibLink> putNonServingLink(RnibCell cell, CRNTI crnti) {
return getUe(cell.getEcgi(), crnti).map(ue -> {
RnibLink link = new RnibLink(cell, ue);
storeLink(link);
return Optional.of(link);
}).orElse(Optional.empty());
}
@Override
public Optional<RnibLink> putNonServingLink(RnibCell cell, Long ueId) {
return getUe(ueId).map(ue -> {
RnibLink link = new RnibLink(cell, ue);
storeLink(link);
return Optional.of(link);
}).orElse(Optional.empty());
}
@Override
public Optional<CRNTI> getCrnti(Long ueId) {
return Optional.ofNullable(getCrnti().inverse().get(ueId).getValue());
}
@Override
public Optional<RnibCell> getPrimaryCell(RnibUe ue) {
// search all links for this UE and find PRIMARY.
Optional<RnibLink> primary = getLinks().stream()
.filter(l -> l.getType().equals(RnibLink.Type.SERVING_PRIMARY))
.filter(l -> l.getLinkId().getUe().equals(ue))
.findFirst();
return primary.flatMap(l -> Optional.of(l.getLinkId().getCell()));
}
@Override
public Optional<RnibUe> getUe(long ueId) {
return Optional.ofNullable(ueMap.get(ueId));
}
@Override
public Optional<RnibUe> getUe(ECGI ecgi, CRNTI crnti) {
return Optional.ofNullable(crntiMap.get(EcgiCrntiPair.valueOf(ecgi, crnti)))
.flatMap(this::getUe);
}
/**
* Get from HEX string the according ECI class object.
*
* @param eciHex HEX string
* @return ECI object if created successfully
*/
private EUTRANCellIdentifier hexToEci(String eciHex) {
byte[] hexBinary = DatatypeConverter.parseHexBinary(eciHex);
return new EUTRANCellIdentifier(hexBinary, 28);
}
}