group_entry * lookup_group_entry( const uint32_t group_id ) { assert( table != NULL ); assert( valid_group_id( group_id ) ); if ( !lock_pipeline() ) { return NULL; } group_entry *entry = NULL; bool found = false; for ( list_element *element = table->entries; element != NULL; element = element->next ) { if ( element->data == NULL ) { continue; } entry = element->data; if ( entry->group_id == group_id ) { found = true; break; } } if ( !unlock_pipeline() ) { return NULL; } return found == true ? entry : NULL; }
OFDPE delete_flow_entries_by_group_id( const uint32_t group_id ) { assert( valid_group_id( group_id ) ); if ( !lock_pipeline() ) { return ERROR_LOCK; } list_element *delete_us = NULL; create_list( &delete_us ); for ( uint8_t table_id = 0; table_id <= FLOW_TABLE_ID_MAX; table_id++ ) { flow_table *table = get_flow_table( table_id ); assert( table != NULL ); for ( list_element *e = table->entries; e != NULL; e = e->next ) { assert( e->data != NULL ); flow_entry *entry = e->data; if ( instructions_have_output_group( entry->instructions, group_id ) ) { append_to_tail( &delete_us, e->data ); } } } delete_flow_entries_in_list( delete_us, 0, 0, OFPP_ANY, OFPG_ANY, OFPRR_GROUP_DELETE ); if ( delete_us != NULL ) { delete_list( delete_us ); } if ( !unlock_pipeline() ) { return ERROR_UNLOCK; } return OFDPE_SUCCESS; }
OFDPE add_group_entry( group_entry *entry ) { assert( table != NULL ); if ( entry == NULL ) { return ERROR_INVALID_PARAMETER; } if ( !valid_group_id( entry->group_id ) ) { return ERROR_OFDPE_GROUP_MOD_FAILED_INVALID_GROUP; } if ( group_exists( entry->group_id ) ) { return ERROR_OFDPE_GROUP_MOD_FAILED_GROUP_EXISTS; } if ( !lock_pipeline() ) { return ERROR_LOCK; } OFDPE ret = validate_group_entry( entry ); if ( ret == OFDPE_SUCCESS ) { append_to_tail( &table->entries, entry ); } if ( !unlock_pipeline() ) { return ERROR_UNLOCK; } return ret; }
void decrement_reference_count( const uint32_t group_id ) { assert( table != NULL ); assert( valid_group_id( group_id ) ); if ( !lock_pipeline() ) { error( "Failed to lock pipeline." ); return; } group_entry *entry = lookup_group_entry( group_id ); if ( entry != NULL ) { entry->ref_count--; } if ( !unlock_pipeline() ) { error( "Failed to unlock pipeline." ); } }
OFDPE update_group_entry( const uint32_t group_id, const uint8_t type, bucket_list *buckets ) { assert( table != NULL ); if ( !valid_group_id( group_id ) ) { return ERROR_OFDPE_GROUP_MOD_FAILED_INVALID_GROUP; } if ( !valid_group_type( type ) ) { return ERROR_OFDPE_GROUP_MOD_FAILED_INVALID_GROUP; } if ( !lock_pipeline() ) { return ERROR_LOCK; } OFDPE ret = OFDPE_SUCCESS; group_entry *entry = lookup_group_entry( group_id ); if ( entry == NULL ) { ret = ERROR_OFDPE_GROUP_MOD_FAILED_UNKNOWN_GROUP; } if ( ret == OFDPE_SUCCESS ) { ret = validate_buckets( entry->type, buckets ); } if ( ret == OFDPE_SUCCESS ) { if ( entry->buckets != NULL ) { delete_action_bucket_list( entry->buckets ); } entry->type = type; entry->buckets = buckets; } if ( !unlock_pipeline() ) { return ERROR_UNLOCK; } return ret; }
OFDPE delete_group_entry( const uint32_t group_id ) { assert( table != NULL ); if ( !valid_group_id( group_id ) ) { return ERROR_OFDPE_GROUP_MOD_FAILED_INVALID_GROUP; } if ( !lock_pipeline() ) { return ERROR_LOCK; } if ( group_id != OFPG_ALL ) { group_entry *entry = lookup_group_entry( group_id ); if ( entry != NULL ) { delete_element( &table->entries, entry ); delete_flow_entries_by_group_id( entry->group_id ); free_group_entry( entry ); } } else { for ( list_element *element = table->entries; element != NULL; element = element->next ) { if ( element->data == NULL ) { continue; } group_entry *entry = element->data; delete_flow_entries_by_group_id( entry->group_id ); free_group_entry( entry ); } delete_list( table->entries ); create_list( &table->entries ); } if ( !unlock_pipeline() ) { return ERROR_UNLOCK; } return OFDPE_SUCCESS; }
OFDPE get_group_stats( const uint32_t group_id, group_stats **stats, uint32_t *n_groups ) { assert( table != NULL ); assert( stats != NULL ); assert( n_groups != NULL ); if ( !valid_group_id( group_id ) && group_id != OFPG_ALL ) { return ERROR_OFDPE_BAD_REQUEST_BAD_TABLE_ID; } if ( !lock_pipeline() ) { return ERROR_LOCK; } OFDPE ret = OFDPE_SUCCESS; list_element *groups = NULL; create_list( &groups ); *n_groups = 0; if ( group_id != OFPG_ALL ) { group_entry *entry = lookup_group_entry( group_id ); if ( entry == NULL ) { if ( !unlock_pipeline() ) { return ERROR_UNLOCK; } return ERROR_OFDPE_BAD_REQUEST_BAD_TABLE_ID; } append_to_tail( &groups, entry ); ( *n_groups )++; } else { for ( list_element *e = table->entries; e != NULL; e = e->next ) { if ( e->data == NULL ) { continue; } group_entry *entry = e->data; append_to_tail( &groups, entry ); ( *n_groups )++; } } *stats = NULL; if ( *n_groups > 0 ) { *stats = xmalloc( sizeof( group_stats ) * ( *n_groups ) ); memset( *stats, 0, sizeof( group_stats ) * ( *n_groups ) ); } group_stats *stat = *stats; for ( list_element *e = groups; e != NULL; e = e->next ) { assert( e->data != NULL ); group_entry *entry = e->data; stat->group_id = entry->group_id; stat->ref_count = entry->ref_count; stat->packet_count = entry->packet_count; stat->byte_count = entry->byte_count; struct timespec now = { 0, 0 }; time_now( &now ); struct timespec diff = { 0, 0 }; timespec_diff( entry->created_at, now, &diff ); stat->duration_sec = ( uint32_t ) diff.tv_sec; stat->duration_nsec = ( uint32_t ) diff.tv_nsec; create_list( &stat->bucket_stats ); for ( dlist_element *b = get_first_element( entry->buckets ); b != NULL; b = b->next ) { if ( b->data == NULL ) { continue; } bucket *bucket = b->data; bucket_counter *counter = xmalloc( sizeof( bucket_counter ) ); memset( counter, 0, sizeof( bucket_counter ) ); counter->packet_count = bucket->packet_count; counter->byte_count = bucket->byte_count; append_to_tail( &stat->bucket_stats, counter ); } stat++; } if ( groups != NULL ) { delete_list( groups ); } if ( !unlock_pipeline() ) { return ERROR_UNLOCK; } return ret; }