def get_Reneseid(self): # This method gets the Id of the RENESE required to perform the different tasks # of this RENEMA App. # To simplify the process, only the Id of the "Switching" service is requested. It's # assumed the NetworkStatus App already has the Id of the "DeviceTracking" service. # Considering a strict behavior, the ParentalControl must get all the Ids of the RENESEs # required by itself. if DB().get_switching_id() == '': # To simplify the message to discover a given RENESE, the field "Todiscover" was # added to the header. However, this is not correct because modifies the # standard header composed of 4 fields: SenderId, ReceiverId, Service and Arguments. # The commented message should be used instead: #message_discover = { # 'SenderId': DB().get_parentalcontrol_id(), # 'ReceiverId': '', # 'Service': 'service_discovery_request', # 'Arguments': { # 'ToDiscover': 'switching', # } #} message_discover = { 'SenderId': DB().get_parentalcontrol_id(), 'ReceiverId': '', 'Service': 'service_discovery_request', 'Todiscover': 'switching' } sender = Sender() sender.setMessageToSend(json.dumps(message_discover)) sender.start()
def run(self): # Run Method: Thread running continuously while flag is True. print '\n', '-' * 20, 'RENEMA App Manager: Receiver Running', '-' * 20 while self.flag: try: c, addr = self.s.accept() # Establish connection with client. c.settimeout(None) received_message = json.loads(c.recv(1024)) #print received_message c.close() # The received_message must be forwarded to the corresponding RENEMA App. # Based on the Receiver_Id, the class_name of the RENEMA App is retrieved from # the HashMap (forwarding_table) in order to launch the method "get_ReneseMessage" # dynamically. This method is called "reflection or instrospection". class_name = DB().get_renema_class_name( received_message['ReceiverId']) package, module = class_name.rsplit('.', 1) generic_module = import_module(package) generic_instance = getattr(generic_module, module) generic_instance().get_ReneseMessage(received_message) except socket.timeout: pass
def add_policy(self, policy, message, service): # This method only prints a message on the screen when an "allow" policy is defined for a device. print '\n--Parental Control App:' print 'Device: ', policy['device'], ' has the following schedule:' for day in policy['schedule']: print '\t', day['day'], '-->', day['time'] print '\n*Device:', policy[ 'device'], ' added to the switching service!!!', '\n' # Next, based on the reply of NERON, the device is added or removed to/from # the switching service. renese_message = { 'SenderId': DB().get_parentalcontrol_id(), 'ReceiverId': DB().get_switching_id(), 'Service': service, 'Arguments': { 'device_mac': message['Arguments']['device_mac'], 'device_port': message['Arguments']['device_port'], 'port_queue': message['Arguments']['port_queue'] } } sender = Sender() sender.setMessageToSend(json.dumps(renese_message)) sender.start()
def clear_policies(self): # This Method deletes all the defined policies and informs the Switching service to remove all the devices # from its service. This action also implies clearing all the flow entries currently installed on the OpenFlow # switch and to install the default flow entry. policies = [] DB().save_policies(policies) renese_message = { 'SenderId': DB().get_parentalcontrol_id(), 'ReceiverId': DB().get_switching_id(), 'Service': 'clear_allowedDevicesTable', 'Arguments': { 'device_mac': '', 'device_port': 0, 'port_queue': 0 } } sender = Sender() sender.setMessageToSend(json.dumps(renese_message)) sender.start() renese_message['ReceiverId'] = DB().get_neron_id() renese_message['Service'] = 'release_all_resources' sender = Sender() sender.setMessageToSend(json.dumps(renese_message)) sender.start()
def get_Renema_id(self): # First, the NetworkStatus App requests an Id if there is no one allocated. if DB().get_networkstatus_id() == '': DB().save_networkstatus_id(IdAllocator().get_renema_app_id()) # Next, the NetworkStatus App registers its Id on the RENEMA App Manager. networkstatus_id = DB().get_networkstatus_id() networkstatus_class_name = self.get_Name() IdAllocator().service_registry(networkstatus_id, networkstatus_class_name)
def get_Renema_id(self): # First, the ParentalControl App requests and Id if there is no one allocated. if DB().get_parentalcontrol_id() == '': DB().save_parentalcontrol_id(IdAllocator().get_renema_app_id()) # Next, the ParentalControl App registers its Id on the RENEMA App Manager. parentalcontrol_id = DB().get_parentalcontrol_id() parentalcontrol_class_name = self.get_Name() IdAllocator().service_registry(parentalcontrol_id, parentalcontrol_class_name)
def device_stats(self, device): # This method returns a more detailed statistic of a specific connected device. device_state = DB().get_state(device) stats = DB().get_stats() for entry in stats: if entry['port'] == device_state[0]['port']: Transmission = "{0:.2f}".format(float(entry['bw_tx'])/1000000) Reception = "{0:.2f}".format(float(entry['bw_rx'])/1000000) stat_to_show = {'device': device, 'port': device_state[0]['port'], 'Transmission (Mbps)': Transmission, 'Reception (Mbps)': Reception} return stat_to_show
def get_renema_app_id(self): # This method retrieves all the allocated Ids in order to know what should # be the next prefix to be allocated. # Then, the new Id is stored in the DB. renema_apps_ids = [] renema_apps_ids = DB().get_renema_apps_ids() app_id = len(renema_apps_ids) + 1 renema_id = prefix + str(app_id) renema_apps_ids.append(renema_id) DB().save_renema_apps_ids(renema_apps_ids) return renema_id
def update_policy(self, device, update): # This Method stores the changes made on a given policy. query = DB().get_policies() policy = [policy for policy in query if policy['device'] == device] policy[0]['action'] = update['action'] policy[0]['priority'] = update['priority'] policy[0]['schedule'] = update['schedule'] DB().save_policies(query) self.set_policy(policy[0])
def devices_stats(self): # This method returns the statistics of all connected devices. # The total bandwdith consumption (Tx + Rx) per device is provided as array. stats_to_show = [] stats = DB().get_stats() status = DB().get_status() for entry in stats: for state in status: if entry['port'] == state['port']: consumption = "{0:.2f}".format((float(entry['bw_rx']) + float(entry['bw_tx']))/1000000) stats_to_show.append({'device': state['device'], 'consumption (Mbps)': consumption}) return stats_to_show
def set_state(self, message, state): # This Method creates a new state entry into the DB. # The entry is created if it has not been created before, otherwise it is updated. retrieve_state = DB().get_state(message['Arguments']['device_mac']) if len(retrieve_state) == 0: query = DB().get_policy(message['Arguments']['device_mac']) if len(query) is not 0: condition = 'defined' else: condition = 'undefined' state = { 'device': message['Arguments']['device_mac'], 'port': message['Arguments']['device_port'], 'policy': condition, 'state': state } status = DB().get_status() status.append(state) DB().save_status(status) else: DB().update_status(message['Arguments']['device_mac'], 'state', 'online')
def boot(): # This script helps in configuring the initial stages of all RENEMA Apps. # In addition the Receiver module of the RENEMA App Manager as well as the REST API # are launched. #------------------------------- STARTUP VALUES ------------------------------- tcp_port = 14712 # Receiver TCP port server = 'http://localhost:5000' headers = {'content-type': 'application/json'} apirest_path = os.path.dirname(os.path.realpath(__file__)) api_rest_full_path = 'python ' + apirest_path + '/ApiRest.py' os.system('clear') #------------------------------------------------------------------------------ # A DB object is created in order to initialize its default values: db = DB() # A subdirectory called 'data' is created to save the files: if os.path.exists(os.getcwd() + '/ManagementLayer/DB/data'): pass else: os.makedirs(os.getcwd() + '/ManagementLayer/DB/data') # The different modules are launched. Ctrl + C ends the booter. try: print '-' * 26, 'MANAGEMENT LAYER RUNNING', '-' * 26 print '(Press CTRL+C to quit)' # The Receiver of RENEMA App Manager is launched: receiver = Receiver(tcp_port) receiver.start() # All RENEMA Apps request an Id ParentalControl().get_Renema_id() NetworkStatus().get_Renema_id() # All RENEMA Apps request the RENESE Id based on the service to be used ParentalControl().get_Reneseid() NetworkStatus().get_Reneseid() # Once the RENESE Id has been discovered, all RENEMA Apps must subscribe to a specific RENESE sleep(0.04) ParentalControl().switching_subscription() NetworkStatus().devicetracker_subscription() # The REST API (flask) is launched: sleep(0.5) status, output = commands.getstatusoutput(api_rest_full_path) while True: sleep(1) # Infinite loop until "CTRL+C" be pressed. except KeyboardInterrupt: # Killing the Receiver of RENEMA App Manager: receiver.stop_receiver() # Killing the REST API (flask): #new_policy = requests.post(server + '/shutdown', data=json.dumps(''), headers=headers) print '-' * 26, 'MANAGEMENT LAYER STOPPED', '-' * 26 sys.exit(0)
def service_registry(self, renema_id, class_name): # This method allows populating a HashMap (Forwarding_Table) where the # key is the RENEMA Id and the value is the class_name of the RENEMA App. # This HashMap is used to perform the forwarding of the received message # to the specific RENEMA App. DB().save_renema_class_name(renema_id, class_name)
def clear_status(self): # This Method sets the "Policy" field in "undefined" for all the state entries. # This method is called when the ParentalControl App deletes all the defined policies. policies = DB().get_policies() if len(policies) is 0: status = DB().get_status() for state in status: state['policy'] = 'undefined' DB().save_status(status) else: print 'Impossible to delete the status'
def show_devices(self): # This Method shows all the state entries stored in the DB. print '\n--NetworkStatus App:' print '\t\t', 'Status of connected devices' query = DB().get_status() for raw in query: print 'Device:', raw['device'], '\t', 'Port:', raw['port'], '\t', 'Policy:', raw['policy'], '\t', 'State:', raw['state']
def device_resources(self, device): # This method returns a more detailed state of network resources per device. device_state = DB().get_state(device) resources = DB().get_resources() resources_to_show = { 'Device': device, 'Port': device_state[0]['port'], 'Port Bandwidth': "{0:.2f}".format(float(resources['bw_per_port'])/1000000), 'Available Queues': { 'q1 (Mbps)': "{0:.2f}".format(float(resources['q1_bw'])/1000000), 'q2 (Mbps)': "{0:.2f}".format(float(resources['q2_bw'])/1000000), 'q3 (Mbps)': "{0:.2f}".format(float(resources['q3_bw'])/1000000), } } return resources_to_show
def get_Reneseid(self): # This method gets the Id of the RENESE required to perform the different tasks # of this RENEMA App. # By now, the NetworkStatus gets the Id of the DeviceTracking and NESA services. # This RENEMA App also needs to get the Id of the NERON service. if DB().get_devicetracker_id() == '': # To simplify the message to discover a given RENESE, the field "Todiscover" was # added to the header. However, this is not correct because modifies the # standard header composed of 4 fields: SenderId, ReceiverId, Service and Arguments. # The commented message should be used instead: #message_discover = { # 'SenderId': DB().get_networkstatus_id(), # 'ReceiverId': '', # 'Service': 'service_discovery_request', # 'Arguments': { # 'ToDiscover': 'devices_tracking', # } #} message_discover = { 'SenderId': DB().get_networkstatus_id(), 'ReceiverId': '', 'Service': 'service_discovery_request', 'Todiscover': 'devices_tracking' } sender = Sender() sender.setMessageToSend(json.dumps(message_discover)) sender.start() if DB().get_nesa_id() == '': message_discover['Todiscover'] = 'network_statistics' sender = Sender() sender.setMessageToSend(json.dumps(message_discover)) sender.start() if DB().get_neron_id() == '': message_discover['Todiscover'] ='network_resources' sender = Sender() sender.setMessageToSend(json.dumps(message_discover)) sender.start()
def get_policy(self, device): # This Method returns a policy defined for a specific device. query = DB().get_policy(device) if len(query) == 0: print '\n--Parental Control App:' print 'The DB is non existent or it is empty' return query
def stats_query(self): # This method allows getting the network stats using an on-demand model. # (Not used at the moment). arguments = [] status = DB().get_status() for entry in status: arguments.append({'port':entry['port'], 'bw_rx':0, 'bw_tx':0}) renese_message = { 'SenderId':DB().get_networkstatus_id(), 'ReceiverId':DB().get_nesa_id(), 'Service': 'stats_request', 'Arguments': arguments } sender = Sender() sender.setMessageToSend(json.dumps(renese_message)) sender.start()
def device_state(self, device): # This Method returns the state of a specific device. # The state is composed of the following fields: "Device", "Port", "Policy" and "State". device_state = DB().get_state(device) if len(device_state) == 0: print '\n--Network Status App:' print 'No Device State' return device_state
def network_resources(self): # This method returns the global state of network resources. resources = DB().get_resources() resources_to_show = { 'Hired Bandwidth (Mbps)': "{0:.2f}".format(float(resources['contracted_ic_bw'])/1000000), 'Bandwidth Consumption (Mbps)': "{0:.2f}".format(float(resources['used_ic_bw'])/1000000), 'Available Bandwidth (Mbps)': "{0:.2f}".format(float(resources['available_ic_bw'])/1000000), 'Active Ports': resources['active_ports'] } return resources_to_show
def delete_device(self, device): # This Method deletes the device state from the DB. status = DB().get_status() state = DB().get_state(device) status.remove(state[0]) DB().save_status(status)
def devicetracker_subscription(self): # Once the NetworkStatus App has got the Id of the RENESE(s) requiered, the # subscription process must be carried out in order to use the underlying services. # For the NetworkStatus App case, a subscription to the "DeviceTracking", "NESA" # and "NERON" services is carried out. # After this process, the state of the corresponding subscription is saved. if DB().get_devicetracking_subscription() == '': subscription = { 'SenderId':DB().get_networkstatus_id(), 'ReceiverId':DB().get_devicetracker_id(), 'Service': 'subscription_request' } sender = Sender() sender.setMessageToSend(json.dumps(subscription)) sender.start() subscription['ReceiverId'] = DB().get_nesa_id() sender = Sender() sender.setMessageToSend(json.dumps(subscription)) sender.start() subscription['ReceiverId'] = DB().get_neron_id() sender = Sender() sender.setMessageToSend(json.dumps(subscription)) sender.start() DB().save_devicetracking_subscription('done')
def remove_policy(self, device): # This Method only prints a message on the screen when the device has been removed from the # Switching service. print '\n--Parental Control App:' print '*Device:', device, ' removed from the switching service!!!', '\n' # First, the device must be removed from the switching service: renese_message = { 'SenderId': DB().get_parentalcontrol_id(), 'ReceiverId': DB().get_switching_id(), 'Service': 'remove_Device', 'Arguments': { 'device_mac': device, 'device_port': 0, 'port_queue': 0 } } sender = Sender() sender.setMessageToSend(json.dumps(renese_message)) sender.start()
def switching_subscription(self): # Once the ParentalControl App has got the Id of the RENESE(s) requiered, the # subscription process must be carried out in order to use the underlying services. # For the ParentalControl App case, a subscription to the "Switching" and "DeviceTracking" # services is carried out. # After this process, the state of the corresponding subscription is saved. if DB().get_switching_subscription() == '': subscription = { 'SenderId': DB().get_parentalcontrol_id(), 'ReceiverId': DB().get_switching_id(), 'Service': 'subscription_request' } sender = Sender() sender.setMessageToSend(json.dumps(subscription)) sender.start() subscription['ReceiverId'] = DB().get_devicetracker_id() sender = Sender() sender.setMessageToSend(json.dumps(subscription)) sender.start() DB().save_switching_subscription('done')
def get_ReneseMessage(self, message): # This Method receives all RENESE Messages sent from the SDN Application layer. Thereby, the # the "connection" or "disconnection" of end user's devices on the network are notified by the # DeviceTracking service. # The messages Subscription and Service Discovery messages are also received. if message['Service'] == 'new_connection': policy = DB().get_policy(message['Arguments']['device_mac']) if len(policy) is not 0: self.set_policy(policy[0]) else: #if message['Service'] == 'new_connection': print '\n--Parental Control App:' print 'No policy for the new device. Please, define it!!' elif message['Service'] == 'disconnection': self.remove_policy( message['Arguments']['device_mac'] ) # This line must be removed because the flow entry will be automatically # removed by the OVS itself. elif message['Service'] == 'subscription_reply': print '\n---ParentalControl App: Service Subscription Reply received' elif message['Service'] == 'service_discovery_reply': print '\n---ParentalControl App: Service Discovery Reply received' DB().save_switching_id(message['SenderId']) elif message[ 'Service'] == 'resource_allocation_reply': # A resource allocation reply is received considering that a device policy = DB().get_policy( message['Arguments']['device_mac'] ) # is going to be added to the Switching service if len(policy) is not 0: self.updateSwitching(policy[0], message) else: print '\n---ParentalControl App: Unknown Service'
def set_policy(self, policy): # This Method specifies the action to be taken on the resources. # This information helps NERON to know if resources must be allocated # or released. if policy['action'] == 'allow': action = 'allocate' service = 'resource_allocation_request' elif policy['action'] == 'block': action = 'release' service = 'release_resources' self.remove_policy(policy['device']) # To build the RESENE Message the device port is requiered. To simplify the process # the information already stored in the DB about the device by the NetworkStatus App # is retrieve by the ParentalControl App. device_state = DB().get_state(policy['device']) # Before to add or remove a device to/from the switching service, it's necessary # to get the corresponding queue allocated by NERON. renese_message = { 'SenderId': DB().get_parentalcontrol_id(), 'ReceiverId': DB().get_neron_id(), 'Service': service, 'Arguments': { 'action': action, 'device_mac': policy['device'], 'priority': policy['priority'], 'device_port': device_state[0]['port'] } } #sleep(0.1) # A delay is introduced until the flow entry be installed on the OVS, otherwise the Drop flow entry # will not be removed. sender = Sender() sender.setMessageToSend(json.dumps(renese_message)) sender.start()
def delete_policy(self, device): # This Method deletes a policy of a specific device and removes the device from # the Switching service. query = DB().get_policies() policy = DB().get_policy(device) query.remove(policy[0]) DB().save_policies(query) DB().update_status( policy[0]['device'], 'policy', 'undefined') # The device state entry must be updated. policy[0]['action'] = 'block' self.set_policy(policy[0])
def devices_state(self): # The NetworkStatus App together with the DeviceTracking service inform the residential user about # all the devices that have been connected or disconnected. The Application groups into two categories, # the "ONLINE" devices and the "OFFLINE" devices. connected_devices = [] no_connected_devices = [] status = DB().get_status() for entry in status: if entry['state'] == 'online': connected_devices.append(entry['device']) if entry['state'] == 'offline': no_connected_devices.append(entry['device']) devices_state = {'ONLINE devices': connected_devices, 'OFFLINE devices': no_connected_devices} return devices_state
def define_policy(self, policy): # This Method stores the policy defined by the user in the DB. policies = DB().get_policies() policies.append(policy) DB().save_policies(policies) DB().update_status( policy['device'], 'policy', 'defined') # The device state entry must be updated. self.set_policy(policy)