Statistics
| Branch: | Tag: | Revision:

mininet / mininet / util.py @ 281f6e59

History | View | Annotate | Download (4.88 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.log import lg
10

    
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 )
27
    # We can't use Popen.communicate() because it uses
28
    # select(), which can't handle
29
    # high file descriptor numbers! poll() can, however.
30
    output = ''
31
    readable = select.poll()
32
    readable.register( popen.stdout )
33
    while True:
34
        while readable.poll():
35
            data = popen.stdout.read( 1024 )
36
            if len( data ) == 0:
37
                break
38
            output += data
39
        popen.poll()
40
        if popen.returncode != None:
41
            break
42
    return output
43

    
44
# Interface management
45
#
46
# Interfaces are managed as strings which are simply the
47
# interface names, of the form 'nodeN-ethM'.
48
#
49
# To connect nodes, we create a pair of veth interfaces, and then place them
50
# in the pair of nodes that we want to communicate. We then update the node's
51
# list of interfaces and connectivity map.
52
#
53
# For the kernel datapath, switch interfaces
54
# live in the root namespace and thus do not have to be
55
# explicitly moved.
56

    
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"""
62
    # Delete any old interfaces with the same names
63
    quietRun( 'ip link del ' + intf1 )
64
    quietRun( 'ip link del ' + intf2 )
65
    # Create new pair
66
    cmd = 'ip link add name ' + intf1 + ' type veth peer name ' + intf2
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' )
91
    if not intf in links:
92
        if printError:
93
            lg.error( '*** Error: moveIntf: ' + intf +
94
                ' not successfully moved to ' + node.name + '\n' )
95
        return False
96
    return True
97

    
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, moveIntfNoRetry, 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"""
109
    intf1 = node1.newIntf()
110
    intf2 = node2.newIntf()
111
    makeIntfPair( intf1, intf2 )
112
    if node1.inNamespace:
113
        retry( retries, delaySecs, moveIntf, intf1, node1 )
114
    if node2.inNamespace:
115
        retry( retries, delaySecs, moveIntf, intf2, node2 )
116
    node1.connection[ intf1 ] = ( node2, intf2 )
117
    node2.connection[ intf2 ] = ( node1, intf1 )
118
    return intf1, intf2
119

    
120
def fixLimits():
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"""
130
    pieces = []
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
148
    lo = ip & 0xff
149
    return "10.%i.%i.%i" % ( hi, mid, lo )