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 make_path( sliceable_switch *sliceable_switch, uint64_t in_datapath_id, uint16_t in_port, uint16_t in_vid, uint64_t out_datapath_id, uint16_t out_port, uint16_t out_vid, const buffer *packet ) { dlist_element *hops = resolve_path( sliceable_switch->pathresolver, in_datapath_id, in_port, out_datapath_id, out_port ); if ( hops == NULL ) { warn( "No available path found ( %#" PRIx64 ":%u -> %#" PRIx64 ":%u ).", in_datapath_id, in_port, out_datapath_id, out_port ); discard_packet_in( in_datapath_id, in_port, packet ); return; } // check if the packet is ARP or not if ( sliceable_switch->handle_arp_with_packetout && packet_type_arp( packet ) ) { // send packet out for tail switch free_hop_list( hops ); output_packet( packet, out_datapath_id, out_port, out_vid ); return; } const uint32_t wildcards = 0; struct ofp_match match; set_match_from_packet( &match, in_port, wildcards, packet ); if ( lookup_path( in_datapath_id, match, PRIORITY ) != NULL ) { warn( "Duplicated path found." ); output_packet( packet, out_datapath_id, out_port, out_vid ); return; } const uint16_t hard_timeout = 0; path *p = create_path( match, PRIORITY, sliceable_switch->idle_timeout, hard_timeout ); assert( p != NULL ); for ( dlist_element *e = get_first_element( hops ); e != NULL; e = e->next ) { pathresolver_hop *rh = e->data; hop *h = create_hop( rh->dpid, rh->in_port_no, rh->out_port_no, NULL ); assert( h != NULL ); append_hop_to_path( p, h ); } // for(;;) dlist_element *e = get_last_element( hops ); pathresolver_hop *last_hop = e->data; packet_out_params *params = xmalloc( sizeof( struct packet_out_params ) ); params->packet = duplicate_buffer( packet ); params->out_datapath_id = last_hop->dpid; params->out_port_no = last_hop->out_port_no; params->out_vid = out_vid; bool ret = setup_path( p, handle_setup, params, NULL, NULL ); if ( ret != true ) { error( "Failed to set up path." ); output_packet( packet, out_datapath_id, out_port, out_vid ); free_buffer( params->packet ); xfree( params ); } delete_path( p ); // free them free_hop_list( hops ); }
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_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 make_path( routing_switch *routing_switch, uint64_t in_datapath_id, uint16_t in_port, uint64_t out_datapath_id, uint16_t out_port, const buffer *packet ) { dlist_element *hops = resolve_path( routing_switch->path_resolver, in_datapath_id, in_port, out_datapath_id, out_port ); if ( hops == NULL ) { warn( "No available path found ( %#" PRIx64 ":%u -> %#" PRIx64 ":%u ).", in_datapath_id, in_port, out_datapath_id, out_port ); discard_packet_in( in_datapath_id, in_port, packet ); return; } // ask path manager to install flow entries size_t length = offsetof( path_manager_path, hops ) + sizeof( path_manager_hop ) * count_hops( hops ); path_manager_path *path = xmalloc( length ); set_match_from_packet( &path->match, OFPP_NONE, 0, packet ); path->n_hops = count_hops( hops ); dlist_element *e = get_first_element( hops ); for( int i = 0; e != NULL; e = e->next, i++ ) { path_resolver_hop *hop = e->data; path->hops[ i ].datapath_id = hop->dpid; path->hops[ i ].in_port = hop->in_port_no; path->hops[ i ].out_port = hop->out_port_no; } send_message( PATH_SETUP_SERVICE_NAME, MESSENGER_PATH_SETUP_REQUEST, ( void * ) path, length ); xfree( path ); // send packet out to tail switch output_packet_from_last_switch( hops, packet ); // free hop list free_hop_list( hops ); }
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 ); }
/* * Creates a {Match} instance from packet_in's data, the method accepts an * additional list of symbols to wildcard set and ignore while matching flow entries. * * @overload match_from(message, *options) * * @example * def packet_in datapath_id, message * send_flow_mod( * datapath_id, * :match => Match.from( message, :dl_type, :nw_proto ), * :actions => Trema::ActionOutput.new( 2 ) * ) * end * * @param [PacketIn] message * the {PacketIn}'s message content. * * @param [optional, list] options * If supplied a comma-separated list of symbol ids indicating fields to be wildcarded. * * [:in_port] * the physical port number to wildcard. * * [:dl_src] * the source Ethernet address to wildcard. * * [:dl_dst] * the destination Ethernet address to wildcard. * * [:dl_vlan] * the IEEE 802.1q virtual VLAN tag to wildcard. * * [:dl_vlan_pcp] * the IEEE 802.1q priority code point to wildcard. * * [:dl_type] * the Ethernet protocol type to wildcard. * * [:nw_tos] * the IP ToS /DSCP field to wildcard. * * [:nw_proto] * the IP protocol type to wildcard. * * [:nw_src] * the IPv4 source address to wildcard. * * [:nw_dst] * the IPv4 destination address to wildcard. * * [:tp_src] * the source TCP/UDP port number to wildcard. * * [:tp_dst] * the destination TCP/UDP port number to wildcard. * * @return [Match] self * the modified or exact match from packet depending on whether the options * argument supplied or not. */ static VALUE match_from( int argc, VALUE *argv, VALUE self ) { VALUE message, obj, wildcard_id, options; struct ofp_match *match = NULL; packet_in *packet = NULL; uint32_t wildcards = 0; if ( rb_scan_args( argc, argv, "1*", &message, &options ) >= 1 ) { obj = rb_funcall( self, rb_intern( "new" ), 0 ); match = get_match( obj ); Data_Get_Struct( message, packet_in, packet ); int i; for ( i = 0; i < RARRAY_LEN( options ); i++ ) { wildcard_id = SYM2ID( RARRAY_PTR( options )[ i ] ); if ( rb_intern( "in_port" ) == wildcard_id ) { wildcards |= OFPFW_IN_PORT; } if ( rb_intern( "dl_src" ) == wildcard_id ) { wildcards |= OFPFW_DL_SRC; } if ( rb_intern( "dl_dst" ) == wildcard_id ) { wildcards |= OFPFW_DL_DST; } if ( rb_intern( "dl_vlan" ) == wildcard_id ) { wildcards |= OFPFW_DL_VLAN; } if ( rb_intern( "dl_vlan_pcp" ) == wildcard_id ) { wildcards |= OFPFW_DL_VLAN_PCP; } if ( rb_intern( "dl_type" ) == wildcard_id ) { wildcards |= OFPFW_DL_TYPE; } if ( rb_intern( "nw_tos" ) == wildcard_id ) { wildcards |= OFPFW_NW_TOS; } if ( rb_intern( "nw_proto" ) == wildcard_id ) { wildcards |= OFPFW_NW_PROTO; } if ( rb_intern( "nw_src" ) == wildcard_id ) { wildcards |= OFPFW_NW_SRC_ALL; } if ( rb_intern( "nw_dst" ) == wildcard_id ) { wildcards |= OFPFW_NW_DST_ALL; } if ( rb_intern( "tp_src" ) == wildcard_id ) { wildcards |= OFPFW_TP_SRC; } if ( rb_intern( "tp_dst" ) == wildcard_id ) { wildcards |= OFPFW_TP_DST; } } set_match_from_packet( match, packet->in_port, wildcards, packet->data ); } else { rb_raise( rb_eArgError, "Message is a mandatory option" ); } return obj; }
static VALUE match_from( VALUE klass, VALUE message ) { VALUE obj; struct ofp_match *match; packet_in *packet; obj = rb_funcall( klass, rb_intern( "new" ), 0 ); Data_Get_Struct( obj, struct ofp_match, match ); Data_Get_Struct( message, packet_in, packet ); set_match_from_packet( match, packet->in_port, 0, packet->data ); return obj; }
static void handle_packet_in( uint64_t datapath_id, uint32_t transaction_id, uint32_t buffer_id, uint16_t total_len, uint16_t in_port, uint8_t reason, const buffer *data, void *user_data ) { UNUSED( user_data ); char match_str[ 1024 ]; struct ofp_match ofp_match; // host order buffer *copy = NULL; packet_info *packet_info = data->user_data; debug( "Receive packet. ethertype=0x%04x, ipproto=0x%x", packet_info->eth_type, packet_info->ipv4_protocol ); if ( packet_type_ipv4_etherip( data ) ) { copy = parse_etherip( data ); } set_match_from_packet( &ofp_match, in_port, 0, copy != NULL ? copy : data ); if ( copy != NULL ) { free_buffer( copy ); copy = NULL; } match_to_string( &ofp_match, match_str, sizeof( match_str ) ); list_element *services = lookup_match_entry( ofp_match ); if ( services == NULL ) { debug( "match entry not found" ); return; } buffer *buf = create_packet_in( transaction_id, buffer_id, total_len, in_port, reason, data ); openflow_service_header_t *message; message = append_front_buffer( buf, sizeof( openflow_service_header_t ) ); message->datapath_id = htonll( datapath_id ); message->service_name_length = htons( 0 ); list_element *element; for ( element = services; element != NULL; element = element->next ) { const char *service_name = element->data; if ( !send_message( service_name, MESSENGER_OPENFLOW_MESSAGE, buf->data, buf->length ) ) { error( "Failed to send a message to %s ( match = %s ).", service_name, match_str ); free_buffer( buf ); return; } debug( "Sending a message to %s ( match = %s ).", service_name, match_str ); } free_buffer( buf ); }
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 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 handle_packet_in( uint64_t datapath_id, uint32_t transaction_id, uint32_t buffer_id, uint16_t total_len, uint16_t in_port, uint8_t reason, const buffer *data, void *user_data ) { UNUSED( user_data ); char match_str[ 1024 ]; struct ofp_match ofp_match; // host order set_match_from_packet( &ofp_match, in_port, 0, data ); match_to_string( &ofp_match, match_str, sizeof( match_str ) ); match_entry *match_entry = lookup_match_entry( &ofp_match ); if ( match_entry == NULL ) { debug( "No match entry found." ); return; } buffer *buf = create_packet_in( transaction_id, buffer_id, total_len, in_port, reason, data ); openflow_service_header_t *message; message = append_front_buffer( buf, sizeof( openflow_service_header_t ) ); message->datapath_id = htonll( datapath_id ); message->service_name_length = htons( 0 ); if ( !send_message( match_entry->service_name, MESSENGER_OPENFLOW_MESSAGE, buf->data, buf->length ) ) { error( "Failed to send a message to %s ( entry_name = %s, match = %s ).", match_entry->service_name, match_entry->entry_name, match_str ); free_buffer( buf ); return; } debug( "Sending a message to %s ( entry_name = %s, match = %s ).", match_entry->service_name, match_entry->entry_name, match_str ); free_buffer( buf ); }
static void modify_flow_entry( const pathresolver_hop *h, const buffer *original_packet, uint16_t idle_timeout ) { const uint32_t wildcards = 0; struct ofp_match match; set_match_from_packet( &match, h->in_port_no, wildcards, original_packet ); uint32_t transaction_id = get_transaction_id(); openflow_actions *actions = create_actions(); const uint16_t max_len = UINT16_MAX; append_action_output( actions, h->out_port_no, max_len ); const uint16_t hard_timeout = 0; const uint16_t priority = UINT16_MAX; const uint32_t buffer_id = UINT32_MAX; const uint16_t flags = 0; buffer *flow_mod = create_flow_mod( transaction_id, match, get_cookie(), OFPFC_ADD, idle_timeout, hard_timeout, priority, buffer_id, h->out_port_no, flags, actions ); send_openflow_message( h->dpid, flow_mod ); delete_actions( actions ); free_buffer( flow_mod ); }
static void handle_packet_in( uint64_t datapath_id, uint32_t transaction_id, uint32_t buffer_id, uint16_t total_len, uint16_t in_port, uint8_t reason, const buffer *data, void *user_data ) { assert( in_port != 0 ); assert( data != NULL ); assert( user_data != NULL ); sliceable_switch *sliceable_switch = user_data; debug( "Packet-In received ( datapath_id = %#" PRIx64 ", transaction_id = %#lx, " "buffer_id = %#lx, total_len = %u, in_port = %u, reason = %#x, " "data_len = %u ).", datapath_id, transaction_id, buffer_id, total_len, in_port, reason, data->length ); if ( in_port > OFPP_MAX && in_port != OFPP_LOCAL ) { error( "Packet-In from invalid port ( in_port = %u ).", in_port ); return; } const port_info *port = lookup_port( sliceable_switch->switches, datapath_id, in_port ); if ( port == NULL ) { debug( "Ignoring Packet-In from unknown port." ); return; } packet_info packet_info = get_packet_info( data ); const uint8_t *src = packet_info.eth_macsa; const uint8_t *dst = packet_info.eth_macda; if ( !port->external_link || port->switch_to_switch_reverse_link ) { if ( !port->external_link && port->switch_to_switch_link && port->switch_to_switch_reverse_link && !is_ether_multicast( dst ) && lookup_fdb( sliceable_switch->fdb, src, &datapath_id, &in_port ) ) { debug( "Found a Packet-In from switch-to-switch link." ); } else { debug( "Ignoring Packet-In from non-external link." ); return; } } uint16_t vid = VLAN_NONE; if ( packet_type_eth_vtag( data ) ) { vid = packet_info.vlan_vid; } if ( !update_fdb( sliceable_switch->fdb, src, datapath_id, in_port ) ) { return; } char match_str[ 1024 ]; struct ofp_match match; set_match_from_packet( &match, in_port, 0, data ); match_to_string( &match, match_str, sizeof( match_str ) ); uint16_t slice = lookup_slice( datapath_id, in_port, vid, src ); if ( slice == SLICE_NOT_FOUND ) { warn( "No slice found ( dpid = %#" PRIx64 ", vid = %u, match = [%s] ).", datapath_id, vid, match_str ); goto deny; } int action = filter( datapath_id, in_port, slice, data ); switch ( action ) { case ALLOW: debug( "Filter: ALLOW ( dpid = %#" PRIx64 ", slice = %#x, match = [%s] ).", datapath_id, slice, match_str ); goto allow; case DENY: debug( "Filter: DENY ( dpid = %#" PRIx64 ", slice = %#x, match = [%s] ).", datapath_id, slice, match_str ); goto deny; case LOCAL: debug( "Filter: LOCAL ( dpid = %#" PRIx64 ", slice = %#x, match = [%s] ).", datapath_id, slice, match_str ); goto local; default: error( "Undefined filter action ( action = %#x ).", action ); goto deny; } allow: { uint16_t out_port; uint64_t out_datapath_id; if ( lookup_fdb( sliceable_switch->fdb, dst, &out_datapath_id, &out_port ) ) { // Host is located, so resolve path and send flowmod if ( ( datapath_id == out_datapath_id ) && ( in_port == out_port ) ) { debug( "Input port and out port are the same ( datapath_id = %#llx, port = %u ).", datapath_id, in_port ); return; } uint16_t out_vid = vid; bool found = get_port_vid( slice, out_datapath_id, out_port, &out_vid ); if ( found == false ) { uint16_t out_slice = lookup_slice_by_mac( dst ); if ( out_slice != slice ) { debug( "Destination is on different slice ( slice = %#x, out_slice = %#x ).", slice, out_slice ); goto deny; } } make_path( sliceable_switch, datapath_id, in_port, vid, out_datapath_id, out_port, out_vid, data ); } else { if ( lookup_path( datapath_id, match, PRIORITY ) != NULL ) { teardown_path( datapath_id, match, PRIORITY ); } // Host's location is unknown, so flood packet flood_packet( datapath_id, in_port, slice, data, sliceable_switch->switches ); } return; } deny: { // Drop packets for a certain period buffer *flow_mod = create_flow_mod( transaction_id, match, get_cookie(), OFPFC_ADD, 0, FLOW_TIMER, UINT16_MAX, UINT32_MAX, OFPP_NONE, 0, NULL ); send_openflow_message( datapath_id, flow_mod ); free_buffer( flow_mod ); return; } local: { // Redirect to controller's local IP stack redirect( datapath_id, in_port, data ); return; } }