blob: 8f374e6fe8a6a73c259e34f5f094123d96fca695 [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<>();
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
slowr73b4eae2017-08-17 16:09:09 -0700158 public SynchronousQueue<String> sendHORequest(RnibLink link_t, RnibLink link_s) {
159 ECGI ecgi_t = link_t.getLinkId().getEcgi(),
160 ecgi_s = link_s.getLinkId().getEcgi();
161
162 CRNTI crnti = linkMap.getCrnti(link_t.getLinkId().getMmeues1apid());
163 ChannelHandlerContext ctx_t = cellMap.getCtx(ecgi_t),
164 ctx_s = cellMap.getCtx(ecgi_s);
slowr67d05e42017-08-11 20:37:22 -0700165
166 try {
slowr73b4eae2017-08-17 16:09:09 -0700167 XrancPdu xrancPdu = HORequest.constructPacket(crnti, ecgi_s, ecgi_t);
168 ctx_t.writeAndFlush(getSctpMessage(xrancPdu));
169 ctx_s.writeAndFlush(getSctpMessage(xrancPdu));
slowr67d05e42017-08-11 20:37:22 -0700170 } catch (IOException e) {
171 e.printStackTrace();
172 }
173
174 SynchronousQueue<String> queue = new SynchronousQueue<>();
slowr73b4eae2017-08-17 16:09:09 -0700175 hoQueue.put(ecgi_s, queue);
slowr67d05e42017-08-11 20:37:22 -0700176
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 {
slowr73b4eae2017-08-17 16:09:09 -0700205 XrancPdu pdu = null;
206
slowr8ddc2b12017-08-14 14:13:38 -0700207 if (xICIC) {
slowr73b4eae2017-08-17 16:09:09 -0700208 CellConfigReport cellConfigReport = cellMap.get(ecgi).getConf();
209 if (cellConfigReport != null) {
210 pdu = XICICConfig.constructPacket(rrmConfig, cellConfigReport);
211 ctx.writeAndFlush(getSctpMessage(pdu));
212 }
slowr8ddc2b12017-08-14 14:13:38 -0700213 } else {
214 pdu = RRMConfig.constructPacket(rrmConfig);
slowr73b4eae2017-08-17 16:09:09 -0700215 ctx.writeAndFlush(getSctpMessage(pdu));
216 SynchronousQueue<String> queue = new SynchronousQueue<>();
217 RRMCellQueue.put(ecgi, queue);
218 return queue;
slowr8ddc2b12017-08-14 14:13:38 -0700219 }
slowr67d05e42017-08-11 20:37:22 -0700220 } catch (IOException e) {
221 e.printStackTrace();
222 }
slowr67d05e42017-08-11 20:37:22 -0700223
slowr73b4eae2017-08-17 16:09:09 -0700224 return null;
slowr67d05e42017-08-11 20:37:22 -0700225 }
226
slowr89c2ac12017-08-15 16:20:06 -0700227 @Override
228 public SynchronousQueue<String> sendScellAdd(RnibLink link) {
229 RnibCell secondaryCell = link.getLinkId().getCell(),
230 primaryCell = linkMap.getPrimaryCell(link.getLinkId().getUe());
231 ECGI primaryEcgi = primaryCell.getEcgi();
232 ChannelHandlerContext ctx = cellMap.getCtx(primaryEcgi);
233
234 CRNTI crnti = linkMap.getCrnti(link.getLinkId().getMmeues1apid());
235
236 CellConfigReport cellReport = secondaryCell.getConf();
237
238 if (cellReport != null) {
239 PCIARFCN pciarfcn = new PCIARFCN();
240 pciarfcn.setPci(cellReport.getPci());
241 pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
242
243 PropScell propScell = new PropScell();
244 propScell.setPciArfcn(pciarfcn);
245
246 XrancPdu pdu = ScellAdd.constructPacket(primaryEcgi, crnti, propScell);
247 try {
248 ctx.writeAndFlush(getSctpMessage(pdu));
249 SynchronousQueue<String> queue = new SynchronousQueue<>();
250 scellAddQueue.put(crnti, queue);
251
252 return queue;
253 } catch (IOException e) {
254 log.error(ExceptionUtils.getFullStackTrace(e));
255 e.printStackTrace();
256 }
257 }
258 return null;
259 }
260
261 @Override
262 public boolean sendScellDelete(RnibLink link) {
263 RnibCell secondaryCell = link.getLinkId().getCell(),
264 primaryCell = linkMap.getPrimaryCell(link.getLinkId().getUe());
265 ECGI primaryEcgi = primaryCell.getEcgi();
266 ChannelHandlerContext ctx = cellMap.getCtx(primaryEcgi);
267
268 CRNTI crnti = linkMap.getCrnti(link.getLinkId().getMmeues1apid());
269
270 CellConfigReport cellReport = secondaryCell.getConf();
271
272 if (cellReport != null) {
273 PCIARFCN pciarfcn = new PCIARFCN();
274 pciarfcn.setPci(cellReport.getPci());
275 pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
276
277 XrancPdu pdu = ScellDelete.constructPacket(primaryEcgi, crnti, pciarfcn);
278
279 try {
280 ctx.writeAndFlush(getSctpMessage(pdu));
281 link.setType(RnibLink.Type.NON_SERVING);
282 return true;
283 } catch (IOException e) {
284 log.error(ExceptionUtils.getFullStackTrace(e));
285 e.printStackTrace();
286 }
287 }
288 return false;
289 }
290
slowr13fa5b02017-08-08 16:32:31 -0700291 private void restartTimer(RnibUe ue) {
292 Timer timer = new Timer();
293 ue.setTimer(timer);
294 log.info("Starting UE timer...");
295 timer.schedule(new TimerTask() {
296 @Override
297 public void run() {
slowr67d05e42017-08-11 20:37:22 -0700298 if (ue.getState() == RnibUe.State.IDLE) {
slowr13fa5b02017-08-08 16:32:31 -0700299 hostAgent.removeConnectedHost(ue);
300 log.info("UE is removed after 10 seconds of IDLE");
301 } else {
302 log.info("UE not removed cause its ACTIVE");
303 }
304 }
305 }, 10000);
306 }
307
308 private void restartTimer(RnibLink link) {
309 Timer timer = new Timer();
310 link.setTimer(timer);
311 log.info("Starting Link timer...");
312 timer.schedule(new TimerTask() {
313 @Override
314 public void run() {
315 LinkId linkId = link.getLinkId();
316 xranStore.removeLink(linkId);
317 log.info("Link is removed after not receiving Meas Reports for 10 seconds");
318 }
319 }, 10000);
320
321 }
322
323 class InternalDeviceListener implements DeviceListener {
324
325 @Override
326 public void event(DeviceEvent event) {
327 log.info("Device Event {}", event);
328 switch (event.type()) {
329 case DEVICE_ADDED: {
330 try {
331 ECGI ecgi = decodeDeviceId(event.subject().id());
332 RnibCell cell = cellMap.get(ecgi);
333 if (cell != null) {
334 Timer timer = new Timer();
335 timer.scheduleAtFixedRate(
336 new TimerTask() {
337 @Override
338 public void run() {
339 CellConfigReport conf = cell.getConf();
340 if (conf == null) {
341 try {
342 ChannelHandlerContext ctx = cellMap.getCtx(ecgi);
slowr8ddc2b12017-08-14 14:13:38 -0700343 XrancPdu xrancPdu = CellConfigRequest.constructPacket(ecgi);
slowr67d05e42017-08-11 20:37:22 -0700344 ctx.writeAndFlush(getSctpMessage(xrancPdu));
slowr13fa5b02017-08-08 16:32:31 -0700345 } catch (IOException e) {
346 log.error(ExceptionUtils.getFullStackTrace(e));
347 e.printStackTrace();
348 }
349 } else {
slowr13fa5b02017-08-08 16:32:31 -0700350 try {
351 ChannelHandlerContext ctx = cellMap.
352 getCtx(ecgi);
slowr8ddc2b12017-08-14 14:13:38 -0700353 XrancPdu xrancPdu = L2MeasConfig.constructPacket(ecgi, xranConfig.getL2MeasInterval());
slowr13fa5b02017-08-08 16:32:31 -0700354 cell.setMeasConfig(xrancPdu.getBody().getL2MeasConfig());
slowr67d05e42017-08-11 20:37:22 -0700355 SctpMessage sctpMessage = getSctpMessage(xrancPdu);
slowr13fa5b02017-08-08 16:32:31 -0700356 ctx.writeAndFlush(sctpMessage);
357 } catch (IOException e) {
358 log.error(ExceptionUtils.getFullStackTrace(e));
359 e.printStackTrace();
360 }
361 timer.cancel();
362 timer.purge();
363 }
364 }
365 },
366 0,
367 xranConfig.getConfigRequestInterval() * 1000
368 );
369 }
370 } catch (IOException e) {
371 log.error(ExceptionUtils.getFullStackTrace(e));
372 e.printStackTrace();
373 }
374 break;
375 }
376 default: {
377 break;
378 }
379 }
380 }
381 }
382
383 class InternalHostListener implements HostListener {
384
385 @Override
386 public void event(HostEvent event) {
387 log.info("Host Event {}", event);
388 switch (event.type()) {
389 case HOST_ADDED:
390 case HOST_MOVED: {
391 RnibUe ue = ueMap.get(hostIdtoMME(event.subject().id()));
392 if (ue != null) {
slowr89c2ac12017-08-15 16:20:06 -0700393 ECGI ecgi_primary = linkMap.getPrimaryCell(ue).getEcgi();
slowr13fa5b02017-08-08 16:32:31 -0700394 RnibCell primary = cellMap.get(ecgi_primary);
395 ue.setMeasConfig(null);
396 if (primary != null) {
397 Timer timer = new Timer();
398 timer.scheduleAtFixedRate(
399 new TimerTask() {
400 @Override
401 public void run() {
slowred74ec72017-08-17 11:25:01 -0700402 if (ue.getCapability() == null && primary.getVersion() >= 3) {
slowr13fa5b02017-08-08 16:32:31 -0700403 try {
404 ChannelHandlerContext ctx = cellMap.getCtx(primary.getEcgi());
slowr8ddc2b12017-08-14 14:13:38 -0700405 XrancPdu xrancPdu = UECapabilityEnquiry.constructPacket(
slowr67d05e42017-08-11 20:37:22 -0700406 primary.getEcgi(),
407 ue.getRanId());
408 ctx.writeAndFlush(getSctpMessage(xrancPdu));
slowr13fa5b02017-08-08 16:32:31 -0700409 } catch (IOException e) {
410 log.warn(ExceptionUtils.getFullStackTrace(e));
411 e.printStackTrace();
412 }
413 } else {
slowr13fa5b02017-08-08 16:32:31 -0700414 timer.cancel();
415 timer.purge();
416 }
417 }
418 },
419 0,
420 xranConfig.getConfigRequestInterval() * 1000
421 );
slowred74ec72017-08-17 11:25:01 -0700422 if (ue.getMeasConfig() == null) {
423 try {
424 ChannelHandlerContext ctx = cellMap.getCtx(primary.getEcgi());
425 RXSigMeasConfig.MeasCells measCells = new RXSigMeasConfig.MeasCells();
426 xranStore.getCellNodes().forEach(cell -> {
427 CellConfigReport cellReport = ((RnibCell) cell).getConf();
428 if (cellReport != null) {
429 PCIARFCN pciarfcn = new PCIARFCN();
430 pciarfcn.setPci(cellReport.getPci());
431 pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
432 measCells.setPCIARFCN(pciarfcn);
433 }
434 });
435 XrancPdu xrancPdu = RXSigMeasConfig.constructPacket(
436 primary.getEcgi(),
437 ue.getRanId(),
438 measCells,
slowr5efb0ce2017-08-18 10:10:06 -0700439 xranConfig.getRxSignalInterval() * 1000
slowred74ec72017-08-17 11:25:01 -0700440 );
441 ue.setMeasConfig(xrancPdu.getBody().getRXSigMeasConfig());
442 ctx.writeAndFlush(getSctpMessage(xrancPdu));
443 } catch (IOException e) {
444 log.warn(ExceptionUtils.getFullStackTrace(e));
445 e.printStackTrace();
446 }
447 }
slowr13fa5b02017-08-08 16:32:31 -0700448 }
449 }
450 break;
451 }
452 default: {
453 break;
454 }
455 }
456 }
457 }
458
459 public class InternalXranDeviceAgent implements XranDeviceAgent {
460
461 private final Logger log = LoggerFactory.getLogger(InternalXranDeviceAgent.class);
462
463 @Override
464 public boolean addConnectedCell(String host, ChannelHandlerContext ctx) {
465 ECGI ecgi = legitCells.get(host);
466
467 if (ecgi == null) {
468 log.error("Device is not a legit source; ignoring...");
469 } else {
470 log.info("Device exists in configuration; registering...");
471 RnibCell storeCell = cellMap.get(ecgi);
472 if (storeCell == null) {
473 storeCell = new RnibCell();
474 storeCell.setEcgi(ecgi);
475 cellMap.put(storeCell, ctx);
476
477 for (XranDeviceListener l : xranDeviceListeners) {
478 l.deviceAdded(storeCell);
479 }
480 return true;
481 } else {
482 log.error("Device already registered; ignoring...");
483 }
484 }
485 ctx.close();
486 return false;
487 }
488
489 @Override
490 public boolean removeConnectedCell(String host) {
491 ECGI ecgi = legitCells.get(host);
492 List<RnibLink> linksByECGI = xranStore.getLinksByECGI(ecgi);
493
494 linksByECGI.forEach(rnibLink -> xranStore.removeLink(rnibLink.getLinkId()));
495
496 if (cellMap.remove(ecgi)) {
497 for (XranDeviceListener l : xranDeviceListeners) {
498 l.deviceRemoved(deviceId(uri(ecgi)));
499 }
500 return true;
501 }
502 return false;
503 }
504 }
505
506 public class InternalXranHostAgent implements XranHostAgent {
507
508 @Override
509 public boolean addConnectedHost(RnibUe ue, RnibCell cell, ChannelHandlerContext ctx) {
510
511 if (ueMap.get(ue.getMmeS1apId()) != null) {
512 linkMap.putPrimaryLink(cell, ue);
513
514 Set<ECGI> ecgiSet = xranStore.getLinksByUeId(ue.getMmeS1apId().longValue())
515 .stream()
slowr8ddc2b12017-08-14 14:13:38 -0700516 .map(l -> l.getLinkId().getEcgi())
slowr13fa5b02017-08-08 16:32:31 -0700517 .collect(Collectors.toSet());
518
519 for (XranHostListener l : xranHostListeners) {
520 l.hostAdded(ue, ecgiSet);
521 }
522 return true;
523 } else {
524 ueMap.put(ue);
525 linkMap.putPrimaryLink(cell, ue);
526
527 Set<ECGI> ecgiSet = Sets.newConcurrentHashSet();
528 ecgiSet.add(cell.getEcgi());
529 for (XranHostListener l : xranHostListeners) {
530 l.hostAdded(ue, ecgiSet);
531 }
532 return true;
533 }
534
535 }
536
537 @Override
538 public boolean removeConnectedHost(RnibUe ue) {
539 List<RnibLink> links = xranStore.getLinksByUeId(ue.getMmeS1apId().longValue());
540 links.forEach(rnibLink -> xranStore.removeLink(rnibLink.getLinkId()));
541 if (ueMap.remove(ue.getMmeS1apId())) {
542 for (XranHostListener l : xranHostListeners) {
543 l.hostRemoved(ue.getHostId());
544 }
545 return true;
546 }
547 return false;
548 }
549 }
550
551 public class InternalXranPacketAgent implements XranPacketProcessor {
552 @Override
553 public void handlePacket(XrancPdu recv_pdu, ChannelHandlerContext ctx) throws IOException {
554 XrancPdu send_pdu;
555
556 int apiID = recv_pdu.getHdr().getApiId().intValue();
557 log.debug("Received message: {}", recv_pdu);
558 switch (apiID) {
559 case 1: {
560 // Decode Cell config report.
561 CellConfigReport report = recv_pdu.getBody().getCellConfigReport();
562
563 ECGI ecgi = report.getEcgi();
564
565 RnibCell cell = xranStore.getCell(ecgi);
slowr8ddc2b12017-08-14 14:13:38 -0700566 cell.setVersion(recv_pdu.getHdr().getVer().toString());
slowr13fa5b02017-08-08 16:32:31 -0700567 cell.setConf(report);
slowr507a0822017-08-17 20:54:18 -0700568 cellMap.putPciArfcn(cell);
slowr13fa5b02017-08-08 16:32:31 -0700569 break;
570 }
571 case 2: {
572 // Decode UE Admission Request.
573 UEAdmissionRequest ueAdmissionRequest = recv_pdu.getBody().getUEAdmissionRequest();
574
575 ECGI ecgi = ueAdmissionRequest.getEcgi();
576 if (xranStore.getCell(ecgi) != null) {
577 CRNTI crnti = ueAdmissionRequest.getCrnti();
slowr8ddc2b12017-08-14 14:13:38 -0700578 send_pdu = UEAdmissionResponse.constructPacket(ecgi, crnti, xranConfig.admissionFlag());
slowr67d05e42017-08-11 20:37:22 -0700579 ctx.writeAndFlush(getSctpMessage(send_pdu));
slowr13fa5b02017-08-08 16:32:31 -0700580 } else {
581 log.warn("Could not find ECGI in registered cells: {}", ecgi);
582 }
583 break;
584 }
585 case 4: {
586 // Decode UE Admission Status.
587 UEAdmissionStatus ueAdmissionStatus = recv_pdu.getBody().getUEAdmissionStatus();
588
589 RnibUe ue = ueMap.get(ueAdmissionStatus.getCrnti());
590 if (ue != null) {
591 if (ueAdmissionStatus.getAdmEstStatus().value.intValue() == 0) {
slowr67d05e42017-08-11 20:37:22 -0700592 ue.setState(RnibUe.State.ACTIVE);
slowr13fa5b02017-08-08 16:32:31 -0700593 } else {
slowr67d05e42017-08-11 20:37:22 -0700594 ue.setState(RnibUe.State.IDLE);
slowr13fa5b02017-08-08 16:32:31 -0700595 }
596 }
597 break;
598 }
599 case 5: {
600 // Decode UE Admission Context Update.
slowr8ddc2b12017-08-14 14:13:38 -0700601 UEContextUpdate ueContextUpdate = recv_pdu.getBody().getUEContextUpdate();
slowr13fa5b02017-08-08 16:32:31 -0700602
slowr8ddc2b12017-08-14 14:13:38 -0700603 RnibUe ue = ueMap.get(ueContextUpdate.getMMEUES1APID());
slowr73b4eae2017-08-17 16:09:09 -0700604 RnibCell cell = xranStore.getCell(ueContextUpdate.getEcgi());
605 if (ue == null) {
606 ue = new RnibUe();
slowr13fa5b02017-08-08 16:32:31 -0700607 }
slowr73b4eae2017-08-17 16:09:09 -0700608
609 ue.setMmeS1apId(ueContextUpdate.getMMEUES1APID());
610 ue.setEnbS1apId(ueContextUpdate.getENBUES1APID());
611 ue.setRanId(ueContextUpdate.getCrnti());
612
613 hostAgent.addConnectedHost(ue, cell, ctx);
614
slowr13fa5b02017-08-08 16:32:31 -0700615 break;
616 }
617 case 6: {
618 // Decode UE Reconfig_Ind.
619 UEReconfigInd ueReconfigInd = recv_pdu.getBody().getUEReconfigInd();
620 RnibUe ue = ueMap.get(ueReconfigInd.getCrntiOld());
621
622 if (ue != null) {
623 ue.setRanId(ueReconfigInd.getCrntiNew());
624 } else {
625 log.warn("Could not find UE with this CRNTI: {}", ueReconfigInd.getCrntiOld());
626 }
627 break;
628 }
629 case 7: {
630 // If xRANc wants to deactivate UE, we pass UEReleaseInd from xRANc to eNB.
631 // Decode UE Release_Ind.
632 UEReleaseInd ueReleaseInd = recv_pdu.getBody().getUEReleaseInd();
633 RnibUe ue = ueMap.get(ueReleaseInd.getCrnti());
634 if (ue != null) {
slowr67d05e42017-08-11 20:37:22 -0700635 ue.setState(RnibUe.State.IDLE);
slowr13fa5b02017-08-08 16:32:31 -0700636 restartTimer(ue);
637 }
638 break;
639 }
640 case 8: {
641 // Decode Bearer Adm Request
642 BearerAdmissionRequest bearerAdmissionRequest = recv_pdu.getBody().getBearerAdmissionRequest();
643
644 ECGI ecgi = bearerAdmissionRequest.getEcgi();
645 CRNTI crnti = bearerAdmissionRequest.getCrnti();
646 ERABParams erabParams = bearerAdmissionRequest.getErabParams();
647 RnibLink link = linkMap.get(ecgi, crnti);
648 if (link != null) {
649 link.setBearerParameters(erabParams);
650 } else {
651 log.warn("Could not find link between {}-{}", ecgi, crnti);
652 }
653
654 BerInteger numErabs = bearerAdmissionRequest.getNumErabs();
slowr8ddc2b12017-08-14 14:13:38 -0700655 // Encode and send Bearer Admission Response
656 send_pdu = BearerAdmissionResponse.constructPacket(ecgi, crnti, erabParams, numErabs, xranConfig.bearerFlag());
slowr67d05e42017-08-11 20:37:22 -0700657 ctx.writeAndFlush(getSctpMessage(send_pdu));
slowr13fa5b02017-08-08 16:32:31 -0700658 break;
659 }
660 case 10: {
661 //Decode Bearer Admission Status
662 BearerAdmissionStatus bearerAdmissionStatus = recv_pdu.getBody().getBearerAdmissionStatus();
slowr8ddc2b12017-08-14 14:13:38 -0700663 break;
slowr13fa5b02017-08-08 16:32:31 -0700664// ECGI ecgi = bearerAdmissionStatus.getEcgi();
665// CRNTI crnti = bearerAdmissionStatus.getCrnti();
666//
667// RnibLink link = linkMap.get(ecgi, crnti);
slowr13fa5b02017-08-08 16:32:31 -0700668 }
669 case 11: {
670 //Decode Bearer Release Ind
671 BearerReleaseInd bearerReleaseInd = recv_pdu.getBody().getBearerReleaseInd();
672
673 ECGI ecgi = bearerReleaseInd.getEcgi();
674 CRNTI crnti = bearerReleaseInd.getCrnti();
675 RnibLink link = linkMap.get(ecgi, crnti);
676
677 List<ERABID> erabidsRelease = bearerReleaseInd.getErabIds().getERABID();
678 List<ERABParamsItem> erabParamsItem = link.getBearerParameters().getERABParamsItem();
679
680 List<ERABParamsItem> unreleased = erabParamsItem
681 .stream()
682 .filter(item -> {
683 Optional<ERABID> any = erabidsRelease.stream().filter(id -> id.equals(item.getId())).findAny();
684 return !any.isPresent();
685 }).collect(Collectors.toList());
686
687 link.getBearerParameters().setERABParamsItem(new ArrayList<>(unreleased));
slowr13fa5b02017-08-08 16:32:31 -0700688 break;
689 }
690 case 13: {
slowr67d05e42017-08-11 20:37:22 -0700691 HOFailure hoFailure = recv_pdu.getBody().getHOFailure();
692
693 try {
slowr73b4eae2017-08-17 16:09:09 -0700694 hoQueue.get(hoFailure.getEcgi())
slowr67d05e42017-08-11 20:37:22 -0700695 .put("Hand Over Failed with cause: " + hoFailure.getCause());
696 } catch (InterruptedException e) {
697 log.error(ExceptionUtils.getFullStackTrace(e));
698 e.printStackTrace();
699 } finally {
slowr73b4eae2017-08-17 16:09:09 -0700700 hoQueue.remove(hoFailure.getEcgi());
slowr67d05e42017-08-11 20:37:22 -0700701 }
702 break;
slowr8ddc2b12017-08-14 14:13:38 -0700703
slowr67d05e42017-08-11 20:37:22 -0700704 }
slowr8ddc2b12017-08-14 14:13:38 -0700705 case 14: {
slowr67d05e42017-08-11 20:37:22 -0700706 HOComplete hoComplete = recv_pdu.getBody().getHOComplete();
707
slowr67d05e42017-08-11 20:37:22 -0700708 try {
slowr73b4eae2017-08-17 16:09:09 -0700709 hoQueue.get(hoComplete.getEcgiS())
slowr67d05e42017-08-11 20:37:22 -0700710 .put("Hand Over Completed");
711 } catch (InterruptedException e) {
712 log.error(ExceptionUtils.getFullStackTrace(e));
713 e.printStackTrace();
714 } finally {
slowr73b4eae2017-08-17 16:09:09 -0700715 hoQueue.remove(hoComplete.getEcgiS());
slowr67d05e42017-08-11 20:37:22 -0700716 }
717 break;
718 }
slowr8ddc2b12017-08-14 14:13:38 -0700719
720 case 16: {
slowr13fa5b02017-08-08 16:32:31 -0700721 // Decode RX Sig Meas Report.
722 RXSigMeasReport rxSigMeasReport = recv_pdu.getBody().getRXSigMeasReport();
723 List<RXSigReport> rxSigReportList = rxSigMeasReport.getCellMeasReports().getRXSigReport();
724
725 if (!rxSigReportList.isEmpty()) {
726 rxSigReportList.forEach(rxSigReport -> {
727 RnibCell cell = cellMap.get(rxSigReport.getPciArfcn());
728 if (cell != null) {
729 ECGI ecgi = cell.getEcgi();
730 RnibLink link = linkMap.get(ecgi, rxSigMeasReport.getCrnti());
731 if (link == null) {
732 log.warn("Could not find link between: {}-{} | Creating non-serving link..", ecgi, rxSigMeasReport.getCrnti());
733 link = linkMap.putNonServingLink(cell, rxSigMeasReport.getCrnti());
734
735 if (link != null) {
736 restartTimer(link);
737 }
738 }
739
740 if (link != null) {
741 RSRQRange rsrq = rxSigReport.getRsrq();
742 RSRPRange rsrp = rxSigReport.getRsrp();
743
744 RnibLink.LinkQuality quality = link.getQuality();
slowrc153ad92017-08-16 19:47:52 -0700745 quality.setRX(new RnibLink.LinkQuality.RX(
746 rsrp.value.intValue() - 140,
747 (rsrq.value.intValue() * 0.5) - 19.5
748 ));
slowr13fa5b02017-08-08 16:32:31 -0700749 }
750 } else {
slowr507a0822017-08-17 20:54:18 -0700751 log.warn("case 16: Could not find cell with PCI-ARFCN: {}", rxSigReport.getPciArfcn());
slowr13fa5b02017-08-08 16:32:31 -0700752 }
753 });
754 }
755 break;
756 }
slowr8ddc2b12017-08-14 14:13:38 -0700757 case 18: {
slowr13fa5b02017-08-08 16:32:31 -0700758 RadioMeasReportPerUE radioMeasReportPerUE = recv_pdu.getBody().getRadioMeasReportPerUE();
759
760 List<RadioRepPerServCell> servCells = radioMeasReportPerUE.getRadioReportServCells().getRadioRepPerServCell();
761
762 servCells.forEach(servCell -> {
763 RnibCell cell = cellMap.get(servCell.getPciArfcn());
764 if (cell != null) {
765 RnibLink link = linkMap.get(cell.getEcgi(), radioMeasReportPerUE.getCrnti());
766 if (link != null) {
767 RadioRepPerServCell.CqiHist cqiHist = servCell.getCqiHist();
768 RnibLink.LinkQuality quality = link.getQuality();
slowr13fa5b02017-08-08 16:32:31 -0700769
770 final double[] values = {0, 0, 0};
slowrd3d7b412017-08-17 11:15:44 -0700771 final int[] i = {1};
slowr13fa5b02017-08-08 16:32:31 -0700772 cqiHist.getBerInteger().forEach(value -> {
773 values[0] = Math.max(values[0], value.intValue());
slowrd3d7b412017-08-17 11:15:44 -0700774 values[1] += i[0] * value.intValue();
slowr13fa5b02017-08-08 16:32:31 -0700775 values[2] += value.intValue();
slowrd3d7b412017-08-17 11:15:44 -0700776 i[0]++;
slowr13fa5b02017-08-08 16:32:31 -0700777 });
778
slowrc153ad92017-08-16 19:47:52 -0700779 quality.setCQI(new RnibLink.LinkQuality.CQI(
780 cqiHist,
781 values[0],
782 values[1] / values[0]
783 ));
slowr13fa5b02017-08-08 16:32:31 -0700784
785 } else {
786 log.warn("Could not find link between: {}-{}", cell.getEcgi(), radioMeasReportPerUE.getCrnti());
787 }
788 } else {
slowr507a0822017-08-17 20:54:18 -0700789 log.warn("case 18: Could not find cell with PCI-ARFCN: {}", servCell.getPciArfcn());
slowr13fa5b02017-08-08 16:32:31 -0700790 }
791 });
slowr67d05e42017-08-11 20:37:22 -0700792 break;
slowr13fa5b02017-08-08 16:32:31 -0700793 }
slowr8ddc2b12017-08-14 14:13:38 -0700794 case 19: {
slowr13fa5b02017-08-08 16:32:31 -0700795 RadioMeasReportPerCell radioMeasReportPerCell = recv_pdu.getBody().getRadioMeasReportPerCell();
796 break;
797 }
slowr8ddc2b12017-08-14 14:13:38 -0700798 case 20: {
slowr13fa5b02017-08-08 16:32:31 -0700799 SchedMeasReportPerUE schedMeasReportPerUE = recv_pdu.getBody().getSchedMeasReportPerUE();
slowr8ddc2b12017-08-14 14:13:38 -0700800 List<SchedMeasRepPerServCell> servCells = schedMeasReportPerUE.getSchedReportServCells()
801 .getSchedMeasRepPerServCell();
slowr13fa5b02017-08-08 16:32:31 -0700802
803 servCells.forEach(servCell -> {
804 RnibCell cell = cellMap.get(servCell.getPciArfcn());
805 if (cell != null) {
806 RnibLink link = linkMap.get(cell.getEcgi(), schedMeasReportPerUE.getCrnti());
807 if (link != null) {
slowrc153ad92017-08-16 19:47:52 -0700808 link.getQuality().setMCS(new RnibLink.LinkQuality.MCS(
809 servCell.getMcsDl(),
810 servCell.getMcsUl()
811 ));
slowr13fa5b02017-08-08 16:32:31 -0700812
slowrc153ad92017-08-16 19:47:52 -0700813 link.setResourceUsage(new RnibLink.ResourceUsage(
814 servCell.getPrbUsage().getPrbUsageDl(),
815 servCell.getPrbUsage().getPrbUsageUl()
816 ));
slowr13fa5b02017-08-08 16:32:31 -0700817 } else {
slowr8ddc2b12017-08-14 14:13:38 -0700818 log.warn("Could not find link between: {}-{}", cell.getEcgi(),
819 schedMeasReportPerUE.getCrnti());
slowr13fa5b02017-08-08 16:32:31 -0700820 }
821 } else {
slowr507a0822017-08-17 20:54:18 -0700822 log.warn("case 20: Could not find cell with PCI-ARFCN: {}", servCell.getPciArfcn());
slowr13fa5b02017-08-08 16:32:31 -0700823 }
824 });
825 break;
826 }
slowr8ddc2b12017-08-14 14:13:38 -0700827 case 21: {
slowr13fa5b02017-08-08 16:32:31 -0700828 SchedMeasReportPerCell schedMeasReportPerCell = recv_pdu.getBody().getSchedMeasReportPerCell();
slowr13fa5b02017-08-08 16:32:31 -0700829 RnibCell cell = cellMap.get(schedMeasReportPerCell.getEcgi());
830 if (cell != null) {
slowrc153ad92017-08-16 19:47:52 -0700831 cell.setPrbUsage(new RnibCell.PrbUsageContainer(
832 schedMeasReportPerCell.getPrbUsagePcell(),
833 schedMeasReportPerCell.getPrbUsageScell()
834 ));
835
slowr13fa5b02017-08-08 16:32:31 -0700836 cell.setQci(schedMeasReportPerCell.getQciVals());
837 } else {
838 log.warn("Could not find cell with ECGI: {}", schedMeasReportPerCell.getEcgi());
839 }
840 break;
841 }
slowr8ddc2b12017-08-14 14:13:38 -0700842 case 22: {
slowr13fa5b02017-08-08 16:32:31 -0700843 PDCPMeasReportPerUe pdcpMeasReportPerUe = recv_pdu.getBody().getPDCPMeasReportPerUe();
844
845 RnibLink link = linkMap.get(pdcpMeasReportPerUe.getEcgi(), pdcpMeasReportPerUe.getCrnti());
846 if (link != null) {
slowrc153ad92017-08-16 19:47:52 -0700847 link.setPdcpThroughput(new RnibLink.PDCPThroughput(
848 pdcpMeasReportPerUe.getThroughputDl(),
849 pdcpMeasReportPerUe.getThroughputUl()
850 ));
851
852 link.setPdcpPackDelay(new RnibLink.PDCPPacketDelay(
853 pdcpMeasReportPerUe.getPktDelayDl(),
854 pdcpMeasReportPerUe.getPktDelayUl()
855 ));
slowr13fa5b02017-08-08 16:32:31 -0700856 } else {
slowr8ddc2b12017-08-14 14:13:38 -0700857 log.warn("Could not find link between: {}-{}", pdcpMeasReportPerUe.getEcgi(),
858 pdcpMeasReportPerUe.getCrnti());
slowr13fa5b02017-08-08 16:32:31 -0700859 }
860 break;
861 }
slowr8ddc2b12017-08-14 14:13:38 -0700862 case 24: {
863 // Decode UE Capability Info
864 UECapabilityInfo capabilityInfo = recv_pdu.getBody().getUECapabilityInfo();
865
866 RnibUe ue = ueMap.get(capabilityInfo.getCrnti());
867 if (ue != null) {
868 ue.setCapability(capabilityInfo);
869 } else {
870 log.warn("Could not find UE with this CRNTI: {}", capabilityInfo.getCrnti());
871 }
872 break;
873 }
874 case 25: {
875 // Don't know what will invoke sending UE CAPABILITY ENQUIRY
876 // Encode and send UE CAPABILITY ENQUIRY
877 UECapabilityEnquiry ueCapabilityEnquiry = recv_pdu.getBody().getUECapabilityEnquiry();
878 XrancPdu xrancPdu = UECapabilityEnquiry.constructPacket(ueCapabilityEnquiry.getEcgi(), ueCapabilityEnquiry.getCrnti());
879 ctx.writeAndFlush(getSctpMessage(xrancPdu));
880 break;
881 }
slowr89c2ac12017-08-15 16:20:06 -0700882 case 27: {
883 //Decode ScellAddStatus
884 ScellAddStatus scellAddStatus = recv_pdu.getBody().getScellAddStatus();
885 try {
886 scellAddQueue.get(scellAddStatus.getCrnti()).put("Scell's status: " + scellAddStatus.getStatus());
887 if (scellAddStatus.getStatus().getBerEnum().get(0).value.intValue() == 0) {
888
889 scellAddStatus.getScellsInd().getPCIARFCN().forEach(
890 pciarfcn -> {
891 RnibCell cell = cellMap.get(pciarfcn);
892 RnibLink link = linkMap.get(cell.getEcgi(), scellAddStatus.getCrnti());
893 link.setType(RnibLink.Type.SERVING_SECONDARY_CA);
894 }
895 );
896 } else {
897 log.error("Scell addition failed.");
898 }
899 } catch (InterruptedException e) {
900 log.error(ExceptionUtils.getFullStackTrace(e));
901 e.printStackTrace();
902 } finally {
903 scellAddQueue.remove(scellAddStatus.getCrnti());
904 }
905 break;
906 }
907 // TODO: 28: ScellDelete
slowr8ddc2b12017-08-14 14:13:38 -0700908
909 case 30: {
910 // Decode RRMConfig Status
slowr67d05e42017-08-11 20:37:22 -0700911 RRMConfigStatus rrmConfigStatus = recv_pdu.getBody().getRRMConfigStatus();
912 try {
913 RRMCellQueue.get(rrmConfigStatus.getEcgi())
914 .put("RRM Config's status: " + rrmConfigStatus.getStatus());
915 } catch (InterruptedException e) {
916 log.error(ExceptionUtils.getFullStackTrace(e));
917 e.printStackTrace();
918 } finally {
919 RRMCellQueue.remove(rrmConfigStatus.getEcgi());
920 }
921 break;
922 }
slowr8ddc2b12017-08-14 14:13:38 -0700923 //TODO Case 31: SeNBAdd 32: SeNBAddStatus 33: SeNBDelete
slowr13fa5b02017-08-08 16:32:31 -0700924 case 34: {
925 TrafficSplitConfig trafficSplitConfig = recv_pdu.getBody().getTrafficSplitConfig();
926
927 List<TrafficSplitPercentage> splitPercentages = trafficSplitConfig.getTrafficSplitPercent().getTrafficSplitPercentage();
928
929 splitPercentages.forEach(trafficSplitPercentage -> {
930 RnibCell cell = cellMap.get(trafficSplitPercentage.getEcgi());
931 if (cell != null) {
932 RnibLink link = linkMap.get(cell.getEcgi(), trafficSplitConfig.getCrnti());
933 if (link != null) {
934 link.setTrafficPercent(trafficSplitPercentage);
935 } else {
936 log.warn("Could not find link between: {}-{}", cell.getEcgi(), trafficSplitConfig.getCrnti());
937 }
938 } else {
939 log.warn("Could not find cell with ECGI: {}", trafficSplitConfig.getEcgi());
940 }
941 });
slowr67d05e42017-08-11 20:37:22 -0700942 break;
slowr13fa5b02017-08-08 16:32:31 -0700943 }
944 default: {
slowr60d4d102017-08-16 18:33:58 -0700945 log.warn("Wrong API ID: {}", recv_pdu);
slowr67d05e42017-08-11 20:37:22 -0700946 break;
slowr13fa5b02017-08-08 16:32:31 -0700947 }
948 }
949
950 }
951 }
952
953 class InternalNetworkConfigListener implements NetworkConfigListener {
954
955 @Override
956 public void event(NetworkConfigEvent event) {
957 switch (event.type()) {
958 case CONFIG_REGISTERED:
959 break;
960 case CONFIG_UNREGISTERED:
961 break;
962 case CONFIG_ADDED:
963 case CONFIG_UPDATED:
964 if (event.configClass() == CONFIG_CLASS) {
965 handleConfigEvent(event.config());
966 }
967 break;
968 case CONFIG_REMOVED:
969 break;
970 default:
971 break;
972 }
973 }
974
975 private void handleConfigEvent(Optional<Config> config) {
976 if (!config.isPresent()) {
977 return;
978 }
979
980 xranConfig = (XranConfig) config.get();
981
982 legitCells.putAll(xranConfig.activeCellSet());
983
984 controller.start(deviceAgent, hostAgent, packetAgent, xranConfig.getXrancPort());
985 }
986 }
987}