Ejemplo n.º 1
0
static bool
_add_timer_event_callback( struct itimerspec *interval, timer_callback callback, void *user_data ) {
  assert( interval != NULL );
  assert( callback != NULL );
  timer_read_begin();
  struct timer_info *timer = get_timer_info();
  timer_read_end();
  assert( timer != NULL );

  debug( "Adding a timer event callback ( interval = %u.%09u, initial expiration = %u.%09u, callback = %p, user_data = %p ).",
         interval->it_interval.tv_sec, interval->it_interval.tv_nsec,
         interval->it_value.tv_sec, interval->it_value.tv_nsec, callback, user_data );

  timer_callback_info *cb;
  struct timespec now;

  cb = xmalloc( sizeof( timer_callback_info ) );
  memset( cb, 0, sizeof( timer_callback_info ) );
  cb->function = callback;
  cb->user_data = user_data;

  if ( clock_gettime( CLOCK_MONOTONIC, &now ) != 0 ) {
    error( "Failed to retrieve monotonic time ( %s [%d] ).", strerror( errno ), errno );
    xfree( cb );
    return false;
  }

  cb->interval = interval->it_interval;

  if ( VALID_TIMESPEC( &interval->it_value ) ) {
    ADD_TIMESPEC( &now, &interval->it_value, &cb->expires_at );
  }
  else if ( VALID_TIMESPEC( &interval->it_interval ) ) {
    ADD_TIMESPEC( &now, &interval->it_interval, &cb->expires_at );
  }
  else {
    error( "Timer must not be zero when a timer event is added." );
    xfree( cb );
    return false;
  }

  debug( "Set an initial expiration time to %u.%09u.", now.tv_sec, now.tv_nsec );

  assert( timer->timer_callbacks != NULL );
  insert_timer_callback( timer, cb );

  return true;
}
Ejemplo n.º 2
0
static void
on_timer( timer_callback_info *callback, struct timespec *now ) {
    assert( callback != NULL );
    assert( callback->function != NULL );

    debug( "Executing a timer event ( function = %p, expires_at = %u.%09u, interval = %u.%09u, user_data = %p ).",
           callback->function, callback->expires_at.tv_sec, callback->expires_at.tv_nsec,
           callback->interval.tv_sec, callback->interval.tv_nsec, callback->user_data );

    if ( VALID_TIMESPEC( &callback->expires_at ) ) {
        callback->function( callback->user_data );
        if ( VALID_TIMESPEC( &callback->interval ) ) {
            ADD_TIMESPEC( &callback->expires_at, &callback->interval, &callback->expires_at );
            if ( TIMESPEC_LESS_THEN( &callback->expires_at, now ) ) {
                callback->expires_at.tv_sec = now->tv_sec;
                callback->expires_at.tv_nsec = now->tv_nsec;
            }
        }
        else {
            callback->expires_at.tv_sec = 0;
            callback->expires_at.tv_nsec = 0;
            callback->function = NULL;
        }
        debug( "Set expires_at value to %u.%09u.", callback->expires_at.tv_sec, callback->expires_at.tv_nsec );
    }
    else {
        error( "Invalid expires_at value." );
    }
}
static void
handle_error( uint64_t datapath_id, uint32_t transaction_id, uint16_t type, uint16_t code,
              const buffer *data, void *user_data ) {
  UNUSED( user_data );
  UNUSED( data );

  warn( "Error ( type = %#x, code = %#x ) from switch %#" PRIx64 " for %#x received.",
        type, code, datapath_id, transaction_id );

  transaction_entry *entry = lookup_transaction_entry_by_xid( transaction_id );
  if ( entry == NULL ) {
    entry = lookup_transaction_entry_by_barrier_xid( transaction_id );
    if ( entry == NULL ) {
      warn( "An error for untracked transaction received "
            "( type = %#x, code = %#x, transaction_id = %#x, datapath_id = %#" PRIx64 " ).",
            type, code, transaction_id, datapath_id );
      return;
    }
    entry->completed = true;
  }

  entry->error_received = true;
  bool ret = get_monotonic_time( &entry->expires_at );
  if ( !ret ) {
    return;
  }
  ADD_TIMESPEC( &entry->expires_at, &TRANSACTION_END_MARGIN, &entry->expires_at );

  debug( "Set transaction timeout to %d.%09d.", ( int ) entry->expires_at.tv_sec, ( int ) entry->expires_at.tv_nsec );
}
static bool
add_transaction_entry( transaction_entry *entry ) {
  debug( "Adding a transaction entry ( entry = %p, transaction_db = %p ).", entry, transaction_db );

  assert( entry != NULL );
  assert( transaction_db != NULL );
  assert( transaction_db->xid != NULL );
  assert( transaction_db->barrier_xid != NULL );

  bool ret = get_monotonic_time( &entry->expires_at );
  if ( !ret ) {
    return false;
  }
  ADD_TIMESPEC( &entry->expires_at, &TRANSACTION_TIMEOUT, &entry->expires_at );

  dump_transaction_entry( debug, entry );

  if ( lookup_transaction_entry_by_xid( entry->xid ) == NULL ) {
    void *duplicated = insert_hash_entry( transaction_db->xid, &entry->xid, entry );
    assert( duplicated == NULL );
  }
  else {
    error( "Duplicated transaction entry found ( entry = %p, xid = %#x ).", entry, entry->xid );
    dump_transaction_entry( error, entry );
    return false;
  }

  if ( lookup_transaction_entry_by_barrier_xid( entry->barrier_xid ) == NULL ) {
    void *duplicated = insert_hash_entry( transaction_db->barrier_xid, &entry->barrier_xid, entry );
    assert( duplicated == NULL );
  }
  else {
    error( "Duplicated transaction entry found ( entry = %p, barrier_xid = %#x ).", entry, entry->barrier_xid );
    dump_transaction_entry( error, entry );
    delete_transaction_entry_by_xid( entry->xid );
    return false;
  }

  debug( "A transaction is added." );
  dump_transaction_entry( debug, entry );

  return true;
}
static void
handle_barrier_reply( uint64_t datapath_id, uint32_t transaction_id, void *user_data ) {
  UNUSED( user_data );

  debug( "Barrier reply from switch %#" PRIx64 " for %#x received.", datapath_id, transaction_id );

  transaction_entry *entry = lookup_transaction_entry_by_barrier_xid( transaction_id );
  if ( entry == NULL ) {
    warn( "A barrier reply for untracked transaction received ( transaction_id = %#x, datapath_id = %#" PRIx64 " ).",
          transaction_id, datapath_id );
    return;
  }

  entry->completed = true;
  bool ret = get_monotonic_time( &entry->expires_at );
  if ( !ret ) {
    return;
  }
  ADD_TIMESPEC( &entry->expires_at, &TRANSACTION_END_MARGIN, &entry->expires_at );

  debug( "Set transaction timeout to %d.%09d.", ( int ) entry->expires_at.tv_sec, ( int ) entry->expires_at.tv_nsec );
}
static void
age_transaction_entries( void *user_data ) {
  UNUSED( user_data );

  debug( "Aging transaction entries ( %p ).", transaction_db );

  assert( transaction_db != NULL );
  assert( transaction_db->xid != NULL );

  struct timespec now;
  bool ret = get_monotonic_time( &now );
  if ( !ret ) {
    return;
  }

  hash_entry *e;
  hash_iterator iter;
  init_hash_iterator( transaction_db->xid, &iter );
  while ( ( e = iterate_hash_next( &iter ) ) != NULL ) {
    transaction_entry *entry = e->value;
    if( entry == NULL ) {
      continue;
    }

    debug( "Checking an entry ( %p ).", entry );
    dump_transaction_entry( debug, entry );

    if ( TIMESPEC_LESS_THAN( &entry->expires_at, &now ) ) {
      struct ofp_header *header = entry->message->data;
      header->xid = htonl( entry->original_xid );
      if ( entry->completed ) {
        if ( !entry->error_received && entry->succeeded_callback != NULL ) {
          debug( "Calling succeeded callback ( %p ).", entry->succeeded_callback );
          entry->succeeded_callback( entry->datapath_id, entry->message, entry->succeeded_user_data );
        }
        else if ( entry->error_received && entry->failed_callback != NULL ) {
          debug( "Calling failed callback ( %p ).", entry->failed_callback );
          entry->failed_callback( entry->datapath_id, entry->message, entry->failed_user_data );
        }
      }
      else {
        if ( !entry->timeout ) {
          debug( "Transaction timeout. Wait for final marin to elapse." );
          // Wait for a moment after deleting all messages in send queue
          delete_openflow_messages( entry->datapath_id );
          entry->expires_at = now;
          ADD_TIMESPEC( &entry->expires_at, &TRANSACTION_END_MARGIN, &entry->expires_at );
          entry->timeout = true;
          continue;
        }
        else {
          warn( "Transaction timeout ( xid = %#x, barrier_xid = %#x, original_xid = %#x, expires_at = %d.%09d ).",
                entry->xid, entry->barrier_xid, entry->original_xid,
                ( int ) entry->expires_at.tv_sec, ( int ) entry->expires_at.tv_nsec );
          if ( entry->failed_callback != NULL ) {
            entry->failed_callback( entry->datapath_id, entry->message, entry->failed_user_data );
          }
        }
      }
      delete_transaction_entry_by_xid( entry->xid );
      free_transaction_entry( entry );
    }
  }

  debug( "Aging completed ( %p ).", transaction_db );
}