Example #1
0
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 );
}
Example #3
0
File: switch.c Project: iqm/apps
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;
  }
}