mirror of
https://github.com/vacp2p/dst-libp2p-test-node.git
synced 2026-08-30 22:31:08 +00:00
167 lines
5.9 KiB
Python
167 lines
5.9 KiB
Python
import math
|
|
import argparse
|
|
import networkx as nx
|
|
import yaml
|
|
|
|
#Configurable in test node, message injector, but fixed here
|
|
shadow_env = 1
|
|
connections = 10
|
|
gml_file = "network_topology.gml"
|
|
yaml_file = "shadow.yaml"
|
|
|
|
|
|
def parse_arguments():
|
|
parser = argparse.ArgumentParser(description="Generate network topology and yaml for shadow")
|
|
parser.add_argument('-n', '--network-size', type=int, help='Number of peers in the network', default=100)
|
|
parser.add_argument('-bl', '--min-bandwidth', type=int, help='Minimum bandwidth in Mbps', default=50)
|
|
parser.add_argument('-bh', '--max-bandwidth', type=int, help='Maximum bandwidth in Mbps', default=50)
|
|
parser.add_argument('-ll', '--min-latency', type=int, help='Minimum latency in ms', default=100)
|
|
parser.add_argument('-lh', '--max-latency', type=int, help='Maximum latency in ms', default=100)
|
|
parser.add_argument('-st', '--anchor-stages', type=int, help='Number of bandwidth/latency variations', default=1)
|
|
parser.add_argument('-l', '--packet-loss', type=float, help='Packet loss rate (0-1)', default=0.0)
|
|
parser.add_argument('-s', '--msg-size-bytes', type=int, help='Message size in bytes', default=1500)
|
|
parser.add_argument('-f', '--num-frags', type=int, choices=range(1, 10), help='Number of fragments per message (1-10)', default=1)
|
|
parser.add_argument('-m', '--messages', type=int, help='Number of messages to publish', default=10)
|
|
parser.add_argument('-d', '--delay-seconds', type=float, help='Inter-message delay in seconds', default=0.1)
|
|
parser.add_argument('-mx', '--muxer', type=str, choices=['mplex', 'yamux', 'quic'], help='Muxer selection', default='yamux')
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Validate arguments
|
|
if args.min_bandwidth > args.max_bandwidth:
|
|
parser.error("min_bandwidth cannot exceed max_bandwidth")
|
|
if args.min_latency > args.max_latency:
|
|
parser.error("min_latency cannot exceed max_latency")
|
|
|
|
return args
|
|
|
|
|
|
def create_network_topology(steps, min_bandwidth, max_bandwidth,
|
|
min_latency, max_latency, packet_loss):
|
|
|
|
G = nx.complete_graph(steps)
|
|
|
|
bandwidth_jump = int((max_bandwidth - min_bandwidth) / steps)
|
|
latency_jump = int((max_latency - min_latency) / steps)
|
|
|
|
# Configure nodes and edges
|
|
for i in range(steps):
|
|
node_bw = f"{math.ceil(i * bandwidth_jump + min_bandwidth)} Mbit"
|
|
G.nodes[i]["host_bandwidth_up"] = node_bw
|
|
G.nodes[i]["host_bandwidth_down"] = node_bw
|
|
|
|
# Self-loop for intra-node communication
|
|
G.add_edge(i, i)
|
|
G.edges[i, i]["latency"] = f"{max((steps - i) * latency_jump, min_latency)} ms"
|
|
G.edges[i, i]["packet_loss"] = packet_loss
|
|
|
|
# Edges to other nodes
|
|
for j in range(i + 1, steps):
|
|
edge_latency = min(math.ceil((steps - j) * latency_jump + min_latency), max_latency)
|
|
G.edges[i, j]["latency"] = f"{edge_latency} ms"
|
|
G.edges[i, j]["packet_loss"] = packet_loss
|
|
|
|
# Add fast node for message injector
|
|
G.add_node(steps, host_bandwidth_up="100 Mbit", host_bandwidth_down="100 Mbit")
|
|
for i in range(steps + 1):
|
|
G.add_edge(i, steps)
|
|
G.edges[i, steps]["latency"] = "1 ms"
|
|
G.edges[i, steps]["packet_loss"] = 0.0
|
|
|
|
nx.write_gml(G, gml_file)
|
|
|
|
|
|
def create_shadow_config(steps, network_size, num_publishers, num_frags,
|
|
message_size, message_delay, muxer):
|
|
|
|
#simulation details
|
|
config = {
|
|
'general': {
|
|
'bootstrap_end_time': '10s',
|
|
'heartbeat_interval': '12s',
|
|
'stop_time': '15m',
|
|
'progress': True
|
|
},
|
|
'experimental': {
|
|
'use_memory_manager': False
|
|
},
|
|
'network': {
|
|
'graph': {
|
|
'type': 'gml',
|
|
'file': {
|
|
'path': gml_file
|
|
}
|
|
}
|
|
},
|
|
'hosts': {}
|
|
}
|
|
|
|
# Peer settings (for each stage)
|
|
host_templates = {}
|
|
for i in range(steps):
|
|
host_config = {
|
|
'network_node_id': i,
|
|
'processes': [{
|
|
'path': './main',
|
|
'start_time': '5s',
|
|
'environment': {
|
|
'PEERS': str(network_size),
|
|
'SHADOWENV': str(shadow_env),
|
|
'CONNECTTO': str(connections),
|
|
'PUBLISHERS': str(num_publishers),
|
|
'FRAGMENTS': str(num_frags),
|
|
'MUXER': muxer
|
|
}
|
|
}]
|
|
}
|
|
host_templates[i] = host_config
|
|
config['hosts'][f'pod-{i}'] = host_config
|
|
|
|
# Distribute peers in all stages
|
|
for i in range(steps, network_size):
|
|
config['hosts'][f'pod-{i}'] = host_templates[i % steps]
|
|
|
|
# Add publish controller
|
|
controller_config = {
|
|
'network_node_id': steps,
|
|
'processes': [{
|
|
'path': '/usr/bin/python',
|
|
'args': f'../../../traffic_sync.py -s {message_size} -m {num_publishers} -d {message_delay} -n {network_size} --peer-selection id',
|
|
'start_time': '500s',
|
|
'environment': {
|
|
'SHADOWENV': str(shadow_env)
|
|
}
|
|
}]
|
|
}
|
|
config['hosts'][f'pod-{network_size}'] = controller_config
|
|
|
|
with open(yaml_file, 'w') as f:
|
|
yaml.dump(config, f, default_flow_style=False, sort_keys=False)
|
|
|
|
|
|
def main():
|
|
args = parse_arguments()
|
|
|
|
# generate network topology
|
|
create_network_topology(
|
|
args.anchor_stages,
|
|
args.min_bandwidth,
|
|
args.max_bandwidth,
|
|
args.min_latency,
|
|
args.max_latency,
|
|
args.packet_loss
|
|
)
|
|
|
|
# generate shadow configuration
|
|
create_shadow_config(
|
|
args.anchor_stages,
|
|
args.network_size,
|
|
args.messages,
|
|
args.num_frags,
|
|
args.msg_size_bytes,
|
|
args.delay_seconds,
|
|
args.muxer
|
|
)
|
|
|
|
if __name__ == "__main__":
|
|
main() |