mirror of
https://github.com/scylladb/scylladb.git
synced 2026-04-23 10:00:35 +00:00
Instead of forward() deciding packet destination make it collect input for RSS hash function depending on packet type. After data is collected use toeplitz hash function to calculate packet's destination.
130 lines
3.5 KiB
C++
130 lines
3.5 KiB
C++
/*
|
|
* Copyright (C) 2014 Cloudius Systems, Ltd.
|
|
*/
|
|
|
|
#include "tcp.hh"
|
|
#include "tcp-stack.hh"
|
|
#include "ip.hh"
|
|
#include "core/align.hh"
|
|
#include "native-stack-impl.hh"
|
|
|
|
namespace net {
|
|
|
|
void tcp_option::parse(uint8_t* beg, uint8_t* end) {
|
|
while (beg < end) {
|
|
auto kind = option_kind(*beg);
|
|
if (kind != option_kind::nop && kind != option_kind::eol) {
|
|
// Make sure there is enough room for this option
|
|
auto len = *(beg + 1);
|
|
if (beg + len > end) {
|
|
return;
|
|
}
|
|
}
|
|
switch (kind) {
|
|
case option_kind::mss:
|
|
_mss_received = true;
|
|
_remote_mss = ntoh(reinterpret_cast<mss*>(beg)->mss);
|
|
beg += option_len::mss;
|
|
break;
|
|
case option_kind::win_scale:
|
|
_win_scale_received = true;
|
|
_remote_win_scale = reinterpret_cast<win_scale*>(beg)->shift;
|
|
// We can turn on win_scale option, 7 is Linux's default win scale size
|
|
_local_win_scale = 7;
|
|
beg += option_len::win_scale;
|
|
break;
|
|
case option_kind::sack:
|
|
_sack_received = true;
|
|
beg += option_len::sack;
|
|
break;
|
|
case option_kind::nop:
|
|
beg += option_len::nop;
|
|
break;
|
|
case option_kind::eol:
|
|
return;
|
|
default:
|
|
// Ignore options we do not understand
|
|
auto len = *(beg + 1);
|
|
beg += len;
|
|
// Prevent infinite loop
|
|
if (len == 0) {
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint8_t tcp_option::fill(tcp_hdr* th, uint8_t options_size) {
|
|
auto hdr = reinterpret_cast<uint8_t*>(th);
|
|
auto off = hdr + sizeof(tcp_hdr);
|
|
uint8_t size = 0;
|
|
|
|
if (th->f_syn) {
|
|
if (_mss_received || !th->f_ack) {
|
|
auto mss = new (off) tcp_option::mss;
|
|
mss->mss = _local_mss;
|
|
off += mss->len;
|
|
size += mss->len;
|
|
*mss = hton(*mss);
|
|
}
|
|
if (_win_scale_received || !th->f_ack) {
|
|
auto win_scale = new (off) tcp_option::win_scale;
|
|
win_scale->shift = _local_win_scale;
|
|
off += win_scale->len;
|
|
size += win_scale->len;
|
|
}
|
|
}
|
|
if (size > 0) {
|
|
// Insert NOP option
|
|
auto size_max = align_up(uint8_t(size + 1), tcp_option::align);
|
|
while (size < size_max - uint8_t(option_len::eol)) {
|
|
new (off) tcp_option::nop;
|
|
off += option_len::nop;
|
|
size += option_len::nop;
|
|
}
|
|
new (off) tcp_option::eol;
|
|
size += option_len::eol;
|
|
}
|
|
assert(size == options_size);
|
|
|
|
return size;
|
|
}
|
|
|
|
uint8_t tcp_option::get_size() {
|
|
uint8_t size = 0;
|
|
if (_mss_received)
|
|
size += option_len::mss;
|
|
if (_win_scale_received)
|
|
size += option_len::win_scale;
|
|
size += option_len::eol;
|
|
// Insert NOP option to align on 32-bit
|
|
size = align_up(size, tcp_option::align);
|
|
return size;
|
|
}
|
|
|
|
ipv4_tcp::ipv4_tcp(ipv4& inet)
|
|
: _inet_l4(inet), _tcp(std::make_unique<tcp<ipv4_traits>>(_inet_l4)) {
|
|
}
|
|
|
|
ipv4_tcp::~ipv4_tcp() {
|
|
}
|
|
|
|
void ipv4_tcp::received(packet p, ipv4_address from, ipv4_address to) {
|
|
_tcp->received(std::move(p), from, to);
|
|
}
|
|
|
|
bool ipv4_tcp::forward(forward_hash& out_hash_data, packet& p, size_t off) {
|
|
|
|
return _tcp->forward(out_hash_data, p, off);
|
|
}
|
|
|
|
server_socket
|
|
tcpv4_listen(tcp<ipv4_traits>& tcpv4, uint16_t port, listen_options opts) {
|
|
return server_socket(std::make_unique<native_server_socket_impl<tcp<ipv4_traits>>>(
|
|
tcpv4, port, opts));
|
|
}
|
|
|
|
}
|
|
|