From 91f2526f15e71e32fcdac5f5a9c54731fce2b5ec Mon Sep 17 00:00:00 2001 From: cozis Date: Tue, 29 Aug 2023 12:56:23 +0200 Subject: [PATCH] added rtt and rtt deviation calculation for the tcp layer --- src/arp.c | 4 +++- src/arp.h | 2 +- src/defs.h | 1 + src/ip.c | 5 ++--- src/ip.h | 2 +- src/microtcp.c | 29 ++++++++++++++++++---------- src/tcp.c | 50 +++++++++++++++++++++++++++++++++++++++++-------- src/tcp.h | 11 +++++++++-- src/tcp_timer.c | 12 ++++++------ src/tcp_timer.h | 6 +++--- 10 files changed, 87 insertions(+), 35 deletions(-) diff --git a/src/arp.c b/src/arp.c index 2a5e795..3cc9b6e 100644 --- a/src/arp.c +++ b/src/arp.c @@ -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 diff --git a/src/arp.h b/src/arp.h index 06e5164..566eea6 100644 --- a/src/arp.h +++ b/src/arp.h @@ -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); \ No newline at end of file diff --git a/src/defs.h b/src/defs.h index a68b828..18db114 100644 --- a/src/defs.h +++ b/src/defs.h @@ -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 */ \ No newline at end of file diff --git a/src/ip.c b/src/ip.c index a548b08..8b4a4d1 100644 --- a/src/ip.c +++ b/src/ip.c @@ -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, diff --git a/src/ip.h b/src/ip.h index 2d0430e..50f9f9e 100644 --- a/src/ip.h +++ b/src/ip.h @@ -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); diff --git a/src/microtcp.c b/src/microtcp.c index afbf44b..86e845d 100644 --- a/src/microtcp.c +++ b/src/microtcp.c @@ -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); - - 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; + uint64_t ms = (current_time_ms - mtcp->last_update_time_ms); + + 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; diff --git a/src/tcp.c b/src/tcp.c index 7d1d725..153daba 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -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; diff --git a/src/tcp.h b/src/tcp.h index 68c7a2e..add4f7b 100644 --- a/src/tcp.h +++ b/src/tcp.h @@ -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); diff --git a/src/tcp_timer.c b/src/tcp_timer.c index 5aa70c4..5f16d8e 100644 --- a/src/tcp_timer.c +++ b/src/tcp_timer.c @@ -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; diff --git a/src/tcp_timer.h b/src/tcp_timer.h index 7841acb..c5064f2 100644 --- a/src/tcp_timer.h +++ b/src/tcp_timer.h @@ -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);