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
157
158
159
160
161
162
163
164
165
166
167
168
169
|
import yaml, os
import numpy as np
class UnitsParser:
def range(r,limit):
if r == "all":
return(range(0,limit))
elt=r.replace("@",str(limit-1)).split("-")
if len(elt) == 2:
min = int(elt[0])
max = int(elt[1])
# TODO: Check min/max
return(range(min,max))
else:
return([int(elt[0])])
def bandwidth(bw):
for i,c in enumerate(bw):
if not c.isdigit() and c != ".":
break
number=float(bw[:i])
unit=bw[i:]
number=number*1000 if unit == "Mbps" else number
number=number*1000*8 if unit == "MBps" else number
number=number*100 if unit == "kbps" else number
number=number*100*8 if unit == "kBps" else number
number=number*8 if unit == "Bps" else number
return(number)
def latency(lat):
for i,c in enumerate(lat):
if not c.isdigit() and c != ".":
break
number=float(lat[:i])
unit=lat[i:]
number=number*60 if unit in ["m","M"] else number
number=number*3600 if unit in ["h","H"] else number
number=number/1000 if unit in ["ms","MS"] else number
return(number)
class YAMLPlatformFile:
def __init__(self, file_path):
self.file_path=file_path
self.default={
"breakpoints": [],
"breakpoints_every": None,
"debug": False,
"interferences": True,
"node_count": 0,
"implementations": [],
"interfaces": dict()
}
with open(file_path) as f:
self.platform = yaml.load(f, Loader=yaml.FullLoader)
##### General
if "general" in self.platform:
self.parse_general()
##### Nodes
if "nodes" in self.platform:
self.parse_nodes()
else:
self.parsing_error("platform file has no nodes section")
##### Interfaces
if "interfaces" in self.platform:
self.parse_interfaces()
else:
self.parsing_error("platform file has no interfaces section")
def parsing_error(self,msg):
raise Exception("Fail to parse platform file \""+self.file_path+"\": "+msg)
def parse_link(self,link):
words=link.split()
if len(words) == 4:
return((
UnitsParser.range(words[0],self.default["node_count"]),
UnitsParser.bandwidth(words[1]),
UnitsParser.latency(words[2]),
UnitsParser.range(words[3],self.default["node_count"])))
elif len(words) == 2:
return((
range(0,self.default["node_count"]),
UnitsParser.bandwidth(words[0]),
UnitsParser.latency(words[1]),
range(0,self.default["node_count"])))
return(None)
def parse_txperf(self,txperf):
elts=txperf.split()
return((UnitsParser.bandwidth(elts[0]),UnitsParser.latency(elts[1])))
def parse_interfaces(self):
interfaces=self.platform["interfaces"]
node_count=self.default["node_count"]
for i in interfaces:
is_wired=not interfaces[i]["wireless"]
links=list()
if type(interfaces[i]["links"]) == list:
for link in interfaces[i]["links"]:
links.append(self.parse_link(link))
else:
links.append(self.parse_link(interfaces[i]["links"]))
##### Create network matrix
BW=np.full((node_count,node_count),0)
LAT=np.full((node_count,node_count),0)
for link in links:
for n1 in link[0]:
for n2 in link[3]:
BW[n1][n2]=link[1]
LAT[n1][n2]=link[2]
##### Set txperfs for wireless interfaces
if not is_wired:
txperfs=interfaces[i]["txperfs"]
for node in range(0,node_count):
txperf=txperfs[0] if len(txperfs) == 1 else txperfs[node]
bw,lat=self.parse_txperf(txperf)
BW[node][node]=bw
LAT[node][node]=lat
self.default["interfaces"][i]={
"is_wired": is_wired,
"bandwidth": BW,
"latency": LAT
}
def parse_nodes(self):
nodes=self.platform["nodes"]
if "count" in nodes:
if not str(nodes["count"]).isnumeric():
self.parsing_error("node count should be a number")
self.default["node_count"]=nodes["count"]
if "implementations" in nodes:
if type(nodes["implementations"]) != list:
self.parsing_error("nodes implementations should be a list of file path")
for file in nodes["implementations"]:
if not os.path.exists(file):
self.parsing_error("File "+file+ " not found")
path, extension = os.path.splitext(file)
if extension != ".py":
self.parsing_error("File "+file+" must be a python file")
self.default["implementations"].append(path)
count = len(nodes["implementations"])
if count > 1 and count != self.default["node_count"]:
self.parsing_error("If more than one implementation is specified, each node implementation should be provided ("+str(self.default["node_count"])+" in total)")
def parse_general(self):
general=self.platform["general"]
if "breakpoints" in general:
if type(general["breakpoints"]) != list:
self.parsing_error("breakpoints should be a list of number")
self.default["breakpoints"]=general["breakpoints"]
if "breakpoints_every" in general:
if not str(general["breakpoints_every"]).isnumeric():
self.parsing_error("breakpoints_every should be a number")
self.default["breakpoints_every"]=general["breakpoints_every"]
if "debug" in general:
if type(general["debug"]) != bool:
self.parsing_error("debug should be on or off")
self.default["debug"]=general["debug"]
if "interferences" in general:
if type(general["interferences"]) != bool:
self.parsing_error("interferences should be on or off")
self.default["interferences"]=general["interferences"]
|