Files
scylladb/net/tcp.cc
Gleb Natapov 7ac3ba901c net: rework packet forwarding logic
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.
2014-12-16 10:53:41 +02:00

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));
}
}