blob: eeb29665b87b9a1a48660d1c9eef0a5df17f9c5a [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.*;
slowrc153ad92017-08-16 19:47:52 -070036import org.onosproject.xran.codecs.ber.types.BerInteger;
slowr13fa5b02017-08-08 16:32:31 -070037import org.onosproject.xran.codecs.pdu.*;
38import org.onosproject.xran.entities.RnibCell;
39import org.onosproject.xran.entities.RnibLink;
40import org.onosproject.xran.entities.RnibUe;
41import org.onosproject.xran.identifiers.LinkId;
42import org.onosproject.xran.impl.XranConfig;
43import org.onosproject.xran.providers.XranDeviceListener;
44import org.onosproject.xran.providers.XranHostListener;
slowr13fa5b02017-08-08 16:32:31 -070045import org.onosproject.xran.wrapper.CellMap;
46import org.onosproject.xran.wrapper.LinkMap;
47import org.onosproject.xran.wrapper.UeMap;
slowr13fa5b02017-08-08 16:32:31 -070048import 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<>();
slowr73b4eae2017-08-17 16:09:09 -0700110 private ConcurrentMap<ECGI, SynchronousQueue<String>> hoQueue = new ConcurrentHashMap<>();
slowr89c2ac12017-08-15 16:20:06 -0700111 private ConcurrentMap<ECGI, SynchronousQueue<String>> RRMCellQueue = new ConcurrentHashMap<>();
112 private ConcurrentMap<CRNTI, SynchronousQueue<String>> scellAddQueue = new ConcurrentHashMap<>();
slowr13fa5b02017-08-08 16:32:31 -0700113 /* AGENTS */
114 private InternalXranDeviceAgent deviceAgent = new InternalXranDeviceAgent();
115 private InternalXranHostAgent hostAgent = new InternalXranHostAgent();
116 private InternalXranPacketAgent packetAgent = new InternalXranPacketAgent();
117 /* LISTENERS */
118 private Set<XranDeviceListener> xranDeviceListeners = new CopyOnWriteArraySet<>();
119 private Set<XranHostListener> xranHostListeners = new CopyOnWriteArraySet<>();
120 private InternalDeviceListener device_listener = new InternalDeviceListener();
121 private InternalHostListener host_listener = new InternalHostListener();
122
123 @Activate
124 public void activate() {
125 appId = coreService.registerApplication(XRAN_APP_ID);
126
127 configService.addListener(configListener);
128 registry.registerConfigFactory(xranConfigFactory);
129 deviceService.addListener(device_listener);
130 hostService.addListener(host_listener);
131
132 cellMap = new CellMap(xranStore);
133 ueMap = new UeMap(xranStore);
134 linkMap = new LinkMap(xranStore);
135
136 xranStore.setController(this);
137
138 log.info("XRAN Controller Started");
139 }
140
141 @Deactivate
142 public void deactivate() {
143 controller.stop();
144
145 deviceService.removeListener(device_listener);
146 hostService.removeListener(host_listener);
147
148 legitCells.clear();
149
150 configService.removeListener(configListener);
151 registry.unregisterConfigFactory(xranConfigFactory);
152
153 log.info("XRAN Controller Stopped");
154 }
155
156 @Override
slowr73b4eae2017-08-17 16:09:09 -0700157 public SynchronousQueue<String> sendHORequest(RnibLink link_t, RnibLink link_s) {
158 ECGI ecgi_t = link_t.getLinkId().getEcgi(),
159 ecgi_s = link_s.getLinkId().getEcgi();
160
161 CRNTI crnti = linkMap.getCrnti(link_t.getLinkId().getMmeues1apid());
162 ChannelHandlerContext ctx_t = cellMap.getCtx(ecgi_t),
163 ctx_s = cellMap.getCtx(ecgi_s);
slowr67d05e42017-08-11 20:37:22 -0700164
165 try {
slowr73b4eae2017-08-17 16:09:09 -0700166 XrancPdu xrancPdu = HORequest.constructPacket(crnti, ecgi_s, ecgi_t);
167 ctx_t.writeAndFlush(getSctpMessage(xrancPdu));
168 ctx_s.writeAndFlush(getSctpMessage(xrancPdu));
slowr67d05e42017-08-11 20:37:22 -0700169 } catch (IOException e) {
170 e.printStackTrace();
171 }
172
173 SynchronousQueue<String> queue = new SynchronousQueue<>();
slowr73b4eae2017-08-17 16:09:09 -0700174 hoQueue.put(ecgi_s, queue);
slowr67d05e42017-08-11 20:37:22 -0700175
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 {
slowr73b4eae2017-08-17 16:09:09 -0700204 XrancPdu pdu = null;
205
slowr8ddc2b12017-08-14 14:13:38 -0700206 if (xICIC) {
slowr73b4eae2017-08-17 16:09:09 -0700207 CellConfigReport cellConfigReport = cellMap.get(ecgi).getConf();
208 if (cellConfigReport != null) {
209 pdu = XICICConfig.constructPacket(rrmConfig, cellConfigReport);
210 ctx.writeAndFlush(getSctpMessage(pdu));
211 }
slowr8ddc2b12017-08-14 14:13:38 -0700212 } else {
213 pdu = RRMConfig.constructPacket(rrmConfig);
slowr73b4eae2017-08-17 16:09:09 -0700214 ctx.writeAndFlush(getSctpMessage(pdu));
215 SynchronousQueue<String> queue = new SynchronousQueue<>();
216 RRMCellQueue.put(ecgi, queue);
217 return queue;
slowr8ddc2b12017-08-14 14:13:38 -0700218 }
slowr67d05e42017-08-11 20:37:22 -0700219 } catch (IOException e) {
220 e.printStackTrace();
221 }
slowr67d05e42017-08-11 20:37:22 -0700222
slowr73b4eae2017-08-17 16:09:09 -0700223 return null;
slowr67d05e42017-08-11 20:37:22 -0700224 }
225
slowr89c2ac12017-08-15 16:20:06 -0700226 @Override
227 public SynchronousQueue<String> sendScellAdd(RnibLink link) {
228 RnibCell secondaryCell = link.getLinkId().getCell(),
229 primaryCell = linkMap.getPrimaryCell(link.getLinkId().getUe());
230 ECGI primaryEcgi = primaryCell.getEcgi();
231 ChannelHandlerContext ctx = cellMap.getCtx(primaryEcgi);
232
233 CRNTI crnti = linkMap.getCrnti(link.getLinkId().getMmeues1apid());
234
235 CellConfigReport cellReport = secondaryCell.getConf();
236
237 if (cellReport != null) {
238 PCIARFCN pciarfcn = new PCIARFCN();
239 pciarfcn.setPci(cellReport.getPci());
240 pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
241
242 PropScell propScell = new PropScell();
243 propScell.setPciArfcn(pciarfcn);
244
245 XrancPdu pdu = ScellAdd.constructPacket(primaryEcgi, crnti, propScell);
246 try {
247 ctx.writeAndFlush(getSctpMessage(pdu));
248 SynchronousQueue<String> queue = new SynchronousQueue<>();
249 scellAddQueue.put(crnti, queue);
250
251 return queue;
252 } catch (IOException e) {
253 log.error(ExceptionUtils.getFullStackTrace(e));
254 e.printStackTrace();
255 }
256 }
257 return null;
258 }
259
260 @Override
261 public boolean sendScellDelete(RnibLink link) {
262 RnibCell secondaryCell = link.getLinkId().getCell(),
263 primaryCell = linkMap.getPrimaryCell(link.getLinkId().getUe());
264 ECGI primaryEcgi = primaryCell.getEcgi();
265 ChannelHandlerContext ctx = cellMap.getCtx(primaryEcgi);
266
267 CRNTI crnti = linkMap.getCrnti(link.getLinkId().getMmeues1apid());
268
269 CellConfigReport cellReport = secondaryCell.getConf();
270
271 if (cellReport != null) {
272 PCIARFCN pciarfcn = new PCIARFCN();
273 pciarfcn.setPci(cellReport.getPci());
274 pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
275
276 XrancPdu pdu = ScellDelete.constructPacket(primaryEcgi, crnti, pciarfcn);
277
278 try {
279 ctx.writeAndFlush(getSctpMessage(pdu));
280 link.setType(RnibLink.Type.NON_SERVING);
281 return true;
282 } catch (IOException e) {
283 log.error(ExceptionUtils.getFullStackTrace(e));
284 e.printStackTrace();
285 }
286 }
287 return false;
288 }
289
slowr13fa5b02017-08-08 16:32:31 -0700290 private void restartTimer(RnibUe ue) {
291 Timer timer = new Timer();
292 ue.setTimer(timer);
293 log.info("Starting UE timer...");
294 timer.schedule(new TimerTask() {
295 @Override
296 public void run() {
slowr67d05e42017-08-11 20:37:22 -0700297 if (ue.getState() == RnibUe.State.IDLE) {
slowr13fa5b02017-08-08 16:32:31 -0700298 hostAgent.removeConnectedHost(ue);
299 log.info("UE is removed after 10 seconds of IDLE");
300 } else {
301 log.info("UE not removed cause its ACTIVE");
302 }
303 }
304 }, 10000);
305 }
306
307 private void restartTimer(RnibLink link) {
308 Timer timer = new Timer();
309 link.setTimer(timer);
310 log.info("Starting Link timer...");
311 timer.schedule(new TimerTask() {
312 @Override
313 public void run() {
314 LinkId linkId = link.getLinkId();
315 xranStore.removeLink(linkId);
316 log.info("Link is removed after not receiving Meas Reports for 10 seconds");
317 }
318 }, 10000);
319
320 }
321
322 class InternalDeviceListener implements DeviceListener {
323
324 @Override
325 public void event(DeviceEvent event) {
326 log.info("Device Event {}", event);
327 switch (event.type()) {
328 case DEVICE_ADDED: {
329 try {
330 ECGI ecgi = decodeDeviceId(event.subject().id());
331 RnibCell cell = cellMap.get(ecgi);
332 if (cell != null) {
333 Timer timer = new Timer();
334 timer.scheduleAtFixedRate(
335 new TimerTask() {
336 @Override
337 public void run() {
338 CellConfigReport conf = cell.getConf();
339 if (conf == null) {
340 try {
341 ChannelHandlerContext ctx = cellMap.getCtx(ecgi);
slowr8ddc2b12017-08-14 14:13:38 -0700342 XrancPdu xrancPdu = CellConfigRequest.constructPacket(ecgi);
slowr67d05e42017-08-11 20:37:22 -0700343 ctx.writeAndFlush(getSctpMessage(xrancPdu));
slowr13fa5b02017-08-08 16:32:31 -0700344 } catch (IOException e) {
345 log.error(ExceptionUtils.getFullStackTrace(e));
346 e.printStackTrace();
347 }
348 } else {
slowr13fa5b02017-08-08 16:32:31 -0700349 try {
350 ChannelHandlerContext ctx = cellMap.
351 getCtx(ecgi);
slowr8ddc2b12017-08-14 14:13:38 -0700352 XrancPdu xrancPdu = L2MeasConfig.constructPacket(ecgi, xranConfig.getL2MeasInterval());
slowr13fa5b02017-08-08 16:32:31 -0700353 cell.setMeasConfig(xrancPdu.getBody().getL2MeasConfig());
slowr67d05e42017-08-11 20:37:22 -0700354 SctpMessage sctpMessage = getSctpMessage(xrancPdu);
slowr13fa5b02017-08-08 16:32:31 -0700355 ctx.writeAndFlush(sctpMessage);
356 } catch (IOException e) {
357 log.error(ExceptionUtils.getFullStackTrace(e));
358 e.printStackTrace();
359 }
360 timer.cancel();
361 timer.purge();
362 }
363 }
364 },
365 0,
366 xranConfig.getConfigRequestInterval() * 1000
367 );
368 }
369 } catch (IOException e) {
370 log.error(ExceptionUtils.getFullStackTrace(e));
371 e.printStackTrace();
372 }
373 break;
374 }
375 default: {
376 break;
377 }
378 }
379 }
380 }
381
382 class InternalHostListener implements HostListener {
383
384 @Override
385 public void event(HostEvent event) {
386 log.info("Host Event {}", event);
387 switch (event.type()) {
388 case HOST_ADDED:
389 case HOST_MOVED: {
390 RnibUe ue = ueMap.get(hostIdtoMME(event.subject().id()));
391 if (ue != null) {
slowr89c2ac12017-08-15 16:20:06 -0700392 ECGI ecgi_primary = linkMap.getPrimaryCell(ue).getEcgi();
slowr13fa5b02017-08-08 16:32:31 -0700393 RnibCell primary = cellMap.get(ecgi_primary);
394 ue.setMeasConfig(null);
395 if (primary != null) {
396 Timer timer = new Timer();
397 timer.scheduleAtFixedRate(
398 new TimerTask() {
399 @Override
400 public void run() {
slowred74ec72017-08-17 11:25:01 -0700401 if (ue.getCapability() == null && primary.getVersion() >= 3) {
slowr13fa5b02017-08-08 16:32:31 -0700402 try {
403 ChannelHandlerContext ctx = cellMap.getCtx(primary.getEcgi());
slowr8ddc2b12017-08-14 14:13:38 -0700404 XrancPdu xrancPdu = UECapabilityEnquiry.constructPacket(
slowr67d05e42017-08-11 20:37:22 -0700405 primary.getEcgi(),
406 ue.getRanId());
407 ctx.writeAndFlush(getSctpMessage(xrancPdu));
slowr13fa5b02017-08-08 16:32:31 -0700408 } catch (IOException e) {
409 log.warn(ExceptionUtils.getFullStackTrace(e));
410 e.printStackTrace();
411 }
412 } else {
slowr13fa5b02017-08-08 16:32:31 -0700413 timer.cancel();
414 timer.purge();
415 }
416 }
417 },
418 0,
419 xranConfig.getConfigRequestInterval() * 1000
420 );
slowred74ec72017-08-17 11:25:01 -0700421 if (ue.getMeasConfig() == null) {
422 try {
423 ChannelHandlerContext ctx = cellMap.getCtx(primary.getEcgi());
424 RXSigMeasConfig.MeasCells measCells = new RXSigMeasConfig.MeasCells();
425 xranStore.getCellNodes().forEach(cell -> {
426 CellConfigReport cellReport = ((RnibCell) cell).getConf();
427 if (cellReport != null) {
428 PCIARFCN pciarfcn = new PCIARFCN();
429 pciarfcn.setPci(cellReport.getPci());
430 pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
431 measCells.setPCIARFCN(pciarfcn);
432 }
433 });
434 XrancPdu xrancPdu = RXSigMeasConfig.constructPacket(
435 primary.getEcgi(),
436 ue.getRanId(),
437 measCells,
slowr5efb0ce2017-08-18 10:10:06 -0700438 xranConfig.getRxSignalInterval() * 1000
slowred74ec72017-08-17 11:25:01 -0700439 );
440 ue.setMeasConfig(xrancPdu.getBody().getRXSigMeasConfig());
441 ctx.writeAndFlush(getSctpMessage(xrancPdu));
442 } catch (IOException e) {
443 log.warn(ExceptionUtils.getFullStackTrace(e));
444 e.printStackTrace();
445 }
446 }
slowr13fa5b02017-08-08 16:32:31 -0700447 }
448 }
449 break;
450 }
451 default: {
452 break;
453 }
454 }
455 }
456 }
457
458 public class InternalXranDeviceAgent implements XranDeviceAgent {
459
460 private final Logger log = LoggerFactory.getLogger(InternalXranDeviceAgent.class);
461
462 @Override
463 public boolean addConnectedCell(String host, ChannelHandlerContext ctx) {
464 ECGI ecgi = legitCells.get(host);
465
466 if (ecgi == null) {
467 log.error("Device is not a legit source; ignoring...");
468 } else {
469 log.info("Device exists in configuration; registering...");
470 RnibCell storeCell = cellMap.get(ecgi);
471 if (storeCell == null) {
472 storeCell = new RnibCell();
473 storeCell.setEcgi(ecgi);
474 cellMap.put(storeCell, ctx);
475
476 for (XranDeviceListener l : xranDeviceListeners) {
477 l.deviceAdded(storeCell);
478 }
479 return true;
480 } else {
481 log.error("Device already registered; ignoring...");
482 }
483 }
484 ctx.close();
485 return false;
486 }
487
488 @Override
489 public boolean removeConnectedCell(String host) {
490 ECGI ecgi = legitCells.get(host);
491 List<RnibLink> linksByECGI = xranStore.getLinksByECGI(ecgi);
492
493 linksByECGI.forEach(rnibLink -> xranStore.removeLink(rnibLink.getLinkId()));
494
495 if (cellMap.remove(ecgi)) {
496 for (XranDeviceListener l : xranDeviceListeners) {
497 l.deviceRemoved(deviceId(uri(ecgi)));
498 }
499 return true;
500 }
501 return false;
502 }
503 }
504
505 public class InternalXranHostAgent implements XranHostAgent {
506
507 @Override
508 public boolean addConnectedHost(RnibUe ue, RnibCell cell, ChannelHandlerContext ctx) {
509
510 if (ueMap.get(ue.getMmeS1apId()) != null) {
511 linkMap.putPrimaryLink(cell, ue);
512
513 Set<ECGI> ecgiSet = xranStore.getLinksByUeId(ue.getMmeS1apId().longValue())
514 .stream()
slowr8ddc2b12017-08-14 14:13:38 -0700515 .map(l -> l.getLinkId().getEcgi())
slowr13fa5b02017-08-08 16:32:31 -0700516 .collect(Collectors.toSet());
517
518 for (XranHostListener l : xranHostListeners) {
519 l.hostAdded(ue, ecgiSet);
520 }
521 return true;
522 } else {
523 ueMap.put(ue);
524 linkMap.putPrimaryLink(cell, ue);
525
526 Set<ECGI> ecgiSet = Sets.newConcurrentHashSet();
527 ecgiSet.add(cell.getEcgi());
528 for (XranHostListener l : xranHostListeners) {
529 l.hostAdded(ue, ecgiSet);
530 }
531 return true;
532 }
533
534 }
535
536 @Override
537 public boolean removeConnectedHost(RnibUe ue) {
538 List<RnibLink> links = xranStore.getLinksByUeId(ue.getMmeS1apId().longValue());
539 links.forEach(rnibLink -> xranStore.removeLink(rnibLink.getLinkId()));
540 if (ueMap.remove(ue.getMmeS1apId())) {
541 for (XranHostListener l : xranHostListeners) {
542 l.hostRemoved(ue.getHostId());
543 }
544 return true;
545 }
546 return false;
547 }
548 }
549
550 public class InternalXranPacketAgent implements XranPacketProcessor {
551 @Override
552 public void handlePacket(XrancPdu recv_pdu, ChannelHandlerContext ctx) throws IOException {
553 XrancPdu send_pdu;
554
555 int apiID = recv_pdu.getHdr().getApiId().intValue();
556 log.debug("Received message: {}", recv_pdu);
557 switch (apiID) {
558 case 1: {
559 // Decode Cell config report.
560 CellConfigReport report = recv_pdu.getBody().getCellConfigReport();
561
562 ECGI ecgi = report.getEcgi();
563
564 RnibCell cell = xranStore.getCell(ecgi);
slowr8ddc2b12017-08-14 14:13:38 -0700565 cell.setVersion(recv_pdu.getHdr().getVer().toString());
slowr13fa5b02017-08-08 16:32:31 -0700566 cell.setConf(report);
slowr507a0822017-08-17 20:54:18 -0700567 cellMap.putPciArfcn(cell);
slowr13fa5b02017-08-08 16:32:31 -0700568 break;
569 }
570 case 2: {
571 // Decode UE Admission Request.
572 UEAdmissionRequest ueAdmissionRequest = recv_pdu.getBody().getUEAdmissionRequest();
573
574 ECGI ecgi = ueAdmissionRequest.getEcgi();
575 if (xranStore.getCell(ecgi) != null) {
576 CRNTI crnti = ueAdmissionRequest.getCrnti();
slowr8ddc2b12017-08-14 14:13:38 -0700577 send_pdu = UEAdmissionResponse.constructPacket(ecgi, crnti, xranConfig.admissionFlag());
slowr67d05e42017-08-11 20:37:22 -0700578 ctx.writeAndFlush(getSctpMessage(send_pdu));
slowr13fa5b02017-08-08 16:32:31 -0700579 } else {
580 log.warn("Could not find ECGI in registered cells: {}", ecgi);
581 }
582 break;
583 }
584 case 4: {
585 // Decode UE Admission Status.
586 UEAdmissionStatus ueAdmissionStatus = recv_pdu.getBody().getUEAdmissionStatus();
587
588 RnibUe ue = ueMap.get(ueAdmissionStatus.getCrnti());
589 if (ue != null) {
590 if (ueAdmissionStatus.getAdmEstStatus().value.intValue() == 0) {
slowr67d05e42017-08-11 20:37:22 -0700591 ue.setState(RnibUe.State.ACTIVE);
slowr13fa5b02017-08-08 16:32:31 -0700592 } else {
slowr67d05e42017-08-11 20:37:22 -0700593 ue.setState(RnibUe.State.IDLE);
slowr13fa5b02017-08-08 16:32:31 -0700594 }
595 }
596 break;
597 }
598 case 5: {
599 // Decode UE Admission Context Update.
slowr8ddc2b12017-08-14 14:13:38 -0700600 UEContextUpdate ueContextUpdate = recv_pdu.getBody().getUEContextUpdate();
slowr13fa5b02017-08-08 16:32:31 -0700601
slowr8ddc2b12017-08-14 14:13:38 -0700602 RnibUe ue = ueMap.get(ueContextUpdate.getMMEUES1APID());
slowr73b4eae2017-08-17 16:09:09 -0700603 RnibCell cell = xranStore.getCell(ueContextUpdate.getEcgi());
604 if (ue == null) {
605 ue = new RnibUe();
slowr13fa5b02017-08-08 16:32:31 -0700606 }
slowr73b4eae2017-08-17 16:09:09 -0700607
608 ue.setMmeS1apId(ueContextUpdate.getMMEUES1APID());
609 ue.setEnbS1apId(ueContextUpdate.getENBUES1APID());
610 ue.setRanId(ueContextUpdate.getCrnti());
611
612 hostAgent.addConnectedHost(ue, cell, ctx);
613
slowr13fa5b02017-08-08 16:32:31 -0700614 break;
615 }
616 case 6: {
617 // Decode UE Reconfig_Ind.
618 UEReconfigInd ueReconfigInd = recv_pdu.getBody().getUEReconfigInd();
619 RnibUe ue = ueMap.get(ueReconfigInd.getCrntiOld());
620
621 if (ue != null) {
622 ue.setRanId(ueReconfigInd.getCrntiNew());
623 } else {
624 log.warn("Could not find UE with this CRNTI: {}", ueReconfigInd.getCrntiOld());
625 }
626 break;
627 }
628 case 7: {
629 // If xRANc wants to deactivate UE, we pass UEReleaseInd from xRANc to eNB.
630 // Decode UE Release_Ind.
631 UEReleaseInd ueReleaseInd = recv_pdu.getBody().getUEReleaseInd();
632 RnibUe ue = ueMap.get(ueReleaseInd.getCrnti());
633 if (ue != null) {
slowr67d05e42017-08-11 20:37:22 -0700634 ue.setState(RnibUe.State.IDLE);
slowr13fa5b02017-08-08 16:32:31 -0700635 restartTimer(ue);
636 }
637 break;
638 }
639 case 8: {
640 // Decode Bearer Adm Request
641 BearerAdmissionRequest bearerAdmissionRequest = recv_pdu.getBody().getBearerAdmissionRequest();
642
643 ECGI ecgi = bearerAdmissionRequest.getEcgi();
644 CRNTI crnti = bearerAdmissionRequest.getCrnti();
645 ERABParams erabParams = bearerAdmissionRequest.getErabParams();
646 RnibLink link = linkMap.get(ecgi, crnti);
647 if (link != null) {
648 link.setBearerParameters(erabParams);
649 } else {
650 log.warn("Could not find link between {}-{}", ecgi, crnti);
651 }
652
653 BerInteger numErabs = bearerAdmissionRequest.getNumErabs();
slowr8ddc2b12017-08-14 14:13:38 -0700654 // Encode and send Bearer Admission Response
655 send_pdu = BearerAdmissionResponse.constructPacket(ecgi, crnti, erabParams, numErabs, xranConfig.bearerFlag());
slowr67d05e42017-08-11 20:37:22 -0700656 ctx.writeAndFlush(getSctpMessage(send_pdu));
slowr13fa5b02017-08-08 16:32:31 -0700657 break;
658 }
659 case 10: {
660 //Decode Bearer Admission Status
661 BearerAdmissionStatus bearerAdmissionStatus = recv_pdu.getBody().getBearerAdmissionStatus();
slowr8ddc2b12017-08-14 14:13:38 -0700662 break;
slowr13fa5b02017-08-08 16:32:31 -0700663// ECGI ecgi = bearerAdmissionStatus.getEcgi();
664// CRNTI crnti = bearerAdmissionStatus.getCrnti();
665//
666// RnibLink link = linkMap.get(ecgi, crnti);
slowr13fa5b02017-08-08 16:32:31 -0700667 }
668 case 11: {
669 //Decode Bearer Release Ind
670 BearerReleaseInd bearerReleaseInd = recv_pdu.getBody().getBearerReleaseInd();
671
672 ECGI ecgi = bearerReleaseInd.getEcgi();
673 CRNTI crnti = bearerReleaseInd.getCrnti();
674 RnibLink link = linkMap.get(ecgi, crnti);
675
676 List<ERABID> erabidsRelease = bearerReleaseInd.getErabIds().getERABID();
677 List<ERABParamsItem> erabParamsItem = link.getBearerParameters().getERABParamsItem();
678
679 List<ERABParamsItem> unreleased = erabParamsItem
680 .stream()
681 .filter(item -> {
682 Optional<ERABID> any = erabidsRelease.stream().filter(id -> id.equals(item.getId())).findAny();
683 return !any.isPresent();
684 }).collect(Collectors.toList());
685
686 link.getBearerParameters().setERABParamsItem(new ArrayList<>(unreleased));
slowr13fa5b02017-08-08 16:32:31 -0700687 break;
688 }
689 case 13: {
slowr67d05e42017-08-11 20:37:22 -0700690 HOFailure hoFailure = recv_pdu.getBody().getHOFailure();
691
692 try {
slowr73b4eae2017-08-17 16:09:09 -0700693 hoQueue.get(hoFailure.getEcgi())
slowr67d05e42017-08-11 20:37:22 -0700694 .put("Hand Over Failed with cause: " + hoFailure.getCause());
695 } catch (InterruptedException e) {
696 log.error(ExceptionUtils.getFullStackTrace(e));
697 e.printStackTrace();
698 } finally {
slowr73b4eae2017-08-17 16:09:09 -0700699 hoQueue.remove(hoFailure.getEcgi());
slowr67d05e42017-08-11 20:37:22 -0700700 }
701 break;
slowr8ddc2b12017-08-14 14:13:38 -0700702
slowr67d05e42017-08-11 20:37:22 -0700703 }
slowr8ddc2b12017-08-14 14:13:38 -0700704 case 14: {
slowr67d05e42017-08-11 20:37:22 -0700705 HOComplete hoComplete = recv_pdu.getBody().getHOComplete();
706
slowr67d05e42017-08-11 20:37:22 -0700707 try {
slowr73b4eae2017-08-17 16:09:09 -0700708 hoQueue.get(hoComplete.getEcgiS())
slowr67d05e42017-08-11 20:37:22 -0700709 .put("Hand Over Completed");
710 } catch (InterruptedException e) {
711 log.error(ExceptionUtils.getFullStackTrace(e));
712 e.printStackTrace();
713 } finally {
slowr73b4eae2017-08-17 16:09:09 -0700714 hoQueue.remove(hoComplete.getEcgiS());
slowr67d05e42017-08-11 20:37:22 -0700715 }
716 break;
717 }
slowr8ddc2b12017-08-14 14:13:38 -0700718
719 case 16: {
slowr13fa5b02017-08-08 16:32:31 -0700720 // Decode RX Sig Meas Report.
721 RXSigMeasReport rxSigMeasReport = recv_pdu.getBody().getRXSigMeasReport();
722 List<RXSigReport> rxSigReportList = rxSigMeasReport.getCellMeasReports().getRXSigReport();
723
724 if (!rxSigReportList.isEmpty()) {
725 rxSigReportList.forEach(rxSigReport -> {
726 RnibCell cell = cellMap.get(rxSigReport.getPciArfcn());
727 if (cell != null) {
728 ECGI ecgi = cell.getEcgi();
729 RnibLink link = linkMap.get(ecgi, rxSigMeasReport.getCrnti());
730 if (link == null) {
731 log.warn("Could not find link between: {}-{} | Creating non-serving link..", ecgi, rxSigMeasReport.getCrnti());
732 link = linkMap.putNonServingLink(cell, rxSigMeasReport.getCrnti());
slowr13fa5b02017-08-08 16:32:31 -0700733 }
734
735 if (link != null) {
slowrda15d9a2017-08-18 10:33:31 -0700736 if (link.getType().equals(RnibLink.Type.NON_SERVING)) {
737 restartTimer(link);
738 }
739
slowr13fa5b02017-08-08 16:32:31 -0700740 RSRQRange rsrq = rxSigReport.getRsrq();
741 RSRPRange rsrp = rxSigReport.getRsrp();
742
743 RnibLink.LinkQuality quality = link.getQuality();
slowrc153ad92017-08-16 19:47:52 -0700744 quality.setRX(new RnibLink.LinkQuality.RX(
745 rsrp.value.intValue() - 140,
746 (rsrq.value.intValue() * 0.5) - 19.5
747 ));
slowr13fa5b02017-08-08 16:32:31 -0700748 }
749 } else {
slowr507a0822017-08-17 20:54:18 -0700750 log.warn("case 16: Could not find cell with PCI-ARFCN: {}", rxSigReport.getPciArfcn());
slowr13fa5b02017-08-08 16:32:31 -0700751 }
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();
slowr13fa5b02017-08-08 16:32:31 -0700768
769 final double[] values = {0, 0, 0};
slowrd3d7b412017-08-17 11:15:44 -0700770 final int[] i = {1};
slowr13fa5b02017-08-08 16:32:31 -0700771 cqiHist.getBerInteger().forEach(value -> {
772 values[0] = Math.max(values[0], value.intValue());
slowrd3d7b412017-08-17 11:15:44 -0700773 values[1] += i[0] * value.intValue();
slowr13fa5b02017-08-08 16:32:31 -0700774 values[2] += value.intValue();
slowrd3d7b412017-08-17 11:15:44 -0700775 i[0]++;
slowr13fa5b02017-08-08 16:32:31 -0700776 });
777
slowrc153ad92017-08-16 19:47:52 -0700778 quality.setCQI(new RnibLink.LinkQuality.CQI(
779 cqiHist,
780 values[0],
781 values[1] / values[0]
782 ));
slowr13fa5b02017-08-08 16:32:31 -0700783
784 } else {
785 log.warn("Could not find link between: {}-{}", cell.getEcgi(), radioMeasReportPerUE.getCrnti());
786 }
787 } else {
slowr507a0822017-08-17 20:54:18 -0700788 log.warn("case 18: Could not find cell with PCI-ARFCN: {}", servCell.getPciArfcn());
slowr13fa5b02017-08-08 16:32:31 -0700789 }
790 });
slowr67d05e42017-08-11 20:37:22 -0700791 break;
slowr13fa5b02017-08-08 16:32:31 -0700792 }
slowr8ddc2b12017-08-14 14:13:38 -0700793 case 19: {
slowr13fa5b02017-08-08 16:32:31 -0700794 RadioMeasReportPerCell radioMeasReportPerCell = recv_pdu.getBody().getRadioMeasReportPerCell();
795 break;
796 }
slowr8ddc2b12017-08-14 14:13:38 -0700797 case 20: {
slowr13fa5b02017-08-08 16:32:31 -0700798 SchedMeasReportPerUE schedMeasReportPerUE = recv_pdu.getBody().getSchedMeasReportPerUE();
slowr8ddc2b12017-08-14 14:13:38 -0700799 List<SchedMeasRepPerServCell> servCells = schedMeasReportPerUE.getSchedReportServCells()
800 .getSchedMeasRepPerServCell();
slowr13fa5b02017-08-08 16:32:31 -0700801
802 servCells.forEach(servCell -> {
803 RnibCell cell = cellMap.get(servCell.getPciArfcn());
804 if (cell != null) {
805 RnibLink link = linkMap.get(cell.getEcgi(), schedMeasReportPerUE.getCrnti());
806 if (link != null) {
slowrc153ad92017-08-16 19:47:52 -0700807 link.getQuality().setMCS(new RnibLink.LinkQuality.MCS(
808 servCell.getMcsDl(),
809 servCell.getMcsUl()
810 ));
slowr13fa5b02017-08-08 16:32:31 -0700811
slowrc153ad92017-08-16 19:47:52 -0700812 link.setResourceUsage(new RnibLink.ResourceUsage(
813 servCell.getPrbUsage().getPrbUsageDl(),
814 servCell.getPrbUsage().getPrbUsageUl()
815 ));
slowr13fa5b02017-08-08 16:32:31 -0700816 } else {
slowr8ddc2b12017-08-14 14:13:38 -0700817 log.warn("Could not find link between: {}-{}", cell.getEcgi(),
818 schedMeasReportPerUE.getCrnti());
slowr13fa5b02017-08-08 16:32:31 -0700819 }
820 } else {
slowr507a0822017-08-17 20:54:18 -0700821 log.warn("case 20: Could not find cell with PCI-ARFCN: {}", servCell.getPciArfcn());
slowr13fa5b02017-08-08 16:32:31 -0700822 }
823 });
824 break;
825 }
slowr8ddc2b12017-08-14 14:13:38 -0700826 case 21: {
slowr13fa5b02017-08-08 16:32:31 -0700827 SchedMeasReportPerCell schedMeasReportPerCell = recv_pdu.getBody().getSchedMeasReportPerCell();
slowr13fa5b02017-08-08 16:32:31 -0700828 RnibCell cell = cellMap.get(schedMeasReportPerCell.getEcgi());
829 if (cell != null) {
slowrc153ad92017-08-16 19:47:52 -0700830 cell.setPrbUsage(new RnibCell.PrbUsageContainer(
831 schedMeasReportPerCell.getPrbUsagePcell(),
832 schedMeasReportPerCell.getPrbUsageScell()
833 ));
834
slowr13fa5b02017-08-08 16:32:31 -0700835 cell.setQci(schedMeasReportPerCell.getQciVals());
836 } else {
837 log.warn("Could not find cell with ECGI: {}", schedMeasReportPerCell.getEcgi());
838 }
839 break;
840 }
slowr8ddc2b12017-08-14 14:13:38 -0700841 case 22: {
slowr13fa5b02017-08-08 16:32:31 -0700842 PDCPMeasReportPerUe pdcpMeasReportPerUe = recv_pdu.getBody().getPDCPMeasReportPerUe();
843
844 RnibLink link = linkMap.get(pdcpMeasReportPerUe.getEcgi(), pdcpMeasReportPerUe.getCrnti());
845 if (link != null) {
slowrc153ad92017-08-16 19:47:52 -0700846 link.setPdcpThroughput(new RnibLink.PDCPThroughput(
847 pdcpMeasReportPerUe.getThroughputDl(),
848 pdcpMeasReportPerUe.getThroughputUl()
849 ));
850
851 link.setPdcpPackDelay(new RnibLink.PDCPPacketDelay(
852 pdcpMeasReportPerUe.getPktDelayDl(),
853 pdcpMeasReportPerUe.getPktDelayUl()
854 ));
slowr13fa5b02017-08-08 16:32:31 -0700855 } else {
slowr8ddc2b12017-08-14 14:13:38 -0700856 log.warn("Could not find link between: {}-{}", pdcpMeasReportPerUe.getEcgi(),
857 pdcpMeasReportPerUe.getCrnti());
slowr13fa5b02017-08-08 16:32:31 -0700858 }
859 break;
860 }
slowr8ddc2b12017-08-14 14:13:38 -0700861 case 24: {
862 // Decode UE Capability Info
863 UECapabilityInfo capabilityInfo = recv_pdu.getBody().getUECapabilityInfo();
864
865 RnibUe ue = ueMap.get(capabilityInfo.getCrnti());
866 if (ue != null) {
867 ue.setCapability(capabilityInfo);
868 } else {
869 log.warn("Could not find UE with this CRNTI: {}", capabilityInfo.getCrnti());
870 }
871 break;
872 }
873 case 25: {
874 // Don't know what will invoke sending UE CAPABILITY ENQUIRY
875 // Encode and send UE CAPABILITY ENQUIRY
876 UECapabilityEnquiry ueCapabilityEnquiry = recv_pdu.getBody().getUECapabilityEnquiry();
877 XrancPdu xrancPdu = UECapabilityEnquiry.constructPacket(ueCapabilityEnquiry.getEcgi(), ueCapabilityEnquiry.getCrnti());
878 ctx.writeAndFlush(getSctpMessage(xrancPdu));
879 break;
880 }
slowr89c2ac12017-08-15 16:20:06 -0700881 case 27: {
882 //Decode ScellAddStatus
883 ScellAddStatus scellAddStatus = recv_pdu.getBody().getScellAddStatus();
884 try {
885 scellAddQueue.get(scellAddStatus.getCrnti()).put("Scell's status: " + scellAddStatus.getStatus());
886 if (scellAddStatus.getStatus().getBerEnum().get(0).value.intValue() == 0) {
887
888 scellAddStatus.getScellsInd().getPCIARFCN().forEach(
889 pciarfcn -> {
890 RnibCell cell = cellMap.get(pciarfcn);
891 RnibLink link = linkMap.get(cell.getEcgi(), scellAddStatus.getCrnti());
892 link.setType(RnibLink.Type.SERVING_SECONDARY_CA);
893 }
894 );
895 } else {
896 log.error("Scell addition failed.");
897 }
898 } catch (InterruptedException e) {
899 log.error(ExceptionUtils.getFullStackTrace(e));
900 e.printStackTrace();
901 } finally {
902 scellAddQueue.remove(scellAddStatus.getCrnti());
903 }
904 break;
905 }
906 // TODO: 28: ScellDelete
slowr8ddc2b12017-08-14 14:13:38 -0700907
908 case 30: {
909 // Decode RRMConfig Status
slowr67d05e42017-08-11 20:37:22 -0700910 RRMConfigStatus rrmConfigStatus = recv_pdu.getBody().getRRMConfigStatus();
911 try {
912 RRMCellQueue.get(rrmConfigStatus.getEcgi())
913 .put("RRM Config's status: " + rrmConfigStatus.getStatus());
914 } catch (InterruptedException e) {
915 log.error(ExceptionUtils.getFullStackTrace(e));
916 e.printStackTrace();
917 } finally {
918 RRMCellQueue.remove(rrmConfigStatus.getEcgi());
919 }
920 break;
921 }
slowr8ddc2b12017-08-14 14:13:38 -0700922 //TODO Case 31: SeNBAdd 32: SeNBAddStatus 33: SeNBDelete
slowr13fa5b02017-08-08 16:32:31 -0700923 case 34: {
924 TrafficSplitConfig trafficSplitConfig = recv_pdu.getBody().getTrafficSplitConfig();
925
926 List<TrafficSplitPercentage> splitPercentages = trafficSplitConfig.getTrafficSplitPercent().getTrafficSplitPercentage();
927
928 splitPercentages.forEach(trafficSplitPercentage -> {
929 RnibCell cell = cellMap.get(trafficSplitPercentage.getEcgi());
930 if (cell != null) {
931 RnibLink link = linkMap.get(cell.getEcgi(), trafficSplitConfig.getCrnti());
932 if (link != null) {
933 link.setTrafficPercent(trafficSplitPercentage);
934 } else {
935 log.warn("Could not find link between: {}-{}", cell.getEcgi(), trafficSplitConfig.getCrnti());
936 }
937 } else {
938 log.warn("Could not find cell with ECGI: {}", trafficSplitConfig.getEcgi());
939 }
940 });
slowr67d05e42017-08-11 20:37:22 -0700941 break;
slowr13fa5b02017-08-08 16:32:31 -0700942 }
943 default: {
slowr60d4d102017-08-16 18:33:58 -0700944 log.warn("Wrong API ID: {}", recv_pdu);
slowr67d05e42017-08-11 20:37:22 -0700945 break;
slowr13fa5b02017-08-08 16:32:31 -0700946 }
947 }
948
949 }
950 }
951
952 class InternalNetworkConfigListener implements NetworkConfigListener {
953
954 @Override
955 public void event(NetworkConfigEvent event) {
956 switch (event.type()) {
957 case CONFIG_REGISTERED:
958 break;
959 case CONFIG_UNREGISTERED:
960 break;
961 case CONFIG_ADDED:
962 case CONFIG_UPDATED:
963 if (event.configClass() == CONFIG_CLASS) {
964 handleConfigEvent(event.config());
965 }
966 break;
967 case CONFIG_REMOVED:
968 break;
969 default:
970 break;
971 }
972 }
973
974 private void handleConfigEvent(Optional<Config> config) {
975 if (!config.isPresent()) {
976 return;
977 }
978
979 xranConfig = (XranConfig) config.get();
980
981 legitCells.putAll(xranConfig.activeCellSet());
982
983 controller.start(deviceAgent, hostAgent, packetAgent, xranConfig.getXrancPort());
984 }
985 }
986}