diff --git a/pydyton/network.py b/pydyton/network.py index 359e8c596f30d304afe6b198be7a60b1aa532e87..3d481dbf37ed1a0906d84fd18bc29ebe22c1b24b 100644 --- a/pydyton/network.py +++ b/pydyton/network.py @@ -9,6 +9,8 @@ import simpy import yaml import networkx as nx +from .core import TickProcess + from .communities import types as communities from .routers import types as routers from .traces import types as traces @@ -83,7 +85,7 @@ class Network: def send_link(self, a, b, packet): '''''' - if self[a][b]['state']: + if self.graph[a][b]['state']: # TODO: transfer delay b.recv(packet) else: @@ -102,47 +104,47 @@ def NodeFactory(router, **kwargs): return factory -class Node: +class Node(TickProcess): '''''' def __init__(self, env, network, nid, buffer_size=None, tick_time=1, router=None): '''''' + super().__init__(tick_time) self.env = env self.network = network self.id = nid - self.tick_time = tick_time - self.ticker = env.process(self.tick()) - self.buffer = Buffer(self.env, capacity=buffer_size) # bind router as a class method if router is None: router = routers['direct'] - self.router = router.__get__(self, Node) + self.router = router #router.__get__(self, Node) self.router_state = {} - def tick(self): - '''''' - while True: - packets_to_delete = [] + self.start(env) - for packet in self.buffer: - if packet.ttl < self.env.now: - packets_to_delete.append(packet) - continue - if self.router(packet, self.router_state): - packets_to_delete.append(packet) + def route_packets(self): + packets_to_delete = [] - for packet in packets_to_delete: - self.buffer.remove(packet) + for packet in self.buffer: + if self.router(self, packet, self.router_state): + packets_to_delete.append(packet) - yield self.env.timeout(self.tick_time) + for packet in packets_to_delete: + self.buffer.remove(packet) - def send(self, to, packet): + def process(self): + '''''' + while True: + self.buffer.clean() + self.route_packets() + yield self.tick() + + def send(self, to, packet, reason=None): # TODO: transfer delay - packet.send() + packet.send(self, to, reason=reason) self.network.send_link(self, to, packet) def recv(self, packet): @@ -151,6 +153,11 @@ class Node: else: self.buffer.add(packet) + ''' + def __eq__(self, other): + return self.id == other.id + ''' + @property def community(self): return self.network.community[self] @@ -175,7 +182,8 @@ class Buffer: def __init__(self, env, capacity=0): self.env = env - if capacity <= 0: + + if capacity is None or capacity <= 0: self.capacity = float('inf') else: self.capacity = capacity @@ -183,6 +191,16 @@ class Buffer: self.buffer = OrderedDict() self.used = 0 + def clean(self): + packets_to_drop = [] + + for packet in self: + if packet.ttl < self.env.now: + packets_to_drop.append(packet) + + for packet in packets_to_drop: + self.remove(packet) + def add(self, packet): if self.used < self.capacity: self.used += 1 @@ -216,13 +234,20 @@ class PacketGenerator(TickProcess): def process(self, network): packet_id = 0 - yield self.env.timeout(self.start_delay) - while True: + def create(packet_id): source, dest = random.choice(network.links) packet = Packet(packet_id, source, dest, self.env.now + self.time_to_live, None) self.packets.append(packet) source.recv(packet) + yield self.env.timeout(self.start_delay) + print('starting packets') + #@DEBUG + for i in range(217): + pass + #@DEBUG + while True: + create(packet_id) yield self.tick() packet_id += 1 @@ -234,6 +259,13 @@ class PacketGenerator(TickProcess): if packet.recieved ]) + @property + def recieved_count(self): + return sum([ + packet.recieved_count + for packet in self.packets + ]) + @property def sent(self): return sum([ @@ -241,16 +273,44 @@ class PacketGenerator(TickProcess): for packet in self.packets ]) + @property + def stats(self): + stats = {} + for packet in self.packets: + for stat, value in packet.stats.items(): + if stat not in stats: + stats[stat] = value + else: + stats[stat] += value + return stats + + @property + def paths(self): + return { + packet: packet.path + for packet in self.packets + if packet.recieved + } + @property def total(self): return len(self.packets) def __str__(self): - return "recieved: {}, sent: {}, packets: {}".format( + ret = "recieved: {}/{}, delivery ratio: {}, packets: {}, sent: {}, stats: {}, path: {}".format( self.recieved, + self.recieved_count, + self.recieved / len(self.packets), + len(self.packets), self.sent, - self.total + self.stats, + sum([ len(path) for path in self.paths.values() ]) / self.recieved ) + ''' + for packet, path in self.paths.items(): + ret += '\n {}: {}'.format(packet, path) + ''' + return ret class Packet: def __init__(self, id, source, destination, ttl, payload): @@ -260,6 +320,10 @@ class Packet: self.ttl = ttl self.payload = payload + self.path = [] + + self.stats = dict() + self.sent = 0 self.recieved = False @@ -268,7 +332,11 @@ class Packet: self.dropped = False self.dropped_count = 0 - def send(self): + def send(self, a, b, reason=None): + if reason is None: + self.path.append((a.id, b.id)) + else: + self.path.append((a.id, b.id, reason)) self.sent += 1 def drop(self): @@ -280,7 +348,7 @@ class Packet: self.recieved_count += 1 def __str__(self): - return "Packet(id={}, source={}, destination={})".format( + return "Packet(id={}, src={}, dst={})".format( self.id, self.source, self.destination