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 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 ); }
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 ); }
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 ); }
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 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 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 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 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 ); }
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; }
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 ); }
/* * @overload send_message(datapath_id, message) * Sends an OpenFlow message to the datapath. * * @example * send_message datapath_id, FeaturesRequest.new * * @param [Integer] datapath_id * the datapath to which a message is sent. * @param [Hello, EchoRequest, EchoReply, FeaturesRequest, SetConfig, GetConfigRequest, QueueGetConfigRequest, StatsRequest, BarrierRequest, PortMod, Vendor] message * the message to be sent. */ static VALUE controller_send_message( VALUE self, VALUE datapath_id, VALUE message ) { buffer *buf; Data_Get_Struct( message, buffer, buf ); send_openflow_message( NUM2ULL( datapath_id ), buf ); return self; }
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 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 ); }
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 ); }
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 ); }
static void send_flow_mod_discarding_all_packets( sw_entry *sw, uint16_t hard_timeout, uint16_t priority ) { struct ofp_match match; memset( &match, 0, sizeof( struct ofp_match ) ); match.wildcards = OFPFW_ALL; 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, NULL ); send_openflow_message( sw->datapath_id, flow_mod ); free_buffer( flow_mod ); debug( "Sent a flow_mod for discarding all packets received on %#" PRIx64 ".", sw->datapath_id ); }
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 ); }
static void delete_flows_of( uint64_t datapath_id, uint16_t port_no ) { struct ofp_match match; memset( &match, 0, sizeof( struct ofp_match ) ); match.wildcards = OFPFW_ALL; buffer *flow_mod = create_flow_mod( get_transaction_id(), match, get_cookie(), OFPFC_DELETE, 0, 0, 0, 0, port_no, 0, NULL ); send_openflow_message( datapath_id, flow_mod ); free_buffer( flow_mod ); memset( &match, 0, sizeof( struct ofp_match ) ); match.wildcards = OFPFW_ALL; match.wildcards &= ( uint32_t ) ~OFPFW_IN_PORT; match.in_port = port_no; teardown_path_by_match( match ); }
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 ); }
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 send_packet_out( uint64_t datapath_id, packet_in *message, uint16_t out_port ) { uint32_t buffer_id = message->buffer_id; uint16_t in_port = message->in_port; if ( datapath_id != message->datapath_id ) { buffer_id = UINT32_MAX; in_port = OFPP_NONE; } openflow_actions *actions = create_actions(); append_action_output( actions, out_port, UINT16_MAX ); const buffer *data = NULL; if ( buffer_id == UINT32_MAX ) { data = message->data; } buffer *packet_out = create_packet_out( get_transaction_id(), buffer_id, in_port, actions, data ); delete_actions( actions ); send_openflow_message( datapath_id, packet_out ); free_buffer( packet_out ); }
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 ); }
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 ); } }