Statistics
| Branch: | Tag: | Revision:

mininet / mininet / util.py @ efc9a01c

History | View | Annotate | Download (4.92 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 lg
9

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

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

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

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

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

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

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

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

    
104
def createLink( node1, port1, node2, port2 ):
105
    """Create a link between nodes, making an interface for each.
106
       node1: Node object
107
       port1: node1 port number
108
       node2: Node object
109
       port2: node2 port number
110
       returns: intf1 name, intf2 name"""
111
    intf1 = node1.intfName( port1 )
112
    intf2 = node2.intfName( port2 )
113
    makeIntfPair( intf1, intf2 )
114
    node1.addIntf( intf1, port1 )
115
    node2.addIntf( intf2, port2 )
116
    node1.connect( intf1, node2, intf2 )
117
    node2.connect( 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
       ip: unsigned int of form x << 16 | y << 8 | z
146
       returns: ip address string 10.x.y.z """
147
    hi = ( ip & 0xff0000 ) >> 16
148
    mid = ( ip & 0xff00 ) >> 8
149
    lo = ip & 0xff
150
    return "10.%i.%i.%i" % ( hi, mid, lo )