예제 #1
0
/*
* Attempts to add a port to the physical switch pool port
*/
rofl_result_t physical_switch_add_port(switch_port_t* port){

	unsigned int i, max;
	switch_port_t** array = NULL;


	if( unlikely(port==NULL) )
		return ROFL_FAILURE;	

	ROFL_PIPELINE_DEBUG("Trying to add port(%p) named %s to the physical switch\n", port, port->name);
	
	if(physical_switch_get_port_by_name(port->name)){
		ROFL_PIPELINE_DEBUG("There is already a port named:%s in the physical switch\n",port->name);
		return ROFL_FAILURE;
	}

	//Serialize
	platform_mutex_lock(psw->mutex);

	switch(port->type){

		case PORT_TYPE_PHYSICAL:
			max = PHYSICAL_SWITCH_MAX_NUM_PHY_PORTS;
			array = psw->physical_ports; 
			break;			

		case PORT_TYPE_VIRTUAL:
			max = PHYSICAL_SWITCH_MAX_NUM_VIR_PORTS;
			array = psw->virtual_ports; 
			break;			

		case PORT_TYPE_TUNNEL:
			max = PHYSICAL_SWITCH_MAX_NUM_TUN_PORTS;
			array = psw->tunnel_ports; 
			break;			
		
		default:
			//Invalid type		
			platform_mutex_unlock(psw->mutex);
			return ROFL_FAILURE;
	}	

	//Look for the first empty slot
	for(i=0;i<max;i++){
		if(array[i] == NULL){
			array[i] = port;
			platform_mutex_unlock(psw->mutex);
			return ROFL_SUCCESS;
		}
	}
	
	platform_mutex_unlock(psw->mutex);

	//No free slots left in the pool
	ROFL_PIPELINE_DEBUG("Insertion failed of port(%p); no available slots\n",port);
	return ROFL_FAILURE;
}
예제 #2
0
/**
 * of1x_dump_timers_structure
 * this function is ment to show the timer groups existing
 * and the entries related
 */
void __of1x_dump_timers_structure(of1x_timer_group_t * timer_group) {

    of1x_timer_group_t * tg = timer_group;
    of1x_entry_timer_t * et;
    if(!tg)
    {
        ROFL_PIPELINE_DEBUG("Timer group list is empty\n");
        return;
    }
#if OF1X_TIMER_STATIC_ALLOCATION_SLOTS
    int i;
    for(i=0; i<OF1X_TIMER_GROUPS_MAX; i++)
    {
        ROFL_PIPELINE_DEBUG("timer group on position %p\n", &(tg[i]));
        ROFL_PIPELINE_DEBUG("	[%p] TO:%"PRIu64" Nent:%d h:%p t:%p\n",&(tg[i]), tg[i].timeout,
                            tg[i].list.num_of_timers, tg[i].list.head, tg[i].list.tail);
        for(et=tg[i].list.head; et; et=et->next)
            ROFL_PIPELINE_DEBUG("	[%p] fe:%p prev:%p next:%p tg:%p\n", et,et->entry, et->prev, et->next, et->group);
    }

#else
    if(tg->prev)
        ROFL_PIPELINE_DEBUG("NOT the first group!!\n");
    for(; tg!=NULL; tg=tg->next)
    {
        ROFL_PIPELINE_DEBUG("timer group on position %p\n", tg);
        ROFL_PIPELINE_DEBUG("	[%p] TO:%"PRIu64" next:%p prev:%p Nent:%d h:%p t:%p\n",tg, tg->timeout, tg->next, tg->prev,
                            tg->list.num_of_timers, tg->list.head, tg->list.tail);
        for(et=tg->list.head; et; et=et->next)
            ROFL_PIPELINE_DEBUG("	[%p] fe:%p prev:%p next:%p tg:%p\n", et,et->entry, et->prev, et->next, et->group);
    }
#endif
}
예제 #3
0
/**
 * of1x_destroy_all_entries_from_timer_group()
 * implements for loop that destroys the complete list of entries
 * This is ment to be used when a timer expires and we want to delete
 * all the entries of the group and the group itself
 */
static rofl_result_t __of1x_destroy_all_entries_from_timer_group(of1x_timer_group_t* tg, of1x_pipeline_t *const pipeline, unsigned int id_table)
{
    of1x_entry_timer_t* entry_iterator, *next/*, *prev*/;
    if(tg->list.num_of_timers>0 && tg->list.head)
    {
        for(entry_iterator = tg->list.head; entry_iterator; entry_iterator=next)
        {
            next = entry_iterator->next;

            //NOTE actual removal of timer_entries is done in the destruction of the entry

            if(entry_iterator->type == IDLE_TO)
            {
                if(__of1x_reschedule_idle_timer(entry_iterator, pipeline, id_table)!=ROFL_SUCCESS)
                    return ROFL_FAILURE;
            }
            else
            {
#ifdef DEBUG_NO_REAL_PIPE
                ROFL_PIPELINE_DEBUG("NOT erasing real entries of table \n");
                __of1x_fill_new_timer_entry_info(entry_iterator->entry,0,0);
                //we delete the enrty_timer form outside
                __of1x_destroy_timer_entries(entry_iterator->entry);
#else
                //ROFL_PIPELINE_DEBUG("Erasing real entries of table \n"); //NOTE DELETE
                __of1x_remove_specific_flow_entry_table(pipeline, id_table,entry_iterator->entry, OF1X_FLOW_REMOVE_HARD_TIMEOUT, MUTEX_ALREADY_ACQUIRED_BY_TIMER_EXPIRATION);
#endif
            }
        }
    }
    return ROFL_SUCCESS;
}
예제 #4
0
/**
 * of1x_timer_group_init creates a new timer group and places it in
 * between tg_next and tg_prev, ordered by timeout values.
 * This function is NOT thread safe, you must lock the timer before.
 */
static of1x_timer_group_t* __of1x_timer_group_init(uint64_t timeout, of1x_timer_group_t* tg_next, of1x_timer_group_t* tg_prev, of1x_flow_table_t* table)
{
    // create the new timer_group
    of1x_timer_group_t* new_group;
    new_group = platform_malloc_shared(sizeof(of1x_timer_group_t));
    if(unlikely(new_group == NULL))
    {
        ROFL_PIPELINE_DEBUG("<%s:%d> Error allocating memory\n",__func__,__LINE__);
        return NULL;
    }
    new_group->timeout = timeout;
    new_group->list.num_of_timers=0;
    new_group->list.head=NULL;
    new_group->list.tail=NULL;

    // place the timer group
    new_group->prev=tg_prev;
    new_group->next=tg_next;

    //if there is a node afterwards we place the new one before
    if (tg_next) tg_next->prev=new_group;
    //if there is a node forewards we place the new one before
    if (tg_prev) tg_prev->next=new_group;

    if(table->timers == tg_next)
        table->timers = new_group;

    return new_group;
}
예제 #5
0
/**
 * if we are using static slots, we need to rotate the memory every time that a slot passes. steps:
 * - if there are entries we must erase them
 * - we must set the new timeout
 * - we must update the pointer to the next timer group
 */
static void __of1x_timer_group_rotate(of1x_pipeline_t *const pipeline, of1x_timer_group_t *tg , unsigned int id_table)
{
    if(tg->list.head)
    {
        //erase_all_entries;
        if(__of1x_destroy_all_entries_from_timer_group(tg, pipeline, id_table)!=ROFL_SUCCESS)
            ROFL_PIPELINE_DEBUG("ERROR in destroying timer group\n");
    }
    tg->timeout += OF1X_TIMER_SLOT_MS*OF1X_TIMER_GROUPS_MAX;
    tg->list.num_of_timers=0;
    tg->list.head = tg->list.tail = NULL;

    pipeline->tables[id_table].current_timer_group++;
    if(pipeline->tables[id_table].current_timer_group>=OF1X_TIMER_GROUPS_MAX)
        pipeline->tables[id_table].current_timer_group=0;
}
예제 #6
0
//Init
rofl_result_t physical_switch_init(){

	ROFL_PIPELINE_DEBUG("Initializing physical switch\n");

	//Allocate memory for the physical switch structure
	psw = platform_malloc_shared(sizeof(physical_switch_t));
	
	if( unlikely(psw==NULL) )
		return ROFL_FAILURE;	
	
	psw->mutex = platform_mutex_init(NULL);
	if(!psw->mutex)
		return ROFL_FAILURE;
	
	platform_memset(psw->logical_switches, 0, sizeof(psw->logical_switches));
	psw->num_of_logical_switches = 0;	

	platform_memset(psw->physical_ports, 0, sizeof(psw->physical_ports));
	platform_memset(psw->tunnel_ports, 0, sizeof(psw->tunnel_ports));
	platform_memset(psw->virtual_ports, 0, sizeof(psw->virtual_ports));
	platform_memset(psw->meta_ports, 0, sizeof(psw->meta_ports));
	
	//Generate metaports
	//Flood
	psw->meta_ports[META_PORT_FLOOD_INDEX].type = PORT_TYPE_META_FLOOD;
	strncpy(psw->meta_ports[META_PORT_FLOOD_INDEX].name, "Flood meta port", SWITCH_PORT_MAX_LEN_NAME);
	//In port
	psw->meta_ports[META_PORT_IN_PORT_INDEX].type = PORT_TYPE_META_IN_PORT;
	strncpy(psw->meta_ports[META_PORT_IN_PORT_INDEX].name, "In port meta port", SWITCH_PORT_MAX_LEN_NAME);
	//All
	psw->meta_ports[META_PORT_ALL_INDEX].type = PORT_TYPE_META_ALL;
	strncpy(psw->meta_ports[META_PORT_ALL_INDEX].name, "All meta port", SWITCH_PORT_MAX_LEN_NAME);

	//Set extern pointer
	flood_meta_port = &psw->meta_ports[META_PORT_FLOOD_INDEX];
	in_port_meta_port = &psw->meta_ports[META_PORT_IN_PORT_INDEX];
	all_meta_port = &psw->meta_ports[META_PORT_ALL_INDEX];

	//Initialize monitoring data
	if(__monitoring_init(&psw->monitoring) != ROFL_SUCCESS)
		return ROFL_FAILURE;		

	//Generate matching algorithm lists
	__physical_switch_generate_matching_algorithm_list();

	return ROFL_SUCCESS;	
}
예제 #7
0
/**
 * of1x_reschedule_idle_timer
 * check if there is the need of re-scheduling an idle timer
 */
static rofl_result_t __of1x_reschedule_idle_timer(of1x_entry_timer_t * entry_timer, of1x_pipeline_t *const pipeline, unsigned int id_table)
{
    struct timeval system_time;
    uint64_t expiration_time;

    if(entry_timer->entry->stats.packet_count == entry_timer->entry->timer_info.last_packet_count)
    {
        // timeout expired so no need to reschedule !!! we have to delete the entry
#ifdef DEBUG_NO_REAL_PIPE
        ROFL_PIPELINE_DEBUG("NOT erasing real entries of table \n");
        __of1x_fill_new_timer_entry_info(entry_timer->entry,0,0);
        //we need to destroy the entries
        __of1x_destroy_timer_entries(entry_timer->entry);
#else
        __of1x_remove_specific_flow_entry_table(pipeline, id_table, entry_timer->entry, OF1X_FLOW_REMOVE_IDLE_TIMEOUT, MUTEX_ALREADY_ACQUIRED_BY_TIMER_EXPIRATION);
#endif
        return ROFL_SUCCESS;
    }

    entry_timer->entry->timer_info.last_packet_count = entry_timer->entry->stats.packet_count;
    //NOTE we calculate the new time of expiration from the checking time and not from the last time it was used (less accurate and more efficient)
    platform_gettimeofday(&system_time);
    expiration_time = __of1x_get_expiration_time_slotted(entry_timer->entry->timer_info.idle_timeout, &system_time);

#if OF1X_TIMER_STATIC_ALLOCATION_SLOTS

    int slot_delta = expiration_time - pipeline->tables[id_table].timers[pipeline->tables[id_table].current_timer_group].timeout; //ms
    int slot_position = (pipeline->tables[id_table].current_timer_group + slot_delta/OF1X_TIMER_SLOT_MS) % OF1X_TIMER_GROUPS_MAX;
    if(__of1x_entry_timer_init(&(pipeline->tables[id_table].timers[slot_position]), entry_timer->entry, IDLE_TO)==NULL)
        return ROFL_FAILURE;
#else

    of1x_timer_group_t * tg_iterator = __of1x_dynamic_slot_search(pipeline->tables[id_table], expiration_time);
    if(tg_iterator==NULL)
        return ROFL_FAILURE;
    // add entry to this group. new_group.list->num_of_timers++; ...
    if(__of1x_entry_timer_init(tg_iterator, entry_timer->entry, IDLE_TO) == NULL)
        return ROFL_FAILURE;
#endif

    //TODO delete timer_entry that has been rescheduled:
    __of1x_destroy_single_timer_entry_clean(entry_timer, &pipeline->tables[id_table]);

    return ROFL_SUCCESS;
}
예제 #8
0
/**
 * of1x_entry_timer_init
 * adds a new entry in the list
 */
static of1x_entry_timer_t* __of1x_entry_timer_init(of1x_timer_group_t* tg, of1x_flow_entry_t* entry, of1x_timer_timeout_type_t is_idle)
{
    of1x_entry_timer_t* new_entry;
    new_entry = platform_malloc_shared(sizeof(of1x_entry_timer_t));
    if(unlikely(new_entry==NULL))
    {
        ROFL_PIPELINE_DEBUG("<%s:%d> Error allocating memory\n",__func__,__LINE__);
        return NULL;
    }
    new_entry->entry = entry;
    new_entry->group = tg;

    // we add the new entries at the end
    new_entry->next=NULL;

    // we check if it is the first entry.
    if(tg->list.tail) //if it is not
    {
        new_entry->prev=tg->list.tail;
        //update the pointer OF the last entry on the list
        tg->list.tail->next=new_entry;
    }
    else //if it is the first one
    {
        new_entry->prev=NULL;
        //normally this should also apply:
        if(!tg->list.head)
            tg->list.head = new_entry;
    }

    // update the pointer TO the last entry of the list
    tg->list.tail = new_entry;
    // update the entries counter
    tg->list.num_of_timers++;

    new_entry->type=is_idle;

    if(is_idle)
        entry->timer_info.idle_timer_entry=new_entry;
    else
        entry->timer_info.hard_timer_entry=new_entry;

    return new_entry;
}
예제 #9
0
/**
 * of1x_dynamic_slot_search
 * extraction of a function used to search a timer group with a specific timeout
 * and if it does not exist create it.
 */
static of1x_timer_group_t * of1x_dynamic_slot_search(of1x_flow_table_t* const table, uint64_t expiration_time)
{
    of1x_timer_group_t* tg_iterator;
    //Determine the slot, check if is already defined, if not allocate
    //We search the timer group with the timeout corresponding to the expiration_time calculated
    for(tg_iterator = table->timers; tg_iterator && tg_iterator->timeout<expiration_time && tg_iterator->next; tg_iterator=tg_iterator->next);
    // After that we expect 3 different situations:

    if(!tg_iterator)
    {
        //the list is empty, we sould create the first group
        table->timers = __of1x_timer_group_init(expiration_time,NULL,NULL, table);
        if(table->timers == NULL)
            return NULL;

        tg_iterator = table->timers;
    }
    else if(tg_iterator->timeout>expiration_time)
    {
        // Create new group and allocate it before the current group
        tg_iterator = __of1x_timer_group_init(expiration_time,tg_iterator,tg_iterator->prev, table);
        if(tg_iterator == NULL)
            return NULL;
    }
    else if(tg_iterator->timeout < expiration_time && !tg_iterator->next)
    {
        // Create new group and allocate it after the current group
        tg_iterator = __of1x_timer_group_init(expiration_time,NULL, tg_iterator, table);
        if(tg_iterator == NULL)
            return NULL;
    }
    else
    {
        if (!(tg_iterator->timeout==expiration_time))
        {
            // Unexpected outcome ...
            ROFL_PIPELINE_DEBUG("<%s:%d> No proper position for this entry found\n",__func__, __LINE__);
            return NULL;
        }
    }

    return tg_iterator;
}
예제 #10
0
/**
 * of1x_destroy_single_timer_entry_clean
 * when the time comes the list of entries must be erased from the list
 * This is ment to be used when a single entry is deleted.
 */
static rofl_result_t __of1x_destroy_single_timer_entry_clean(of1x_entry_timer_t* entry, of1x_flow_table_t * table)
{
    if(likely(entry!=NULL))
    {
        if(!entry->next && !entry->prev) // this is the only entry
        {
            entry->group->list.head=NULL;
            entry->group->list.tail=NULL;
        }
        else if(!entry->prev) //is the first entry
        {
            entry->group->list.head=entry->next;
            entry->next->prev = NULL;
        }
        else if(!entry->next) //last entry
        {
            entry->group->list.tail=entry->prev;
            entry->prev->next = NULL;
        }
        else
        {
            entry->next->prev = entry->prev;
            entry->prev->next = entry->next;
        }

        entry->group->list.num_of_timers--;
#if ! OF1X_TIMER_STATIC_ALLOCATION_SLOTS
        //we need to check if this entry was the last one and delete the timer group
        if(entry->group->list.num_of_timers == 0)
            __of1x_destroy_timer_group(entry->group,table);
#endif
        platform_free_shared(entry);
        entry = NULL;

        return ROFL_SUCCESS;

    } else {
        ROFL_PIPELINE_DEBUG("<%s:%d> Not a valid timer entry %p\n",__func__,__LINE__,entry);
        return ROFL_FAILURE;
    }
}
예제 #11
0
//Destroy
void physical_switch_destroy(){
	
	unsigned int i;
	
	ROFL_PIPELINE_DEBUG("Destroying physical switch\n");

	//Serialize
	platform_mutex_lock(psw->mutex);

	//Destroy logical switches
	for(i=0;i<PHYSICAL_SWITCH_MAX_LS;i++){
		if(psw->logical_switches[i])
			of_destroy_switch(psw->logical_switches[i]);	
	}

	//Destroying ports
	for(i=0;i<PHYSICAL_SWITCH_MAX_NUM_PHY_PORTS;i++){
		if( psw->physical_ports[i] != NULL ){ 
			switch_port_destroy(psw->physical_ports[i]);
		}
	}
	for(i=0;i<PHYSICAL_SWITCH_MAX_NUM_VIR_PORTS;i++){
		if( psw->virtual_ports[i] != NULL ){ 
			switch_port_destroy(psw->virtual_ports[i]);
		}
	}
	for(i=0;i<PHYSICAL_SWITCH_MAX_NUM_TUN_PORTS;i++){
		if( psw->tunnel_ports[i] != NULL ){ 
			switch_port_destroy(psw->tunnel_ports[i]);
		}
	}

	//Destroy monitoring
	__monitoring_destroy(&psw->monitoring);		
	
	//Destroy mutex
	platform_mutex_destroy(psw->mutex);
	
	//destroy physical switch
	platform_free_shared(psw);
}
예제 #12
0
void __of1x_process_pipeline_tables_timeout_expirations(of1x_pipeline_t *const pipeline) {

    unsigned int i;

    struct timeval system_time;
    platform_gettimeofday(&system_time);
    uint64_t now = __of1x_get_time_ms(&system_time);

    for(i=0; i<pipeline->num_of_tables; i++)
    {
        of1x_flow_table_t* table = &pipeline->tables[i];
        platform_mutex_lock(table->mutex);
#if OF1X_TIMER_STATIC_ALLOCATION_SLOTS
        while(table->timers[table->current_timer_group].timeout<=now)
        {
            //rotate the timers
            __of1x_timer_group_rotate(pipeline,&(table->timers[table->current_timer_group]),i);
        }
#else
        of1x_timer_group_t* slot_it, *next;
        for(slot_it=table->timers; slot_it; slot_it=next)
        {
            if(now<slot_it->timeout) //Current slot time > time_now. We are done
                break;
            //remove all entries and the timer group.
            if(__of1x_destroy_all_entries_from_timer_group(slot_it, table)!=ROFL_SUCCESS)
            {
                ROFL_PIPELINE_DEBUG("Error while destroying timer group\n");
                platform_mutex_unlock(table->mutex);
                return;
            }
            next = slot_it->next;
            if(slot_it)
                __of1x_destroy_timer_group(slot_it, table);
        }
#endif
        platform_mutex_unlock(table->mutex);
    }
    return;
}
예제 #13
0
rofl_result_t physical_switch_remove_logical_switch_by_dpid(const uint64_t dpid){

	int i;
	of_switch_t* sw;

	ROFL_PIPELINE_DEBUG("Removing logical switch with dpid: 0x%"PRIx64"\n",dpid);

	//Serialize
	platform_mutex_lock(psw->mutex);

	if(!physical_switch_get_logical_switch_by_dpid(dpid)){
		platform_mutex_unlock(psw->mutex);
		ROFL_PIPELINE_WARN("Logical switch not found\n");	
		return ROFL_FAILURE;
	}
	
	for(i=0;i<PHYSICAL_SWITCH_MAX_LS;i++){
		if(psw->logical_switches[i] && psw->logical_switches[i]->dpid == dpid){

			sw = psw->logical_switches[i];

			psw->logical_switches[i] = NULL;
			psw->num_of_logical_switches--;

			//Free the rest to do stuff with the physical sw
			platform_mutex_unlock(psw->mutex);

			//Destroy the switch				
			of_destroy_switch(sw);				
			
			return ROFL_SUCCESS;
		}
	}
	
	//This statement can never be reached	
	platform_mutex_unlock(psw->mutex);
	return ROFL_FAILURE;
}
예제 #14
0
static rofl_result_t __of1x_add_single_timer(of1x_flow_table_t* const table, const uint32_t timeout, of1x_flow_entry_t* entry, of1x_timer_timeout_type_t is_idle)
{
    uint64_t expiration_time;
    struct timeval now;
    platform_gettimeofday(&now);
    expiration_time = __of1x_get_expiration_time_slotted(timeout, &now);
#if OF1X_TIMER_STATIC_ALLOCATION_SLOTS
    // add entries to the position tc + hard_timeout_s
    if(timeout > OF1X_TIMER_GROUPS_MAX)
    {
        ROFL_PIPELINE_DEBUG("Timeout value excedded maximum value (hto=%d, MAX=%d)\n", timeout,OF1X_TIMER_GROUPS_MAX);
        return ROFL_FAILURE;
    }


    int slot_delta = expiration_time - table->timers[table->current_timer_group].timeout; //ms

    //NOTE we allocate the timer in the next slot rounding up:
    //so the actual expiration time will be a value in [hard_timeout,hard_timeout+OF1X_TIMER_SLOT_MS)
    int slot_position = (table->current_timer_group+(slot_delta/OF1X_TIMER_SLOT_MS))%(OF1X_TIMER_GROUPS_MAX);
    if(__of1x_entry_timer_init(&(table->timers[slot_position]), entry, is_idle)==NULL)
        return ROFL_FAILURE;

#else

    of1x_timer_group_t* tg_iterator = __of1x_dynamic_slot_search(table, expiration_time);
    if (tg_iterator==NULL)
        return ROFL_FAILURE;

    // add entry to this group. new_group.list->num_of_timers++; ...
    if(__of1x_entry_timer_init(tg_iterator, entry, is_idle, NULL) == NULL)
        return ROFL_FAILURE;

#endif
    return ROFL_SUCCESS;
}