static void handle_desc_stats_reply( uint64_t datapath_id, uint32_t transaction_id, uint16_t type, uint16_t flags, const buffer *data, void *user_data ) { UNUSED( transaction_id ); UNUSED( type ); UNUSED( flags ); show_desc *show_desc = user_data; if ( data->length < SIZE_OF_OFP_DESC ) { error( "invalid data" ); stop_trema(); return; } desc_entry *entry = xmalloc( sizeof( desc_entry ) ); entry->datapath_id = datapath_id; #ifdef TREMA_EDGE create_list( &entry->port_desc ); #endif memcpy( &entry->desc_stats, data->data, SIZE_OF_OFP_DESC ); insert_hash_entry( show_desc->db, &entry->datapath_id, entry ); #ifdef TREMA_EDGE buffer *port_desc_request = create_port_desc_multipart_request( get_transaction_id(), 0 ); send_openflow_message( datapath_id, port_desc_request ); free_buffer( port_desc_request ); #else buffer *features_request = create_features_request( get_transaction_id() ); send_openflow_message( datapath_id, features_request ); free_buffer( features_request ); #endif }
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 ); }
static void poison( uint64_t dpid, const uint8_t mac[ OFP_ETH_ALEN ] ) { struct ofp_match match; memset( &match, 0, sizeof( struct ofp_match ) ); match.wildcards = ( OFPFW_ALL & ~OFPFW_DL_DST ); memcpy( match.dl_dst, mac, OFP_ETH_ALEN ); const uint16_t idle_timeout = 0; const uint16_t hard_timeout = 0; const uint16_t priority = 0; const uint32_t buffer_id = 0; const uint16_t flags = 0; buffer *flow_mod = create_flow_mod( get_transaction_id(), match, get_cookie(), OFPFC_DELETE, idle_timeout, hard_timeout, priority, buffer_id, OFPP_NONE, flags, NULL ); send_openflow_message( dpid, flow_mod ); free_buffer( flow_mod ); memset( &match, 0, sizeof( struct ofp_match ) ); match.wildcards = ( OFPFW_ALL & ~OFPFW_DL_SRC ); memcpy( match.dl_src, mac, OFP_ETH_ALEN ); flow_mod = create_flow_mod( get_transaction_id(), match, get_cookie(), OFPFC_DELETE, idle_timeout, hard_timeout, priority, buffer_id, OFPP_NONE, flags, NULL ); send_openflow_message( dpid, flow_mod ); free_buffer( flow_mod ); debug( "Poisoning all entries whose dl_src or dl_dst matches %02x:%02x:%02x:%02x:%02x:%02x at dpid %#" PRIx64, mac[ 0 ], mac[ 1 ], mac[ 2 ], mac[ 3 ], mac[ 4 ], mac[ 5 ], dpid ); }
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 ); }
/* * Creates a Vendor Request message. This message can be used * to facilitate sending of vendor-defined arbitrary data. * * @overload initialize * @example * Vendor.new * * @overload initialize(options) * @example * Vendor.new( * :vendor => 0x3000, * :data => "deadbeef".unpack( "C*" ), * :transaction_id => 123 * ) * * @param [Hash] options * the options to create a message with. * @option options [Number] :xid * @option options [Number] :transaction_id * an unsigned 32bit integer number associated with this message. * if not specified, an auto-generated value is set. * @option options [Number] :vendor * the vendor identifier. If MSB is zero low order bytes are IEEE OUI. Otherwise defined by openflow. * @option options [Array] :data * a String that holds vendor's defined arbitrary length data. * * @raise [ArgumentError] if transaction ID is not an unsigned 32-bit integer. * @raise [ArgumentError] if user data is not an array of bytes. * @raise [TypeError] if options is not a hash. * @return [Vendor] */ static VALUE vendor_init( int argc, VALUE *argv, VALUE self ) { buffer *vendor = NULL; Data_Get_Struct( self, buffer, vendor ); VALUE options = Qnil; if ( rb_scan_args( argc, argv, "01", &options ) == 0 ) { set_xid( vendor, get_transaction_id() ); } else { if ( options == Qnil ) { set_xid( vendor, get_transaction_id() ); } else { if ( rb_scan_args( argc, argv, "01", &options ) == 1 ) { Check_Type( options, T_HASH ); VALUE tmp = Qnil; VALUE xid = Qnil; tmp = rb_hash_aref( options, ID2SYM( rb_intern( "transaction_id" ) ) ); if ( tmp != Qnil ) { xid = tmp; } tmp = rb_hash_aref( options, ID2SYM( rb_intern( "xid" ) ) ); if ( tmp != Qnil ) { xid = tmp; } if ( xid != Qnil ) { validate_xid( xid ); set_xid( vendor, ( uint32_t ) NUM2UINT( xid ) ); } else { set_xid( vendor, get_transaction_id() ); } tmp = rb_hash_aref( options, ID2SYM( rb_intern( "vendor" ) ) ); if ( tmp != Qnil ) { ( ( struct ofp_vendor_header * ) ( vendor->data ) )->vendor = htonl( ( uint32_t ) NUM2UINT( tmp ) ); } tmp = rb_hash_aref( options, ID2SYM( rb_intern( "data" ) ) ); if ( tmp != Qnil ) { Check_Type( tmp, T_ARRAY ); uint16_t length = ( uint16_t ) RARRAY_LEN( tmp ); append_back_buffer( vendor, length ); set_length( vendor, length ); uint8_t *data = ( uint8_t * ) ( ( char * ) vendor->data + sizeof( struct ofp_vendor_header ) ); int i; for ( i = 0; i < length; i++ ) { data[ i ] = ( uint8_t ) FIX2INT( RARRAY_PTR( tmp )[ i ] ); } } } } } return self; }
bool execute_transaction( uint64_t datapath_id, const buffer *message, succeeded_handler succeeded_callback, void *succeeded_user_data, failed_handler failed_callback, void *failed_user_data ) { assert( message != NULL ); assert( message->length >= sizeof( struct ofp_header ) ); transaction_entry *entry = alloc_transaction_entry(); entry->datapath_id = datapath_id; entry->message = duplicate_buffer( message ); entry->xid = get_transaction_id(); entry->barrier_xid = get_transaction_id(); struct ofp_header *header = entry->message->data; entry->original_xid = ntohl( header->xid ); header->xid = htonl( entry->xid ); // Override xid for keeping uniqueness entry->completed = false; entry->error_received = false; entry->timeout = false; debug( "Executing a transaction ( xid = %#x, barrier_xid = %#x, original_xid = %#x ).", entry->xid, entry->barrier_xid, entry->original_xid ); bool ret = send_openflow_message( datapath_id, entry->message ); if ( !ret ) { // FIXME: send queue may be full. We may need to retry for sending the message. error( "Failed to send an OpenFlow message ( datapath_id = %#" PRIx64 ", transaction_id = %#x ).", datapath_id, entry->original_xid ); free_transaction_entry( entry ); return false; } buffer *barrier = create_barrier_request( entry->barrier_xid ); ret = send_openflow_message( datapath_id, barrier ); free_buffer( barrier ); if ( !ret ) { error( "Failed to send a barrier request ( datapath_id = %#" PRIx64 ", transaction_id = %#x ).", datapath_id, entry->barrier_xid ); free_transaction_entry( entry ); return false; } entry->succeeded_callback = succeeded_callback; entry->succeeded_user_data = succeeded_user_data; entry->failed_callback = failed_callback; entry->failed_user_data = failed_user_data; ret = add_transaction_entry( entry ); if ( !ret ) { error( "Failed to save transaction entry ( %p ).", entry ); dump_transaction_entry( error, entry ); free_transaction_entry( entry ); return false; } debug( "OpenFlow messages are put into a send queue and a transaction entry is saved." ); return true; }
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 ); }
VALUE echo_init( int argc, VALUE *argv, VALUE self ) { buffer *echo = NULL; Data_Get_Struct( self, buffer, echo ); VALUE options = Qnil; if ( rb_scan_args( argc, argv, "01", &options ) == 0 ) { set_xid( echo, get_transaction_id() ); } else { if ( options == Qnil ) { set_xid( echo, get_transaction_id() ); } else if ( rb_obj_is_kind_of( options, rb_cInteger ) == Qtrue ) { validate_xid( options ); set_xid( echo, ( uint32_t ) NUM2UINT( options ) ); } else { Check_Type( options, T_HASH ); VALUE tmp = Qnil; VALUE xid = Qnil; tmp = rb_hash_aref( options, ID2SYM( rb_intern( "transaction_id" ) ) ); if ( tmp != Qnil ) { xid = tmp; } tmp = rb_hash_aref( options, ID2SYM( rb_intern( "xid" ) ) ); if ( tmp != Qnil ) { xid = tmp; } if ( xid != Qnil ) { validate_xid( xid ); set_xid( echo, ( uint32_t ) NUM2UINT( xid ) ); } else { set_xid( echo, get_transaction_id() ); } VALUE user_data = rb_hash_aref( options, ID2SYM( rb_intern( "user_data" ) ) ); if ( user_data != Qnil ) { Check_Type( user_data, T_STRING ); uint16_t length = ( uint16_t ) RSTRING_LEN( user_data ); append_back_buffer( echo, length ); set_length( echo, ( uint16_t ) ( sizeof( struct ofp_header ) + length ) ); memcpy( ( char * ) echo->data + sizeof( struct ofp_header ), RSTRING_PTR( user_data ), length ); } } } return self; }
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 ); }
bool send_lldp( probe_timer_entry *port ) { buffer *lldp; lldp = create_lldp_frame( port->mac, port->datapath_id, port->port_no ); openflow_actions *actions = create_actions(); if ( !append_action_output( actions, port->port_no, UINT16_MAX ) ) { free_buffer( lldp ); error( "Failed to sent LLDP frame(%#" PRIx64 ", %u)", port->datapath_id, port->port_no ); return false; } uint32_t transaction_id = get_transaction_id(); buffer *packetout = create_packet_out( transaction_id, UINT32_MAX, OFPP_NONE, actions, lldp ); if ( !send_openflow_message( port->datapath_id, packetout ) ) { free_buffer( lldp ); free_buffer( packetout ); delete_actions( actions ); die( "send_openflow_message" ); } free_buffer( lldp ); free_buffer( packetout ); delete_actions( actions ); debug( "Sent LLDP frame(%#" PRIx64 ", %u)", port->datapath_id, port->port_no ); return true; }
/* * Request message to retrieve configuration about a queue port setting that * quantifies a QoS. * Each flow entry contains a queue that a flow is mapped to set constraints to * define some restriction like maximum/minimum data rate. * * @overload initialize(options={}) * @example * QueueGetConfigRequest.new * QueueGetConfigRequest.new( :port => 1 ) * QueueGetConfigRequest.new( :port => 1, :transaction_id => 123 ) * * @param [Hash] options * the options to create a message with. * * @option options [Number] :port * a port number to query (defaults to 1). * * @option options [Number] :transaction_id * An unsigned 32-bit integer number associated with this message. * If not specified, an auto-generated value is set. * * @raise [ArgumentError] if transaction_id is not an unsigned 32-bit integer. * @raise [ArgumentError] if port is not an unsigned 16-bit integer. * @raise [TypeError] if options is not a hash. * * @return [QueueGetConfigRequest] * an object that encapsulates the +OFPT_GET_CONFIG_REQUEST+ OpenFlow message. */ static VALUE queue_get_config_request_init( int argc, VALUE *argv, VALUE self ) { buffer *queue_get_config_request; Data_Get_Struct( self, buffer, queue_get_config_request ); uint32_t xid = get_transaction_id(); uint16_t port = 1; VALUE options; if ( rb_scan_args( argc, argv, "01", &options ) == 1 ) { Check_Type( options, T_HASH ); VALUE xid_ruby; if ( ( xid_ruby = rb_hash_aref( options, ID2SYM( rb_intern( "transaction_id" ) ) ) ) != Qnil ) { if ( rb_funcall( xid_ruby, rb_intern( "unsigned_32bit?" ), 0 ) == Qfalse ) { rb_raise( rb_eArgError, "Transaction ID must be an unsigned 32-bit integer" ); } xid = ( uint32_t ) NUM2UINT( xid_ruby ); } VALUE port_ruby; if ( ( port_ruby = rb_hash_aref( options, ID2SYM( rb_intern( "port" ) ) ) ) != Qnil ) { if ( rb_funcall( port_ruby, rb_intern( "unsigned_16bit?" ), 0 ) == Qfalse ) { rb_raise( rb_eArgError, "Port must be an unsigned 16-bit integer" ); } port = ( uint16_t ) NUM2UINT( port_ruby ); } } ( ( struct ofp_header * ) ( queue_get_config_request->data ) )->xid = htonl( xid ); ( ( struct ofp_queue_get_config_request * ) ( queue_get_config_request->data ) )->port = htons( port ); return self; }
static void handle_packet_in( uint64_t datapath_id, packet_in message ) { openflow_actions *actions = create_actions(); append_action_output( actions, ( uint16_t ) ( message.in_port + 1 ), OFPCML_NO_BUFFER ); struct ofp_match match; set_match_from_packet( &match, message.in_port, 0, message.data ); buffer *flow_mod = create_flow_mod( get_transaction_id(), match, get_cookie(), OFPFC_ADD, 0, 0, OFP_HIGH_PRIORITY, message.buffer_id, OFPP_NONE, 0, actions ); send_openflow_message( datapath_id, flow_mod ); free_buffer( flow_mod ); delete_actions( actions ); }
static void discard_packet_in( uint64_t datapath_id, uint16_t in_port, const buffer *packet ) { const uint32_t wildcards = 0; struct ofp_match match; set_match_from_packet( &match, in_port, wildcards, packet ); char match_str[ 1024 ]; match_to_string( &match, match_str, sizeof( match_str ) ); const uint16_t idle_timeout = 0; const uint16_t hard_timeout = PACKET_IN_DISCARD_DURATION; const uint16_t priority = UINT16_MAX; const uint32_t buffer_id = UINT32_MAX; const uint16_t flags = 0; info( "Discarding packets for a certain period ( datapath_id = %#" PRIx64 ", match = [%s], duration = %u [sec] ).", datapath_id, match_str, hard_timeout ); buffer *flow_mod = create_flow_mod( get_transaction_id(), match, get_cookie(), OFPFC_ADD, idle_timeout, hard_timeout, priority, buffer_id, OFPP_NONE, flags, NULL ); send_openflow_message( datapath_id, flow_mod ); free_buffer( flow_mod ); }
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, UINT32_MAX, OFPP_NONE, OFPFF_SEND_FLOW_REM, actions ); send_openflow_message( packet_in.datapath_id, flow_mod ); free_buffer( flow_mod ); send_packet_out( packet_in, actions ); delete_actions( actions ); }
static void handle_switch_ready( uint64_t datapath_id, void *user_data ) { UNUSED( user_data ); openflow_actions *actions = create_actions(); append_action_output( actions, OFPP_CONTROLLER, OFPCML_NO_BUFFER ); openflow_instructions *insts = create_instructions(); append_instructions_apply_actions( insts, actions ); buffer *flow_mod = create_flow_mod( get_transaction_id(), get_cookie(), 0, 0, OFPFC_ADD, 0, 0, OFP_LOW_PRIORITY, OFP_NO_BUFFER, 0, 0, OFPFF_SEND_FLOW_REM, NULL, insts ); send_openflow_message( datapath_id, flow_mod ); free_buffer( flow_mod ); delete_instructions( insts ); delete_actions( actions ); }
static void send_flow_mod_receiving_lldp( sw_entry *sw, uint16_t hard_timeout, uint16_t priority ) { struct ofp_match match; memset( &match, 0, sizeof( struct ofp_match ) ); if ( !options.lldp_over_ip ) { match.wildcards = OFPFW_ALL & ~OFPFW_DL_TYPE; match.dl_type = ETH_ETHTYPE_LLDP; } else { match.wildcards = OFPFW_ALL & ~( OFPFW_DL_TYPE | OFPFW_NW_PROTO | OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK ); match.dl_type = ETH_ETHTYPE_IPV4; match.nw_proto = IPPROTO_ETHERIP; match.nw_src = options.lldp_ip_src; match.nw_dst = options.lldp_ip_dst; } openflow_actions *actions = create_actions(); const uint16_t max_len = UINT16_MAX; append_action_output( actions, OFPP_CONTROLLER, max_len ); const uint16_t idle_timeout = 0; const uint32_t buffer_id = UINT32_MAX; const uint16_t flags = 0; buffer *flow_mod = create_flow_mod( get_transaction_id(), match, get_cookie(), OFPFC_ADD, idle_timeout, hard_timeout, priority, buffer_id, OFPP_NONE, flags, actions ); send_openflow_message( sw->datapath_id, flow_mod ); delete_actions( actions ); free_buffer( flow_mod ); debug( "Sent a flow_mod for receiving LLDP frames from %#" PRIx64 ".", sw->datapath_id ); }
/* * A {PortMod} instance a request object to perform operations on a physical port. * * @overload initialize(options={}) * @example * PortMod.new( * :port_no => 1, * :hw_addr => "11:22:33:44:55:66", * :config => 1, * :mask => 1, * :advertise => 0 * ) * * @param [Hash] options * the options to create a message with. * * @param [Number] :port_no * an index into datapath's ports list. * * @param [String,Number,Trema::Mac] :hw_addr * the hardware address of a port. * Unique for each port. Obtained from +OFPT_FEATURES_REPLY+ message. * Can be supplied as a string, number or as a Mac object. * * @param [Number] :config * a bitmap that can be set to configure a port. * * @param [Number] :mask * set the bits of the +config+ flag to change. * * @param [Number] :advertise * bitmap of +ofp_port_features+ set to zero to prevent * any changes. Or can be copied from +OFPT_FEATURES_REPLY+ message. * * @return [PortMod] * an object that encapsulates the +OFPT_PORT_MOD+ OpenFlow message. */ static VALUE port_mod_init( int argc, VALUE *argv, VALUE self ) { VALUE options; if ( rb_scan_args( argc, argv, "01", &options ) == 1 ) { Check_Type( options, T_HASH ); buffer *port_mod; Data_Get_Struct( self, buffer, port_mod ); VALUE mac; VALUE hw_addr; uint8_t *ptr; uint8_t haddr[ OFP_ETH_ALEN ]; if ( ( hw_addr = rb_hash_aref( options, ID2SYM( rb_intern( "hw_addr" ) ) ) ) != Qnil ) { mac = hw_addr; if ( rb_obj_is_kind_of( hw_addr, rb_cString ) == Qtrue || rb_obj_is_kind_of( hw_addr, rb_cInteger ) == Qtrue ) { mac = rb_funcall( rb_eval_string( "Trema::Mac" ), rb_intern( "new" ), 1, hw_addr ); } else if ( rb_obj_is_instance_of( hw_addr, rb_eval_string( "Trema::Mac" ) ) == Qfalse ) { rb_raise( rb_eArgError, "hw_addr must be a string or an integer or Mac object" ); } ptr = ( uint8_t * ) dl_addr_to_a( mac, haddr ); rb_iv_set( self, "@hw_addr", mac ); } VALUE port_no; if ( ( port_no = rb_hash_aref( options, ID2SYM( rb_intern( "port_no" ) ) ) ) != Qnil ) { if ( rb_funcall( port_no, rb_intern( "unsigned_16bit?" ), 0 ) == Qfalse ) { rb_raise( rb_eArgError, "Port number must be an unsigned 16-bit integer" ); } rb_iv_set( self, "@port_no", port_no ); } VALUE config; if ( ( config = rb_hash_aref( options, ID2SYM( rb_intern( "config" ) ) ) ) != Qnil ) { rb_iv_set( self, "@config", config ); } VALUE mask; if ( ( mask = rb_hash_aref( options, ID2SYM( rb_intern( "mask" ) ) ) ) != Qnil ) { rb_iv_set( self, "@mask", mask ); } VALUE advertise; if ( ( advertise = rb_hash_aref( options, ID2SYM( rb_intern( "advertise" ) ) ) ) != Qnil ) { rb_iv_set( self, "@advertise", advertise ); } uint32_t xid = get_transaction_id(); rb_iv_set( self, "@transaction_id", UINT2NUM( xid ) ); ( ( struct ofp_header * ) ( port_mod->data ) )->xid = htonl( xid ); ( ( struct ofp_port_mod * ) ( port_mod->data ) )->port_no = htons( ( uint16_t ) NUM2UINT( port_no ) ); memcpy( ( ( struct ofp_port_mod * ) ( port_mod->data ) )->hw_addr, ptr, OFP_ETH_ALEN ); ( ( struct ofp_port_mod * ) ( port_mod->data ) )->config = htonl( ( uint32_t ) NUM2UINT( config ) ); ( ( struct ofp_port_mod * ) ( port_mod->data ) )->mask = htonl( ( uint32_t ) NUM2UINT( mask ) ); ( ( struct ofp_port_mod * ) ( port_mod->data ) )->advertise = htonl( ( uint32_t ) NUM2UINT( advertise ) ); } else { rb_raise( rb_eArgError, "Port no, hw_addr, config, mask, advertise are mandatory options" ); } return self; }
static void handle_switch_ready( uint64_t datapath_id, void *user_data ) { UNUSED( user_data ); buffer *message = create_features_request( get_transaction_id() ); send_openflow_message( datapath_id, message ); free_buffer( message ); }
static void send_features_request( sw_entry *sw ) { uint32_t id = get_transaction_id(); buffer *buf = create_features_request( id ); send_openflow_message( sw->datapath_id, buf ); free_buffer( buf ); debug( "Sent switch features request to %#" PRIx64 ".", sw->datapath_id ); }
static void handle_switch_ready( uint64_t datapath_id, void *user_data ) { UNUSED( user_data ); uint32_t id = get_transaction_id(); buffer *buf = create_features_request( id ); send_openflow_message( datapath_id, buf ); free_buffer( buf ); }
/* * Creates a {GetConfigRequest} instance to query configuration parameters * from the switch. * * @overload initialize() * @example * GetConfigRequest.new * * @overload initialize(transaction_id) * @example * GetConfigRequest.new( 123 ) * @param [Integer] transaction_id * An unsigned 32-bit integer number associated with this message. * * @overload initialize(options) * @example * GetConfigRequest.new( :xid => 123 ) * GetConfigRequest.new( :transaction_id => 123 ) * @param [Hash] options * the options to create a message with. * @option options [Number] :xid an alias to transaction_id. * @option options [Number] :transaction_id * An unsigned 32-bit integer number associated with this message. * If not specified, an auto-generated value is set. * * @raise [ArgumentError] if transaction ID is not an unsigned 32-bit integer. * @raise [TypeError] if argument is not a Integer or a Hash. * @return [GetConfigRequest] * an object that encapsulates the +OFPT_GET_CONFIG+ OpenFlow message. */ static VALUE get_config_request_init( int argc, VALUE *argv, VALUE self ) { buffer *get_config_request; Data_Get_Struct( self, buffer, get_config_request ); VALUE options = Qnil; if ( rb_scan_args( argc, argv, "01", &options ) == 0 ) { set_xid( get_config_request, get_transaction_id() ); } else { if ( options == Qnil ) { set_xid( get_config_request, get_transaction_id() ); } else if ( rb_obj_is_kind_of( options, rb_cInteger ) == Qtrue ) { validate_xid( options ); set_xid( get_config_request, ( uint32_t ) NUM2UINT( options ) ); } else { Check_Type( options, T_HASH ); VALUE tmp = Qnil; VALUE xid = Qnil; tmp = rb_hash_aref( options, ID2SYM( rb_intern( "transaction_id" ) ) ); if ( tmp != Qnil ) { xid = tmp; } tmp = rb_hash_aref( options, ID2SYM( rb_intern( "xid" ) ) ); if ( tmp != Qnil ) { xid = tmp; } if ( xid != Qnil ) { validate_xid( xid ); set_xid( get_config_request, ( uint32_t ) NUM2UINT( xid ) ); } else { set_xid( get_config_request, get_transaction_id() ); } } } return self; }
static void handle_list_switches_reply( const list_element *switches, void *user_data ) { show_desc *show_desc = user_data; #ifdef TREMA_EDGE buffer *desc_stats_request = create_desc_multipart_request( get_transaction_id(), 0 ); #else buffer *desc_stats_request = create_desc_stats_request( get_transaction_id(), 0 ); #endif const list_element *element; for ( element = switches; element != NULL; element = element->next ) { uint64_t datapath_id = * ( uint64_t *) element->data; send_openflow_message( datapath_id, desc_stats_request ); show_desc->count++; } free_buffer( desc_stats_request ); }
static void set_miss_send_len_maximum( uint64_t datapath_id ) { uint32_t id = get_transaction_id(); const uint16_t config_flags = OFPC_FRAG_NORMAL; const uint16_t miss_send_len = UINT16_MAX; buffer *buf = create_set_config( id, config_flags, miss_send_len ); send_openflow_message( datapath_id, buf ); free_buffer( buf ); }
/* * @overload initialize(transaction_id=nil, type=OFPET_HELLO_FAILED, code=OFPHFC_INCOMPATIBLE, user_data=nil) * * @param [Number] transaction_id * a positive number, not recently attached to any previous pending commands to * guarantee message integrity auto-generated if not specified. * * @param [Number] type * a command or action that failed. Defaults to +OFPET_HELLO_FAILED+ if * not specified. * * @param [Number] code * the reason of the failed type error. Defaults to +OFPHFC_INCOMPATIBLE+ if * not specified. * * @param [String] user_data * a more user friendly explanation of the error. Defaults to nil if not * specified. * * @example Instantiate with type and code * Error.new(OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE) * * @example Instantiate with transaction_id, type and code. * Error.new(1234, OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR) * * @example Instantiate with transaction_id, type, code, user_data * Error.new(6789, OFPET_FLOW_MOD_FAILED, OFPFMFC_BAD_EMERG_TIMEOUT, "this is a test") * * @raise [ArgumentError] if transaction id is negative. * @raise [ArgumentError] if user data is not a string. * * @return [Error] * an object that encapsulates the +OFPT_ERROR+ openflow message. */ static VALUE error_new( int argc, VALUE *argv, VALUE klass ) { buffer *data = NULL; uint32_t xid = get_transaction_id(); VALUE xid_r; VALUE user_data; VALUE type_r; VALUE code_r; uint16_t type; uint16_t code; switch ( argc ) { case 2: // type, code specified. rb_scan_args( argc, argv, "02", &type_r, &code_r ); type = ( uint16_t ) NUM2UINT( type_r ); code = ( uint16_t ) NUM2UINT( code_r ); break; case 3: // transaction id, type, code specified. rb_scan_args( argc, argv, "03", &xid_r, &type_r, &code_r ); if ( NUM2INT( xid_r ) < 0 ) { rb_raise( rb_eArgError, "Transaction ID must be >= 0" ); } xid = ( uint32_t ) NUM2UINT( xid_r ); type = ( uint16_t ) NUM2UINT( type_r ); code = ( uint16_t ) NUM2UINT( code_r ); break; case 4: rb_scan_args( argc, argv, "04", &xid_r, &type_r, &code_r, &user_data ); if ( NUM2INT( xid_r ) < 0 ) { rb_raise( rb_eArgError, "Transaction ID must be >= 0" ); } if ( rb_obj_is_kind_of( user_data, rb_cString ) == Qfalse ) { rb_raise( rb_eArgError, "User data must be a string" ); } xid = ( uint32_t ) NUM2UINT( xid_r ); type = ( uint16_t ) NUM2UINT( type_r ); code = ( uint16_t ) NUM2UINT( code_r ); uint16_t length = ( u_int16_t ) RSTRING_LEN( user_data ); data = alloc_buffer_with_length( length ); void *p = append_back_buffer( data, length ); memcpy( p, RSTRING_PTR( user_data ), length ); break; default: type = OFPET_HELLO_FAILED; code = OFPHFC_INCOMPATIBLE; break; } buffer *error = create_error( xid, type, code, data ); if ( data != NULL ) { free_buffer( data ); } return Data_Wrap_Struct( klass, NULL, free_buffer, error ); }
static void send_echo_requests( uint64_t datapath_id, void *count ) { for ( int i = 0; i < *( ( int * ) count ); i++ ) { buffer *echo_request = create_echo_request( get_transaction_id(), NULL ); bool ret = send_openflow_message( datapath_id, echo_request ); if ( !ret ) { error( "Failed to send an echo request message to the switch with datapath ID = %#" PRIx64 ".", datapath_id ); } free_buffer( echo_request ); } }
static void send_hello( uint64_t datapath_id, void *count ) { for ( int i = 0; i < *( ( int * ) count ); i++ ) { buffer *hello = create_hello( get_transaction_id(), NULL ); bool ret = send_openflow_message( datapath_id, hello ); if ( !ret ) { error( "Failed to send an hello message to the switch with datapath ID = %#" PRIx64 ".", datapath_id ); } free_buffer( hello ); } }
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 ); }
static void send_features_request( uint64_t datapath_id, void *user_data ) { UNUSED( user_data ); buffer *features_request = create_features_request( get_transaction_id() ); bool ret = send_openflow_message( datapath_id, features_request ); if ( !ret ) { error( "Failed to send a features request message to the switch with datapath ID = %#" PRIx64 ".", datapath_id ); stop_trema(); } free_buffer( features_request ); }
/* * @overload initialize(options) * @example * Error.new( * :type => OFPET_BAD_REQUEST, * :code => OFPBRC_BAD_TYPE, * ) * Error.new( * :type => OFPET_BAD_REQUEST, * :code => OFPBRC_BAD_TYPE, * :transcation_id => 123 * ) * Error.new( * :type => OFPET_BAD_REQUEST, * :code => OFPBRC_BAD_TYPE, * :transcation_id => 123 * :data => "Error!!" * ) * @param [Hash] options * the options to create a message with. * @option options [Number] :type * a command or action that failed. * @option options [Number] :code * the reason of the failed type error. * @option options [String] :data * a more user friendly explanation of the error. Defaults to nil * if not specified. * @option options [Number] :xid * @option options [Number] :transaction_id * An unsigned 32bit integer number associated with this message. * If not specified, an auto-generated value is set. * @raise [ArgumentError] if transaction ID is not an unsigned 32bit integer. * @raise [ArgumentError] if type and code are not supplied. * @raise [ArgumentError] if user data is not a string. * @raise [TypeError] if options is not a hash. * @return [Error] */ static VALUE error_init( int argc, VALUE *argv, VALUE self ) { buffer *error = NULL; Data_Get_Struct( self, buffer, error ); VALUE options; if ( rb_scan_args( argc, argv, "01", &options ) == 1 ) { Check_Type( options, T_HASH ); VALUE tmp = Qnil; tmp = rb_hash_aref( options, ID2SYM( rb_intern( "type" ) ) ); if ( tmp != Qnil ) { ( ( struct ofp_error_msg * ) error->data )->type = htons( ( uint16_t ) NUM2UINT( tmp ) ); } else { rb_raise( rb_eArgError, "Type is a mandatory option" ); } tmp = rb_hash_aref( options, ID2SYM( rb_intern( "code" ) ) ); if ( tmp != Qnil ) { ( ( struct ofp_error_msg * ) error->data )->code = htons( ( uint16_t ) NUM2UINT( tmp ) ); } else { rb_raise( rb_eArgError, "Code is a mandatory option" ); } VALUE xid = Qnil; tmp = rb_hash_aref( options, ID2SYM( rb_intern( "transaction_id" ) ) ); if ( tmp != Qnil ) { xid = tmp; } tmp = rb_hash_aref( options, ID2SYM( rb_intern( "xid" ) ) ); if ( tmp != Qnil ) { xid = tmp; } if ( xid != Qnil ) { validate_xid( xid ); set_xid( error, ( uint32_t ) NUM2UINT( xid ) ); } else { set_xid( error, get_transaction_id() ); } VALUE data = rb_hash_aref( options, ID2SYM( rb_intern( "data" ) ) ); if ( data != Qnil ) { Check_Type( data, T_STRING ); uint16_t length = ( uint16_t ) RSTRING_LEN( data ); append_back_buffer( error, length ); ( ( struct ofp_header * ) ( error->data ) )->length = htons( ( uint16_t ) ( offsetof( struct ofp_error_msg, data ) + length ) ); memcpy( ( char * ) error->data + offsetof( struct ofp_error_msg, data ), RSTRING_PTR( data ), length ); }
buffer * pack_experimenter_multipart_request( VALUE options ) { uint32_t xid = get_transaction_id(); VALUE r_xid = HASH_REF( options, transaction_id ); if ( !NIL_P( r_xid ) ) { xid = NUM2UINT( r_xid ); } uint16_t flags = 0; VALUE r_flags = HASH_REF( options, flags ); if ( !NIL_P( r_flags ) ) { flags = ( uint16_t ) NUM2UINT( r_flags ); } uint32_t experimenter = 0; VALUE r_experimenter = HASH_REF( options, experimenter ); if ( !NIL_P( r_experimenter ) ) { experimenter = NUM2UINT( r_experimenter ); } uint32_t exp_type = 0; VALUE r_exp_type = HASH_REF( options, exp_type ); if ( !NIL_P( r_exp_type ) ) { exp_type = NUM2UINT( r_exp_type ); } VALUE r_body = HASH_REF( options, user_data ); buffer *body = NULL; if ( !NIL_P( r_body ) ) { if ( TYPE( r_body ) == T_ARRAY ) { uint16_t buffer_len = ( uint16_t ) RARRAY_LEN( r_body ); body = alloc_buffer_with_length( ( size_t ) RARRAY_LEN( r_body ) ); append_back_buffer( body, buffer_len ); uint8_t *buf = body->data; for ( int i = 0; i < buffer_len && i < RARRAY_LEN( r_body ); i++ ) { buf[ i ]= ( uint8_t ) FIX2INT( rb_ary_entry( r_body , i ) ); } } else { rb_raise( rb_eTypeError, "experimenter user data must be specified as an array of bytes" ); } } buffer *experimenter_multipart_request = create_experimenter_multipart_request( xid, flags, experimenter, exp_type, body ); return experimenter_multipart_request; }