Beispiel #1
0
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 );
}
Beispiel #4
0
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 );
}
Beispiel #5
0
Datei: switch.c Projekt: 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 );
}
Beispiel #6
0
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 );
}
Beispiel #7
0
/*
 * 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;
}
Beispiel #8
0
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;
}
Beispiel #9
0
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 );
}
Beispiel #11
0
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 );
}
Beispiel #12
0
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 );
}
Beispiel #13
0
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 );
}
Beispiel #14
0
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;
  }
}