blob: 8040cea8124dc13cf4c76f5bda3972b2f8659296 [file] [log] [blame]
slowr13fa5b02017-08-08 16:32:31 -07001/*
slowr577f3222017-08-28 10:49:08 -07002 * Copyright 2015-present Open Networking Foundation
slowr13fa5b02017-08-08 16:32:31 -07003 *
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;
slowr577f3222017-08-28 10:49:08 -070023import org.apache.felix.scr.annotations.Activate;
24import org.apache.felix.scr.annotations.Component;
25import org.apache.felix.scr.annotations.Deactivate;
26import org.apache.felix.scr.annotations.Reference;
27import org.apache.felix.scr.annotations.ReferenceCardinality;
28import org.apache.felix.scr.annotations.Service;
29import org.onlab.packet.IpAddress;
slowr13fa5b02017-08-08 16:32:31 -070030import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
slowr577f3222017-08-28 10:49:08 -070032import org.onosproject.net.config.Config;
33import org.onosproject.net.config.ConfigFactory;
34import org.onosproject.net.config.NetworkConfigEvent;
35import org.onosproject.net.config.NetworkConfigListener;
36import org.onosproject.net.config.NetworkConfigRegistry;
37import org.onosproject.net.config.NetworkConfigService;
slowr13fa5b02017-08-08 16:32:31 -070038import org.onosproject.net.config.basics.SubjectFactories;
39import org.onosproject.net.device.DeviceEvent;
40import org.onosproject.net.device.DeviceListener;
41import org.onosproject.net.device.DeviceService;
42import org.onosproject.net.host.HostEvent;
43import org.onosproject.net.host.HostListener;
44import org.onosproject.net.host.HostService;
45import org.onosproject.xran.XranStore;
slowr577f3222017-08-28 10:49:08 -070046import org.onosproject.xran.codecs.api.CRNTI;
47import org.onosproject.xran.codecs.api.ECGI;
48import org.onosproject.xran.codecs.api.ERABID;
49import org.onosproject.xran.codecs.api.ERABParams;
50import org.onosproject.xran.codecs.api.ERABParamsItem;
51import org.onosproject.xran.codecs.api.PCIARFCN;
52import org.onosproject.xran.codecs.api.PropScell;
53import org.onosproject.xran.codecs.api.RSRPRange;
54import org.onosproject.xran.codecs.api.RSRQRange;
55import org.onosproject.xran.codecs.api.RXSigReport;
56import org.onosproject.xran.codecs.api.RadioRepPerServCell;
57import org.onosproject.xran.codecs.api.SchedMeasRepPerServCell;
58import org.onosproject.xran.codecs.api.TrafficSplitPercentage;
slowrc153ad92017-08-16 19:47:52 -070059import org.onosproject.xran.codecs.ber.types.BerInteger;
slowr577f3222017-08-28 10:49:08 -070060import org.onosproject.xran.codecs.pdu.BearerAdmissionRequest;
61import org.onosproject.xran.codecs.pdu.BearerAdmissionResponse;
62import org.onosproject.xran.codecs.pdu.BearerAdmissionStatus;
63import org.onosproject.xran.codecs.pdu.BearerReleaseInd;
64import org.onosproject.xran.codecs.pdu.CellConfigReport;
65import org.onosproject.xran.codecs.pdu.CellConfigRequest;
66import org.onosproject.xran.codecs.pdu.HOComplete;
67import org.onosproject.xran.codecs.pdu.HOFailure;
68import org.onosproject.xran.codecs.pdu.HORequest;
69import org.onosproject.xran.codecs.pdu.L2MeasConfig;
70import org.onosproject.xran.codecs.pdu.PDCPMeasReportPerUe;
71import org.onosproject.xran.codecs.pdu.RRMConfig;
72import org.onosproject.xran.codecs.pdu.RRMConfigStatus;
73import org.onosproject.xran.codecs.pdu.RXSigMeasConfig;
74import org.onosproject.xran.codecs.pdu.RXSigMeasReport;
75import org.onosproject.xran.codecs.pdu.RadioMeasReportPerCell;
76import org.onosproject.xran.codecs.pdu.RadioMeasReportPerUE;
77import org.onosproject.xran.codecs.pdu.ScellAdd;
78import org.onosproject.xran.codecs.pdu.ScellAddStatus;
79import org.onosproject.xran.codecs.pdu.ScellDelete;
80import org.onosproject.xran.codecs.pdu.SchedMeasReportPerCell;
81import org.onosproject.xran.codecs.pdu.SchedMeasReportPerUE;
82import org.onosproject.xran.codecs.pdu.TrafficSplitConfig;
83import org.onosproject.xran.codecs.pdu.UEAdmissionRequest;
84import org.onosproject.xran.codecs.pdu.UEAdmissionResponse;
85import org.onosproject.xran.codecs.pdu.UEAdmissionStatus;
86import org.onosproject.xran.codecs.pdu.UECapabilityEnquiry;
87import org.onosproject.xran.codecs.pdu.UECapabilityInfo;
88import org.onosproject.xran.codecs.pdu.UEContextUpdate;
89import org.onosproject.xran.codecs.pdu.UEReconfigInd;
90import org.onosproject.xran.codecs.pdu.UEReleaseInd;
91import org.onosproject.xran.codecs.pdu.XICICConfig;
92import org.onosproject.xran.codecs.pdu.XrancPdu;
slowr13fa5b02017-08-08 16:32:31 -070093import org.onosproject.xran.entities.RnibCell;
94import org.onosproject.xran.entities.RnibLink;
95import org.onosproject.xran.entities.RnibUe;
slowr577f3222017-08-28 10:49:08 -070096import org.onosproject.xran.identifiers.ContextUpdateHandler;
slowrc86750e2017-08-22 17:26:47 -070097import org.onosproject.xran.identifiers.EcgiCrntiPair;
slowr13fa5b02017-08-08 16:32:31 -070098import org.onosproject.xran.identifiers.LinkId;
99import org.onosproject.xran.impl.XranConfig;
100import org.onosproject.xran.providers.XranDeviceListener;
101import org.onosproject.xran.providers.XranHostListener;
slowr13fa5b02017-08-08 16:32:31 -0700102import org.onosproject.xran.wrapper.CellMap;
103import org.onosproject.xran.wrapper.LinkMap;
104import org.onosproject.xran.wrapper.UeMap;
slowr13fa5b02017-08-08 16:32:31 -0700105import org.slf4j.Logger;
106import org.slf4j.LoggerFactory;
107
108import java.io.IOException;
slowr577f3222017-08-28 10:49:08 -0700109import java.util.ArrayList;
110import java.util.List;
111import java.util.Optional;
112import java.util.Set;
113import java.util.Timer;
114import java.util.TimerTask;
115import java.util.concurrent.BlockingQueue;
116import java.util.concurrent.ConcurrentHashMap;
117import java.util.concurrent.ConcurrentMap;
118import java.util.concurrent.CopyOnWriteArraySet;
119import java.util.concurrent.LinkedBlockingQueue;
120import java.util.concurrent.SynchronousQueue;
slowr13fa5b02017-08-08 16:32:31 -0700121import java.util.stream.Collectors;
122
123import static org.onosproject.net.DeviceId.deviceId;
slowr67d05e42017-08-11 20:37:22 -0700124import static org.onosproject.xran.controller.XranChannelHandler.getSctpMessage;
slowr13fa5b02017-08-08 16:32:31 -0700125import static org.onosproject.xran.entities.RnibCell.decodeDeviceId;
126import static org.onosproject.xran.entities.RnibCell.uri;
slowrc86750e2017-08-22 17:26:47 -0700127import static org.onosproject.xran.entities.RnibUe.hostIdtoUEId;
slowr13fa5b02017-08-08 16:32:31 -0700128
129/**
130 * Created by dimitris on 7/20/17.
131 */
132@Component(immediate = true)
133@Service
134public class XranControllerImpl implements XranController {
135 private static final String XRAN_APP_ID = "org.onosproject.xran";
136 private static final Class<XranConfig> CONFIG_CLASS = XranConfig.class;
137
138 private static final Logger log =
139 LoggerFactory.getLogger(XranControllerImpl.class);
140 /* CONFIG */
141 private final InternalNetworkConfigListener configListener =
142 new InternalNetworkConfigListener();
143 /* VARIABLES */
144 private final Controller controller = new Controller();
145 private XranConfig xranConfig;
146 private ApplicationId appId;
slowr577f3222017-08-28 10:49:08 -0700147 private int northboundTimeout;
slowr13fa5b02017-08-08 16:32:31 -0700148 /* Services */
149 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
150 private DeviceService deviceService;
151 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
152 private HostService hostService;
153 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
154 private NetworkConfigRegistry registry;
155 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
156 private NetworkConfigService configService;
157 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
158 private CoreService coreService;
159 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
160 private XranStore xranStore;
161 private ConfigFactory<ApplicationId, XranConfig> xranConfigFactory =
162 new ConfigFactory<ApplicationId, XranConfig>(
163 SubjectFactories.APP_SUBJECT_FACTORY, CONFIG_CLASS, "xran") {
164 @Override
165 public XranConfig createConfig() {
166 return new XranConfig();
167 }
168 };
169 /* WRAPPERS */
170 private CellMap cellMap;
171 private UeMap ueMap;
172 private LinkMap linkMap;
173 /* MAPS */
slowr577f3222017-08-28 10:49:08 -0700174 private ConcurrentMap<IpAddress, ECGI> legitCells = new ConcurrentHashMap<>();
slowrc86750e2017-08-22 17:26:47 -0700175 private ConcurrentMap<ECGI, SynchronousQueue<String>> hoMap = new ConcurrentHashMap<>();
slowr577f3222017-08-28 10:49:08 -0700176 private ConcurrentMap<ECGI, SynchronousQueue<String>> rrmcellMap = new ConcurrentHashMap<>();
slowrc86750e2017-08-22 17:26:47 -0700177 private ConcurrentMap<CRNTI, SynchronousQueue<String>> scellAddMap = new ConcurrentHashMap<>();
slowr577f3222017-08-28 10:49:08 -0700178 private ConcurrentMap<EcgiCrntiPair, ContextUpdateHandler> contextUpdateMap = new ConcurrentHashMap<>();
slowrc86750e2017-08-22 17:26:47 -0700179 /* QUEUE */
180 private BlockingQueue<Long> ueIdQueue = new LinkedBlockingQueue<>();
slowr13fa5b02017-08-08 16:32:31 -0700181 /* AGENTS */
182 private InternalXranDeviceAgent deviceAgent = new InternalXranDeviceAgent();
183 private InternalXranHostAgent hostAgent = new InternalXranHostAgent();
184 private InternalXranPacketAgent packetAgent = new InternalXranPacketAgent();
185 /* LISTENERS */
186 private Set<XranDeviceListener> xranDeviceListeners = new CopyOnWriteArraySet<>();
187 private Set<XranHostListener> xranHostListeners = new CopyOnWriteArraySet<>();
slowr577f3222017-08-28 10:49:08 -0700188 private InternalDeviceListener deviceListener = new InternalDeviceListener();
189 private InternalHostListener hostListener = new InternalHostListener();
slowr13fa5b02017-08-08 16:32:31 -0700190
191 @Activate
192 public void activate() {
193 appId = coreService.registerApplication(XRAN_APP_ID);
194
195 configService.addListener(configListener);
196 registry.registerConfigFactory(xranConfigFactory);
slowr577f3222017-08-28 10:49:08 -0700197 deviceService.addListener(deviceListener);
198 hostService.addListener(hostListener);
slowr13fa5b02017-08-08 16:32:31 -0700199
200 cellMap = new CellMap(xranStore);
201 ueMap = new UeMap(xranStore);
slowrd337c932017-08-18 13:54:02 -0700202 linkMap = new LinkMap(xranStore, ueMap);
slowr13fa5b02017-08-08 16:32:31 -0700203
204 xranStore.setController(this);
205
206 log.info("XRAN Controller Started");
207 }
208
209 @Deactivate
210 public void deactivate() {
211 controller.stop();
212
slowr577f3222017-08-28 10:49:08 -0700213 deviceService.removeListener(deviceListener);
214 hostService.removeListener(hostListener);
slowr13fa5b02017-08-08 16:32:31 -0700215
216 legitCells.clear();
217
218 configService.removeListener(configListener);
219 registry.unregisterConfigFactory(xranConfigFactory);
220
221 log.info("XRAN Controller Stopped");
222 }
223
224 @Override
slowr577f3222017-08-28 10:49:08 -0700225 public SynchronousQueue<String> sendHORequest(RnibLink linkT, RnibLink linkS) throws InterruptedException {
226 ECGI ecgiT = linkT.getLinkId().getEcgi(),
227 ecgiS = linkS.getLinkId().getEcgi();
slowr73b4eae2017-08-17 16:09:09 -0700228
slowr577f3222017-08-28 10:49:08 -0700229 CRNTI crnti = linkMap.getCrnti(linkT.getLinkId().getUeId());
230 ChannelHandlerContext ctxT = cellMap.getCtx(ecgiT),
231 ctxS = cellMap.getCtx(ecgiS);
slowrc86750e2017-08-22 17:26:47 -0700232
233 SynchronousQueue<String> queue = new SynchronousQueue<>();
slowr67d05e42017-08-11 20:37:22 -0700234 try {
slowr577f3222017-08-28 10:49:08 -0700235 XrancPdu xrancPdu = HORequest.constructPacket(crnti, ecgiS, ecgiT);
slowrc86750e2017-08-22 17:26:47 -0700236
slowr577f3222017-08-28 10:49:08 -0700237 // temporary map that has ECGI source of a handoff to a queue waiting for REST response.
238 hoMap.put(ecgiS, queue);
slowrc86750e2017-08-22 17:26:47 -0700239
slowr577f3222017-08-28 10:49:08 -0700240 ctxT.writeAndFlush(getSctpMessage(xrancPdu));
241 ctxS.writeAndFlush(getSctpMessage(xrancPdu));
242
243 // FIXME: only works for one HO at a time.
244 ueIdQueue.put(linkT.getLinkId().getUeId());
slowr67d05e42017-08-11 20:37:22 -0700245 } catch (IOException e) {
246 e.printStackTrace();
247 }
248
slowr67d05e42017-08-11 20:37:22 -0700249 return queue;
250 }
251
252 @Override
slowr13fa5b02017-08-08 16:32:31 -0700253 public void addListener(XranDeviceListener listener) {
254 xranDeviceListeners.add(listener);
255 }
256
257 @Override
258 public void addListener(XranHostListener listener) {
259 xranHostListeners.add(listener);
260 }
261
262 @Override
263 public void removeListener(XranDeviceListener listener) {
264 xranDeviceListeners.remove(listener);
265 }
266
267 @Override
268 public void removeListener(XranHostListener listener) {
269 xranHostListeners.remove(listener);
270 }
271
slowr67d05e42017-08-11 20:37:22 -0700272 @Override
slowr577f3222017-08-28 10:49:08 -0700273 public int getNorthboundTimeout() {
274 return northboundTimeout;
slowrc86750e2017-08-22 17:26:47 -0700275 }
276
277 @Override
slowr577f3222017-08-28 10:49:08 -0700278 public SynchronousQueue<String> sendmodifiedrrmconf(RRMConfig rrmConfig, boolean xicic) {
slowr8ddc2b12017-08-14 14:13:38 -0700279 ECGI ecgi = rrmConfig.getEcgi();
slowr67d05e42017-08-11 20:37:22 -0700280 ChannelHandlerContext ctx = cellMap.getCtx(ecgi);
281 try {
slowrc86750e2017-08-22 17:26:47 -0700282 XrancPdu pdu;
slowr73b4eae2017-08-17 16:09:09 -0700283
slowr577f3222017-08-28 10:49:08 -0700284 if (xicic) {
slowr73b4eae2017-08-17 16:09:09 -0700285 CellConfigReport cellConfigReport = cellMap.get(ecgi).getConf();
286 if (cellConfigReport != null) {
287 pdu = XICICConfig.constructPacket(rrmConfig, cellConfigReport);
288 ctx.writeAndFlush(getSctpMessage(pdu));
289 }
slowr8ddc2b12017-08-14 14:13:38 -0700290 } else {
291 pdu = RRMConfig.constructPacket(rrmConfig);
slowr73b4eae2017-08-17 16:09:09 -0700292 ctx.writeAndFlush(getSctpMessage(pdu));
293 SynchronousQueue<String> queue = new SynchronousQueue<>();
slowr577f3222017-08-28 10:49:08 -0700294 rrmcellMap.put(ecgi, queue);
slowr73b4eae2017-08-17 16:09:09 -0700295 return queue;
slowr8ddc2b12017-08-14 14:13:38 -0700296 }
slowr67d05e42017-08-11 20:37:22 -0700297 } catch (IOException e) {
298 e.printStackTrace();
299 }
slowr67d05e42017-08-11 20:37:22 -0700300
slowr73b4eae2017-08-17 16:09:09 -0700301 return null;
slowr67d05e42017-08-11 20:37:22 -0700302 }
303
slowr89c2ac12017-08-15 16:20:06 -0700304 @Override
305 public SynchronousQueue<String> sendScellAdd(RnibLink link) {
306 RnibCell secondaryCell = link.getLinkId().getCell(),
307 primaryCell = linkMap.getPrimaryCell(link.getLinkId().getUe());
308 ECGI primaryEcgi = primaryCell.getEcgi();
309 ChannelHandlerContext ctx = cellMap.getCtx(primaryEcgi);
310
slowrc86750e2017-08-22 17:26:47 -0700311 CRNTI crnti = linkMap.getCrnti(link.getLinkId().getUeId());
slowr89c2ac12017-08-15 16:20:06 -0700312
313 CellConfigReport cellReport = secondaryCell.getConf();
314
315 if (cellReport != null) {
316 PCIARFCN pciarfcn = new PCIARFCN();
317 pciarfcn.setPci(cellReport.getPci());
318 pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
319
320 PropScell propScell = new PropScell();
321 propScell.setPciArfcn(pciarfcn);
322
323 XrancPdu pdu = ScellAdd.constructPacket(primaryEcgi, crnti, propScell);
324 try {
325 ctx.writeAndFlush(getSctpMessage(pdu));
326 SynchronousQueue<String> queue = new SynchronousQueue<>();
slowrc86750e2017-08-22 17:26:47 -0700327 scellAddMap.put(crnti, queue);
slowr89c2ac12017-08-15 16:20:06 -0700328
329 return queue;
330 } catch (IOException e) {
331 log.error(ExceptionUtils.getFullStackTrace(e));
332 e.printStackTrace();
333 }
334 }
335 return null;
336 }
337
338 @Override
339 public boolean sendScellDelete(RnibLink link) {
340 RnibCell secondaryCell = link.getLinkId().getCell(),
341 primaryCell = linkMap.getPrimaryCell(link.getLinkId().getUe());
342 ECGI primaryEcgi = primaryCell.getEcgi();
343 ChannelHandlerContext ctx = cellMap.getCtx(primaryEcgi);
344
slowrc86750e2017-08-22 17:26:47 -0700345 CRNTI crnti = linkMap.getCrnti(link.getLinkId().getUeId());
slowr89c2ac12017-08-15 16:20:06 -0700346
347 CellConfigReport cellReport = secondaryCell.getConf();
348
349 if (cellReport != null) {
350 PCIARFCN pciarfcn = new PCIARFCN();
351 pciarfcn.setPci(cellReport.getPci());
352 pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
353
354 XrancPdu pdu = ScellDelete.constructPacket(primaryEcgi, crnti, pciarfcn);
355
356 try {
357 ctx.writeAndFlush(getSctpMessage(pdu));
358 link.setType(RnibLink.Type.NON_SERVING);
359 return true;
360 } catch (IOException e) {
361 log.error(ExceptionUtils.getFullStackTrace(e));
362 e.printStackTrace();
363 }
364 }
365 return false;
366 }
367
slowr577f3222017-08-28 10:49:08 -0700368 /**
369 * Timer to delete UE after being IDLE.
370 *
371 * @param ue UE entity
372 */
slowr13fa5b02017-08-08 16:32:31 -0700373 private void restartTimer(RnibUe ue) {
374 Timer timer = new Timer();
375 ue.setTimer(timer);
slowr13fa5b02017-08-08 16:32:31 -0700376 timer.schedule(new TimerTask() {
377 @Override
378 public void run() {
slowr67d05e42017-08-11 20:37:22 -0700379 if (ue.getState() == RnibUe.State.IDLE) {
slowr13fa5b02017-08-08 16:32:31 -0700380 hostAgent.removeConnectedHost(ue);
slowrc86750e2017-08-22 17:26:47 -0700381 log.info("UE is removed after {} ms of IDLE", xranConfig.getIdleUeRemoval());
slowr13fa5b02017-08-08 16:32:31 -0700382 } else {
383 log.info("UE not removed cause its ACTIVE");
384 }
385 }
slowrd337c932017-08-18 13:54:02 -0700386 }, xranConfig.getIdleUeRemoval());
slowr13fa5b02017-08-08 16:32:31 -0700387 }
388
slowr577f3222017-08-28 10:49:08 -0700389 /**
390 * Timer to delete LINK after not receiving measurements.
391 *
392 * @param link LINK entity
393 */
slowr13fa5b02017-08-08 16:32:31 -0700394 private void restartTimer(RnibLink link) {
395 Timer timer = new Timer();
396 link.setTimer(timer);
slowr13fa5b02017-08-08 16:32:31 -0700397 timer.schedule(new TimerTask() {
398 @Override
399 public void run() {
400 LinkId linkId = link.getLinkId();
401 xranStore.removeLink(linkId);
slowr577f3222017-08-28 10:49:08 -0700402 log.info("Link is removed after not receiving Meas Reports for {} ms",
403 xranConfig.getNoMeasLinkRemoval());
slowr13fa5b02017-08-08 16:32:31 -0700404 }
slowrd337c932017-08-18 13:54:02 -0700405 }, xranConfig.getNoMeasLinkRemoval());
slowr13fa5b02017-08-08 16:32:31 -0700406
407 }
408
slowr577f3222017-08-28 10:49:08 -0700409 /**
410 * Request measurement configuration field of specified UE.
411 *
412 * @param primary primary CELL
413 * @param ue UE entity
414 */
415 private void populateMeasConfig(RnibCell primary, RnibUe ue) {
416 try {
417 ChannelHandlerContext ctx = cellMap.getCtx(primary.getEcgi());
418 RXSigMeasConfig.MeasCells measCells = new RXSigMeasConfig.MeasCells();
419 xranStore.getcellnodes().forEach(cell -> {
420 CellConfigReport cellReport = ((RnibCell) cell).getConf();
421 if (cellReport != null) {
422 PCIARFCN pciarfcn = new PCIARFCN();
423 pciarfcn.setPci(cellReport.getPci());
424 pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
425 measCells.setPCIARFCN(pciarfcn);
426 }
427 });
428 XrancPdu xrancPdu = RXSigMeasConfig.constructPacket(
429 primary.getEcgi(),
430 ue.getCrnti(),
431 measCells,
432 xranConfig.getRxSignalInterval()
433 );
434 ue.setMeasConfig(xrancPdu.getBody().getRXSigMeasConfig());
435 ctx.writeAndFlush(getSctpMessage(xrancPdu));
436 } catch (IOException e) {
437 log.warn(ExceptionUtils.getFullStackTrace(e));
438 e.printStackTrace();
439 }
440 }
441
442 /**
443 * Internal device listener.
444 */
slowr13fa5b02017-08-08 16:32:31 -0700445 class InternalDeviceListener implements DeviceListener {
446
447 @Override
448 public void event(DeviceEvent event) {
449 log.info("Device Event {}", event);
450 switch (event.type()) {
451 case DEVICE_ADDED: {
452 try {
453 ECGI ecgi = decodeDeviceId(event.subject().id());
454 RnibCell cell = cellMap.get(ecgi);
455 if (cell != null) {
456 Timer timer = new Timer();
457 timer.scheduleAtFixedRate(
458 new TimerTask() {
459 @Override
460 public void run() {
461 CellConfigReport conf = cell.getConf();
462 if (conf == null) {
463 try {
464 ChannelHandlerContext ctx = cellMap.getCtx(ecgi);
slowr8ddc2b12017-08-14 14:13:38 -0700465 XrancPdu xrancPdu = CellConfigRequest.constructPacket(ecgi);
slowr67d05e42017-08-11 20:37:22 -0700466 ctx.writeAndFlush(getSctpMessage(xrancPdu));
slowr13fa5b02017-08-08 16:32:31 -0700467 } catch (IOException e) {
468 log.error(ExceptionUtils.getFullStackTrace(e));
469 e.printStackTrace();
470 }
471 } else {
slowr577f3222017-08-28 10:49:08 -0700472 List<Object> ueNodes = xranStore.getuenodes();
slowrd337c932017-08-18 13:54:02 -0700473 ueNodes.forEach(object -> {
474 RnibUe ue = (RnibUe) object;
475 try {
slowr577f3222017-08-28 10:49:08 -0700476 ECGI primaryEcgi = linkMap.getPrimaryCell(ue).getEcgi();
477 ChannelHandlerContext ctx = cellMap.getCtx(primaryEcgi);
478 RXSigMeasConfig.MeasCells measCells =
479 new RXSigMeasConfig.MeasCells();
480 xranStore.getcellnodes().forEach(cell -> {
slowrd337c932017-08-18 13:54:02 -0700481 CellConfigReport cellReport = ((RnibCell) cell).getConf();
482 if (cellReport != null) {
483 PCIARFCN pciarfcn = new PCIARFCN();
484 pciarfcn.setPci(cellReport.getPci());
485 pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
486 measCells.setPCIARFCN(pciarfcn);
487 }
488 });
489 XrancPdu xrancPdu = RXSigMeasConfig.constructPacket(
slowr577f3222017-08-28 10:49:08 -0700490 primaryEcgi,
slowrc86750e2017-08-22 17:26:47 -0700491 ue.getCrnti(),
slowrd337c932017-08-18 13:54:02 -0700492 measCells,
493 xranConfig.getRxSignalInterval()
494 );
495 ue.setMeasConfig(xrancPdu.getBody().getRXSigMeasConfig());
496 ctx.writeAndFlush(getSctpMessage(xrancPdu));
497 } catch (IOException e) {
498 log.warn(ExceptionUtils.getFullStackTrace(e));
499 e.printStackTrace();
500 }
501 });
502
slowr13fa5b02017-08-08 16:32:31 -0700503 try {
slowrd337c932017-08-18 13:54:02 -0700504 ChannelHandlerContext ctx = cellMap.getCtx(ecgi);
slowr577f3222017-08-28 10:49:08 -0700505 XrancPdu xrancPdu = L2MeasConfig
506 .constructPacket(ecgi, xranConfig.getL2MeasInterval());
slowr13fa5b02017-08-08 16:32:31 -0700507 cell.setMeasConfig(xrancPdu.getBody().getL2MeasConfig());
slowr67d05e42017-08-11 20:37:22 -0700508 SctpMessage sctpMessage = getSctpMessage(xrancPdu);
slowr13fa5b02017-08-08 16:32:31 -0700509 ctx.writeAndFlush(sctpMessage);
510 } catch (IOException e) {
511 log.error(ExceptionUtils.getFullStackTrace(e));
512 e.printStackTrace();
513 }
514 timer.cancel();
515 timer.purge();
516 }
517 }
518 },
519 0,
520 xranConfig.getConfigRequestInterval() * 1000
521 );
522 }
523 } catch (IOException e) {
524 log.error(ExceptionUtils.getFullStackTrace(e));
525 e.printStackTrace();
526 }
527 break;
528 }
529 default: {
530 break;
531 }
532 }
533 }
534 }
535
slowr577f3222017-08-28 10:49:08 -0700536 /**
537 * Internal host listener.
538 */
slowr13fa5b02017-08-08 16:32:31 -0700539 class InternalHostListener implements HostListener {
540
541 @Override
542 public void event(HostEvent event) {
543 log.info("Host Event {}", event);
544 switch (event.type()) {
545 case HOST_ADDED:
546 case HOST_MOVED: {
slowrc86750e2017-08-22 17:26:47 -0700547 RnibUe ue = ueMap.get(hostIdtoUEId(event.subject().id()));
slowr13fa5b02017-08-08 16:32:31 -0700548 if (ue != null) {
slowr577f3222017-08-28 10:49:08 -0700549 ECGI ecgiPrimary = linkMap.getPrimaryCell(ue).getEcgi();
550 RnibCell primary = cellMap.get(ecgiPrimary);
slowr13fa5b02017-08-08 16:32:31 -0700551 ue.setMeasConfig(null);
552 if (primary != null) {
553 Timer timer = new Timer();
554 timer.scheduleAtFixedRate(
555 new TimerTask() {
556 @Override
557 public void run() {
slowred74ec72017-08-17 11:25:01 -0700558 if (ue.getCapability() == null && primary.getVersion() >= 3) {
slowr13fa5b02017-08-08 16:32:31 -0700559 try {
560 ChannelHandlerContext ctx = cellMap.getCtx(primary.getEcgi());
slowr8ddc2b12017-08-14 14:13:38 -0700561 XrancPdu xrancPdu = UECapabilityEnquiry.constructPacket(
slowr67d05e42017-08-11 20:37:22 -0700562 primary.getEcgi(),
slowrc86750e2017-08-22 17:26:47 -0700563 ue.getCrnti());
slowr67d05e42017-08-11 20:37:22 -0700564 ctx.writeAndFlush(getSctpMessage(xrancPdu));
slowr13fa5b02017-08-08 16:32:31 -0700565 } catch (IOException e) {
566 log.warn(ExceptionUtils.getFullStackTrace(e));
567 e.printStackTrace();
568 }
569 } else {
slowr13fa5b02017-08-08 16:32:31 -0700570 timer.cancel();
571 timer.purge();
572 }
573 }
574 },
575 0,
576 xranConfig.getConfigRequestInterval() * 1000
577 );
slowred74ec72017-08-17 11:25:01 -0700578 if (ue.getMeasConfig() == null) {
slowr577f3222017-08-28 10:49:08 -0700579 populateMeasConfig(primary, ue);
slowred74ec72017-08-17 11:25:01 -0700580 }
slowr13fa5b02017-08-08 16:32:31 -0700581 }
582 }
583 break;
584 }
585 default: {
586 break;
587 }
588 }
589 }
590 }
591
slowr577f3222017-08-28 10:49:08 -0700592 /**
593 * Internal xran device agent.
594 */
slowr13fa5b02017-08-08 16:32:31 -0700595 public class InternalXranDeviceAgent implements XranDeviceAgent {
596
597 private final Logger log = LoggerFactory.getLogger(InternalXranDeviceAgent.class);
598
599 @Override
600 public boolean addConnectedCell(String host, ChannelHandlerContext ctx) {
slowr577f3222017-08-28 10:49:08 -0700601 ECGI ecgi = legitCells.get(IpAddress.valueOf(host));
slowr13fa5b02017-08-08 16:32:31 -0700602
603 if (ecgi == null) {
604 log.error("Device is not a legit source; ignoring...");
605 } else {
606 log.info("Device exists in configuration; registering...");
607 RnibCell storeCell = cellMap.get(ecgi);
608 if (storeCell == null) {
609 storeCell = new RnibCell();
610 storeCell.setEcgi(ecgi);
611 cellMap.put(storeCell, ctx);
612
613 for (XranDeviceListener l : xranDeviceListeners) {
614 l.deviceAdded(storeCell);
615 }
616 return true;
617 } else {
618 log.error("Device already registered; ignoring...");
619 }
620 }
621 ctx.close();
622 return false;
623 }
624
625 @Override
626 public boolean removeConnectedCell(String host) {
slowr577f3222017-08-28 10:49:08 -0700627 ECGI ecgi = legitCells.get(IpAddress.valueOf(host));
628 List<RnibLink> linksbyecgi = xranStore.getlinksbyecgi(ecgi);
slowr13fa5b02017-08-08 16:32:31 -0700629
slowr577f3222017-08-28 10:49:08 -0700630 linksbyecgi.forEach(rnibLink -> xranStore.removeLink(rnibLink.getLinkId()));
slowr13fa5b02017-08-08 16:32:31 -0700631
632 if (cellMap.remove(ecgi)) {
633 for (XranDeviceListener l : xranDeviceListeners) {
634 l.deviceRemoved(deviceId(uri(ecgi)));
635 }
636 return true;
637 }
638 return false;
639 }
640 }
641
slowr577f3222017-08-28 10:49:08 -0700642 /**
643 * Internal xran host agent.
644 */
slowr13fa5b02017-08-08 16:32:31 -0700645 public class InternalXranHostAgent implements XranHostAgent {
646
647 @Override
648 public boolean addConnectedHost(RnibUe ue, RnibCell cell, ChannelHandlerContext ctx) {
649
slowrc86750e2017-08-22 17:26:47 -0700650 if (ue.getId() != null && ueMap.get(ue.getId()) != null) {
slowr13fa5b02017-08-08 16:32:31 -0700651 linkMap.putPrimaryLink(cell, ue);
652
slowrc86750e2017-08-22 17:26:47 -0700653 Set<ECGI> ecgiSet = Sets.newConcurrentHashSet();
654
slowr577f3222017-08-28 10:49:08 -0700655 xranStore.getlinksbyueid(ue.getId())
slowr13fa5b02017-08-08 16:32:31 -0700656 .stream()
slowrc86750e2017-08-22 17:26:47 -0700657 .filter(l -> l.getType().equals(RnibLink.Type.SERVING_PRIMARY))
slowr577f3222017-08-28 10:49:08 -0700658 .findFirst()
659 .ifPresent(l -> ecgiSet.add(l.getLinkId().getEcgi()));
slowr13fa5b02017-08-08 16:32:31 -0700660
661 for (XranHostListener l : xranHostListeners) {
662 l.hostAdded(ue, ecgiSet);
663 }
664 return true;
665 } else {
slowrd337c932017-08-18 13:54:02 -0700666 ueMap.put(cell, ue);
slowr13fa5b02017-08-08 16:32:31 -0700667 linkMap.putPrimaryLink(cell, ue);
668
669 Set<ECGI> ecgiSet = Sets.newConcurrentHashSet();
670 ecgiSet.add(cell.getEcgi());
671 for (XranHostListener l : xranHostListeners) {
672 l.hostAdded(ue, ecgiSet);
673 }
674 return true;
675 }
676
677 }
678
679 @Override
680 public boolean removeConnectedHost(RnibUe ue) {
slowr577f3222017-08-28 10:49:08 -0700681 List<RnibLink> links = xranStore.getlinksbyueid(ue.getId());
slowr13fa5b02017-08-08 16:32:31 -0700682 links.forEach(rnibLink -> xranStore.removeLink(rnibLink.getLinkId()));
slowrc86750e2017-08-22 17:26:47 -0700683 if (ueMap.remove(ue.getId())) {
slowr13fa5b02017-08-08 16:32:31 -0700684 for (XranHostListener l : xranHostListeners) {
685 l.hostRemoved(ue.getHostId());
686 }
687 return true;
688 }
689 return false;
690 }
691 }
692
693 public class InternalXranPacketAgent implements XranPacketProcessor {
694 @Override
slowr577f3222017-08-28 10:49:08 -0700695 public void handlePacket(XrancPdu recvPdu, ChannelHandlerContext ctx)
696 throws IOException, InterruptedException {
697 XrancPdu sendPdu;
slowr13fa5b02017-08-08 16:32:31 -0700698
slowr577f3222017-08-28 10:49:08 -0700699 int apiID = recvPdu.getHdr().getApiId().intValue();
700 log.debug("Received message: {}", recvPdu);
slowr13fa5b02017-08-08 16:32:31 -0700701 switch (apiID) {
702 case 1: {
703 // Decode Cell config report.
slowr577f3222017-08-28 10:49:08 -0700704 CellConfigReport report = recvPdu.getBody().getCellConfigReport();
705 handleCellconfigreport(report, recvPdu.getHdr().getVer().toString());
slowr13fa5b02017-08-08 16:32:31 -0700706 break;
707 }
708 case 2: {
709 // Decode UE Admission Request.
slowr577f3222017-08-28 10:49:08 -0700710 UEAdmissionRequest ueAdmissionRequest = recvPdu.getBody().getUEAdmissionRequest();
711 handleUeadmissionrequest(ueAdmissionRequest, ctx);
slowr13fa5b02017-08-08 16:32:31 -0700712 break;
713 }
714 case 4: {
715 // Decode UE Admission Status.
slowr577f3222017-08-28 10:49:08 -0700716 UEAdmissionStatus ueAdmissionStatus = recvPdu.getBody().getUEAdmissionStatus();
717 handleAdmissionstatus(ueAdmissionStatus, ctx);
slowr13fa5b02017-08-08 16:32:31 -0700718 break;
719 }
720 case 5: {
slowrc86750e2017-08-22 17:26:47 -0700721 // Decode UE Context Update.
slowr577f3222017-08-28 10:49:08 -0700722 UEContextUpdate ueContextUpdate = recvPdu.getBody().getUEContextUpdate();
723 handleUecontextupdate(ueContextUpdate, ctx);
slowr73b4eae2017-08-17 16:09:09 -0700724
slowr13fa5b02017-08-08 16:32:31 -0700725 break;
726 }
727 case 6: {
728 // Decode UE Reconfig_Ind.
slowr577f3222017-08-28 10:49:08 -0700729 UEReconfigInd ueReconfigInd = recvPdu.getBody().getUEReconfigInd();
730 handleUereconfigind(ueReconfigInd);
slowr13fa5b02017-08-08 16:32:31 -0700731 break;
732 }
733 case 7: {
734 // If xRANc wants to deactivate UE, we pass UEReleaseInd from xRANc to eNB.
735 // Decode UE Release_Ind.
slowr577f3222017-08-28 10:49:08 -0700736 UEReleaseInd ueReleaseInd = recvPdu.getBody().getUEReleaseInd();
737 handleUereleaseind(ueReleaseInd);
slowr13fa5b02017-08-08 16:32:31 -0700738 break;
739 }
740 case 8: {
741 // Decode Bearer Adm Request
slowr577f3222017-08-28 10:49:08 -0700742 BearerAdmissionRequest bearerAdmissionRequest = recvPdu.getBody().getBearerAdmissionRequest();
743 handleBeareradmissionrequest(bearerAdmissionRequest, ctx);
slowr13fa5b02017-08-08 16:32:31 -0700744 break;
745 }
746 case 10: {
747 //Decode Bearer Admission Status
slowr577f3222017-08-28 10:49:08 -0700748 BearerAdmissionStatus bearerAdmissionStatus = recvPdu.getBody().getBearerAdmissionStatus();
slowr8ddc2b12017-08-14 14:13:38 -0700749 break;
slowr13fa5b02017-08-08 16:32:31 -0700750 }
751 case 11: {
752 //Decode Bearer Release Ind
slowr577f3222017-08-28 10:49:08 -0700753 BearerReleaseInd bearerReleaseInd = recvPdu.getBody().getBearerReleaseInd();
754 handleBearerreleaseind(bearerReleaseInd);
slowr13fa5b02017-08-08 16:32:31 -0700755 break;
756 }
757 case 13: {
slowr577f3222017-08-28 10:49:08 -0700758 HOFailure hoFailure = recvPdu.getBody().getHOFailure();
759 handleHofailure(hoFailure);
slowr67d05e42017-08-11 20:37:22 -0700760 break;
slowr8ddc2b12017-08-14 14:13:38 -0700761
slowr67d05e42017-08-11 20:37:22 -0700762 }
slowr8ddc2b12017-08-14 14:13:38 -0700763 case 14: {
slowr577f3222017-08-28 10:49:08 -0700764 HOComplete hoComplete = recvPdu.getBody().getHOComplete();
765 handleHocomplete(hoComplete, ctx);
slowr67d05e42017-08-11 20:37:22 -0700766 break;
767 }
slowr8ddc2b12017-08-14 14:13:38 -0700768
769 case 16: {
slowr577f3222017-08-28 10:49:08 -0700770 // Decode Rx Sig Meas Report.
771 RXSigMeasReport rxSigMeasReport = recvPdu.getBody().getRXSigMeasReport();
772 handleRxsigmeasreport(rxSigMeasReport);
slowr13fa5b02017-08-08 16:32:31 -0700773 break;
774 }
slowr8ddc2b12017-08-14 14:13:38 -0700775 case 18: {
slowr577f3222017-08-28 10:49:08 -0700776 RadioMeasReportPerUE radioMeasReportPerUE = recvPdu.getBody().getRadioMeasReportPerUE();
777 handleRadionmeasreportperue(radioMeasReportPerUE);
slowr67d05e42017-08-11 20:37:22 -0700778 break;
slowr13fa5b02017-08-08 16:32:31 -0700779 }
slowr8ddc2b12017-08-14 14:13:38 -0700780 case 19: {
slowr577f3222017-08-28 10:49:08 -0700781 RadioMeasReportPerCell radioMeasReportPerCell = recvPdu.getBody().getRadioMeasReportPerCell();
slowr13fa5b02017-08-08 16:32:31 -0700782 break;
783 }
slowr8ddc2b12017-08-14 14:13:38 -0700784 case 20: {
slowr577f3222017-08-28 10:49:08 -0700785 SchedMeasReportPerUE schedMeasReportPerUE = recvPdu.getBody().getSchedMeasReportPerUE();
786 handleSchedmeasreportperue(schedMeasReportPerUE);
slowr13fa5b02017-08-08 16:32:31 -0700787 break;
788 }
slowr8ddc2b12017-08-14 14:13:38 -0700789 case 21: {
slowr577f3222017-08-28 10:49:08 -0700790 SchedMeasReportPerCell schedMeasReportPerCell = recvPdu.getBody().getSchedMeasReportPerCell();
791 handleSchedmeasreportpercell(schedMeasReportPerCell);
slowr13fa5b02017-08-08 16:32:31 -0700792 break;
793 }
slowr8ddc2b12017-08-14 14:13:38 -0700794 case 22: {
slowr577f3222017-08-28 10:49:08 -0700795 PDCPMeasReportPerUe pdcpMeasReportPerUe = recvPdu.getBody().getPDCPMeasReportPerUe();
796 handlePdcpmeasreportperue(pdcpMeasReportPerUe);
slowr13fa5b02017-08-08 16:32:31 -0700797 break;
798 }
slowr8ddc2b12017-08-14 14:13:38 -0700799 case 24: {
800 // Decode UE Capability Info
slowr577f3222017-08-28 10:49:08 -0700801 UECapabilityInfo capabilityInfo = recvPdu.getBody().getUECapabilityInfo();
802 handleCapabilityinfo(capabilityInfo);
slowr8ddc2b12017-08-14 14:13:38 -0700803 break;
804 }
805 case 25: {
806 // Don't know what will invoke sending UE CAPABILITY ENQUIRY
807 // Encode and send UE CAPABILITY ENQUIRY
slowr577f3222017-08-28 10:49:08 -0700808 UECapabilityEnquiry ueCapabilityEnquiry = recvPdu.getBody().getUECapabilityEnquiry();
809 handleUecapabilityenquiry(ueCapabilityEnquiry, ctx);
slowr8ddc2b12017-08-14 14:13:38 -0700810 break;
811 }
slowr89c2ac12017-08-15 16:20:06 -0700812 case 27: {
813 //Decode ScellAddStatus
slowr577f3222017-08-28 10:49:08 -0700814 ScellAddStatus scellAddStatus = recvPdu.getBody().getScellAddStatus();
815 handleScelladdstatus(scellAddStatus);
slowr89c2ac12017-08-15 16:20:06 -0700816 break;
817 }
slowr8ddc2b12017-08-14 14:13:38 -0700818 case 30: {
819 // Decode RRMConfig Status
slowr577f3222017-08-28 10:49:08 -0700820 RRMConfigStatus rrmConfigStatus = recvPdu.getBody().getRRMConfigStatus();
821 handleRrmconfigstatus(rrmConfigStatus);
slowr67d05e42017-08-11 20:37:22 -0700822 break;
823 }
slowr8ddc2b12017-08-14 14:13:38 -0700824 //TODO Case 31: SeNBAdd 32: SeNBAddStatus 33: SeNBDelete
slowr13fa5b02017-08-08 16:32:31 -0700825 case 34: {
slowr577f3222017-08-28 10:49:08 -0700826 TrafficSplitConfig trafficSplitConfig = recvPdu.getBody().getTrafficSplitConfig();
827 handleTrafficSplitConfig(trafficSplitConfig);
slowr67d05e42017-08-11 20:37:22 -0700828 break;
slowr13fa5b02017-08-08 16:32:31 -0700829 }
830 default: {
slowr577f3222017-08-28 10:49:08 -0700831 log.warn("Wrong API ID: {}", recvPdu);
slowr67d05e42017-08-11 20:37:22 -0700832 break;
slowr13fa5b02017-08-08 16:32:31 -0700833 }
834 }
835
836 }
slowrc86750e2017-08-22 17:26:47 -0700837
slowr577f3222017-08-28 10:49:08 -0700838 /**
839 * Handle Cellconfigreport.
840 * @param report CellConfigReport
841 * @param version String version ID
842 */
843 private void handleCellconfigreport(CellConfigReport report, String version) {
844 ECGI ecgi = report.getEcgi();
845
846 RnibCell cell = xranStore.getCell(ecgi);
847 cell.setVersion(version);
848 cell.setConf(report);
849 cellMap.putPciArfcn(cell);
850 }
851
852 /**
853 * Handle Ueadmissionrequest.
854 * @param ueAdmissionRequest UEAdmissionRequest
855 * @param ctx ChannelHandlerContext
856 * @throws IOException IO Exception
857 */
858 private void handleUeadmissionrequest(UEAdmissionRequest ueAdmissionRequest, ChannelHandlerContext ctx)
859 throws IOException {
860 ECGI ecgi = ueAdmissionRequest.getEcgi();
861 if (xranStore.getCell(ecgi) != null) {
862 CRNTI crnti = ueAdmissionRequest.getCrnti();
863 XrancPdu sendPdu = UEAdmissionResponse.constructPacket(ecgi, crnti, xranConfig.admissionFlag());
864 ctx.writeAndFlush(getSctpMessage(sendPdu));
865 } else {
866 log.warn("Could not find ECGI in registered cells: {}", ecgi);
867 }
868 }
869
870 /**
871 * Handle UEAdmissionStatus.
872 * @param ueAdmissionStatus UEAdmissionStatus
873 * @param ctx ChannelHandlerContext
874 */
875 private void handleAdmissionstatus(UEAdmissionStatus ueAdmissionStatus, ChannelHandlerContext ctx) {
876 RnibUe ue = ueMap.get(ueAdmissionStatus.getEcgi(), ueAdmissionStatus.getCrnti());
877 if (ue != null) {
878 if (ueAdmissionStatus.getAdmEstStatus().value.intValue() == 0) {
879 ue.setState(RnibUe.State.ACTIVE);
880 } else {
881 ue.setState(RnibUe.State.IDLE);
882 }
883 }
884
885 if (ueAdmissionStatus.getAdmEstStatus().value.intValue() == 0) {
886 EcgiCrntiPair ecgiCrntiPair = EcgiCrntiPair
887 .valueOf(ueAdmissionStatus.getEcgi(), ueAdmissionStatus.getCrnti());
888 contextUpdateMap.compute(ecgiCrntiPair, (k, v) -> {
889 if (v == null) {
890 v = new ContextUpdateHandler();
891 }
892 if (v.setAdmissionStatus(ueAdmissionStatus)) {
893 handleContextUpdate(v.getContextUpdate(), ctx, false);
894 }
895 return v;
896 });
897 }
898 }
899
900 /**
901 * Handle UEContextUpdate.
902 * @param ueContextUpdate UEContextUpdate
903 * @param ctx ChannelHandlerContext
904 */
905 private void handleUecontextupdate(UEContextUpdate ueContextUpdate, ChannelHandlerContext ctx) {
906 EcgiCrntiPair ecgiCrntiPair = EcgiCrntiPair
907 .valueOf(ueContextUpdate.getEcgi(), ueContextUpdate.getCrnti());
908
909 contextUpdateMap.compute(ecgiCrntiPair, (k, v) -> {
910 if (v == null) {
911 v = new ContextUpdateHandler();
912 }
913 if (v.setContextUpdate(ueContextUpdate)) {
914 HOComplete hoComplete = v.getHoComplete();
915 handleContextUpdate(ueContextUpdate, ctx, hoComplete != null);
916 if (hoComplete != null) {
917 try {
918 hoMap.get(hoComplete.getEcgiS()).put("Hand Over Completed");
919 } catch (InterruptedException e) {
920 log.error(ExceptionUtils.getFullStackTrace(e));
921 e.printStackTrace();
922 } finally {
923 hoMap.remove(hoComplete.getEcgiS());
924 }
925 }
926 }
927 return v;
928 });
929 }
930
931 /**
932 * Handle UEReconfigInd.
933 * @param ueReconfigInd UEReconfigInd
934 */
935 private void handleUereconfigind(UEReconfigInd ueReconfigInd) {
936 RnibUe ue = ueMap.get(ueReconfigInd.getEcgi(), ueReconfigInd.getCrntiOld());
937 RnibCell cell = cellMap.get(ueReconfigInd.getEcgi());
938
939 if (ue != null && cell != null) {
940 ue.setCrnti(ueReconfigInd.getCrntiNew());
941 ueMap.putCrnti(cell, ue);
942 } else {
943 log.warn("Could not find UE with this CRNTI: {}", ueReconfigInd.getCrntiOld());
944 }
945 }
946
947 /**
948 * Handle UEReleaseInd.
949 * @param ueReleaseInd UEReleaseInd
950 */
951 private void handleUereleaseind(UEReleaseInd ueReleaseInd) {
952 ECGI ecgi = ueReleaseInd.getEcgi();
953 CRNTI crnti = ueReleaseInd.getCrnti();
954 RnibUe ue = ueMap.get(ecgi, crnti);
955
956 // Check if there is an ongoing handoff and only remove if ue is not part of the handoff.
957 Long peek = ueIdQueue.peek();
958 if (peek != null) {
959 EcgiCrntiPair ecgiCrntiPair = ueMap.getCrntUe().inverse().get(peek);
960 if (ecgiCrntiPair != null && ecgiCrntiPair.equals(EcgiCrntiPair.valueOf(ecgi, crnti))) {
961 return;
962 }
963 }
964
965 if (ue != null) {
966 ue.setState(RnibUe.State.IDLE);
967 restartTimer(ue);
968 } else {
969 log.warn("Cannot release UE from non primary link.");
970 }
971 }
972
973 /**
974 * Handle BearerAdmissionRequest.
975 * @param bearerAdmissionRequest BearerAdmissionRequest
976 * @param ctx ChannelHandlerContext
977 * @throws IOException IO Exception
978 */
979 private void handleBeareradmissionrequest(BearerAdmissionRequest bearerAdmissionRequest,
980 ChannelHandlerContext ctx) throws IOException {
981 ECGI ecgi = bearerAdmissionRequest.getEcgi();
982 CRNTI crnti = bearerAdmissionRequest.getCrnti();
983 ERABParams erabParams = bearerAdmissionRequest.getErabParams();
984 RnibLink link = linkMap.get(ecgi, crnti);
985 if (link != null) {
986 link.setBearerParameters(erabParams);
987 } else {
988 log.warn("Could not find link between {}-{}", ecgi, crnti);
989 }
990
991 BerInteger numErabs = bearerAdmissionRequest.getNumErabs();
992 // Encode and send Bearer Admission Response
993 XrancPdu sendPdu = BearerAdmissionResponse
994 .constructPacket(ecgi, crnti, erabParams, numErabs, xranConfig.bearerFlag());
995 ctx.writeAndFlush(getSctpMessage(sendPdu));
996 }
997
998 /**
999 * Handle BearerReleaseInd.
1000 * @param bearerReleaseInd
1001 */
1002 private void handleBearerreleaseind(BearerReleaseInd bearerReleaseInd) {
1003 ECGI ecgi = bearerReleaseInd.getEcgi();
1004 CRNTI crnti = bearerReleaseInd.getCrnti();
1005 RnibLink link = linkMap.get(ecgi, crnti);
1006
1007 List<ERABID> erabidsRelease = bearerReleaseInd.getErabIds().getERABID();
1008 List<ERABParamsItem> erabParamsItem = link.getBearerParameters().getERABParamsItem();
1009
1010 List<ERABParamsItem> unreleased = erabParamsItem
1011 .stream()
1012 .filter(item -> {
1013 Optional<ERABID> any = erabidsRelease.stream()
1014 .filter(id -> id.equals(item.getId())).findAny();
1015 return !any.isPresent();
1016 }).collect(Collectors.toList());
1017
1018 link.getBearerParameters().setERABParamsItem(new ArrayList<>(unreleased));
1019 }
1020
1021 /**
1022 * Handle HOFailure.
1023 * @param hoFailure HOFailure
1024 * @throws InterruptedException ueIdQueue interruption
1025 */
1026 private void handleHofailure(HOFailure hoFailure) throws InterruptedException {
1027 try {
1028 hoMap.get(hoFailure.getEcgi())
1029 .put("Hand Over Failed with cause: " + hoFailure.getCause());
1030 } catch (InterruptedException e) {
1031 log.error(ExceptionUtils.getFullStackTrace(e));
1032 e.printStackTrace();
1033 } finally {
1034 hoMap.remove(hoFailure.getEcgi());
1035 ueIdQueue.take();
1036 }
1037 }
1038
1039 /**
1040 * Handle HOComplete.
1041 * @param hoComplete HOComplete
1042 * @param ctx ChannelHandlerContext
1043 */
1044 private void handleHocomplete(HOComplete hoComplete, ChannelHandlerContext ctx) {
1045 EcgiCrntiPair ecgiCrntiPair = EcgiCrntiPair.valueOf(hoComplete.getEcgiT(),
1046 hoComplete.getCrntiNew());
1047 contextUpdateMap.compute(ecgiCrntiPair, (k, v) -> {
1048 if (v == null) {
1049 v = new ContextUpdateHandler();
1050 }
1051 if (v.setHoComplete(hoComplete)) {
1052 handleContextUpdate(v.getContextUpdate(), ctx, true);
1053
1054 try {
1055 hoMap.get(hoComplete.getEcgiS()).put("Hand Over Completed");
1056 } catch (InterruptedException e) {
1057 log.error(ExceptionUtils.getFullStackTrace(e));
1058 e.printStackTrace();
1059 } finally {
1060 hoMap.remove(hoComplete.getEcgiS());
1061 }
1062 }
1063 return v;
1064 });
1065 }
1066
1067 /**
1068 * Handle RXSigMeasReport.
1069 * @param rxSigMeasReport RXSigMeasReport
1070 */
1071 private void handleRxsigmeasreport(RXSigMeasReport rxSigMeasReport) {
1072 List<RXSigReport> rxSigReportList = rxSigMeasReport.getCellMeasReports().getRXSigReport();
1073
1074 RnibUe ue = ueMap.get(rxSigMeasReport.getEcgi(), rxSigMeasReport.getCrnti());
1075 if (ue != null) {
1076 Long ueId = ue.getId();
1077
1078 if (!rxSigReportList.isEmpty()) {
1079 rxSigReportList.forEach(rxSigReport -> {
1080 RnibCell cell = cellMap.get(rxSigReport.getPciArfcn());
1081 if (cell != null) {
1082 ECGI ecgi = cell.getEcgi();
1083
1084 RnibLink link = linkMap.get(ecgi, ueId);
1085 if (link == null) {
1086 log.warn("Could not find link between: {}-{} | Creating non-serving link..",
1087 ecgi, ueId);
1088 link = linkMap.putNonServingLink(cell, ueId);
1089 }
1090
1091 if (link != null) {
1092 if (link.getType().equals(RnibLink.Type.NON_SERVING)) {
1093 restartTimer(link);
1094 }
1095
1096 RSRQRange rsrq = rxSigReport.getRsrq();
1097 RSRPRange rsrp = rxSigReport.getRsrp();
1098
1099 RnibLink.LinkQuality quality = link.getQuality();
1100 quality.setRx(new RnibLink.LinkQuality.Rx(
1101 rsrp.value.intValue() - 140,
1102 (rsrq.value.intValue() * 0.5) - 19.5
1103 ));
1104 }
1105 } else {
1106 log.warn("case 16: Could not find cell with PCI-ARFCN: {}",
1107 rxSigReport.getPciArfcn());
1108 }
1109 });
1110 }
1111 }
1112 }
1113
1114 /**
1115 * Handle RadioMeasReportPerUE.
1116 * @param radioMeasReportPerUE RadioMeasReportPerUE
1117 */
1118 private void handleRadionmeasreportperue(RadioMeasReportPerUE radioMeasReportPerUE) {
1119 RnibUe ue = ueMap.get(radioMeasReportPerUE.getEcgi(), radioMeasReportPerUE.getCrnti());
1120 if (ue != null) {
1121 Long ueId = ue.getId();
1122 List<RadioRepPerServCell> servCells = radioMeasReportPerUE.getRadioReportServCells()
1123 .getRadioRepPerServCell();
1124
1125 servCells.forEach(servCell -> {
1126 RnibCell cell = cellMap.get(servCell.getPciArfcn());
1127 if (cell != null) {
1128 RnibLink link = linkMap.get(cell.getEcgi(), ueId);
1129 if (link != null) {
1130 RadioRepPerServCell.CqiHist cqiHist = servCell.getCqiHist();
1131 RnibLink.LinkQuality quality = link.getQuality();
1132
1133 final double[] values = {0, 0, 0};
1134 final int[] i = {1};
1135 cqiHist.getBerInteger().forEach(value -> {
1136 values[0] = Math.max(values[0], value.intValue());
1137 values[1] += i[0] * value.intValue();
1138 values[2] += value.intValue();
1139 i[0]++;
1140 });
1141
1142 quality.setCqi(new RnibLink.LinkQuality.Cqi(
1143 cqiHist,
1144 values[0],
1145 values[1] / values[0]
1146 ));
1147
1148 } else {
1149 log.warn("Could not find link between: {}-{}", cell.getEcgi(), ueId);
1150 }
1151 } else {
1152 log.warn("case 18: Could not find cell with PCI-ARFCN: {}", servCell.getPciArfcn());
1153 }
1154 });
1155 }
1156 }
1157
1158 /**
1159 * Handle SchedMeasReportPerUE.
1160 * @param schedMeasReportPerUE SchedMeasReportPerUE
1161 */
1162 private void handleSchedmeasreportperue(SchedMeasReportPerUE schedMeasReportPerUE) {
1163 RnibUe ue = ueMap.get(schedMeasReportPerUE.getEcgi(), schedMeasReportPerUE.getCrnti());
1164 if (ue != null) {
1165 Long ueId = ue.getId();
1166
1167 List<SchedMeasRepPerServCell> servCells = schedMeasReportPerUE.getSchedReportServCells()
1168 .getSchedMeasRepPerServCell();
1169
1170 servCells.forEach(servCell -> {
1171 RnibCell cell = cellMap.get(servCell.getPciArfcn());
1172 if (cell != null) {
1173 RnibLink link = linkMap.get(cell.getEcgi(), ueId);
1174 if (link != null) {
1175 link.getQuality().setMcs(new RnibLink.LinkQuality.Mcs(
1176 servCell.getMcsDl(),
1177 servCell.getMcsUl()
1178 ));
1179
1180 link.setResourceUsage(new RnibLink.ResourceUsage(
1181 servCell.getPrbUsage().getPrbUsageDl(),
1182 servCell.getPrbUsage().getPrbUsageUl()
1183 ));
1184 } else {
1185 log.warn("Could not find link between: {}-{}", cell.getEcgi(), ueId);
1186 }
1187 } else {
1188 log.warn("case 20: Could not find cell with PCI-ARFCN: {}", servCell.getPciArfcn());
1189 }
1190 });
1191 }
1192 }
1193
1194 /**
1195 * Handle SchedMeasReportPerCell.
1196 * @param schedMeasReportPerCell SchedMeasReportPerCell
1197 */
1198 private void handleSchedmeasreportpercell(SchedMeasReportPerCell schedMeasReportPerCell) {
1199 RnibCell cell = cellMap.get(schedMeasReportPerCell.getEcgi());
1200 if (cell != null) {
1201 cell.setPrbUsage(new RnibCell.PrbUsageContainer(
1202 schedMeasReportPerCell.getPrbUsagePcell(),
1203 schedMeasReportPerCell.getPrbUsageScell()
1204 ));
1205
1206 cell.setQci(schedMeasReportPerCell.getQciVals());
1207 } else {
1208 log.warn("Could not find cell with ECGI: {}", schedMeasReportPerCell.getEcgi());
1209 }
1210 }
1211
1212 /**
1213 * Handle PDCPMeasReportPerUe.
1214 * @param pdcpMeasReportPerUe PDCPMeasReportPerUe
1215 */
1216 private void handlePdcpmeasreportperue(PDCPMeasReportPerUe pdcpMeasReportPerUe) {
1217 RnibUe ue = ueMap.get(pdcpMeasReportPerUe.getEcgi(), pdcpMeasReportPerUe.getCrnti());
1218 if (ue != null) {
1219 Long ueId = ue.getId();
1220 RnibLink link = linkMap.get(pdcpMeasReportPerUe.getEcgi(), ueId);
1221 if (link != null) {
1222 link.setPdcpThroughput(new RnibLink.PdcpThroughput(
1223 pdcpMeasReportPerUe.getThroughputDl(),
1224 pdcpMeasReportPerUe.getThroughputUl()
1225 ));
1226
1227 link.setPdcpPackDelay(new RnibLink.PdcpPacketdelay(
1228 pdcpMeasReportPerUe.getPktDelayDl(),
1229 pdcpMeasReportPerUe.getPktDelayUl()
1230 ));
1231 } else {
1232 log.warn("Could not find link between: {}-{}", pdcpMeasReportPerUe.getEcgi(), ueId);
1233 }
1234 }
1235 }
1236
1237 /**
1238 * Handle UECapabilityInfo.
1239 * @param capabilityInfo UECapabilityInfo
1240 */
1241 private void handleCapabilityinfo(UECapabilityInfo capabilityInfo) {
1242 RnibUe ue = ueMap.get(capabilityInfo.getEcgi(), capabilityInfo.getCrnti());
1243 if (ue != null) {
1244 ue.setCapability(capabilityInfo);
1245 } else {
1246 log.warn("Could not find UE with this CRNTI: {}", capabilityInfo.getCrnti());
1247 }
1248 }
1249
1250 /**
1251 * Handle UECapabilityEnquiry.
1252 * @param ueCapabilityEnquiry UECapabilityEnquiry
1253 * @param ctx ChannelHandlerContext
1254 * @throws IOException IO Exception
1255 */
1256 private void handleUecapabilityenquiry(UECapabilityEnquiry ueCapabilityEnquiry, ChannelHandlerContext ctx)
1257 throws IOException {
1258 XrancPdu xrancPdu = UECapabilityEnquiry.constructPacket(ueCapabilityEnquiry.getEcgi(),
1259 ueCapabilityEnquiry.getCrnti());
1260 ctx.writeAndFlush(getSctpMessage(xrancPdu));
1261 }
1262
1263 /**
1264 * Handle ScellAddStatus.
1265 * @param scellAddStatus ScellAddStatus
1266 */
1267 private void handleScelladdstatus(ScellAddStatus scellAddStatus) {
1268 RnibUe ue = ueMap.get(scellAddStatus.getEcgi(), scellAddStatus.getCrnti());
1269 if (ue != null) {
1270 Long ueId = ue.getId();
1271 try {
1272 scellAddMap.get(scellAddStatus.getCrnti()).put("Scell's status: " +
1273 scellAddStatus.getStatus());
1274 final int[] i = {0};
1275 scellAddStatus.getScellsInd().getPCIARFCN().forEach(
1276 pciarfcn -> {
1277 if (scellAddStatus.getStatus().getBerEnum().get(i[0]).value.intValue() == 0) {
1278 RnibCell cell = cellMap.get(pciarfcn);
1279 RnibLink link = linkMap.get(cell.getEcgi(), ueId);
1280 link.setType(RnibLink.Type.SERVING_SECONDARY_CA);
1281 }
1282 i[0]++;
1283 }
1284 );
1285
1286 } catch (InterruptedException e) {
1287 log.error(ExceptionUtils.getFullStackTrace(e));
1288 e.printStackTrace();
1289 } finally {
1290 scellAddMap.remove(scellAddStatus.getCrnti());
1291 }
1292 }
1293 }
1294
1295 /**
1296 * Handle RRMConfigStatus.
1297 * @param rrmConfigStatus RRMConfigStatus
1298 */
1299 private void handleRrmconfigstatus(RRMConfigStatus rrmConfigStatus) {
1300 try {
1301 rrmcellMap.get(rrmConfigStatus.getEcgi())
1302 .put("RRM Config's status: " + rrmConfigStatus.getStatus());
1303 } catch (InterruptedException e) {
1304 log.error(ExceptionUtils.getFullStackTrace(e));
1305 e.printStackTrace();
1306 } finally {
1307 rrmcellMap.remove(rrmConfigStatus.getEcgi());
1308 }
1309 }
1310
1311 /**
1312 * Handle TrafficSplitConfig.
1313 * @param trafficSplitConfig TrafficSplitConfig
1314 */
1315 private void handleTrafficSplitConfig(TrafficSplitConfig trafficSplitConfig) {
1316 RnibUe ue = ueMap.get(trafficSplitConfig.getEcgi(), trafficSplitConfig.getCrnti());
1317 if (ue != null) {
1318 Long ueId = ue.getId();
1319 List<TrafficSplitPercentage> splitPercentages = trafficSplitConfig
1320 .getTrafficSplitPercent().getTrafficSplitPercentage();
1321
1322 splitPercentages.forEach(trafficSplitPercentage -> {
1323 RnibCell cell = cellMap.get(trafficSplitPercentage.getEcgi());
1324 if (cell != null) {
1325 RnibLink link = linkMap.get(cell.getEcgi(), ueId);
1326 if (link != null) {
1327 link.setTrafficPercent(trafficSplitPercentage);
1328 } else {
1329 log.warn("Could not find link between: {}-{}", cell.getEcgi(), ueId);
1330 }
1331 } else {
1332 log.warn("Could not find cell with ECGI: {}", trafficSplitConfig.getEcgi());
1333 }
1334 });
1335 }
1336 }
1337
1338 /**
1339 * Handle context update depending if its handoff or not.
1340 *
1341 * @param contextUpdate context update packet
1342 * @param ctx channel context for the CELL
1343 * @param handoff true if we handle a Hand Off
1344 */
slowrc86750e2017-08-22 17:26:47 -07001345 private void handleContextUpdate(UEContextUpdate contextUpdate, ChannelHandlerContext ctx, boolean handoff) {
1346 RnibUe ue;
1347 RnibCell cell = xranStore.getCell(contextUpdate.getEcgi());
1348
1349 if (handoff) {
1350 try {
1351 ue = ueMap.get(ueIdQueue.take());
1352 } catch (InterruptedException e) {
1353 e.printStackTrace();
1354 log.error(ExceptionUtils.getFullStackTrace(e));
1355 ue = new RnibUe();
1356 }
1357 } else {
1358 ue = new RnibUe();
1359 }
1360
1361 ue.setMmeS1apId(contextUpdate.getMMEUES1APID());
1362 ue.setEnbS1apId(contextUpdate.getENBUES1APID());
1363 ue.setCrnti(contextUpdate.getCrnti());
1364
1365 hostAgent.addConnectedHost(ue, cell, ctx);
1366 }
slowr13fa5b02017-08-08 16:32:31 -07001367 }
1368
slowr577f3222017-08-28 10:49:08 -07001369 /**
1370 * Internal class for NetworkConfigListener.
1371 */
slowr13fa5b02017-08-08 16:32:31 -07001372 class InternalNetworkConfigListener implements NetworkConfigListener {
1373
1374 @Override
1375 public void event(NetworkConfigEvent event) {
1376 switch (event.type()) {
1377 case CONFIG_REGISTERED:
1378 break;
1379 case CONFIG_UNREGISTERED:
1380 break;
1381 case CONFIG_ADDED:
1382 case CONFIG_UPDATED:
1383 if (event.configClass() == CONFIG_CLASS) {
1384 handleConfigEvent(event.config());
1385 }
1386 break;
1387 case CONFIG_REMOVED:
1388 break;
1389 default:
1390 break;
1391 }
1392 }
1393
slowr577f3222017-08-28 10:49:08 -07001394 /**
1395 * Handle config event.
1396 *
1397 * @param config
1398 */
slowr13fa5b02017-08-08 16:32:31 -07001399 private void handleConfigEvent(Optional<Config> config) {
1400 if (!config.isPresent()) {
1401 return;
1402 }
1403
1404 xranConfig = (XranConfig) config.get();
1405
slowr577f3222017-08-28 10:49:08 -07001406 northboundTimeout = xranConfig.getNorthBoundTimeout();
slowrd337c932017-08-18 13:54:02 -07001407
slowr13fa5b02017-08-08 16:32:31 -07001408 legitCells.putAll(xranConfig.activeCellSet());
1409
1410 controller.start(deviceAgent, hostAgent, packetAgent, xranConfig.getXrancPort());
1411 }
1412 }
1413}