feat(evaluation): Added results and modified scripts and execution for a test evaluation

Signed-off-by: Tuan-Dat Tran <tuan-dat.tran@tudattr.dev>
This commit is contained in:
Tuan-Dat Tran
2024-12-28 00:51:37 +01:00
parent 2f1bcbd5d4
commit d5847cd916
7 changed files with 387 additions and 46 deletions

View File

@@ -6,12 +6,17 @@ from scapy.all import Ether, IP, UDP, send, sendp, Raw, sniff
global initial_timestamp
initial_timestamp = int(time.time() * 1000)
# Simulated ACK sending function
def send_ack(destination_IP, my_port, sender_port):
ack_data = ""
###################
# With localhost:
ack_packet = IP(dst=destination_IP) / UDP(dport=sender_port, sport=my_port) / Raw(load=str(ack_data))
ack_packet = (
IP(dst=destination_IP)
/ UDP(dport=sender_port, sport=my_port)
/ Raw(load=str(ack_data))
)
send(ack_packet, verbose=False)
###################
# With netns:
@@ -20,18 +25,25 @@ def send_ack(destination_IP, my_port, sender_port):
###################
print(f"Sent ACK: {ack_data}")
# Process incoming packets
def process_packet(pkt):
################### Save timestamps ###################
if Raw in pkt:
with open(save_file, "a") as f: # open as "a" for append
with open(save_file, "a") as f: # open as "a" for append
global initial_timestamp
receival_time = str(int(time.time() * 1000) - initial_timestamp) # time of arrival at receiver
send_time = pkt[Raw].load # time it was sent from the sender
receival_time = str(
int(time.time() * 1000) - initial_timestamp
) # time of arrival at receiver
send_time = pkt[Raw].load # time it was sent from the sender
################### Conversion & error handling ###################
try:
send_time = int(send_time.decode("utf-8").split("X")[0]) # decode the payload and stop at "X"
except ValueError: # For the last packet without a timestamp but "END" as payload
send_time = int(
send_time.decode("utf-8").split("X")[0]
) # decode the payload and stop at "X"
except (
ValueError
): # For the last packet without a timestamp but "END" as payload
print(f"END for {my_port}")
send_ack(destination_IP, my_port, sender_port)
return
@@ -45,23 +57,32 @@ def process_packet(pkt):
send_ack(destination_IP, my_port, sender_port)
# Main loop
def main(destination_IP, my_port, sender_port):
###################
# With localhost:
sniff(iface="lo", filter=f"udp and dst port {my_port}", prn=process_packet, store=False)
sniff(
iface="lo",
filter=f"udp and dst port {my_port}",
prn=process_packet,
store=False,
)
###################
# With netns:
# sniff(iface="ns-g", filter=f"udp and dst port {my_port}", prn=process_packet, store=False)
###################
if __name__ == "__main__":
if len(sys.argv) != 4:
print("Usage: python receive_and_ack.py <destination_IP> <my_port> <sender_port>")
print(
"Usage: python receive_and_ack.py <destination_IP> <my_port> <sender_port>"
)
sys.exit(1)
destination_IP = sys.argv[1] # Clear
my_port = int(sys.argv[2]) # Port to listen on
sender_port = int(sys.argv[3]) # Port to send acks to
destination_IP = sys.argv[1] # Clear
my_port = int(sys.argv[2]) # Port to listen on
sender_port = int(sys.argv[3]) # Port to send acks to
save_file = f"timestamps_{my_port}"
main(destination_IP, my_port, sender_port)

View File

@@ -0,0 +1,67 @@
import sys
import time
import threading
from scapy.all import Ether, IP, UDP, send, sendp, Raw, sniff
global initial_timestamp
initial_timestamp = int(time.time() * 1000)
# Simulated ACK sending function
def send_ack(destination_IP, my_port, sender_port):
ack_data = ""
###################
# With localhost:
# ack_packet = IP(dst=destination_IP) / UDP(dport=sender_port, sport=my_port) / Raw(load=str(ack_data))
# send(ack_packet, verbose=False)
###################
# With netns:
ack_packet = Ether(dst="64:9d:99:b1:0a:a4", src="64:9d:99:b1:0a:88") / IP(dst=destination_IP) / UDP(sport=my_port,dport=sender_port) / Raw(load=str(ack_data))
sendp(ack_packet, verbose=False)
###################
print(f"Sent ACK: {ack_data}")
# Process incoming packets
def process_packet(pkt):
################### Save timestamps ###################
if Raw in pkt:
with open(save_file, "a") as f: # open as "a" for append
global initial_timestamp
receival_time = str(int(time.time() * 1000) - initial_timestamp) # time of arrival at receiver
send_time = pkt[Raw].load # time it was sent from the sender
################### Conversion & error handling ###################
try:
send_time = int(send_time.decode("utf-8").split("X")[0]) # decode the payload and stop at "X"
except ValueError: # For the last packet without a timestamp but "END" as payload
print(f"END for {my_port}")
send_ack(destination_IP, my_port, sender_port)
return
except Exception as e:
print(f"Decoding error at {my_port}")
send_ack(destination_IP, my_port, sender_port)
return
################### Write data ###################
aoi = int(receival_time) - send_time
f.write(f"{send_time},{receival_time},{aoi}\n")
send_ack(destination_IP, my_port, sender_port)
# Main loop
def main(destination_IP, my_port, sender_port):
###################
# With localhost:
# sniff(iface="lo", filter=f"udp and dst port {my_port}", prn=process_packet, store=False)
###################
# With netns:
sniff(iface="enp6s0f0np0", filter=f"udp and dst port {my_port}", prn=process_packet, store=False)
###################
if __name__ == "__main__":
if len(sys.argv) != 4:
print("Usage: python receive_and_ack.py <destination_IP> <my_port> <sender_port>")
sys.exit(1)
destination_IP = sys.argv[1] # Clear
my_port = int(sys.argv[2]) # Port to listen on
sender_port = int(sys.argv[3]) # Port to send acks to
save_file = f"timestamps_{my_port}"
main(destination_IP, my_port, sender_port)

View File

@@ -0,0 +1,3 @@
#!/bin/bash
sudo ip netns exec tb_node1_if0 python3 receiver.py 10.0.2.1 30123 30123

View File

@@ -0,0 +1,135 @@
import sys
import time
import random
import threading
from scapy.all import Ether, IP, UDP, sendp, Raw, sniff, send
global initial_timestamp
initial_timestamp = int(time.time() * 1000)
# Parameters
Q_max = 10 # Maximum queue size
age_threshold = 1.0 # Delta_T in seconds
# Sender's state
last_update_time = None # Last time an ACK was received
N = 1 # Active senders (received from ACK)
queue_utilization = 0 # Received as Q_i/Q_max
delta_c = 0 # Time since the last ACK (calculated using T_ACK)
# Function to calculate P_s
def calculate_probability(N, queue_utilization, delta_c):
if queue_utilization < 1:
return 1.0 # Full probability if the queue is underutilized
elif queue_utilization == 1:
# Calculate f(Delta_i)
f_delta = max((delta_c - age_threshold) / age_threshold, 0)
return (Q_max / N) + f_delta # Combine probabilities
# Function to send a packet
def send_packet(target_ip, receiver_port, my_port, dscp_value, packet_size, FIN_flag):
ether_layer = Ether(dst="64:9d:99:b1:0a:88", src="64:9d:99:b1:0a:a4")
ip_layer = IP(dst=target_ip, tos=dscp_value << 2)
udp_layer = UDP(dport=receiver_port, sport=my_port)
# # Socket to listen for the ACKs
# ack_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# ack_socket.settimeout(2) # 2 seconds timer to receive the ack. Otherwise considered lost
# ack_socket.bind(("", my_port))
# timestamp = str(int(time.time())) # Convert to a string for embedding
global initial_timestamp
timestamp = str(int(time.time() * 1000) - initial_timestamp)
if (not FIN_flag):
payload = timestamp + "X" * max((packet_size - len(timestamp)), 0) # max to prevent possible errors when choosing too small packet size
else:
payload = "END" + "X" * max((packet_size - len(timestamp)), 0)
packet = ether_layer / ip_layer / udp_layer / Raw(load=payload)
# packet = ip_layer / udp_layer / Raw(load=payload)
sendp(packet, verbose=False)
# send(packet, verbose=False)
print(".", end='', flush=True)
# Listen for ACKs
def process_ack(pkt):
global last_update_time, N, queue_utilization, delta_c
if Raw in pkt:
ack_data = pkt[Raw].load.decode('utf-8')
print(ack_data)
# N, queue_utilization, T_ACK = eval(ack_data)
# last_update_time = T_ACK
# print(f"Received ACK: N={N}, Utilization={queue_utilization}, T_ACK={T_ACK}")
# Main loop
def main(target_ip, receiver_port, my_port, dscp_value, nb_packets, packet_size):
global delta_c
packets_sent = 0
while packets_sent < nb_packets:
# Update delta_c (time since the last ACK)
if last_update_time:
delta_c = time.time() - last_update_time
else:
delta_c = float('inf') # No ACK received yet
# Calculate sending probability
P_s = calculate_probability(N, queue_utilization, delta_c)
# Decide whether to send a packet
if random.random() < P_s:
FIN_flag = False
if packets_sent == nb_packets - 1:
FIN_flag = True
send_packet(target_ip, receiver_port, my_port, dscp_value, packet_size, FIN_flag)
packets_sent += 1
print(f"Packet sent with probability P_s={P_s:.2f}")
else:
print(f"Packet skipped with probability P_s={P_s:.2f}")
# Wait for a short interval before the next attempt
time.sleep(0.1)
print(f"Finished sending {nb_packets} packets to {target_ip}:{receiver_port}")
if __name__ == "__main__":
if len(sys.argv) != 6:
print("Usage: python send_dscp_packets.py <target_ip> <my_port> <receiver_port> <nb_packets> <packet_size(in Bytes)>")
sys.exit(1)
target_ip = sys.argv[1] # IP of the receiver
my_port = int(sys.argv[2]) # Sender port
receiver_port = int(sys.argv[3]) # Receiver port
nb_packets = int(sys.argv[4]) # Total number of packets to send
packet_size = int(sys.argv[5]) - 42 # Packet size in Bytes - 42 (previous headers)
dscp_value = 0 # Hardcoded DSCP value for now
# main(target_ip, receiver_port, my_port, dscp_value, nb_packets)
threading.Thread(target=main, args=(target_ip, receiver_port, my_port, dscp_value, nb_packets, packet_size), daemon=True).start()
###################
# With localhost:
# sniff(iface="lo", filter=f"udp and dst port {my_port}", prn=process_ack, store=False)#, timeout=0.1)
###################
# With netns:
sniff(iface="enp6s0f0np0", filter=f"udp and dst port {my_port}", prn=process_ack, store=False)
###################
''' Archive:
# Add padding:
payload = timestamp + "X" * (packet_size - len(timestamp))
'''

View File

@@ -0,0 +1,3 @@
#!/bin/bash
sudo ip netns exec tb_node2_if0 python3 sender.py 10.0.1.1 30123 30123 100 128

View File

@@ -0,0 +1,99 @@
1,8490,8489
136,8618,8482
252,8750,8498
368,8886,8518
484,9022,8538
604,9158,8554
720,9298,8578
843,9438,8595
962,9578,8616
1077,9706,8629
1192,9846,8654
1311,9962,8651
1426,10106,8680
1545,10255,8710
1660,10391,8731
1776,10547,8771
1891,10681,8790
2007,10816,8809
2123,10947,8824
2239,11082,8843
2358,11221,8863
2474,11356,8882
2593,11495,8902
2709,11626,8917
2825,11761,8936
2940,11896,8956
3056,12044,8988
3171,12174,9003
3286,12310,9024
3402,12442,9040
3517,12557,9040
3632,12692,9060
3747,12823,9076
3863,12958,9095
3978,13097,9119
4093,13236,9143
4212,13393,9181
4331,13524,9193
4447,13659,9212
4562,13794,9232
4679,13929,9250
4795,14067,9272
4910,14185,9275
5026,14341,9315
5145,14477,9332
5260,14612,9352
5376,14748,9372
5492,14887,9395
5608,15022,9414
5723,15153,9430
5838,15267,9429
5953,15402,9449
6068,15537,9469
6184,15672,9488
6303,15804,9501
6418,15943,9525
6533,16078,9545
6649,16221,9572
6765,16360,9595
6880,16499,9619
6995,16631,9636
7110,16766,9656
7225,16901,9676
7341,17061,9720
7470,17196,9726
7587,17339,9752
7703,17478,9775
7818,17596,9778
7933,17739,9806
8050,17874,9824
8169,18009,9840
8288,18158,9870
8404,18289,9885
8523,18424,9901
8638,18555,9917
8754,18670,9916
8874,18805,9931
8989,18936,9947
9105,19075,9970
9220,19206,9986
9335,19341,10006
9454,19472,10018
9577,19615,10038
9693,19742,10049
9808,19898,10090
9924,20029,10105
10039,20168,10129
10159,20299,10140
10274,20434,10160
10389,20565,10176
10512,20693,10181
10627,20820,10193
10742,20951,10209
10857,21086,10229
10977,21238,10261
11092,21359,10267
11207,21515,10308
11331,21646,10315
11453,21781,10328

View File

@@ -9,63 +9,67 @@ initial_timestamp = int(time.time() * 1000)
# Parameters
Q_max = 10 # Maximum queue size
age_threshold = 1.0 # Delta_T in seconds
Q_max = 10 # Maximum queue size
age_threshold = 1.0 # Delta_T in seconds
# Sender's state
last_update_time = None # Last time an ACK was received
N = 1 # Active senders (received from ACK)
queue_utilization = 0 # Received as Q_i/Q_max
delta_c = 0 # Time since the last ACK (calculated using T_ACK)
last_update_time = None # Last time an ACK was received
N = 1 # Active senders (received from ACK)
queue_utilization = 0 # Received as Q_i/Q_max
delta_c = 0 # Time since the last ACK (calculated using T_ACK)
# Function to calculate P_s
def calculate_probability(N, queue_utilization, delta_c):
if queue_utilization < 1:
return 1.0 # Full probability if the queue is underutilized
return 1.0 # Full probability if the queue is underutilized
elif queue_utilization == 1:
# Calculate f(Delta_i)
f_delta = max((delta_c - age_threshold) / age_threshold, 0)
return (Q_max / N) + f_delta # Combine probabilities
return (Q_max / N) + f_delta # Combine probabilities
# Function to send a packet
def send_packet(target_ip, receiver_port, my_port, dscp_value, packet_size, FIN_flag):
ether_layer = Ether(dst="00:00:00:00:00:04", src="00:00:00:00:00:01")
ip_layer = IP(dst=target_ip, tos=dscp_value << 2)
udp_layer = UDP(dport=receiver_port, sport=my_port)
# # Socket to listen for the ACKs
# ack_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# ack_socket.settimeout(2) # 2 seconds timer to receive the ack. Otherwise considered lost
# ack_socket.bind(("", my_port))
# timestamp = str(int(time.time())) # Convert to a string for embedding
global initial_timestamp
timestamp = str(int(time.time() * 1000) - initial_timestamp)
if (not FIN_flag):
payload = timestamp + "X" * max((packet_size - len(timestamp)), 0) # max to prevent possible errors when choosing too small packet size
if not FIN_flag:
payload = timestamp + "X" * max(
(packet_size - len(timestamp)), 0
) # max to prevent possible errors when choosing too small packet size
else:
payload = "END" + "X" * max((packet_size - len(timestamp)), 0)
# packet = ether_layer / ip_layer / udp_layer / Raw(load=payload)
packet = ip_layer / udp_layer / Raw(load=payload)
# sendp(packet, verbose=False)
send(packet, verbose=False)
print(".", end='', flush=True)
# sendp(packet, verbose=False)
send(packet, verbose=False)
print(".", end="", flush=True)
# Listen for ACKs
def process_ack(pkt):
global last_update_time, N, queue_utilization, delta_c
if Raw in pkt:
ack_data = pkt[Raw].load.decode('utf-8')
ack_data = pkt[Raw].load.decode("utf-8")
N, queue_utilization, T_ACK = eval(ack_data)
last_update_time = T_ACK
print(f"Received ACK: N={N}, Utilization={queue_utilization}, T_ACK={T_ACK}")
# Main loop
def main(target_ip, receiver_port, my_port, dscp_value, nb_packets, packet_size):
global delta_c
@@ -76,19 +80,20 @@ def main(target_ip, receiver_port, my_port, dscp_value, nb_packets, packet_size)
if last_update_time:
delta_c = time.time() - last_update_time
else:
delta_c = float('inf') # No ACK received yet
delta_c = float("inf") # No ACK received yet
# Calculate sending probability
P_s = calculate_probability(N, queue_utilization, delta_c)
# Decide whether to send a packet
if random.random() < P_s:
FIN_flag = False
if packets_sent == nb_packets - 1:
FIN_flag = True
send_packet(target_ip, receiver_port, my_port, dscp_value, packet_size, FIN_flag)
send_packet(
target_ip, receiver_port, my_port, dscp_value, packet_size, FIN_flag
)
packets_sent += 1
print(f"Packet sent with probability P_s={P_s:.2f}")
else:
@@ -102,28 +107,36 @@ def main(target_ip, receiver_port, my_port, dscp_value, nb_packets, packet_size)
if __name__ == "__main__":
if len(sys.argv) != 6:
print("Usage: python send_dscp_packets.py <target_ip> <my_port> <receiver_port> <nb_packets> <packet_size(in Bytes)>")
print(
"Usage: python send_dscp_packets.py <target_ip> <my_port> <receiver_port> <nb_packets> <packet_size(in Bytes)>"
)
sys.exit(1)
target_ip = sys.argv[1] # IP of the receiver
my_port = int(sys.argv[2]) # Sender port
receiver_port = int(sys.argv[3]) # Receiver port
nb_packets = int(sys.argv[4]) # Total number of packets to send
packet_size = int(sys.argv[5]) - 42 # Packet size in Bytes - 42 (previous headers)
dscp_value = 0 # Hardcoded DSCP value for now
target_ip = sys.argv[1] # IP of the receiver
my_port = int(sys.argv[2]) # Sender port
receiver_port = int(sys.argv[3]) # Receiver port
nb_packets = int(sys.argv[4]) # Total number of packets to send
packet_size = int(sys.argv[5]) - 42 # Packet size in Bytes - 42 (previous headers)
dscp_value = 0 # Hardcoded DSCP value for now
# main(target_ip, receiver_port, my_port, dscp_value, nb_packets)
threading.Thread(target=main, args=(target_ip, receiver_port, my_port, dscp_value, nb_packets, packet_size), daemon=True).start()
threading.Thread(
target=main,
args=(target_ip, receiver_port, my_port, dscp_value, nb_packets, packet_size),
daemon=True,
).start()
###################
# With localhost:
sniff(iface="lo", filter=f"udp and dst port {my_port}", prn=process_ack, store=False)#, timeout=0.1)
###################
# With netns:
# sniff(iface="ns-r", filter=f"udp and dst port {my_port}", prn=process_ack, store=False)
sniff(
iface="lo", filter=f"udp and dst port {my_port}", prn=process_ack, store=False
) # , timeout=0.1)
###################
# With netns:
# sniff(iface="ns-r", filter=f"udp and dst port {my_port}", prn=process_ack, store=False)
###################
''' Archive:
""" Archive:
# Add padding:
payload = timestamp + "X" * (packet_size - len(timestamp))
@@ -131,4 +144,4 @@ if __name__ == "__main__":
'''
"""