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 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->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; } // count elements uint32_t hop_count = count_hops( hops ); // send flow entry from tail switch for ( dlist_element *e = get_last_element( hops ); e != NULL; e = e->prev, hop_count-- ) { uint16_t idle_timer = ( uint16_t ) ( routing_switch->idle_timeout + hop_count ); modify_flow_entry( e->data, packet, idle_timer ); } // for(;;) // send packet out for tail switch dlist_element *e = get_last_element( hops ); pathresolver_hop *last_hop = e->data; output_packet_from_last_switch( last_hop, packet ); // free them free_hop_list( hops ); }
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, 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 = %#" PRIx32 ", " "buffer_id = %#" PRIx32 ", total_len = %u, in_port = %u, reason = %#x, " "data_len = %zu ).", 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 = %#" PRIx64 ", 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 discard_packet_in( datapath_id, in_port, data, DISCARD_DURATION_DENY ); return; } local: { // Redirect to controller's local IP stack redirect( datapath_id, in_port, data ); return; } }