added rtt and rtt deviation calculation for the tcp layer
This commit is contained in:
@@ -223,8 +223,10 @@ static void arp_translation_table_seconds_passed(arp_translation_table_t *table,
|
||||
}
|
||||
}
|
||||
|
||||
void arp_seconds_passed(arp_state_t *state, size_t seconds)
|
||||
void arp_ms_passed(arp_state_t *state, size_t ms)
|
||||
{
|
||||
size_t seconds = ms / 1000;
|
||||
|
||||
state->time += seconds;
|
||||
|
||||
// Scan through all of the timed-out entries
|
||||
|
||||
@@ -124,5 +124,5 @@ void arp_resolve_mac(arp_state_t *state,
|
||||
void *userp,
|
||||
void (*callback)(void*, arp_resolution_status_t, mac_address_t));
|
||||
|
||||
void arp_seconds_passed(arp_state_t *state, size_t seconds);
|
||||
void arp_ms_passed(arp_state_t *state, size_t ms);
|
||||
void arp_change_output_buffer(arp_state_t *state, void *ptr, size_t max);
|
||||
@@ -22,5 +22,6 @@ typedef struct {
|
||||
|
||||
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
|
||||
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
|
||||
#define ABS(X) ((X) < 0 ? -(X) : (X))
|
||||
|
||||
#endif /* MICROTCP_DEFS_H */
|
||||
@@ -29,7 +29,6 @@ static uint16_t calculate_checksum_ip(const void *src, size_t len)
|
||||
return cpu_to_net_u16(~sum);
|
||||
}
|
||||
|
||||
|
||||
static ip_plugged_protocol_t *
|
||||
find_protocol_with_id(ip_state_t *ip_state, uint8_t protocol)
|
||||
{
|
||||
@@ -125,10 +124,10 @@ void ip_change_output_buffer(ip_state_t *state, void *ptr, size_t max)
|
||||
icmp_change_output_buffer(&state->icmp_state, (ip_packet_t*) ptr + 1, max - sizeof(ip_packet_t));
|
||||
}
|
||||
|
||||
void ip_seconds_passed(ip_state_t *state, size_t seconds)
|
||||
void ip_ms_passed(ip_state_t *state, size_t ms)
|
||||
{
|
||||
(void) state;
|
||||
(void) seconds;
|
||||
(void) ms;
|
||||
}
|
||||
|
||||
int ip_send(ip_state_t *state, ip_protocol_t protocol,
|
||||
|
||||
@@ -54,7 +54,7 @@ typedef struct {
|
||||
ip_plugged_protocol_t plugged_protocols[IP_PLUGGED_PROTOCOLS_MAX];
|
||||
} ip_state_t;
|
||||
|
||||
void ip_seconds_passed(ip_state_t *state, size_t seconds);
|
||||
void ip_ms_passed(ip_state_t *state, size_t ms);
|
||||
void ip_change_output_buffer(ip_state_t *state, void *ptr, size_t max);
|
||||
void ip_init(ip_state_t *state, ip_address_t ip, void *send_data, void (*send)(void*, ip_address_t, size_t));
|
||||
void ip_free(ip_state_t *state);
|
||||
|
||||
+18
-9
@@ -105,7 +105,7 @@ struct microtcp_socket_t {
|
||||
|
||||
struct microtcp_t {
|
||||
|
||||
time_t last_update_time;
|
||||
uint64_t last_update_time_ms;
|
||||
|
||||
#ifdef MICROTCP_BACKGROUND_THREAD
|
||||
bool thread_should_stop;
|
||||
@@ -396,6 +396,13 @@ void microtcp_process_packet(microtcp_t *mtcp, const void *packet, size_t len)
|
||||
UNLOCK_WHEN_THREADED(mtcp);
|
||||
}
|
||||
|
||||
static uint64_t get_time_in_ms(void)
|
||||
{
|
||||
struct timespec t;
|
||||
clock_gettime(CLOCK_MONOTONIC, &t);
|
||||
return t.tv_sec * 1000 + t.tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
void microtcp_step(microtcp_t *mtcp)
|
||||
{
|
||||
char packet[1024]; // This buffer is the bottleneck for the
|
||||
@@ -408,18 +415,20 @@ void microtcp_step(microtcp_t *mtcp)
|
||||
if (size < 0)
|
||||
return;
|
||||
|
||||
uint64_t current_time_ms = get_time_in_ms();
|
||||
fprintf(stderr, "current_time_ms=%lld\n", current_time_ms);
|
||||
|
||||
LOCK_WHEN_THREADED(mtcp);
|
||||
{
|
||||
process_packet(mtcp, packet, size);
|
||||
|
||||
time_t current_time = time(NULL);
|
||||
int secs = (float) (current_time - mtcp->last_update_time);
|
||||
uint64_t ms = (current_time_ms - mtcp->last_update_time_ms);
|
||||
|
||||
if (secs > 0) {
|
||||
ip_seconds_passed(&mtcp->ip_state, secs);
|
||||
arp_seconds_passed(&mtcp->arp_state, secs);
|
||||
tcp_seconds_passed(&mtcp->tcp_state, secs);
|
||||
mtcp->last_update_time = current_time;
|
||||
if (ms > 0) {
|
||||
ip_ms_passed(&mtcp->ip_state, ms);
|
||||
arp_ms_passed(&mtcp->arp_state, ms);
|
||||
tcp_ms_passed(&mtcp->tcp_state, ms);
|
||||
mtcp->last_update_time_ms = current_time_ms;
|
||||
}
|
||||
}
|
||||
UNLOCK_WHEN_THREADED(mtcp);
|
||||
@@ -458,7 +467,7 @@ microtcp_t *microtcp_create_using_callbacks(const char *ip, const char *mac,
|
||||
mtcp->ip = parsed_ip;
|
||||
mtcp->mac = parsed_mac;
|
||||
mtcp->callbacks = callbacks;
|
||||
mtcp->last_update_time = time(NULL);
|
||||
mtcp->last_update_time_ms = get_time_in_ms();
|
||||
|
||||
mtcp->used_buffer = NULL;
|
||||
mtcp->wait_buffer_list = NULL;
|
||||
|
||||
@@ -42,9 +42,9 @@ void tcp_free(tcp_state_t *state)
|
||||
tcp_timerset_free(&state->timers);
|
||||
}
|
||||
|
||||
void tcp_seconds_passed(tcp_state_t *state, size_t seconds)
|
||||
void tcp_ms_passed(tcp_state_t *state, size_t ms)
|
||||
{
|
||||
tcp_timerset_step(&state->timers, seconds);
|
||||
tcp_timerset_step(&state->timers, ms);
|
||||
}
|
||||
|
||||
static tcp_connection_t*
|
||||
@@ -74,6 +74,13 @@ connection_create(tcp_listener_t *listener,
|
||||
|
||||
connection->state = TCP_STATE_CLOSED;
|
||||
|
||||
connection->rtt = 0;
|
||||
connection->dev_rtt = 0;
|
||||
|
||||
connection->calculating_rtt = false;
|
||||
connection->rtt_calc_seq = 0;
|
||||
connection->rtt_calc_time = 0;
|
||||
|
||||
connection->peer_port = peer_port;
|
||||
connection->peer_ip = peer_ip;
|
||||
|
||||
@@ -110,7 +117,7 @@ find_listener_with_port(tcp_state_t *state, uint16_t port)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint32_t choose_sequence_no()
|
||||
static uint32_t choose_sequence_no(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -222,6 +229,11 @@ static void emit_segment(tcp_connection_t *connection, uint8_t flags, size_t pay
|
||||
}
|
||||
}
|
||||
|
||||
if (!connection->calculating_rtt) {
|
||||
connection->calculating_rtt = true;
|
||||
connection->rtt_calc_seq = connection->snd_nxt; // -1?
|
||||
connection->rtt_calc_time = connection->listener->state->timers.current_time_ms;
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_received_data(tcp_connection_t *connection,
|
||||
@@ -331,10 +343,30 @@ static bool ack_until(tcp_connection_t *connection, uint32_t ack_no)
|
||||
}
|
||||
|
||||
size_t newly_acked_bytes = ack_no - connection->snd_una;
|
||||
memmove(connection->out_buffer, connection->out_buffer + newly_acked_bytes, connection->snd_wnd - newly_acked_bytes);
|
||||
connection->snd_wnd -= newly_acked_bytes;
|
||||
|
||||
if (ack_no > 1) { // Only remove data from the output buffer when
|
||||
// the acked data wasn't a ghost byte
|
||||
memmove(connection->out_buffer, connection->out_buffer + newly_acked_bytes, connection->snd_wnd - newly_acked_bytes);
|
||||
connection->snd_wnd -= newly_acked_bytes;
|
||||
}
|
||||
connection->snd_una = ack_no;
|
||||
|
||||
TCP_DEBUG_LOG("calculating_rtt=%s, ack_no=%d, calc_seq=%d", connection->calculating_rtt ? "true" : "false", ack_no, connection->rtt_calc_seq);
|
||||
if (connection->calculating_rtt) {
|
||||
if (ack_no >= connection->rtt_calc_seq) {
|
||||
|
||||
uint64_t rtt = connection->listener->state->timers.current_time_ms - connection->rtt_calc_time;
|
||||
TCP_DEBUG_LOG("Estimated RTT=%lld", rtt);
|
||||
|
||||
float w1 = 0.9;
|
||||
float w2 = 0.125;
|
||||
connection->rtt = w1 * rtt + (1-w1) * connection->rtt;
|
||||
connection->dev_rtt = w2 * ABS((int) rtt - (int) connection->rtt) + (1-w2) * connection->dev_rtt;
|
||||
|
||||
connection->calculating_rtt = false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -519,6 +551,9 @@ void tcp_process_segment(tcp_state_t *state, ip_address_t sender,
|
||||
TCP_DEBUG_LOG("Connection request handled");
|
||||
|
||||
} else {
|
||||
|
||||
TCP_DEBUG_LOG("RTT=%lld, DevRTT=%lld", connection->rtt, connection->dev_rtt);
|
||||
|
||||
// Something sent to an already instanciated
|
||||
// connection. Since there is an instance, it
|
||||
// means that at least the first SYN was received
|
||||
@@ -560,7 +595,8 @@ void tcp_process_segment(tcp_state_t *state, ip_address_t sender,
|
||||
"the peer will retransmit it");
|
||||
|
||||
// The connection is now established.
|
||||
connection->snd_una = net_to_cpu_u32(segment->ack_no);
|
||||
uint32_t ack_no = net_to_cpu_u32(segment->ack_no);
|
||||
ack_until(connection, ack_no);
|
||||
connection->state = TCP_STATE_ESTAB;
|
||||
|
||||
move_from_non_established_list_to_non_accepted_queue(connection);
|
||||
@@ -747,8 +783,6 @@ tcp_connection_t *tcp_listener_accept(tcp_listener_t *listener, void *callback_d
|
||||
void (*callback_ready_to_recv)(void*),
|
||||
void (*callback_ready_to_send)(void*))
|
||||
{
|
||||
(void) listener;
|
||||
|
||||
if (!listener->non_accepted_queue_head)
|
||||
// Nothing to accept
|
||||
return NULL;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "tcp_timer.h"
|
||||
#endif
|
||||
|
||||
#define TCP_TIMEOUT_TIME_WAIT 240
|
||||
#define TCP_TIMEOUT_TIME_WAIT 240000
|
||||
|
||||
#define TCP_MAX_TIMEOUTS 1024
|
||||
#define TCP_MAX_LISTENERS 32
|
||||
@@ -88,6 +88,13 @@ struct tcp_connection_t {
|
||||
ip_address_t peer_ip; // Network byte order
|
||||
uint16_t peer_port; // CPU byte order
|
||||
|
||||
uint64_t rtt;
|
||||
uint64_t dev_rtt;
|
||||
|
||||
bool calculating_rtt;
|
||||
uint32_t rtt_calc_seq;
|
||||
uint64_t rtt_calc_time;
|
||||
|
||||
// Send Sequence Space
|
||||
//
|
||||
// 1 2 3 4
|
||||
@@ -166,7 +173,7 @@ struct tcp_state_t {
|
||||
|
||||
void tcp_init(tcp_state_t *tcp_state, ip_address_t ip, tcp_callbacks_t callbacks);
|
||||
void tcp_free(tcp_state_t *tcp_state);
|
||||
void tcp_seconds_passed(tcp_state_t *state, size_t seconds);
|
||||
void tcp_ms_passed(tcp_state_t *state, size_t ms);
|
||||
void tcp_process_segment(tcp_state_t *state, ip_address_t sender, tcp_segment_t *segment, size_t len);
|
||||
tcp_listener_t *tcp_listener_create(tcp_state_t *state, uint16_t port, bool reuse, void *data, void (*callback)(void*));
|
||||
void tcp_listener_destroy(tcp_listener_t *listener);
|
||||
|
||||
+6
-6
@@ -41,7 +41,7 @@ void tcp_timer_disable(tcp_timer_t *timer)
|
||||
set->free_list = timer;
|
||||
}
|
||||
|
||||
tcp_timer_t *tcp_timer_create(tcp_timerset_t *set, size_t seconds,
|
||||
tcp_timer_t *tcp_timer_create(tcp_timerset_t *set, size_t ms,
|
||||
void (*callback)(void*), void *data)
|
||||
{
|
||||
assert(callback);
|
||||
@@ -58,7 +58,7 @@ tcp_timer_t *tcp_timer_create(tcp_timerset_t *set, size_t seconds,
|
||||
// first item of the free list.
|
||||
|
||||
timer->set = set;
|
||||
timer->deadline = set->current_time + seconds;
|
||||
timer->deadline = set->current_time_ms + ms;
|
||||
timer->data = data;
|
||||
timer->callback = callback;
|
||||
|
||||
@@ -107,11 +107,11 @@ tcp_timer_t *tcp_timer_create(tcp_timerset_t *set, size_t seconds,
|
||||
return timer;
|
||||
}
|
||||
|
||||
void tcp_timerset_step(tcp_timerset_t *set, size_t seconds)
|
||||
void tcp_timerset_step(tcp_timerset_t *set, size_t ms)
|
||||
{
|
||||
set->current_time += seconds;
|
||||
set->current_time_ms += ms;
|
||||
|
||||
if (set->used_list == NULL || set->used_list->deadline > set->current_time)
|
||||
if (set->used_list == NULL || set->used_list->deadline > set->current_time_ms)
|
||||
// No timeouts triggered
|
||||
return;
|
||||
|
||||
@@ -122,7 +122,7 @@ void tcp_timerset_step(tcp_timerset_t *set, size_t seconds)
|
||||
tcp_timer_t *timeout = set->used_list;
|
||||
while (timeout) {
|
||||
|
||||
if (timeout->deadline > set->current_time)
|
||||
if (timeout->deadline > set->current_time_ms)
|
||||
// This timeout didn't trigger, so the last
|
||||
// timed out timeout was the previous one.
|
||||
break;
|
||||
|
||||
+3
-3
@@ -17,15 +17,15 @@ struct tcp_timer_t {
|
||||
};
|
||||
|
||||
struct tcp_timerset_t {
|
||||
uint64_t current_time;
|
||||
uint64_t current_time_ms;
|
||||
tcp_timer_t *used_list;
|
||||
tcp_timer_t *free_list;
|
||||
tcp_timer_t pool[TCP_MAX_TIMERS];
|
||||
};
|
||||
|
||||
void tcp_timerset_step(tcp_timerset_t *set, size_t seconds);
|
||||
void tcp_timerset_step(tcp_timerset_t *set, size_t ms);
|
||||
void tcp_timerset_init(tcp_timerset_t *set);
|
||||
void tcp_timerset_free(tcp_timerset_t *set);
|
||||
void tcp_timer_disable(tcp_timer_t *timer);
|
||||
tcp_timer_t *tcp_timer_create(tcp_timerset_t *set, size_t seconds,
|
||||
tcp_timer_t *tcp_timer_create(tcp_timerset_t *set, size_t ms,
|
||||
void (*callback)(void*), void *data);
|
||||
|
||||
Reference in New Issue
Block a user