Statistics
| Branch: | Tag: | Revision:

mininet / mininet / util.py @ 7d4b7b7f

History | View | Annotate | Download (4.88 KB)

1
#!/usr/bin/env python
2

    
3
"Utility functions for Mininet."
4

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

    
10
from mininet.log import lg
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
    check_call( cmd.split( ' ' ) )
21

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

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

    
58
def makeIntfPair( intf1, intf2 ):
59
    """Make a veth pair connecting intf1 and intf2.
60
       intf1: string, interface
61
       intf2: string, interface
62
       returns: success boolean"""
63
    # Delete any old interfaces with the same names
64
    quietRun( 'ip link del ' + intf1 )
65
    quietRun( 'ip link del ' + intf2 )
66
    # Create new pair
67
    cmd = 'ip link add name ' + intf1 + ' type veth peer name ' + intf2
68
    return checkRun( cmd )
69

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

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

    
99
def moveIntf( intf, node, printError=False, retries=3, delaySecs=0.001 ):
100
    """Move interface to node, retrying on failure.
101
       intf: string, interface
102
       node: Node object
103
       printError: if true, print error"""
104
    retry( retries, delaySecs, moveIntfNoRetry, intf, node, printError )
105

    
106
def createLink( node1, node2, retries=10, delaySecs=0.001 ):
107
    """Create a link between nodes, making an interface for each.
108
       node1: Node object
109
       node2: Node object"""
110
    intf1 = node1.newIntf()
111
    intf2 = node2.newIntf()
112
    makeIntfPair( intf1, intf2 )
113
    if node1.inNamespace:
114
        retry( retries, delaySecs, moveIntf, intf1, node1 )
115
    if node2.inNamespace:
116
        retry( retries, delaySecs, moveIntf, intf2, node2 )
117
    node1.connection[ intf1 ] = ( node2, intf2 )
118
    node2.connection[ intf2 ] = ( node1, intf1 )
119
    return intf1, intf2
120

    
121
def fixLimits():
122
    "Fix ridiculously small resource limits."
123
    setrlimit( RLIMIT_NPROC, ( 4096, 8192 ) )
124
    setrlimit( RLIMIT_NOFILE, ( 16384, 32768 ) )
125

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

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

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