Statistics
| Branch: | Revision:

wcn_emulator / network_builder.py @ b1497c9f

History | View | Annotate | Download (8.58 KB)

1
import re
2
import networkx as nx
3
import graph_utils as gu
4

    
5
from mininet.net import Mininet
6
from mininet.node import OVSController
7
from mininet.node import CPULimitedHost
8
from mininet.link import TCLink
9
from mininet.log import info, debug
10

    
11

    
12
class PowerNet(Mininet):
13
    def __init__(self, **params):
14
        if 'controller' not in params.keys():
15
            params['controller'] = OVSController
16
        if 'host' not in params.keys():
17
            params['host'] = CPULimitedHost
18
        if 'link' not in params.keys():
19
            params['link'] = TCLink
20
        super(PowerNet, self).__init__(**params)
21

    
22
    def enableForwarding(self):
23
        for node in self.values():
24
            node.cmd("echo 1 > /proc/sys/net/ipv4/ip_forward")
25

    
26
    def setNeighboursRoutes(self):
27
        for node in self.values():
28
            for intf in node.intfList():
29
                if intf.link:
30
                    rintf = self.remoteIntf(intf)
31
                    raddrs = self.getNodeAddrs(rintf.node)
32
                    for addr in raddrs:
33
                        node.setHostRoute(addr, intf.name)
34

    
35
    def getNodeAddrs(self, node):
36
        r = []
37
        for intf in node.intfList():
38
            if intf.link and intf.ip:
39
                r.append(intf.ip)
40
        return r
41

    
42
    def remoteIntf(self, intf):
43
        if intf.link:
44
            intfs = [intf.link.intf1, intf.link.intf2]
45
            intfs.remove(intf)
46
            return intfs[0]
47
        return None
48

    
49
    def getLinks(self):
50
        # returns the hosts couples representing the links
51
        links = []
52
        hosts = self.values()
53
        for h in hosts:
54
            intfs = h.intfList()
55
            for intf in intfs:
56
                if intf.link and intf.link not in links:
57
                    links.append(intf.link)
58
        return links
59

    
60
    def linkSentPackets(self, link):
61
        pstr1 = link.intf1.node.cmd("ifconfig ", link.intf1.name, "| grep -Eo \
62
                                    'TX packets:[0-9]+' | cut -d':' -f 2")
63
        pstr2 = link.intf2.node.cmd("ifconfig ", link.intf2.name, "| grep -Eo \
64
                                    'TX packets:[0-9]+' | cut -d':' -f 2")
65
        packets1 = int(pstr1.split("\n")[0])
66
        packets2 = int(pstr2.split("\n")[0])
67
        return packets1+packets2
68

    
69
    def linkSentBytes(self, link):
70
        pstr1 = link.intf1.node.cmd("ifconfig ", link.intf1.name, "| grep -Eo\
71
                                    'TX bytes:[0-9]+' | cut -d':' -f 2")
72
        pstr2 = link.intf2.node.cmd("ifconfig ", link.intf2.name, "| grep -Eo\
73
                                    'TX bytes:[0-9]+' | cut -d':' -f 2")
74
        bytes1 = int(pstr1.split("\n")[0].split(" ")[0])
75
        bytes2 = int(pstr2.split("\n")[0].split(" ")[0])
76
        return bytes2+bytes1
77

    
78
    def hostSentPackets(self, host):
79
        sent_packets = 0
80
        sent_bytes = 0
81
        intfs = host.intfNames()
82
        for intf in intfs:
83
            host.cmd("ifconfig", intf, "| grep -Eo 'TX bytes:[0-9]+' | \
84
                     cut -d':' -f 2")
85
            sent_bytes += int(re.findall(r'\d+', host.cmd("ifconfig", intf, "| grep -Eo 'TX bytes:[0-9]+' | cut -d':' -f 2"))[0])
86
            sent_packets += int(re.findall(r'\d+', host.cmd("ifconfig ", intf, "| grep -Eo 'TX packets:[0-9]+' | cut -d':' -f 2"))[0])
87
        return (sent_packets, sent_bytes)
88

    
89
    def hostReceivedPackets(self, host):
90
        received_packets = 0
91
        received_bytes = 0
92
        intfs = host.intfNames()
93
        for intf in intfs:
94
            received_bytes += int(re.findall(r'\d+', host.cmd("ifconfig " + intf + " | grep -Eo 'RX bytes:[0-9]+' | cut -d':' -f 2"))[0])
95
            received_packets += int(re.findall(r'\d+', host.cmd("ifconfig " + intf + " | grep -Eo 'RX packets:[0-9]+' | cut -d':' -f 2"))[0])
96
        return (received_packets, received_bytes)
97

    
98
    def sentPackets(self):
99
        # if you experience assertion errors, you should
100
        # try to make sleep the mininet thread for a second
101
        sent_packets = 0
102
        sent_bytes = 0
103
        hosts = self.values()
104
        for h in hosts:
105
            p, b = self.hostSentPackets(h)
106
            sent_packets += p
107
            sent_bytes += b
108
        return (sent_packets, sent_bytes)
109

    
110

    
111
class GraphNet(PowerNet):
112
    def __init__(self, edges_file, draw=True, **params):
113
        if "link_opts" in params.keys():
114
            self.link_opts = params["link_opts"]
115
            del params["link_opts"]
116

    
117
        super(GraphNet, self).__init__(**params)
118
        info("\nReading "+edges_file+"\n")
119

    
120
        g = gu.loadGraph(edges_file, connected=True)
121

    
122
        nodeCounter = 0
123
        nodeMap = {}
124
        # mininet bails if host names are longer than 10 chars
125
        max_name_len = 10 - len(str(len(g))) - 2
126
        for name in g.nodes():
127
            # remove unprintable chars from name
128
            nodeMap[name] = "h" + filter(str.isalnum, str(name))[-max_name_len:]\
129
                            + "_" + str(nodeCounter)
130
            nodeCounter += 1
131

    
132
        self.gg = nx.relabel_nodes(g, nodeMap)
133

    
134
        self.hosts_port = {}
135

    
136
        # add nodes
137
        for n in self.gg.nodes():
138
            self.addHost(n)
139
            self.hosts_port[n] = 1
140

    
141
        # add edges
142
        for e in self.gg.edges(data=True):
143
            # 10 Mbps, 5ms delay, 10% loss, 1000 packet queue
144
            # htp: Hierarchical Token Bucket rate limiter
145
            quality_params = {}
146
            quality_params.update(self.link_opts)
147
            # quality_params["bw"] = 10
148
            # quality_params["delay"] = '0.515ms'
149
            # quality_params["jitter"] = '0.284ms'
150
            # quality_params["delay_distribution"] = 'wifi_m0.515_s0.284'
151
            if "loss" in quality_params.keys():
152
                if quality_params["loss"] == "wifi_loss":
153
                    quality_params["loss"] = \
154
                        100*((1-(1.0/(e[2]['weight'])))**7)
155
                else:
156
                    quality_params["loss"] = float(quality_params["loss"])
157
            # the number of retransmisison (4) derives from a parameter of the
158
            # 802.11 standard: dot11LongRetryLink (for Long Packets, are longer
159
            # than dot11RTSthreshold)
160
            quality_params["use_htb"] = True
161
            self.insertLink(self.get(e[0]), self.get(e[1]), quality_params)
162

    
163
        if draw:
164
            nx.draw(self.gg)
165

    
166
    def pickHostAddrPort(self, node):
167
        port = self.hosts_port[node.name]
168
        addr = "10.0."+node.name.split('_')[-1]+"."+str(port)+"/8"
169
        self.hosts_port[node.name] += 1
170
        return addr, port
171

    
172
    def insertLink(self, n1, n2, quality_params={}):
173
        addr1, port1 = self.pickHostAddrPort(n1)
174
        addr2, port2 = self.pickHostAddrPort(n2)
175
        self.addLink(n1, n2,
176
                     port1=port1,
177
                     port2=port2,
178
                     params1=dict([('ip', addr1)] + quality_params.items()),
179
                     params2=dict([('ip', addr2)] + quality_params.items()))
180

    
181
    def setShortestRoutes(self):
182
        paths = nx.all_pairs_dijkstra_path(self.gg, weight='weight')
183
        for node1 in paths.keys():
184
            host1 = self.get(node1)
185
            debug("Starting node: "+node1+'\n')
186
            debug("\tpaths: "+str(paths[node1])+'\n')
187
            for node2 in paths[node1].keys():
188
                if node2 != node1:
189
                    if len(paths[node1][node2]) > 2:
190
                        debug("\tDestination node: "+node2+'\n')
191
                        nextHop = self.get(paths[node1][node2][1])
192
                        debug("\tNextHop node: "+nextHop.name+'\n')
193
                        dsts = self.getNodeAddrs(self.get(node2))
194
                        intfs = host1.connectionsTo(nextHop)
195
                        nextAddrs = [couple[1].ip
196
                                     for couple in intfs if couple[1].ip]
197
                        rintf = intfs[0][0]  # WARNING we just consider one link
198
                        for dst in dsts:
199
                            for addr in nextAddrs:
200
                                debug("\tip route add "+str(dst) +
201
                                      " via " + str(addr)+'\n')
202
                                host1.cmd("ip route add " + dst +
203
                                          " via " + addr + " dev "+rintf.name)
204
                                debug("\tip route add " + dst +
205
                                      " via " + addr + '\n')
206
                    else:
207
                        host2 = self.get(node2)
208
                        intfs = [couple[0]
209
                                 for couple in host1.connectionsTo(host2)]
210
                        rintf = intfs[0]  # WARNING we just consider one link
211
                        raddrs = self.getNodeAddrs(host2)
212
                        for addr in raddrs:
213
                            host1.setHostRoute(addr, rintf.name)