Statistics
| Branch: | Tag: | Revision:

mininet / mininet / util.py @ 723d068c

History | View | Annotate | Download (5.65 KB)

1
#!/usr/bin/env python
2
'''Utility functions for Mininet.'''
3

    
4
from time import sleep
5
from resource import setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE
6
import select
7
from subprocess import call, check_call, Popen, PIPE, STDOUT
8

    
9
from mininet.logging_mod import lg
10

    
11

    
12
def run(cmd):
13
    '''Simple interface to subprocess.call()
14

15
     @param cmd list of command params
16
    '''
17
    return call(cmd.split(' '))
18

    
19

    
20
def checkRun(cmd):
21
    '''Simple interface to subprocess.check_call()
22

23
    @param cmd list of command params
24
    '''
25
    check_call(cmd.split(' '))
26

    
27

    
28
def quietRun(cmd):
29
    '''Run a command, routing stderr to stdout, and return the output.
30

31
    @param cmd list of command params
32
    '''
33
    if isinstance(cmd, str):
34
        cmd = cmd.split(' ')
35
    popen = Popen(cmd, stdout=PIPE, stderr=STDOUT)
36
    # We can't use Popen.communicate() because it uses
37
    # select(), which can't handle
38
    # high file descriptor numbers! poll() can, however.
39
    output = ''
40
    readable = select.poll()
41
    readable.register(popen.stdout)
42
    while True:
43
        while readable.poll():
44
            data = popen.stdout.read(1024)
45
            if len(data) == 0:
46
                break
47
            output += data
48
        popen.poll()
49
        if popen.returncode != None:
50
            break
51
    return output
52

    
53

    
54
def make_veth_pair(intf1, intf2):
55
    '''Create a veth pair connecting intf1 and intf2.
56

57
    @param intf1 string, interface name
58
    @param intf2 string, interface name
59
    '''
60
    # Delete any old interfaces with the same names
61
    quietRun('ip link del ' + intf1)
62
    quietRun('ip link del ' + intf2)
63
    # Create new pair
64
    cmd = 'ip link add name ' + intf1 + ' type veth peer name ' + intf2
65
    #lg.info('running command: %s\n' % cmd)
66
    return checkRun(cmd)
67

    
68

    
69
def move_intf(intf, node):
70
    '''Move interface to node.
71

72
    @param intf string interface name
73
    @param node Node object
74

75
    @return success boolean, did operation complete?
76
    '''
77
    cmd = 'ip link set ' + intf + ' netns ' + repr(node.pid)
78
    #lg.info('running command: %s\n' % cmd)
79
    quietRun(cmd)
80
    #lg.info(' output: %s\n' % output)
81
    links = node.cmd('ip link show')
82
    if not intf in links:
83
        lg.error('*** Error: move_intf: %s not successfully moved to %s:\n' %
84
                 (intf, node.name))
85
        return False
86
    return True
87

    
88

    
89
# Interface management
90
#
91
# Interfaces are managed as strings which are simply the
92
# interface names, of the form 'nodeN-ethM'.
93
#
94
# To connect nodes, we create a pair of veth interfaces, and then place them
95
# in the pair of nodes that we want to communicate. We then update the node's
96
# list of interfaces and connectivity map.
97
#
98
# For the kernel datapath, switch interfaces
99
# live in the root namespace and thus do not have to be
100
# explicitly moved.
101

    
102

    
103
def makeIntfPair(intf1, intf2):
104
    '''Make a veth pair.
105

106
    @param intf1 string, interface
107
    @param intf2 string, interface
108
    @return success boolean
109
    '''
110
    # Delete any old interfaces with the same names
111
    quietRun('ip link del ' + intf1)
112
    quietRun('ip link del ' + intf2)
113
    # Create new pair
114
    cmd = 'ip link add name ' + intf1 + ' type veth peer name ' + intf2
115
    return checkRun(cmd)
116

    
117

    
118
def moveIntf(intf, node, print_error = False):
119
    '''Move interface to node.
120

121
    @param intf string, interface
122
    @param node Node object
123
    @param print_error if true, print error
124
    '''
125
    cmd = 'ip link set ' + intf + ' netns ' + repr(node.pid)
126
    quietRun(cmd)
127
    links = node.cmd('ip link show')
128
    if not intf in links:
129
        if print_error:
130
            lg.error('*** Error: moveIntf: % not successfully moved to %s:\n' %
131
                     (intf, node.name))
132
        return False
133
    return True
134

    
135

    
136
def retry(n, retry_delay, fn, *args, **keywords):
137
    '''Try something N times before giving up.
138

139
    @param n number of times to retry
140
    @param retry_delay seconds wait this long between tries
141
    @param fn function to call
142
    @param args args to apply to function call
143
    '''
144
    tries = 0
145
    while not fn(*args, **keywords) and tries < n:
146
        sleep(retry_delay)
147
        tries += 1
148
    if tries >= n:
149
        lg.error("*** gave up after %i retries\n" % tries)
150
        exit(1)
151

    
152

    
153
# delay between interface move checks in seconds
154
MOVEINTF_DELAY = 0.0001
155

    
156
CREATE_LINK_RETRIES = 10
157

    
158

    
159
def createLink(node1, node2):
160
    '''Create a link between nodes, making an interface for each.
161

162
    @param node1 Node object
163
    @param node2 Node object
164
    '''
165
    intf1 = node1.newIntf()
166
    intf2 = node2.newIntf()
167
    makeIntfPair(intf1, intf2)
168
    if node1.inNamespace:
169
        retry(CREATE_LINK_RETRIES, MOVEINTF_DELAY, moveIntf, intf1, node1)
170
    if node2.inNamespace:
171
        retry(CREATE_LINK_RETRIES, MOVEINTF_DELAY, moveIntf, intf2, node2)
172
    node1.connection[intf1] = (node2, intf2)
173
    node2.connection[intf2] = (node1, intf1)
174
    return intf1, intf2
175

    
176

    
177
def fixLimits():
178
    '''Fix ridiculously small resource limits.'''
179
    setrlimit(RLIMIT_NPROC, (4096, 8192))
180
    setrlimit(RLIMIT_NOFILE, (16384, 32768))
181

    
182

    
183
def _colonHex(val, bytes):
184
    '''Generate colon-hex string.
185

186
    @param val input as unsigned int
187
    @param bytes number of bytes to convert
188
    @return ch_str colon-hex string
189
    '''
190
    pieces = []
191
    for i in range(bytes - 1, -1, -1):
192
        pieces.append('%02x' % (((0xff << (i * 8)) & val) >> (i * 8)))
193
    ch_str = ':'.join(pieces)
194
    return ch_str
195

    
196

    
197
def macColonHex(mac):
198
    '''Generate MAC colon-hex string from unsigned int.
199

200
    @param mac MAC address as unsigned int
201
    @return mac_str MAC colon-hex string
202
    '''
203
    return _colonHex(mac, 6)
204

    
205

    
206
def ipStr(ip):
207
    '''Generate IP address string
208

209
    @return ip addr string
210
    '''
211
    hi = (ip & 0xff0000) >> 16
212
    mid = (ip & 0xff00) >> 8
213
    lo = ip & 0xff
214
    return "10.%i.%i.%i" % (hi, mid, lo)