blob: a5e073ab4d07afe51b5c0a6d479233d002b91c80 [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;
slowr13fa5b02017-08-08 16:32:31 -070044import org.onosproject.xran.wrapper.CellMap;
45import org.onosproject.xran.wrapper.LinkMap;
46import org.onosproject.xran.wrapper.UeMap;
47import org.openmuc.jasn1.ber.types.BerInteger;
48import org.slf4j.Logger;
49import org.slf4j.LoggerFactory;
50
51import java.io.IOException;
52import java.util.*;
slowr8ddc2b12017-08-14 14:13:38 -070053import java.util.concurrent.ConcurrentHashMap;
54import java.util.concurrent.ConcurrentMap;
55import java.util.concurrent.CopyOnWriteArraySet;
56import java.util.concurrent.SynchronousQueue;
slowr13fa5b02017-08-08 16:32:31 -070057import java.util.stream.Collectors;
58
59import static org.onosproject.net.DeviceId.deviceId;
slowr67d05e42017-08-11 20:37:22 -070060import static org.onosproject.xran.controller.XranChannelHandler.getSctpMessage;
slowr13fa5b02017-08-08 16:32:31 -070061import static org.onosproject.xran.entities.RnibCell.decodeDeviceId;
62import static org.onosproject.xran.entities.RnibCell.uri;
slowr13fa5b02017-08-08 16:32:31 -070063import static org.onosproject.xran.entities.RnibUe.hostIdtoMME;
64
65/**
66 * Created by dimitris on 7/20/17.
67 */
68@Component(immediate = true)
69@Service
70public class XranControllerImpl implements XranController {
71 private static final String XRAN_APP_ID = "org.onosproject.xran";
72 private static final Class<XranConfig> CONFIG_CLASS = XranConfig.class;
73
74 private static final Logger log =
75 LoggerFactory.getLogger(XranControllerImpl.class);
76 /* CONFIG */
77 private final InternalNetworkConfigListener configListener =
78 new InternalNetworkConfigListener();
79 /* VARIABLES */
80 private final Controller controller = new Controller();
81 private XranConfig xranConfig;
82 private ApplicationId appId;
83 /* Services */
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 private DeviceService deviceService;
86 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
87 private HostService hostService;
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 private NetworkConfigRegistry registry;
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 private NetworkConfigService configService;
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 private CoreService coreService;
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 private XranStore xranStore;
96 private ConfigFactory<ApplicationId, XranConfig> xranConfigFactory =
97 new ConfigFactory<ApplicationId, XranConfig>(
98 SubjectFactories.APP_SUBJECT_FACTORY, CONFIG_CLASS, "xran") {
99 @Override
100 public XranConfig createConfig() {
101 return new XranConfig();
102 }
103 };
104 /* WRAPPERS */
105 private CellMap cellMap;
106 private UeMap ueMap;
107 private LinkMap linkMap;
108 /* MAPS */
109 private ConcurrentMap<String, ECGI> legitCells = new ConcurrentHashMap<>();
slowr67d05e42017-08-11 20:37:22 -0700110 private ConcurrentMap<CRNTI, SynchronousQueue<String>> hoQueue = new ConcurrentHashMap<CRNTI, SynchronousQueue<String>>();
111 private ConcurrentMap<ECGI, SynchronousQueue<String>> RRMCellQueue = new ConcurrentHashMap<ECGI, SynchronousQueue<String>>();
slowr13fa5b02017-08-08 16:32:31 -0700112 /* AGENTS */
113 private InternalXranDeviceAgent deviceAgent = new InternalXranDeviceAgent();
114 private InternalXranHostAgent hostAgent = new InternalXranHostAgent();
115 private InternalXranPacketAgent packetAgent = new InternalXranPacketAgent();
116 /* LISTENERS */
117 private Set<XranDeviceListener> xranDeviceListeners = new CopyOnWriteArraySet<>();
118 private Set<XranHostListener> xranHostListeners = new CopyOnWriteArraySet<>();
119 private InternalDeviceListener device_listener = new InternalDeviceListener();
120 private InternalHostListener host_listener = new InternalHostListener();
121
122 @Activate
123 public void activate() {
124 appId = coreService.registerApplication(XRAN_APP_ID);
125
126 configService.addListener(configListener);
127 registry.registerConfigFactory(xranConfigFactory);
128 deviceService.addListener(device_listener);
129 hostService.addListener(host_listener);
130
131 cellMap = new CellMap(xranStore);
132 ueMap = new UeMap(xranStore);
133 linkMap = new LinkMap(xranStore);
134
135 xranStore.setController(this);
136
137 log.info("XRAN Controller Started");
138 }
139
140 @Deactivate
141 public void deactivate() {
142 controller.stop();
143
144 deviceService.removeListener(device_listener);
145 hostService.removeListener(host_listener);
146
147 legitCells.clear();
148
149 configService.removeListener(configListener);
150 registry.unregisterConfigFactory(xranConfigFactory);
151
152 log.info("XRAN Controller Stopped");
153 }
154
155 @Override
slowr67d05e42017-08-11 20:37:22 -0700156 public SynchronousQueue<String> sendHORequest(RnibLink newLink, RnibLink oldLink) {
slowr8ddc2b12017-08-14 14:13:38 -0700157 ECGI newEcgi = newLink.getLinkId().getEcgi(),
158 oldEcgi = oldLink.getLinkId().getEcgi();
159 CRNTI crnti = linkMap.getCrnti(newLink.getLinkId().getMmeues1apid());
slowr67d05e42017-08-11 20:37:22 -0700160 ChannelHandlerContext newCtx = cellMap.getCtx(newEcgi),
161 oldCtx = cellMap.getCtx(oldEcgi);
162
163 try {
slowr8ddc2b12017-08-14 14:13:38 -0700164 XrancPdu xrancPdu = HORequest.constructPacket(crnti, oldEcgi, newEcgi);
slowr67d05e42017-08-11 20:37:22 -0700165 newCtx.writeAndFlush(getSctpMessage(xrancPdu));
166 oldCtx.writeAndFlush(getSctpMessage(xrancPdu));
167 } catch (IOException e) {
168 e.printStackTrace();
169 }
170
171 SynchronousQueue<String> queue = new SynchronousQueue<>();
172 hoQueue.put(crnti, queue);
173
174 return queue;
175 }
176
177 @Override
slowr13fa5b02017-08-08 16:32:31 -0700178 public void addListener(XranDeviceListener listener) {
179 xranDeviceListeners.add(listener);
180 }
181
182 @Override
183 public void addListener(XranHostListener listener) {
184 xranHostListeners.add(listener);
185 }
186
187 @Override
188 public void removeListener(XranDeviceListener listener) {
189 xranDeviceListeners.remove(listener);
190 }
191
192 @Override
193 public void removeListener(XranHostListener listener) {
194 xranHostListeners.remove(listener);
195 }
196
slowr67d05e42017-08-11 20:37:22 -0700197 @Override
slowr8ddc2b12017-08-14 14:13:38 -0700198 public SynchronousQueue<String> sendModifiedRRMConf(RRMConfig rrmConfig, boolean xICIC) {
199 ECGI ecgi = rrmConfig.getEcgi();
slowr67d05e42017-08-11 20:37:22 -0700200 ChannelHandlerContext ctx = cellMap.getCtx(ecgi);
201 try {
slowr8ddc2b12017-08-14 14:13:38 -0700202 XrancPdu pdu;
203 if (xICIC) {
204 pdu = XICICConfig.constructPacket(rrmConfig);
205 } else {
206 pdu = RRMConfig.constructPacket(rrmConfig);
207 }
slowr67d05e42017-08-11 20:37:22 -0700208 ctx.writeAndFlush(getSctpMessage(pdu));
209 } catch (IOException e) {
210 e.printStackTrace();
211 }
212 SynchronousQueue<String> queue = new SynchronousQueue<>();
213 RRMCellQueue.put(ecgi, queue);
214
215 return queue;
216 }
217
slowr13fa5b02017-08-08 16:32:31 -0700218 private void restartTimer(RnibUe ue) {
219 Timer timer = new Timer();
220 ue.setTimer(timer);
221 log.info("Starting UE timer...");
222 timer.schedule(new TimerTask() {
223 @Override
224 public void run() {
slowr67d05e42017-08-11 20:37:22 -0700225 if (ue.getState() == RnibUe.State.IDLE) {
slowr13fa5b02017-08-08 16:32:31 -0700226 hostAgent.removeConnectedHost(ue);
227 log.info("UE is removed after 10 seconds of IDLE");
228 } else {
229 log.info("UE not removed cause its ACTIVE");
230 }
231 }
232 }, 10000);
233 }
234
235 private void restartTimer(RnibLink link) {
236 Timer timer = new Timer();
237 link.setTimer(timer);
238 log.info("Starting Link timer...");
239 timer.schedule(new TimerTask() {
240 @Override
241 public void run() {
242 LinkId linkId = link.getLinkId();
243 xranStore.removeLink(linkId);
244 log.info("Link is removed after not receiving Meas Reports for 10 seconds");
245 }
246 }, 10000);
247
248 }
249
250 class InternalDeviceListener implements DeviceListener {
251
252 @Override
253 public void event(DeviceEvent event) {
254 log.info("Device Event {}", event);
255 switch (event.type()) {
256 case DEVICE_ADDED: {
257 try {
258 ECGI ecgi = decodeDeviceId(event.subject().id());
259 RnibCell cell = cellMap.get(ecgi);
260 if (cell != null) {
261 Timer timer = new Timer();
262 timer.scheduleAtFixedRate(
263 new TimerTask() {
264 @Override
265 public void run() {
266 CellConfigReport conf = cell.getConf();
267 if (conf == null) {
268 try {
269 ChannelHandlerContext ctx = cellMap.getCtx(ecgi);
slowr8ddc2b12017-08-14 14:13:38 -0700270 XrancPdu xrancPdu = CellConfigRequest.constructPacket(ecgi);
slowr67d05e42017-08-11 20:37:22 -0700271 ctx.writeAndFlush(getSctpMessage(xrancPdu));
slowr13fa5b02017-08-08 16:32:31 -0700272 } catch (IOException e) {
273 log.error(ExceptionUtils.getFullStackTrace(e));
274 e.printStackTrace();
275 }
276 } else {
277 // FIXME: maybe remove this map.
278 cellMap.putPciArfcn(cell);
279 try {
280 ChannelHandlerContext ctx = cellMap.
281 getCtx(ecgi);
slowr8ddc2b12017-08-14 14:13:38 -0700282 XrancPdu xrancPdu = L2MeasConfig.constructPacket(ecgi, xranConfig.getL2MeasInterval());
slowr13fa5b02017-08-08 16:32:31 -0700283 cell.setMeasConfig(xrancPdu.getBody().getL2MeasConfig());
slowr67d05e42017-08-11 20:37:22 -0700284 SctpMessage sctpMessage = getSctpMessage(xrancPdu);
slowr13fa5b02017-08-08 16:32:31 -0700285 ctx.writeAndFlush(sctpMessage);
286 } catch (IOException e) {
287 log.error(ExceptionUtils.getFullStackTrace(e));
288 e.printStackTrace();
289 }
290 timer.cancel();
291 timer.purge();
292 }
293 }
294 },
295 0,
296 xranConfig.getConfigRequestInterval() * 1000
297 );
298 }
299 } catch (IOException e) {
300 log.error(ExceptionUtils.getFullStackTrace(e));
301 e.printStackTrace();
302 }
303 break;
304 }
305 default: {
306 break;
307 }
308 }
309 }
310 }
311
312 class InternalHostListener implements HostListener {
313
314 @Override
315 public void event(HostEvent event) {
316 log.info("Host Event {}", event);
317 switch (event.type()) {
318 case HOST_ADDED:
319 case HOST_MOVED: {
320 RnibUe ue = ueMap.get(hostIdtoMME(event.subject().id()));
321 if (ue != null) {
322 ECGI ecgi_primary = linkMap.getPrimaryCell(ue);
323 RnibCell primary = cellMap.get(ecgi_primary);
324 ue.setMeasConfig(null);
325 if (primary != null) {
326 Timer timer = new Timer();
327 timer.scheduleAtFixedRate(
328 new TimerTask() {
329 @Override
330 public void run() {
331 if (ue.getCapability() == null) {
332 try {
333 ChannelHandlerContext ctx = cellMap.getCtx(primary.getEcgi());
slowr8ddc2b12017-08-14 14:13:38 -0700334 XrancPdu xrancPdu = UECapabilityEnquiry.constructPacket(
slowr67d05e42017-08-11 20:37:22 -0700335 primary.getEcgi(),
336 ue.getRanId());
337 ctx.writeAndFlush(getSctpMessage(xrancPdu));
slowr13fa5b02017-08-08 16:32:31 -0700338 } catch (IOException e) {
339 log.warn(ExceptionUtils.getFullStackTrace(e));
340 e.printStackTrace();
341 }
342 } else {
343 if (ue.getMeasConfig() == null) {
344 try {
345 ChannelHandlerContext ctx = cellMap.getCtx(primary.getEcgi());
346 RXSigMeasConfig.MeasCells measCells = new RXSigMeasConfig.MeasCells();
347 xranStore.getCellNodes().forEach(cell -> {
348 CellConfigReport cellReport = cell.getConf();
349 if (cellReport != null) {
350 PCIARFCN pciarfcn = new PCIARFCN();
351 pciarfcn.setPci(cellReport.getPci());
352 pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
353 measCells.setPCIARFCN(pciarfcn);
354 }
355 });
slowr8ddc2b12017-08-14 14:13:38 -0700356 XrancPdu xrancPdu = RXSigMeasConfig.constructPacket(
slowr13fa5b02017-08-08 16:32:31 -0700357 primary.getEcgi(),
358 ue.getRanId(),
359 measCells,
360 xranConfig.getRxSignalInterval()
361 );
362 ue.setMeasConfig(xrancPdu.getBody().getRXSigMeasConfig());
slowr67d05e42017-08-11 20:37:22 -0700363 ctx.writeAndFlush(getSctpMessage(xrancPdu));
slowr13fa5b02017-08-08 16:32:31 -0700364 } catch (IOException e) {
365 log.warn(ExceptionUtils.getFullStackTrace(e));
366 e.printStackTrace();
367 }
368 }
369 timer.cancel();
370 timer.purge();
371 }
372 }
373 },
374 0,
375 xranConfig.getConfigRequestInterval() * 1000
376 );
377 }
378 }
379 break;
380 }
381 default: {
382 break;
383 }
384 }
385 }
386 }
387
388 public class InternalXranDeviceAgent implements XranDeviceAgent {
389
390 private final Logger log = LoggerFactory.getLogger(InternalXranDeviceAgent.class);
391
392 @Override
393 public boolean addConnectedCell(String host, ChannelHandlerContext ctx) {
394 ECGI ecgi = legitCells.get(host);
395
396 if (ecgi == null) {
397 log.error("Device is not a legit source; ignoring...");
398 } else {
399 log.info("Device exists in configuration; registering...");
400 RnibCell storeCell = cellMap.get(ecgi);
401 if (storeCell == null) {
402 storeCell = new RnibCell();
403 storeCell.setEcgi(ecgi);
404 cellMap.put(storeCell, ctx);
405
406 for (XranDeviceListener l : xranDeviceListeners) {
407 l.deviceAdded(storeCell);
408 }
409 return true;
410 } else {
411 log.error("Device already registered; ignoring...");
412 }
413 }
414 ctx.close();
415 return false;
416 }
417
418 @Override
419 public boolean removeConnectedCell(String host) {
420 ECGI ecgi = legitCells.get(host);
421 List<RnibLink> linksByECGI = xranStore.getLinksByECGI(ecgi);
422
423 linksByECGI.forEach(rnibLink -> xranStore.removeLink(rnibLink.getLinkId()));
424
425 if (cellMap.remove(ecgi)) {
426 for (XranDeviceListener l : xranDeviceListeners) {
427 l.deviceRemoved(deviceId(uri(ecgi)));
428 }
429 return true;
430 }
431 return false;
432 }
433 }
434
435 public class InternalXranHostAgent implements XranHostAgent {
436
437 @Override
438 public boolean addConnectedHost(RnibUe ue, RnibCell cell, ChannelHandlerContext ctx) {
439
440 if (ueMap.get(ue.getMmeS1apId()) != null) {
441 linkMap.putPrimaryLink(cell, ue);
442
443 Set<ECGI> ecgiSet = xranStore.getLinksByUeId(ue.getMmeS1apId().longValue())
444 .stream()
slowr8ddc2b12017-08-14 14:13:38 -0700445 .map(l -> l.getLinkId().getEcgi())
slowr13fa5b02017-08-08 16:32:31 -0700446 .collect(Collectors.toSet());
447
448 for (XranHostListener l : xranHostListeners) {
449 l.hostAdded(ue, ecgiSet);
450 }
451 return true;
452 } else {
453 ueMap.put(ue);
454 linkMap.putPrimaryLink(cell, ue);
455
456 Set<ECGI> ecgiSet = Sets.newConcurrentHashSet();
457 ecgiSet.add(cell.getEcgi());
458 for (XranHostListener l : xranHostListeners) {
459 l.hostAdded(ue, ecgiSet);
460 }
461 return true;
462 }
463
464 }
465
466 @Override
467 public boolean removeConnectedHost(RnibUe ue) {
468 List<RnibLink> links = xranStore.getLinksByUeId(ue.getMmeS1apId().longValue());
469 links.forEach(rnibLink -> xranStore.removeLink(rnibLink.getLinkId()));
470 if (ueMap.remove(ue.getMmeS1apId())) {
471 for (XranHostListener l : xranHostListeners) {
472 l.hostRemoved(ue.getHostId());
473 }
474 return true;
475 }
476 return false;
477 }
478 }
479
480 public class InternalXranPacketAgent implements XranPacketProcessor {
481 @Override
482 public void handlePacket(XrancPdu recv_pdu, ChannelHandlerContext ctx) throws IOException {
483 XrancPdu send_pdu;
484
485 int apiID = recv_pdu.getHdr().getApiId().intValue();
486 log.debug("Received message: {}", recv_pdu);
487 switch (apiID) {
488 case 1: {
489 // Decode Cell config report.
490 CellConfigReport report = recv_pdu.getBody().getCellConfigReport();
491
492 ECGI ecgi = report.getEcgi();
493
494 RnibCell cell = xranStore.getCell(ecgi);
slowr8ddc2b12017-08-14 14:13:38 -0700495 cell.setVersion(recv_pdu.getHdr().getVer().toString());
slowr13fa5b02017-08-08 16:32:31 -0700496 cell.setConf(report);
497
498 break;
499 }
500 case 2: {
501 // Decode UE Admission Request.
502 UEAdmissionRequest ueAdmissionRequest = recv_pdu.getBody().getUEAdmissionRequest();
503
504 ECGI ecgi = ueAdmissionRequest.getEcgi();
505 if (xranStore.getCell(ecgi) != null) {
506 CRNTI crnti = ueAdmissionRequest.getCrnti();
slowr8ddc2b12017-08-14 14:13:38 -0700507 send_pdu = UEAdmissionResponse.constructPacket(ecgi, crnti, xranConfig.admissionFlag());
slowr67d05e42017-08-11 20:37:22 -0700508 ctx.writeAndFlush(getSctpMessage(send_pdu));
slowr13fa5b02017-08-08 16:32:31 -0700509 } else {
510 log.warn("Could not find ECGI in registered cells: {}", ecgi);
511 }
512 break;
513 }
514 case 4: {
515 // Decode UE Admission Status.
516 UEAdmissionStatus ueAdmissionStatus = recv_pdu.getBody().getUEAdmissionStatus();
517
518 RnibUe ue = ueMap.get(ueAdmissionStatus.getCrnti());
519 if (ue != null) {
520 if (ueAdmissionStatus.getAdmEstStatus().value.intValue() == 0) {
slowr67d05e42017-08-11 20:37:22 -0700521 ue.setState(RnibUe.State.ACTIVE);
slowr13fa5b02017-08-08 16:32:31 -0700522 } else {
slowr67d05e42017-08-11 20:37:22 -0700523 ue.setState(RnibUe.State.IDLE);
slowr13fa5b02017-08-08 16:32:31 -0700524 }
525 }
526 break;
527 }
528 case 5: {
529 // Decode UE Admission Context Update.
slowr8ddc2b12017-08-14 14:13:38 -0700530 UEContextUpdate ueContextUpdate = recv_pdu.getBody().getUEContextUpdate();
slowr13fa5b02017-08-08 16:32:31 -0700531
slowr8ddc2b12017-08-14 14:13:38 -0700532 RnibCell cell = xranStore.getCell(ueContextUpdate.getEcgi());
slowr13fa5b02017-08-08 16:32:31 -0700533
slowr8ddc2b12017-08-14 14:13:38 -0700534 RnibUe ue = ueMap.get(ueContextUpdate.getMMEUES1APID());
535 if (ueMap.get(ueContextUpdate.getMMEUES1APID()) == null) {
slowr13fa5b02017-08-08 16:32:31 -0700536 ue = new RnibUe();
537 }
538
slowr8ddc2b12017-08-14 14:13:38 -0700539 ue.setMmeS1apId(ueContextUpdate.getMMEUES1APID());
540 ue.setEnbS1apId(ueContextUpdate.getENBUES1APID());
541 ue.setRanId(ueContextUpdate.getCrnti());
slowr13fa5b02017-08-08 16:32:31 -0700542
543 hostAgent.addConnectedHost(ue, cell, ctx);
544 break;
545 }
546 case 6: {
547 // Decode UE Reconfig_Ind.
548 UEReconfigInd ueReconfigInd = recv_pdu.getBody().getUEReconfigInd();
549 RnibUe ue = ueMap.get(ueReconfigInd.getCrntiOld());
550
551 if (ue != null) {
552 ue.setRanId(ueReconfigInd.getCrntiNew());
553 } else {
554 log.warn("Could not find UE with this CRNTI: {}", ueReconfigInd.getCrntiOld());
555 }
556 break;
557 }
558 case 7: {
559 // If xRANc wants to deactivate UE, we pass UEReleaseInd from xRANc to eNB.
560 // Decode UE Release_Ind.
561 UEReleaseInd ueReleaseInd = recv_pdu.getBody().getUEReleaseInd();
562 RnibUe ue = ueMap.get(ueReleaseInd.getCrnti());
563 if (ue != null) {
slowr67d05e42017-08-11 20:37:22 -0700564 ue.setState(RnibUe.State.IDLE);
slowr13fa5b02017-08-08 16:32:31 -0700565 restartTimer(ue);
566 }
567 break;
568 }
569 case 8: {
570 // Decode Bearer Adm Request
571 BearerAdmissionRequest bearerAdmissionRequest = recv_pdu.getBody().getBearerAdmissionRequest();
572
573 ECGI ecgi = bearerAdmissionRequest.getEcgi();
574 CRNTI crnti = bearerAdmissionRequest.getCrnti();
575 ERABParams erabParams = bearerAdmissionRequest.getErabParams();
576 RnibLink link = linkMap.get(ecgi, crnti);
577 if (link != null) {
578 link.setBearerParameters(erabParams);
579 } else {
580 log.warn("Could not find link between {}-{}", ecgi, crnti);
581 }
582
583 BerInteger numErabs = bearerAdmissionRequest.getNumErabs();
slowr8ddc2b12017-08-14 14:13:38 -0700584 // Encode and send Bearer Admission Response
585 send_pdu = BearerAdmissionResponse.constructPacket(ecgi, crnti, erabParams, numErabs, xranConfig.bearerFlag());
slowr67d05e42017-08-11 20:37:22 -0700586 ctx.writeAndFlush(getSctpMessage(send_pdu));
slowr13fa5b02017-08-08 16:32:31 -0700587 break;
588 }
589 case 10: {
590 //Decode Bearer Admission Status
591 BearerAdmissionStatus bearerAdmissionStatus = recv_pdu.getBody().getBearerAdmissionStatus();
slowr8ddc2b12017-08-14 14:13:38 -0700592 break;
slowr13fa5b02017-08-08 16:32:31 -0700593// ECGI ecgi = bearerAdmissionStatus.getEcgi();
594// CRNTI crnti = bearerAdmissionStatus.getCrnti();
595//
596// RnibLink link = linkMap.get(ecgi, crnti);
slowr13fa5b02017-08-08 16:32:31 -0700597 }
598 case 11: {
599 //Decode Bearer Release Ind
600 BearerReleaseInd bearerReleaseInd = recv_pdu.getBody().getBearerReleaseInd();
601
602 ECGI ecgi = bearerReleaseInd.getEcgi();
603 CRNTI crnti = bearerReleaseInd.getCrnti();
604 RnibLink link = linkMap.get(ecgi, crnti);
605
606 List<ERABID> erabidsRelease = bearerReleaseInd.getErabIds().getERABID();
607 List<ERABParamsItem> erabParamsItem = link.getBearerParameters().getERABParamsItem();
608
609 List<ERABParamsItem> unreleased = erabParamsItem
610 .stream()
611 .filter(item -> {
612 Optional<ERABID> any = erabidsRelease.stream().filter(id -> id.equals(item.getId())).findAny();
613 return !any.isPresent();
614 }).collect(Collectors.toList());
615
616 link.getBearerParameters().setERABParamsItem(new ArrayList<>(unreleased));
slowr13fa5b02017-08-08 16:32:31 -0700617 break;
618 }
619 case 13: {
slowr67d05e42017-08-11 20:37:22 -0700620 HOFailure hoFailure = recv_pdu.getBody().getHOFailure();
621
622 try {
623 hoQueue.get(hoFailure.getCrnti())
624 .put("Hand Over Failed with cause: " + hoFailure.getCause());
625 } catch (InterruptedException e) {
626 log.error(ExceptionUtils.getFullStackTrace(e));
627 e.printStackTrace();
628 } finally {
629 hoQueue.remove(hoFailure.getCrnti());
630 }
631 break;
slowr8ddc2b12017-08-14 14:13:38 -0700632
slowr67d05e42017-08-11 20:37:22 -0700633 }
slowr8ddc2b12017-08-14 14:13:38 -0700634 case 14: {
slowr67d05e42017-08-11 20:37:22 -0700635 HOComplete hoComplete = recv_pdu.getBody().getHOComplete();
636
637 RnibLink oldLink = linkMap.get(hoComplete.getEcgiS(), hoComplete.getCrntiNew()),
638 newLink = linkMap.get(hoComplete.getEcgiT(), hoComplete.getCrntiNew());
639
640 oldLink.setType(RnibLink.Type.NON_SERVING);
641 newLink.setType(RnibLink.Type.SERVING_PRIMARY);
642
643 try {
644 hoQueue.get(hoComplete.getCrntiNew())
645 .put("Hand Over Completed");
646 } catch (InterruptedException e) {
647 log.error(ExceptionUtils.getFullStackTrace(e));
648 e.printStackTrace();
649 } finally {
650 hoQueue.remove(hoComplete.getCrntiNew());
651 }
652 break;
653 }
slowr8ddc2b12017-08-14 14:13:38 -0700654
655 case 16: {
slowr13fa5b02017-08-08 16:32:31 -0700656 // Decode RX Sig Meas Report.
657 RXSigMeasReport rxSigMeasReport = recv_pdu.getBody().getRXSigMeasReport();
658 List<RXSigReport> rxSigReportList = rxSigMeasReport.getCellMeasReports().getRXSigReport();
659
660 if (!rxSigReportList.isEmpty()) {
661 rxSigReportList.forEach(rxSigReport -> {
662 RnibCell cell = cellMap.get(rxSigReport.getPciArfcn());
663 if (cell != null) {
664 ECGI ecgi = cell.getEcgi();
665 RnibLink link = linkMap.get(ecgi, rxSigMeasReport.getCrnti());
666 if (link == null) {
667 log.warn("Could not find link between: {}-{} | Creating non-serving link..", ecgi, rxSigMeasReport.getCrnti());
668 link = linkMap.putNonServingLink(cell, rxSigMeasReport.getCrnti());
669
670 if (link != null) {
671 restartTimer(link);
672 }
673 }
674
675 if (link != null) {
676 RSRQRange rsrq = rxSigReport.getRsrq();
677 RSRPRange rsrp = rxSigReport.getRsrp();
678
679 RnibLink.LinkQuality quality = link.getQuality();
680 quality.setRsrp(rsrp.value.intValue() - 140);
681 quality.setRsrq((rsrq.value.intValue() * 0.5) - 19.5);
682 }
683 } else {
684 log.warn("Could not find cell with PCI-ARFCN: {}", rxSigReport.getPciArfcn());
685 }
686 });
687 }
688 break;
689 }
slowr8ddc2b12017-08-14 14:13:38 -0700690 case 18: {
slowr13fa5b02017-08-08 16:32:31 -0700691 RadioMeasReportPerUE radioMeasReportPerUE = recv_pdu.getBody().getRadioMeasReportPerUE();
692
693 List<RadioRepPerServCell> servCells = radioMeasReportPerUE.getRadioReportServCells().getRadioRepPerServCell();
694
695 servCells.forEach(servCell -> {
696 RnibCell cell = cellMap.get(servCell.getPciArfcn());
697 if (cell != null) {
698 RnibLink link = linkMap.get(cell.getEcgi(), radioMeasReportPerUE.getCrnti());
699 if (link != null) {
700 RadioRepPerServCell.CqiHist cqiHist = servCell.getCqiHist();
701 RnibLink.LinkQuality quality = link.getQuality();
702 quality.setCqiHist(cqiHist);
703
704 final double[] values = {0, 0, 0};
705 int i = 1;
706 cqiHist.getBerInteger().forEach(value -> {
707 values[0] = Math.max(values[0], value.intValue());
708 values[1] += i * value.intValue();
709 values[2] += value.intValue();
710 });
711
712 quality.setCqiMode(values[0]);
713 quality.setCqiMean(values[1] / values[2]);
714
715 } else {
716 log.warn("Could not find link between: {}-{}", cell.getEcgi(), radioMeasReportPerUE.getCrnti());
717 }
718 } else {
719 log.warn("Could not find cell with PCI-ARFCN: {}", servCell.getPciArfcn());
720 }
721 });
slowr67d05e42017-08-11 20:37:22 -0700722 break;
slowr13fa5b02017-08-08 16:32:31 -0700723 }
slowr8ddc2b12017-08-14 14:13:38 -0700724 case 19: {
slowr13fa5b02017-08-08 16:32:31 -0700725 RadioMeasReportPerCell radioMeasReportPerCell = recv_pdu.getBody().getRadioMeasReportPerCell();
726 break;
727 }
slowr8ddc2b12017-08-14 14:13:38 -0700728 case 20: {
slowr13fa5b02017-08-08 16:32:31 -0700729 SchedMeasReportPerUE schedMeasReportPerUE = recv_pdu.getBody().getSchedMeasReportPerUE();
slowr8ddc2b12017-08-14 14:13:38 -0700730 List<SchedMeasRepPerServCell> servCells = schedMeasReportPerUE.getSchedReportServCells()
731 .getSchedMeasRepPerServCell();
slowr13fa5b02017-08-08 16:32:31 -0700732
733 servCells.forEach(servCell -> {
734 RnibCell cell = cellMap.get(servCell.getPciArfcn());
735 if (cell != null) {
736 RnibLink link = linkMap.get(cell.getEcgi(), schedMeasReportPerUE.getCrnti());
737 if (link != null) {
738 link.getQuality().setMcs_dl(servCell.getMcsDl());
739 link.getQuality().setMcs_ul(servCell.getMcsUl());
740
741 link.getResourceUsage().setDl(servCell.getPrbUsage().getPrbUsageDl());
742 link.getResourceUsage().setUl(servCell.getPrbUsage().getPrbUsageUl());
743 } else {
slowr8ddc2b12017-08-14 14:13:38 -0700744 log.warn("Could not find link between: {}-{}", cell.getEcgi(),
745 schedMeasReportPerUE.getCrnti());
slowr13fa5b02017-08-08 16:32:31 -0700746 }
747 } else {
748 log.warn("Could not find cell with PCI-ARFCN: {}", servCell.getPciArfcn());
749 }
750 });
751 break;
752 }
slowr8ddc2b12017-08-14 14:13:38 -0700753 case 21: {
slowr13fa5b02017-08-08 16:32:31 -0700754 SchedMeasReportPerCell schedMeasReportPerCell = recv_pdu.getBody().getSchedMeasReportPerCell();
slowr13fa5b02017-08-08 16:32:31 -0700755 RnibCell cell = cellMap.get(schedMeasReportPerCell.getEcgi());
756 if (cell != null) {
757 cell.setPrimaryPrbUsage(schedMeasReportPerCell.getPrbUsagePcell());
758 cell.setSecondaryPrbUsage(schedMeasReportPerCell.getPrbUsageScell());
759 cell.setQci(schedMeasReportPerCell.getQciVals());
760 } else {
761 log.warn("Could not find cell with ECGI: {}", schedMeasReportPerCell.getEcgi());
762 }
763 break;
764 }
slowr8ddc2b12017-08-14 14:13:38 -0700765 case 22: {
slowr13fa5b02017-08-08 16:32:31 -0700766 PDCPMeasReportPerUe pdcpMeasReportPerUe = recv_pdu.getBody().getPDCPMeasReportPerUe();
767
768 RnibLink link = linkMap.get(pdcpMeasReportPerUe.getEcgi(), pdcpMeasReportPerUe.getCrnti());
769 if (link != null) {
770 link.getPdcpThroughput().setDl(pdcpMeasReportPerUe.getThroughputDl());
771 link.getPdcpThroughput().setUl(pdcpMeasReportPerUe.getThroughputUl());
772 link.getPdcpPackDelay().setDl(pdcpMeasReportPerUe.getPktDelayDl());
773 link.getPdcpPackDelay().setUl(pdcpMeasReportPerUe.getPktDelayUl());
774 } else {
slowr8ddc2b12017-08-14 14:13:38 -0700775 log.warn("Could not find link between: {}-{}", pdcpMeasReportPerUe.getEcgi(),
776 pdcpMeasReportPerUe.getCrnti());
slowr13fa5b02017-08-08 16:32:31 -0700777 }
778 break;
779 }
slowr8ddc2b12017-08-14 14:13:38 -0700780 case 24: {
781 // Decode UE Capability Info
782 UECapabilityInfo capabilityInfo = recv_pdu.getBody().getUECapabilityInfo();
783
784 RnibUe ue = ueMap.get(capabilityInfo.getCrnti());
785 if (ue != null) {
786 ue.setCapability(capabilityInfo);
787 } else {
788 log.warn("Could not find UE with this CRNTI: {}", capabilityInfo.getCrnti());
789 }
790 break;
791 }
792 case 25: {
793 // Don't know what will invoke sending UE CAPABILITY ENQUIRY
794 // Encode and send UE CAPABILITY ENQUIRY
795 UECapabilityEnquiry ueCapabilityEnquiry = recv_pdu.getBody().getUECapabilityEnquiry();
796 XrancPdu xrancPdu = UECapabilityEnquiry.constructPacket(ueCapabilityEnquiry.getEcgi(), ueCapabilityEnquiry.getCrnti());
797 ctx.writeAndFlush(getSctpMessage(xrancPdu));
798 break;
799 }
800 // TODO: Case 26: ScellAdd 27: ScellAddStatus 28: ScellDelete
801
802 case 30: {
803 // Decode RRMConfig Status
slowr67d05e42017-08-11 20:37:22 -0700804 RRMConfigStatus rrmConfigStatus = recv_pdu.getBody().getRRMConfigStatus();
805 try {
806 RRMCellQueue.get(rrmConfigStatus.getEcgi())
807 .put("RRM Config's status: " + rrmConfigStatus.getStatus());
808 } catch (InterruptedException e) {
809 log.error(ExceptionUtils.getFullStackTrace(e));
810 e.printStackTrace();
811 } finally {
812 RRMCellQueue.remove(rrmConfigStatus.getEcgi());
813 }
814 break;
815 }
slowr8ddc2b12017-08-14 14:13:38 -0700816 //TODO Case 31: SeNBAdd 32: SeNBAddStatus 33: SeNBDelete
slowr13fa5b02017-08-08 16:32:31 -0700817 case 34: {
818 TrafficSplitConfig trafficSplitConfig = recv_pdu.getBody().getTrafficSplitConfig();
819
820 List<TrafficSplitPercentage> splitPercentages = trafficSplitConfig.getTrafficSplitPercent().getTrafficSplitPercentage();
821
822 splitPercentages.forEach(trafficSplitPercentage -> {
823 RnibCell cell = cellMap.get(trafficSplitPercentage.getEcgi());
824 if (cell != null) {
825 RnibLink link = linkMap.get(cell.getEcgi(), trafficSplitConfig.getCrnti());
826 if (link != null) {
827 link.setTrafficPercent(trafficSplitPercentage);
828 } else {
829 log.warn("Could not find link between: {}-{}", cell.getEcgi(), trafficSplitConfig.getCrnti());
830 }
831 } else {
832 log.warn("Could not find cell with ECGI: {}", trafficSplitConfig.getEcgi());
833 }
834 });
slowr67d05e42017-08-11 20:37:22 -0700835 break;
slowr13fa5b02017-08-08 16:32:31 -0700836 }
837 default: {
838 log.warn("Wrong API ID");
slowr67d05e42017-08-11 20:37:22 -0700839 break;
slowr13fa5b02017-08-08 16:32:31 -0700840 }
841 }
842
843 }
844 }
845
846 class InternalNetworkConfigListener implements NetworkConfigListener {
847
848 @Override
849 public void event(NetworkConfigEvent event) {
850 switch (event.type()) {
851 case CONFIG_REGISTERED:
852 break;
853 case CONFIG_UNREGISTERED:
854 break;
855 case CONFIG_ADDED:
856 case CONFIG_UPDATED:
857 if (event.configClass() == CONFIG_CLASS) {
858 handleConfigEvent(event.config());
859 }
860 break;
861 case CONFIG_REMOVED:
862 break;
863 default:
864 break;
865 }
866 }
867
868 private void handleConfigEvent(Optional<Config> config) {
869 if (!config.isPresent()) {
870 return;
871 }
872
873 xranConfig = (XranConfig) config.get();
874
875 legitCells.putAll(xranConfig.activeCellSet());
876
877 controller.start(deviceAgent, hostAgent, packetAgent, xranConfig.getXrancPort());
878 }
879 }
880}