Statistics
| Branch: | Revision:

wcn_emulator / network_builder.py @ 2fd1c362

History | View | Annotate | Download (8.64 KB)

1
import re
2
import networkx as nx
3
import graph_utils as gu
4
import matplotlib.pyplot as plt
5

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

    
12

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

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

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

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

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

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

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

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

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

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

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

    
111

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

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

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

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

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

    
135
        self.hosts_port = {}
136

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

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

    
164
        if draw:
165
            nx.draw(self.gg)
166
            plt.show()
167

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

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

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