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