blob: 14b93af2b8767811bbde193201528172c3445dbc [file] [log] [blame]
Dimitrios Mavrommatis96b255a2017-12-06 13:09:25 -08001/*
2 * Copyright 2017-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.xran.impl;
18
19import com.fasterxml.jackson.databind.JsonNode;
20import com.fasterxml.jackson.databind.node.ObjectNode;
21import com.google.common.collect.BiMap;
22import com.google.common.collect.HashBiMap;
23import com.google.common.collect.Lists;
24import io.netty.channel.ChannelHandlerContext;
25import org.apache.felix.scr.annotations.Activate;
26import org.apache.felix.scr.annotations.Component;
27import org.apache.felix.scr.annotations.Deactivate;
28import org.apache.felix.scr.annotations.Reference;
29import org.apache.felix.scr.annotations.ReferenceCardinality;
30import org.apache.felix.scr.annotations.Service;
31import org.onosproject.core.ApplicationId;
32import org.onosproject.core.CoreService;
33import org.onosproject.core.IdGenerator;
34import org.onosproject.store.AbstractStore;
35import org.onosproject.xran.XranService;
36import org.onosproject.xran.XranStore;
37import org.onosproject.xran.asn1lib.api.CRNTI;
38import org.onosproject.xran.asn1lib.api.ECGI;
39import org.onosproject.xran.asn1lib.api.EUTRANCellIdentifier;
40import org.onosproject.xran.asn1lib.api.PCIARFCN;
41import org.onosproject.xran.impl.entities.RnibCell;
42import org.onosproject.xran.impl.entities.RnibLink;
43import org.onosproject.xran.impl.entities.RnibSlice;
44import org.onosproject.xran.impl.entities.RnibUe;
45import org.onosproject.xran.impl.identifiers.EcgiCrntiPair;
46import org.onosproject.xran.impl.identifiers.LinkId;
47import org.slf4j.Logger;
48
49import javax.xml.bind.DatatypeConverter;
50import java.util.List;
51import java.util.Optional;
52import java.util.concurrent.ConcurrentHashMap;
53import java.util.concurrent.ConcurrentMap;
54import java.util.stream.Collectors;
55
56import static org.slf4j.LoggerFactory.getLogger;
57
58/**
59 * Default xran store.
60 */
61@Component(immediate = true)
62@Service
63public class DefaultXranStore extends AbstractStore implements XranStore {
64 private static final String XRAN_APP_ID = "org.onosproject.xran";
65
66 private final Logger log = getLogger(getClass());
67
68 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
69 protected CoreService coreService;
70
71 protected ConcurrentMap<LinkId, RnibLink> linkMap = new ConcurrentHashMap<>();
72 private ConcurrentMap<ECGI, RnibCell> cellMap = new ConcurrentHashMap<>();
73 private ConcurrentMap<Long, RnibUe> ueMap = new ConcurrentHashMap<>();
74 private ConcurrentMap<Object, RnibSlice> sliceMap = new ConcurrentHashMap<>();
75
76 private XranService controller;
77 private IdGenerator ueIdGenerator;
78
79 // map to get the context channel based on ecgi
80 private ConcurrentMap<ECGI, ChannelHandlerContext> ctxMap = new ConcurrentHashMap<>();
81 // pci-arfcn to ecgi bimap
82 private BiMap<PCIARFCN, ECGI> pciarfcnMap = HashBiMap.create();
83 // ECGI, CRNTI pair of primary cell for specified UE.
84 private BiMap<EcgiCrntiPair, Long> crntiMap = HashBiMap.create();
85
86
87 @Activate
88 public void activate() {
89 ApplicationId appId = coreService.getAppId(XRAN_APP_ID);
90
91 // create ue id generator
92 ueIdGenerator = coreService.getIdGenerator("xran-ue-id");
93
94 log.info("XRAN Default Store Started");
95 }
96
97 @Deactivate
98 public void deactivate() {
99 linkMap.clear();
100 cellMap.clear();
101 ueMap.clear();
102 sliceMap.clear();
103
104 controller = null;
105 ueIdGenerator = null;
106
107 log.info("XRAN Default Store Stopped");
108 }
109
110 @Override
111 public List<RnibLink> getLinks() {
112 List<RnibLink> list = Lists.newArrayList();
113 list.addAll(linkMap.values());
114 return list;
115 }
116
117 @Override
118 public List<RnibLink> getLinks(ECGI ecgi) {
119 List<RnibLink> list = Lists.newArrayList();
120 list.addAll(
121 linkMap.keySet()
122 .stream()
123 .filter(k -> k.getEcgi().equals(ecgi))
124 .map(v -> linkMap.get(v))
125 .collect(Collectors.toList()));
126 return list;
127 }
128
129 @Override
130 public List<RnibLink> getLinks(String eciHex) {
131 List<RnibLink> list = Lists.newArrayList();
132 EUTRANCellIdentifier eci = hexToEci(eciHex);
133
134 list.addAll(
135 linkMap.keySet()
136 .stream()
137 .filter(k -> k.getEcgi().getEUTRANcellIdentifier().equals(eci))
138 .map(v -> linkMap.get(v))
139 .collect(Collectors.toList()));
140
141 return list;
142 }
143
144 @Override
145 public List<RnibLink> getLinks(long euId) {
146 List<RnibLink> list = Lists.newArrayList();
147
148 list.addAll(
149 linkMap.keySet()
150 .stream()
151 .filter(k -> k.getUeId().equals(euId))
152 .map(v -> linkMap.get(v))
153 .collect(Collectors.toList()));
154
155 return list;
156 }
157
158
159 @Override
160 public Optional<RnibLink> getLink(String eciHex, long euId) {
161 EUTRANCellIdentifier eci = hexToEci(eciHex);
162
163 Optional<LinkId> first = linkMap.keySet()
164 .stream()
165 .filter(linkId -> linkId.getEcgi().getEUTRANcellIdentifier().equals(eci) &&
166 linkId.getUeId().equals(euId))
167 .findFirst();
168
169 return first.map(linkId -> linkMap.get(linkId));
170 }
171
172 @Override
173 public void storeLink(RnibLink link) {
174 synchronized (this) {
175 if (link.getLinkId() != null) {
176 // if we add a primary link then change the primary to non serving
177 if (link.getType().equals(RnibLink.Type.SERVING_PRIMARY)) {
178 RnibUe ue = link.getLinkId().getUe();
179 getLinks(ue.getId())
180 .stream()
181 .filter(l -> l.getType().equals(RnibLink.Type.SERVING_PRIMARY))
182 .forEach(l -> l.setType(RnibLink.Type.NON_SERVING));
183 }
184 linkMap.put(link.getLinkId(), link);
185 }
186 }
187 }
188
189 @Override
190 public boolean removeLink(LinkId link) {
191 return linkMap.remove(link) != null;
192 }
193
194 @Override
195 public Optional<RnibLink> getLink(ECGI ecgi, Long ueId) {
196 LinkId linkId = LinkId.valueOf(ecgi, ueId);
197 return Optional.ofNullable(linkMap.get(linkId));
198 }
199
200 @Override
201 public Optional<RnibLink> getLink(ECGI src, CRNTI dst) {
202 return getUe(src, dst).flatMap(ue -> getLink(src, ue.getId()));
203 }
204
205 @Override
206 public void modifyLinkRrmConf(RnibLink link, JsonNode rrmConf) {
207 link.modifyRrmParameters(rrmConf);
208 }
209
210 @Override
211 public List<Object> getNodes() {
212 List<Object> list = Lists.newArrayList();
213 list.addAll(cellMap.values());
214 list.addAll(ueMap.values());
215 return list;
216 }
217
218 @Override
219 public List<RnibCell> getCellNodes() {
220 List<RnibCell> list = Lists.newArrayList();
221 list.addAll(cellMap.values());
222 return list;
223 }
224
225 @Override
226 public List<RnibUe> getUeNodes() {
227 List<RnibUe> list = Lists.newArrayList();
228 list.addAll(ueMap.values());
229 return list;
230 }
231
232 @Override
233 public Optional<Object> getNode(String nodeId) {
234 try {
235 return Optional.ofNullable(getCell(nodeId));
236 } catch (Exception ignored) {
237 }
238 return Optional.ofNullable(getUe(Long.parseLong(nodeId)));
239 }
240
241 @Override
242 public void storeCell(RnibCell cell) {
243 if (cell.getEcgi() != null) {
244 cellMap.putIfAbsent(cell.getEcgi(), cell);
245 }
246 }
247
248 @Override
249 public boolean removeCell(ECGI ecgi) {
250 pciarfcnMap.inverse().remove(ecgi);
251 ctxMap.remove(ecgi);
252 return cellMap.remove(ecgi) != null;
253 }
254
255 @Override
256 public boolean removeCell(PCIARFCN pciarfcn) {
257 return removeCell(pciarfcnMap.get(pciarfcn));
258 }
259
260 @Override
261 public Optional<RnibCell> getCell(String hexeci) {
262 EUTRANCellIdentifier eci = hexToEci(hexeci);
263 Optional<ECGI> first = cellMap.keySet()
264 .stream()
265 .filter(ecgi -> ecgi.getEUTRANcellIdentifier().equals(eci))
266 .findFirst();
267 return first.map(ecgi -> cellMap.get(ecgi));
268 }
269
270 @Override
271 public Optional<RnibCell> getCell(ECGI ecgi) {
272 return Optional.ofNullable(cellMap.get(ecgi));
273 }
274
275 @Override
276 public Optional<RnibCell> getCell(PCIARFCN id) {
277 ECGI ecgi;
278 ecgi = pciarfcnMap.get(id);
279 return getCell(ecgi);
280 }
281
282 @Override
283 public void modifyCellRrmConf(RnibCell cell, JsonNode rrmConf) throws Exception {
284 List<RnibLink> linkList = getLinks(cell.getEcgi());
285 List<RnibUe> ueList = linkList.stream()
286 .map(link -> link.getLinkId().getUe())
287 .collect(Collectors.toList());
288
289 cell.modifyRrmConfig(rrmConf, ueList);
290 }
291
292 @Override
293 public Optional<RnibSlice> getSlice(long sliceId) {
294 return Optional.ofNullable(sliceMap.get(sliceId));
295 }
296
297 @Override
298 public boolean createSlice(ObjectNode attributes) {
299 return false;
300 }
301
302 @Override
303 public boolean removeCell(long sliceId) {
304 return sliceMap.remove(sliceId) != null;
305 }
306
307 @Override
308 public Optional<XranService> getController() {
309 return Optional.ofNullable(controller);
310 }
311
312 @Override
313 public void setController(XranService controller) {
314 this.controller = controller;
315 }
316
317 @Override
318 public void storeUe(RnibUe ue) {
319 long newId;
320 if (ue.getId() == null) {
321 newId = ueIdGenerator.getNewId();
322 ue.setId(newId);
323 } else {
324 newId = ue.getId();
325 }
326 ueMap.put(newId, ue);
327 }
328
329 @Override
330 public void storeUe(RnibCell cell, RnibUe ue) {
331 storeUe(ue);
332 storeCrnti(cell, ue);
333 }
334
335 @Override
336 public boolean removeUe(long ueId) {
337 log.info("removing ue {} {}", ueId, ueMap);
338 crntiMap.inverse().remove(ueId);
339 return ueMap.remove(ueId) != null;
340 }
341
342 @Override
343 public void storePciArfcn(RnibCell value) {
344 value.getOptConf().ifPresent(cfg -> {
345 PCIARFCN pciarfcn = new PCIARFCN();
346 pciarfcn.setPci(cfg.getPci());
347 pciarfcn.setEarfcnDl(cfg.getEarfcnDl());
348 pciarfcnMap.put(pciarfcn, value.getEcgi());
349 });
350 }
351
352 @Override
353 public void storeCtx(RnibCell value, ChannelHandlerContext ctx) {
354 if (value.getEcgi() != null) {
355 ctxMap.put(value.getEcgi(), ctx);
356 storeCell(value);
357 }
358 }
359
360 @Override
361 public Optional<ChannelHandlerContext> getCtx(ECGI ecgi) {
362 return Optional.ofNullable(ctxMap.get(ecgi));
363 }
364
365 @Override
366 public BiMap<EcgiCrntiPair, Long> getCrnti() {
367 return crntiMap;
368 }
369
370 @Override
371 public void storeCrnti(RnibCell cell, RnibUe ue) {
372 CRNTI crnti = ue.getCrnti();
373 ECGI ecgi = cell.getEcgi();
374
375 if (crnti != null && ecgi != null) {
376 // check if there is an ecgi, crnti pair for this UE id.
377 EcgiCrntiPair oldPair = crntiMap.inverse().get(ue.getId()),
378 newPair = EcgiCrntiPair.valueOf(cell.getEcgi(), ue.getCrnti());
379
380 if (oldPair == null) {
381 crntiMap.put(newPair, ue.getId());
382 } else {
383 // remove old pair and add the new pair which corresponds to the primary cell.
384 crntiMap.inverse().remove(ue.getId());
385 crntiMap.put(newPair, ue.getId());
386 }
387 }
388 }
389
390 @Override
391 public void putPrimaryLink(RnibCell cell, RnibUe ue) {
392 RnibLink link = new RnibLink(cell, ue);
393 // set link to primary before storing
394 link.setType(RnibLink.Type.SERVING_PRIMARY);
395 storeLink(link);
396 storeCrnti(cell, ue);
397 }
398
399 @Override
400 public Optional<RnibLink> putNonServingLink(RnibCell cell, CRNTI crnti) {
401 return getUe(cell.getEcgi(), crnti).map(ue -> {
402 RnibLink link = new RnibLink(cell, ue);
403 storeLink(link);
404 return Optional.of(link);
405 }).orElse(Optional.empty());
406 }
407
408 @Override
409 public Optional<RnibLink> putNonServingLink(RnibCell cell, Long ueId) {
410 return getUe(ueId).map(ue -> {
411 RnibLink link = new RnibLink(cell, ue);
412 storeLink(link);
413 return Optional.of(link);
414 }).orElse(Optional.empty());
415 }
416
417 @Override
418 public Optional<CRNTI> getCrnti(Long ueId) {
419 return Optional.ofNullable(getCrnti().inverse().get(ueId).getValue());
420 }
421
422 @Override
423 public Optional<RnibCell> getPrimaryCell(RnibUe ue) {
424 // search all links for this UE and find PRIMARY.
425 Optional<RnibLink> primary = getLinks().stream()
426 .filter(l -> l.getType().equals(RnibLink.Type.SERVING_PRIMARY))
427 .filter(l -> l.getLinkId().getUe().equals(ue))
428 .findFirst();
429
430 return primary.flatMap(l -> Optional.of(l.getLinkId().getCell()));
431 }
432
433 @Override
434 public Optional<RnibUe> getUe(long ueId) {
435 return Optional.ofNullable(ueMap.get(ueId));
436 }
437
438 @Override
439 public Optional<RnibUe> getUe(ECGI ecgi, CRNTI crnti) {
440 return Optional.ofNullable(crntiMap.get(EcgiCrntiPair.valueOf(ecgi, crnti)))
441 .flatMap(this::getUe);
442 }
443
444 /**
445 * Get from HEX string the according ECI class object.
446 *
447 * @param eciHex HEX string
448 * @return ECI object if created successfully
449 */
450 private EUTRANCellIdentifier hexToEci(String eciHex) {
451 byte[] hexBinary = DatatypeConverter.parseHexBinary(eciHex);
452 return new EUTRANCellIdentifier(hexBinary, 28);
453 }
454}