Exemple #1
0
static void
delete_flow_entries_in_list( list_element *entries, const uint64_t cookie, const uint64_t cookie_mask,
                             const uint32_t out_port, const uint32_t out_group, const uint8_t reason ) {
  for ( list_element *e = entries; e != NULL; e = e->next ) {
    flow_entry *entry = e->data;
    assert( entry != NULL );

    bool to_be_deleted = true;
    if ( cookie_mask != 0 ) {
      if ( ( entry->cookie & cookie_mask ) != ( cookie & cookie_mask ) ) {
        to_be_deleted = false;
      }
    }

    if ( to_be_deleted && out_port != OFPP_ANY ) {
      if ( !instructions_have_output_port( entry->instructions, out_port ) ) {
        to_be_deleted = false;
      }
    }
    if ( to_be_deleted && out_group != OFPG_ANY ) {
      if ( !instructions_have_output_group( entry->instructions, out_group ) ) {
        to_be_deleted = false;
      }
    }

    if ( !to_be_deleted ) {
      continue;
    }

    flow_table *table = get_flow_table( entry->table_id );
    assert( table != NULL );
    delete_flow_entry_from_table( table, entry, reason, true );
  }
}
Exemple #2
0
OFDPE
finalize_flow_table( const uint8_t table_id ) {
  if ( !valid_table_id( table_id ) ) {
    error( "Invalid flow table id ( %#x ).", table_id );
    return OFDPE_FAILED;
  }

  flow_table *table = get_flow_table( table_id );
  if ( table == NULL ) {
    return OFDPE_FAILED;
  }

  delete_timer_event_safe( age_flow_entries, &table->features.table_id );

  for ( list_element *e = table->entries; e != NULL; e = e->next ) {
    flow_entry *entry = e->data;
    if ( entry != NULL ) {
      free_flow_entry( entry );
    }
  }
  delete_list( table->entries );

  memset( table, 0, sizeof( flow_table ) );
  table->initialized = false;
  
  return OFDPE_SUCCESS;
}
Exemple #3
0
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;
}
Exemple #4
0
void
dump_flow_table( const uint8_t table_id, void dump_function( const char *format, ... ) ) {
  assert( valid_table_id( table_id ) );
  assert( dump_function != NULL );

  if ( !lock_pipeline() ) {
    return;
  }

  flow_table *table = get_flow_table( table_id );
  assert( table != NULL );

  ( *dump_function )( "#### TABLE %#x (%s) ####", table_id, table->initialized ? "initialized" : "not initialized yet" );
  ( *dump_function )( "[Features]" );
  ( *dump_function )( "table_id: %#x", table->features.table_id );
  ( *dump_function )( "name: %s", table->features.name );
  ( *dump_function )( "metadata_match: %#" PRIx64, table->features.metadata_match );
  ( *dump_function )( "metadata_write: %#" PRIx64, table->features.metadata_write );
  ( *dump_function )( "config: %#x", table->features.config );
  ( *dump_function )( "max_entries: %u", table->features.max_entries );
  ( *dump_function )( "instructions: %#" PRIx64, table->features.instructions );
  ( *dump_function )( "instructions_miss: %#" PRIx64, table->features.instructions_miss );
  ( *dump_function )( "write_actions: %#" PRIx64, table->features.write_actions );
  ( *dump_function )( "write_actions_miss: %#" PRIx64, table->features.write_actions_miss );
  ( *dump_function )( "apply_actions: %#" PRIx64, table->features.apply_actions );
  ( *dump_function )( "apply_actions_miss: %#" PRIx64, table->features.apply_actions_miss );
  ( *dump_function )( "matches: %#" PRIx64, table->features.matches );
  ( *dump_function )( "wildcards: %#" PRIx64, table->features.wildcards );
  ( *dump_function )( "write_setfield: %#" PRIx64, table->features.write_setfield );
  ( *dump_function )( "write_setfield_miss: %#" PRIx64, table->features.write_setfield_miss );
  ( *dump_function )( "apply_setfield: %#" PRIx64, table->features.apply_setfield );
  ( *dump_function )( "apply_setfield_miss: %#" PRIx64, table->features.apply_setfield_miss );
  for ( uint8_t i = 0; i < N_FLOW_TABLES; i++ ) {
    if ( !table->features.next_table_ids[ i ] ) {
      ( *dump_function )( "next_table_id: %#x - %s", i, table->features.next_table_ids[ i ] ? "true" : "false" ); 
    }
  }
  for ( uint8_t i = 0; i < N_FLOW_TABLES; i++ ) {
    if ( !table->features.next_table_ids_miss[ i ] ) {
      ( *dump_function )( "next_table_id_miss: %#x - %s", i, table->features.next_table_ids_miss[ i ] ? "true" : "false" ); 
    }
  }

  ( *dump_function )( "[Stats]" );
  ( *dump_function )( "active_count: %u", table->counters.active_count );
  ( *dump_function )( "lookup_count: %" PRIu64, table->counters.lookup_count );
  ( *dump_function )( "matched_count: %" PRIu64, table->counters.matched_count );

  ( *dump_function )( "[Entries]" );

  for ( list_element *e = table->entries; e != NULL; e = e->next ) {
    flow_entry *entry = e->data;
    assert( entry != NULL );
    dump_flow_entry( entry, dump_function );
  }

  unlock_pipeline();
}
Exemple #5
0
static uint64_t
get_matched_count( const uint8_t table_id ) {
  assert( valid_table_id( table_id ) );

  flow_table *table = get_flow_table( table_id );
  if ( table == NULL ) {
    return 0;
  }

  return table->counters.matched_count;
}
Exemple #6
0
static uint64_t
increment_lookup_count( const uint8_t table_id ) {
  assert( valid_table_id( table_id ) );

  flow_table *table = get_flow_table( table_id );
  if ( table == NULL ) {
    return 0;
  }

  return ++table->counters.lookup_count;
}
Exemple #7
0
static uint32_t
get_active_count( const uint8_t table_id ) {
  assert( valid_table_id( table_id ) );

  flow_table *table = get_flow_table( table_id );
  if ( table == NULL ) {
    return 0;
  }

  return table->counters.active_count;
}
Exemple #8
0
OFDPE
update_flow_entry_strict( const uint8_t table_id, const match *match, const uint64_t cookie, const uint64_t cookie_mask,
                          const uint16_t priority, const uint16_t flags, instruction_set *instructions ) {
  /*
   * FLOW_TABLE_ALL (=OFPTT_ALL) is not allowed in the protocol specification.
   * But we allow it for internal use.
   */
  if ( !valid_table_id( table_id ) && table_id != FLOW_TABLE_ALL ) {
    return ERROR_OFDPE_FLOW_MOD_FAILED_BAD_TABLE_ID;
  }

  if ( match == NULL ) {
    error( "Invalid match ( %p ).", match );
    return ERROR_INVALID_PARAMETER;
  }
  if ( instructions == NULL ) {
    error( "Invalid instruction set ( %p ).", instructions );
    return ERROR_INVALID_PARAMETER;
  }

  if ( !lock_pipeline() ) {
    return ERROR_LOCK;
  }

  flow_table *table = get_flow_table( table_id );
  assert( table != NULL );

  OFDPE ret = validate_instruction_set( instructions, table->features.metadata_write );
  if ( ret != OFDPE_SUCCESS ) {
    error( "Invalid instruction set ( ret = %#x, instructions = %p ).", ret, instructions );
    return ret;
  }

  list_element *list = NULL;
  if ( table_id != FLOW_TABLE_ALL ) {
    list = lookup_flow_entries_with_table_id( table_id, match, priority, true, false );
  }
  else {
    list = lookup_flow_entries_from_all_tables( match, priority, true, false );
  }

  update_flow_entries_in_list( list, cookie, cookie_mask, flags, instructions );

  if ( list != NULL ) {
    delete_list( list );
  }

  if ( !unlock_pipeline() ) {
    return ERROR_UNLOCK;
  }

  return OFDPE_SUCCESS;
}
Exemple #9
0
static list_element *
lookup_flow_entries_with_table_id( const uint8_t table_id, const match *match, const uint16_t priority,
                                   const bool strict, const bool update_counters ) {
  assert( valid_table_id( table_id ) );

  if ( get_logging_level() >= LOG_DEBUG ) {
    debug( "Looking up flow entries ( table_id = %#x, match = %p, priority = %u, strict = %s, update_counters = %s ).",
           table_id, match, priority, strict ? "true" : "false", update_counters ? "true" : "false" );
    if ( match != NULL ) {
      dump_match( match, debug );
    }
  }

  flow_table *table = get_flow_table( table_id );
  if ( table == NULL ) {
    return NULL;
  }

  if ( update_counters ) {
    increment_lookup_count( table_id );
  }

  list_element *head = NULL;
  create_list( &head );

  for ( list_element *e = table->entries; e != NULL; e = e->next ) {
    flow_entry *entry = e->data;
    assert( entry != NULL );
    if ( strict ) {
      if ( entry->priority < priority ) {
        break;
      }
      if ( priority == entry->priority && compare_match_strict( match, entry->match ) ) {
        if ( update_counters ) {
          increment_matched_count( table_id );
        }
        append_to_tail( &head, entry );
        break;
      }
    }
    else {
      if ( compare_match( match, entry->match ) ) {
        if ( update_counters ) {
          increment_matched_count( table_id );
        }
        append_to_tail( &head, entry );
      }
    }
  }

  return head;
}
Exemple #10
0
static OFDPE
insert_flow_entry( flow_table *table, flow_entry *entry, const uint16_t flags ) {
  assert( table != NULL );
  assert( entry != NULL );

  list_element *element = table->entries;
  while( element != NULL ) {
    list_element *next = element->next;
    flow_entry *e = element->data;
    assert( e != NULL );
    if ( e->priority < entry->priority ) {
      break;
    }
    if ( e->priority == entry->priority ) {
      if ( e->table_miss && !entry->table_miss ) {
        break;
      }
      if ( ( flags & OFPFF_CHECK_OVERLAP ) != 0 && compare_match( e->match, entry->match ) ) {
        return ERROR_OFDPE_FLOW_MOD_FAILED_OVERLAP;
      }
      if ( compare_match_strict( e->match, entry->match ) ) {
        if ( ( flags & OFPFF_RESET_COUNTS ) != 0 ) {
          entry->byte_count = e->byte_count;
          entry->packet_count = e->packet_count;
        }
        flow_table *table = get_flow_table( e->table_id );
        assert( table != NULL );
        delete_flow_entry_from_table( table, e, 0, false );
      }
    }
    element = next;
  }

  if ( element == NULL ) {
    // tail
    append_to_tail( &table->entries, entry );
  }
  else if ( element == table->entries ) {
    // head
    insert_in_front( &table->entries, entry );
  }
  else {
    // insert before
    insert_before( &table->entries, element->data, entry );
  }

  increment_active_count( table->features.table_id );

  return OFDPE_SUCCESS;
}
Exemple #11
0
OFDPE
get_flow_table_config( const uint8_t table_id, uint32_t *config ) {
  assert( valid_table_id( table_id ) );
  assert( config != NULL );

  flow_table *table = get_flow_table( table_id );
  if ( table == NULL ) {
    return OFDPE_FAILED;
  }

  *config = table->features.config;

  return OFDPE_SUCCESS;
}
Exemple #12
0
OFDPE
get_flow_table_features( const uint8_t table_id, flow_table_features *stats ) {
  if ( stats == NULL ) {
    return ERROR_INVALID_PARAMETER;
  }

  flow_table *table = get_flow_table( table_id );
  if ( table == NULL ) {
    return ERROR_OFDPE_BAD_REQUEST_BAD_TABLE_ID;
  }

  memcpy( stats, &( table->features ), sizeof( flow_table_features ) );

  return OFDPE_SUCCESS;
}
Exemple #13
0
static void
foreach_flow_entry( const uint8_t table_id, flow_entry_handler callback, void *user_data ) {
  assert( valid_table_id( table_id ) );
  assert( callback != NULL );

  flow_table *table = get_flow_table( table_id );
  assert( table != NULL );

  list_element *e = table->entries;
  while ( e != NULL ) {
    list_element *next = e->next; // Current element may be deleted inside the callback function.
    flow_entry *entry = e->data;
    assert( entry != NULL );
    callback( entry, user_data );
    e = next;
  }
}
Exemple #14
0
OFDPE
add_flow_entry( const uint8_t table_id, flow_entry *entry, const uint16_t flags ) {
  if ( !valid_table_id( table_id ) ) {
    return ERROR_OFDPE_FLOW_MOD_FAILED_BAD_TABLE_ID;
  }
  if ( entry == NULL ) {
    return ERROR_INVALID_PARAMETER;
  }

  if ( !lock_pipeline() ) {
    return ERROR_LOCK;
  }

  flow_table *table = get_flow_table( table_id );
  if ( table == NULL ) {
    return ERROR_OFDPE_FLOW_MOD_FAILED_BAD_TABLE_ID;
  }

  if ( table->features.max_entries <= get_active_count( table_id ) ) {
    return ERROR_OFDPE_FLOW_MOD_FAILED_TABLE_FULL;
  }

  OFDPE ret = validate_instruction_set( entry->instructions, table->features.metadata_write );
  if ( ret == OFDPE_SUCCESS ) {
    entry->table_id = table_id;
    ret = insert_flow_entry( table, entry, flags );
    if ( ret == OFDPE_SUCCESS ) {
      increment_reference_counters_in_groups( entry->instructions );
    }
  }

  if ( !unlock_pipeline() ) {
    return ERROR_UNLOCK;
  }

  return ret;
}
Exemple #15
0
OFDPE
update_or_add_flow_entry( const uint8_t table_id, const match *key,
                          const uint64_t cookie, const uint64_t cookie_mask,
                          const uint16_t priority, const uint16_t idle_timeout, const uint16_t hard_timeout,
                          const uint16_t flags, const bool strict, instruction_set *instructions ) {
  if ( !valid_table_id( table_id ) ) {
    return ERROR_OFDPE_FLOW_MOD_FAILED_BAD_TABLE_ID;
  }

  if ( key == NULL ) {
    error( "Invalid match ( %p ).", key );
    return ERROR_INVALID_PARAMETER;
  }
  if ( instructions == NULL ) {
    error( "Invalid instruction set ( %p ).", instructions );
    return ERROR_INVALID_PARAMETER;
  }

  if ( !lock_pipeline() ) {
    return ERROR_LOCK;
  }

  flow_table *table = get_flow_table( table_id );
  assert( table != NULL );

  OFDPE ret = validate_instruction_set( instructions, table->features.metadata_write );
  if ( ret != OFDPE_SUCCESS ) {
    error( "Invalid instruction set ( ret = %#x, instructions = %p ).", ret, instructions );
    unlock_pipeline();
    return ret;
  }

  list_element *list = lookup_flow_entries_with_table_id( table_id, key, priority, strict, false );
  if ( list != NULL ) {
    update_flow_entries_in_list( list, cookie, cookie_mask, flags, instructions );
    delete_list( list );
  }
  else {
    match *duplicated_match = duplicate_match( key );
    instruction_set *duplicated_instructions = duplicate_instructions( instructions );
    flow_entry *entry = alloc_flow_entry( duplicated_match, duplicated_instructions,
                                          priority, idle_timeout, hard_timeout, flags, cookie );
    if ( entry != NULL ) {
      ret = add_flow_entry( table_id, entry, flags );
      if ( ret != OFDPE_SUCCESS ) {
        error( "Failed to add flow entry ( table_id = %#x, entry = %p, flags = %#x ).", table_id, entry, flags );
      }
    }
    else { 
      delete_match( duplicated_match );
      delete_instructions( duplicated_instructions );
      ret = OFDPE_FAILED;
    }
  }

  if ( !unlock_pipeline() ) {
    return ERROR_UNLOCK;
  }

  return ret;
}