Пример #1
0
 def __init__(self):
     core.openflow.addListeners(self, priority = of.OFP_DEFAULT_PRIORITY)
     self.database = PMdatabase()
     self.switches = {}  #device_id:Switch()
Пример #2
0
 def __init__(self):
     core.openflow.addListeners(self, priority = of.OFP_DEFAULT_PRIORITY)
     self.database = PMdatabase()
     self.switches = {}  #device_id:Switch()
Пример #3
0
class PofManager(EventMixin):
    
    def __init__(self):
        core.openflow.addListeners(self, priority = of.OFP_DEFAULT_PRIORITY)
        self.database = PMdatabase()
        self.switches = {}  #device_id:Switch()
          
    # Protocol functions
    def add_protocol(self, protocol_name, field_list):   # protocol_name: string, field_list: list of ofp_match20
        if field_list == None or len(field_list) == 0 or False == self.check_field_list(field_list):
            log.error("Add protocol failed")
            return OFPROTOCOLID_INVALID
        protocol_id = self.database.add_protocol(protocol_name, field_list) 
        log.info("Add Protocol: " + protocol_name + "protocol_id=" + str(protocol_id))
        return protocol_id
    
    def get_protocol_by_id(self, protocol_id):
        protocol_map = self.database.get_protocol_map()
        if protocol_map is None:
            return None
        return protocol_map.get(protocol_id)
    
    def get_protocol_by_name(self, protocol_name):
        protocol_name_map = self.database.get_protocol_name_map()
        if protocol_name_map is None:
            return None
        protocol_id = protocol_name_map.get(protocol_name)
        if protocol_id is not None:
            return self.get_protocol_by_id(protocol_id)
        return None
    
    def check_field_list(self, field_list):
        if field_list is None:
            return False
        previous_field_offset = 0
        previous_field_length = 0
        for field in field_list:
            if field.offset < previous_field_offset + previous_field_length:
                return False
            previous_field_offset = field.offset
            previous_field_length = field.length
        return True
    
    def get_all_protocol(self):
        protocol_list = []
        protocol_map = self.database.get_protocol_map()
        if protocol_map is not None:
            for protocol_id in protocol_map:
                protocol_list.append(protocol_map.get(protocol_id))
        return protocol_list
        
    def modify_protocol(self, protocol_id, new_field_list):
        protocol = self.get_protocol_by_id(protocol_id)
        if protocol is None:
            log.error("no such protocol")
            return False
        if new_field_list == None or len(new_field_list) == 0 or False == self.check_field_list(new_field_list):
            log.error("Modify protocol failed, wrong field_list")
            return False
        return self.database.modify_protocol(protocol, new_field_list)
        
    def del_protocol(self, protocol_id):
        protocol = self.get_protocol_by_id(protocol_id)
        if protocol is None:
            log.error("no such protocol")
            return False
        log.info("Delete Protocol: " + protocol.protocol_name + 'protocol_id=' + str(protocol_id))
        field_list = protocol.get_all_field()
        if field_list is not None:
            for field in field_list:
                self.delete_field(field.field_id)
        self.database.del_protocol(protocol)
        return True
        
    def del_all_protocol(self):
        protocol_list = self.get_all_protocol()
        if protocol_list is not None:
            for protocol in protocol_list:
                self.del_protocol(protocol.get_protocol_id())
    
    # Field functions
    def new_field(self, field_name, field_offset, field_length):   #return field_id
        return self.database.new_field(field_name, field_offset, field_length)
    
    def modify_field(self, field_id, field_name, field_offset, field_length):
        return self.database.modify_field(field_id, field_name, field_offset, field_length)
        
    def delete_field(self, field_id):
        return self.database.del_field(field_id)
    
    def get_field(self, field):   #type(field) is integer or string (field_id or field_name)
        if isinstance(field, int):
            return self.database.get_field_by_id(field)   #return a ofp_match20
        elif isinstance(field, str):
            return self.database.get_field_by_name(field)   #return a list of ofp_match20
        return None
    
    def get_all_field(self):   # return a list of ofp_match20
        return self.database.get_all_field()
        
    def get_belonged_protocol(self, field_id):
        protocol_map = self.database.get_protocol_map()
        if protocol_map != None:
            for protocol_id in protocol_map:
                field_list = protocol_map.get(protocol_id).get_all_field()
                for field in field_list:
                    if field.field_id == field_id:
                        return protocol_map.get(protocol_id)
        return None
    
    # METADATA functions
    def modify_metadata(self, metadata_list):  # metadata_list: a list of ofp_match20
        self.database.modify_metadata(metadata_list)
    
    def get_metadata(self):
        return self.database.get_metadata()     #return a list of ofp_match20
    
    def get_metadata_field(self, field_name):   # return a ofp_match20
        return self.database.get_metadata_field(field_name)
    
    def remove_all_metadata(self):
        self.database.get_metadata().clear()
        
    def new_metadata_field(self, field_name, field_offset, field_length):
        self.database.new_metadata_field(field_name, field_offset, field_length)
    
    # Flow Table functions
    def add_flow_table(self, switch_id, table_name, table_type, table_size, match_field_list = []): 
        # Have been tested
        if (switch_id not in self.switches) or (table_name == None) or (len(table_name) == 0):
            return FLOWTABLEID_INVALID
        if (table_size == 0) or (table_type < 0) or (table_type >= of.OF_MAX_TABLE_TYPE):
            return FLOWTABLEID_INVALID
        if (table_type == of.OF_LINEAR_TABLE) and (len(match_field_list) != 0):
            return FLOWTABLEID_INVALID
        if (table_type != of.OF_LINEAR_TABLE) and (len(match_field_list) == 0):
            return FLOWTABLEID_INVALID
        
        field_num = len(match_field_list)
        key_length = 0
        for field in match_field_list:
            key_length += field.length
            
        global_table_id = self.database.add_flow_table(switch_id, table_name, table_type, key_length, table_size, field_num, match_field_list)
        if global_table_id == FLOWTABLEID_INVALID:
            return FLOWTABLEID_INVALID
        flow_table = self.database.get_flow_table(switch_id, global_table_id)
        msg = of.ofp_table_mod()
        msg.flow_table = flow_table
        self.write_of(switch_id, msg)
        #self.add_sended_msg(switch_id, msg)
        return global_table_id
        
    def get_all_flow_table(self, switch_id):   # return a list of ofp_flow_table
        # Have been tested
        flow_table_map = self.database.get_flow_table_map(switch_id)
        if flow_table_map is None:
            return None
        return flow_table_map.values()
    
    def get_flow_table(self, switch_id, global_table_id):
        # Have been tested
        return self.database.get_flow_table(switch_id, global_table_id)
    
    def del_empty_flow_table(self, switch_id, global_table_id):
        # Have been tested
        flow_entry_map = self.database.get_flow_entries_map(switch_id, global_table_id)
        if len(flow_entry_map) != 0:
            log.error("table is not empty")
            return False
        flow_table = self.get_flow_table(switch_id, global_table_id)
        if flow_table is None:
            log.error("table doesn't exist, no need to delete")
            return True
        self.database.delete_flow_table(switch_id, flow_table.table_type, global_table_id)
        flow_table.command = of.OFPTC_DELETE  
        table_mod = of.ofp_table_mod()
        table_mod.flow_table = flow_table
        self.write_of(switch_id, table_mod)      # send to switch
        return True
        # TODO: add sended msg
    
    def del_flow_table_and_all_sub_entries(self, switch_id, global_table_id):
        # Have been tested
        flow_entry_map = self.database.get_flow_entries_map(switch_id, global_table_id)
        if flow_entry_map is None:
            log.error("This table doesn't exist, no need to delete!")
            return True
        for entry_id in flow_entry_map.keys():
            self.delete_flow_entry(switch_id, global_table_id, entry_id)
        self.del_empty_flow_table(switch_id, global_table_id)   #now, the table is empty
        return True
    
    def del_all_flow_tables(self, switch_id):
        # Have been tested
        table_list = self.get_all_flow_table(switch_id)    # list of ofp_flow_table
        if table_list is not None:
            for flow_table in table_list:
                global_table_id = self.parse_to_global_table_id(switch_id, flow_table.table_type, flow_table.table_id)
                self.del_flow_table_and_all_sub_entries(switch_id, global_table_id)
        return True
    
    def get_flow_table_no_base(self, switch_id, table_type):
        return self.database.get_flow_table_no_base(switch_id, table_type)
    
    def parse_to_small_table_id(self, switch_id, global_table_id):
        return self.database.parse_to_small_table_id(switch_id, global_table_id)
    
    def parse_to_global_table_id(self, switch_id, table_type, small_table_id):
        return self.database.parse_to_global_table_id(switch_id, table_type, small_table_id)
    
    # Flow Entry functions
    def add_flow_entry(self, switch_id, global_table_id, matchx_list, instruction_list, priority = 0, counter_enable = True):
        # return entry_id
        # Have been tested
        if not isinstance(matchx_list, list):
            log.error("wrong matchx_list")
            return FLOWENTRYID_INVALID
        if not isinstance(instruction_list, list):
            log.error("wrong instruction_list")
            return FLOWENTRYID_INVALID
        
        flow_table = self.get_flow_table(switch_id, global_table_id)
        if flow_table is None or not isinstance(flow_table, of.ofp_flow_table):
            log.error("wrong flow table")
            return FLOWENTRYID_INVALID
        
        table_type = flow_table.table_type
        if table_type == of.OF_LINEAR_TABLE and len(matchx_list) != 0:
            return FLOWENTRYID_INVALID
        if table_type != of.OF_LINEAR_TABLE and len(matchx_list) == 0:
            return FLOWENTRYID_INVALID
        
        if len(matchx_list) != 0:
            total_field_length = 0
            for matchx in matchx_list:
                if not isinstance(matchx, of.ofp_matchx):
                    log.error("wrong matchx")
                    return FLOWENTRYID_INVALID
                total_field_length += matchx.length
            if total_field_length != flow_table.key_length:
                log.error("wrong total field_length")
                return FLOWENTRYID_INVALID
                
        #TODO: CHECK DUPLICATION
        
        match_field_num = len(matchx_list)
        instruction_num = len(instruction_list)
        flow_entry_id = self.database.add_flow_entry(switch_id, global_table_id, match_field_num, matchx_list, instruction_num, instruction_list, priority, counter_enable)
        flow_entry = self.get_flow_entry(switch_id, global_table_id, flow_entry_id)
        self.write_of(switch_id, flow_entry)
        log.info('ADD <entry[' + str(flow_entry.table_type) + '][' + str(flow_entry.table_id) + '][' + str(flow_entry.index) + ']>')
        return flow_entry_id
    
    def get_flow_entry(self, switch_id, global_table_id, flow_entry_id):   #return ofp_flow_mod
        # Have been tested
        return self.database.get_flow_entry(switch_id, global_table_id, flow_entry_id)
    
    def get_all_flow_entry(self, switch_id, global_table_id):   #return a list of ofp_flow_mod
        # Have been tested
        #flow_entry_list = []
        flow_entry_map = self.database.get_flow_entries_map(switch_id, global_table_id)
        if flow_entry_map is None:
            return None
        return flow_entry_map.values()
    
    def get_all_matched_flow_entry(self, switch_id, global_table_id, matchx_list):   #return a list of ofp_flow_mod 
        pass
    
    def get_exact_matched_flow_entry(self, switch_id, global_table_id, matchx_list):  #return ofp_flow_mod
        pass
    
    def modify_flow_entry(self, switch_id, global_table_id, flow_entry_id, matchx_list, instruction_list, priority = 0, counter_enable = True):   # return boolean
        # Have been tested
        if not isinstance(matchx_list, list):
            log.error("wrong matchx_list")
            return False
        if not isinstance(instruction_list, list):
            log.error("wrong instruction_list")
            return False
        
        flow_table = self.get_flow_table(switch_id, global_table_id)
        if flow_table is None or not isinstance(flow_table, of.ofp_flow_table):
            log.error("wrong flow table")
            return False
        table_type = flow_table.table_type
        if table_type == of.OF_LINEAR_TABLE and len(matchx_list) != 0:
            return False
        if table_type != of.OF_LINEAR_TABLE and len(matchx_list) == 0:
            return False
        
        if len(matchx_list) != 0:
            total_field_length = 0
            for matchx in matchx_list:
                if not isinstance(matchx, of.ofp_matchx):
                    log.error("wrong matchx")
                    return False
                total_field_length += matchx.length
            if total_field_length != flow_table.key_length:
                log.error("wrong total field_length")
                return False
        """
        old_flow_mod = self.database.get_flow_entry(switch_id, global_table_id, flow_entry_id)
        if old_flow_mod is None:
            return False
        """
        #TODO: CHECK DUPLICATION
        
        match_field_num = len(matchx_list)
        instruction_num = len(instruction_list)  #FIXME:
        self.database.modify_flow_entry(switch_id, global_table_id, flow_entry_id, match_field_num, matchx_list, instruction_num, instruction_list, priority, counter_enable)
        flow_entry = self.get_flow_entry(switch_id, global_table_id, flow_entry_id)
        flow_entry.command = of.OFPFC_MODIFY  # 1
        self.write_of(switch_id, flow_entry)
        log.info('MOD <entry[' + str(flow_entry.table_type) + '][' + str(flow_entry.table_id) + '][' + str(flow_entry.index) + ']>')
        # TODO: add sended msg
        return True
    
    def delete_flow_entry(self, switch_id, global_table_id, index):
        #Have been tested
        flow_entry = self.database.get_flow_entry(switch_id, global_table_id, index)
        if flow_entry is None or not isinstance(flow_entry, of.ofp_flow_mod):
            return None
        self.database.delete_flow_entry(switch_id, global_table_id, index)   # delete flow_entry from the database
        flow_entry.command = of.OFPFC_DELETE  # 3
        self.write_of(switch_id, flow_entry)
        log.info('DELETE <entry[' + str(flow_entry.table_type) + '][' + str(flow_entry.table_id) + '][' + str(flow_entry.index) + ']>')
        # TODO: add sended msg
        # TODO: delete match key
    
    def check_flow_entry_reduplication(self):
        pass
    
    # Port functions
    def set_port_status(self, switch_id, port_status):
        self.database.set_port_status(switch_id, port_status)
        #TODO: need to display in the GUI
    
    def get_port_status(self, switch_id, port_id):
        #return self.database.get_switch_DB(switch_id).get_port(port_id)
        return self.database.get_port_status(switch_id, port_id)
    
    def get_port_id_by_name(self, switch_id, port_name):
        return self.database.get_switch_DB(switch_id).get_port_id_by_name(port_name)
    
    def set_port_of_enable(self, device_id, port_id, onoff = True):
        self.database.set_port_of_enable(device_id, port_id, onoff)
        port = self.database.get_port_status(device_id, port_id)   # instance of ofp_port_status
        if port != None:
            msg = of.ofp_port_mod(reason = of.OFPPR_MODIFY)    # OFPPR_MODIFY = 2
            msg.desc = port.desc
            self.write_of(device_id, msg)
            log.info("Port [" + str(port.desc.port_id) + "] Set pof enable [" + str(port.desc.device_id) + "]")
            
    def get_all_port_id(self, switch_id):
        return self.database.get_all_port_id(switch_id)   # return a list of port_id
            
    # Switch functions
    def add_switch(self, switch_id, sw):
        self.switches[switch_id] = sw
    
    def remove_switch(self, switch_id):
        self.switches.pop(switch_id)
        
    def get_switch_by_id(self, switch_id):
        return self.switches.get(switch_id)
    
    def check_switch_connected(self, switch_id):
        pass   #FIXME:
    
    def get_all_switch_id(self):
        return self.database.get_all_switch_id()
    
    def send_all_of_messages_base_on_DB(self):
        pass  #FIXME:
    
    def write_of(self, switch_id, ofp):
        #time.sleep(0.1)
        sw = self.get_switch_by_id(switch_id)
        sw.connection.send(ofp)
        
    # Resource report functions
    def get_resource_report_map(self, switch_id):
        return self.database.get_resource_report_map(switch_id)
    
    def get_resource_report(self, switch_id, slot_id):
        return self.database.get_resource_report(switch_id, slot_id)
    
    # Counter functions
    def allocate_counter(self, switch_id):   # return counter_id
        pass
    
    def free_counter(self, switch_id, counter_id): # return ofp_counter
        pass
    
    def free_all_counters(self, switch_id):
        pass
    
    def reset_counter(self, switch_id, counter_id, writo_to_switch=True):   #return boolean
        pass
    
    def query_counter_value(self, switch_id, counter_id):   # return a ofp_counter
        if self.database.get_counter(switch_id, counter_id) is None:
            return None
        """
        value = of.ofp_counter()
        value.counter_id = counter_id
        counter_reply_list = []
        """
        counter_req = of.ofp_counter_request()
        counter_req.counter.counter_id = counter_id
        counter_req.counter.command = of.OFPCC_QUERY
        self.write_of(switch_id, counter_req)
        #FIXME:
    
    # Meter functions
    def add_meter_entry(self, switch_id, rate):  # return meter_id
        pass
    
    def free_meter(self, switch_id, meter_id):  # return ofp_meter_mod
        pass
    
    def free_all_meters(self, switch_id):
        pass
    
    def get_meter(self, switch_id, meter_id):  # return ofp_meter_mod
        pass
        
    def get_all_meters(self, switch_id):   #return a list of ofp_meter_mod
        pass
    
    def modify_meter(self, switch_id, meter_id, rate):   #return boolean
        pass
    
    # Group functions
    def add_group_entry(self, switch_id, group_type, action_num, action_list, counter_enable = True):
        pass
    
    def free_group_entry(self, switch_id, group_id):  #return ofp_group_mod
        pass
    
    def get_group_entry(self, switch_id, group_id):  #return ofp_group_mod
        pass
    
    def modify_group_entry(self, switch_id, group_id, group_type, action_num, action_list, counter_enable = True):
        pass
    
    def get_all_groups(self, switch_id):
        pass
    
    def free_all_groups(self, switch_id):
        pass
    
    # Matchx functions
    def new_matchx(self, field, value, mask):
        """
        """
        if isinstance(field, int):   #field_id
            field = self.get_field(field)   # get match20
        elif isinstance(field, of.ofp_match20):
            pass
        else:
            log.error("Wrong parameter: field")
        matchx = of.ofp_matchx(match20 = field)
        matchx.value = value
        matchx.mask = mask
        return matchx
    
    # Instruction functions
    def new_ins_goto_table(self, switch_id, next_global_table_id, packet_offset = 0):    # 1
        next_flow_table = self.database.get_flow_table(switch_id, next_global_table_id)
        match_field_num = next_flow_table.match_field_num
        match_field_list = next_flow_table.match_field_list
        instruction = of.ofp_instruction_goto_table()
        instruction.next_table_id = next_global_table_id
        instruction.match_field_num = match_field_num
        instruction.match_list = match_field_list
        instruction.packet_offset = packet_offset
        return instruction
    
    def new_ins_goto_direct_table(self, next_global_table_id, index_type, packet_offset, index_value, index_field = None):   # 8
        instruction = of.ofp_instruction_goto_direct_table()
        instruction.next_table_id = next_global_table_id
        instruction.index_type = index_type
        instruction.packet_offset = packet_offset
        instruction.index_value = index_value
        instruction.index_field = index_field
        return instruction
        
    def new_ins_write_metadata(self, metadata_offset, write_length, value):  # 2
        instruction = of.ofp_instruction_write_metadata()
        instruction.metadata_offset = metadata_offset
        instruction.write_length = write_length
        instruction.value = value
        return instruction
    
    def new_ins_write_metadata_from_packet(self, metadata_offset, write_length, packet_offset = 0):  # 7
        instruction = of.ofp_instruction_write_metadata_from_packet()
        instruction.metadata_offset = metadata_offset
        instruction.write_length = write_length
        instruction.packet_offset = packet_offset
        return instruction
    
    def new_ins_meter(self, meter_id):
        instruction = of.ofp_instruction_meter()
        instruction.meter_id = meter_id
        return instruction
        
    def new_ins_calculate_field(self, calc_type, src_value_type, des_field, src_value, src_field = None):
        instruction = of.ofp_instruction_calculate_field()
        instruction.calc_type = calc_type  # ofp_calc_type_map, +,-,....
        instruction.src_value_type = src_value_type   #0: use srcField_Value; 1: use srcField;
        instruction.des_field = des_field
        instruction.src_value = src_value
        instruction.src_field = src_field
        return instruction
    
    def new_ins_apply_actions(self, action_list = []):   # 4
        action_num = len(action_list)
        instruction = of.ofp_instruction_apply_actions()
        instruction.action_num = action_num
        instruction.action_list = action_list
        return instruction
    
    # Action functions
    def new_action_output(self, port_id_value_type, metadata_offset, metadata_length, packet_offset, port_id, port_id_field = None):  # 0
        #port_id_value_type: 0 for immediate number and 1 for field, metadata_offset:int
        action = of.ofp_action_output()
        action.port_id_value_type = port_id_value_type
        action.metadata_offset = metadata_offset
        action.metadata_length = metadata_length
        action.packet_offset = packet_offset
        action.port_id = port_id
        action.port_id_field = port_id_field
        return action
    
    def new_action_set_field(self, field_setting):  # 1
        #field_setting:ofp_matchx
        action = of.ofp_action_set_field()
        action.field_setting = field_setting
        return action
    
    def new_action_set_field_from_metadata(self, field_setting, metadata_offset):  # 2
        #field_setting:ofp_matchx, metadata_offset:int
        action = of.ofp_action_set_field_from_metadata()
        action.field_setting = field_setting
        action.metadata_offset = metadata_offset
        return action
    
    def new_action_modify_field(self, match_field, increment):  #3
        #match_field:ofp_match20, increment:int
        action = of.ofp_action_modify_field()
        action.match_field = match_field
        action.increment = increment
        return action
        
    def new_action_add_field(self, field_id, field_position, field_length, field_value):  #4
        #field_id:int, field_position:int, field_length:int, field_value:string
        action = of.ofp_action_add_field()
        action.field_id = field_id
        action.field_position = field_position
        action.field_length = field_length
        action.field_value = field_value
        return action
    
    def new_action_delete_field(self, field_position, length_value_type, length_value, length_field = None):  #5
        """generate a instance of ofp_action_delete_field (action_type: 5)
        
        Args:
        
        Returns:
            A instance of ofp_action_delete_field (action_type: 5)
        
        Raises:
        """
        #field_position:int, length_value_type:0 for immediate number and 1 for field, length_value:int, length_field:ofp_match20
        action = of.ofp_action_delete_field()
        action.tag_position = field_position
        action.tag_length_value_type = length_value_type
        action.tag_length_value = length_value
        action.tag_length_field = length_field
        return action
    
    def new_action_calculate_checksum(self,checksum_pos_type,calc_pos_type,checksum_position,checksum_length,calc_start_position,calc_length): #6
        #
        action = of.ofp_action_calculate_checksum()
        action.checksum_pos_type = checksum_pos_type     #0: packet; 1: metadata
        action.calc_pos_type = calc_pos_type             #0: packet; 1: metadata
        action.checksum_position = checksum_position
        action.checksum_length = checksum_length
        action.calc_start_position = calc_start_position
        action.calc_length = calc_length
        return action
    
    def new_action_group(self, group_id):  #7
        action = of.ofp_action_group()
        action.group_id = group_id
        return action
    
    def new_action_drop(self, reason):  #8
        action = of.ofp_action_drop()
        action.reason = reason
        return action
    
    def new_action_packetin(self, reason):  #9
        action = of.ofp_action_packetin()
        action.reason = reason
        return action
    
    def new_action_counter(self, counter_id):  #10
        action = of.ofp_action_counter()
        action.counter_id = counter_id
        return action
    
    def save_all_data_into_file(self, file_name = DEFAULT_SAVE_FILE_NAME):
        pass
    
    def save_metadata_into_file(self):
        pass
    
    def load_all_data_from_file(self):
        pass
    
    def load_metadata_from_file(self):
        pass
    
    def send_all_of_msg_based_on_DB(self):
        pass
    
    # Handlers of POF messages
    def _handle_FeaturesReceived(self, event):
        #print "PofManager: Features Reply Received"
        features_reply = event.ofp
        if not isinstance(features_reply, of.ofp_features_reply):
            log.error("wrong features_reply")
        
        device_id = event.dpid
        sw = Switch()
        #sw.set_device_id(features_reply.device_id)
        sw.set_device_id(device_id)
        sw.connect(event.connection)
        self.add_switch(device_id, sw)
        
        self.database.add_switch_DB(device_id)
        self.database.set_features(device_id, features_reply)
        
    def _handle_ResourceReport(self, event):
        #print "PofManager: Resource Report Received"
        switch_id = event.dpid
        resource_report = event.ofp
        self.database.set_resource_report(switch_id, resource_report)
        
    def _handle_PortStatus(self, event):
        #print "PofManager: Port Status Received"     #for test
        port_status = event.ofp    # ofp_port_status 
        port = port_status.desc    # ofp_phy_port
        if port_status.reason == of.OFPPR_ADD:    # 0
            self.database.set_port_status(port.device_id, port_status)
            log.info("Port [" + str(port.port_id) + "] added for Switch [" + str(port.device_id) + "]")
            #self.set_port_of_enable(event.dpid, port.port_id)    #set pof_enable
        elif port_status.reason == of.OFPPR_DELETE: # 1
            self.database.del_port_status(port.device_id, port.port_id)
            log.info("Port [" + str(port.port_id) + "] deleted for Switch [" + str(port.device_id) + "]")
        elif port_status.reason == of.OFPPR_MODIFY:   # 2
            self.database.set_port_status(port.device_id, port_status)
            log.info("Port [" + str(port.port_id) + "] modified for Switch [" + str(port.device_id) + "]")
            
    def _handle_CounterReply(self, event):
        print 'PofManager: CounterReply received'
Пример #4
0
class PofManager(EventMixin):
    
    def __init__(self):
        core.openflow.addListeners(self, priority = of.OFP_DEFAULT_PRIORITY)
        self.database = PMdatabase()
        self.switches = {}  #device_id:Switch()
          
    # Protocol functions
    def add_protocol(self, protocol_name, field_list):   # protocol_name: string, field_list: list of ofp_match20
        if field_list == None or len(field_list) == 0 or False == self.check_field_list(field_list):
            log.error("Add protocol failed")
            return OFPROTOCOLID_INVALID
        protocol_id = self.database.add_protocol(protocol_name, field_list) 
        log.info("Add Protocol: [protocol_name] " + protocol_name + " [protocol_id] " + str(protocol_id))
        return protocol_id
    
    def get_protocol_by_id(self, protocol_id):
        protocol_map = self.database.get_protocol_map()
        if protocol_map is None:
            return None
        return protocol_map.get(protocol_id)
    
    def get_protocol_by_name(self, protocol_name):
        protocol_name_map = self.database.get_protocol_name_map()
        if protocol_name_map is None:
            return None
        protocol_id = protocol_name_map.get(protocol_name)
        if protocol_id is not None:
            return self.get_protocol_by_id(protocol_id)
        return None
    
    def check_field_list(self, field_list):
        if field_list is None:
            return False
        previous_field_offset = 0
        previous_field_length = 0
        for field in field_list:
            if field.offset < previous_field_offset + previous_field_length:
                return False
            previous_field_offset = field.offset
            previous_field_length = field.length
        return True
    
    def get_all_protocol(self):
        protocol_list = []
        protocol_map = self.database.get_protocol_map()
        if protocol_map is not None:
            for protocol_id in protocol_map:
                protocol_list.append(protocol_map.get(protocol_id))
        return protocol_list
        
    def modify_protocol(self, protocol_id, new_field_list):
        protocol = self.get_protocol_by_id(protocol_id)
        if protocol is None:
            log.error("no such protocol")
            return False
        if new_field_list == None or len(new_field_list) == 0 or False == self.check_field_list(new_field_list):
            log.error("Modify protocol failed, wrong field_list")
            return False
        return self.database.modify_protocol(protocol, new_field_list)
        
    def del_protocol(self, protocol_id):
        protocol = self.get_protocol_by_id(protocol_id)
        if protocol is None:
            log.error("no such protocol")
            return False
        log.info("Delete Protocol: " + protocol.protocol_name + 'protocol_id=' + str(protocol_id))
        field_list = protocol.get_all_field()
        if field_list is not None:
            for field in field_list:
                self.delete_field(field.field_id)
        self.database.del_protocol(protocol)
        return True
        
    def del_all_protocol(self):
        protocol_list = self.get_all_protocol()
        if protocol_list is not None:
            for protocol in protocol_list:
                self.del_protocol(protocol.get_protocol_id())
    
    # Field functions
    def new_field(self, field_name, field_offset, field_length):   #return field_id
        field_id = self.database.new_field(field_name, field_offset, field_length)
        return field_id
    
    def modify_field(self, field_id, field_name, field_offset, field_length):  #return boolean
        return self.database.modify_field(field_id, field_name, field_offset, field_length)
        
    def delete_field(self, field_id):
        return self.database.del_field(field_id)
    
    def get_field(self, field):   #type(field) is integer or string (field_id or field_name)
        if isinstance(field, int):
            return self.database.get_field_by_id(field)   #return a ofp_match20
        elif isinstance(field, str):
            return self.database.get_field_by_name(field)   #return a list of ofp_match20
        return None
    
    def get_all_field(self):   # return a list of ofp_match20
        return self.database.get_all_field()
        
    def get_belonged_protocol(self, field_id):
        protocol_map = self.database.get_protocol_map()
        if protocol_map != None:
            for protocol_id in protocol_map:
                field_list = protocol_map.get(protocol_id).get_all_field()
                for field in field_list:
                    if field.field_id == field_id:
                        return protocol_map.get(protocol_id)
        return None
    
    # METADATA functions
    def modify_metadata(self, metadata_list):  # metadata_list: a list of ofp_match20
        self.database.modify_metadata(metadata_list)
    
    def get_metadata(self):
        return self.database.get_metadata()     #return a list of ofp_match20
    
    def get_metadata_field(self, field_name):   # return a ofp_match20
        return self.database.get_metadata_field(field_name)
    
    def remove_all_metadata(self):
        self.database.get_metadata().clear()
        
    def new_metadata_field(self, field_name, field_offset, field_length):
        self.database.new_metadata_field(field_name, field_offset, field_length)
    
    # Flow Table functions
    def add_flow_table(self, switch_id, table_name, table_type, table_size, match_field_list = []): 
        # Have been tested
        if (switch_id not in self.switches) or (table_name == None) or (len(table_name) == 0):
            log.error("no such switch_id or wrong table name")
            return FLOWTABLEID_INVALID
        if (table_size == 0) or (table_type < 0) or (table_type >= of.OF_MAX_TABLE_TYPE):
            log.error("wrong table size or wrong table type")
            return FLOWTABLEID_INVALID
        if (table_type == of.OF_LINEAR_TABLE) and (len(match_field_list) != 0):
            log.error("wrong match_field_list")
            return FLOWTABLEID_INVALID
        if (table_type != of.OF_LINEAR_TABLE) and (len(match_field_list) == 0):
            log.error("wrong match_field_list")
            return FLOWTABLEID_INVALID
        
        field_num = len(match_field_list)  # calculate the field_num
        key_length = 0
        for field in match_field_list:     # calculate the key_length
            key_length += field.length
            
        global_table_id = self.database.add_flow_table(switch_id, table_name, table_type, key_length, table_size, field_num, match_field_list)
        if global_table_id == FLOWTABLEID_INVALID:
            log.error("ERROR when add flow table in PMDatabase")
            return FLOWTABLEID_INVALID
        flow_table = self.database.get_flow_table(switch_id, global_table_id)
        msg = of.ofp_table_mod()
        msg.flow_table = flow_table
        self.write_of(switch_id, msg)
        msg_info = ''
        msg_info += ('ADD <table[' + str(flow_table.table_type) + '][' + str(flow_table.table_id) + ']> ')
        msg_info += ('[G_TID] ' + str(global_table_id) + ' [T_NAME] ' + flow_table.table_name)
        #log.info('ADD <table[' + str(flow_table.table_type) + '][' + str(flow_table.table_id) + ']> ' + flow_table.table_name)
        log.info(msg_info)
        #self.add_sended_msg(switch_id, msg)
        return global_table_id
        
    def get_all_flow_table(self, switch_id):   # return a list of ofp_flow_table
        # Have been tested
        flow_table_map = self.database.get_flow_table_map(switch_id)
        if flow_table_map is None:
            return None
        return flow_table_map.values()
    
    def get_flow_table(self, switch_id, global_table_id):   # return ofp_flow_table
        # Have been tested
        return self.database.get_flow_table(switch_id, global_table_id)
    
    def get_flow_table_id(self, switch_id, table_name):   # return global_table_id
        return self.database.get_flow_table_id(switch_id, table_name)
    
    def del_empty_flow_table(self, switch_id, global_table_id):
        # Have been tested
        flow_entry_map = self.database.get_flow_entries_map(switch_id, global_table_id)
        if len(flow_entry_map) != 0:
            log.error("table is not empty")
            return False
        flow_table = self.get_flow_table(switch_id, global_table_id)
        if flow_table is None:
            log.error("table doesn't exist, no need to delete")
            return True
        self.database.delete_flow_table(switch_id, flow_table.table_type, global_table_id)
        flow_table.command = of.OFPTC_DELETE  
        table_mod = of.ofp_table_mod()
        table_mod.flow_table = flow_table
        self.write_of(switch_id, table_mod)      # send to switch
        return True
        # TODO: add sended msg
    
    def del_flow_table_and_all_sub_entries(self, switch_id, global_table_id):
        # Have been tested
        flow_entry_map = self.database.get_flow_entries_map(switch_id, global_table_id)
        if flow_entry_map is None:
            log.error("This table doesn't exist, no need to delete!")
            return True
        for entry_id in flow_entry_map.keys():
            self.delete_flow_entry(switch_id, global_table_id, entry_id)
        self.del_empty_flow_table(switch_id, global_table_id)   #now, the table is empty
        return True
    
    def del_all_flow_tables(self, switch_id):
        # Have been tested
        table_list = self.get_all_flow_table(switch_id)    # list of ofp_flow_table
        if table_list is not None:
            for flow_table in table_list:
                global_table_id = self.parse_to_global_table_id(switch_id, flow_table.table_type, flow_table.table_id)
                self.del_flow_table_and_all_sub_entries(switch_id, global_table_id)
        return True
    
    def get_flow_table_no_base(self, switch_id, table_type):
        return self.database.get_flow_table_no_base(switch_id, table_type)
    
    def parse_to_small_table_id(self, switch_id, global_table_id):
        return self.database.parse_to_small_table_id(switch_id, global_table_id)
    
    def parse_to_global_table_id(self, switch_id, table_type, small_table_id):
        return self.database.parse_to_global_table_id(switch_id, table_type, small_table_id)
    
    # Flow Entry functions
    def add_flow_entry(self, switch_id, global_table_id, matchx_list, instruction_list, priority = 0, counter_enable = True):
        # return entry_id
        # Have been tested
        if not isinstance(matchx_list, list):
            log.error("wrong matchx_list")
            return FLOWENTRYID_INVALID
        if not isinstance(instruction_list, list):
            log.error("wrong instruction_list")
            return FLOWENTRYID_INVALID
        
        flow_table = self.get_flow_table(switch_id, global_table_id)
        if flow_table is None or not isinstance(flow_table, of.ofp_flow_table):
            log.error("wrong flow table")
            return FLOWENTRYID_INVALID
        
        table_type = flow_table.table_type
        if table_type == of.OF_LINEAR_TABLE and len(matchx_list) != 0:
            return FLOWENTRYID_INVALID
        if table_type != of.OF_LINEAR_TABLE and len(matchx_list) == 0:
            return FLOWENTRYID_INVALID
        
        if len(matchx_list) != 0:
            total_field_length = 0
            for matchx in matchx_list:
                if not isinstance(matchx, of.ofp_matchx):
                    log.error("wrong matchx")
                    return FLOWENTRYID_INVALID
                total_field_length += matchx.length
            if total_field_length != flow_table.key_length:
                log.error("wrong total field_length")
                return FLOWENTRYID_INVALID
                
        #TODO: CHECK DUPLICATION
        
        match_field_num = len(matchx_list)
        instruction_num = len(instruction_list)
        flow_entry_id = self.database.add_flow_entry(switch_id, global_table_id, match_field_num, matchx_list, instruction_num, instruction_list, priority, counter_enable)
        flow_entry = self.get_flow_entry(switch_id, global_table_id, flow_entry_id)
        self.write_of(switch_id, flow_entry)
        log.info('ADD <entry[' + str(flow_entry.table_type) + '][' + str(flow_entry.table_id) + '][' + str(flow_entry.index) + ']>')
        return flow_entry_id
    
    def get_flow_entry(self, switch_id, global_table_id, flow_entry_id):   #return ofp_flow_mod
        # Have been tested
        return self.database.get_flow_entry(switch_id, global_table_id, flow_entry_id)
    
    def get_all_flow_entry(self, switch_id, global_table_id):   #return a list of ofp_flow_mod
        # Have been tested
        #flow_entry_list = []
        flow_entry_map = self.database.get_flow_entries_map(switch_id, global_table_id)
        if flow_entry_map is None:
            return None
        return flow_entry_map.values()
    
    def get_all_matched_flow_entry(self, switch_id, global_table_id, matchx_list):   #return a list of ofp_flow_mod 
        pass
    
    def get_exact_matched_flow_entry(self, switch_id, global_table_id, matchx_list):  #return ofp_flow_mod
        pass
    
    def modify_flow_entry(self, switch_id, global_table_id, flow_entry_id, matchx_list, instruction_list, priority = 0, counter_enable = True):   # return boolean
        # Have been tested
        if not isinstance(matchx_list, list):
            log.error("wrong matchx_list")
            return False
        if not isinstance(instruction_list, list):
            log.error("wrong instruction_list")
            return False
        
        flow_table = self.get_flow_table(switch_id, global_table_id)
        if flow_table is None or not isinstance(flow_table, of.ofp_flow_table):
            log.error("wrong flow table")
            return False
        table_type = flow_table.table_type
        if table_type == of.OF_LINEAR_TABLE and len(matchx_list) != 0:
            return False
        if table_type != of.OF_LINEAR_TABLE and len(matchx_list) == 0:
            return False
        
        if len(matchx_list) != 0:
            total_field_length = 0
            for matchx in matchx_list:
                if not isinstance(matchx, of.ofp_matchx):
                    log.error("wrong matchx")
                    return False
                total_field_length += matchx.length
            if total_field_length != flow_table.key_length:
                log.error("wrong total field_length")
                return False
        """
        old_flow_mod = self.database.get_flow_entry(switch_id, global_table_id, flow_entry_id)
        if old_flow_mod is None:
            return False
        """
        #TODO: CHECK DUPLICATION
        
        match_field_num = len(matchx_list)
        instruction_num = len(instruction_list)  #FIXME:
        self.database.modify_flow_entry(switch_id, global_table_id, flow_entry_id, match_field_num, matchx_list, instruction_num, instruction_list, priority, counter_enable)
        flow_entry = self.get_flow_entry(switch_id, global_table_id, flow_entry_id)
        flow_entry.command = of.OFPFC_MODIFY  # 1
        self.write_of(switch_id, flow_entry)
        log.info('MOD <entry[' + str(flow_entry.table_type) + '][' + str(flow_entry.table_id) + '][' + str(flow_entry.index) + ']>')
        # TODO: add sended msg
        return True
    
    def delete_flow_entry(self, switch_id, global_table_id, index):
        #Have been tested
        flow_entry = self.database.get_flow_entry(switch_id, global_table_id, index)
        if flow_entry is None or not isinstance(flow_entry, of.ofp_flow_mod):
            return None
        self.database.delete_flow_entry(switch_id, global_table_id, index)   # delete flow_entry from the database
        flow_entry.command = of.OFPFC_DELETE  # 3
        self.write_of(switch_id, flow_entry)
        log.info('DELETE <entry[' + str(flow_entry.table_type) + '][' + str(flow_entry.table_id) + '][' + str(flow_entry.index) + ']>')
        # TODO: add sended msg
        # TODO: delete match key
    
    def check_flow_entry_reduplication(self):
        pass
    
    # Port functions
    def set_port_status(self, switch_id, port_status):
        self.database.set_port_status(switch_id, port_status)
        #TODO: need to display in the GUI
    
    def get_port_status(self, switch_id, port_id):
        #return self.database.get_switch_DB(switch_id).get_port(port_id)
        return self.database.get_port_status(switch_id, port_id)
    
    def get_port_id_by_name(self, switch_id, port_name):
        return self.database.get_switch_DB(switch_id).get_port_id_by_name(port_name)
    
    def set_port_of_enable(self, device_id, port_id, onoff = True):
        self.database.set_port_of_enable(device_id, port_id, onoff)
        port = self.database.get_port_status(device_id, port_id)   # instance of ofp_port_status
        if port != None:
            msg = of.ofp_port_mod(reason = of.OFPPR_MODIFY)    # OFPPR_MODIFY = 2
            msg.desc = port.desc
            self.write_of(device_id, msg)
            #log.info("Port [" + str(port.desc.port_id) + "] Set pof enable [" + str(port.desc.device_id) + "]")
            log.info("Port [" + "0x%x" % port.desc.port_id + "] Set POF Enable [" + str(port.desc.device_id) + "]")
            
    def get_all_port_id(self, switch_id):
        return self.database.get_all_port_id(switch_id)   # return a list of port_id
            
    # Switch functions
    def add_switch(self, switch_id, sw):
        self.switches[switch_id] = sw
    
    def remove_switch(self, switch_id):
        self.switches.pop(switch_id)
        
    def get_switch_by_id(self, switch_id):
        return self.switches.get(switch_id)
    
    def check_switch_connected(self, switch_id):
        pass   #FIXME:
    
    def get_all_switch_id(self):
        return self.database.get_all_switch_id()
    
    def send_all_of_messages_base_on_DB(self):
        pass  #FIXME:
    
    def write_of(self, switch_id, ofp):
        #time.sleep(0.1)
        sw = self.get_switch_by_id(switch_id)
        sw.connection.send(ofp)
        
    # Resource report functions
    def get_resource_report_map(self, switch_id):
        return self.database.get_resource_report_map(switch_id)
    
    def get_resource_report(self, switch_id, slot_id):
        return self.database.get_resource_report(switch_id, slot_id)
    
    # Counter functions
    def allocate_counter(self, switch_id):   # return counter_id
        pass
    
    def free_counter(self, switch_id, counter_id): # return ofp_counter
        pass
    
    def free_all_counters(self, switch_id):
        pass
    
    def reset_counter(self, switch_id, counter_id, writo_to_switch=True):   #return boolean
        pass
    
    def query_counter_value(self, switch_id, counter_id):   # return a ofp_counter
        if self.database.get_counter(switch_id, counter_id) is None:
            return None
        """
        value = of.ofp_counter()
        value.counter_id = counter_id
        counter_reply_list = []
        """
        counter_req = of.ofp_counter_request()
        counter_req.counter.counter_id = counter_id
        counter_req.counter.command = of.OFPCC_QUERY
        self.write_of(switch_id, counter_req)
        #FIXME:
    
    # Meter functions
    def add_meter_entry(self, switch_id, rate):  # return meter_id
        pass
    
    def free_meter(self, switch_id, meter_id):  # return ofp_meter_mod
        pass
    
    def free_all_meters(self, switch_id):
        pass
    
    def get_meter(self, switch_id, meter_id):  # return ofp_meter_mod
        pass
        
    def get_all_meters(self, switch_id):   #return a list of ofp_meter_mod
        pass
    
    def modify_meter(self, switch_id, meter_id, rate):   #return boolean
        pass
    
    # Group functions
    def add_group_entry(self, switch_id, group_type, action_num, action_list, counter_enable = True):
        pass
    
    def free_group_entry(self, switch_id, group_id):  #return ofp_group_mod
        pass
    
    def get_group_entry(self, switch_id, group_id):  #return ofp_group_mod
        pass
    
    def modify_group_entry(self, switch_id, group_id, group_type, action_num, action_list, counter_enable = True):
        pass
    
    def get_all_groups(self, switch_id):
        pass
    
    def free_all_groups(self, switch_id):
        pass
    
    # Matchx functions
    def new_matchx(self, field, value, mask):
        """
        field: field_id or an instance of ofp_match20
        value: hexadecimal string
        mask: hexadecimal string
        """
        if isinstance(field, int):   #field_id
            field = self.get_field(field)   # get match20
        elif isinstance(field, of.ofp_match20):
            pass
        else:
            log.error("Wrong parameter: field")
        matchx = of.ofp_matchx(match20 = field)
        matchx.value = value
        matchx.mask = mask
        return matchx
    
    # Instruction functions
    def new_ins_goto_table(self, switch_id, next_global_table_id, packet_offset = 0):    # 1
        next_flow_table = self.database.get_flow_table(switch_id, next_global_table_id)
        match_field_num = next_flow_table.match_field_num
        match_field_list = next_flow_table.match_field_list
        instruction = of.ofp_instruction_goto_table()
        instruction.next_table_id = next_global_table_id
        instruction.match_field_num = match_field_num
        instruction.match_list = match_field_list
        instruction.packet_offset = packet_offset
        return instruction
    
    def new_ins_goto_direct_table(self, next_global_table_id, index_type, packet_offset, index_value, index_field = None):   # 8
        instruction = of.ofp_instruction_goto_direct_table()
        instruction.next_table_id = next_global_table_id
        instruction.index_type = index_type
        instruction.packet_offset = packet_offset
        instruction.index_value = index_value
        instruction.index_field = index_field
        return instruction
        
    def new_ins_write_metadata(self, metadata_offset, write_length, value):  # 2
        instruction = of.ofp_instruction_write_metadata()
        instruction.metadata_offset = metadata_offset
        instruction.write_length = write_length
        instruction.value = value
        return instruction
    
    def new_ins_write_metadata_from_packet(self, metadata_offset, write_length, packet_offset = 0):  # 7
        instruction = of.ofp_instruction_write_metadata_from_packet()
        instruction.metadata_offset = metadata_offset
        instruction.write_length = write_length
        instruction.packet_offset = packet_offset
        return instruction
    
    def new_ins_meter(self, meter_id):
        instruction = of.ofp_instruction_meter()
        instruction.meter_id = meter_id
        return instruction
        
    def new_ins_calculate_field(self, calc_type, src_value_type, des_field, src_value, src_field = None):
        instruction = of.ofp_instruction_calculate_field()
        instruction.calc_type = calc_type  # ofp_calc_type_map, +,-,....
        instruction.src_value_type = src_value_type   #0: use srcField_Value; 1: use srcField;
        instruction.des_field = des_field
        instruction.src_value = src_value
        instruction.src_field = src_field
        return instruction
    
    def new_ins_apply_actions(self, action_list = []):   # 4
        action_num = len(action_list)
        instruction = of.ofp_instruction_apply_actions()
        instruction.action_num = action_num
        instruction.action_list = action_list
        return instruction
    
    # Action functions
    def new_action_output(self, port_id_value_type, metadata_offset, metadata_length, packet_offset, port_id, port_id_field = None):  # 0
        #port_id_value_type: 0 for immediate number and 1 for field, metadata_offset:int
        action = of.ofp_action_output()
        action.port_id_value_type = port_id_value_type
        action.metadata_offset = metadata_offset
        action.metadata_length = metadata_length
        action.packet_offset = packet_offset
        action.port_id = port_id
        action.port_id_field = port_id_field
        return action
    
    def new_action_set_field(self, field_setting):  # 1
        #field_setting:ofp_matchx
        action = of.ofp_action_set_field()
        action.field_setting = field_setting
        return action
    
    def new_action_set_field_from_metadata(self, field_setting, metadata_offset):  # 2
        #field_setting:ofp_matchx, metadata_offset:int
        action = of.ofp_action_set_field_from_metadata()
        action.field_setting = field_setting
        action.metadata_offset = metadata_offset
        return action
    
    def new_action_modify_field(self, match_field, increment):  #3
        #match_field:ofp_match20, increment:int
        action = of.ofp_action_modify_field()
        action.match_field = match_field
        action.increment = increment
        return action
        
    def new_action_add_field(self, field_id, field_position, field_length, field_value):  #4
        #field_id:int, field_position:int, field_length:int, field_value:string
        action = of.ofp_action_add_field()
        action.field_id = field_id
        action.field_position = field_position
        action.field_length = field_length
        action.field_value = field_value
        return action
    
    def new_action_delete_field(self, field_position, length_value_type, length_value, length_field = None):  #5
        """generate a instance of ofp_action_delete_field (action_type: 5)
        
        Args:
        
        Returns:
            A instance of ofp_action_delete_field (action_type: 5)
        
        Raises:
        """
        #field_position:int, length_value_type:0 for immediate number and 1 for field, length_value:int, length_field:ofp_match20
        action = of.ofp_action_delete_field()
        action.tag_position = field_position
        action.tag_length_value_type = length_value_type
        action.tag_length_value = length_value
        action.tag_length_field = length_field
        return action
    
    def new_action_calculate_checksum(self,checksum_pos_type,calc_pos_type,checksum_position,checksum_length,calc_start_position,calc_length): #6
        #
        action = of.ofp_action_calculate_checksum()
        action.checksum_pos_type = checksum_pos_type     #0: packet; 1: metadata
        action.calc_pos_type = calc_pos_type             #0: packet; 1: metadata
        action.checksum_position = checksum_position
        action.checksum_length = checksum_length
        action.calc_start_position = calc_start_position
        action.calc_length = calc_length
        return action
    
    def new_action_group(self, group_id):  #7
        action = of.ofp_action_group()
        action.group_id = group_id
        return action
    
    def new_action_drop(self, reason):  #8
        action = of.ofp_action_drop()
        action.reason = reason
        return action
    
    def new_action_packetin(self, reason):  #9
        """packet_in_reason
        'OFPR_NO_MATCH'    : 0,
        'OFPR_ACTION'      : 1,
        'OFPR_INVALID_TTL' : 2,
        """
        action = of.ofp_action_packetin()
        action.reason = reason
        return action
    
    def new_action_counter(self, counter_id):  #10
        action = of.ofp_action_counter()
        action.counter_id = counter_id
        return action
    
    def save_all_data_into_file(self, file_name = DEFAULT_SAVE_FILE_NAME):
        pass
    
    def save_metadata_into_file(self):
        pass
    
    def load_all_data_from_file(self):
        pass
    
    def load_metadata_from_file(self):
        pass
    
    def send_all_of_msg_based_on_DB(self):
        pass
    
    # Handlers of POF messages
    def _handle_FeaturesReceived(self, event):
        #print "PofManager: Features Reply Received"
        features_reply = event.ofp
        if not isinstance(features_reply, of.ofp_features_reply):
            log.error("wrong features_reply")
        
        device_id = event.dpid
        sw = Switch()
        #sw.set_device_id(features_reply.device_id)
        sw.set_device_id(device_id)
        sw.connect(event.connection)
        self.add_switch(device_id, sw)
        
        self.database.add_switch_DB(device_id)
        self.database.set_features(device_id, features_reply)
        
    def _handle_ResourceReport(self, event):
        #print "PofManager: Resource Report Received"
        switch_id = event.dpid
        resource_report = event.ofp
        self.database.set_resource_report(switch_id, resource_report)
        
    def _handle_PortStatus(self, event):
        #print "PofManager: Port Status Received"     #for test
        port_status = event.ofp    # ofp_port_status 
        port = port_status.desc    # ofp_phy_port
        if port_status.reason == of.OFPPR_ADD:    # 0
            self.database.set_port_status(port.device_id, port_status)
            #log.info("Port [" + str(port.port_id) + "] added for Switch [" + str(port.device_id) + "]")
            #log.info("Port [0x%x] " % port.port_id + " added for Switch [0x%x]" % port.device_id + " Name " + port.name + " HW_addr [%s]" % EthAddr(port.hw_addr))
            log.info("Port [0x%x] added for Switch [0x%x], HW_addr [%s] Name [%s] " % (port.port_id, port.device_id, EthAddr(port.hw_addr), port.name))
            #self.set_port_of_enable(event.dpid, port.port_id)    #set pof_enable
        elif port_status.reason == of.OFPPR_DELETE: # 1
            self.database.del_port_status(port.device_id, port.port_id)
            #log.info("Port [" + str(port.port_id) + "] deleted for Switch [" + str(port.device_id) + "]")
            log.info("Port [" + "0x%x" % port.port_id + "] deleted for Switch [" + str(port.device_id) + "]")
        elif port_status.reason == of.OFPPR_MODIFY:   # 2
            self.database.set_port_status(port.device_id, port_status)
            #log.info("Port [" + str(port.port_id) + "] modified for Switch [" + str(port.device_id) + "]")
            log.info("Port [" + "0x%x" % port.port_id + "] modified for Switch [" + str(port.device_id) + "]")
            
    def _handle_CounterReply(self, event):
        print 'PofManager: CounterReply received'