예제 #1
0
static void
do_flooding( packet_in packet_in ) {
  openflow_actions *actions = create_actions();
  append_action_output( actions, OFPP_FLOOD, UINT16_MAX );

  buffer *packet_out;
  if ( packet_in.buffer_id == UINT32_MAX ) {
    buffer *frame = duplicate_buffer( packet_in.data );
    fill_ether_padding( frame );
    packet_out = create_packet_out(
      get_transaction_id(),
      packet_in.buffer_id,
      packet_in.in_port,
      actions,
      frame
    );
    free_buffer( frame );
  }
  else {
    packet_out = create_packet_out(
      get_transaction_id(),
      packet_in.buffer_id,
      packet_in.in_port,
      actions,
      NULL
    );
  }
  send_openflow_message( packet_in.datapath_id, packet_out );
  free_buffer( packet_out );
  delete_actions( actions );
}
static void
do_flooding( packet_in packet_in, uint32_t in_port ) {
  openflow_actions *actions = create_actions();
  append_action_output( actions, OFPP_ALL, OFPCML_NO_BUFFER );

  buffer *packet_out;
  if ( packet_in.buffer_id == OFP_NO_BUFFER ) {
    buffer *frame = duplicate_buffer( packet_in.data );
    fill_ether_padding( frame );
    packet_out = create_packet_out(
      get_transaction_id(),
      packet_in.buffer_id,
      in_port,
      actions,
      frame
    );
    free_buffer( frame );
  }
  else {
    packet_out = create_packet_out(
      get_transaction_id(),
      packet_in.buffer_id,
      in_port,
      actions,
      NULL
    );
  }
  send_openflow_message( packet_in.datapath_id, packet_out );
  free_buffer( packet_out );
  delete_actions( actions );
}
예제 #3
0
static void
handle_packet_in( uint64_t datapath_id, packet_in message ) {
  if ( message.data == NULL ) {
    error( "data must not be NULL" );
    return;
  }
  uint32_t in_port = get_in_port_from_oxm_matches( message.match );
  if ( in_port == 0 ) {
    return;
  }

  openflow_actions *actions = create_actions();
  append_action_output( actions, OFPP_ALL, OFPCML_NO_BUFFER );

  openflow_instructions *insts = create_instructions();
  append_instructions_apply_actions( insts, actions );

  oxm_matches *match = create_oxm_matches();
  set_match_from_packet( match, in_port, 0, message.data );

  buffer *flow_mod = create_flow_mod(
    get_transaction_id(),
    get_cookie(),
    0,
    0,
    OFPFC_ADD,
    60,
    0,
    OFP_HIGH_PRIORITY,
    message.buffer_id,
    0,
    0,
    OFPFF_SEND_FLOW_REM,
    match,
    insts
  );
  send_openflow_message( datapath_id, flow_mod );
  free_buffer( flow_mod );
  delete_oxm_matches( match );
  delete_instructions( insts );

  if ( message.buffer_id == OFP_NO_BUFFER ) {
    buffer *frame = duplicate_buffer( message.data );
    fill_ether_padding( frame );
    buffer *packet_out = create_packet_out(
      get_transaction_id(),
      message.buffer_id,
      in_port,
      actions,
      frame
    );
    send_openflow_message( datapath_id, packet_out );
    free_buffer( packet_out );
    free_buffer( frame );
  }

  delete_actions( actions );
}
예제 #4
0
파일: ether_test.c 프로젝트: nhst/trema
void
test_fill_ether_padding_succeeds_if_length_is_less_than_ETH_MINIMUM_LENGTH() {
  buffer *buffer = alloc_buffer_with_length( ( size_t ) ETH_MINIMUM_LENGTH - ETH_FCS_LENGTH - 1 );
  append_back_buffer( buffer, ETH_MINIMUM_LENGTH - ETH_FCS_LENGTH - 1 );

  fill_ether_padding( buffer );

  assert_int_equal ( ( int ) buffer->length, ETH_MINIMUM_LENGTH - ETH_FCS_LENGTH );

  free_buffer( buffer );
}
static void
send_packet( uint32_t destination_port, packet_in packet_in, uint32_t in_port ) {
  openflow_actions *actions = create_actions();
  append_action_output( actions, destination_port, OFPCML_NO_BUFFER );

  openflow_instructions *insts = create_instructions();
  append_instructions_apply_actions( insts, actions );

  oxm_matches *match = create_oxm_matches();
  set_match_from_packet( match, in_port, NULL, packet_in.data );

  buffer *flow_mod = create_flow_mod(
    get_transaction_id(),
    get_cookie(),
    0,
    0,
    OFPFC_ADD,
    60,
    0,
    OFP_HIGH_PRIORITY,
    packet_in.buffer_id,
    0,
    0,
    OFPFF_SEND_FLOW_REM,
    match,
    insts
  );
  send_openflow_message( packet_in.datapath_id, flow_mod );
  free_buffer( flow_mod );
  delete_oxm_matches( match );
  delete_instructions( insts );

  if ( packet_in.buffer_id == OFP_NO_BUFFER ) {
    buffer *frame = duplicate_buffer( packet_in.data );
    fill_ether_padding( frame );
    buffer *packet_out = create_packet_out(
      get_transaction_id(),
      packet_in.buffer_id,
      in_port,
      actions,
      frame
    );
    send_openflow_message( packet_in.datapath_id, packet_out );
    free_buffer( packet_out );
    free_buffer( frame );
  }

  delete_actions( actions );
}
예제 #6
0
static void
send_packet_out( packet_in packet_in, openflow_actions *actions ) {
  buffer *frame = duplicate_buffer( packet_in.data );
  fill_ether_padding( frame );

  buffer *packet_out = create_packet_out(
    get_transaction_id(),
    UINT32_MAX,
    packet_in.in_port,
    actions,
    frame
  );

  free_buffer( frame );
  send_openflow_message( packet_in.datapath_id, packet_out );
  free_buffer( packet_out );
}
예제 #7
0
static void
output_packet( buffer *packet, uint64_t dpid, uint16_t port_no ) {
  openflow_actions *actions = create_actions();
  const uint16_t max_len = UINT16_MAX;
  append_action_output( actions, port_no, max_len );

  const uint32_t transaction_id = get_transaction_id();
  const uint32_t buffer_id = UINT32_MAX;
  const uint16_t in_port = OFPP_NONE;

  fill_ether_padding( packet );
  buffer *packet_out = create_packet_out( transaction_id, buffer_id, in_port,
                                          actions, packet );

  send_openflow_message( dpid, packet_out );

  free_buffer( packet_out );
  delete_actions( actions );
}
예제 #8
0
static void
send_packet( uint16_t destination_port, packet_in packet_in ) {
  openflow_actions *actions = create_actions();
  append_action_output( actions, destination_port, UINT16_MAX );

  struct ofp_match match;
  set_match_from_packet( &match, packet_in.in_port, 0, packet_in.data );

  buffer *flow_mod = create_flow_mod(
    get_transaction_id(),
    match,
    get_cookie(),
    OFPFC_ADD,
    60,
    0,
    UINT16_MAX,
    packet_in.buffer_id,
    OFPP_NONE,
    OFPFF_SEND_FLOW_REM,
    actions
  );
  send_openflow_message( packet_in.datapath_id, flow_mod );
  free_buffer( flow_mod );

  if ( packet_in.buffer_id == UINT32_MAX ) {
    buffer *frame = duplicate_buffer( packet_in.data );
    fill_ether_padding( frame );
    buffer *packet_out = create_packet_out(
      get_transaction_id(),
      packet_in.buffer_id,
      packet_in.in_port,
      actions,
      frame
    );
    send_openflow_message( packet_in.datapath_id, packet_out );
    free_buffer( packet_out );
    free_buffer( frame );
  }

  delete_actions( actions );
}
예제 #9
0
static void
send_packet_out_for_each_switch( switch_info *sw, buffer *packet, uint64_t dpid, uint16_t in_port ) {
  openflow_actions *actions = create_actions();
  int number_of_actions = foreach_port( sw->ports, build_packet_out_actions, actions, dpid, in_port );

  // check if no action is build
  if ( number_of_actions > 0 ) {
    const uint32_t transaction_id = get_transaction_id();
    const uint32_t buffer_id = UINT32_MAX;
    const uint16_t in_port = OFPP_NONE;

    fill_ether_padding( packet );
    buffer *packet_out = create_packet_out( transaction_id, buffer_id, in_port,
                                            actions, packet );

    send_openflow_message( sw->dpid, packet_out );

    free_buffer( packet_out );
  }

  delete_actions( actions );
}
예제 #10
0
static void
send_packet_out( uint64_t datapath_id, openflow_actions *actions, const buffer *original ) {
  const uint32_t transaction_id = get_transaction_id();
  const uint32_t buffer_id = UINT32_MAX;
  const uint16_t in_port = OFPP_NONE;
  buffer *copy = NULL;
  const buffer *packet = original;

  if ( original->length + ETH_FCS_LENGTH < ETH_MINIMUM_LENGTH ) {
    copy = duplicate_buffer( original );
    fill_ether_padding( copy );
    packet = copy;
  }
  buffer *packet_out = create_packet_out( transaction_id, buffer_id, in_port,
                                          actions, packet );

  send_openflow_message( datapath_id, packet_out );

  free_buffer( packet_out );
  if ( copy != NULL ) {
    free_buffer( copy );
  }
}
예제 #11
0
static void
handle_frame_received_on_switch_port( buffer *frame, void *user_data ) {
  assert( frame != NULL );
  assert( user_data != NULL );

  switch_port *port = user_data;

  if ( !lock_mutex( &mutex ) ) {
    return;
  }

  if ( ( port->config & ( OFPPC_PORT_DOWN | OFPPC_NO_RECV ) ) != 0 ) {
    unlock_mutex( &mutex );
    return;
  }

  if ( frame->length + ETH_FCS_LENGTH < ETH_MINIMUM_LENGTH ) {
    fill_ether_padding( frame );
  }

  handle_received_frame( port, frame );

  unlock_mutex( &mutex );
}
예제 #12
0
void
test_fill_ether_padding_fails_if_buffer_is_NULL() {
  expect_string( mock_die, output,
                 "Argument of fill_ether_padding must not be NULL." );
  expect_assert_failure( fill_ether_padding( NULL ) );
}
예제 #13
0
파일: controller.c 프로젝트: aigamo/trema
/*
 * @overload send_packet_out(datapath_id, options={})
 *   Sends a packet_out message to have a packet processed by the datapath.
 *
 *   @example
 *     send_packet_out(
 *       datapath_id,
 *       :packet_in => message,
 *       :actions => Trema::SendOutPort.new(port_no)
 *     )
 *
 *
 *   @param [Number] datapath_id
 *     the datapath to which a message is sent.
 *
 *   @param [Hash] options
 *     the options to create a message with.
 *
 *
 *   @option options [PacketIn] :packet_in (nil)
 *     The {PacketIn} object received by packet_in handler. If this
 *     option is not nil, :buffer_id, :data, and :in_port option is
 *     set automatically according to the value of :packet_in.
 *
 *   @option options [Number] :in_port (OFPP_NONE)
 *     The port from which the frame is to be sent. OFPP_NONE if
 *     none. OFPP_TABLE to perform the actions defined in the flow
 *     table.
 *
 *   @option options [Number] :buffer_id (0xffffffff)
 *     The buffer ID assigned by the datapath. If 0xffffffff, the
 *     frame is not buffered, and the entire frame must be passed in
 *     :data.
 *
 *   @option options [String, nil] :data (nil)
 *     The entire Ethernet frame. Should be of length 0 if buffer_id
 *     is 0xffffffff, and should be of length >0 otherwise.
 *
 *   @option options [Action, Array<Action>, nil] :actions (nil)
 *     The sequence of actions specifying the actions to perform on
 *     the frame.
 *
 *   @option options [Boolean] :zero_padding (false)
 *     If true, fill up to minimum ethernet frame size.
 */
static VALUE
controller_send_packet_out( int argc, VALUE *argv, VALUE self ) {
  VALUE datapath_id = Qnil;
  VALUE options = Qnil;
  rb_scan_args( argc, argv, "11", &datapath_id, &options );

  // Defaults.
  uint32_t buffer_id = UINT32_MAX;
  uint16_t in_port = OFPP_NONE;
  openflow_actions *actions = create_actions();
  const buffer *data = NULL;
  buffer *allocated_data = NULL;
  VALUE opt_zero_padding = Qnil;

  if ( options != Qnil ) {
    VALUE opt_message = rb_hash_aref( options, ID2SYM( rb_intern( "packet_in" ) ) );
    if ( opt_message != Qnil ) {
      packet_in *message;
      Data_Get_Struct( opt_message, packet_in, message );

      if ( NUM2ULL( datapath_id ) == message->datapath_id ) {
        buffer_id = message->buffer_id;
        in_port = message->in_port;
      }
      data = ( buffer_id == UINT32_MAX ? message->data : NULL );
    }

    VALUE opt_buffer_id = rb_hash_aref( options, ID2SYM( rb_intern( "buffer_id" ) ) );
    if ( opt_buffer_id != Qnil ) {
      buffer_id = ( uint32_t ) NUM2ULONG( opt_buffer_id );
    }

    VALUE opt_in_port = rb_hash_aref( options, ID2SYM( rb_intern( "in_port" ) ) );
    if ( opt_in_port != Qnil ) {
      in_port = ( uint16_t ) NUM2UINT( opt_in_port );
    }

    VALUE opt_action = rb_hash_aref( options, ID2SYM( rb_intern( "actions" ) ) );
    if ( opt_action != Qnil ) {
      form_actions( opt_action, actions );
    }

    VALUE opt_data = rb_hash_aref( options, ID2SYM( rb_intern( "data" ) ) );
    if ( opt_data != Qnil ) {
      Check_Type( opt_data, T_STRING );
      uint16_t length = ( uint16_t ) RSTRING_LEN( opt_data );
      allocated_data = alloc_buffer_with_length( length );
      memcpy( append_back_buffer( allocated_data, length ), RSTRING_PTR( opt_data ), length );
      data = allocated_data;
    }

    opt_zero_padding = rb_hash_aref( options, ID2SYM( rb_intern( "zero_padding" ) ) );
    if ( opt_zero_padding != Qnil ) {
      if ( TYPE( opt_zero_padding ) != T_TRUE && TYPE( opt_zero_padding ) != T_FALSE ) {
        rb_raise( rb_eTypeError, ":zero_padding must be true or false" );
      }
    }
  }

  if ( data != NULL && data->length + ETH_FCS_LENGTH < ETH_MINIMUM_LENGTH &&
       opt_zero_padding != Qnil && TYPE( opt_zero_padding ) == T_TRUE ) {
    if ( allocated_data == NULL ) {
      allocated_data = duplicate_buffer( data );
      data = allocated_data;
    }
    fill_ether_padding( allocated_data );
  }

  buffer *packet_out = create_packet_out(
    get_transaction_id(),
    buffer_id,
    in_port,
    actions,
    data
  );
  send_openflow_message( NUM2ULL( datapath_id ), packet_out );

  if ( allocated_data != NULL ) {
    free_buffer( allocated_data );
  }
  free_buffer( packet_out );
  delete_actions( actions );
  return self;
}
예제 #14
0
OFDPE
send_frame_from_switch_port( const uint32_t port_no, buffer *frame ) {
  assert( port_no > 0 );
  assert( frame != NULL );
 
  if ( port_no == OFPP_NORMAL || port_no == OFPP_CONTROLLER || port_no == OFPP_LOCAL || port_no == OFPP_ANY ) {
    error( "Invalid output port number ( port_no = %u, frame = %p ).", port_no, frame );
    return OFDPE_FAILED;
  }

  if ( frame->length + ETH_FCS_LENGTH < ETH_MINIMUM_LENGTH ) {
    fill_ether_padding( frame );
  }

  uint32_t in_port = 0;
  if ( port_no == OFPP_ALL || port_no == OFPP_FLOOD || port_no == OFPP_IN_PORT || port_no == OFPP_TABLE ) {
    if ( frame->user_data == NULL ) {
      warn( "Ethernet frame is not parsed yet. OFPP_ALL, OFPP_FLOOD, OFPP_IN_PORT, and OFPP_TABLE "
            "require eth_in_port to find actual output ports ( port_no = %u, frame = %p ).", port_no, frame );
      return OFDPE_FAILED;
    }
    in_port = ( ( packet_info * ) frame->user_data )->eth_in_port;
    if ( in_port == 0 || ( in_port > OFPP_MAX && in_port != OFPP_CONTROLLER ) ) {
      warn( "Invalid eth_in_port found in a parsed frame ( frame = %p, eth_in_port = %u ).", frame, in_port );
      return OFDPE_FAILED;
    }
  }

  if ( !lock_mutex( &mutex ) ) {
    return ERROR_LOCK;
  }

  OFDPE ret = OFDPE_SUCCESS;
  if ( port_no != OFPP_TABLE ) {
    list_element *ports = get_switch_ports_to_output( port_no, in_port );
    for ( list_element *e = ports; e != NULL;  e = e->next ) {
      assert( e->data != NULL );
      switch_port *port = e->data;
      if ( ( port->config & ( OFPPC_PORT_DOWN | OFPPC_NO_FWD ) ) != 0 ) {
        continue;
      }
      assert( port->device != NULL );
      send_frame( port->device, frame );
    }

    if ( ports != NULL ) {
      delete_list( ports );
    }
  }
  else {
    if ( in_port != OFPP_CONTROLLER ) {
      switch_port *port = lookup_switch_port( in_port );
      if ( port != NULL ) {
        handle_received_frame( port, frame );
      }
      else {
        ret = OFDPE_FAILED;
      }
    }
    else {
      warn( "Packet-out with in_port = OFPP_CONTROLLER is not supported." );
      ret = OFDPE_FAILED;
    }
  }

  if ( !unlock_mutex( &mutex ) ) {
    return ERROR_UNLOCK;
  }

  return ret;
}
예제 #15
0
static buffer *
create_lldp_frame( const uint8_t *mac, uint64_t dpid, uint16_t port_no ) {
  buffer *lldp_buf;
  size_t lldp_buf_len = 0;
  ether_header_t *ether;

  struct tlv *chassis_id_tlv;
  uint32_t chassis_id_tlv_len = 0;
  uint32_t chassis_id_strlen = 0;
  struct tlv *port_id_tlv;
  uint32_t port_id_tlv_len = 0;
  uint32_t port_id_strlen = 0;
  struct tlv *ttl_tlv;
  struct tlv *end_tlv;
  char *info;
  char dpid_str[ LLDP_TLV_CHASSIS_ID_INFO_MAX_LEN ];
  char port_no_str[ LLDP_TLV_PORT_ID_INFO_MAX_LEN ];
  uint16_t *ttl_val;
  size_t padding_length = 0;

  debug( "Creating LLDP Frame." );

  // Convert Chassis ID into string
  chassis_id_strlen = ( uint32_t ) snprintf( dpid_str, ( LLDP_TLV_CHASSIS_ID_INFO_MAX_LEN - 1 ), "%#" PRIx64, dpid );

  assert ( chassis_id_strlen <= ( LLDP_TLV_CHASSIS_ID_INFO_MAX_LEN - 1 ) );

  chassis_id_tlv_len = LLDP_TLV_HEAD_LEN + LLDP_SUBTYPE_LEN + chassis_id_strlen;

  // Convert Port ID into string
  port_id_strlen = ( uint32_t ) snprintf( port_no_str, ( LLDP_TLV_PORT_ID_INFO_MAX_LEN - 1 ), "%d", port_no );
  assert ( port_id_strlen <= ( LLDP_TLV_PORT_ID_INFO_MAX_LEN - 1 ) );
  port_id_tlv_len = LLDP_TLV_HEAD_LEN + LLDP_SUBTYPE_LEN + port_id_strlen;

  lldp_buf_len = sizeof( ether_header_t ) + chassis_id_tlv_len + port_id_tlv_len
    + LLDP_TTL_LEN;

  if ( lldp_buf_len + ETH_FCS_LENGTH < ETH_MINIMUM_LENGTH ) {
    padding_length = ETH_MINIMUM_LENGTH - ( lldp_buf_len + ETH_FCS_LENGTH );
    lldp_buf_len += padding_length;
  }
  if ( lldp_over_ip ) {
    lldp_ethtype = ETH_ETHTYPE_IPV4;
    lldp_buf_len += sizeof( ipv4_header_t ) + sizeof( etherip_header ) + sizeof( ether_header_t );
  }

  lldp_buf = alloc_buffer_with_length( lldp_buf_len );

  if ( lldp_over_ip ) {
    ether = append_back_buffer( lldp_buf, sizeof( ether_header_t ) );
    memset( ether->macda, 0xff, ETH_ADDRLEN );
    memcpy( ether->macsa, mac, ETH_ADDRLEN );
    ether->type = htons( ETH_ETHTYPE_IPV4 );

    ipv4_header_t *ip = append_back_buffer( lldp_buf, sizeof( ipv4_header_t ) );
    memset( ip, 0, sizeof( ipv4_header_t ) );
    ip->ihl = 5;
    ip->version = 4;
    ip->ttl = 1;
    ip->protocol = IPPROTO_ETHERIP;
    ip->tot_len = htons( ( uint16_t ) ( lldp_buf_len - sizeof( ether_header_t ) ) );
    ip->saddr = htonl( lldp_ip_src );
    ip->daddr = htonl( lldp_ip_dst );
    ip->csum = get_checksum( ( uint16_t * ) ip, sizeof( ipv4_header_t ) );
    etherip_header *etherip = append_back_buffer( lldp_buf, sizeof( etherip_header ) );
    etherip->version = htons( ETHERIP_VERSION );
  }

  // Create ether frame header
  ether = append_back_buffer( lldp_buf, sizeof( ether_header_t ) );
  memcpy( ether->macda, lldp_mac_dst, ETH_ADDRLEN );
  memcpy( ether->macsa, mac, ETH_ADDRLEN );
  ether->type = htons( ETH_ETHTYPE_LLDP );

  // Create Chassis ID TLV
  chassis_id_tlv = append_back_buffer( lldp_buf, chassis_id_tlv_len );
  chassis_id_tlv->type_len = LLDP_TL( LLDP_TYPE_CHASSIS_ID, chassis_id_tlv_len );
  info = chassis_id_tlv->val;
  *info = CHASSIS_ID_SUBTYPE_LOCALLY_ASSINED;
  info += LLDP_SUBTYPE_LEN;
  strncpy( info, dpid_str, chassis_id_strlen );

  // Create Port ID TLV
  port_id_tlv = append_back_buffer( lldp_buf, port_id_tlv_len );
  port_id_tlv->type_len = LLDP_TL( LLDP_TYPE_PORT_ID, port_id_tlv_len );
  info = port_id_tlv->val;
  *info = PORT_ID_SUBTYPE_LOCALLY_ASSINED;
  info += LLDP_SUBTYPE_LEN;
  strncpy( info, port_no_str, port_id_strlen );

  // Create TTL TLV
  ttl_tlv = append_back_buffer( lldp_buf, LLDP_TTL_LEN );
  ttl_tlv->type_len = LLDP_TL( LLDP_TYPE_TTL, LLDP_TTL_LEN );
  ttl_val = ( uint16_t * ) ttl_tlv->val;
  *ttl_val = htons( LLDP_DEFAULT_TTL );

  // Create END OF LLDPDU TLV
  end_tlv = append_back_buffer( lldp_buf, LLDP_END_PDU_LEN );
  end_tlv->type_len = LLDP_TL( LLDP_TYPE_END, LLDP_TLV_HEAD_LEN );

  if ( padding_length > 0 ) {
    fill_ether_padding( lldp_buf );
  }

  return lldp_buf;
}
예제 #16
0
static VALUE
send_packet_out( int argc, VALUE *argv, VALUE self ) {
  VALUE datapath_id = Qnil;
  VALUE options = Qnil;
  rb_scan_args( argc, argv, "11", &datapath_id, &options );

  uint32_t buffer_id = OFP_NO_BUFFER;
  buffer *data = NULL;
  openflow_actions *actions = NULL;
  uint32_t in_port = OFPP_ANY;
  if ( !NIL_P( options ) ) {
    VALUE r_opt_action = HASH_REF( options, actions );
    if ( !NIL_P( r_opt_action ) ) {
      actions = pack_basic_action( r_opt_action );
    }

    VALUE r_opt_message = HASH_REF( options, packet_in );
    VALUE r_opt_data = HASH_REF( options, data );
    if ( !NIL_P( r_opt_message ) ) {

      if ( datapath_id == rb_iv_get( r_opt_message, "@datapath_id" ) ) {
        buffer_id = NUM2UINT( rb_iv_get( r_opt_message, "@buffer_id" ) );
        VALUE match = rb_iv_get( r_opt_message, "@match" );
        in_port = NUM2UINT( rb_iv_get( match, "@in_port" ) );
      }
       
      VALUE r_data = rb_iv_get( r_opt_message, "@data" );
      data = r_array_to_buffer( r_data );
    }
    else if ( !NIL_P( r_opt_data ) ) {
      data = r_array_to_buffer( r_opt_data );
    }

    buffer *packet_out;
    if ( buffer_id == OFP_NO_BUFFER &&
         ( !NIL_P( r_opt_message ) || !NIL_P( r_opt_data ) )) {
      buffer *frame = duplicate_buffer( data );
      fill_ether_padding( frame );

      packet_out = create_packet_out(
        get_transaction_id(),
        buffer_id, 
        in_port,
        actions,
        frame
      );
      free_buffer( data );
      free_buffer( frame );
    } 
    else {
      packet_out = create_packet_out(
        get_transaction_id(),
        buffer_id, 
        in_port,
        actions,
        NULL
      );
    }
    send_openflow_message( NUM2ULL( datapath_id ), packet_out );

    free_buffer( packet_out );
    delete_actions( actions );
  }
  return self;
}
예제 #17
0
파일: ether_test.c 프로젝트: nhst/trema
void
test_fill_ether_padding_fails_if_buffer_is_NULL() {
  expect_assert_failure( fill_ether_padding( NULL ) );
}
예제 #18
0
static void
recv_packet_from_tun() {
  char data[ PKT_BUF_SIZE ];
  ssize_t ret;

  ret = read( fd, data, PKT_BUF_SIZE );

  if ( ret <= 0 ) {
    return;
  }

  debug( "%zd bytes packet received from tun interface (fd = %d).", ret, fd );

  // FIXME: we need to parse the ipv4 packet.

  ipv4_header_t *ip_header = ( ipv4_header_t * ) data;
  host_entry *entry = lookup_host( ntohl( ip_header->daddr ) );
  struct in_addr addr;
  addr.s_addr = ip_header->daddr;

  if ( entry == NULL ) {
    error( "Failed to resolve host location (ip = %s).",
           inet_ntoa( addr ) );
    return;
  }

  // create an Ethernet frame and send a packet-out
  void *p;
  uint16_t *type;
  buffer *frame;
  buffer *pout;
  openflow_actions *actions;
  size_t frame_length = ETH_ADDRLEN * 2 + 2 + ( size_t ) ret;

  frame = alloc_buffer_with_length( frame_length );

  p = append_back_buffer( frame, ETH_ADDRLEN );
  memcpy( p, entry->mac, ETH_ADDRLEN );
  p = append_back_buffer( frame, ETH_ADDRLEN );
  memcpy( p, redirector_mac, ETH_ADDRLEN );

  type = append_back_buffer( frame, 2 );
  *type = htons( ETH_ETHTYPE_IPV4 );

  p = append_back_buffer( frame, ( size_t ) ret );
  memcpy( p, data, ( size_t ) ret );

  debug( "Sending a packet-out to a switch (ip = %s, dpid = %#" PRIx64 ", port = %u).",
         inet_ntoa( addr ), entry->dpid, entry->port );

  actions = create_actions();
  append_action_output( actions, entry->port, UINT16_MAX );

  fill_ether_padding( frame );
  pout = create_packet_out( get_transaction_id(), UINT32_MAX, OFPP_NONE,
                            actions, frame );

  send_openflow_message( entry->dpid, pout );

  free_buffer( frame );
  free_buffer( pout );
  delete_actions( actions );
}