Statistics
| Branch: | Tag: | Revision:

mininet / mininet / util.py @ 54037995

History | View | Annotate | Download (5.64 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.logging_mod import lg
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)
36
    # We can't use Popen.communicate() because it uses
37
    # select(), which can't handle
38
    # high file descriptor numbers! poll() can, however.
39
    output = ''
40
    readable = select.poll()
41
    readable.register(popen.stdout)
42
    while True:
43
        while readable.poll():
44
            data = popen.stdout.read(1024)
45
            if len(data) == 0:
46
                break
47
            output += data
48
        popen.poll()
49
        if popen.returncode != None:
50
            break
51
    return output
52

    
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
# Interface management
90
#
91
# Interfaces are managed as strings which are simply the
92
# interface names, of the form 'nodeN-ethM'.
93
#
94
# To connect nodes, we create a pair of veth interfaces, and then place them
95
# in the pair of nodes that we want to communicate. We then update the node's
96
# list of interfaces and connectivity map.
97
#
98
# For the kernel datapath, switch interfaces
99
# live in the root namespace and thus do not have to be
100
# explicitly moved.
101

    
102
def makeIntfPair(intf1, intf2):
103
    '''Make a veth pair.
104

105
    @param intf1 string, interface
106
    @param intf2 string, interface
107
    @return success boolean
108
    '''
109
    # Delete any old interfaces with the same names
110
    quietRun('ip link del ' + intf1)
111
    quietRun('ip link del ' + intf2)
112
    # Create new pair
113
    cmd = 'ip link add name ' + intf1 + ' type veth peer name ' + intf2
114
    return checkRun( cmd )
115

    
116

    
117
def moveIntf(intf, node, print_error = False):
118
    '''Move interface to node.
119

120
    @param intf string, interface
121
    @param node Node object
122
    @param print_error if true, print error
123
    '''
124
    cmd = 'ip link set ' + intf + ' netns ' + repr(node.pid)
125
    quietRun(cmd)
126
    links = node.cmd('ip link show')
127
    if not intf in links:
128
        if print_error:
129
            lg.error('*** Error: moveIntf: % not successfully moved to %s:\n' %
130
                     (intf, node.name))
131
        return False
132
    return True
133

    
134

    
135
def retry(n, retry_delay, fn, *args):
136
    '''Try something N times before giving up.
137

138
    @param n number of times to retry
139
    @param retry_delay seconds wait this long between tries
140
    @param fn function to call
141
    @param args args to apply to function call
142
    '''
143
    tries = 0
144
    while not apply(fn, args) and tries < n:
145
        sleep(retry_delay)
146
        tries += 1
147
    if tries >= n:
148
        lg.error("*** gave up after %i retries\n" % tries)
149
        exit( 1 )
150

    
151

    
152
# delay between interface move checks in seconds
153
MOVEINTF_DELAY = 0.0001
154

    
155
CREATE_LINK_RETRIES = 10
156

    
157
def createLink(node1, node2):
158
    '''Create a link between nodes, making an interface for each.
159

160
    @param node1 Node object
161
    @param node2 Node object
162
    '''
163
    intf1 = node1.newIntf()
164
    intf2 = node2.newIntf()
165
    makeIntfPair(intf1, intf2)
166
    if node1.inNamespace:
167
        retry(CREATE_LINK_RETRIES, MOVEINTF_DELAY, moveIntf, intf1, node1)
168
    if node2.inNamespace:
169
        retry(CREATE_LINK_RETRIES, MOVEINTF_DELAY, moveIntf, intf2, node2)
170
    node1.connection[intf1] = (node2, intf2)
171
    node2.connection[intf2] = (node1, intf1)
172
    return intf1, intf2
173

    
174

    
175
def fixLimits():
176
    '''Fix ridiculously small resource limits.'''
177
    setrlimit( RLIMIT_NPROC, (4096, 8192))
178
    setrlimit( RLIMIT_NOFILE, (16384, 32768))
179

    
180

    
181
def _colonHex(val, bytes):
182
    '''Generate colon-hex string.
183

184
    @param val input as unsigned int
185
    @param bytes number of bytes to convert
186
    @return ch_str colon-hex string
187
    '''
188
    pieces = []
189
    for i in range (bytes - 1, -1, -1):
190
        pieces.append('%02x' % (((0xff << (i * 8)) & val) >> (i * 8)))
191
    ch_str = ':'.join(pieces)
192
    return ch_str
193

    
194

    
195
def macColonHex(mac):
196
    '''Generate MAC colon-hex string from unsigned int.
197

198
    @param mac MAC address as unsigned int
199
    @return mac_str MAC colon-hex string
200
    '''
201
    return _colonHex(mac, 6)
202

    
203

    
204
def ipStr(ip):
205
    '''Generate IP address string
206

207
    @return ip addr string
208
    '''
209
    hi = (ip & 0xff0000) >> 16
210
    mid = (ip & 0xff00) >> 8
211
    lo = ip & 0xff
212
    return "10.%i.%i.%i" % (hi, mid, lo)