Statistics
| Branch: | Tag: | Revision:

mininet / mininet / util.py @ 28f46c8d

History | View | Annotate | Download (6.29 KB)

1
"Utility functions for Mininet."
2

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

    
8
from mininet.log import error
9

    
10
# Command execution support
11

    
12
def run( cmd ):
13
    """Simple interface to subprocess.call()
14
       cmd: list of command params"""
15
    return call( cmd.split( ' ' ) )
16

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

    
22
# pylint doesn't understand explicit type checking
23
# pylint: disable-msg=E1103
24

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

    
50
# pylint: enable-msg=E1103
51
# pylint: disable-msg=E1101,W0612
52

    
53
def isShellBuiltin( cmd ):
54
    "Return True if cmd is a bash builtin."
55
    if isShellBuiltin.builtIns is None:
56
        isShellBuiltin.builtIns = quietRun( 'bash -c enable' )
57
    space = cmd.find( ' ' )
58
    if space > 0:
59
        cmd = cmd[ :space]
60
    return cmd in isShellBuiltin.builtIns
61

    
62
isShellBuiltin.builtIns = None
63

    
64
# pylint: enable-msg=E1101,W0612
65

    
66
# Interface management
67
#
68
# Interfaces are managed as strings which are simply the
69
# interface names, of the form 'nodeN-ethM'.
70
#
71
# To connect nodes, we create a pair of veth interfaces, and then place them
72
# in the pair of nodes that we want to communicate. We then update the node's
73
# list of interfaces and connectivity map.
74
#
75
# For the kernel datapath, switch interfaces
76
# live in the root namespace and thus do not have to be
77
# explicitly moved.
78

    
79
def makeIntfPair( intf1, intf2 ):
80
    """Make a veth pair connecting intf1 and intf2.
81
       intf1: string, interface
82
       intf2: string, interface
83
       returns: success boolean"""
84
    # Delete any old interfaces with the same names
85
    quietRun( 'ip link del ' + intf1 )
86
    quietRun( 'ip link del ' + intf2 )
87
    # Create new pair
88
    cmd = 'ip link add name ' + intf1 + ' type veth peer name ' + intf2
89
    return quietRun( cmd )
90

    
91
def retry( retries, delaySecs, fn, *args, **keywords ):
92
    """Try something several times before giving up.
93
       n: number of times to retry
94
       delaySecs: wait this long between tries
95
       fn: function to call
96
       args: args to apply to function call"""
97
    tries = 0
98
    while not fn( *args, **keywords ) and tries < retries:
99
        sleep( delaySecs )
100
        tries += 1
101
    if tries >= retries:
102
        error( "*** gave up after %i retries\n" % tries )
103
        exit( 1 )
104

    
105
def moveIntfNoRetry( intf, node, printError=False ):
106
    """Move interface to node, without retrying.
107
       intf: string, interface
108
       node: Node object
109
       printError: if true, print error"""
110
    cmd = 'ip link set ' + intf + ' netns ' + repr( node.pid )
111
    quietRun( cmd )
112
    links = node.cmd( 'ip link show' )
113
    if not ( ' %s:' % intf ) in links:
114
        if printError:
115
            error( '*** Error: moveIntf: ' + intf +
116
                ' not successfully moved to ' + node.name + '\n' )
117
        return False
118
    return True
119

    
120
def moveIntf( intf, node, printError=False, retries=3, delaySecs=0.001 ):
121
    """Move interface to node, retrying on failure.
122
       intf: string, interface
123
       node: Node object
124
       printError: if true, print error"""
125
    retry( retries, delaySecs, moveIntfNoRetry, intf, node, printError )
126

    
127
def createLink( node1, node2, port1=None, port2=None ):
128
    """Create a link between nodes, making an interface for each.
129
       node1: Node object
130
       node2: Node object
131
       port1: node1 port number (optional)
132
       port2: node2 port number (optional)
133
       returns: intf1 name, intf2 name"""
134
    return node1.linkTo( node2, port1, port2 )
135

    
136

    
137
# IP and Mac address formatting and parsing
138

    
139
def _colonHex( val, count ):
140
    """Generate colon-hex string.
141
       val: input as unsigned int
142
       count: number of bytes to convert
143
       returns: chStr colon-hex string"""
144
    pieces = []
145
    for i in range( count - 1, -1, -1 ):
146
        piece = ( ( 0xff << ( i * 8 ) ) & val ) >> ( i * 8 )
147
        pieces.append( '%02x' % piece )
148
    chStr = ':'.join( pieces )
149
    return chStr
150

    
151
def macColonHex( mac ):
152
    """Generate MAC colon-hex string from unsigned int.
153
       mac: MAC address as unsigned int
154
       returns: macStr MAC colon-hex string"""
155
    return _colonHex( mac, 6 )
156

    
157
def ipStr( ip ):
158
    """Generate IP address string from an unsigned int.
159
       ip: unsigned int of form w << 24 | x << 16 | y << 8 | z
160
       returns: ip address string w.x.y.z, or 10.x.y.z if w==0"""
161
    w = ( ip & 0xff000000 ) >> 24
162
    w = 10 if w == 0 else w
163
    x = ( ip & 0xff0000 ) >> 16
164
    y = ( ip & 0xff00 ) >> 8
165
    z = ip & 0xff
166
    return "%i.%i.%i.%i" % ( w, x, y, z )
167

    
168
def ipNum( w, x, y, z ):
169
    """Generate unsigned int from components ofIP address
170
       returns: w << 24 | x << 16 | y << 8 | z"""
171
    return  ( w << 24 ) | ( x << 16 ) | ( y << 8 ) | z
172

    
173
def ipParse( ip ):
174
    "Parse an IP address and return an unsigned int."
175
    args = [ int( arg ) for arg in ip.split( '.' ) ]
176
    return ipNum( *args )
177

    
178
def checkInt( s ):
179
    "Check if input string is an int"
180
    try:
181
        int( s )
182
        return True
183
    except ValueError:
184
        return False
185

    
186
def checkFloat( s ):
187
    "Check if input string is a float"
188
    try:
189
        float( s )
190
        return True
191
    except ValueError:
192
        return False
193

    
194
def makeNumeric( s ):
195
    "Convert string to int or float if numeric."
196
    if checkInt( s ):
197
        return int( s )
198
    elif checkFloat( s ):
199
        return float( s )
200
    else:
201
        return s
202

    
203

    
204
# Other stuff we use
205

    
206
def fixLimits():
207
    "Fix ridiculously small resource limits."
208
    setrlimit( RLIMIT_NPROC, ( 4096, 8192 ) )
209
    setrlimit( RLIMIT_NOFILE, ( 16384, 32768 ) )