def upsert_mcast_service(self, ipaddress, receivers, status, service_type): """Update/insert new mcast services. Expected input: { "ip": "224.0.1.200", "receivers": ["ff:ff:ff:ff:ff:ff"], "status": True, "type": "emergency" } """ addr = self.mcast_ip_to_ether(ipaddress) if addr not in self.mcast_services: schedule = self.schedule[-self._services_registered:] + \ self.schedule[:-self._services_registered] self.mcast_services[addr] = { "addr": addr, "ipaddress": ipaddress, "mcs": 6, "schedule": schedule, "receivers": [EtherAddress(x) for x in receivers], "status": status, "service_type": service_type } self._services_registered += 1 else: self.mcast_services[addr]["receivers"] = \ [EtherAddress(x) for x in receivers] self.mcast_services[addr]["status"] = status self.mcast_services[addr]["service_type"] = service_type return addr
def put(self, *args, **kwargs): """Modify the LVAP Args: [0]: the lvap address (mandatory) Example URLs: PUT /api/v1/lvaps/60:F4:45:D0:3B:FC { "version": "1.0", "wtp": "04:F0:21:09:F9:AA" } """ lvap = self.service.lvaps[EtherAddress(args[0])] if "blocks" in kwargs: addr = EtherAddress(kwargs['wtp']) wtp = self.service.devices[addr] pool = ResourcePool() for block_id in kwargs["blocks"]: pool.append(wtp.blocks[block_id]) lvap.blocks = pool elif "wtp" in kwargs: wtp = self.service.devices[EtherAddress(kwargs['wtp'])] lvap.wtp = wtp if "encap" in kwargs: encap = EtherAddress(kwargs["encap"]) lvap.encap = encap
def delete(self, *args, **kwargs): """Delete one or all devices. Args: [0]: the device address (mandatory) Example URLs: DELETE /api/v1/wtps DELETE /api/v1/wtps/00:0D:B9:2F:56:64 """ if args: self.service.remove(EtherAddress(args[0])) else: self.service.remove_all()
def delete(self, *args, **kwargs): """Delete the mcast_services . Args: [0]: the project id (mandatory) [1]: the app id (mandatory) [3]: the mcast service MAC address (mandatory) Example URLs: DELETE /api/v1/projects/52313ecb-9d00-4b7d-b873-b55d3d9ada26/apps/ mcast_services/01:00:5E:00:01:C8 """ self.service.delete_mcast_service(EtherAddress(args[2])) self.service.save_service_state()
def delete(self, *args, **kwargs): """Delete one or all devices. Args: [0]: the device address Example URLs: DELETE /api/v1/vbses DELETE /api/v1/vbses/00:00:00:00:00:01 """ if args: self.service.remove(EtherAddress(args[0])) else: self.service.remove_all()
def __init__(self, slice_id, properties=None, devices=None): # set read-only parameters self.slice_id = int(slice_id) # logger :) self.log = logging.getLogger(self.__class__.__module__) # parse properties self.properties = self._parse_properties(properties) # parse per device properties self.devices = {} if devices: for device in devices: self.devices[EtherAddress(device)] = \ self._parse_properties(devices[device])
def handle_ucqm_response(self, response, wtp, _): """Handle UCQM_RESPONSE message.""" block = wtp.blocks[response.iface_id] block.ucqm = {} # generate data points points = [] timestamp = datetime.utcnow() for entry in response.entries: addr = EtherAddress(entry['addr']) block.ucqm[addr] = { 'addr': addr, 'last_rssi_std': entry['last_rssi_std'], 'last_rssi_avg': entry['last_rssi_avg'], 'last_packets': entry['last_packets'], 'hist_packets': entry['hist_packets'], 'mov_rssi': entry['mov_rssi'] } tags = dict(self.params) tags["wtp"] = wtp.addr tags["block_id"] = response.iface_id tags["addr"] = addr sample = { "measurement": 'ucqm_rssi', "tags": tags, "time": timestamp, "fields": block.ucqm[addr] } points.append(sample) # save to db self.write_points(points) if wtp.addr not in self.ucqm: self.ucqm[wtp.addr] = {} self.ucqm[wtp.addr][block.block_id] = block.ucqm self.ucqm[wtp.addr][block.block_id]['timestamp'] = timestamp # handle callbacks self.handle_callbacks()
def handle_slice_stats_response(self, response, *_): """Handle WIFI_SLICE_STATS_RESPONSE message.""" wtp = EtherAddress(response.device) # slc = str(response.slice_id) slc = self.slc_xid[response.xid] # update this object if wtp not in self.stats: self.slice_stats[slc][wtp] = {} # generate data points points = [] timestamp = datetime.utcnow() for entry in response.stats: self.slice_stats[slc][wtp][entry.iface_id] = { 'deficit_used': float(entry.deficit_used), 'max_queue_length': float(entry.max_queue_length), 'tx_packets': float(entry.tx_packets), 'tx_bytes': float(entry.tx_bytes), } tags = dict(self.params) tags["slc"] = slc tags["wtp"] = wtp tags["iface_id"] = entry.iface_id sample = { "measurement": "wifi_slice_stats", "tags": tags, "time": timestamp, "fields": self.slice_stats[slc][wtp][entry.iface_id] } points.append(sample) # save to db self.write_points(points) # handle callbacks self.handle_callbacks()
def get(self, *args, **kwargs): """Lists all clients in the ACL. Args: [0], the project id (mandatory) [0]: the device address (optional) Example URLs: GET /api/v1/projects/52313ecb-9d00-4b7d-b873-b55d3d9ada26/ wifi_acl/ { "60:57:18:B1:A4:B8": { "addr": "60:57:18:B1:A4:B8", "desc": "Dell Laptop" }, "18:5E:0F:E3:B8:68": { "addr": "18:5E:0F:E3:B8:68", "desc": "Dell Laptop" }, "60:F4:45:D0:3B:FC": { "addr": "60:F4:45:D0:3B:FC", "desc": "Roberto's iPhone" } } GET /api/v1/projects/52313ecb-9d00-4b7d-b873-b55d3d9ada26/ wifi_acl/60:57:18:B1:A4:B8 { "addr": "60:57:18:B1:A4:B8", "desc": "Dell Laptop" } """ project_id = uuid.UUID(args[0]) project = self.service.projects[project_id] allowed = project.wifi_props.allowed return allowed if not args else allowed[str(EtherAddress(args[1]))]
def _handle_tx_policy_status_response(self, status): """Handle an incoming TX_POLICY_STATUS_RESPONSE message.""" block = self.device.blocks[status.iface_id] addr = EtherAddress(status.sta) if addr not in block.tx_policies: block.tx_policies[addr] = TxPolicy(addr, block) txp = block.tx_policies[addr] txp.set_mcs([float(x) / 2 for x in status.mcs]) txp.set_ht_mcs([int(x) for x in status.mcs_ht]) txp.set_rts_cts(status.rts_cts) txp.set_max_amsdu_len(status.max_amsdu_len) txp.set_mcast(status.tx_mcast) txp.set_no_ack(status.flags.no_ack) self.log.info("TX policy status: %s", txp)
def get(self, *args, **kwargs): """Access the mcast_services . Args: [0]: the project id (mandatory) [1]: the app id (mandatory) [2]: the mcast service MAC address (optional) Example URLs: GET /api/v1/projects/52313ecb-9d00-4b7d-b873-b55d3d9ada26/apps/ mcast_services/01:00:5E:00:01:C8 { addr: "01:00:5E:00:01:C8", ipaddress: "224.0.1.200", mcs: 0, schedule: [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], receivers: [ "FF:FF:FF:FF:FF:FF" ], status: "true", service_type: "emergency" } """ if len(args) == 2: return self.service.mcast_services return self.service.mcast_services[EtherAddress(args[2])]
def delete(self, *args, **kwargs): """Delete an entry in ACL. Args: [0], the project id (mandatory) [0]: the device address (mandatory) Example URLs: DELETE /api/v1/projects/52313ecb-9d00-4b7d-b873-b55d3d9ada26/ wifi_acl/60:57:18:B1:A4:B8 """ project_id = uuid.UUID(args[0]) project = self.service.projects[project_id] del project.wifi_props.allowed[str(EtherAddress(args[1]))] project.save()
def handle_ncqm_response(self, response, wtp, _): """Handle NCQM_RESPONSE message.""" block = wtp.blocks[response.iface_id] block.ncqm = {} for entry in response.entries: addr = EtherAddress(entry['addr']) block.ncqm[addr] = { 'addr': addr, 'last_rssi_std': entry['last_rssi_std'], 'last_rssi_avg': entry['last_rssi_avg'], 'last_packets': entry['last_packets'], 'hist_packets': entry['hist_packets'], 'mov_rssi': entry['mov_rssi'] } self.ncqm = block.ncqm # handle callbacks self.handle_callbacks("ncqm")
def delete(self, *args, **kwargs): """Delete an entry in ACL. Args: [0], the project id (mandatory) [0]: the device address (mandatory) Example URLs: DELETE /api/v1/projects/52313ecb-9d00-4b7d-b873-b55d3d9ada26/ wifi_acl/60:57:18:B1:A4:B8 """ project_id = uuid.UUID(args[0]) project = self.service.projects[project_id] if len(args) == 2: project.remove_acl(EtherAddress(args[1])) else: project.remove_acl()
def get(self, *args, **kwargs): """List devices. Args: [0]: the device address (optional) Example URLs: GET /api/v1/vbses [ { "addr": "00:00:00:00:00:01", "cells": {}, "connection": null, "desc": "Ettus B210", "last_seen": 0, "last_seen_ts": "1970-01-01T01:00:00.000000Z", "period": 0, "state": "disconnected" } ] GET /api/v1/vbses/00:00:00:00:00:01 { "addr": "00:00:00:00:00:01", "cells": {}, "connection": null, "desc": "Ettus B210", "last_seen": 0, "last_seen_ts": "1970-01-01T01:00:00.000000Z", "period": 0, "state": "disconnected" } """ return self.service.devices \ if not args else self.service.devices[EtherAddress(args[0])]
def handle_ncqm_response(self, response, wtp, _): """Handle NCQM_RESPONSE message.""" block = wtp.blocks[response.iface_id] block.ncqm = {} for entry in response.entries: addr = EtherAddress(entry['addr']) block.ncqm[addr] = { 'addr': addr, 'last_rssi_std': entry['last_rssi_std'], 'last_rssi_avg': entry['last_rssi_avg'], 'last_packets': entry['last_packets'], 'hist_packets': entry['hist_packets'], 'mov_rssi': entry['mov_rssi'] } if wtp.addr not in self.ncqm: self.ncqm[wtp.addr] = {} self.ncqm[wtp.addr][block.block_id] = block.ncqm self.ucqm[wtp.addr][block.block_id]['timestamp'] = datetime.utcnow() # handle callbacks self.handle_callbacks()
def mcast_ip_to_ether(cls, ip_mcast_addr): """Transform an IP multicast address into an Ethernet one.""" if ip_mcast_addr is None: return '\x00' * 6 # The first 24 bits are fixed according to class D IP # and IP multicast address convenctions mcast_base = '01:00:5e' # The 23 low order bits are mapped. ip_addr_bytes = str(ip_mcast_addr).split('.') # The first IP byte is not use, # and only the last 7 bits of the second byte are used. second_byte = int(ip_addr_bytes[1]) & 127 third_byte = int(ip_addr_bytes[2]) fourth_byte = int(ip_addr_bytes[3]) mcast_upper = format(second_byte, '02x') + ':' + \ format(third_byte, '02x') + ':' + \ format(fourth_byte, '02x') return EtherAddress(mcast_base + ':' + mcast_upper)
def put(self, *args, **kwargs): """Update the description of the device. Request: version: protocol version (1.0) desc: a human readable description of the device (optional) Example URLs: PUT /api/v1/vbses/00:0D:B9:2F:56:64 { "version":"1.0", "desc": "SrsLTE eNB" } """ addr = EtherAddress(args[0]) if 'desc' in kwargs: self.service.update(addr, kwargs['desc']) else: self.service.update(addr)
def _handle_vap_status_response(self, status): """Handle an incoming STATUS_VAP message.""" bssid = EtherAddress(status.bssid) ssid = SSID(status.ssid) project = self.manager.projects_manager.load_project_by_ssid(ssid) if not project: self.log.warning("Unable to find SSID %s", ssid) self.send_del_vap(bssid) return # If the VAP does not exists, then create a new one if bssid not in self.manager.vaps: incoming = self.device.blocks[status.iface_id] self.manager.vaps[bssid] = VAP(bssid, incoming, project.wifi_props.ssid) vap = self.manager.vaps[bssid] self.log.info("VAP status %s", vap)
def send_add_lvap_request(self, lvap, block, set_mask): """Send a ADD_LVAP message.""" flags = Container(ht_caps=lvap.ht_caps, authenticated=lvap.authentication_state, associated=lvap.association_state, set_mask=set_mask) encap = EtherAddress("00:00:00:00:00:00") if lvap.encap: encap = lvap.encap bssid = EtherAddress() if lvap.bssid: bssid = lvap.bssid ssid = SSID() if lvap.ssid: ssid = lvap.ssid msg = Container(length=80, flags=flags, assoc_id=lvap.assoc_id, iface_id=block.block_id, ht_caps_info=Container(**lvap.ht_caps_info), sta=lvap.addr.to_raw(), encap=encap.to_raw(), bssid=bssid.to_raw(), ssid=ssid.to_raw(), networks=[]) for network in lvap.networks: msg.length = msg.length + 6 + WIFI_NWID_MAXSIZE + 1 msg.networks.append( Container(bssid=network[0].to_raw(), ssid=network[1].to_raw())) return self.send_message(self.proto.PT_ADD_LVAP_REQUEST, msg, lvap.handle_add_lvap_response)
def sta(self, sta): """ Set the station address. """ self.params['sta'] = EtherAddress(sta)
def get(self, *args, **kwargs): """List the LVAPs. Args: [0], the project id (mandatory) [1]: the lvap address (optional) Example URLs: GET /api/v1/projects/52313ecb-9d00-4b7d-b873-b55d3d9ada26/lvaps [ { "addr": "60:F4:45:D0:3B:FC", "assoc_id": 732, "association_state": true, "authentication_state": true, "blocks": [ ... ], "bssid": "52:31:3E:D0:3B:FC", "encap": "00:00:00:00:00:00", "ht_caps": true, "ht_caps_info": { "DSSS_CCK_Mode_in_40_MHz": false, "Forty_MHz_Intolerant": false, "HT_Delayed_Block_Ack": false, "HT_Greenfield": false, "LDPC_Coding_Capability": true, "L_SIG_TXOP_Protection_Support": false, "Maximum_AMSDU_Length": false, "Reserved": false, "Rx_STBC": 0, "SM_Power_Save": 3, "Short_GI_for_20_MHz": true, "Short_GI_for_40_MHz": true, "Supported_Channel_Width_Set": true, "Tx_STBC": false }, "networks": [ [ "52:31:3E:D0:3B:FC", "EmPOWER" ] ], "pending": [], "ssid": "EmPOWER", "state": "running", "wtp": { ... } } ] GET /api/v1/projects/52313ecb-9d00-4b7d-b873-b55d3d9ada26/lvaps/ 60:F4:45:D0:3B:FC { "addr": "60:F4:45:D0:3B:FC", "assoc_id": 732, "association_state": true, "authentication_state": true, "blocks": [ ... ], "bssid": "52:31:3E:D0:3B:FC", "encap": "00:00:00:00:00:00", "ht_caps": true, "ht_caps_info": { "DSSS_CCK_Mode_in_40_MHz": false, "Forty_MHz_Intolerant": false, "HT_Delayed_Block_Ack": false, "HT_Greenfield": false, "LDPC_Coding_Capability": true, "L_SIG_TXOP_Protection_Support": false, "Maximum_AMSDU_Length": false, "Reserved": false, "Rx_STBC": 0, "SM_Power_Save": 3, "Short_GI_for_20_MHz": true, "Short_GI_for_40_MHz": true, "Supported_Channel_Width_Set": true, "Tx_STBC": false }, "networks": [ [ "52:31:3E:D0:3B:FC", "EmPOWER" ] ], "pending": [], "ssid": "EmPOWER", "state": "running", "wtp": { ... } } """ project_id = uuid.UUID(args[0]) project = self.service.projects[project_id] return project.lvaps \ if len(args) == 1 else project.lvaps[EtherAddress(args[1])]
def _handle_auth_request(self, request): """Handle an incoming AUTH_REQUEST message.""" sta = EtherAddress(request.sta) if sta not in self.manager.lvaps: self.log.info("Auth request from unknown LVAP %s", sta) return lvap = self.manager.lvaps[sta] incoming_bssid = EtherAddress(request.bssid) # The request bssid is the lvap current bssid, then just reply if lvap.bssid == incoming_bssid: lvap.bssid = incoming_bssid lvap.authentication_state = True lvap.association_state = False lvap.ssid = None lvap.commit() self.send_auth_response(lvap) return # Otherwise check if the requested BSSID belongs to a unique tenant for project in self.manager.projects_manager.projects.values(): if not project.wifi_props: continue if project.wifi_props.bssid_type == T_BSSID_TYPE_SHARED: continue bssid = project.generate_bssid(lvap.addr) if bssid == incoming_bssid: lvap.bssid = incoming_bssid lvap.authentication_state = True lvap.association_state = False lvap.ssid = None lvap.commit() self.send_auth_response(lvap) return # Finally check if this is a shared bssid for project in self.manager.projects_manager.projects.values(): if not project.wifi_props: continue if project.wifi_props.bssid_type == T_BSSID_TYPE_UNIQUE: continue if incoming_bssid in project.vaps: lvap.bssid = incoming_bssid lvap.authentication_state = True lvap.association_state = False lvap.ssid = None lvap.commit() self.send_auth_response(lvap) return self.log.info("Auth request from unknown BSSID %s", incoming_bssid)
def get(self, *args, **kwargs): """List the LVAPs. Args: [0]: the lvap address (optional) Example URLs: GET /api/v1/lvaps [ { "addr": "60:F4:45:D0:3B:FC", "assoc_id": 732, "association_state": false, "authentication_state": false, "blocks": [ ... ], "bssid": null, "encap": "00:00:00:00:00:00", "ht_caps": true, "ht_caps_info": { "DSSS_CCK_Mode_in_40_MHz": false, "Forty_MHz_Intolerant": false, "HT_Delayed_Block_Ack": false, "HT_Greenfield": false, "LDPC_Coding_Capability": true, "L_SIG_TXOP_Protection_Support": false, "Maximum_AMSDU_Length": false, "Reserved": false, "Rx_STBC": 0, "SM_Power_Save": 3, "Short_GI_for_20_MHz": true, "Short_GI_for_40_MHz": true, "Supported_Channel_Width_Set": true, "Tx_STBC": false }, "networks": [ [ "52:31:3E:D0:3B:FC", "EmPOWER" ] ], "pending": [], "ssid": null, "state": "running", "wtp": { ... } } ] GET /api/v1/lvaps/60:F4:45:D0:3B:FC { "addr": "60:F4:45:D0:3B:FC", "assoc_id": 732, "association_state": false, "authentication_state": false, "blocks": [ ... ], "bssid": null, "encap": "00:00:00:00:00:00", "ht_caps": true, "ht_caps_info": { "DSSS_CCK_Mode_in_40_MHz": false, "Forty_MHz_Intolerant": false, "HT_Delayed_Block_Ack": false, "HT_Greenfield": false, "LDPC_Coding_Capability": true, "L_SIG_TXOP_Protection_Support": false, "Maximum_AMSDU_Length": false, "Reserved": false, "Rx_STBC": 0, "SM_Power_Save": 3, "Short_GI_for_20_MHz": true, "Short_GI_for_40_MHz": true, "Supported_Channel_Width_Set": true, "Tx_STBC": false }, "networks": [ [ "52:31:3E:D0:3B:FC", "EmPOWER" ] ], "pending": [], "ssid": null, "state": "running", "wtp": { ... } } """ return self.service.lvaps \ if not args else self.service.lvaps[EtherAddress(args[0])]
def _handle_assoc_request(self, request): """Handle an incoming ASSOC_REQUEST message.""" sta = EtherAddress(request.sta) ht_caps = request.flags.ht_caps ht_caps_info = dict(request.ht_caps_info) del ht_caps_info['_io'] if sta not in self.manager.lvaps: self.log.info("Assoc request from unknown LVAP %s", sta) return lvap = self.manager.lvaps[sta] incoming_bssid = EtherAddress(request.bssid) if lvap.bssid != incoming_bssid: self.log.info("Assoc request for invalid BSSID %s", incoming_bssid) return incoming_ssid = SSID(request.ssid) # Check if the requested SSID is from a unique project for project in self.manager.projects_manager.projects.values(): if not project.wifi_props: continue if project.wifi_props.bssid_type == T_BSSID_TYPE_SHARED: continue bssid = project.generate_bssid(lvap.addr) if bssid != incoming_bssid: self.log.info("Invalid BSSID %s", incoming_bssid) continue if project.wifi_props.ssid == incoming_ssid: lvap.bssid = incoming_bssid lvap.authentication_state = True lvap.association_state = True lvap.ssid = incoming_ssid lvap.ht_caps = ht_caps lvap.ht_caps_info = ht_caps_info lvap.commit() self.send_assoc_response(lvap) return # Check if the requested SSID is from a unique project for project in self.manager.projects_manager.projects.values(): if not project.wifi_props: continue if project.wifi_props.bssid_type == T_BSSID_TYPE_UNIQUE: continue if incoming_bssid not in project.vaps: self.log.info("Invalid BSSID %s", incoming_bssid) continue if project.wifi_props.ssid == incoming_ssid: lvap.bssid = incoming_bssid lvap.authentication_state = True lvap.association_state = True lvap.ssid = incoming_ssid lvap.ht_caps = ht_caps lvap.ht_caps_info = ht_caps_info lvap.commit() self.send_assoc_response(lvap) return self.log.info("Unable to find SSID %s", incoming_ssid)
def get_prefix(self): """Return tenant prefix.""" tokens = [self.project_id.hex[0:12][i:i + 2] for i in range(0, 12, 2)] return EtherAddress(':'.join(tokens))
def decreaseQuantum(self, slc, wtp, ratesProm): res = False self.decreased_quantums = "" updated_slice = {} # para todos los lvaps en el wtp for sta in self.context.lvaps: lvap = self.context.lvaps[sta] if lvap.wtp != None and lvap.wtp.addr == wtp.to_str(): lvap_slice = self.getSliceLvap(sta) if not (self.change_quantum[lvap_slice][wtp]): promised_rate = ratesProm[lvap_slice] lvap_rate = self.getLVAPRateMBits(sta.to_str()) # si al menos un lvap tiene mayor rate al prometido y el quantum de esa slice en el wtp es mayor al minimo, le saco recursos if lvap_rate > promised_rate: actual_slice = self.context.wifi_slices[str( lvap_slice)] wtp_quantum = actual_slice.properties['quantum'] if EtherAddress(wtp) in actual_slice.devices: wtp_quantum = actual_slice.devices[wtp]['quantum'] if wtp_quantum > self.quantum_min: res = True self.change_quantum[lvap_slice][wtp] = True updated_slice = { 'slice_id': actual_slice.slice_id, 'properties': { 'amsdu_aggregation': actual_slice. properties['amsdu_aggregation'], 'quantum': actual_slice.properties['quantum'], 'sta_scheduler': actual_slice.properties['sta_scheduler'] }, 'devices': actual_slice.devices } addr = EtherAddress(wtp) if addr not in updated_slice['devices']: self.decreased_quantums = self.decreased_quantums + "// S-" + lvap_slice + "--" + str( updated_slice['properties']['quantum'] ) + "->" + str( updated_slice['properties']['quantum'] - updated_slice['properties']['quantum'] * self.quantum_decrease) updated_slice['devices'][addr] = { 'amsdu_aggregation': actual_slice. properties['amsdu_aggregation'], 'quantum': actual_slice.properties['quantum'] - actual_slice.properties['quantum'] * self.quantum_decrease, 'sta_scheduler': actual_slice.properties['sta_scheduler'] } else: self.decreased_quantums = self.decreased_quantums + "// S-" + lvap_slice + "--" + str( updated_slice['devices'][addr]['quantum'] ) + "->" + str( updated_slice['devices'][addr]['quantum'] - updated_slice['devices'][addr]['quantum'] * self.quantum_decrease) updated_slice['devices'][addr][ 'quantum'] = updated_slice['devices'][ addr]['quantum'] - updated_slice[ 'devices'][addr][ 'quantum'] * self.quantum_decrease self.context.upsert_wifi_slice(**updated_slice) #return updated_slice return res
def _handle_lvap_status_response(self, status): """Handle an incoming LVAP_STATUS_RESPONSE message.""" sta = EtherAddress(status.sta) # If the LVAP does not exists, then create a new one if sta not in self.manager.lvaps: self.manager.lvaps[sta] = \ LVAP(sta, assoc_id=status.assoc_id, state=PROCESS_RUNNING) lvap = self.manager.lvaps[sta] # update LVAP params lvap.encap = EtherAddress(status.encap) lvap.authentication_state = bool(status.flags.authenticated) lvap.association_state = bool(status.flags.associated) lvap.ht_caps = bool(status.flags.ht_caps) lvap.ht_caps_info = dict(status.ht_caps_info) del lvap.ht_caps_info['_io'] ssid = SSID(status.ssid) if ssid == SSID(): ssid = None bssid = EtherAddress(status.bssid) if bssid == EtherAddress("00:00:00:00:00:00"): bssid = None lvap.bssid = bssid incoming = self.device.blocks[status.iface_id] if status.flags.set_mask: lvap.downlink = incoming else: lvap.uplink.append(incoming) # if this is not a DL+UL block then stop here if not status.flags.set_mask: return # if an SSID is set and the incoming SSID is different from the # current one then raise an LVAP leave event if lvap.ssid and ssid != lvap.ssid: self.send_client_leave_message_to_self(lvap) lvap.ssid = None # if the incoming ssid is not none then raise an lvap join event if ssid: lvap.ssid = ssid self.send_client_join_message_to_self(lvap) # udpate networks networks = list() for network in status.networks: incoming = (EtherAddress(network.bssid), SSID(network.ssid)) networks.append(incoming) lvap.networks = networks self.log.info("LVAP status: %s", lvap)
def try_handover(self, sta, slc, rate, ratesProm, actual_rate): posibles_handovers = [] lvap = self.context.lvaps[EtherAddress(sta)] blocks = self.blocks().sort_by_rssi(lvap.addr) def filterBlocks(block): if block.ucqm[lvap.addr][ 'mov_rssi'] > self.RSSI_min and block.hwaddr.to_str( ) != lvap.blocks[0].hwaddr.to_str(): return True else: return False # Filtramos los wtp que tengan malo RSSI filtered_blocks = list(filter(filterBlocks, blocks)) # obtengo el uso del wtp actual query = 'select * from wifi_channel_stats where wtp=\'' + lvap.wtp.addr.to_str( ) + '\' and block_id=\'' + str( lvap.blocks[0].block_id) + '\' and time > now() - ' + str( int(self.every / 1000)) + 's;' result = self.query(query) current_channel_stats = list(result.get_points()) current_usage = 0 for current_stats in current_channel_stats: current_usage += current_stats[ 'tx'] # + current_stats['rx'] + current_stats['ed'] current_usage = current_usage / len(current_channel_stats) # obtengo historial de handovers para verificar ping pong query = 'select * from lvaps_handover where sta=\'' + sta + '\' and time > now() - ' + str( int(self.every / 1000) * 10) + 's;' result = self.query(query) handover_list = list(result.get_points()) for block in filtered_blocks: query = 'select * from wifi_channel_stats where wtp=\'' + block.wtp.addr.to_str( ) + '\' and block_id=\'' + str( block.block_id) + '\' and time > now() - ' + str( int(self.every / 1000)) + 's;' result = self.query(query) channel_stats = list(result.get_points()) usage = 0 for stats in channel_stats: usage += stats['tx'] #+ stats['rx'] + stats['ed'] usage = usage / len(channel_stats) # si el uso del wtp es menor al actual, lo agrego como posible handover if usage * 1.1 < current_usage and self.wtp_handovers[ block.wtp.addr] < self.max_handovers and not ( self.ping_pong(handover_list, block.wtp.addr)): posibles_handovers.append({'block': block, 'usage': usage}) if len(posibles_handovers) > 0: # Ordeno los bloques por usage asi me quedo con el que tenga menos posibles_handovers.sort(key=lambda x: x['usage']) # escribo en logger self.write_log( slc, sta, "H", lvap.blocks[0].wtp.addr.to_str() + "->" + posibles_handovers[0]['block'].wtp.addr.to_str(), "Usage new WTP: " + str(posibles_handovers[0]['usage'])) # Do Handover lvap.blocks = posibles_handovers[0]['block'] self.wtp_handovers[posibles_handovers[0]['block'].wtp.addr] += 1 # guardar cambios # generate data points points = [] timestamp = datetime.utcnow() fields = {"wtp": posibles_handovers[0]['block'].wtp.addr} tags = {"sta": sta} sample = { "measurement": 'lvaps_handover', "tags": tags, "time": timestamp, "fields": fields } points.append(sample) # save to db self.write_points(points) return True else: # No encontre WTP con uso menor al actual, entonces me fijo si algun wtp tiene lvaps con rate mayor al prometido for block in filtered_blocks: extra_rate = 0 for sta2 in self.context.lvaps: lvap = self.context.lvaps[sta2] if lvap.wtp != None and lvap.wtp.addr == block.wtp.addr: lvap_slice = self.getSliceLvap(sta2) promised_rate = ratesProm[lvap_slice] lvap_rate = self.getLVAPRateMBits(sta2.to_str()) if (lvap_rate - promised_rate) > 0: extra_rate += (lvap_rate - promised_rate) if extra_rate > 0 and ( extra_rate >= (actual_rate * 1.2) or extra_rate >= rate) and self.wtp_handovers[ block.wtp.addr] < self.max_handovers and not ( self.ping_pong(handover_list, block.wtp.addr)): posibles_handovers.append({ 'block': block, 'extra_rate': extra_rate }) if len(posibles_handovers) > 0: # Ordeno los bloques por rate extra asi me quedo con el que tenga mas posibles_handovers.sort(key=lambda x: x['extra_rate']) # escribo en logger self.write_log( slc, sta, "H", lvap.blocks[0].wtp.addr.to_str() + "->" + posibles_handovers[0]['block'].wtp.addr.to_str(), "Extra rate new WTP: " + str(posibles_handovers[0]['extra_rate'])) # Do Handover lvap.blocks = posibles_handovers[-1]['block'] self.wtp_handovers[posibles_handovers[-1] ['block'].wtp.addr] += 1 # guardar cambios # generate data points points = [] timestamp = datetime.utcnow() fields = {"wtp": posibles_handovers[-1]['block'].wtp.addr} tags = {"sta": sta} sample = { "measurement": 'lvaps_handover', "tags": tags, "time": timestamp, "fields": fields } points.append(sample) # save to db self.write_points(points) return True else: return False
def get(self, *args, **kwargs): """List devices. Args: [0]: the device address (optional) Example URLs: GET /api/v1/wtps [ { "addr": "00:0D:B9:2F:56:64", "blocks": {}, "connection": null, "desc": "PC Engines ALIX 2D", "last_seen": 0, "last_seen_ts": "1970-01-01T01:00:00.000000Z", "period": 0, "state": "disconnected" } ] GET /api/v1/wtps/00:0D:B9:2F:56:64 (disconnected) { "addr": "00:0D:B9:2F:56:64", "blocks": {}, "connection": null, "desc": "PC Engines ALIX 2D", "last_seen": 0, "last_seen_ts": "1970-01-01T01:00:00.000000Z", "period": 0, "state": "disconnected" } GET /api/v1/wtps/00:0D:B9:2F:56:64 (connected) { "addr": "00:0D:B9:30:3E:18", "blocks": { "0": { "addr": "00:0D:B9:30:3E:18", "band": "HT20", "channel": 36, "ht_supports": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ], "hwaddr": "04:F0:21:09:F9:9E", "supports": [ 6, 9, 12, 18, 24, 36, 48, 54 ], "tx_policies": { "60:F4:45:D0:3B:FC": { "addr": "60:F4:45:D0:3B:FC", "ht_mcs": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ], "max_amsdu_len": 3839, "mcast": "legacy", "mcs": [ 6.0, 9.0, 12.0, 18.0, 24.0, 36.0, 48.0, 54.0 ], "no_ack": false, "rts_cts": 2436, "ur_count": 3 } } }, "1": { "addr": "00:0D:B9:30:3E:18", "band": "HT20", "channel": 6, "ht_supports": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ], "hwaddr": "D4:CA:6D:14:C2:09", "supports": [ 1, 2, 5, 6, 9, 11, 12, 18, 24, 36, 48, 54 ], "tx_policies": {} } }, "connection": { "addr": [ "192.168.1.9", 46066 ] }, "desc": "PC Engines ALIX 2D", "last_seen": 8560, "last_seen_ts": "2019-08-23T13:09:43.140533Z", "period": 0, "state": "online" } """ return self.service.devices \ if not args else self.service.devices[EtherAddress(args[0])]