diff --git a/sender-receiver-scripts/receiver.py b/sender-receiver-scripts/receiver.py index 8d52b94..8796328 100644 --- a/sender-receiver-scripts/receiver.py +++ b/sender-receiver-scripts/receiver.py @@ -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 ") + print( + "Usage: python receive_and_ack.py " + ) 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) diff --git a/sender-receiver-scripts/results/receiver.py b/sender-receiver-scripts/results/receiver.py new file mode 100644 index 0000000..72a914c --- /dev/null +++ b/sender-receiver-scripts/results/receiver.py @@ -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 ") + 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) diff --git a/sender-receiver-scripts/results/receiver.sh b/sender-receiver-scripts/results/receiver.sh new file mode 100755 index 0000000..5c31c7e --- /dev/null +++ b/sender-receiver-scripts/results/receiver.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +sudo ip netns exec tb_node1_if0 python3 receiver.py 10.0.2.1 30123 30123 diff --git a/sender-receiver-scripts/results/sender.py b/sender-receiver-scripts/results/sender.py new file mode 100644 index 0000000..fa6f24f --- /dev/null +++ b/sender-receiver-scripts/results/sender.py @@ -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 ") + 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)) + + + + +''' diff --git a/sender-receiver-scripts/results/sender.sh b/sender-receiver-scripts/results/sender.sh new file mode 100755 index 0000000..a783392 --- /dev/null +++ b/sender-receiver-scripts/results/sender.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +sudo ip netns exec tb_node2_if0 python3 sender.py 10.0.1.1 30123 30123 100 128 diff --git a/sender-receiver-scripts/results/timestamps_30123 b/sender-receiver-scripts/results/timestamps_30123 new file mode 100644 index 0000000..62d0971 --- /dev/null +++ b/sender-receiver-scripts/results/timestamps_30123 @@ -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 diff --git a/sender-receiver-scripts/sender.py b/sender-receiver-scripts/sender.py index d438413..3ca7547 100644 --- a/sender-receiver-scripts/sender.py +++ b/sender-receiver-scripts/sender.py @@ -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 ") + print( + "Usage: python send_dscp_packets.py " + ) 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__": -''' +"""