Revision 80a8fa62 mininet/util.py

View differences:

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

  
4 4
from time import sleep
5 5
from resource import setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE
......
8 8

  
9 9
from mininet.log import lg
10 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)
11
def run( cmd ):
12
    """Simple interface to subprocess.call()
13
       cmd: list of command params"""
14
    return call( cmd.split( ' ' ) )
15

  
16
def checkRun( cmd ):
17
    """Simple interface to subprocess.check_call()
18
       cmd: list of command params"""
19
    check_call( cmd.split( ' ' ) )
20

  
21
def quietRun( cmd ):
22
    """Run a command, routing stderr to stdout, and return the output.
23
       cmd: list of command params"""
24
    if isinstance( cmd, str ):
25
        cmd = cmd.split( ' ' )
26
    popen = Popen( cmd, stdout=PIPE, stderr=STDOUT )
36 27
    # We can't use Popen.communicate() because it uses
37 28
    # select(), which can't handle
38 29
    # high file descriptor numbers! poll() can, however.
39 30
    output = ''
40 31
    readable = select.poll()
41
    readable.register(popen.stdout)
32
    readable.register( popen.stdout )
42 33
    while True:
43 34
        while readable.poll():
44
            data = popen.stdout.read(1024)
45
            if len(data) == 0:
35
            data = popen.stdout.read( 1024 )
36
            if len( data ) == 0:
46 37
                break
47 38
            output += data
48 39
        popen.poll()
......
50 41
            break
51 42
    return output
52 43

  
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 44
# Interface management
90 45
#
91 46
# Interfaces are managed as strings which are simply the
......
99 54
# live in the root namespace and thus do not have to be
100 55
# explicitly moved.
101 56

  
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
    '''
57
def makeIntfPair( intf1, intf2 ):
58
    """Make a veth pair connecting intf1 and intf2.
59
       intf1: string, interface
60
       intf2: string, interface
61
       returns: success boolean"""
110 62
    # Delete any old interfaces with the same names
111
    quietRun('ip link del ' + intf1)
112
    quietRun('ip link del ' + intf2)
63
    quietRun( 'ip link del ' + intf1 )
64
    quietRun( 'ip link del ' + intf2 )
113 65
    # Create new pair
114 66
    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')
67
    return checkRun( cmd )
68

  
69
def retry( retries, delaySecs, fn, *args, **keywords ):
70
    """Try something several times before giving up.
71
       n: number of times to retry
72
       delaySecs: wait this long between tries
73
       fn: function to call
74
       args: args to apply to function call"""
75
    tries = 0
76
    while not fn( *args, **keywords ) and tries < retries:
77
        sleep( delaySecs )
78
        tries += 1
79
    if tries >= retries:
80
        lg.error( "*** gave up after %i retries\n" % tries )
81
        exit( 1 )
82

  
83
def moveIntfNoRetry( intf, node, printError=False ):
84
    """Move interface to node, without retrying.
85
       intf: string, interface
86
       node: Node object
87
       printError: if true, print error"""
88
    cmd = 'ip link set ' + intf + ' netns ' + repr( node.pid )
89
    quietRun( cmd )
90
    links = node.cmd( 'ip link show' )
128 91
    if not intf in links:
129
        if print_error:
130
            lg.error('*** Error: moveIntf: % not successfully moved to %s:\n' %
131
                     (intf, node.name))
92
        if printError:
93
            lg.error( '*** Error: moveIntf: ' + intf +
94
                ' not successfully moved to ' + node.name + '\n' )
132 95
        return False
133 96
    return True
134 97

  
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
    '''
98
def moveIntf( intf, node, printError=False, retries=3, delaySecs=0.001 ):
99
    """Move interface to node, retrying on failure.
100
       intf: string, interface
101
       node: Node object
102
       printError: if true, print error"""
103
    retry( retries, delaySecs, moveIntf, intf, node, printError )
104

  
105
def createLink( node1, node2, retries=10, delaySecs=0.001 ):
106
    """Create a link between nodes, making an interface for each.
107
       node1: Node object
108
       node2: Node object"""
165 109
    intf1 = node1.newIntf()
166 110
    intf2 = node2.newIntf()
167
    makeIntfPair(intf1, intf2)
111
    makeIntfPair( intf1, intf2 )
168 112
    if node1.inNamespace:
169
        retry(CREATE_LINK_RETRIES, MOVEINTF_DELAY, moveIntf, intf1, node1)
113
        retry( retries, delaySecs, moveIntf, intf1, node1 )
170 114
    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)
115
        retry( retries, delaySecs, moveIntf, intf2, node2 )
116
    node1.connection[ intf1 ] = ( node2, intf2 )
117
    node2.connection[ intf2 ] = ( node1, intf1 )
174 118
    return intf1, intf2
175 119

  
176

  
177 120
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
    '''
121
    "Fix ridiculously small resource limits."
122
    setrlimit( RLIMIT_NPROC, ( 4096, 8192 ) )
123
    setrlimit( RLIMIT_NOFILE, ( 16384, 32768 ) )
124

  
125
def _colonHex( val, bytes ):
126
    """Generate colon-hex string.
127
       val: input as unsigned int
128
       bytes: number of bytes to convert
129
       returns: chStr colon-hex string"""
190 130
    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
131
    for i in range( bytes - 1, -1, -1 ):
132
        piece = ( ( 0xff << ( i * 8 ) ) & val ) >> ( i * 8 )
133
        pieces.append( '%02x' % piece )
134
    chStr = ':'.join( pieces )
135
    return chStr
136

  
137
def macColonHex( mac ):
138
    """Generate MAC colon-hex string from unsigned int.
139
       mac: MAC address as unsigned int
140
       returns: macStr MAC colon-hex string"""
141
    return _colonHex( mac, 6 )
142

  
143
def ipStr( ip ):
144
    """Generate IP address string
145
       returns: ip addr string"""
146
    hi = ( ip & 0xff0000 ) >> 16
147
    mid = ( ip & 0xff00 ) >> 8
213 148
    lo = ip & 0xff
214
    return "10.%i.%i.%i" % (hi, mid, lo)
149
    return "10.%i.%i.%i" % ( hi, mid, lo )

Also available in: Unified diff