Пример #1
0
void
send_etherframe_from_local_to_vxlan( struct vxlan_instance *instance,
                                     struct ether_header *ether, size_t len ) {
  assert( vxlan != NULL );
  assert( instance != NULL );
  assert( ether != NULL );
  assert( len > 0 );

  if ( !instance->activated || !vxlan->active ) {
    return;
  }

  struct vxlanhdr vhdr;
  memset( &vhdr, 0, sizeof( vhdr ) );
  vhdr.flags = VXLAN_VALIDFLAG;
  memcpy( vhdr.vni, instance->vni, VXLAN_VNISIZE );

  struct iovec iov[ 2 ];
  memset( iov, 0, sizeof( iov ) );
  iov[ 0 ].iov_base = &vhdr;
  iov[ 0 ].iov_len  = sizeof( vhdr );
  iov[ 1 ].iov_base = ether;
  iov[ 1 ].iov_len  = len;

  struct msghdr mhdr;
  memset( &mhdr, 0, sizeof( mhdr ) );
  mhdr.msg_iov = iov;
  mhdr.msg_iovlen = 2;
  mhdr.msg_controllen = 0;

  char buf[ 256 ];

  struct fdb_entry *entry = fdb_search_entry( instance->fdb, ether->ether_dhost );
  if ( entry == NULL ) {
    mhdr.msg_name = &instance->addr;
    mhdr.msg_namelen = sizeof( instance->addr );
    if ( sendmsg( instance->udp_sock, &mhdr, 0 ) < 0 ) {
      char *error_string = safe_strerror_r( errno, buf, sizeof( buf ) );
      warn( "Failed to send a vxlan message ( errno = %s [%d] ).", error_string, errno );
    }
  }
  else {
    entry->vtep_addr.sin_port = htons( instance->port );
    mhdr.msg_name = &entry->vtep_addr;
    mhdr.msg_namelen = sizeof( entry->vtep_addr );
    if ( sendmsg( instance->udp_sock, &mhdr, 0 ) < 0 ) {
      char *error_string = safe_strerror_r( errno, buf, sizeof( buf ) );
      warn( "Failed to send a vxlan message ( errno = %s [%d] ).", error_string, errno );
    }
  }
}
Пример #2
0
static bool
set_ipv4_multicast_leave( int socket, struct in_addr maddr, char *ifname ) {
  assert( ifname != NULL );

  if ( !IN_MULTICAST( ntohl( maddr.s_addr ) ) ) {
    return false;
  }

  unsigned int n_users = 0;
  delete_user_from_multicast_group( maddr, &n_users );
  if ( n_users > 0 ) {
    // Still used.
    return true;
  }

  struct ip_mreq mreq;
  memset( &mreq, 0, sizeof( mreq ) );
  mreq.imr_multiaddr = maddr;
  if ( !getifaddr( ifname, &mreq.imr_interface ) ) {
    return false;
  }

  int ret = setsockopt( socket, IPPROTO_IP, IP_DROP_MEMBERSHIP,
                        ( char * ) &mreq, sizeof( mreq ) );
  if ( ret < 0 ) {
    char buf[ 256 ];
    char *error_string = safe_strerror_r( errno, buf, sizeof( buf ) );
    error( "Failed to send a leave group ( socket = %d, ret = %d, errno = %s [%d] ).",
           socket, ret, error_string, errno );
    return false;
  }

  return true;
}
Пример #3
0
bool
set_device_flags( const char *name, short int flags ) {
    assert( name != NULL );

    int fd = socket( AF_INET, SOCK_DGRAM, 0 );

    struct ifreq ifr;
    memset( &ifr, 0, sizeof( ifr ) );
    strncpy( ifr.ifr_name, name, IFNAMSIZ );
    ifr.ifr_name[ IFNAMSIZ - 1 ] = '\0';

    ifr.ifr_flags = flags;
    int ret = ioctl( fd, SIOCSIFFLAGS, &ifr );
    if ( ret == -1 ) {
        char error_string[ ERROR_STRING_SIZE ];
        error( "Failed to set interface flags ( device = %s, flags = %#x, ret = %d, errno = %s [%d] ).",
               ifr.ifr_name, ifr.ifr_flags, ret, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno );
        close( fd );
        return false;
    }

    close( fd );

    return true;
}
Пример #4
0
static bool
set_ipv4_multicast_join_and_iface( int socket, struct in_addr maddr, char *ifname ) {
  assert( ifname != NULL );

  if ( !IN_MULTICAST( ntohl( maddr.s_addr ) ) ) {
    return false;
  }

  unsigned int n_users = 0;
  add_user_into_multicast_group( maddr, &n_users );
  if ( n_users > 1 ) {
    // Already joined.
    return true;
  }
  else if ( n_users != 1 ) {
    return false;
  }

  struct ip_mreq mreq;
  memset( &mreq, 0, sizeof( mreq ) );
  mreq.imr_multiaddr = maddr;
  if ( !getifaddr( ifname, &mreq.imr_interface ) ) {
    return false;
  }

  char buf[ 256 ];

  int ret = setsockopt( socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                        ( char * ) &mreq, sizeof( mreq ) );
  if ( ret < 0 ) {
    char *error_string = safe_strerror_r( errno, buf, sizeof( buf ) );
    error( "Failed to send a membership report ( socket = %d, ret = %d, errno = %s [%d] ).",
           socket, ret, error_string, errno );
    return false;
  }

  ret = setsockopt( socket, IPPROTO_IP, IP_MULTICAST_IF,
                    ( char * ) &mreq.imr_interface, sizeof( mreq.imr_interface ) );
  if ( ret < 0 ) {
    char *error_string = safe_strerror_r( errno, buf, sizeof( buf ) );
    error( "Failed to set a network interface ( socket = %d, ret = %d, errno = %s [%d] ).",
           socket, ret, error_string, errno );
    return false;
  }

  return true;
}
Пример #5
0
static void
receive_frame( int fd, void *user_data ) {
  UNUSED( fd );

  ether_device *device = user_data;
  assert( device != NULL );

  if ( !device->status.up ) {
    return;
  }

  if ( get_max_packet_buffers_length( device->recv_queue ) <= get_packet_buffers_length( device->recv_queue ) ) {
    warn( "Receive queue is full ( device = %s, usage = %u/%u ).", device->name,
          get_packet_buffers_length( device->recv_queue ), get_max_packet_buffers_length( device->recv_queue ) );
    return;
  }

  unsigned int count = 0;
  const unsigned int max_queue_length = get_max_packet_buffers_length( device->recv_queue );
  const unsigned int max_loop_count = max_queue_length < 256 ? max_queue_length : 256;
  while ( count < max_loop_count ) {
    buffer *frame = get_buffer_from_free_buffers( device->recv_queue );
    if ( frame == NULL ) {
      warn( "Failed to retrieve a receive buffer ( device = %s, queue usage = %u/%u ).", device->name,
            get_packet_buffers_length( device->recv_queue ), max_queue_length );
      frame = device->recv_buffer; // Use recv_buffer as a trash.
    }
    append_back_buffer( frame, device->mtu );

    ssize_t length = recv( device->fd, frame->data, frame->length, MSG_DONTWAIT );
    assert( length != 0 );
    if ( length < 0 ) {
      if ( frame != device->recv_buffer ) {
        mark_packet_buffer_as_used( device->recv_queue, frame );
      }
      if ( ( errno == EINTR ) || ( errno == EAGAIN ) || ( errno == EWOULDBLOCK ) || ( errno == ENETDOWN ) ) {
        break;
      }
      char error_string[ ERROR_STRING_SIZE ];
      error( "Receive error ( device = %s, errno = %s [%d] ).",
             device->name, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno );
      break;
    }
    if ( frame != device->recv_buffer ) {
      frame->length = ( size_t ) length;
      enqueue_packet_buffer( device->recv_queue, frame );
    }
    else {
      reset_buffer( frame );
    }
    count++;
  }

  handle_received_frames( device );
}
Пример #6
0
static void
flush_send_queue( int fd, void *user_data ) {
    UNUSED( fd );

    ether_device *device = user_data;
    assert( device != NULL );

    debug( "Flushing send queue ( device = %s, queue length = %u ).", device->name, get_packet_buffers_length( device->send_queue ) );

    set_writable_safe( device->fd, false );

    struct sockaddr_ll sll;
    memset( &sll, 0, sizeof( sll ) );
    sll.sll_ifindex = device->ifindex;

    int count = 0;
    buffer *buf = NULL;
    while ( ( buf = peek_packet_buffer( device->send_queue ) ) != NULL && count < 256 ) {
#if WITH_PCAP
        if( pcap_sendpacket( device->pcap, buf->data, ( int ) buf->length ) < 0 ) {
            error( "Failed to send a message to ethernet device ( device = %s, pcap_err = %s ).",
                   device->name, pcap_geterr( device->pcap ) );
        }
        size_t length = buf->length;
#else
        ssize_t length = sendto( device->fd, buf->data, buf->length, MSG_DONTWAIT, ( struct sockaddr * ) &sll, sizeof( sll ) );
        if ( length < 0 ) {
            if ( ( errno == EINTR ) || ( errno == EAGAIN ) || ( errno == EWOULDBLOCK ) ) {
                break;
            }
            char error_string[ ERROR_STRING_SIZE ];
            error( "Failed to send a message to ethernet device ( device = %s, errno = %s [%d] ).",
                   device->name, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno );
            return;
        }
#endif

        if ( ( size_t ) length < buf->length ) {
            remove_front_buffer( buf, ( size_t ) length );
            break;
        }

        buf = dequeue_packet_buffer( device->send_queue );
        mark_packet_buffer_as_used( device->send_queue, buf );
        count++;
    }
    if ( get_packet_buffers_length( device->send_queue ) > 0 ) {
        set_writable_safe( device->fd, true );
    }
}
Пример #7
0
bool
try_lock( pthread_mutex_t *mutex ) {
    assert( mutex != NULL );

    int ret = pthread_mutex_trylock( mutex );
    if ( ret != 0 ) {
        char error_string[ ERROR_STRING_SIZE ];
        error( "Failed to try lock mutex ( mutex = %p, ret = %s [%d] ).",
               mutex, safe_strerror_r( ret, error_string, sizeof( error_string ) ), ret );
        return false;
    }

    return true;
}
Пример #8
0
static void
enable_promiscuous( ether_device *device ) {
    int fd = socket( AF_INET, SOCK_DGRAM, 0 );
    if ( fd < 0 ) {
        char error_string[ ERROR_STRING_SIZE ];
        error( "Failed to open a socket ( ret = %d, errno = %s [%d] ).",
               fd, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno );
        return;
    }

    struct ifreq ifr;

    memset( &ifr, 0, sizeof( ifr ) );
    strncpy( ifr.ifr_name, device->name, IFNAMSIZ );
    ifr.ifr_name[ IFNAMSIZ - 1 ] = '\0';

    int ret = ioctl( fd, SIOCGIFFLAGS, &ifr );
    if ( ret == -1 ) {
        char error_string[ ERROR_STRING_SIZE ];
        error( "Failed to get interface flags ( device = %s, ret = %d, errno = %s [%d] ).",
               ifr.ifr_name, ret, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno );
        close( fd );
        return;
    }

    ifr.ifr_flags |= IFF_PROMISC;
    ret = ioctl( fd, SIOCSIFFLAGS, &ifr );
    if ( ret == -1 ) {
        char error_string[ ERROR_STRING_SIZE ];
        error( "Failed to set interface flags ( device = %s, flags = %#x, ret = %d, errno = %s [%d] ).",
               ifr.ifr_name, ifr.ifr_flags, ret, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno );
        close( fd );
        return;
    }

    close( fd );
}
Пример #9
0
static bool
set_ipv4_multicast_loop( int socket, int stat ) {
  assert( socket >= 0 );

  int ret = setsockopt( socket, IPPROTO_IP, IP_MULTICAST_LOOP,
                        ( char * ) &stat, sizeof( stat ) );
  if ( ret < 0 ) {
    char buf[ 256 ];
    char *error_string = safe_strerror_r( errno, buf, sizeof( buf ) );
    error( "Failed to turn off multicast loopback ( socket = %d, ret = %d, errno = %s [%d] ).",
           socket, ret, error_string, errno );
    return false;
  }

  return true;
}
Пример #10
0
static bool
set_ipv4_multicast_ttl( int socket, int ttl ) {
  assert( socket >= 0 );

  int ret = setsockopt( socket, IPPROTO_IP, IP_MULTICAST_TTL,
                        ( char * ) &ttl, sizeof( ttl ) );
  if ( ret < 0 ) {
    char buf[ 256 ];
    char *error_string = safe_strerror_r( errno, buf, sizeof( buf ) );
    error( "Failed to set TTL value to %d ( socket = %d, ret = %d, errno = %s [%d] ).",
           ttl, socket, ret, error_string, errno );
    return false;
  }

  return true;
}
Пример #11
0
bool
init_net( struct vxlan *_vxlan ) {
  assert( _vxlan != NULL );

  vxlan = _vxlan;

  vxlan->udp_sock = socket( AF_INET, SOCK_DGRAM, 0 );
  if ( vxlan->udp_sock < 0 ) {
    char buf[ 256 ];
    char *error_string = safe_strerror_r( errno, buf, sizeof( buf ) );
    error( "Failed to create a socket for IPv4 ( ret = %d, errno = %s [%d] ).",
           vxlan->udp_sock, error_string, errno );
    goto error;
  }

  bool ret = bind_ipv4_inaddrany( vxlan->udp_sock, vxlan->port );
  if ( !ret ) {
    goto error;
  }
  ret = set_ipv4_multicast_loop( vxlan->udp_sock, 0 );
  if ( !ret ) {
    goto error;
  }
  ret = set_ipv4_multicast_ttl( vxlan->udp_sock, VXLAN_MCAST_TTL );
  if ( !ret ) {
    goto error;
  }

  ret = update_interface_state();
  if ( !ret ) {
    goto error;
  }

  ret = init_multicast_group_table();
  if ( !ret ) {
    goto error;
  }

  return true;

error:
  if ( vxlan->udp_sock >= 0 ) {
    close( vxlan->udp_sock );
  }

  return false;
}
Пример #12
0
bool
init_mutex( pthread_mutex_t *mutex ) {
    assert( mutex != NULL );

    pthread_mutexattr_t attr;
    pthread_mutexattr_init( &attr );
    pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE_NP );

    int ret = pthread_mutex_init( mutex, &attr );
    if ( ret != 0 ) {
        char error_string[ ERROR_STRING_SIZE ];
        error( "Failed to initialize mutex ( mutex = %p, ret = %s [%d] ).",
               mutex, safe_strerror_r( ret, error_string, sizeof( error_string ) ), ret );
        return false;
    }

    return true;
}
Пример #13
0
void
send_etherframe_from_vxlan_to_local( struct vxlan_instance *instance,
                                     struct ether_header *ether, size_t len ) {
  assert( vxlan != NULL );
  assert( instance != NULL );
  assert( ether != NULL );
  assert( len > 0 );

  if ( !instance->activated || !vxlan->active ) {
    return;
  }

  ssize_t ret = write( instance->tap_sock, ether, len );
  if ( ret != ( ssize_t ) len ) {
    char buf[ 256 ];
    char *error_string = safe_strerror_r( errno, buf, sizeof( buf ) );
    warn( "Failed to write an Ethernet frame to a tap interface ( socket = %d, "
          "len = %u, ret = %d, errno = %s [%d] ).",
          instance->tap_sock, len, ret, error_string, errno );
  }
}
Пример #14
0
static bool
bind_ipv4_inaddrany( int socket, uint16_t port ) {
  assert( socket >= 0 );
  assert( port > 0 );

  struct sockaddr_in saddr_in;

  memset( &saddr_in, 0, sizeof( saddr_in ) );
  saddr_in.sin_family = AF_INET;
  saddr_in.sin_port = htons( port );
  saddr_in.sin_addr.s_addr = INADDR_ANY;

  int ret = bind( socket, ( struct sockaddr * ) &saddr_in, sizeof( saddr_in ) );
  if ( ret < 0 ) {
    char buf[ 256 ];
    char *error_string = safe_strerror_r( errno, buf, sizeof( buf ) );
    error( "Failed to bind a socket ( fd = %d, errno = %s [%d] ).",
           socket, error_string, errno );
    return false;
  }

  return true;
}
Пример #15
0
ether_device *
create_ether_device( const char *name, const size_t max_send_queue, const size_t max_recv_queue ) {
    assert( name != NULL );
    assert( strlen( name ) > 0 );
    assert( max_send_queue > 0 );
    assert( max_recv_queue > 0 );

    int nfd = socket( PF_INET, SOCK_DGRAM, 0 );
    if ( nfd < 0 ) {
        char error_string[ ERROR_STRING_SIZE ];
        error( "Failed to open a socket ( ret = %d, errno = %s [%d] ).",
               nfd, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno );
        return NULL;
    }

    struct ifreq ifr;
    memset( &ifr, 0, sizeof( ifr ) );
    strncpy( ifr.ifr_name, name, IFNAMSIZ );
    ifr.ifr_name[ IFNAMSIZ - 1 ] = '\0';
    int ret = ioctl( nfd, SIOCGIFINDEX, &ifr );
    if ( ret == -1 ) {
        char error_string[ ERROR_STRING_SIZE ];
        error( "Failed to retrieve an interface index of %s ( ret = %d, errno = %s [%d] ).",
               name, ret, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno );
        close( nfd );
        return NULL;
    }
    int ifindex = ifr.ifr_ifindex;

    ret = ioctl( nfd, SIOCGIFMTU, &ifr );
    if ( ret == -1 ) {
        char error_string[ ERROR_STRING_SIZE ];
        error( "Failed to retrieve MTU of %s ( ret = %d, errno = %s [%d] ).",
               name, ret, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno );
        close( nfd );
        return NULL;
    }
    int mtu = ifr.ifr_mtu;

    ret = ioctl( nfd, SIOCGIFHWADDR, &ifr );
    if ( ret == -1 ) {
        char error_string[ ERROR_STRING_SIZE ];
        error( "Failed to retrieve hardware address of %s ( ret = %d, error = %s [%d] ).",
               name, ret, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno );
        close( nfd );
        return NULL;
    }

    close( nfd );

    size_t device_mtu = ( size_t ) mtu + MAX_L2_HEADER_LENGTH;
#ifdef WITH_PCAP
    char errbuf[ PCAP_ERRBUF_SIZE ];
    pcap_t *handle = pcap_open_live( name, ( int ) device_mtu, 1, 100, errbuf );
    if( handle == NULL ) {
        error( "Failed to open %s ( %s ).", name, errbuf );
        return NULL;
    }
    if ( pcap_setnonblock( handle, 1, errbuf ) == -1 ) {
        warn( "Failed to setnonblock %s ( %s ).", name, errbuf );
    }
    int fd = pcap_get_selectable_fd( handle );
#else // WITH_PCAP
    int fd = socket( PF_PACKET, SOCK_RAW, htons( ETH_P_ALL ) );
    if ( fd < 0 ) {
        char error_string[ ERROR_STRING_SIZE ];
        error( "Failed to open a socket ( ret = %d, errno = %s [%d] ).",
               fd, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno );
        return NULL;
    }

    struct sockaddr_ll sll;
    memset( &sll, 0, sizeof( sll ) );
    sll.sll_family = AF_PACKET;
    sll.sll_protocol = htons( ETH_P_ALL );
    sll.sll_ifindex = ifindex;
    ret = bind( fd, ( struct sockaddr * ) &sll, sizeof( sll ) );
    if ( ret < 0 ) {
        char error_string[ ERROR_STRING_SIZE ];
        error( "Failed to bind ( fd = %d, ret = %d, errno = %s [%d] ).",
               fd, ret, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno );
        close( fd );
        return NULL;
    }

    int val = TPACKET_V2;
    ret = setsockopt( fd, SOL_PACKET, PACKET_VERSION, &val, sizeof( val ) );
    if ( ret < 0 ) {
        char error_string[ ERROR_STRING_SIZE ];
        error( "Failed to set PACKET_VERSION to %d ( fd = %d, ret = %d, errno = %s [%d] ).",
               val, fd, ret, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno );
        close( fd );
        return NULL;
    }

    val = 1;
    ret = setsockopt( fd, SOL_PACKET, PACKET_AUXDATA, &val, sizeof( val ) );
    if ( ret < 0 ) {
        char error_string[ ERROR_STRING_SIZE ];
        error( "Failed to set PACKET_AUXDATA to %d ( fd = %d, ret = %d, errno = %s [%d] ).",
               val, fd, ret, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno );
        close( fd );
        return NULL;
    }

    while ( 1 ) {
        char buf;
        ssize_t length = recv( fd, &buf, 1, MSG_DONTWAIT );
        if ( length <= 0 ) {
            break;
        }
    }
#endif // WITH_PCAP

    ether_device *device = xmalloc( sizeof( ether_device ) );
    memset( device, 0, sizeof( ether_device ) );
    strncpy( device->name, name, IFNAMSIZ );
    device->name[ IFNAMSIZ - 1 ] = '\0';
#if WITH_PCAP
    device->pcap = handle;
#endif
    device->fd = fd;
    device->ifindex = ifindex;
    memcpy( device->hw_addr, ifr.ifr_hwaddr.sa_data, ETH_ADDRLEN );
    device->status.can_retrieve_link_status = true;
    device->status.can_retrieve_pause = true;
    device->mtu = device_mtu;
    device->recv_buffer = alloc_buffer_with_length( device->mtu );
    device->send_queue = create_packet_buffers( ( unsigned int ) max_send_queue, device->mtu );
    device->recv_queue = create_packet_buffers( ( unsigned int ) max_recv_queue, device->mtu );

    short int flags = get_device_flags( device->name );
    device->original_flags = flags;

    set_fd_handler_safe( fd, receive_frame, device, flush_send_queue, device );
    set_readable_safe( fd, true );

    enable_promiscuous( device );
    up_ether_device( device );
    update_device_status( device );

    time_now( &device->created_at );

    return device;
}
Пример #16
0
void *
receiver_main( void *args ) {
  assert( args != NULL );

  info( "Receiver thread is started ( pid = %u, tid = %u).",
        getpid(), receiver_thread );

  receiver_options *options = args;
  ethdev *dev = options->dev;
  assert( dev->fd >= 0 );
  packet_buffer trash;

  while ( running ) {
    notify_distributor();

    fd_set fds;
    FD_ZERO( &fds );
    FD_SET( dev->fd, &fds );
    struct timespec timeout = { 0, 1000000 };
    int ret = pselect( dev->fd + 1, &fds, NULL, NULL, &timeout, NULL );
    if ( ret < 0 ) {
      if ( errno == EINTR ) {
        continue;
      }
      char buf[ 256 ];
      char *error_string = safe_strerror_r( errno, buf, sizeof( buf ) );
      error( "Failed to select ( errno = %s [%d] ).", error_string, errno );
      break;
    }
    else if ( ret == 0 ) {
      continue;
    }

    if ( !FD_ISSET( dev->fd, &fds ) ) {
      continue;
    }

    packet_buffer *packet = peek( free_packet_buffers );
    if ( packet == NULL ) {
      // TODO: implement a counter to remember # of packet losses
      packet = &trash;
    }
    int err = 0;
    ssize_t length = recv_from_ethdev( dev, packet->data, sizeof( packet->data ), &err );
    if ( packet == &trash ) {
      continue;
    }

    if ( length < ( sizeof( struct iphdr ) + sizeof( struct udphdr ) + sizeof( struct vxlanhdr ) ) ||
         length > PACKET_SIZE ) {
      continue;
    }

    packet->ip = ( struct iphdr * ) packet->data;
    if ( packet->ip->protocol != IPPROTO_UDP ) {
      continue;
    }
    packet->udp = ( struct udphdr * ) ( ( char * ) packet->ip + ( packet->ip->ihl * 4 ) );

    if ( ntohs( packet->udp->dest ) != options->port ) {
      continue;
    }
    packet->vxlan = ( struct vxlanhdr * ) ( ( char * ) packet->udp + sizeof( struct udphdr ) );
    packet->length = ( size_t ) length;

    dequeue( free_packet_buffers );
    enqueue( received_packets, packet );
  }

  running = false;

  info( "Receiver thread is terminated ( pid = %u, tid = %u ).",
        getpid(), receiver_thread );

  free( options );

  return NULL;
}
Пример #17
0
static void
receive_frame( int fd, void *user_data ) {
    UNUSED( fd );

    ether_device *device = user_data;
    assert( device != NULL );

    if ( !device->status.up ) {
        return;
    }

    if ( get_max_packet_buffers_length( device->recv_queue ) <= get_packet_buffers_length( device->recv_queue ) ) {
        warn( "Receive queue is full ( device = %s, usage = %u/%u ).", device->name,
              get_packet_buffers_length( device->recv_queue ), get_max_packet_buffers_length( device->recv_queue ) );
        return;
    }

    unsigned int count = 0;
    const unsigned int max_queue_length = get_max_packet_buffers_length( device->recv_queue );
    const unsigned int max_loop_count = max_queue_length < 256 ? max_queue_length : 256;
    while ( count < max_loop_count ) {
        buffer *frame = get_buffer_from_free_buffers( device->recv_queue );
        if ( frame == NULL ) {
            warn( "Failed to retrieve a receive buffer ( device = %s, queue usage = %u/%u ).", device->name,
                  get_packet_buffers_length( device->recv_queue ), max_queue_length );
            frame = device->recv_buffer; // Use recv_buffer as a trash.
        }
        reset_buffer( frame );
        append_back_buffer( frame, device->mtu );

#if WITH_PCAP
        size_t length = 0;
        struct pcap_pkthdr *header = NULL;
        const u_char *packet = NULL;
        int ret = pcap_next_ex( device->pcap, &header, &packet );
        if ( ret == 1 ) {
            length = header->caplen;
            if ( length > frame->length ) {
                append_back_buffer( frame, length - frame->length );
            }
            memcpy( frame->data, packet, length );
        }
        else {
            if ( frame != device->recv_buffer ) {
                mark_packet_buffer_as_used( device->recv_queue, frame );
            }
            if ( ret == -1 ) {
                error( "Receive error ( device = %s, pcap_err = %s ).",
                       device->name, pcap_geterr( device->pcap ) );
            }
            break;
        }
#else // WITH_PCAP
        struct msghdr msg;
        msg.msg_name = NULL;
        msg.msg_namelen = 0;

        struct iovec iovec;
        size_t headroom_length = sizeof( vlantag_header_t );
        char *head = ( char * ) frame->data + headroom_length;
        iovec.iov_base = head;
        iovec.iov_len = frame->length - headroom_length;
        msg.msg_iov = &iovec;
        msg.msg_iovlen = 1;

        char cmsg_buf[ CMSG_SPACE( sizeof( struct tpacket_auxdata ) ) ];
        msg.msg_control = cmsg_buf;
        msg.msg_controllen = sizeof( cmsg_buf );
        msg.msg_flags = 0;

        ssize_t length = recvmsg( device->fd, &msg, MSG_DONTWAIT );
        assert( length != 0 );
        if ( length < 0 ) {
            if ( frame != device->recv_buffer ) {
                mark_packet_buffer_as_used( device->recv_queue, frame );
            }
            if ( ( errno == EINTR ) || ( errno == EAGAIN ) || ( errno == EWOULDBLOCK ) || ( errno == ENETDOWN ) ) {
                break;
            }
            char error_string[ ERROR_STRING_SIZE ];
            error( "Receive error ( device = %s, errno = %s [%d] ).",
                   device->name, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno );
            break;
        }

        for ( struct cmsghdr *cmsg = CMSG_FIRSTHDR( &msg ); cmsg != NULL; cmsg = CMSG_NXTHDR( &msg, cmsg ) ) {
            if ( cmsg->cmsg_len < CMSG_LEN( sizeof( struct tpacket_auxdata ) ) ) {
                continue;
            }
            if ( cmsg->cmsg_level != SOL_PACKET || cmsg->cmsg_type != PACKET_AUXDATA ) {
                continue;
            }
            struct tpacket_auxdata *auxdata = ( struct tpacket_auxdata * ) CMSG_DATA( cmsg );
            if ( auxdata->tp_vlan_tci == 0 ) {
                continue;
            }
            head -= sizeof( vlantag_header_t );
            if ( ( void * ) head < frame->data ) {
                append_front_buffer( frame, sizeof( vlantag_header_t ) );
                head = frame->data;
            }
            length += ( ssize_t ) sizeof( vlantag_header_t );
            memmove( head, head + sizeof( vlantag_header_t ), ETH_ADDRLEN * 2 );
            uint16_t *eth_type = ( uint16_t * ) ( head + ETH_ADDRLEN * 2 );
            *eth_type = htons( ETH_ETHTYPE_TPID );
            uint16_t *tci = ++eth_type;
            *tci = htons( auxdata->tp_vlan_tci );
        }
        frame->data = head;
#endif
        if ( frame != device->recv_buffer ) {
            frame->length = ( size_t ) length;
            enqueue_packet_buffer( device->recv_queue, frame );
        }
        count++;
    }

    handle_received_frames( device );
}
Пример #18
0
bool
update_device_status( ether_device *device ) {
    assert( device != NULL );
    assert( strlen( device->name ) > 0 );

    int fd = socket( PF_INET, SOCK_DGRAM, 0 );
    if ( fd < 0 ) {
        char error_string[ ERROR_STRING_SIZE ];
        error( "Failed to open a socket ( ret = %d, errno = %s [%d] ).",
               fd, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno );
        return false;
    }

    struct ifreq ifr;
    memset( &ifr, 0, sizeof( ifr ) );
    strncpy( ifr.ifr_name, device->name, IFNAMSIZ );
    ifr.ifr_name[ IFNAMSIZ - 1 ] = '\0';

    struct ethtool_value ev;
    memset( &ev, 0, sizeof( struct ethtool_value ) );
    ev.cmd = ETHTOOL_GLINK;
    ifr.ifr_data = ( char * ) &ev;
    int ret = ioctl( fd, SIOCETHTOOL, &ifr );
    if ( ret == -1 ) {
        char error_string[ ERROR_STRING_SIZE ];
        error( "Failed to retrieve link status of %s ( ret = %d, error = %s [%d] ).",
               device->name, ret, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno );
        warn( "Assuming link is up ( device = %s ).", device->name );
        device->status.up = true;
    } else {
        if ( ev.data > 0 ) {
            device->status.up = true;
        } else {
            device->status.up = false;
        }
    }

    struct ethtool_cmd ec;
    memset( &ec, 0, sizeof( struct ethtool_cmd ) );
    if ( device->status.can_retrieve_link_status ) {
        ec.cmd = ETHTOOL_GSET;
        ifr.ifr_data = ( char * ) &ec;
        ret = ioctl( fd, SIOCETHTOOL, &ifr );
        if ( ret == -1 ) {
            char error_string[ ERROR_STRING_SIZE ];
            warn( "Failed to retrieve statuses of %s ( ret = %d, error = %s [%d] ).",
                  device->name, ret, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno );
            warn( "Assuming 100Mbps/Full Duplex/Twisted Pair link ( device = %s ).", device->name );
            device->status.can_retrieve_link_status = false;
        }
    }
    if ( !device->status.can_retrieve_link_status ) {
        ethtool_cmd_speed_set( &ec, SPEED_100 );
        ec.duplex = DUPLEX_FULL;
        ec.port = PORT_TP;
        ec.advertising = ADVERTISED_100baseT_Full | ADVERTISED_TP;
        ec.supported = SUPPORTED_100baseT_Full | SUPPORTED_TP;
    }

    struct ethtool_pauseparam ep;
    memset( &ep, 0, sizeof( struct ethtool_pauseparam ) );
    if ( device->status.can_retrieve_pause ) {
        ep.cmd = ETHTOOL_GPAUSEPARAM;
        ifr.ifr_data = ( char * ) &ep;
        ret = ioctl( fd, SIOCETHTOOL, &ifr );
        if ( ret == -1 ) {
            char error_string[ ERROR_STRING_SIZE ];
            warn( "Failed to retrieve pause parameters of %s ( ret = %d, error = %s [%d] ).",
                  device->name, ret, safe_strerror_r( errno, error_string, sizeof( error_string ) ), errno );
            warn( "Assuming pause is disabled ( device = %s ).", device->name );
            device->status.can_retrieve_pause = false;
        }
    }

    close( fd );

    device->status.curr = make_current_ofp_port_features( ethtool_cmd_speed( &ec ), ec.duplex, ec.port,
                          ec.autoneg, ep.rx_pause, ep.tx_pause );
    device->status.advertised = make_supported_ofp_port_features( ec.advertising );
    device->status.supported = make_supported_ofp_port_features( ec.supported );
    device->status.peer = device->status.curr; // FIMXE: how to know the correct value?
    device->status.curr_speed = 0; // Since we set curr flags, this field might be meaningless.
    device->status.max_speed = 0; // Since we set supported flags, this field might be meaningless.

    return true;
}