blob: 47af1f1723ae5460f920263c33946856f58cda70 [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<>();
slowrab685ef2017-08-31 17:17:35 -0700178 // Map used to keep messages in pairs (HO Complete - CTX Update, Adm Status - CTX Update)
slowr577f3222017-08-28 10:49:08 -0700179 private ConcurrentMap<EcgiCrntiPair, ContextUpdateHandler> contextUpdateMap = new ConcurrentHashMap<>();
slowrc86750e2017-08-22 17:26:47 -0700180 /* QUEUE */
181 private BlockingQueue<Long> ueIdQueue = new LinkedBlockingQueue<>();
slowr13fa5b02017-08-08 16:32:31 -0700182 /* AGENTS */
183 private InternalXranDeviceAgent deviceAgent = new InternalXranDeviceAgent();
184 private InternalXranHostAgent hostAgent = new InternalXranHostAgent();
185 private InternalXranPacketAgent packetAgent = new InternalXranPacketAgent();
186 /* LISTENERS */
187 private Set<XranDeviceListener> xranDeviceListeners = new CopyOnWriteArraySet<>();
188 private Set<XranHostListener> xranHostListeners = new CopyOnWriteArraySet<>();
slowr577f3222017-08-28 10:49:08 -0700189 private InternalDeviceListener deviceListener = new InternalDeviceListener();
190 private InternalHostListener hostListener = new InternalHostListener();
slowr13fa5b02017-08-08 16:32:31 -0700191
192 @Activate
193 public void activate() {
194 appId = coreService.registerApplication(XRAN_APP_ID);
195
196 configService.addListener(configListener);
197 registry.registerConfigFactory(xranConfigFactory);
slowr577f3222017-08-28 10:49:08 -0700198 deviceService.addListener(deviceListener);
199 hostService.addListener(hostListener);
slowr13fa5b02017-08-08 16:32:31 -0700200
201 cellMap = new CellMap(xranStore);
202 ueMap = new UeMap(xranStore);
slowrd337c932017-08-18 13:54:02 -0700203 linkMap = new LinkMap(xranStore, ueMap);
slowr13fa5b02017-08-08 16:32:31 -0700204
205 xranStore.setController(this);
206
207 log.info("XRAN Controller Started");
208 }
209
210 @Deactivate
211 public void deactivate() {
212 controller.stop();
213
slowr577f3222017-08-28 10:49:08 -0700214 deviceService.removeListener(deviceListener);
215 hostService.removeListener(hostListener);
slowr13fa5b02017-08-08 16:32:31 -0700216
217 legitCells.clear();
218
219 configService.removeListener(configListener);
220 registry.unregisterConfigFactory(xranConfigFactory);
221
222 log.info("XRAN Controller Stopped");
223 }
224
225 @Override
slowr577f3222017-08-28 10:49:08 -0700226 public SynchronousQueue<String> sendHORequest(RnibLink linkT, RnibLink linkS) throws InterruptedException {
227 ECGI ecgiT = linkT.getLinkId().getEcgi(),
228 ecgiS = linkS.getLinkId().getEcgi();
slowr73b4eae2017-08-17 16:09:09 -0700229
slowr577f3222017-08-28 10:49:08 -0700230 CRNTI crnti = linkMap.getCrnti(linkT.getLinkId().getUeId());
231 ChannelHandlerContext ctxT = cellMap.getCtx(ecgiT),
232 ctxS = cellMap.getCtx(ecgiS);
slowrc86750e2017-08-22 17:26:47 -0700233
234 SynchronousQueue<String> queue = new SynchronousQueue<>();
slowr67d05e42017-08-11 20:37:22 -0700235 try {
slowr577f3222017-08-28 10:49:08 -0700236 XrancPdu xrancPdu = HORequest.constructPacket(crnti, ecgiS, ecgiT);
slowrc86750e2017-08-22 17:26:47 -0700237
slowr577f3222017-08-28 10:49:08 -0700238 // temporary map that has ECGI source of a handoff to a queue waiting for REST response.
239 hoMap.put(ecgiS, queue);
slowrc86750e2017-08-22 17:26:47 -0700240
slowr577f3222017-08-28 10:49:08 -0700241 ctxT.writeAndFlush(getSctpMessage(xrancPdu));
242 ctxS.writeAndFlush(getSctpMessage(xrancPdu));
243
244 // FIXME: only works for one HO at a time.
245 ueIdQueue.put(linkT.getLinkId().getUeId());
slowr67d05e42017-08-11 20:37:22 -0700246 } catch (IOException e) {
247 e.printStackTrace();
248 }
249
slowr67d05e42017-08-11 20:37:22 -0700250 return queue;
251 }
252
253 @Override
slowr13fa5b02017-08-08 16:32:31 -0700254 public void addListener(XranDeviceListener listener) {
255 xranDeviceListeners.add(listener);
256 }
257
258 @Override
259 public void addListener(XranHostListener listener) {
260 xranHostListeners.add(listener);
261 }
262
263 @Override
264 public void removeListener(XranDeviceListener listener) {
265 xranDeviceListeners.remove(listener);
266 }
267
268 @Override
269 public void removeListener(XranHostListener listener) {
270 xranHostListeners.remove(listener);
271 }
272
slowr67d05e42017-08-11 20:37:22 -0700273 @Override
slowr577f3222017-08-28 10:49:08 -0700274 public int getNorthboundTimeout() {
275 return northboundTimeout;
slowrc86750e2017-08-22 17:26:47 -0700276 }
277
278 @Override
slowr577f3222017-08-28 10:49:08 -0700279 public SynchronousQueue<String> sendmodifiedrrmconf(RRMConfig rrmConfig, boolean xicic) {
slowr8ddc2b12017-08-14 14:13:38 -0700280 ECGI ecgi = rrmConfig.getEcgi();
slowr67d05e42017-08-11 20:37:22 -0700281 ChannelHandlerContext ctx = cellMap.getCtx(ecgi);
282 try {
slowrc86750e2017-08-22 17:26:47 -0700283 XrancPdu pdu;
slowr73b4eae2017-08-17 16:09:09 -0700284
slowr577f3222017-08-28 10:49:08 -0700285 if (xicic) {
slowr73b4eae2017-08-17 16:09:09 -0700286 CellConfigReport cellConfigReport = cellMap.get(ecgi).getConf();
287 if (cellConfigReport != null) {
288 pdu = XICICConfig.constructPacket(rrmConfig, cellConfigReport);
289 ctx.writeAndFlush(getSctpMessage(pdu));
290 }
slowr8ddc2b12017-08-14 14:13:38 -0700291 } else {
292 pdu = RRMConfig.constructPacket(rrmConfig);
slowr73b4eae2017-08-17 16:09:09 -0700293 ctx.writeAndFlush(getSctpMessage(pdu));
294 SynchronousQueue<String> queue = new SynchronousQueue<>();
slowr577f3222017-08-28 10:49:08 -0700295 rrmcellMap.put(ecgi, queue);
slowr73b4eae2017-08-17 16:09:09 -0700296 return queue;
slowr8ddc2b12017-08-14 14:13:38 -0700297 }
slowr67d05e42017-08-11 20:37:22 -0700298 } catch (IOException e) {
299 e.printStackTrace();
300 }
slowr67d05e42017-08-11 20:37:22 -0700301
slowr73b4eae2017-08-17 16:09:09 -0700302 return null;
slowr67d05e42017-08-11 20:37:22 -0700303 }
304
slowr89c2ac12017-08-15 16:20:06 -0700305 @Override
306 public SynchronousQueue<String> sendScellAdd(RnibLink link) {
307 RnibCell secondaryCell = link.getLinkId().getCell(),
308 primaryCell = linkMap.getPrimaryCell(link.getLinkId().getUe());
309 ECGI primaryEcgi = primaryCell.getEcgi();
310 ChannelHandlerContext ctx = cellMap.getCtx(primaryEcgi);
311
slowrc86750e2017-08-22 17:26:47 -0700312 CRNTI crnti = linkMap.getCrnti(link.getLinkId().getUeId());
slowr89c2ac12017-08-15 16:20:06 -0700313
314 CellConfigReport cellReport = secondaryCell.getConf();
315
316 if (cellReport != null) {
317 PCIARFCN pciarfcn = new PCIARFCN();
318 pciarfcn.setPci(cellReport.getPci());
319 pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
320
321 PropScell propScell = new PropScell();
322 propScell.setPciArfcn(pciarfcn);
323
324 XrancPdu pdu = ScellAdd.constructPacket(primaryEcgi, crnti, propScell);
325 try {
326 ctx.writeAndFlush(getSctpMessage(pdu));
327 SynchronousQueue<String> queue = new SynchronousQueue<>();
slowrc86750e2017-08-22 17:26:47 -0700328 scellAddMap.put(crnti, queue);
slowr89c2ac12017-08-15 16:20:06 -0700329
330 return queue;
331 } catch (IOException e) {
332 log.error(ExceptionUtils.getFullStackTrace(e));
333 e.printStackTrace();
334 }
335 }
336 return null;
337 }
338
339 @Override
340 public boolean sendScellDelete(RnibLink link) {
341 RnibCell secondaryCell = link.getLinkId().getCell(),
342 primaryCell = linkMap.getPrimaryCell(link.getLinkId().getUe());
343 ECGI primaryEcgi = primaryCell.getEcgi();
344 ChannelHandlerContext ctx = cellMap.getCtx(primaryEcgi);
345
slowrc86750e2017-08-22 17:26:47 -0700346 CRNTI crnti = linkMap.getCrnti(link.getLinkId().getUeId());
slowr89c2ac12017-08-15 16:20:06 -0700347
348 CellConfigReport cellReport = secondaryCell.getConf();
349
350 if (cellReport != null) {
351 PCIARFCN pciarfcn = new PCIARFCN();
352 pciarfcn.setPci(cellReport.getPci());
353 pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
354
355 XrancPdu pdu = ScellDelete.constructPacket(primaryEcgi, crnti, pciarfcn);
356
357 try {
358 ctx.writeAndFlush(getSctpMessage(pdu));
359 link.setType(RnibLink.Type.NON_SERVING);
360 return true;
361 } catch (IOException e) {
362 log.error(ExceptionUtils.getFullStackTrace(e));
363 e.printStackTrace();
364 }
365 }
366 return false;
367 }
368
slowr577f3222017-08-28 10:49:08 -0700369 /**
370 * Timer to delete UE after being IDLE.
371 *
372 * @param ue UE entity
373 */
slowr13fa5b02017-08-08 16:32:31 -0700374 private void restartTimer(RnibUe ue) {
375 Timer timer = new Timer();
376 ue.setTimer(timer);
slowr13fa5b02017-08-08 16:32:31 -0700377 timer.schedule(new TimerTask() {
378 @Override
379 public void run() {
slowr67d05e42017-08-11 20:37:22 -0700380 if (ue.getState() == RnibUe.State.IDLE) {
slowr13fa5b02017-08-08 16:32:31 -0700381 hostAgent.removeConnectedHost(ue);
slowrc86750e2017-08-22 17:26:47 -0700382 log.info("UE is removed after {} ms of IDLE", xranConfig.getIdleUeRemoval());
slowr13fa5b02017-08-08 16:32:31 -0700383 } else {
384 log.info("UE not removed cause its ACTIVE");
385 }
386 }
slowrd337c932017-08-18 13:54:02 -0700387 }, xranConfig.getIdleUeRemoval());
slowr13fa5b02017-08-08 16:32:31 -0700388 }
389
slowr577f3222017-08-28 10:49:08 -0700390 /**
391 * Timer to delete LINK after not receiving measurements.
392 *
393 * @param link LINK entity
394 */
slowr13fa5b02017-08-08 16:32:31 -0700395 private void restartTimer(RnibLink link) {
396 Timer timer = new Timer();
397 link.setTimer(timer);
slowr13fa5b02017-08-08 16:32:31 -0700398 timer.schedule(new TimerTask() {
399 @Override
400 public void run() {
401 LinkId linkId = link.getLinkId();
402 xranStore.removeLink(linkId);
slowr577f3222017-08-28 10:49:08 -0700403 log.info("Link is removed after not receiving Meas Reports for {} ms",
404 xranConfig.getNoMeasLinkRemoval());
slowr13fa5b02017-08-08 16:32:31 -0700405 }
slowrd337c932017-08-18 13:54:02 -0700406 }, xranConfig.getNoMeasLinkRemoval());
slowr13fa5b02017-08-08 16:32:31 -0700407
408 }
409
slowr577f3222017-08-28 10:49:08 -0700410 /**
411 * Request measurement configuration field of specified UE.
412 *
413 * @param primary primary CELL
414 * @param ue UE entity
415 */
416 private void populateMeasConfig(RnibCell primary, RnibUe ue) {
417 try {
418 ChannelHandlerContext ctx = cellMap.getCtx(primary.getEcgi());
419 RXSigMeasConfig.MeasCells measCells = new RXSigMeasConfig.MeasCells();
420 xranStore.getcellnodes().forEach(cell -> {
421 CellConfigReport cellReport = ((RnibCell) cell).getConf();
422 if (cellReport != null) {
423 PCIARFCN pciarfcn = new PCIARFCN();
424 pciarfcn.setPci(cellReport.getPci());
425 pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
426 measCells.setPCIARFCN(pciarfcn);
427 }
428 });
429 XrancPdu xrancPdu = RXSigMeasConfig.constructPacket(
430 primary.getEcgi(),
431 ue.getCrnti(),
432 measCells,
433 xranConfig.getRxSignalInterval()
434 );
435 ue.setMeasConfig(xrancPdu.getBody().getRXSigMeasConfig());
436 ctx.writeAndFlush(getSctpMessage(xrancPdu));
437 } catch (IOException e) {
438 log.warn(ExceptionUtils.getFullStackTrace(e));
439 e.printStackTrace();
440 }
441 }
442
443 /**
444 * Internal device listener.
445 */
slowr13fa5b02017-08-08 16:32:31 -0700446 class InternalDeviceListener implements DeviceListener {
447
448 @Override
449 public void event(DeviceEvent event) {
450 log.info("Device Event {}", event);
451 switch (event.type()) {
452 case DEVICE_ADDED: {
453 try {
454 ECGI ecgi = decodeDeviceId(event.subject().id());
455 RnibCell cell = cellMap.get(ecgi);
456 if (cell != null) {
457 Timer timer = new Timer();
458 timer.scheduleAtFixedRate(
459 new TimerTask() {
460 @Override
461 public void run() {
462 CellConfigReport conf = cell.getConf();
463 if (conf == null) {
464 try {
465 ChannelHandlerContext ctx = cellMap.getCtx(ecgi);
slowr8ddc2b12017-08-14 14:13:38 -0700466 XrancPdu xrancPdu = CellConfigRequest.constructPacket(ecgi);
slowr67d05e42017-08-11 20:37:22 -0700467 ctx.writeAndFlush(getSctpMessage(xrancPdu));
slowr13fa5b02017-08-08 16:32:31 -0700468 } catch (IOException e) {
469 log.error(ExceptionUtils.getFullStackTrace(e));
470 e.printStackTrace();
471 }
472 } else {
slowr577f3222017-08-28 10:49:08 -0700473 List<Object> ueNodes = xranStore.getuenodes();
slowrd337c932017-08-18 13:54:02 -0700474 ueNodes.forEach(object -> {
475 RnibUe ue = (RnibUe) object;
476 try {
slowr577f3222017-08-28 10:49:08 -0700477 ECGI primaryEcgi = linkMap.getPrimaryCell(ue).getEcgi();
478 ChannelHandlerContext ctx = cellMap.getCtx(primaryEcgi);
479 RXSigMeasConfig.MeasCells measCells =
480 new RXSigMeasConfig.MeasCells();
481 xranStore.getcellnodes().forEach(cell -> {
slowrd337c932017-08-18 13:54:02 -0700482 CellConfigReport cellReport = ((RnibCell) cell).getConf();
483 if (cellReport != null) {
484 PCIARFCN pciarfcn = new PCIARFCN();
485 pciarfcn.setPci(cellReport.getPci());
486 pciarfcn.setEarfcnDl(cellReport.getEarfcnDl());
487 measCells.setPCIARFCN(pciarfcn);
488 }
489 });
490 XrancPdu xrancPdu = RXSigMeasConfig.constructPacket(
slowr577f3222017-08-28 10:49:08 -0700491 primaryEcgi,
slowrc86750e2017-08-22 17:26:47 -0700492 ue.getCrnti(),
slowrd337c932017-08-18 13:54:02 -0700493 measCells,
494 xranConfig.getRxSignalInterval()
495 );
496 ue.setMeasConfig(xrancPdu.getBody().getRXSigMeasConfig());
497 ctx.writeAndFlush(getSctpMessage(xrancPdu));
498 } catch (IOException e) {
499 log.warn(ExceptionUtils.getFullStackTrace(e));
500 e.printStackTrace();
501 }
502 });
503
slowr13fa5b02017-08-08 16:32:31 -0700504 try {
slowrd337c932017-08-18 13:54:02 -0700505 ChannelHandlerContext ctx = cellMap.getCtx(ecgi);
slowr577f3222017-08-28 10:49:08 -0700506 XrancPdu xrancPdu = L2MeasConfig
507 .constructPacket(ecgi, xranConfig.getL2MeasInterval());
slowr13fa5b02017-08-08 16:32:31 -0700508 cell.setMeasConfig(xrancPdu.getBody().getL2MeasConfig());
slowr67d05e42017-08-11 20:37:22 -0700509 SctpMessage sctpMessage = getSctpMessage(xrancPdu);
slowr13fa5b02017-08-08 16:32:31 -0700510 ctx.writeAndFlush(sctpMessage);
511 } catch (IOException e) {
512 log.error(ExceptionUtils.getFullStackTrace(e));
513 e.printStackTrace();
514 }
515 timer.cancel();
516 timer.purge();
517 }
518 }
519 },
520 0,
521 xranConfig.getConfigRequestInterval() * 1000
522 );
523 }
524 } catch (IOException e) {
525 log.error(ExceptionUtils.getFullStackTrace(e));
526 e.printStackTrace();
527 }
528 break;
529 }
530 default: {
531 break;
532 }
533 }
534 }
535 }
536
slowr577f3222017-08-28 10:49:08 -0700537 /**
538 * Internal host listener.
539 */
slowr13fa5b02017-08-08 16:32:31 -0700540 class InternalHostListener implements HostListener {
541
542 @Override
543 public void event(HostEvent event) {
544 log.info("Host Event {}", event);
545 switch (event.type()) {
546 case HOST_ADDED:
547 case HOST_MOVED: {
slowrc86750e2017-08-22 17:26:47 -0700548 RnibUe ue = ueMap.get(hostIdtoUEId(event.subject().id()));
slowr13fa5b02017-08-08 16:32:31 -0700549 if (ue != null) {
slowr577f3222017-08-28 10:49:08 -0700550 ECGI ecgiPrimary = linkMap.getPrimaryCell(ue).getEcgi();
551 RnibCell primary = cellMap.get(ecgiPrimary);
slowr13fa5b02017-08-08 16:32:31 -0700552 ue.setMeasConfig(null);
553 if (primary != null) {
554 Timer timer = new Timer();
555 timer.scheduleAtFixedRate(
556 new TimerTask() {
557 @Override
558 public void run() {
slowred74ec72017-08-17 11:25:01 -0700559 if (ue.getCapability() == null && primary.getVersion() >= 3) {
slowr13fa5b02017-08-08 16:32:31 -0700560 try {
561 ChannelHandlerContext ctx = cellMap.getCtx(primary.getEcgi());
slowr8ddc2b12017-08-14 14:13:38 -0700562 XrancPdu xrancPdu = UECapabilityEnquiry.constructPacket(
slowr67d05e42017-08-11 20:37:22 -0700563 primary.getEcgi(),
slowrc86750e2017-08-22 17:26:47 -0700564 ue.getCrnti());
slowr67d05e42017-08-11 20:37:22 -0700565 ctx.writeAndFlush(getSctpMessage(xrancPdu));
slowr13fa5b02017-08-08 16:32:31 -0700566 } catch (IOException e) {
567 log.warn(ExceptionUtils.getFullStackTrace(e));
568 e.printStackTrace();
569 }
570 } else {
slowr13fa5b02017-08-08 16:32:31 -0700571 timer.cancel();
572 timer.purge();
573 }
574 }
575 },
576 0,
577 xranConfig.getConfigRequestInterval() * 1000
578 );
slowred74ec72017-08-17 11:25:01 -0700579 if (ue.getMeasConfig() == null) {
slowr577f3222017-08-28 10:49:08 -0700580 populateMeasConfig(primary, ue);
slowred74ec72017-08-17 11:25:01 -0700581 }
slowr13fa5b02017-08-08 16:32:31 -0700582 }
583 }
584 break;
585 }
586 default: {
587 break;
588 }
589 }
590 }
591 }
592
slowr577f3222017-08-28 10:49:08 -0700593 /**
594 * Internal xran device agent.
595 */
slowr13fa5b02017-08-08 16:32:31 -0700596 public class InternalXranDeviceAgent implements XranDeviceAgent {
597
598 private final Logger log = LoggerFactory.getLogger(InternalXranDeviceAgent.class);
599
600 @Override
601 public boolean addConnectedCell(String host, ChannelHandlerContext ctx) {
slowr577f3222017-08-28 10:49:08 -0700602 ECGI ecgi = legitCells.get(IpAddress.valueOf(host));
slowr13fa5b02017-08-08 16:32:31 -0700603
604 if (ecgi == null) {
605 log.error("Device is not a legit source; ignoring...");
606 } else {
607 log.info("Device exists in configuration; registering...");
608 RnibCell storeCell = cellMap.get(ecgi);
609 if (storeCell == null) {
610 storeCell = new RnibCell();
611 storeCell.setEcgi(ecgi);
612 cellMap.put(storeCell, ctx);
613
614 for (XranDeviceListener l : xranDeviceListeners) {
615 l.deviceAdded(storeCell);
616 }
617 return true;
618 } else {
619 log.error("Device already registered; ignoring...");
620 }
621 }
622 ctx.close();
623 return false;
624 }
625
626 @Override
627 public boolean removeConnectedCell(String host) {
slowr577f3222017-08-28 10:49:08 -0700628 ECGI ecgi = legitCells.get(IpAddress.valueOf(host));
629 List<RnibLink> linksbyecgi = xranStore.getlinksbyecgi(ecgi);
slowr13fa5b02017-08-08 16:32:31 -0700630
slowr577f3222017-08-28 10:49:08 -0700631 linksbyecgi.forEach(rnibLink -> xranStore.removeLink(rnibLink.getLinkId()));
slowr13fa5b02017-08-08 16:32:31 -0700632
633 if (cellMap.remove(ecgi)) {
634 for (XranDeviceListener l : xranDeviceListeners) {
635 l.deviceRemoved(deviceId(uri(ecgi)));
636 }
637 return true;
638 }
639 return false;
640 }
641 }
642
slowr577f3222017-08-28 10:49:08 -0700643 /**
644 * Internal xran host agent.
645 */
slowr13fa5b02017-08-08 16:32:31 -0700646 public class InternalXranHostAgent implements XranHostAgent {
647
648 @Override
649 public boolean addConnectedHost(RnibUe ue, RnibCell cell, ChannelHandlerContext ctx) {
650
slowrc86750e2017-08-22 17:26:47 -0700651 if (ue.getId() != null && ueMap.get(ue.getId()) != null) {
slowr13fa5b02017-08-08 16:32:31 -0700652 linkMap.putPrimaryLink(cell, ue);
653
slowrc86750e2017-08-22 17:26:47 -0700654 Set<ECGI> ecgiSet = Sets.newConcurrentHashSet();
655
slowr577f3222017-08-28 10:49:08 -0700656 xranStore.getlinksbyueid(ue.getId())
slowr13fa5b02017-08-08 16:32:31 -0700657 .stream()
slowrc86750e2017-08-22 17:26:47 -0700658 .filter(l -> l.getType().equals(RnibLink.Type.SERVING_PRIMARY))
slowr577f3222017-08-28 10:49:08 -0700659 .findFirst()
660 .ifPresent(l -> ecgiSet.add(l.getLinkId().getEcgi()));
slowr13fa5b02017-08-08 16:32:31 -0700661
662 for (XranHostListener l : xranHostListeners) {
663 l.hostAdded(ue, ecgiSet);
664 }
665 return true;
666 } else {
slowrd337c932017-08-18 13:54:02 -0700667 ueMap.put(cell, ue);
slowr13fa5b02017-08-08 16:32:31 -0700668 linkMap.putPrimaryLink(cell, ue);
669
670 Set<ECGI> ecgiSet = Sets.newConcurrentHashSet();
671 ecgiSet.add(cell.getEcgi());
672 for (XranHostListener l : xranHostListeners) {
673 l.hostAdded(ue, ecgiSet);
674 }
675 return true;
676 }
677
678 }
679
680 @Override
681 public boolean removeConnectedHost(RnibUe ue) {
slowr577f3222017-08-28 10:49:08 -0700682 List<RnibLink> links = xranStore.getlinksbyueid(ue.getId());
slowr13fa5b02017-08-08 16:32:31 -0700683 links.forEach(rnibLink -> xranStore.removeLink(rnibLink.getLinkId()));
slowrc86750e2017-08-22 17:26:47 -0700684 if (ueMap.remove(ue.getId())) {
slowr13fa5b02017-08-08 16:32:31 -0700685 for (XranHostListener l : xranHostListeners) {
686 l.hostRemoved(ue.getHostId());
687 }
688 return true;
689 }
690 return false;
691 }
692 }
693
694 public class InternalXranPacketAgent implements XranPacketProcessor {
695 @Override
slowr577f3222017-08-28 10:49:08 -0700696 public void handlePacket(XrancPdu recvPdu, ChannelHandlerContext ctx)
697 throws IOException, InterruptedException {
698 XrancPdu sendPdu;
slowr13fa5b02017-08-08 16:32:31 -0700699
slowr577f3222017-08-28 10:49:08 -0700700 int apiID = recvPdu.getHdr().getApiId().intValue();
701 log.debug("Received message: {}", recvPdu);
slowr13fa5b02017-08-08 16:32:31 -0700702 switch (apiID) {
703 case 1: {
704 // Decode Cell config report.
slowr577f3222017-08-28 10:49:08 -0700705 CellConfigReport report = recvPdu.getBody().getCellConfigReport();
706 handleCellconfigreport(report, recvPdu.getHdr().getVer().toString());
slowr13fa5b02017-08-08 16:32:31 -0700707 break;
708 }
709 case 2: {
710 // Decode UE Admission Request.
slowr577f3222017-08-28 10:49:08 -0700711 UEAdmissionRequest ueAdmissionRequest = recvPdu.getBody().getUEAdmissionRequest();
712 handleUeadmissionrequest(ueAdmissionRequest, ctx);
slowr13fa5b02017-08-08 16:32:31 -0700713 break;
714 }
715 case 4: {
716 // Decode UE Admission Status.
slowr577f3222017-08-28 10:49:08 -0700717 UEAdmissionStatus ueAdmissionStatus = recvPdu.getBody().getUEAdmissionStatus();
718 handleAdmissionstatus(ueAdmissionStatus, ctx);
slowr13fa5b02017-08-08 16:32:31 -0700719 break;
720 }
721 case 5: {
slowrc86750e2017-08-22 17:26:47 -0700722 // Decode UE Context Update.
slowr577f3222017-08-28 10:49:08 -0700723 UEContextUpdate ueContextUpdate = recvPdu.getBody().getUEContextUpdate();
724 handleUecontextupdate(ueContextUpdate, ctx);
slowr73b4eae2017-08-17 16:09:09 -0700725
slowr13fa5b02017-08-08 16:32:31 -0700726 break;
727 }
728 case 6: {
729 // Decode UE Reconfig_Ind.
slowr577f3222017-08-28 10:49:08 -0700730 UEReconfigInd ueReconfigInd = recvPdu.getBody().getUEReconfigInd();
731 handleUereconfigind(ueReconfigInd);
slowr13fa5b02017-08-08 16:32:31 -0700732 break;
733 }
734 case 7: {
735 // If xRANc wants to deactivate UE, we pass UEReleaseInd from xRANc to eNB.
736 // Decode UE Release_Ind.
slowr577f3222017-08-28 10:49:08 -0700737 UEReleaseInd ueReleaseInd = recvPdu.getBody().getUEReleaseInd();
738 handleUereleaseind(ueReleaseInd);
slowr13fa5b02017-08-08 16:32:31 -0700739 break;
740 }
741 case 8: {
742 // Decode Bearer Adm Request
slowr577f3222017-08-28 10:49:08 -0700743 BearerAdmissionRequest bearerAdmissionRequest = recvPdu.getBody().getBearerAdmissionRequest();
744 handleBeareradmissionrequest(bearerAdmissionRequest, ctx);
slowr13fa5b02017-08-08 16:32:31 -0700745 break;
746 }
747 case 10: {
748 //Decode Bearer Admission Status
slowr577f3222017-08-28 10:49:08 -0700749 BearerAdmissionStatus bearerAdmissionStatus = recvPdu.getBody().getBearerAdmissionStatus();
slowr8ddc2b12017-08-14 14:13:38 -0700750 break;
slowr13fa5b02017-08-08 16:32:31 -0700751 }
752 case 11: {
753 //Decode Bearer Release Ind
slowr577f3222017-08-28 10:49:08 -0700754 BearerReleaseInd bearerReleaseInd = recvPdu.getBody().getBearerReleaseInd();
755 handleBearerreleaseind(bearerReleaseInd);
slowr13fa5b02017-08-08 16:32:31 -0700756 break;
757 }
758 case 13: {
slowr577f3222017-08-28 10:49:08 -0700759 HOFailure hoFailure = recvPdu.getBody().getHOFailure();
760 handleHofailure(hoFailure);
slowr67d05e42017-08-11 20:37:22 -0700761 break;
slowr8ddc2b12017-08-14 14:13:38 -0700762
slowr67d05e42017-08-11 20:37:22 -0700763 }
slowr8ddc2b12017-08-14 14:13:38 -0700764 case 14: {
slowr577f3222017-08-28 10:49:08 -0700765 HOComplete hoComplete = recvPdu.getBody().getHOComplete();
766 handleHocomplete(hoComplete, ctx);
slowr67d05e42017-08-11 20:37:22 -0700767 break;
768 }
slowr8ddc2b12017-08-14 14:13:38 -0700769
770 case 16: {
slowr577f3222017-08-28 10:49:08 -0700771 // Decode Rx Sig Meas Report.
772 RXSigMeasReport rxSigMeasReport = recvPdu.getBody().getRXSigMeasReport();
773 handleRxsigmeasreport(rxSigMeasReport);
slowr13fa5b02017-08-08 16:32:31 -0700774 break;
775 }
slowr8ddc2b12017-08-14 14:13:38 -0700776 case 18: {
slowr577f3222017-08-28 10:49:08 -0700777 RadioMeasReportPerUE radioMeasReportPerUE = recvPdu.getBody().getRadioMeasReportPerUE();
778 handleRadionmeasreportperue(radioMeasReportPerUE);
slowr67d05e42017-08-11 20:37:22 -0700779 break;
slowr13fa5b02017-08-08 16:32:31 -0700780 }
slowr8ddc2b12017-08-14 14:13:38 -0700781 case 19: {
slowr577f3222017-08-28 10:49:08 -0700782 RadioMeasReportPerCell radioMeasReportPerCell = recvPdu.getBody().getRadioMeasReportPerCell();
slowr13fa5b02017-08-08 16:32:31 -0700783 break;
784 }
slowr8ddc2b12017-08-14 14:13:38 -0700785 case 20: {
slowr577f3222017-08-28 10:49:08 -0700786 SchedMeasReportPerUE schedMeasReportPerUE = recvPdu.getBody().getSchedMeasReportPerUE();
787 handleSchedmeasreportperue(schedMeasReportPerUE);
slowr13fa5b02017-08-08 16:32:31 -0700788 break;
789 }
slowr8ddc2b12017-08-14 14:13:38 -0700790 case 21: {
slowr577f3222017-08-28 10:49:08 -0700791 SchedMeasReportPerCell schedMeasReportPerCell = recvPdu.getBody().getSchedMeasReportPerCell();
792 handleSchedmeasreportpercell(schedMeasReportPerCell);
slowr13fa5b02017-08-08 16:32:31 -0700793 break;
794 }
slowr8ddc2b12017-08-14 14:13:38 -0700795 case 22: {
slowr577f3222017-08-28 10:49:08 -0700796 PDCPMeasReportPerUe pdcpMeasReportPerUe = recvPdu.getBody().getPDCPMeasReportPerUe();
797 handlePdcpmeasreportperue(pdcpMeasReportPerUe);
slowr13fa5b02017-08-08 16:32:31 -0700798 break;
799 }
slowr8ddc2b12017-08-14 14:13:38 -0700800 case 24: {
801 // Decode UE Capability Info
slowr577f3222017-08-28 10:49:08 -0700802 UECapabilityInfo capabilityInfo = recvPdu.getBody().getUECapabilityInfo();
803 handleCapabilityinfo(capabilityInfo);
slowr8ddc2b12017-08-14 14:13:38 -0700804 break;
805 }
806 case 25: {
807 // Don't know what will invoke sending UE CAPABILITY ENQUIRY
808 // Encode and send UE CAPABILITY ENQUIRY
slowr577f3222017-08-28 10:49:08 -0700809 UECapabilityEnquiry ueCapabilityEnquiry = recvPdu.getBody().getUECapabilityEnquiry();
810 handleUecapabilityenquiry(ueCapabilityEnquiry, ctx);
slowr8ddc2b12017-08-14 14:13:38 -0700811 break;
812 }
slowr89c2ac12017-08-15 16:20:06 -0700813 case 27: {
814 //Decode ScellAddStatus
slowr577f3222017-08-28 10:49:08 -0700815 ScellAddStatus scellAddStatus = recvPdu.getBody().getScellAddStatus();
816 handleScelladdstatus(scellAddStatus);
slowr89c2ac12017-08-15 16:20:06 -0700817 break;
818 }
slowr8ddc2b12017-08-14 14:13:38 -0700819 case 30: {
820 // Decode RRMConfig Status
slowr577f3222017-08-28 10:49:08 -0700821 RRMConfigStatus rrmConfigStatus = recvPdu.getBody().getRRMConfigStatus();
822 handleRrmconfigstatus(rrmConfigStatus);
slowr67d05e42017-08-11 20:37:22 -0700823 break;
824 }
slowr8ddc2b12017-08-14 14:13:38 -0700825 //TODO Case 31: SeNBAdd 32: SeNBAddStatus 33: SeNBDelete
slowr13fa5b02017-08-08 16:32:31 -0700826 case 34: {
slowr577f3222017-08-28 10:49:08 -0700827 TrafficSplitConfig trafficSplitConfig = recvPdu.getBody().getTrafficSplitConfig();
828 handleTrafficSplitConfig(trafficSplitConfig);
slowr67d05e42017-08-11 20:37:22 -0700829 break;
slowr13fa5b02017-08-08 16:32:31 -0700830 }
831 default: {
slowr577f3222017-08-28 10:49:08 -0700832 log.warn("Wrong API ID: {}", recvPdu);
slowr67d05e42017-08-11 20:37:22 -0700833 break;
slowr13fa5b02017-08-08 16:32:31 -0700834 }
835 }
836
837 }
slowrc86750e2017-08-22 17:26:47 -0700838
slowr577f3222017-08-28 10:49:08 -0700839 /**
840 * Handle Cellconfigreport.
841 * @param report CellConfigReport
842 * @param version String version ID
843 */
844 private void handleCellconfigreport(CellConfigReport report, String version) {
845 ECGI ecgi = report.getEcgi();
846
847 RnibCell cell = xranStore.getCell(ecgi);
848 cell.setVersion(version);
849 cell.setConf(report);
850 cellMap.putPciArfcn(cell);
851 }
852
853 /**
854 * Handle Ueadmissionrequest.
855 * @param ueAdmissionRequest UEAdmissionRequest
856 * @param ctx ChannelHandlerContext
857 * @throws IOException IO Exception
858 */
859 private void handleUeadmissionrequest(UEAdmissionRequest ueAdmissionRequest, ChannelHandlerContext ctx)
860 throws IOException {
861 ECGI ecgi = ueAdmissionRequest.getEcgi();
862 if (xranStore.getCell(ecgi) != null) {
863 CRNTI crnti = ueAdmissionRequest.getCrnti();
864 XrancPdu sendPdu = UEAdmissionResponse.constructPacket(ecgi, crnti, xranConfig.admissionFlag());
865 ctx.writeAndFlush(getSctpMessage(sendPdu));
866 } else {
867 log.warn("Could not find ECGI in registered cells: {}", ecgi);
868 }
869 }
870
871 /**
872 * Handle UEAdmissionStatus.
873 * @param ueAdmissionStatus UEAdmissionStatus
874 * @param ctx ChannelHandlerContext
875 */
876 private void handleAdmissionstatus(UEAdmissionStatus ueAdmissionStatus, ChannelHandlerContext ctx) {
877 RnibUe ue = ueMap.get(ueAdmissionStatus.getEcgi(), ueAdmissionStatus.getCrnti());
878 if (ue != null) {
879 if (ueAdmissionStatus.getAdmEstStatus().value.intValue() == 0) {
880 ue.setState(RnibUe.State.ACTIVE);
881 } else {
882 ue.setState(RnibUe.State.IDLE);
883 }
884 }
885
886 if (ueAdmissionStatus.getAdmEstStatus().value.intValue() == 0) {
887 EcgiCrntiPair ecgiCrntiPair = EcgiCrntiPair
888 .valueOf(ueAdmissionStatus.getEcgi(), ueAdmissionStatus.getCrnti());
889 contextUpdateMap.compute(ecgiCrntiPair, (k, v) -> {
890 if (v == null) {
891 v = new ContextUpdateHandler();
892 }
893 if (v.setAdmissionStatus(ueAdmissionStatus)) {
slowrab685ef2017-08-31 17:17:35 -0700894 handlePairedPackets(v.getContextUpdate(), ctx, false);
895 v.reset();
slowr577f3222017-08-28 10:49:08 -0700896 }
897 return v;
898 });
899 }
900 }
901
902 /**
903 * Handle UEContextUpdate.
904 * @param ueContextUpdate UEContextUpdate
905 * @param ctx ChannelHandlerContext
906 */
907 private void handleUecontextupdate(UEContextUpdate ueContextUpdate, ChannelHandlerContext ctx) {
908 EcgiCrntiPair ecgiCrntiPair = EcgiCrntiPair
909 .valueOf(ueContextUpdate.getEcgi(), ueContextUpdate.getCrnti());
910
911 contextUpdateMap.compute(ecgiCrntiPair, (k, v) -> {
912 if (v == null) {
913 v = new ContextUpdateHandler();
914 }
915 if (v.setContextUpdate(ueContextUpdate)) {
916 HOComplete hoComplete = v.getHoComplete();
slowrab685ef2017-08-31 17:17:35 -0700917 handlePairedPackets(ueContextUpdate, ctx, hoComplete != null);
slowr577f3222017-08-28 10:49:08 -0700918 if (hoComplete != null) {
919 try {
920 hoMap.get(hoComplete.getEcgiS()).put("Hand Over Completed");
921 } catch (InterruptedException e) {
922 log.error(ExceptionUtils.getFullStackTrace(e));
923 e.printStackTrace();
924 } finally {
925 hoMap.remove(hoComplete.getEcgiS());
926 }
927 }
slowrab685ef2017-08-31 17:17:35 -0700928 v.reset();
slowr577f3222017-08-28 10:49:08 -0700929 }
930 return v;
931 });
932 }
933
934 /**
935 * Handle UEReconfigInd.
936 * @param ueReconfigInd UEReconfigInd
937 */
938 private void handleUereconfigind(UEReconfigInd ueReconfigInd) {
939 RnibUe ue = ueMap.get(ueReconfigInd.getEcgi(), ueReconfigInd.getCrntiOld());
940 RnibCell cell = cellMap.get(ueReconfigInd.getEcgi());
941
942 if (ue != null && cell != null) {
943 ue.setCrnti(ueReconfigInd.getCrntiNew());
944 ueMap.putCrnti(cell, ue);
945 } else {
946 log.warn("Could not find UE with this CRNTI: {}", ueReconfigInd.getCrntiOld());
947 }
948 }
949
950 /**
951 * Handle UEReleaseInd.
952 * @param ueReleaseInd UEReleaseInd
953 */
954 private void handleUereleaseind(UEReleaseInd ueReleaseInd) {
955 ECGI ecgi = ueReleaseInd.getEcgi();
956 CRNTI crnti = ueReleaseInd.getCrnti();
957 RnibUe ue = ueMap.get(ecgi, crnti);
958
959 // Check if there is an ongoing handoff and only remove if ue is not part of the handoff.
960 Long peek = ueIdQueue.peek();
961 if (peek != null) {
962 EcgiCrntiPair ecgiCrntiPair = ueMap.getCrntUe().inverse().get(peek);
963 if (ecgiCrntiPair != null && ecgiCrntiPair.equals(EcgiCrntiPair.valueOf(ecgi, crnti))) {
964 return;
965 }
966 }
967
968 if (ue != null) {
969 ue.setState(RnibUe.State.IDLE);
970 restartTimer(ue);
971 } else {
972 log.warn("Cannot release UE from non primary link.");
973 }
974 }
975
976 /**
977 * Handle BearerAdmissionRequest.
978 * @param bearerAdmissionRequest BearerAdmissionRequest
979 * @param ctx ChannelHandlerContext
980 * @throws IOException IO Exception
981 */
982 private void handleBeareradmissionrequest(BearerAdmissionRequest bearerAdmissionRequest,
983 ChannelHandlerContext ctx) throws IOException {
984 ECGI ecgi = bearerAdmissionRequest.getEcgi();
985 CRNTI crnti = bearerAdmissionRequest.getCrnti();
986 ERABParams erabParams = bearerAdmissionRequest.getErabParams();
987 RnibLink link = linkMap.get(ecgi, crnti);
988 if (link != null) {
989 link.setBearerParameters(erabParams);
990 } else {
991 log.warn("Could not find link between {}-{}", ecgi, crnti);
992 }
993
994 BerInteger numErabs = bearerAdmissionRequest.getNumErabs();
995 // Encode and send Bearer Admission Response
996 XrancPdu sendPdu = BearerAdmissionResponse
997 .constructPacket(ecgi, crnti, erabParams, numErabs, xranConfig.bearerFlag());
998 ctx.writeAndFlush(getSctpMessage(sendPdu));
999 }
1000
1001 /**
1002 * Handle BearerReleaseInd.
1003 * @param bearerReleaseInd
1004 */
1005 private void handleBearerreleaseind(BearerReleaseInd bearerReleaseInd) {
1006 ECGI ecgi = bearerReleaseInd.getEcgi();
1007 CRNTI crnti = bearerReleaseInd.getCrnti();
1008 RnibLink link = linkMap.get(ecgi, crnti);
1009
1010 List<ERABID> erabidsRelease = bearerReleaseInd.getErabIds().getERABID();
1011 List<ERABParamsItem> erabParamsItem = link.getBearerParameters().getERABParamsItem();
1012
1013 List<ERABParamsItem> unreleased = erabParamsItem
1014 .stream()
1015 .filter(item -> {
1016 Optional<ERABID> any = erabidsRelease.stream()
1017 .filter(id -> id.equals(item.getId())).findAny();
1018 return !any.isPresent();
1019 }).collect(Collectors.toList());
1020
1021 link.getBearerParameters().setERABParamsItem(new ArrayList<>(unreleased));
1022 }
1023
1024 /**
1025 * Handle HOFailure.
1026 * @param hoFailure HOFailure
1027 * @throws InterruptedException ueIdQueue interruption
1028 */
1029 private void handleHofailure(HOFailure hoFailure) throws InterruptedException {
1030 try {
1031 hoMap.get(hoFailure.getEcgi())
1032 .put("Hand Over Failed with cause: " + hoFailure.getCause());
1033 } catch (InterruptedException e) {
1034 log.error(ExceptionUtils.getFullStackTrace(e));
1035 e.printStackTrace();
1036 } finally {
1037 hoMap.remove(hoFailure.getEcgi());
1038 ueIdQueue.take();
1039 }
1040 }
1041
1042 /**
1043 * Handle HOComplete.
1044 * @param hoComplete HOComplete
1045 * @param ctx ChannelHandlerContext
1046 */
1047 private void handleHocomplete(HOComplete hoComplete, ChannelHandlerContext ctx) {
1048 EcgiCrntiPair ecgiCrntiPair = EcgiCrntiPair.valueOf(hoComplete.getEcgiT(),
1049 hoComplete.getCrntiNew());
1050 contextUpdateMap.compute(ecgiCrntiPair, (k, v) -> {
1051 if (v == null) {
1052 v = new ContextUpdateHandler();
1053 }
1054 if (v.setHoComplete(hoComplete)) {
slowrab685ef2017-08-31 17:17:35 -07001055 handlePairedPackets(v.getContextUpdate(), ctx, true);
slowr577f3222017-08-28 10:49:08 -07001056
1057 try {
1058 hoMap.get(hoComplete.getEcgiS()).put("Hand Over Completed");
1059 } catch (InterruptedException e) {
1060 log.error(ExceptionUtils.getFullStackTrace(e));
1061 e.printStackTrace();
1062 } finally {
1063 hoMap.remove(hoComplete.getEcgiS());
1064 }
slowrab685ef2017-08-31 17:17:35 -07001065 v.reset();
slowr577f3222017-08-28 10:49:08 -07001066 }
1067 return v;
1068 });
1069 }
1070
1071 /**
1072 * Handle RXSigMeasReport.
1073 * @param rxSigMeasReport RXSigMeasReport
1074 */
1075 private void handleRxsigmeasreport(RXSigMeasReport rxSigMeasReport) {
1076 List<RXSigReport> rxSigReportList = rxSigMeasReport.getCellMeasReports().getRXSigReport();
1077
1078 RnibUe ue = ueMap.get(rxSigMeasReport.getEcgi(), rxSigMeasReport.getCrnti());
1079 if (ue != null) {
1080 Long ueId = ue.getId();
1081
1082 if (!rxSigReportList.isEmpty()) {
1083 rxSigReportList.forEach(rxSigReport -> {
1084 RnibCell cell = cellMap.get(rxSigReport.getPciArfcn());
1085 if (cell != null) {
1086 ECGI ecgi = cell.getEcgi();
1087
1088 RnibLink link = linkMap.get(ecgi, ueId);
1089 if (link == null) {
1090 log.warn("Could not find link between: {}-{} | Creating non-serving link..",
1091 ecgi, ueId);
1092 link = linkMap.putNonServingLink(cell, ueId);
1093 }
1094
1095 if (link != null) {
1096 if (link.getType().equals(RnibLink.Type.NON_SERVING)) {
1097 restartTimer(link);
1098 }
1099
1100 RSRQRange rsrq = rxSigReport.getRsrq();
1101 RSRPRange rsrp = rxSigReport.getRsrp();
1102
1103 RnibLink.LinkQuality quality = link.getQuality();
1104 quality.setRx(new RnibLink.LinkQuality.Rx(
1105 rsrp.value.intValue() - 140,
1106 (rsrq.value.intValue() * 0.5) - 19.5
1107 ));
1108 }
1109 } else {
1110 log.warn("case 16: Could not find cell with PCI-ARFCN: {}",
1111 rxSigReport.getPciArfcn());
1112 }
1113 });
1114 }
1115 }
1116 }
1117
1118 /**
1119 * Handle RadioMeasReportPerUE.
1120 * @param radioMeasReportPerUE RadioMeasReportPerUE
1121 */
1122 private void handleRadionmeasreportperue(RadioMeasReportPerUE radioMeasReportPerUE) {
1123 RnibUe ue = ueMap.get(radioMeasReportPerUE.getEcgi(), radioMeasReportPerUE.getCrnti());
1124 if (ue != null) {
1125 Long ueId = ue.getId();
1126 List<RadioRepPerServCell> servCells = radioMeasReportPerUE.getRadioReportServCells()
1127 .getRadioRepPerServCell();
1128
1129 servCells.forEach(servCell -> {
1130 RnibCell cell = cellMap.get(servCell.getPciArfcn());
1131 if (cell != null) {
1132 RnibLink link = linkMap.get(cell.getEcgi(), ueId);
1133 if (link != null) {
1134 RadioRepPerServCell.CqiHist cqiHist = servCell.getCqiHist();
1135 RnibLink.LinkQuality quality = link.getQuality();
1136
1137 final double[] values = {0, 0, 0};
1138 final int[] i = {1};
1139 cqiHist.getBerInteger().forEach(value -> {
1140 values[0] = Math.max(values[0], value.intValue());
1141 values[1] += i[0] * value.intValue();
1142 values[2] += value.intValue();
1143 i[0]++;
1144 });
1145
1146 quality.setCqi(new RnibLink.LinkQuality.Cqi(
1147 cqiHist,
1148 values[0],
1149 values[1] / values[0]
1150 ));
1151
1152 } else {
1153 log.warn("Could not find link between: {}-{}", cell.getEcgi(), ueId);
1154 }
1155 } else {
1156 log.warn("case 18: Could not find cell with PCI-ARFCN: {}", servCell.getPciArfcn());
1157 }
1158 });
1159 }
1160 }
1161
1162 /**
1163 * Handle SchedMeasReportPerUE.
1164 * @param schedMeasReportPerUE SchedMeasReportPerUE
1165 */
1166 private void handleSchedmeasreportperue(SchedMeasReportPerUE schedMeasReportPerUE) {
1167 RnibUe ue = ueMap.get(schedMeasReportPerUE.getEcgi(), schedMeasReportPerUE.getCrnti());
1168 if (ue != null) {
1169 Long ueId = ue.getId();
1170
1171 List<SchedMeasRepPerServCell> servCells = schedMeasReportPerUE.getSchedReportServCells()
1172 .getSchedMeasRepPerServCell();
1173
1174 servCells.forEach(servCell -> {
1175 RnibCell cell = cellMap.get(servCell.getPciArfcn());
1176 if (cell != null) {
1177 RnibLink link = linkMap.get(cell.getEcgi(), ueId);
1178 if (link != null) {
1179 link.getQuality().setMcs(new RnibLink.LinkQuality.Mcs(
1180 servCell.getMcsDl(),
1181 servCell.getMcsUl()
1182 ));
1183
1184 link.setResourceUsage(new RnibLink.ResourceUsage(
1185 servCell.getPrbUsage().getPrbUsageDl(),
1186 servCell.getPrbUsage().getPrbUsageUl()
1187 ));
1188 } else {
1189 log.warn("Could not find link between: {}-{}", cell.getEcgi(), ueId);
1190 }
1191 } else {
1192 log.warn("case 20: Could not find cell with PCI-ARFCN: {}", servCell.getPciArfcn());
1193 }
1194 });
1195 }
1196 }
1197
1198 /**
1199 * Handle SchedMeasReportPerCell.
1200 * @param schedMeasReportPerCell SchedMeasReportPerCell
1201 */
1202 private void handleSchedmeasreportpercell(SchedMeasReportPerCell schedMeasReportPerCell) {
1203 RnibCell cell = cellMap.get(schedMeasReportPerCell.getEcgi());
1204 if (cell != null) {
1205 cell.setPrbUsage(new RnibCell.PrbUsageContainer(
1206 schedMeasReportPerCell.getPrbUsagePcell(),
1207 schedMeasReportPerCell.getPrbUsageScell()
1208 ));
1209
1210 cell.setQci(schedMeasReportPerCell.getQciVals());
1211 } else {
1212 log.warn("Could not find cell with ECGI: {}", schedMeasReportPerCell.getEcgi());
1213 }
1214 }
1215
1216 /**
1217 * Handle PDCPMeasReportPerUe.
1218 * @param pdcpMeasReportPerUe PDCPMeasReportPerUe
1219 */
1220 private void handlePdcpmeasreportperue(PDCPMeasReportPerUe pdcpMeasReportPerUe) {
1221 RnibUe ue = ueMap.get(pdcpMeasReportPerUe.getEcgi(), pdcpMeasReportPerUe.getCrnti());
1222 if (ue != null) {
1223 Long ueId = ue.getId();
1224 RnibLink link = linkMap.get(pdcpMeasReportPerUe.getEcgi(), ueId);
1225 if (link != null) {
1226 link.setPdcpThroughput(new RnibLink.PdcpThroughput(
1227 pdcpMeasReportPerUe.getThroughputDl(),
1228 pdcpMeasReportPerUe.getThroughputUl()
1229 ));
1230
1231 link.setPdcpPackDelay(new RnibLink.PdcpPacketdelay(
1232 pdcpMeasReportPerUe.getPktDelayDl(),
1233 pdcpMeasReportPerUe.getPktDelayUl()
1234 ));
1235 } else {
1236 log.warn("Could not find link between: {}-{}", pdcpMeasReportPerUe.getEcgi(), ueId);
1237 }
1238 }
1239 }
1240
1241 /**
1242 * Handle UECapabilityInfo.
1243 * @param capabilityInfo UECapabilityInfo
1244 */
1245 private void handleCapabilityinfo(UECapabilityInfo capabilityInfo) {
1246 RnibUe ue = ueMap.get(capabilityInfo.getEcgi(), capabilityInfo.getCrnti());
1247 if (ue != null) {
1248 ue.setCapability(capabilityInfo);
1249 } else {
1250 log.warn("Could not find UE with this CRNTI: {}", capabilityInfo.getCrnti());
1251 }
1252 }
1253
1254 /**
1255 * Handle UECapabilityEnquiry.
1256 * @param ueCapabilityEnquiry UECapabilityEnquiry
1257 * @param ctx ChannelHandlerContext
1258 * @throws IOException IO Exception
1259 */
1260 private void handleUecapabilityenquiry(UECapabilityEnquiry ueCapabilityEnquiry, ChannelHandlerContext ctx)
1261 throws IOException {
1262 XrancPdu xrancPdu = UECapabilityEnquiry.constructPacket(ueCapabilityEnquiry.getEcgi(),
1263 ueCapabilityEnquiry.getCrnti());
1264 ctx.writeAndFlush(getSctpMessage(xrancPdu));
1265 }
1266
1267 /**
1268 * Handle ScellAddStatus.
1269 * @param scellAddStatus ScellAddStatus
1270 */
1271 private void handleScelladdstatus(ScellAddStatus scellAddStatus) {
1272 RnibUe ue = ueMap.get(scellAddStatus.getEcgi(), scellAddStatus.getCrnti());
1273 if (ue != null) {
1274 Long ueId = ue.getId();
1275 try {
1276 scellAddMap.get(scellAddStatus.getCrnti()).put("Scell's status: " +
1277 scellAddStatus.getStatus());
1278 final int[] i = {0};
1279 scellAddStatus.getScellsInd().getPCIARFCN().forEach(
1280 pciarfcn -> {
1281 if (scellAddStatus.getStatus().getBerEnum().get(i[0]).value.intValue() == 0) {
1282 RnibCell cell = cellMap.get(pciarfcn);
1283 RnibLink link = linkMap.get(cell.getEcgi(), ueId);
1284 link.setType(RnibLink.Type.SERVING_SECONDARY_CA);
1285 }
1286 i[0]++;
1287 }
1288 );
1289
1290 } catch (InterruptedException e) {
1291 log.error(ExceptionUtils.getFullStackTrace(e));
1292 e.printStackTrace();
1293 } finally {
1294 scellAddMap.remove(scellAddStatus.getCrnti());
1295 }
1296 }
1297 }
1298
1299 /**
1300 * Handle RRMConfigStatus.
1301 * @param rrmConfigStatus RRMConfigStatus
1302 */
1303 private void handleRrmconfigstatus(RRMConfigStatus rrmConfigStatus) {
1304 try {
1305 rrmcellMap.get(rrmConfigStatus.getEcgi())
1306 .put("RRM Config's status: " + rrmConfigStatus.getStatus());
1307 } catch (InterruptedException e) {
1308 log.error(ExceptionUtils.getFullStackTrace(e));
1309 e.printStackTrace();
1310 } finally {
1311 rrmcellMap.remove(rrmConfigStatus.getEcgi());
1312 }
1313 }
1314
1315 /**
1316 * Handle TrafficSplitConfig.
1317 * @param trafficSplitConfig TrafficSplitConfig
1318 */
1319 private void handleTrafficSplitConfig(TrafficSplitConfig trafficSplitConfig) {
1320 RnibUe ue = ueMap.get(trafficSplitConfig.getEcgi(), trafficSplitConfig.getCrnti());
1321 if (ue != null) {
1322 Long ueId = ue.getId();
1323 List<TrafficSplitPercentage> splitPercentages = trafficSplitConfig
1324 .getTrafficSplitPercent().getTrafficSplitPercentage();
1325
1326 splitPercentages.forEach(trafficSplitPercentage -> {
1327 RnibCell cell = cellMap.get(trafficSplitPercentage.getEcgi());
1328 if (cell != null) {
1329 RnibLink link = linkMap.get(cell.getEcgi(), ueId);
1330 if (link != null) {
1331 link.setTrafficPercent(trafficSplitPercentage);
1332 } else {
1333 log.warn("Could not find link between: {}-{}", cell.getEcgi(), ueId);
1334 }
1335 } else {
1336 log.warn("Could not find cell with ECGI: {}", trafficSplitConfig.getEcgi());
1337 }
1338 });
1339 }
1340 }
1341
1342 /**
1343 * Handle context update depending if its handoff or not.
1344 *
1345 * @param contextUpdate context update packet
1346 * @param ctx channel context for the CELL
1347 * @param handoff true if we handle a Hand Off
1348 */
slowrab685ef2017-08-31 17:17:35 -07001349 private void handlePairedPackets(UEContextUpdate contextUpdate, ChannelHandlerContext ctx, boolean handoff) {
slowrc86750e2017-08-22 17:26:47 -07001350 RnibUe ue;
1351 RnibCell cell = xranStore.getCell(contextUpdate.getEcgi());
1352
1353 if (handoff) {
1354 try {
1355 ue = ueMap.get(ueIdQueue.take());
1356 } catch (InterruptedException e) {
1357 e.printStackTrace();
1358 log.error(ExceptionUtils.getFullStackTrace(e));
1359 ue = new RnibUe();
1360 }
1361 } else {
1362 ue = new RnibUe();
1363 }
1364
1365 ue.setMmeS1apId(contextUpdate.getMMEUES1APID());
1366 ue.setEnbS1apId(contextUpdate.getENBUES1APID());
1367 ue.setCrnti(contextUpdate.getCrnti());
1368
1369 hostAgent.addConnectedHost(ue, cell, ctx);
1370 }
slowr13fa5b02017-08-08 16:32:31 -07001371 }
1372
slowr577f3222017-08-28 10:49:08 -07001373 /**
1374 * Internal class for NetworkConfigListener.
1375 */
slowr13fa5b02017-08-08 16:32:31 -07001376 class InternalNetworkConfigListener implements NetworkConfigListener {
1377
1378 @Override
1379 public void event(NetworkConfigEvent event) {
1380 switch (event.type()) {
1381 case CONFIG_REGISTERED:
1382 break;
1383 case CONFIG_UNREGISTERED:
1384 break;
1385 case CONFIG_ADDED:
1386 case CONFIG_UPDATED:
1387 if (event.configClass() == CONFIG_CLASS) {
1388 handleConfigEvent(event.config());
1389 }
1390 break;
1391 case CONFIG_REMOVED:
1392 break;
1393 default:
1394 break;
1395 }
1396 }
1397
slowr577f3222017-08-28 10:49:08 -07001398 /**
1399 * Handle config event.
1400 *
1401 * @param config
1402 */
slowr13fa5b02017-08-08 16:32:31 -07001403 private void handleConfigEvent(Optional<Config> config) {
1404 if (!config.isPresent()) {
1405 return;
1406 }
1407
1408 xranConfig = (XranConfig) config.get();
1409
slowr577f3222017-08-28 10:49:08 -07001410 northboundTimeout = xranConfig.getNorthBoundTimeout();
slowrd337c932017-08-18 13:54:02 -07001411
slowr13fa5b02017-08-08 16:32:31 -07001412 legitCells.putAll(xranConfig.activeCellSet());
1413
1414 controller.start(deviceAgent, hostAgent, packetAgent, xranConfig.getXrancPort());
1415 }
1416 }
1417}