def _handle_ue_report_response(self, vbs, hdr, event, ue_report): """Handle an incoming UE_REPORT message. Args: hello, a UE_REPORT message Returns: None """ incoming = [] for ue in ue_report.ues: if RUNTIME.find_ue_by_rnti(ue.rnti, ue.pci, vbs): continue plmn_id = PLMNID(ue.plmn_id[1:].hex()) tenant = RUNTIME.load_tenant_by_plmn_id(plmn_id) if not tenant: self.log.info("Unable to find PLMN id %s", plmn_id) continue if vbs.addr not in tenant.vbses: self.log.info("VBS %s not in PLMN id %s", vbs.addr, plmn_id) continue cell = vbs.get_cell_by_pci(ue.pci) if not cell: self.log.info("PCI %u not found", u.pci) continue if ue.imsi != 0: ue_id = uuid.uuid5(uuid.NAMESPACE_DNS, str(ue.imsi)) else: ue_id = uuid.uuid4() ue = UE(ue_id, ue.imsi, ue.rnti, cell, plmn_id, tenant) ue.set_active() RUNTIME.ues[ue.ue_id] = ue tenant.ues[ue.ue_id] = ue incoming.append(ue.ue_id) self.server.send_ue_join_message_to_self(ue) # check for leaving UEs for ue_id in list(RUNTIME.ues.keys()): if RUNTIME.ues[ue_id].vbs != vbs: continue if not RUNTIME.ues[ue_id].is_active(): self.log.info("Handover in progress for %u, ignoring", ue_id) continue if ue_id not in incoming: RUNTIME.remove_ue(ue_id)
def _handle_ue_report_response(self, vbs, hdr, event, ue_report): """Handle an incoming UE_REPORT message. Args: hello, a UE_REPORT message Returns: None """ ues = {u.imsi: u for u in ue_report.ues} # check for new UEs for u in ues.values(): # UE already known if u.imsi in RUNTIME.ues: continue plmn_id = PLMNID(u.plmn_id[1:].hex()) tenant = RUNTIME.load_tenant_by_plmn_id(plmn_id) if not tenant: self.log.info("Unable to find PLMN id %s", plmn_id) continue if vbs.addr not in tenant.vbses: self.log.info("VBS %s not in PLMN id %s", vbs.addr, plmn_id) continue cell = None for c in vbs.cells: if c.pci == u.pci: cell = c break if not cell: self.log.info("PCI %u not found", u.pci) continue ue = UE(u.imsi, u.rnti, cell, plmn_id, tenant) ue.set_active() RUNTIME.ues[u.imsi] = ue tenant.ues[u.imsi] = ue self.server.send_ue_join_message_to_self(ue) # check for leaving UEs for imsi in list(RUNTIME.ues.keys()): if RUNTIME.ues[imsi].vbs != vbs: continue if imsi not in ues: RUNTIME.remove_ue(imsi)
def _handle_ue_report_response(self, vbs, hdr, event, msg): """Handle an incoming UE_REPORT message. Args: hello, a UE_REPORT message Returns: None """ for raw_entry in msg.options: if raw_entry.type not in UE_REPORT_TYPES: self.log.warning("Unknown options %u", raw_entry) continue prop = UE_REPORT_TYPES[raw_entry.type].name option = UE_REPORT_TYPES[raw_entry.type].parse(raw_entry.data) self.log.warning("Processing options %s", prop) if raw_entry.type == EP_UE_REPORT_IDENTITY: plmn_id = PLMNID(option.plmn_id) tenant = RUNTIME.load_tenant_by_plmn_id(plmn_id) if not tenant: self.log.info("Unknown tenant %s", plmn_id) continue # TODO: Implement fallback mechanism IMSI->TMSI->RNTI ue_id = uuid.UUID(int=option.imsi) # UE already known, update its parameters if ue_id in RUNTIME.ues: ue = RUNTIME.ues[ue_id] ue.rnti = option.rnti # UE is disconnecting if option.state == 1: RUNTIME.remove_ue(ue_id) else: cell = vbs.cells[hdr.cellid] ue = UE(ue_id, option.rnti, option.imsi, option.timsi, cell, tenant) RUNTIME.ues[ue.ue_id] = ue tenant.ues[ue.ue_id] = ue # UE is connected if option.state == 0: self.server.send_ue_join_message_to_self(ue)
def _handle_ue_report_response(self, vbs, hdr, event, ue_report): """Handle an incoming UE_REPORT message. Args: hello, a UE_REPORT message Returns: None """ LOG.info("UE report from %s VBS %s seq %u", self.addr[0], vbs.addr, hdr.seq) ues = {u.imsi: u for u in ue_report.ues} for u in ues.values(): plmn_id = PLMNID(u.plmn_id[1:].hex()) tenant = RUNTIME.load_tenant_by_plmn_id(plmn_id) if not tenant: LOG.info("Unable to find PLMN id %s", plmn_id) continue if vbs.addr not in tenant.vbses: LOG.info("VBS %s not in PLMN id %s", vbs.addr, plmn_id) continue cell = None for c in vbs.cells: if c.pci == u.pci: cell = c if not cell: LOG.info("PCI %u not found", u.pci) continue ue = UE(u.imsi, u.rnti, cell, plmn_id, tenant) new_ue = False if u.imsi not in RUNTIME.ues: new_ue = True RUNTIME.ues[u.imsi] = ue tenant.ues[u.imsi] = ue if new_ue: self.server.send_ue_join_message_to_self(ue) for ue in RUNTIME.ues.values(): if ue.imsi not in ues: self.server.send_ue_leave_message_to_self(ue)
def _handle_ue_state_change(self, ue_state): ue_state_dict = protobuf_to_dict(ue_state)[PRT_UE_STATE_CHANGE] rnti = ue_state_dict["config"]["rnti"] if ue_state_dict["type"] != config_common_pb2.PRUESC_DEACTIVATED: if "capabilities" not in ue_state_dict["config"]: capabilities = {} else: capabilities = ue_state_dict["config"]["capabilities"] del ue_state_dict["config"]["capabilities"] del ue_state_dict["config"]["rnti"] self.vbsp.ues[rnti] = UE(rnti, self.vbsp, ue_state_dict["config"], capabilities) elif ue_state_dict[ "type"] == config_common_pb2.PRUESC_DEACTIVATED and rnti in self.vbsp.ues: del self.vbsp.ues[rnti]
def _handle_UEs_id_repl(self, main_msg): """Handle an incoming UEs ID reply. Args: message, a emage_msg containing UE IDs (RNTIs) Returns: None """ enb_id = main_msg.head.b_id active_ues = {} inactive_ues = {} event_type = main_msg.WhichOneof("event_types") msg = protobuf_to_dict(main_msg) ues_id_msg_repl = msg[event_type]["mUEs_id"]["repl"] if ues_id_msg_repl["status"] != configs_pb2.CREQS_SUCCESS: return # List of active UEs if "active_ue_id" in ues_id_msg_repl: for ue in ues_id_msg_repl["active_ue_id"]: addr = rnti_to_ue_id(ue["rnti"], enb_id) active_ues[addr] = {} active_ues[addr]["addr"] = addr active_ues[addr]["rnti"] = ue["rnti"] if "imsi" in ue: active_ues[addr]["imsi"] = int(ue["imsi"]) if "plmn_id" in ue: active_ues[addr]["plmn_id"] = ue["plmn_id"] # List of inactive UEs if "inactive_ue_id" in ues_id_msg_repl: for ue in ues_id_msg_repl["inactive_ue_id"]: addr = rnti_to_ue_id(ue["rnti"], enb_id) inactive_ues[addr] = {} inactive_ues[addr]["addr"] = addr inactive_ues[addr]["rnti"] = ue["rnti"] if "imsi" in ue: inactive_ues[addr]["imsi"] = int(ue["imsi"]) if "plmn_id" in ue: inactive_ues[addr]["plmn_id"] = ue["plmn_id"] for new_ue in active_ues.values(): if new_ue["addr"] not in RUNTIME.ues: ue = UE(new_ue["addr"], new_ue["rnti"], self.vbs) if "imsi" in new_ue: ue.imsi = new_ue["imsi"] if "plmn_id" in new_ue: ue.tenant = \ RUNTIME.load_tenant_by_plmn_id(new_ue["plmn_id"]) RUNTIME.ues[new_ue["addr"]] = ue continue ue = RUNTIME.ues[new_ue["addr"]] if "plmn_id" in new_ue: ue.tenant = \ RUNTIME.load_tenant_by_plmn_id(new_ue["plmn_id"]) for addr in list(RUNTIME.ues.keys()): if addr not in active_ues: RUNTIME.remove_ue(addr)
def _handle_ue_report_response(self, vbs, hdr, event, msg): """Handle an incoming UE_REPORT message. Args: hello, a UE_REPORT message Returns: None """ for raw_entry in msg.options: if raw_entry.type not in UE_REPORT_TYPES: self.log.warning("Unknown options %u", raw_entry) continue prop = UE_REPORT_TYPES[raw_entry.type].name option = UE_REPORT_TYPES[raw_entry.type].parse(raw_entry.data) self.log.warning("Processing options %s", prop) if raw_entry.type == EP_UE_REPORT_IDENTITY: # NOTE: These ID generation should fallback to a data-type like for PLMNID imsi_id = uuid.UUID(int=option.imsi) tmsi_id = uuid.UUID(int=option.tmsi) # VBS can have multiple carriers (cells), and each carrier can allocate # its own RNTI range independently. This means that on UUID generation # by RNTI you can get multiple different UEs with the same UUID if only # RNTI is considered. This gives to the ID a little of context. rnti_id = uuid.UUID(int=vbs.addr.to_int() << 32 | hdr.cellid << 16 | option.rnti) plmn_id = PLMNID(option.plmn_id) tenant = RUNTIME.load_tenant_by_plmn_id(plmn_id) if not tenant: self.log.info("Unknown tenant %s", plmn_id) continue # Basic fallback mechanism for UE unique ID generation # # IMSI # UE ID is generated using the Subscriber Identity, thus it # will remain stable through multiple connection/disconnection if option.imsi != 0: ue_id = imsi_id # TMSI # UE ID is generated using Temporary ID assigned by the Core # Network, and will be stable depending on the CN ID generation # behavior elif option.tmsi != 0: ue_id = tmsi_id # RNTI # UE ID is generated using the Radio Network Temporary # Identifier. This means that at any event where such identifier # is changed update, the UE ID will potentially will change too else: ue_id = rnti_id # UE already known, update its parameters if ue_id in RUNTIME.ues: ue = RUNTIME.ues[ue_id] # RNTI must always be set, but just in case handle the event if option.rnti != 0: ue.rnti = option.rnti else: self.log.info("UE is missing RNTI identifier!") continue # Update the TMSI if has been renew for some reason if option.tmsi != 0: ue.tmsi = option.tmsi # Fill IMSI only if it was not previously set if option.imsi != 0 and ue.imsi != 0: ue.imsi = option.imsi # UE is disconnecting if option.state == 1: RUNTIME.remove_ue(ue_id) # UE not known else: # Reporting on and entry which switched to offline; ignore if option.state == 1: continue cell = vbs.cells[hdr.cellid] ue = UE(ue_id, option.rnti, option.imsi, option.tmsi, cell, tenant) RUNTIME.ues[ue.ue_id] = ue tenant.ues[ue.ue_id] = ue # UE is connected if option.state == 0: self.server.send_ue_join_message_to_self(ue)
def _handle_ue_report_response(self, vbs, hdr, event, msg): """Handle an incoming UE_REPORT message. Args: hello, a UE_REPORT message Returns: None """ for raw_entry in msg.options: if raw_entry.type not in UE_REPORT_TYPES: self.log.warning("Unknown options %u", raw_entry.raw_entry) continue prop = UE_REPORT_TYPES[raw_entry.type].name option = UE_REPORT_TYPES[raw_entry.type].parse(raw_entry.data) self.log.warning("Processing options %s", prop) if raw_entry.type == EP_UE_REPORT_IDENTITY: plmn_id = PLMNID(option.plmn_id) tenant = RUNTIME.load_tenant_by_plmn_id(plmn_id) if not tenant: self.log.info("Unknown tenant %s", plmn_id) continue ue = RUNTIME.find_ue_by_rnti(option.rnti, hdr.cellid, vbs) # UE already known, update its parameters if ue: ue.plmn_id = plmn_id ue.tmsi = option.timsi else: cell = vbs.cells[hdr.cellid] ue_id = uuid.uuid4() ue = UE(ue_id, option.rnti, option.imsi, option.timsi, cell, tenant) RUNTIME.ues[ue.ue_id] = ue tenant.ues[ue.ue_id] = ue self.server.send_ue_join_message_to_self(ue) elif raw_entry.type == EP_UE_REPORT_STATE: ue_id = uuid.uuid4() ue = RUNTIME.find_ue_by_rnti(option.rnti, hdr.cellid, vbs) if not ue: continue try: ue.state = UE_REPORT_STATES[option.state] except IOError: self.log.error("Invalid transistion %s -> %s" \ %(ue.state, UE_REPORT_STATES[option.state]))
def _handle_UEs_id_repl(self, main_msg): """Handle an incoming UEs ID reply. Args: message, a emage_msg containing UE IDs (RNTIs) Returns: None """ active_ues = {} inactive_ues = {} event_type = main_msg.WhichOneof("event_types") msg = protobuf_to_dict(main_msg) ues_id_msg_repl = msg[event_type]["mUEs_id"]["repl"] if ues_id_msg_repl["status"] != configs_pb2.CREQS_SUCCESS: return # List of active UEs if "active_ue_id" in ues_id_msg_repl: for ue in ues_id_msg_repl["active_ue_id"]: active_ues[(self.vbs.addr, ue["rnti"])] = {} if "imsi" in ue: active_ues[(self.vbs.addr, ue["rnti"])]["imsi"] = \ int(ue["imsi"]) else: active_ues[(self.vbs.addr, ue["rnti"])]["imsi"] = None if "plmn_id" in ue: active_ues[(self.vbs.addr, ue["rnti"])]["plmn_id"] = \ int(ue["plmn_id"]) else: active_ues[(self.vbs.addr, ue["rnti"])]["plmn_id"] = None # List of inactive UEs if "inactive_ue_id" in ues_id_msg_repl: for ue in ues_id_msg_repl["inactive_ue_id"]: inactive_ues[(self.vbs.addr, ue["rnti"])] = {} if "imsi" in ue: inactive_ues[(self.vbs.addr, ue["rnti"])]["imsi"] = \ int(ue["imsi"]) else: inactive_ues[(self.vbs.addr, ue["rnti"])]["imsi"] = None if "plmn_id" in ue: inactive_ues[(self.vbs.addr, ue["rnti"])]["plmn_id"] = \ int(ue["plmn_id"]) else: inactive_ues[(self.vbs.addr, ue["rnti"])]["plmn_id"] = None for vbs_id, rnti in active_ues.keys(): ue_id = (self.vbs.addr, rnti) if ue_id not in RUNTIME.ues: new_ue = UE(ue_id, ue_id[1], self.vbs) RUNTIME.ues[ue_id] = new_ue ue = RUNTIME.ues[ue_id] imsi = active_ues[ue_id]["imsi"] plmn_id = active_ues[ue_id]["plmn_id"] # Setting IMSI of UE ue.imsi = imsi if not ue.plmn_id and plmn_id: # Setting tenant ue.tenant = RUNTIME.load_tenant_by_plmn_id(plmn_id) if ue.tenant: # Adding UE to tenant LOG.info("Adding %s to tenant %s", ue.addr, ue.tenant.plmn_id) ue.tenant.ues[ue.addr] = ue # Raise UE join self.server.send_ue_join_message_to_self(ue) # Create a trigger for reporting RRC measurements config. from empower.ue_confs.ue_rrc_meas_confs import ue_rrc_meas_confs conf_req = {"event_type": "trigger"} ue_rrc_meas_confs(tenant_id=ue.tenant.tenant_id, vbs=ue.vbs.addr, ue=ue.rnti, conf_req=conf_req) if ue.plmn_id and not plmn_id: # Raise UE leave self.server.send_ue_leave_message_to_self(ue) # Removing UE from tenant LOG.info("Removing %s from tenant %s", ue.addr, ue.tenant.plmn_id) del ue.tenant.ues[ue.addr] # Resetting tenant ue.tenant = None existing_ues = [] existing_ues.extend(RUNTIME.ues.keys()) for ue_addr in existing_ues: if ue_addr not in active_ues: RUNTIME.remove_ue(ue_addr)