-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathrouter.py
156 lines (132 loc) · 5.73 KB
/
router.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
from packet import Packet, RoutingUpdatePacket
import random
class Router(object):
def __init__(self, env, router_id, update_interval):
"""
Attributes:
env:
main environment
router_id:
id of router
links:
a dict of {link_id: link object}
host_links:
a dict of {link_id: host_id}, if the link connects to a host
routing_table:
a dict of {node_id: link_id}
min_dists:
the min cost from the router to other nodes.
a dict of {node_id: dist}
links_to_dists:
the min cost from the router using a link to other nodes.
a dict of {link_id: a dict of {node_id: dist}}
links_update_timestamp:
stores the last time a link sends over routingUpdatePacket
a dict of {link_id: timestamp}
update_interval:
the update_interval for updating the dynamic routing.
"""
self.env = env
self.id = router_id
self.links = {}
self.host_links = {}
self.routing_table = {}
self.min_dists = {}
self.links_to_dists = {}
self.links_update_timestamp = {}
self.update_interval = update_interval
env.process(self.dynamic_routing(self.env))
def get_id(self):
"""Returns host ID."""
return self.id
def add_link(self, link):
"""Adding one link to the router. """
self.links[link.get_id()] = link
self.links_update_timestamp[link.get_id()] = None
def add_host(self, host):
"""Adding a host to the link. """
hid = host.get_id()
lid = host.link.get_id()
self.host_links[lid] = hid
self.min_dists[hid] = 0
self.routing_table[hid] = lid
self.links_to_dists[lid] = {hid: 0}
def remove_link(self, link_id):
"""Remove a link from the router. """
if link_id in self.links:
del self.links[link_id]
def add_static_routing(self, routing_table):
"""Inserts environment-configured routing table. Not currently
supported due to dynamic programming."""
self.routing_table = routing_table
def process_routing_packet(self, packet):
"""Processes a routing packet.
Args:
packet:
a RoutingUpdatePacket
"""
# RoutingUpdatePackt has source of link_id
lid = packet.get_source()
link = self.links[lid]
link_cost = link.get_weight()
link_dists = packet.get_distance_estimates()
# Updating the distances between the router and other nodes using this
# specific link. Also add the current link_cost on the link_dist.
self.links_to_dists[lid] = {nid: link_cost + link_dists[nid]
for nid in link_dists}
self.links_update_timestamp[lid] = self.env.now
self.update_table()
def update_table(self):
"""Refreshes routing table based on information in links_to_dists.
Broadcasts routing information if min_dists changes."""
min_dists = {}
for lid in self.links:
# Set dist to host as 0 and lid as forwarding link.
if lid in self.host_links:
min_dists[self.host_links[lid]] = 0
self.routing_table[self.host_links[lid]] = lid
# Only update with infomation sent within two update_interval times.
elif ((lid in self.links_to_dists) and
(self.links_update_timestamp[lid] + 2 * self.update_interval
>= self.env.now)):
cur_dists = self.links_to_dists[lid]
for nid in cur_dists:
if (not nid in min_dists or cur_dists[nid] < min_dists[nid]):
min_dists[nid] = cur_dists[nid]
self.routing_table[nid] = lid
change = self.min_dists != min_dists
self.min_dists = min_dists
# Broadcast to neighbors if min_dists has changed.
if change:
# Broadcast every part to let routing converge at first
if self.env.now < 500:
self.broadcast_dists()
# Broadcast 1/10 of the packets to avoid overflowing the links
# in the later stage
elif random.randint(0, 10) == 1:
self.broadcast_dists()
def broadcast_dists(self):
"""Broadcasts min_dists to all adjacent non-host devices."""
for lid in self.links:
# Only broadcast to non-host links
if not lid in self.host_links:
packet = RoutingUpdatePacket(lid, -1, -1, self.env.now, 0,
self.min_dists)
self.links[lid].enqueue(packet, self.id)
def dynamic_routing(self, env):
"""Initializes dynamic routing after every update_interval time."""
while True:
self.broadcast_dists()
yield env.timeout(self.update_interval)
self.update_table()
def receive_packet(self, packet):
""" Receives a packet. """
# Process RoutingUpdatePackets.
if packet.get_packet_type() == Packet.PacketTypes.routing_update_packet:
self.process_routing_packet(packet)
# Immediately forward all other packets.
else:
dest = packet.get_destination()
if (dest in self.routing_table and
self.routing_table[dest] is not None):
self.links[self.routing_table[dest]].enqueue(packet, self.id)