blob: 1d9653d765fa578e4b7000e20c5e2ac688186a1b [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<>();
slowr89c2ac12017-08-15 16:20:06 -0700110 private ConcurrentMap<CRNTI, SynchronousQueue<String>> hoQueue = new ConcurrentHashMap<>();
111 private ConcurrentMap<ECGI, SynchronousQueue<String>> RRMCellQueue = new ConcurrentHashMap<>();
112 private ConcurrentMap<CRNTI, SynchronousQueue<String>> scellAddQueue = new ConcurrentHashMap<>();
113 private ConcurrentMap<CRNTI, SynchronousQueue<String>> scellDeleteQueue = new ConcurrentHashMap<>();
slowr13fa5b02017-08-08 16:32:31 -0700114 /* AGENTS */
115 private InternalXranDeviceAgent deviceAgent = new InternalXranDeviceAgent();
116 private InternalXranHostAgent hostAgent = new InternalXranHostAgent();
117 private InternalXranPacketAgent packetAgent = new InternalXranPacketAgent();
118 /* LISTENERS */
119 private Set<XranDeviceListener> xranDeviceListeners = new CopyOnWriteArraySet<>();
120 private Set<XranHostListener> xranHostListeners = new CopyOnWriteArraySet<>();
121 private InternalDeviceListener device_listener = new InternalDeviceListener();
122 private InternalHostListener host_listener = new InternalHostListener();
123
124 @Activate
125 public void activate() {
126 appId = coreService.registerApplication(XRAN_APP_ID);
127
128 configService.addListener(configListener);
129 registry.registerConfigFactory(xranConfigFactory);
130 deviceService.addListener(device_listener);
131 hostService.addListener(host_listener);
132
133 cellMap = new CellMap(xranStore);
134 ueMap = new UeMap(xranStore);
135 linkMap = new LinkMap(xranStore);
136
137 xranStore.setController(this);
138
139 log.info("XRAN Controller Started");
140 }
141
142 @Deactivate
143 public void deactivate() {
144 controller.stop();
145
146 deviceService.removeListener(device_listener);
147 hostService.removeListener(host_listener);
148
149 legitCells.clear();
150
151 configService.removeListener(configListener);
152 registry.unregisterConfigFactory(xranConfigFactory);
153
154 log.info("XRAN Controller Stopped");
155 }
156
157 @Override
slowr67d05e42017-08-11 20:37:22 -0700158 public SynchronousQueue<String> sendHORequest(RnibLink newLink, RnibLink oldLink) {
slowr8ddc2b12017-08-14 14:13:38 -0700159 ECGI newEcgi = newLink.getLinkId().getEcgi(),
160 oldEcgi = oldLink.getLinkId().getEcgi();
161 CRNTI crnti = linkMap.getCrnti(newLink.getLinkId().getMmeues1apid());
slowr67d05e42017-08-11 20:37:22 -0700162 ChannelHandlerContext newCtx = cellMap.getCtx(newEcgi),
163 oldCtx = cellMap.getCtx(oldEcgi);
164
165 try {
slowr8ddc2b12017-08-14 14:13:38 -0700166 XrancPdu xrancPdu = HORequest.constructPacket(crnti, oldEcgi, newEcgi);
slowr67d05e42017-08-11 20:37:22 -0700167 newCtx.writeAndFlush(getSctpMessage(xrancPdu));
168 oldCtx.writeAndFlush(getSctpMessage(xrancPdu));
169 } catch (IOException e) {
170 e.printStackTrace();
171 }
172
173 SynchronousQueue<String> queue = new SynchronousQueue<>();
174 hoQueue.put(crnti, queue);
175
176 return queue;
177 }
178
179 @Override
slowr13fa5b02017-08-08 16:32:31 -0700180 public void addListener(XranDeviceListener listener) {
181 xranDeviceListeners.add(listener);
182 }
183
184 @Override
185 public void addListener(XranHostListener listener) {
186 xranHostListeners.add(listener);
187 }
188
189 @Override
190 public void removeListener(XranDeviceListener listener) {
191 xranDeviceListeners.remove(listener);
192 }
193
194 @Override
195 public void removeListener(XranHostListener listener) {
196 xranHostListeners.remove(listener);
197 }
198
slowr67d05e42017-08-11 20:37:22 -0700199 @Override
slowr8ddc2b12017-08-14 14:13:38 -0700200 public SynchronousQueue<String> sendModifiedRRMConf(RRMConfig rrmConfig, boolean xICIC) {
201 ECGI ecgi = rrmConfig.getEcgi();
slowr67d05e42017-08-11 20:37:22 -0700202 ChannelHandlerContext ctx = cellMap.getCtx(ecgi);
203 try {
slowr8ddc2b12017-08-14 14:13:38 -0700204 XrancPdu pdu;
205 if (xICIC) {
206 pdu = XICICConfig.constructPacket(rrmConfig);
207 } else {
208 pdu = RRMConfig.constructPacket(rrmConfig);
209 }
slowr67d05e42017-08-11 20:37:22 -0700210 ctx.writeAndFlush(getSctpMessage(pdu));
211 } catch (IOException e) {
212 e.printStackTrace();
213 }
214 SynchronousQueue<String> queue = new SynchronousQueue<>();
215 RRMCellQueue.put(ecgi, queue);
216
217 return queue;
218 }
219
slowr89c2ac12017-08-15 16:20:06 -0700220 @Override
221 public SynchronousQueue<String> sendScellAdd(RnibLink link) {
222 RnibCell secondaryCell = link.getLinkId().getCell(),
223 primaryCell = linkMap.getPrimaryCell(link.getLinkId().getUe());
224 ECGI primaryEcgi = primaryCell.getEcgi();
225 ChannelHandlerContext ctx = cellMap.getCtx(primaryEcgi);
226
227 CRNTI crnti = linkMap.getCrnti(link.getLinkId().getMmeues1apid());
228
229 CellConfigReport cellReport = secondaryCell.getConf();
230
231 if (cellReport != null) {
232 PCIARFCN pciarfcn = new PCIARFCN();
233 pciarfcn.setPci(cellReport.getPci());
234 pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
235
236 PropScell propScell = new PropScell();
237 propScell.setPciArfcn(pciarfcn);
238
239 XrancPdu pdu = ScellAdd.constructPacket(primaryEcgi, crnti, propScell);
240 try {
241 ctx.writeAndFlush(getSctpMessage(pdu));
242 SynchronousQueue<String> queue = new SynchronousQueue<>();
243 scellAddQueue.put(crnti, queue);
244
245 return queue;
246 } catch (IOException e) {
247 log.error(ExceptionUtils.getFullStackTrace(e));
248 e.printStackTrace();
249 }
250 }
251 return null;
252 }
253
254 @Override
255 public boolean sendScellDelete(RnibLink link) {
256 RnibCell secondaryCell = link.getLinkId().getCell(),
257 primaryCell = linkMap.getPrimaryCell(link.getLinkId().getUe());
258 ECGI primaryEcgi = primaryCell.getEcgi();
259 ChannelHandlerContext ctx = cellMap.getCtx(primaryEcgi);
260
261 CRNTI crnti = linkMap.getCrnti(link.getLinkId().getMmeues1apid());
262
263 CellConfigReport cellReport = secondaryCell.getConf();
264
265 if (cellReport != null) {
266 PCIARFCN pciarfcn = new PCIARFCN();
267 pciarfcn.setPci(cellReport.getPci());
268 pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
269
270 XrancPdu pdu = ScellDelete.constructPacket(primaryEcgi, crnti, pciarfcn);
271
272 try {
273 ctx.writeAndFlush(getSctpMessage(pdu));
274 link.setType(RnibLink.Type.NON_SERVING);
275 return true;
276 } catch (IOException e) {
277 log.error(ExceptionUtils.getFullStackTrace(e));
278 e.printStackTrace();
279 }
280 }
281 return false;
282 }
283
slowr13fa5b02017-08-08 16:32:31 -0700284 private void restartTimer(RnibUe ue) {
285 Timer timer = new Timer();
286 ue.setTimer(timer);
287 log.info("Starting UE timer...");
288 timer.schedule(new TimerTask() {
289 @Override
290 public void run() {
slowr67d05e42017-08-11 20:37:22 -0700291 if (ue.getState() == RnibUe.State.IDLE) {
slowr13fa5b02017-08-08 16:32:31 -0700292 hostAgent.removeConnectedHost(ue);
293 log.info("UE is removed after 10 seconds of IDLE");
294 } else {
295 log.info("UE not removed cause its ACTIVE");
296 }
297 }
298 }, 10000);
299 }
300
301 private void restartTimer(RnibLink link) {
302 Timer timer = new Timer();
303 link.setTimer(timer);
304 log.info("Starting Link timer...");
305 timer.schedule(new TimerTask() {
306 @Override
307 public void run() {
308 LinkId linkId = link.getLinkId();
309 xranStore.removeLink(linkId);
310 log.info("Link is removed after not receiving Meas Reports for 10 seconds");
311 }
312 }, 10000);
313
314 }
315
316 class InternalDeviceListener implements DeviceListener {
317
318 @Override
319 public void event(DeviceEvent event) {
320 log.info("Device Event {}", event);
321 switch (event.type()) {
322 case DEVICE_ADDED: {
323 try {
324 ECGI ecgi = decodeDeviceId(event.subject().id());
325 RnibCell cell = cellMap.get(ecgi);
326 if (cell != null) {
327 Timer timer = new Timer();
328 timer.scheduleAtFixedRate(
329 new TimerTask() {
330 @Override
331 public void run() {
332 CellConfigReport conf = cell.getConf();
333 if (conf == null) {
334 try {
335 ChannelHandlerContext ctx = cellMap.getCtx(ecgi);
slowr8ddc2b12017-08-14 14:13:38 -0700336 XrancPdu xrancPdu = CellConfigRequest.constructPacket(ecgi);
slowr67d05e42017-08-11 20:37:22 -0700337 ctx.writeAndFlush(getSctpMessage(xrancPdu));
slowr13fa5b02017-08-08 16:32:31 -0700338 } catch (IOException e) {
339 log.error(ExceptionUtils.getFullStackTrace(e));
340 e.printStackTrace();
341 }
342 } else {
343 // FIXME: maybe remove this map.
344 cellMap.putPciArfcn(cell);
345 try {
346 ChannelHandlerContext ctx = cellMap.
347 getCtx(ecgi);
slowr8ddc2b12017-08-14 14:13:38 -0700348 XrancPdu xrancPdu = L2MeasConfig.constructPacket(ecgi, xranConfig.getL2MeasInterval());
slowr13fa5b02017-08-08 16:32:31 -0700349 cell.setMeasConfig(xrancPdu.getBody().getL2MeasConfig());
slowr67d05e42017-08-11 20:37:22 -0700350 SctpMessage sctpMessage = getSctpMessage(xrancPdu);
slowr13fa5b02017-08-08 16:32:31 -0700351 ctx.writeAndFlush(sctpMessage);
352 } catch (IOException e) {
353 log.error(ExceptionUtils.getFullStackTrace(e));
354 e.printStackTrace();
355 }
356 timer.cancel();
357 timer.purge();
358 }
359 }
360 },
361 0,
362 xranConfig.getConfigRequestInterval() * 1000
363 );
364 }
365 } catch (IOException e) {
366 log.error(ExceptionUtils.getFullStackTrace(e));
367 e.printStackTrace();
368 }
369 break;
370 }
371 default: {
372 break;
373 }
374 }
375 }
376 }
377
378 class InternalHostListener implements HostListener {
379
380 @Override
381 public void event(HostEvent event) {
382 log.info("Host Event {}", event);
383 switch (event.type()) {
384 case HOST_ADDED:
385 case HOST_MOVED: {
386 RnibUe ue = ueMap.get(hostIdtoMME(event.subject().id()));
387 if (ue != null) {
slowr89c2ac12017-08-15 16:20:06 -0700388 ECGI ecgi_primary = linkMap.getPrimaryCell(ue).getEcgi();
slowr13fa5b02017-08-08 16:32:31 -0700389 RnibCell primary = cellMap.get(ecgi_primary);
390 ue.setMeasConfig(null);
391 if (primary != null) {
392 Timer timer = new Timer();
393 timer.scheduleAtFixedRate(
394 new TimerTask() {
395 @Override
396 public void run() {
397 if (ue.getCapability() == null) {
398 try {
399 ChannelHandlerContext ctx = cellMap.getCtx(primary.getEcgi());
slowr8ddc2b12017-08-14 14:13:38 -0700400 XrancPdu xrancPdu = UECapabilityEnquiry.constructPacket(
slowr67d05e42017-08-11 20:37:22 -0700401 primary.getEcgi(),
402 ue.getRanId());
403 ctx.writeAndFlush(getSctpMessage(xrancPdu));
slowr13fa5b02017-08-08 16:32:31 -0700404 } catch (IOException e) {
405 log.warn(ExceptionUtils.getFullStackTrace(e));
406 e.printStackTrace();
407 }
408 } else {
409 if (ue.getMeasConfig() == null) {
410 try {
411 ChannelHandlerContext ctx = cellMap.getCtx(primary.getEcgi());
412 RXSigMeasConfig.MeasCells measCells = new RXSigMeasConfig.MeasCells();
413 xranStore.getCellNodes().forEach(cell -> {
414 CellConfigReport cellReport = cell.getConf();
415 if (cellReport != null) {
416 PCIARFCN pciarfcn = new PCIARFCN();
417 pciarfcn.setPci(cellReport.getPci());
418 pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
419 measCells.setPCIARFCN(pciarfcn);
420 }
421 });
slowr8ddc2b12017-08-14 14:13:38 -0700422 XrancPdu xrancPdu = RXSigMeasConfig.constructPacket(
slowr13fa5b02017-08-08 16:32:31 -0700423 primary.getEcgi(),
424 ue.getRanId(),
425 measCells,
426 xranConfig.getRxSignalInterval()
427 );
428 ue.setMeasConfig(xrancPdu.getBody().getRXSigMeasConfig());
slowr67d05e42017-08-11 20:37:22 -0700429 ctx.writeAndFlush(getSctpMessage(xrancPdu));
slowr13fa5b02017-08-08 16:32:31 -0700430 } catch (IOException e) {
431 log.warn(ExceptionUtils.getFullStackTrace(e));
432 e.printStackTrace();
433 }
434 }
435 timer.cancel();
436 timer.purge();
437 }
438 }
439 },
440 0,
441 xranConfig.getConfigRequestInterval() * 1000
442 );
443 }
444 }
445 break;
446 }
447 default: {
448 break;
449 }
450 }
451 }
452 }
453
454 public class InternalXranDeviceAgent implements XranDeviceAgent {
455
456 private final Logger log = LoggerFactory.getLogger(InternalXranDeviceAgent.class);
457
458 @Override
459 public boolean addConnectedCell(String host, ChannelHandlerContext ctx) {
460 ECGI ecgi = legitCells.get(host);
461
462 if (ecgi == null) {
463 log.error("Device is not a legit source; ignoring...");
464 } else {
465 log.info("Device exists in configuration; registering...");
466 RnibCell storeCell = cellMap.get(ecgi);
467 if (storeCell == null) {
468 storeCell = new RnibCell();
469 storeCell.setEcgi(ecgi);
470 cellMap.put(storeCell, ctx);
471
472 for (XranDeviceListener l : xranDeviceListeners) {
473 l.deviceAdded(storeCell);
474 }
475 return true;
476 } else {
477 log.error("Device already registered; ignoring...");
478 }
479 }
480 ctx.close();
481 return false;
482 }
483
484 @Override
485 public boolean removeConnectedCell(String host) {
486 ECGI ecgi = legitCells.get(host);
487 List<RnibLink> linksByECGI = xranStore.getLinksByECGI(ecgi);
488
489 linksByECGI.forEach(rnibLink -> xranStore.removeLink(rnibLink.getLinkId()));
490
491 if (cellMap.remove(ecgi)) {
492 for (XranDeviceListener l : xranDeviceListeners) {
493 l.deviceRemoved(deviceId(uri(ecgi)));
494 }
495 return true;
496 }
497 return false;
498 }
499 }
500
501 public class InternalXranHostAgent implements XranHostAgent {
502
503 @Override
504 public boolean addConnectedHost(RnibUe ue, RnibCell cell, ChannelHandlerContext ctx) {
505
506 if (ueMap.get(ue.getMmeS1apId()) != null) {
507 linkMap.putPrimaryLink(cell, ue);
508
509 Set<ECGI> ecgiSet = xranStore.getLinksByUeId(ue.getMmeS1apId().longValue())
510 .stream()
slowr8ddc2b12017-08-14 14:13:38 -0700511 .map(l -> l.getLinkId().getEcgi())
slowr13fa5b02017-08-08 16:32:31 -0700512 .collect(Collectors.toSet());
513
514 for (XranHostListener l : xranHostListeners) {
515 l.hostAdded(ue, ecgiSet);
516 }
517 return true;
518 } else {
519 ueMap.put(ue);
520 linkMap.putPrimaryLink(cell, ue);
521
522 Set<ECGI> ecgiSet = Sets.newConcurrentHashSet();
523 ecgiSet.add(cell.getEcgi());
524 for (XranHostListener l : xranHostListeners) {
525 l.hostAdded(ue, ecgiSet);
526 }
527 return true;
528 }
529
530 }
531
532 @Override
533 public boolean removeConnectedHost(RnibUe ue) {
534 List<RnibLink> links = xranStore.getLinksByUeId(ue.getMmeS1apId().longValue());
535 links.forEach(rnibLink -> xranStore.removeLink(rnibLink.getLinkId()));
536 if (ueMap.remove(ue.getMmeS1apId())) {
537 for (XranHostListener l : xranHostListeners) {
538 l.hostRemoved(ue.getHostId());
539 }
540 return true;
541 }
542 return false;
543 }
544 }
545
546 public class InternalXranPacketAgent implements XranPacketProcessor {
547 @Override
548 public void handlePacket(XrancPdu recv_pdu, ChannelHandlerContext ctx) throws IOException {
549 XrancPdu send_pdu;
550
551 int apiID = recv_pdu.getHdr().getApiId().intValue();
552 log.debug("Received message: {}", recv_pdu);
553 switch (apiID) {
554 case 1: {
555 // Decode Cell config report.
556 CellConfigReport report = recv_pdu.getBody().getCellConfigReport();
557
558 ECGI ecgi = report.getEcgi();
559
560 RnibCell cell = xranStore.getCell(ecgi);
slowr8ddc2b12017-08-14 14:13:38 -0700561 cell.setVersion(recv_pdu.getHdr().getVer().toString());
slowr13fa5b02017-08-08 16:32:31 -0700562 cell.setConf(report);
563
564 break;
565 }
566 case 2: {
567 // Decode UE Admission Request.
568 UEAdmissionRequest ueAdmissionRequest = recv_pdu.getBody().getUEAdmissionRequest();
569
570 ECGI ecgi = ueAdmissionRequest.getEcgi();
571 if (xranStore.getCell(ecgi) != null) {
572 CRNTI crnti = ueAdmissionRequest.getCrnti();
slowr8ddc2b12017-08-14 14:13:38 -0700573 send_pdu = UEAdmissionResponse.constructPacket(ecgi, crnti, xranConfig.admissionFlag());
slowr67d05e42017-08-11 20:37:22 -0700574 ctx.writeAndFlush(getSctpMessage(send_pdu));
slowr13fa5b02017-08-08 16:32:31 -0700575 } else {
576 log.warn("Could not find ECGI in registered cells: {}", ecgi);
577 }
578 break;
579 }
580 case 4: {
581 // Decode UE Admission Status.
582 UEAdmissionStatus ueAdmissionStatus = recv_pdu.getBody().getUEAdmissionStatus();
583
584 RnibUe ue = ueMap.get(ueAdmissionStatus.getCrnti());
585 if (ue != null) {
586 if (ueAdmissionStatus.getAdmEstStatus().value.intValue() == 0) {
slowr67d05e42017-08-11 20:37:22 -0700587 ue.setState(RnibUe.State.ACTIVE);
slowr13fa5b02017-08-08 16:32:31 -0700588 } else {
slowr67d05e42017-08-11 20:37:22 -0700589 ue.setState(RnibUe.State.IDLE);
slowr13fa5b02017-08-08 16:32:31 -0700590 }
591 }
592 break;
593 }
594 case 5: {
595 // Decode UE Admission Context Update.
slowr8ddc2b12017-08-14 14:13:38 -0700596 UEContextUpdate ueContextUpdate = recv_pdu.getBody().getUEContextUpdate();
slowr13fa5b02017-08-08 16:32:31 -0700597
slowr8ddc2b12017-08-14 14:13:38 -0700598 RnibCell cell = xranStore.getCell(ueContextUpdate.getEcgi());
slowr13fa5b02017-08-08 16:32:31 -0700599
slowr8ddc2b12017-08-14 14:13:38 -0700600 RnibUe ue = ueMap.get(ueContextUpdate.getMMEUES1APID());
601 if (ueMap.get(ueContextUpdate.getMMEUES1APID()) == null) {
slowr13fa5b02017-08-08 16:32:31 -0700602 ue = new RnibUe();
603 }
604
slowr8ddc2b12017-08-14 14:13:38 -0700605 ue.setMmeS1apId(ueContextUpdate.getMMEUES1APID());
606 ue.setEnbS1apId(ueContextUpdate.getENBUES1APID());
607 ue.setRanId(ueContextUpdate.getCrnti());
slowr13fa5b02017-08-08 16:32:31 -0700608
609 hostAgent.addConnectedHost(ue, cell, ctx);
610 break;
611 }
612 case 6: {
613 // Decode UE Reconfig_Ind.
614 UEReconfigInd ueReconfigInd = recv_pdu.getBody().getUEReconfigInd();
615 RnibUe ue = ueMap.get(ueReconfigInd.getCrntiOld());
616
617 if (ue != null) {
618 ue.setRanId(ueReconfigInd.getCrntiNew());
619 } else {
620 log.warn("Could not find UE with this CRNTI: {}", ueReconfigInd.getCrntiOld());
621 }
622 break;
623 }
624 case 7: {
625 // If xRANc wants to deactivate UE, we pass UEReleaseInd from xRANc to eNB.
626 // Decode UE Release_Ind.
627 UEReleaseInd ueReleaseInd = recv_pdu.getBody().getUEReleaseInd();
628 RnibUe ue = ueMap.get(ueReleaseInd.getCrnti());
629 if (ue != null) {
slowr67d05e42017-08-11 20:37:22 -0700630 ue.setState(RnibUe.State.IDLE);
slowr13fa5b02017-08-08 16:32:31 -0700631 restartTimer(ue);
632 }
633 break;
634 }
635 case 8: {
636 // Decode Bearer Adm Request
637 BearerAdmissionRequest bearerAdmissionRequest = recv_pdu.getBody().getBearerAdmissionRequest();
638
639 ECGI ecgi = bearerAdmissionRequest.getEcgi();
640 CRNTI crnti = bearerAdmissionRequest.getCrnti();
641 ERABParams erabParams = bearerAdmissionRequest.getErabParams();
642 RnibLink link = linkMap.get(ecgi, crnti);
643 if (link != null) {
644 link.setBearerParameters(erabParams);
645 } else {
646 log.warn("Could not find link between {}-{}", ecgi, crnti);
647 }
648
649 BerInteger numErabs = bearerAdmissionRequest.getNumErabs();
slowr8ddc2b12017-08-14 14:13:38 -0700650 // Encode and send Bearer Admission Response
651 send_pdu = BearerAdmissionResponse.constructPacket(ecgi, crnti, erabParams, numErabs, xranConfig.bearerFlag());
slowr67d05e42017-08-11 20:37:22 -0700652 ctx.writeAndFlush(getSctpMessage(send_pdu));
slowr13fa5b02017-08-08 16:32:31 -0700653 break;
654 }
655 case 10: {
656 //Decode Bearer Admission Status
657 BearerAdmissionStatus bearerAdmissionStatus = recv_pdu.getBody().getBearerAdmissionStatus();
slowr8ddc2b12017-08-14 14:13:38 -0700658 break;
slowr13fa5b02017-08-08 16:32:31 -0700659// ECGI ecgi = bearerAdmissionStatus.getEcgi();
660// CRNTI crnti = bearerAdmissionStatus.getCrnti();
661//
662// RnibLink link = linkMap.get(ecgi, crnti);
slowr13fa5b02017-08-08 16:32:31 -0700663 }
664 case 11: {
665 //Decode Bearer Release Ind
666 BearerReleaseInd bearerReleaseInd = recv_pdu.getBody().getBearerReleaseInd();
667
668 ECGI ecgi = bearerReleaseInd.getEcgi();
669 CRNTI crnti = bearerReleaseInd.getCrnti();
670 RnibLink link = linkMap.get(ecgi, crnti);
671
672 List<ERABID> erabidsRelease = bearerReleaseInd.getErabIds().getERABID();
673 List<ERABParamsItem> erabParamsItem = link.getBearerParameters().getERABParamsItem();
674
675 List<ERABParamsItem> unreleased = erabParamsItem
676 .stream()
677 .filter(item -> {
678 Optional<ERABID> any = erabidsRelease.stream().filter(id -> id.equals(item.getId())).findAny();
679 return !any.isPresent();
680 }).collect(Collectors.toList());
681
682 link.getBearerParameters().setERABParamsItem(new ArrayList<>(unreleased));
slowr13fa5b02017-08-08 16:32:31 -0700683 break;
684 }
685 case 13: {
slowr67d05e42017-08-11 20:37:22 -0700686 HOFailure hoFailure = recv_pdu.getBody().getHOFailure();
687
688 try {
689 hoQueue.get(hoFailure.getCrnti())
690 .put("Hand Over Failed with cause: " + hoFailure.getCause());
691 } catch (InterruptedException e) {
692 log.error(ExceptionUtils.getFullStackTrace(e));
693 e.printStackTrace();
694 } finally {
695 hoQueue.remove(hoFailure.getCrnti());
696 }
697 break;
slowr8ddc2b12017-08-14 14:13:38 -0700698
slowr67d05e42017-08-11 20:37:22 -0700699 }
slowr8ddc2b12017-08-14 14:13:38 -0700700 case 14: {
slowr67d05e42017-08-11 20:37:22 -0700701 HOComplete hoComplete = recv_pdu.getBody().getHOComplete();
702
703 RnibLink oldLink = linkMap.get(hoComplete.getEcgiS(), hoComplete.getCrntiNew()),
704 newLink = linkMap.get(hoComplete.getEcgiT(), hoComplete.getCrntiNew());
705
706 oldLink.setType(RnibLink.Type.NON_SERVING);
707 newLink.setType(RnibLink.Type.SERVING_PRIMARY);
708
709 try {
710 hoQueue.get(hoComplete.getCrntiNew())
711 .put("Hand Over Completed");
712 } catch (InterruptedException e) {
713 log.error(ExceptionUtils.getFullStackTrace(e));
714 e.printStackTrace();
715 } finally {
716 hoQueue.remove(hoComplete.getCrntiNew());
717 }
718 break;
719 }
slowr8ddc2b12017-08-14 14:13:38 -0700720
721 case 16: {
slowr13fa5b02017-08-08 16:32:31 -0700722 // Decode RX Sig Meas Report.
723 RXSigMeasReport rxSigMeasReport = recv_pdu.getBody().getRXSigMeasReport();
724 List<RXSigReport> rxSigReportList = rxSigMeasReport.getCellMeasReports().getRXSigReport();
725
726 if (!rxSigReportList.isEmpty()) {
727 rxSigReportList.forEach(rxSigReport -> {
728 RnibCell cell = cellMap.get(rxSigReport.getPciArfcn());
729 if (cell != null) {
730 ECGI ecgi = cell.getEcgi();
731 RnibLink link = linkMap.get(ecgi, rxSigMeasReport.getCrnti());
732 if (link == null) {
733 log.warn("Could not find link between: {}-{} | Creating non-serving link..", ecgi, rxSigMeasReport.getCrnti());
734 link = linkMap.putNonServingLink(cell, rxSigMeasReport.getCrnti());
735
736 if (link != null) {
737 restartTimer(link);
738 }
739 }
740
741 if (link != null) {
742 RSRQRange rsrq = rxSigReport.getRsrq();
743 RSRPRange rsrp = rxSigReport.getRsrp();
744
745 RnibLink.LinkQuality quality = link.getQuality();
746 quality.setRsrp(rsrp.value.intValue() - 140);
747 quality.setRsrq((rsrq.value.intValue() * 0.5) - 19.5);
748 }
749 } else {
750 log.warn("Could not find cell with PCI-ARFCN: {}", rxSigReport.getPciArfcn());
751 }
752 });
753 }
754 break;
755 }
slowr8ddc2b12017-08-14 14:13:38 -0700756 case 18: {
slowr13fa5b02017-08-08 16:32:31 -0700757 RadioMeasReportPerUE radioMeasReportPerUE = recv_pdu.getBody().getRadioMeasReportPerUE();
758
759 List<RadioRepPerServCell> servCells = radioMeasReportPerUE.getRadioReportServCells().getRadioRepPerServCell();
760
761 servCells.forEach(servCell -> {
762 RnibCell cell = cellMap.get(servCell.getPciArfcn());
763 if (cell != null) {
764 RnibLink link = linkMap.get(cell.getEcgi(), radioMeasReportPerUE.getCrnti());
765 if (link != null) {
766 RadioRepPerServCell.CqiHist cqiHist = servCell.getCqiHist();
767 RnibLink.LinkQuality quality = link.getQuality();
768 quality.setCqiHist(cqiHist);
769
770 final double[] values = {0, 0, 0};
771 int i = 1;
772 cqiHist.getBerInteger().forEach(value -> {
773 values[0] = Math.max(values[0], value.intValue());
774 values[1] += i * value.intValue();
775 values[2] += value.intValue();
776 });
777
778 quality.setCqiMode(values[0]);
779 quality.setCqiMean(values[1] / values[2]);
780
781 } else {
782 log.warn("Could not find link between: {}-{}", cell.getEcgi(), radioMeasReportPerUE.getCrnti());
783 }
784 } else {
785 log.warn("Could not find cell with PCI-ARFCN: {}", servCell.getPciArfcn());
786 }
787 });
slowr67d05e42017-08-11 20:37:22 -0700788 break;
slowr13fa5b02017-08-08 16:32:31 -0700789 }
slowr8ddc2b12017-08-14 14:13:38 -0700790 case 19: {
slowr13fa5b02017-08-08 16:32:31 -0700791 RadioMeasReportPerCell radioMeasReportPerCell = recv_pdu.getBody().getRadioMeasReportPerCell();
792 break;
793 }
slowr8ddc2b12017-08-14 14:13:38 -0700794 case 20: {
slowr13fa5b02017-08-08 16:32:31 -0700795 SchedMeasReportPerUE schedMeasReportPerUE = recv_pdu.getBody().getSchedMeasReportPerUE();
slowr8ddc2b12017-08-14 14:13:38 -0700796 List<SchedMeasRepPerServCell> servCells = schedMeasReportPerUE.getSchedReportServCells()
797 .getSchedMeasRepPerServCell();
slowr13fa5b02017-08-08 16:32:31 -0700798
799 servCells.forEach(servCell -> {
800 RnibCell cell = cellMap.get(servCell.getPciArfcn());
801 if (cell != null) {
802 RnibLink link = linkMap.get(cell.getEcgi(), schedMeasReportPerUE.getCrnti());
803 if (link != null) {
804 link.getQuality().setMcs_dl(servCell.getMcsDl());
805 link.getQuality().setMcs_ul(servCell.getMcsUl());
806
807 link.getResourceUsage().setDl(servCell.getPrbUsage().getPrbUsageDl());
808 link.getResourceUsage().setUl(servCell.getPrbUsage().getPrbUsageUl());
809 } else {
slowr8ddc2b12017-08-14 14:13:38 -0700810 log.warn("Could not find link between: {}-{}", cell.getEcgi(),
811 schedMeasReportPerUE.getCrnti());
slowr13fa5b02017-08-08 16:32:31 -0700812 }
813 } else {
814 log.warn("Could not find cell with PCI-ARFCN: {}", servCell.getPciArfcn());
815 }
816 });
817 break;
818 }
slowr8ddc2b12017-08-14 14:13:38 -0700819 case 21: {
slowr13fa5b02017-08-08 16:32:31 -0700820 SchedMeasReportPerCell schedMeasReportPerCell = recv_pdu.getBody().getSchedMeasReportPerCell();
slowr13fa5b02017-08-08 16:32:31 -0700821 RnibCell cell = cellMap.get(schedMeasReportPerCell.getEcgi());
822 if (cell != null) {
823 cell.setPrimaryPrbUsage(schedMeasReportPerCell.getPrbUsagePcell());
824 cell.setSecondaryPrbUsage(schedMeasReportPerCell.getPrbUsageScell());
825 cell.setQci(schedMeasReportPerCell.getQciVals());
826 } else {
827 log.warn("Could not find cell with ECGI: {}", schedMeasReportPerCell.getEcgi());
828 }
829 break;
830 }
slowr8ddc2b12017-08-14 14:13:38 -0700831 case 22: {
slowr13fa5b02017-08-08 16:32:31 -0700832 PDCPMeasReportPerUe pdcpMeasReportPerUe = recv_pdu.getBody().getPDCPMeasReportPerUe();
833
834 RnibLink link = linkMap.get(pdcpMeasReportPerUe.getEcgi(), pdcpMeasReportPerUe.getCrnti());
835 if (link != null) {
836 link.getPdcpThroughput().setDl(pdcpMeasReportPerUe.getThroughputDl());
837 link.getPdcpThroughput().setUl(pdcpMeasReportPerUe.getThroughputUl());
838 link.getPdcpPackDelay().setDl(pdcpMeasReportPerUe.getPktDelayDl());
839 link.getPdcpPackDelay().setUl(pdcpMeasReportPerUe.getPktDelayUl());
840 } else {
slowr8ddc2b12017-08-14 14:13:38 -0700841 log.warn("Could not find link between: {}-{}", pdcpMeasReportPerUe.getEcgi(),
842 pdcpMeasReportPerUe.getCrnti());
slowr13fa5b02017-08-08 16:32:31 -0700843 }
844 break;
845 }
slowr8ddc2b12017-08-14 14:13:38 -0700846 case 24: {
847 // Decode UE Capability Info
848 UECapabilityInfo capabilityInfo = recv_pdu.getBody().getUECapabilityInfo();
849
850 RnibUe ue = ueMap.get(capabilityInfo.getCrnti());
851 if (ue != null) {
852 ue.setCapability(capabilityInfo);
853 } else {
854 log.warn("Could not find UE with this CRNTI: {}", capabilityInfo.getCrnti());
855 }
856 break;
857 }
858 case 25: {
859 // Don't know what will invoke sending UE CAPABILITY ENQUIRY
860 // Encode and send UE CAPABILITY ENQUIRY
861 UECapabilityEnquiry ueCapabilityEnquiry = recv_pdu.getBody().getUECapabilityEnquiry();
862 XrancPdu xrancPdu = UECapabilityEnquiry.constructPacket(ueCapabilityEnquiry.getEcgi(), ueCapabilityEnquiry.getCrnti());
863 ctx.writeAndFlush(getSctpMessage(xrancPdu));
864 break;
865 }
slowr89c2ac12017-08-15 16:20:06 -0700866 case 27: {
867 //Decode ScellAddStatus
868 ScellAddStatus scellAddStatus = recv_pdu.getBody().getScellAddStatus();
869 try {
870 scellAddQueue.get(scellAddStatus.getCrnti()).put("Scell's status: " + scellAddStatus.getStatus());
871 if (scellAddStatus.getStatus().getBerEnum().get(0).value.intValue() == 0) {
872
873 scellAddStatus.getScellsInd().getPCIARFCN().forEach(
874 pciarfcn -> {
875 RnibCell cell = cellMap.get(pciarfcn);
876 RnibLink link = linkMap.get(cell.getEcgi(), scellAddStatus.getCrnti());
877 link.setType(RnibLink.Type.SERVING_SECONDARY_CA);
878 }
879 );
880 } else {
881 log.error("Scell addition failed.");
882 }
883 } catch (InterruptedException e) {
884 log.error(ExceptionUtils.getFullStackTrace(e));
885 e.printStackTrace();
886 } finally {
887 scellAddQueue.remove(scellAddStatus.getCrnti());
888 }
889 break;
890 }
891 // TODO: 28: ScellDelete
slowr8ddc2b12017-08-14 14:13:38 -0700892
893 case 30: {
894 // Decode RRMConfig Status
slowr67d05e42017-08-11 20:37:22 -0700895 RRMConfigStatus rrmConfigStatus = recv_pdu.getBody().getRRMConfigStatus();
896 try {
897 RRMCellQueue.get(rrmConfigStatus.getEcgi())
898 .put("RRM Config's status: " + rrmConfigStatus.getStatus());
899 } catch (InterruptedException e) {
900 log.error(ExceptionUtils.getFullStackTrace(e));
901 e.printStackTrace();
902 } finally {
903 RRMCellQueue.remove(rrmConfigStatus.getEcgi());
904 }
905 break;
906 }
slowr8ddc2b12017-08-14 14:13:38 -0700907 //TODO Case 31: SeNBAdd 32: SeNBAddStatus 33: SeNBDelete
slowr13fa5b02017-08-08 16:32:31 -0700908 case 34: {
909 TrafficSplitConfig trafficSplitConfig = recv_pdu.getBody().getTrafficSplitConfig();
910
911 List<TrafficSplitPercentage> splitPercentages = trafficSplitConfig.getTrafficSplitPercent().getTrafficSplitPercentage();
912
913 splitPercentages.forEach(trafficSplitPercentage -> {
914 RnibCell cell = cellMap.get(trafficSplitPercentage.getEcgi());
915 if (cell != null) {
916 RnibLink link = linkMap.get(cell.getEcgi(), trafficSplitConfig.getCrnti());
917 if (link != null) {
918 link.setTrafficPercent(trafficSplitPercentage);
919 } else {
920 log.warn("Could not find link between: {}-{}", cell.getEcgi(), trafficSplitConfig.getCrnti());
921 }
922 } else {
923 log.warn("Could not find cell with ECGI: {}", trafficSplitConfig.getEcgi());
924 }
925 });
slowr67d05e42017-08-11 20:37:22 -0700926 break;
slowr13fa5b02017-08-08 16:32:31 -0700927 }
928 default: {
929 log.warn("Wrong API ID");
slowr67d05e42017-08-11 20:37:22 -0700930 break;
slowr13fa5b02017-08-08 16:32:31 -0700931 }
932 }
933
934 }
935 }
936
937 class InternalNetworkConfigListener implements NetworkConfigListener {
938
939 @Override
940 public void event(NetworkConfigEvent event) {
941 switch (event.type()) {
942 case CONFIG_REGISTERED:
943 break;
944 case CONFIG_UNREGISTERED:
945 break;
946 case CONFIG_ADDED:
947 case CONFIG_UPDATED:
948 if (event.configClass() == CONFIG_CLASS) {
949 handleConfigEvent(event.config());
950 }
951 break;
952 case CONFIG_REMOVED:
953 break;
954 default:
955 break;
956 }
957 }
958
959 private void handleConfigEvent(Optional<Config> config) {
960 if (!config.isPresent()) {
961 return;
962 }
963
964 xranConfig = (XranConfig) config.get();
965
966 legitCells.putAll(xranConfig.activeCellSet());
967
968 controller.start(deviceAgent, hostAgent, packetAgent, xranConfig.getXrancPort());
969 }
970 }
971}