diff --git a/src/rust/lqos_node_manager/static/main.html b/src/rust/lqos_node_manager/static/main.html
index b90cdc45..ebde62f2 100644
--- a/src/rust/lqos_node_manager/static/main.html
+++ b/src/rust/lqos_node_manager/static/main.html
@@ -322,6 +322,7 @@
html += "
DL ⬇️ | ";
html += "UL RTT | ";
html += "DL RTT | ";
+ html += "TCP Retries | ";
html += "Remote ASN | ";
html += "Country | ";
html += "";
@@ -336,6 +337,7 @@
html += "" + scaleNumber(data[i].rate_estimate_bps[1] * 8) + " | ";
html += "" + (data[i].last_rtt[0] / 1000000).toFixed(2) + " | ";
html += "" + (data[i].last_rtt[1] / 1000000).toFixed(2) + " | ";
+ html += "" + data[i].retries[0] + "/" + data[i].retries[1] + " | ";
html += "" + data[i].remote_asn_name + " | ";
html += "" + data[i].remote_asn_country + " | ";
html += "";
diff --git a/src/rust/lqos_sys/src/bpf/common/dissector.h b/src/rust/lqos_sys/src/bpf/common/dissector.h
index fe43f7e2..1e65e651 100644
--- a/src/rust/lqos_sys/src/bpf/common/dissector.h
+++ b/src/rust/lqos_sys/src/bpf/common/dissector.h
@@ -54,6 +54,7 @@ struct dissector_t
__u32 tsecr;
__u32 sequence;
__u32 ack_seq;
+ __u64 now;
};
// Representation of the VLAN header type.
@@ -118,6 +119,7 @@ static __always_inline bool dissector_new(
dissector->tos = 0;
dissector->sequence = 0;
dissector->ack_seq = 0;
+ dissector->now = bpf_ktime_get_boot_ns();
// Check that there's room for an ethernet header
if SKB_OVERFLOW (dissector->start, dissector->end, ethhdr)
diff --git a/src/rust/lqos_sys/src/bpf/common/flows.h b/src/rust/lqos_sys/src/bpf/common/flows.h
index 55952e81..9c2cd02a 100644
--- a/src/rust/lqos_sys/src/bpf/common/flows.h
+++ b/src/rust/lqos_sys/src/bpf/common/flows.h
@@ -86,19 +86,17 @@ struct
// Construct an empty flow_data_t structure, using default values.
static __always_inline struct flow_data_t new_flow_data(
- // The current time in nanoseconds, from bpf_ktime_get_boot_ns
- __u64 now,
// The packet dissector from the previous step
struct dissector_t *dissector
) {
struct flow_data_t data = {
- .start_time = now,
+ .start_time = dissector->now,
.bytes_sent = { 0, 0 },
.packets_sent = { 0, 0 },
// Track flow rates at an MS scale rather than per-second
// to minimize rounding errors.
- .next_count_time = { now + SECOND_IN_NANOS, now + SECOND_IN_NANOS },
- .last_count_time = { now, now },
+ .next_count_time = { dissector->now + SECOND_IN_NANOS, dissector->now + SECOND_IN_NANOS },
+ .last_count_time = { dissector->now, dissector->now },
.next_count_bytes = { dissector->skb_len, dissector->skb_len },
.rate_estimate_bps = { 0, 0 },
.last_sequence = { 0, 0 },
@@ -148,25 +146,23 @@ static __always_inline void update_flow_rates(
// The rate index (0 = to internet, 1 = to local network)
u_int8_t rate_index,
// The flow data structure to update
- struct flow_data_t *data,
- // The current time in nanoseconds, from bpf_ktime_get_boot_ns
- __u64 now
+ struct flow_data_t *data
) {
- data->last_seen = now;
+ data->last_seen = dissector->now;
data->end_status = 0; // Reset the end status
// Update bytes and packets sent
data->bytes_sent[rate_index] += dissector->skb_len;
data->packets_sent[rate_index]++;
- if (now > data->next_count_time[rate_index]) {
+ if (dissector->now > data->next_count_time[rate_index]) {
// Calculate the rate estimate
__u64 bits = (data->bytes_sent[rate_index] - data->next_count_bytes[rate_index])*8;
- __u64 time = (now - data->last_count_time[rate_index]) / 10000000; // 1 Second
+ __u64 time = (dissector->now - data->last_count_time[rate_index]) / 10000000; // 1 Second
data->rate_estimate_bps[rate_index] = (bits/time); // bits per second
- data->next_count_time[rate_index] = now + SECOND_IN_NANOS;
+ data->next_count_time[rate_index] = dissector->now + SECOND_IN_NANOS;
data->next_count_bytes[rate_index] = data->bytes_sent[rate_index];
- data->last_count_time[rate_index] = now;
+ data->last_count_time[rate_index] = dissector->now;
//bpf_debug("[FLOWS] Rate Estimate: %llu", data->rate_estimate_bps[rate_index]);
}
}
@@ -176,14 +172,13 @@ static __always_inline void process_icmp(
struct dissector_t *dissector,
u_int8_t direction,
u_int8_t rate_index,
- u_int8_t other_rate_index,
- u_int64_t now
+ u_int8_t other_rate_index
) {
struct flow_key_t key = build_flow_key(dissector, direction);
struct flow_data_t *data = bpf_map_lookup_elem(&flowbee, &key);
if (data == NULL) {
// There isn't a flow, so we need to make one
- struct flow_data_t new_data = new_flow_data(now, dissector);
+ struct flow_data_t new_data = new_flow_data(dissector);
if (bpf_map_update_elem(&flowbee, &key, &new_data, BPF_ANY) != 0) {
bpf_debug("[FLOWS] Failed to add new flow to map");
return;
@@ -191,7 +186,7 @@ static __always_inline void process_icmp(
data = bpf_map_lookup_elem(&flowbee, &key);
if (data == NULL) return;
}
- update_flow_rates(dissector, rate_index, data, now);
+ update_flow_rates(dissector, rate_index, data);
}
// Handle Per-Flow UDP Analysis
@@ -199,14 +194,13 @@ static __always_inline void process_udp(
struct dissector_t *dissector,
u_int8_t direction,
u_int8_t rate_index,
- u_int8_t other_rate_index,
- u_int64_t now
+ u_int8_t other_rate_index
) {
struct flow_key_t key = build_flow_key(dissector, direction);
struct flow_data_t *data = bpf_map_lookup_elem(&flowbee, &key);
if (data == NULL) {
// There isn't a flow, so we need to make one
- struct flow_data_t new_data = new_flow_data(now, dissector);
+ struct flow_data_t new_data = new_flow_data(dissector);
if (bpf_map_update_elem(&flowbee, &key, &new_data, BPF_ANY) != 0) {
bpf_debug("[FLOWS] Failed to add new flow to map");
return;
@@ -214,7 +208,7 @@ static __always_inline void process_udp(
data = bpf_map_lookup_elem(&flowbee, &key);
if (data == NULL) return;
}
- update_flow_rates(dissector, rate_index, data, now);
+ update_flow_rates(dissector, rate_index, data);
}
// Store the most recent sequence and ack numbers, and detect retransmissions.
@@ -249,8 +243,7 @@ static __always_inline void process_tcp(
struct dissector_t *dissector,
u_int8_t direction,
u_int8_t rate_index,
- u_int8_t other_rate_index,
- u_int64_t now
+ u_int8_t other_rate_index
) {
// SYN packet indicating the start of a conversation. We are explicitly ignoring
// SYN-ACK packets, we just want to catch the opening of a new connection.
@@ -262,7 +255,7 @@ static __always_inline void process_tcp(
bpf_debug("[FLOWS] New TCP Connection Detected (%u)", direction);
#endif
struct flow_key_t key = build_flow_key(dissector, direction);
- struct flow_data_t data = new_flow_data(now, dissector);
+ struct flow_data_t data = new_flow_data(dissector);
data.tos = dissector->tos;
data.ip_flags = 0; // Obtain these
if (bpf_map_update_elem(&flowbee, &key, &data, BPF_ANY) != 0) {
@@ -281,7 +274,7 @@ static __always_inline void process_tcp(
}
// Update the flow data with the current packet's information
- update_flow_rates(dissector, rate_index, data, now);
+ update_flow_rates(dissector, rate_index, data);
// Sequence and Acknowledgement numbers
detect_retries(dissector, rate_index, data);
@@ -294,12 +287,12 @@ static __always_inline void process_tcp(
if (tsval != data->tsval[rate_index] && tsecr != data->tsecr[rate_index]) {
if (tsecr == data->tsval[other_rate_index]) {
- __u64 elapsed = now - data->ts_change_time[other_rate_index];
+ __u64 elapsed = dissector->now - data->ts_change_time[other_rate_index];
data->last_rtt[rate_index] = elapsed;
//bpf_debug("[FLOWS][%d] RTT: %llu", direction, elapsed);
}
- data->ts_change_time[rate_index] = now;
+ data->ts_change_time[rate_index] = dissector->now;
data->tsval[rate_index] = tsval;
data->tsecr[rate_index] = tsecr;
}
@@ -319,8 +312,6 @@ static __always_inline void track_flows(
struct dissector_t *dissector, // The packet dissector from the previous step
u_int8_t direction // The direction of the packet (1 = to internet, 2 = to local network)
) {
- __u64 now = bpf_ktime_get_boot_ns();
-
u_int8_t rate_index;
u_int8_t other_rate_index;
if (direction == TO_INTERNET) {
@@ -334,9 +325,9 @@ static __always_inline void track_flows(
// Pass to the appropriate protocol handler
switch (dissector->ip_protocol)
{
- case IPPROTO_TCP: process_tcp(dissector, direction, rate_index, other_rate_index, now); break;
- case IPPROTO_UDP: process_udp(dissector, direction, rate_index, other_rate_index, now); break;
- case IPPROTO_ICMP: process_icmp(dissector, direction, rate_index, other_rate_index, now); break;
+ case IPPROTO_TCP: process_tcp(dissector, direction, rate_index, other_rate_index); break;
+ case IPPROTO_UDP: process_udp(dissector, direction, rate_index, other_rate_index); break;
+ case IPPROTO_ICMP: process_icmp(dissector, direction, rate_index, other_rate_index); break;
default: {
#ifdef VERBOSE
bpf_debug("[FLOWS] Unsupported protocol: %d", dissector->ip_protocol);
diff --git a/src/rust/lqos_sys/src/bpf/common/heimdall.h b/src/rust/lqos_sys/src/bpf/common/heimdall.h
index 9d5b8342..17b14ba7 100644
--- a/src/rust/lqos_sys/src/bpf/common/heimdall.h
+++ b/src/rust/lqos_sys/src/bpf/common/heimdall.h
@@ -137,7 +137,7 @@ static __always_inline void update_heimdall(struct dissector_t *dissector, __u32
struct heimdall_data *counter = (struct heimdall_data *)bpf_map_lookup_elem(&heimdall, &key);
if (counter)
{
- counter->last_seen = bpf_ktime_get_boot_ns();
+ counter->last_seen = dissector->now;
counter->packets += 1;
counter->bytes += size;
if (dissector->tos != 0)
@@ -148,7 +148,7 @@ static __always_inline void update_heimdall(struct dissector_t *dissector, __u32
else
{
struct heimdall_data counter = {0};
- counter.last_seen = bpf_ktime_get_boot_ns();
+ counter.last_seen = dissector->now;
counter.bytes = size;
counter.packets = 1;
counter.tos = dissector->tos;
@@ -160,7 +160,7 @@ static __always_inline void update_heimdall(struct dissector_t *dissector, __u32
}
} else if (mode == 2) {
struct heimdall_event event = {0};
- event.timetamp = bpf_ktime_get_boot_ns();
+ event.timetamp = dissector->now;
event.src = dissector->src_ip;
event.dst = dissector->dst_ip;
event.src_port = dissector->src_port;
diff --git a/src/rust/lqos_sys/src/bpf/common/throughput.h b/src/rust/lqos_sys/src/bpf/common/throughput.h
index 89466409..93fb4e47 100644
--- a/src/rust/lqos_sys/src/bpf/common/throughput.h
+++ b/src/rust/lqos_sys/src/bpf/common/throughput.h
@@ -33,13 +33,14 @@ static __always_inline void track_traffic(
int direction,
struct in6_addr * key,
__u32 size,
- __u32 tc_handle
+ __u32 tc_handle,
+ __u64 now
) {
// Count the bits. It's per-CPU, so we can't be interrupted - no sync required
struct host_counter * counter =
(struct host_counter *)bpf_map_lookup_elem(&map_traffic, key);
if (counter) {
- counter->last_seen = bpf_ktime_get_boot_ns();
+ counter->last_seen = now;
counter->tc_handle = tc_handle;
if (direction == 1) {
// Download
@@ -53,7 +54,7 @@ static __always_inline void track_traffic(
} else {
struct host_counter new_host = {0};
new_host.tc_handle = tc_handle;
- new_host.last_seen = bpf_ktime_get_boot_ns();
+ new_host.last_seen = now;
if (direction == 1) {
new_host.download_packets = 1;
new_host.download_bytes = size;
diff --git a/src/rust/lqos_sys/src/bpf/lqos_kern.c b/src/rust/lqos_sys/src/bpf/lqos_kern.c
index 79307cdd..9ad2a20c 100644
--- a/src/rust/lqos_sys/src/bpf/lqos_kern.c
+++ b/src/rust/lqos_sys/src/bpf/lqos_kern.c
@@ -147,7 +147,8 @@ int xdp_prog(struct xdp_md *ctx)
effective_direction,
&lookup_key.address,
ctx->data_end - ctx->data, // end - data = length
- tc_handle
+ tc_handle,
+ dissector.now
);
// Send on its way
@@ -303,16 +304,6 @@ int tc_iphash_to_cpu(struct __sk_buff *skb)
bpf_debug("(TC) effective direction: %d", effective_direction);
#endif
-/*
- // Call pping to obtain RTT times
- struct parsing_context context = {0};
- context.now = bpf_ktime_get_ns();
- context.tcp = NULL;
- context.dissector = &dissector;
- context.active_host = &lookup_key.address;
- tc_pping_start(&context);
-*/
-
if (ip_info && ip_info->tc_handle != 0) {
// We found a matching mapped TC flow
#ifdef VERBOSE