blob: a3740bc7dcdadaae0d7e28252c750ed4e74c993b [file] [log] [blame]
slowr13fa5b02017-08-08 16:32:31 -07001/*
2 * Copyright 2015-present Open Networking Laboratory
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.controller;
18
19import com.google.common.collect.Sets;
20import io.netty.channel.ChannelHandlerContext;
21import io.netty.channel.sctp.SctpMessage;
22import org.apache.commons.lang.exception.ExceptionUtils;
23import org.apache.felix.scr.annotations.*;
24import org.onosproject.core.ApplicationId;
25import org.onosproject.core.CoreService;
26import org.onosproject.net.config.*;
27import org.onosproject.net.config.basics.SubjectFactories;
28import org.onosproject.net.device.DeviceEvent;
29import org.onosproject.net.device.DeviceListener;
30import org.onosproject.net.device.DeviceService;
31import org.onosproject.net.host.HostEvent;
32import org.onosproject.net.host.HostListener;
33import org.onosproject.net.host.HostService;
34import org.onosproject.xran.XranStore;
35import org.onosproject.xran.codecs.api.*;
36import org.onosproject.xran.codecs.pdu.*;
37import org.onosproject.xran.entities.RnibCell;
38import org.onosproject.xran.entities.RnibLink;
39import org.onosproject.xran.entities.RnibUe;
40import org.onosproject.xran.identifiers.LinkId;
41import org.onosproject.xran.impl.XranConfig;
42import org.onosproject.xran.providers.XranDeviceListener;
43import org.onosproject.xran.providers.XranHostListener;
44import org.onosproject.xran.samplemessages.*;
45import org.onosproject.xran.wrapper.CellMap;
46import org.onosproject.xran.wrapper.LinkMap;
47import org.onosproject.xran.wrapper.UeMap;
48import org.openmuc.jasn1.ber.types.BerInteger;
49import org.slf4j.Logger;
50import org.slf4j.LoggerFactory;
51
slowr67d05e42017-08-11 20:37:22 -070052import javax.xml.bind.DatatypeConverter;
slowr13fa5b02017-08-08 16:32:31 -070053import java.io.IOException;
54import java.util.*;
slowr67d05e42017-08-11 20:37:22 -070055import java.util.concurrent.*;
slowr13fa5b02017-08-08 16:32:31 -070056import java.util.stream.Collectors;
57
58import static org.onosproject.net.DeviceId.deviceId;
slowr67d05e42017-08-11 20:37:22 -070059import static org.onosproject.xran.controller.XranChannelHandler.getSctpMessage;
slowr13fa5b02017-08-08 16:32:31 -070060import static org.onosproject.xran.entities.RnibCell.decodeDeviceId;
61import static org.onosproject.xran.entities.RnibCell.uri;
slowr13fa5b02017-08-08 16:32:31 -070062import static org.onosproject.xran.entities.RnibUe.hostIdtoMME;
63
64/**
65 * Created by dimitris on 7/20/17.
66 */
67@Component(immediate = true)
68@Service
69public class XranControllerImpl implements XranController {
70 private static final String XRAN_APP_ID = "org.onosproject.xran";
71 private static final Class<XranConfig> CONFIG_CLASS = XranConfig.class;
72
73 private static final Logger log =
74 LoggerFactory.getLogger(XranControllerImpl.class);
75 /* CONFIG */
76 private final InternalNetworkConfigListener configListener =
77 new InternalNetworkConfigListener();
78 /* VARIABLES */
79 private final Controller controller = new Controller();
80 private XranConfig xranConfig;
81 private ApplicationId appId;
82 /* Services */
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 private DeviceService deviceService;
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 private HostService hostService;
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 private NetworkConfigRegistry registry;
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 private NetworkConfigService configService;
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 private CoreService coreService;
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 private XranStore xranStore;
95 private ConfigFactory<ApplicationId, XranConfig> xranConfigFactory =
96 new ConfigFactory<ApplicationId, XranConfig>(
97 SubjectFactories.APP_SUBJECT_FACTORY, CONFIG_CLASS, "xran") {
98 @Override
99 public XranConfig createConfig() {
100 return new XranConfig();
101 }
102 };
103 /* WRAPPERS */
104 private CellMap cellMap;
105 private UeMap ueMap;
106 private LinkMap linkMap;
107 /* MAPS */
108 private ConcurrentMap<String, ECGI> legitCells = new ConcurrentHashMap<>();
slowr67d05e42017-08-11 20:37:22 -0700109 private ConcurrentMap<CRNTI, SynchronousQueue<String>> hoQueue = new ConcurrentHashMap<CRNTI, SynchronousQueue<String>>();
110 private ConcurrentMap<ECGI, SynchronousQueue<String>> RRMCellQueue = new ConcurrentHashMap<ECGI, SynchronousQueue<String>>();
slowr13fa5b02017-08-08 16:32:31 -0700111 /* AGENTS */
112 private InternalXranDeviceAgent deviceAgent = new InternalXranDeviceAgent();
113 private InternalXranHostAgent hostAgent = new InternalXranHostAgent();
114 private InternalXranPacketAgent packetAgent = new InternalXranPacketAgent();
115 /* LISTENERS */
116 private Set<XranDeviceListener> xranDeviceListeners = new CopyOnWriteArraySet<>();
117 private Set<XranHostListener> xranHostListeners = new CopyOnWriteArraySet<>();
118 private InternalDeviceListener device_listener = new InternalDeviceListener();
119 private InternalHostListener host_listener = new InternalHostListener();
120
121 @Activate
122 public void activate() {
123 appId = coreService.registerApplication(XRAN_APP_ID);
124
125 configService.addListener(configListener);
126 registry.registerConfigFactory(xranConfigFactory);
127 deviceService.addListener(device_listener);
128 hostService.addListener(host_listener);
129
130 cellMap = new CellMap(xranStore);
131 ueMap = new UeMap(xranStore);
132 linkMap = new LinkMap(xranStore);
133
134 xranStore.setController(this);
135
136 log.info("XRAN Controller Started");
137 }
138
139 @Deactivate
140 public void deactivate() {
141 controller.stop();
142
143 deviceService.removeListener(device_listener);
144 hostService.removeListener(host_listener);
145
146 legitCells.clear();
147
148 configService.removeListener(configListener);
149 registry.unregisterConfigFactory(xranConfigFactory);
150
151 log.info("XRAN Controller Stopped");
152 }
153
154 @Override
slowr67d05e42017-08-11 20:37:22 -0700155 public SynchronousQueue<String> sendHORequest(RnibLink newLink, RnibLink oldLink) {
156 ECGI newEcgi = newLink.getLinkId().getSourceId(),
157 oldEcgi = oldLink.getLinkId().getSourceId();
158 CRNTI crnti = linkMap.getCrnti(newLink.getLinkId().getDestinationId());
159 ChannelHandlerContext newCtx = cellMap.getCtx(newEcgi),
160 oldCtx = cellMap.getCtx(oldEcgi);
161
162 try {
163 XrancPdu xrancPdu = HandoffRequest.constructPacket(crnti, oldEcgi, newEcgi);
164 newCtx.writeAndFlush(getSctpMessage(xrancPdu));
165 oldCtx.writeAndFlush(getSctpMessage(xrancPdu));
166 } catch (IOException e) {
167 e.printStackTrace();
168 }
169
170 SynchronousQueue<String> queue = new SynchronousQueue<>();
171 hoQueue.put(crnti, queue);
172
173 return queue;
174 }
175
176 @Override
slowr13fa5b02017-08-08 16:32:31 -0700177 public void addListener(XranDeviceListener listener) {
178 xranDeviceListeners.add(listener);
179 }
180
181 @Override
182 public void addListener(XranHostListener listener) {
183 xranHostListeners.add(listener);
184 }
185
186 @Override
187 public void removeListener(XranDeviceListener listener) {
188 xranDeviceListeners.remove(listener);
189 }
190
191 @Override
192 public void removeListener(XranHostListener listener) {
193 xranHostListeners.remove(listener);
194 }
195
slowr67d05e42017-08-11 20:37:22 -0700196 @Override
197 public SynchronousQueue<String> sendModifiedRRMConf(RnibCell cell) {
198 ECGI ecgi = cell.getEcgi();
199 ChannelHandlerContext ctx = cellMap.getCtx(ecgi);
200 try {
201 XrancPdu pdu = RRMConfig.constructPacket(cell);
202 ctx.writeAndFlush(getSctpMessage(pdu));
203 } catch (IOException e) {
204 e.printStackTrace();
205 }
206 SynchronousQueue<String> queue = new SynchronousQueue<>();
207 RRMCellQueue.put(ecgi, queue);
208
209 return queue;
210 }
211
slowr13fa5b02017-08-08 16:32:31 -0700212 private void restartTimer(RnibUe ue) {
213 Timer timer = new Timer();
214 ue.setTimer(timer);
215 log.info("Starting UE timer...");
216 timer.schedule(new TimerTask() {
217 @Override
218 public void run() {
slowr67d05e42017-08-11 20:37:22 -0700219 if (ue.getState() == RnibUe.State.IDLE) {
slowr13fa5b02017-08-08 16:32:31 -0700220 hostAgent.removeConnectedHost(ue);
221 log.info("UE is removed after 10 seconds of IDLE");
222 } else {
223 log.info("UE not removed cause its ACTIVE");
224 }
225 }
226 }, 10000);
227 }
228
229 private void restartTimer(RnibLink link) {
230 Timer timer = new Timer();
231 link.setTimer(timer);
232 log.info("Starting Link timer...");
233 timer.schedule(new TimerTask() {
234 @Override
235 public void run() {
236 LinkId linkId = link.getLinkId();
237 xranStore.removeLink(linkId);
238 log.info("Link is removed after not receiving Meas Reports for 10 seconds");
239 }
240 }, 10000);
241
242 }
243
244 class InternalDeviceListener implements DeviceListener {
245
246 @Override
247 public void event(DeviceEvent event) {
248 log.info("Device Event {}", event);
249 switch (event.type()) {
250 case DEVICE_ADDED: {
251 try {
252 ECGI ecgi = decodeDeviceId(event.subject().id());
253 RnibCell cell = cellMap.get(ecgi);
254 if (cell != null) {
255 Timer timer = new Timer();
256 timer.scheduleAtFixedRate(
257 new TimerTask() {
258 @Override
259 public void run() {
260 CellConfigReport conf = cell.getConf();
261 if (conf == null) {
262 try {
263 ChannelHandlerContext ctx = cellMap.getCtx(ecgi);
slowr67d05e42017-08-11 20:37:22 -0700264 XrancPdu xrancPdu = ConfigEncoderDecoder.constructPacket(ecgi);
265 ctx.writeAndFlush(getSctpMessage(xrancPdu));
slowr13fa5b02017-08-08 16:32:31 -0700266 } catch (IOException e) {
267 log.error(ExceptionUtils.getFullStackTrace(e));
268 e.printStackTrace();
269 }
270 } else {
271 // FIXME: maybe remove this map.
272 cellMap.putPciArfcn(cell);
273 try {
274 ChannelHandlerContext ctx = cellMap.
275 getCtx(ecgi);
276 XrancPdu xrancPdu = L2MeasConf.constructPacket(ecgi, xranConfig.getL2MeasInterval());
277 cell.setMeasConfig(xrancPdu.getBody().getL2MeasConfig());
slowr67d05e42017-08-11 20:37:22 -0700278 SctpMessage sctpMessage = getSctpMessage(xrancPdu);
slowr13fa5b02017-08-08 16:32:31 -0700279 ctx.writeAndFlush(sctpMessage);
280 } catch (IOException e) {
281 log.error(ExceptionUtils.getFullStackTrace(e));
282 e.printStackTrace();
283 }
284 timer.cancel();
285 timer.purge();
286 }
287 }
288 },
289 0,
290 xranConfig.getConfigRequestInterval() * 1000
291 );
292 }
293 } catch (IOException e) {
294 log.error(ExceptionUtils.getFullStackTrace(e));
295 e.printStackTrace();
296 }
297 break;
298 }
299 default: {
300 break;
301 }
302 }
303 }
304 }
305
306 class InternalHostListener implements HostListener {
307
308 @Override
309 public void event(HostEvent event) {
310 log.info("Host Event {}", event);
311 switch (event.type()) {
312 case HOST_ADDED:
313 case HOST_MOVED: {
314 RnibUe ue = ueMap.get(hostIdtoMME(event.subject().id()));
315 if (ue != null) {
316 ECGI ecgi_primary = linkMap.getPrimaryCell(ue);
317 RnibCell primary = cellMap.get(ecgi_primary);
318 ue.setMeasConfig(null);
319 if (primary != null) {
320 Timer timer = new Timer();
321 timer.scheduleAtFixedRate(
322 new TimerTask() {
323 @Override
324 public void run() {
325 if (ue.getCapability() == null) {
326 try {
327 ChannelHandlerContext ctx = cellMap.getCtx(primary.getEcgi());
slowr67d05e42017-08-11 20:37:22 -0700328 XrancPdu xrancPdu = UECapabilityEnq.constructPacket(
329 primary.getEcgi(),
330 ue.getRanId());
331 ctx.writeAndFlush(getSctpMessage(xrancPdu));
slowr13fa5b02017-08-08 16:32:31 -0700332 } catch (IOException e) {
333 log.warn(ExceptionUtils.getFullStackTrace(e));
334 e.printStackTrace();
335 }
336 } else {
337 if (ue.getMeasConfig() == null) {
338 try {
339 ChannelHandlerContext ctx = cellMap.getCtx(primary.getEcgi());
340 RXSigMeasConfig.MeasCells measCells = new RXSigMeasConfig.MeasCells();
341 xranStore.getCellNodes().forEach(cell -> {
342 CellConfigReport cellReport = cell.getConf();
343 if (cellReport != null) {
344 PCIARFCN pciarfcn = new PCIARFCN();
345 pciarfcn.setPci(cellReport.getPci());
346 pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
347 measCells.setPCIARFCN(pciarfcn);
348 }
349 });
350 XrancPdu xrancPdu = SignalMeasConfig.constructPacket(
351 primary.getEcgi(),
352 ue.getRanId(),
353 measCells,
354 xranConfig.getRxSignalInterval()
355 );
356 ue.setMeasConfig(xrancPdu.getBody().getRXSigMeasConfig());
slowr67d05e42017-08-11 20:37:22 -0700357 ctx.writeAndFlush(getSctpMessage(xrancPdu));
slowr13fa5b02017-08-08 16:32:31 -0700358 } catch (IOException e) {
359 log.warn(ExceptionUtils.getFullStackTrace(e));
360 e.printStackTrace();
361 }
362 }
363 timer.cancel();
364 timer.purge();
365 }
366 }
367 },
368 0,
369 xranConfig.getConfigRequestInterval() * 1000
370 );
371 }
372 }
373 break;
374 }
375 default: {
376 break;
377 }
378 }
379 }
380 }
381
382 public class InternalXranDeviceAgent implements XranDeviceAgent {
383
384 private final Logger log = LoggerFactory.getLogger(InternalXranDeviceAgent.class);
385
386 @Override
387 public boolean addConnectedCell(String host, ChannelHandlerContext ctx) {
388 ECGI ecgi = legitCells.get(host);
389
390 if (ecgi == null) {
391 log.error("Device is not a legit source; ignoring...");
392 } else {
393 log.info("Device exists in configuration; registering...");
394 RnibCell storeCell = cellMap.get(ecgi);
395 if (storeCell == null) {
396 storeCell = new RnibCell();
397 storeCell.setEcgi(ecgi);
398 cellMap.put(storeCell, ctx);
399
400 for (XranDeviceListener l : xranDeviceListeners) {
401 l.deviceAdded(storeCell);
402 }
403 return true;
404 } else {
405 log.error("Device already registered; ignoring...");
406 }
407 }
408 ctx.close();
409 return false;
410 }
411
412 @Override
413 public boolean removeConnectedCell(String host) {
414 ECGI ecgi = legitCells.get(host);
415 List<RnibLink> linksByECGI = xranStore.getLinksByECGI(ecgi);
416
417 linksByECGI.forEach(rnibLink -> xranStore.removeLink(rnibLink.getLinkId()));
418
419 if (cellMap.remove(ecgi)) {
420 for (XranDeviceListener l : xranDeviceListeners) {
421 l.deviceRemoved(deviceId(uri(ecgi)));
422 }
423 return true;
424 }
425 return false;
426 }
427 }
428
429 public class InternalXranHostAgent implements XranHostAgent {
430
431 @Override
432 public boolean addConnectedHost(RnibUe ue, RnibCell cell, ChannelHandlerContext ctx) {
433
434 if (ueMap.get(ue.getMmeS1apId()) != null) {
435 linkMap.putPrimaryLink(cell, ue);
436
437 Set<ECGI> ecgiSet = xranStore.getLinksByUeId(ue.getMmeS1apId().longValue())
438 .stream()
slowr67d05e42017-08-11 20:37:22 -0700439 .map(l -> l.getLinkId().getSourceId())
slowr13fa5b02017-08-08 16:32:31 -0700440 .collect(Collectors.toSet());
441
442 for (XranHostListener l : xranHostListeners) {
443 l.hostAdded(ue, ecgiSet);
444 }
445 return true;
446 } else {
447 ueMap.put(ue);
448 linkMap.putPrimaryLink(cell, ue);
449
450 Set<ECGI> ecgiSet = Sets.newConcurrentHashSet();
451 ecgiSet.add(cell.getEcgi());
452 for (XranHostListener l : xranHostListeners) {
453 l.hostAdded(ue, ecgiSet);
454 }
455 return true;
456 }
457
458 }
459
460 @Override
461 public boolean removeConnectedHost(RnibUe ue) {
462 List<RnibLink> links = xranStore.getLinksByUeId(ue.getMmeS1apId().longValue());
463 links.forEach(rnibLink -> xranStore.removeLink(rnibLink.getLinkId()));
464 if (ueMap.remove(ue.getMmeS1apId())) {
465 for (XranHostListener l : xranHostListeners) {
466 l.hostRemoved(ue.getHostId());
467 }
468 return true;
469 }
470 return false;
471 }
472 }
473
474 public class InternalXranPacketAgent implements XranPacketProcessor {
475 @Override
476 public void handlePacket(XrancPdu recv_pdu, ChannelHandlerContext ctx) throws IOException {
477 XrancPdu send_pdu;
478
479 int apiID = recv_pdu.getHdr().getApiId().intValue();
480 log.debug("Received message: {}", recv_pdu);
481 switch (apiID) {
482 case 1: {
483 // Decode Cell config report.
484 CellConfigReport report = recv_pdu.getBody().getCellConfigReport();
485
486 ECGI ecgi = report.getEcgi();
487
488 RnibCell cell = xranStore.getCell(ecgi);
489 cell.setConf(report);
490
491 break;
492 }
493 case 2: {
494 // Decode UE Admission Request.
495 UEAdmissionRequest ueAdmissionRequest = recv_pdu.getBody().getUEAdmissionRequest();
496
497 ECGI ecgi = ueAdmissionRequest.getEcgi();
498 if (xranStore.getCell(ecgi) != null) {
499 CRNTI crnti = ueAdmissionRequest.getCrnti();
500 send_pdu = UEAdmEncoderDecoder.constructPacket(ecgi, crnti);
slowr67d05e42017-08-11 20:37:22 -0700501 ctx.writeAndFlush(getSctpMessage(send_pdu));
slowr13fa5b02017-08-08 16:32:31 -0700502 } else {
503 log.warn("Could not find ECGI in registered cells: {}", ecgi);
504 }
505 break;
506 }
507 case 4: {
508 // Decode UE Admission Status.
509 UEAdmissionStatus ueAdmissionStatus = recv_pdu.getBody().getUEAdmissionStatus();
510
511 RnibUe ue = ueMap.get(ueAdmissionStatus.getCrnti());
512 if (ue != null) {
513 if (ueAdmissionStatus.getAdmEstStatus().value.intValue() == 0) {
slowr67d05e42017-08-11 20:37:22 -0700514 ue.setState(RnibUe.State.ACTIVE);
slowr13fa5b02017-08-08 16:32:31 -0700515 } else {
slowr67d05e42017-08-11 20:37:22 -0700516 ue.setState(RnibUe.State.IDLE);
slowr13fa5b02017-08-08 16:32:31 -0700517 }
518 }
519 break;
520 }
521 case 5: {
522 // Decode UE Admission Context Update.
523 UEAttachComplete ueAttachComplete = recv_pdu.getBody().getUEAttachComplete();
524
525 RnibCell cell = xranStore.getCell(ueAttachComplete.getEcgi());
526
527 RnibUe ue = ueMap.get(ueAttachComplete.getMMEUES1APID());
528 if (ueMap.get(ueAttachComplete.getMMEUES1APID()) == null) {
529 ue = new RnibUe();
530 }
531
532 ue.setMmeS1apId(ueAttachComplete.getMMEUES1APID());
533 ue.setEnbS1apId(ueAttachComplete.getENBUES1APID());
534 ue.setRanId(ueAttachComplete.getCrnti());
535
536 hostAgent.addConnectedHost(ue, cell, ctx);
537 break;
538 }
539 case 6: {
540 // Decode UE Reconfig_Ind.
541 UEReconfigInd ueReconfigInd = recv_pdu.getBody().getUEReconfigInd();
542 RnibUe ue = ueMap.get(ueReconfigInd.getCrntiOld());
543
544 if (ue != null) {
545 ue.setRanId(ueReconfigInd.getCrntiNew());
546 } else {
547 log.warn("Could not find UE with this CRNTI: {}", ueReconfigInd.getCrntiOld());
548 }
549 break;
550 }
551 case 7: {
552 // If xRANc wants to deactivate UE, we pass UEReleaseInd from xRANc to eNB.
553 // Decode UE Release_Ind.
554 UEReleaseInd ueReleaseInd = recv_pdu.getBody().getUEReleaseInd();
555 RnibUe ue = ueMap.get(ueReleaseInd.getCrnti());
556 if (ue != null) {
slowr67d05e42017-08-11 20:37:22 -0700557 ue.setState(RnibUe.State.IDLE);
slowr13fa5b02017-08-08 16:32:31 -0700558 restartTimer(ue);
559 }
560 break;
561 }
562 case 8: {
563 // Decode Bearer Adm Request
564 BearerAdmissionRequest bearerAdmissionRequest = recv_pdu.getBody().getBearerAdmissionRequest();
565
566 ECGI ecgi = bearerAdmissionRequest.getEcgi();
567 CRNTI crnti = bearerAdmissionRequest.getCrnti();
568 ERABParams erabParams = bearerAdmissionRequest.getErabParams();
569 RnibLink link = linkMap.get(ecgi, crnti);
570 if (link != null) {
571 link.setBearerParameters(erabParams);
572 } else {
573 log.warn("Could not find link between {}-{}", ecgi, crnti);
574 }
575
576 BerInteger numErabs = bearerAdmissionRequest.getNumErabs();
577
578 send_pdu = BearerEncoderDecoder.constructPacket(ecgi, crnti, erabParams, numErabs);
579 // Encode and send Bearer Admission Response - API ID 9
slowr67d05e42017-08-11 20:37:22 -0700580 ctx.writeAndFlush(getSctpMessage(send_pdu));
slowr13fa5b02017-08-08 16:32:31 -0700581 break;
582 }
583 case 10: {
584 //Decode Bearer Admission Status
585 BearerAdmissionStatus bearerAdmissionStatus = recv_pdu.getBody().getBearerAdmissionStatus();
586
587// ECGI ecgi = bearerAdmissionStatus.getEcgi();
588// CRNTI crnti = bearerAdmissionStatus.getCrnti();
589//
590// RnibLink link = linkMap.get(ecgi, crnti);
591
592 break;
593 }
594 case 11: {
595 //Decode Bearer Release Ind
596 BearerReleaseInd bearerReleaseInd = recv_pdu.getBody().getBearerReleaseInd();
597
598 ECGI ecgi = bearerReleaseInd.getEcgi();
599 CRNTI crnti = bearerReleaseInd.getCrnti();
600 RnibLink link = linkMap.get(ecgi, crnti);
601
602 List<ERABID> erabidsRelease = bearerReleaseInd.getErabIds().getERABID();
603 List<ERABParamsItem> erabParamsItem = link.getBearerParameters().getERABParamsItem();
604
605 List<ERABParamsItem> unreleased = erabParamsItem
606 .stream()
607 .filter(item -> {
608 Optional<ERABID> any = erabidsRelease.stream().filter(id -> id.equals(item.getId())).findAny();
609 return !any.isPresent();
610 }).collect(Collectors.toList());
611
612 link.getBearerParameters().setERABParamsItem(new ArrayList<>(unreleased));
613
614 break;
615 }
616 case 12: {
617 // Don't know what will invoke sending UE CAPABILITY ENQUIRY
618 // Encode and send UE CAPABILITY ENQUIRY
619 UECapabilityEnquiry ueCapabilityEnquiry = recv_pdu.getBody().getUECapabilityEnquiry();
620 XrancPdu xrancPdu = UECapabilityEnq.constructPacket(ueCapabilityEnquiry.getEcgi(), ueCapabilityEnquiry.getCrnti());
slowr67d05e42017-08-11 20:37:22 -0700621 ctx.writeAndFlush(getSctpMessage(xrancPdu));
slowr13fa5b02017-08-08 16:32:31 -0700622 break;
623 }
624 case 13: {
625 // Decode UE Capability Info
626 UECapabilityInfo capabilityInfo = recv_pdu.getBody().getUECapabilityInfo();
627
628 RnibUe ue = ueMap.get(capabilityInfo.getCrnti());
629 if (ue != null) {
630 ue.setCapability(capabilityInfo);
631 } else {
632 log.warn("Could not find UE with this CRNTI: {}", capabilityInfo.getCrnti());
633 }
634 break;
635
636 //14, 15, 16 are handoff
637 }
slowr67d05e42017-08-11 20:37:22 -0700638 case 15: {
639 HOFailure hoFailure = recv_pdu.getBody().getHOFailure();
640
641 try {
642 hoQueue.get(hoFailure.getCrnti())
643 .put("Hand Over Failed with cause: " + hoFailure.getCause());
644 } catch (InterruptedException e) {
645 log.error(ExceptionUtils.getFullStackTrace(e));
646 e.printStackTrace();
647 } finally {
648 hoQueue.remove(hoFailure.getCrnti());
649 }
650 break;
651 }
652 case 16: {
653 HOComplete hoComplete = recv_pdu.getBody().getHOComplete();
654
655 RnibLink oldLink = linkMap.get(hoComplete.getEcgiS(), hoComplete.getCrntiNew()),
656 newLink = linkMap.get(hoComplete.getEcgiT(), hoComplete.getCrntiNew());
657
658 oldLink.setType(RnibLink.Type.NON_SERVING);
659 newLink.setType(RnibLink.Type.SERVING_PRIMARY);
660
661 try {
662 hoQueue.get(hoComplete.getCrntiNew())
663 .put("Hand Over Completed");
664 } catch (InterruptedException e) {
665 log.error(ExceptionUtils.getFullStackTrace(e));
666 e.printStackTrace();
667 } finally {
668 hoQueue.remove(hoComplete.getCrntiNew());
669 }
670 break;
671 }
slowr13fa5b02017-08-08 16:32:31 -0700672 case 18: {
673 // Decode RX Sig Meas Report.
674 RXSigMeasReport rxSigMeasReport = recv_pdu.getBody().getRXSigMeasReport();
675 List<RXSigReport> rxSigReportList = rxSigMeasReport.getCellMeasReports().getRXSigReport();
676
677 if (!rxSigReportList.isEmpty()) {
678 rxSigReportList.forEach(rxSigReport -> {
679 RnibCell cell = cellMap.get(rxSigReport.getPciArfcn());
680 if (cell != null) {
681 ECGI ecgi = cell.getEcgi();
682 RnibLink link = linkMap.get(ecgi, rxSigMeasReport.getCrnti());
683 if (link == null) {
684 log.warn("Could not find link between: {}-{} | Creating non-serving link..", ecgi, rxSigMeasReport.getCrnti());
685 link = linkMap.putNonServingLink(cell, rxSigMeasReport.getCrnti());
686
687 if (link != null) {
688 restartTimer(link);
689 }
690 }
691
692 if (link != null) {
693 RSRQRange rsrq = rxSigReport.getRsrq();
694 RSRPRange rsrp = rxSigReport.getRsrp();
695
696 RnibLink.LinkQuality quality = link.getQuality();
697 quality.setRsrp(rsrp.value.intValue() - 140);
698 quality.setRsrq((rsrq.value.intValue() * 0.5) - 19.5);
699 }
700 } else {
701 log.warn("Could not find cell with PCI-ARFCN: {}", rxSigReport.getPciArfcn());
702 }
703 });
704 }
705 break;
706 }
707 case 20: {
708 RadioMeasReportPerUE radioMeasReportPerUE = recv_pdu.getBody().getRadioMeasReportPerUE();
709
710 List<RadioRepPerServCell> servCells = radioMeasReportPerUE.getRadioReportServCells().getRadioRepPerServCell();
711
712 servCells.forEach(servCell -> {
713 RnibCell cell = cellMap.get(servCell.getPciArfcn());
714 if (cell != null) {
715 RnibLink link = linkMap.get(cell.getEcgi(), radioMeasReportPerUE.getCrnti());
716 if (link != null) {
717 RadioRepPerServCell.CqiHist cqiHist = servCell.getCqiHist();
718 RnibLink.LinkQuality quality = link.getQuality();
719 quality.setCqiHist(cqiHist);
720
721 final double[] values = {0, 0, 0};
722 int i = 1;
723 cqiHist.getBerInteger().forEach(value -> {
724 values[0] = Math.max(values[0], value.intValue());
725 values[1] += i * value.intValue();
726 values[2] += value.intValue();
727 });
728
729 quality.setCqiMode(values[0]);
730 quality.setCqiMean(values[1] / values[2]);
731
732 } else {
733 log.warn("Could not find link between: {}-{}", cell.getEcgi(), radioMeasReportPerUE.getCrnti());
734 }
735 } else {
736 log.warn("Could not find cell with PCI-ARFCN: {}", servCell.getPciArfcn());
737 }
738 });
slowr67d05e42017-08-11 20:37:22 -0700739 break;
slowr13fa5b02017-08-08 16:32:31 -0700740 }
741 case 21: {
742 RadioMeasReportPerCell radioMeasReportPerCell = recv_pdu.getBody().getRadioMeasReportPerCell();
743 break;
744 }
745 case 22: {
746 SchedMeasReportPerUE schedMeasReportPerUE = recv_pdu.getBody().getSchedMeasReportPerUE();
747
748 List<SchedMeasRepPerServCell> servCells = schedMeasReportPerUE.getSchedReportServCells().getSchedMeasRepPerServCell();
749
750 servCells.forEach(servCell -> {
751 RnibCell cell = cellMap.get(servCell.getPciArfcn());
752 if (cell != null) {
753 RnibLink link = linkMap.get(cell.getEcgi(), schedMeasReportPerUE.getCrnti());
754 if (link != null) {
755 link.getQuality().setMcs_dl(servCell.getMcsDl());
756 link.getQuality().setMcs_ul(servCell.getMcsUl());
757
758 link.getResourceUsage().setDl(servCell.getPrbUsage().getPrbUsageDl());
759 link.getResourceUsage().setUl(servCell.getPrbUsage().getPrbUsageUl());
760 } else {
761 log.warn("Could not find link between: {}-{}", cell.getEcgi(), schedMeasReportPerUE.getCrnti());
762 }
763 } else {
764 log.warn("Could not find cell with PCI-ARFCN: {}", servCell.getPciArfcn());
765 }
766 });
767 break;
768 }
769 case 23: {
770 SchedMeasReportPerCell schedMeasReportPerCell = recv_pdu.getBody().getSchedMeasReportPerCell();
771
772 RnibCell cell = cellMap.get(schedMeasReportPerCell.getEcgi());
773 if (cell != null) {
774 cell.setPrimaryPrbUsage(schedMeasReportPerCell.getPrbUsagePcell());
775 cell.setSecondaryPrbUsage(schedMeasReportPerCell.getPrbUsageScell());
776 cell.setQci(schedMeasReportPerCell.getQciVals());
777 } else {
778 log.warn("Could not find cell with ECGI: {}", schedMeasReportPerCell.getEcgi());
779 }
780 break;
781 }
782 case 24: {
783 PDCPMeasReportPerUe pdcpMeasReportPerUe = recv_pdu.getBody().getPDCPMeasReportPerUe();
784
785 RnibLink link = linkMap.get(pdcpMeasReportPerUe.getEcgi(), pdcpMeasReportPerUe.getCrnti());
786 if (link != null) {
787 link.getPdcpThroughput().setDl(pdcpMeasReportPerUe.getThroughputDl());
788 link.getPdcpThroughput().setUl(pdcpMeasReportPerUe.getThroughputUl());
789 link.getPdcpPackDelay().setDl(pdcpMeasReportPerUe.getPktDelayDl());
790 link.getPdcpPackDelay().setUl(pdcpMeasReportPerUe.getPktDelayUl());
791 } else {
792 log.warn("Could not find link between: {}-{}", pdcpMeasReportPerUe.getEcgi(), pdcpMeasReportPerUe.getCrnti());
793 }
794 break;
795 }
slowr67d05e42017-08-11 20:37:22 -0700796 case 27: {
797 RRMConfigStatus rrmConfigStatus = recv_pdu.getBody().getRRMConfigStatus();
798 try {
799 RRMCellQueue.get(rrmConfigStatus.getEcgi())
800 .put("RRM Config's status: " + rrmConfigStatus.getStatus());
801 } catch (InterruptedException e) {
802 log.error(ExceptionUtils.getFullStackTrace(e));
803 e.printStackTrace();
804 } finally {
805 RRMCellQueue.remove(rrmConfigStatus.getEcgi());
806 }
807 break;
808 }
slowr13fa5b02017-08-08 16:32:31 -0700809 case 34: {
810 TrafficSplitConfig trafficSplitConfig = recv_pdu.getBody().getTrafficSplitConfig();
811
812 List<TrafficSplitPercentage> splitPercentages = trafficSplitConfig.getTrafficSplitPercent().getTrafficSplitPercentage();
813
814 splitPercentages.forEach(trafficSplitPercentage -> {
815 RnibCell cell = cellMap.get(trafficSplitPercentage.getEcgi());
816 if (cell != null) {
817 RnibLink link = linkMap.get(cell.getEcgi(), trafficSplitConfig.getCrnti());
818 if (link != null) {
819 link.setTrafficPercent(trafficSplitPercentage);
820 } else {
821 log.warn("Could not find link between: {}-{}", cell.getEcgi(), trafficSplitConfig.getCrnti());
822 }
823 } else {
824 log.warn("Could not find cell with ECGI: {}", trafficSplitConfig.getEcgi());
825 }
826 });
slowr67d05e42017-08-11 20:37:22 -0700827 break;
slowr13fa5b02017-08-08 16:32:31 -0700828 }
829 default: {
830 log.warn("Wrong API ID");
slowr67d05e42017-08-11 20:37:22 -0700831 break;
slowr13fa5b02017-08-08 16:32:31 -0700832 }
833 }
834
835 }
836 }
837
838 class InternalNetworkConfigListener implements NetworkConfigListener {
839
840 @Override
841 public void event(NetworkConfigEvent event) {
842 switch (event.type()) {
843 case CONFIG_REGISTERED:
844 break;
845 case CONFIG_UNREGISTERED:
846 break;
847 case CONFIG_ADDED:
848 case CONFIG_UPDATED:
849 if (event.configClass() == CONFIG_CLASS) {
850 handleConfigEvent(event.config());
851 }
852 break;
853 case CONFIG_REMOVED:
854 break;
855 default:
856 break;
857 }
858 }
859
860 private void handleConfigEvent(Optional<Config> config) {
861 if (!config.isPresent()) {
862 return;
863 }
864
865 xranConfig = (XranConfig) config.get();
866
867 legitCells.putAll(xranConfig.activeCellSet());
868
869 controller.start(deviceAgent, hostAgent, packetAgent, xranConfig.getXrancPort());
870 }
871 }
872}