Files
mininet/mininet/util.py
T
Brandon Heller 376bcba442 Add options for auto MAC and ARP setup.
Auto MAC setup sets each host MAC equal to its DPID, which simplifies
debugging.

Auto ARP setup removes the need for broadcast support for ARP, which
enables a smaller NOX controller.
2010-01-03 09:16:14 -08:00

200 lines
5.4 KiB
Python

#!/usr/bin/env python
'''Utility functions for Mininet.'''
from time import sleep
from resource import setrlimit, RLIMIT_NPROC, RLIMIT_NOFILE
import select
from subprocess import call, check_call, Popen, PIPE, STDOUT
from mininet.logging_mod import lg
def run(cmd):
'''Simple interface to subprocess.call()
@param cmd list of command params
'''
return call(cmd.split(' '))
def checkRun(cmd):
'''Simple interface to subprocess.check_call()
@param cmd list of command params
'''
check_call(cmd.split(' '))
def quietRun(cmd):
'''Run a command, routing stderr to stdout, and return the output.
@param cmd list of command params
'''
if isinstance(cmd, str):
cmd = cmd.split(' ')
popen = Popen(cmd, stdout=PIPE, stderr=STDOUT)
# We can't use Popen.communicate() because it uses
# select(), which can't handle
# high file descriptor numbers! poll() can, however.
output = ''
readable = select.poll()
readable.register(popen.stdout)
while True:
while readable.poll():
data = popen.stdout.read(1024)
if len(data) == 0:
break
output += data
popen.poll()
if popen.returncode != None:
break
return output
def make_veth_pair(intf1, intf2):
'''Create a veth pair connecting intf1 and intf2.
@param intf1 string, interface name
@param intf2 string, interface name
'''
# Delete any old interfaces with the same names
quietRun('ip link del ' + intf1)
quietRun('ip link del ' + intf2)
# Create new pair
cmd = 'ip link add name ' + intf1 + ' type veth peer name ' + intf2
#lg.info('running command: %s\n' % cmd)
return checkRun(cmd)
def move_intf(intf, node):
'''Move interface to node.
@param intf string interface name
@param node Node object
@return success boolean, did operation complete?
'''
cmd = 'ip link set ' + intf + ' netns ' + repr(node.pid)
#lg.info('running command: %s\n' % cmd)
quietRun(cmd)
#lg.info(' output: %s\n' % output)
links = node.cmd('ip link show')
if not intf in links:
lg.error('*** Error: move_intf: %s not successfully moved to %s:\n' %
(intf, node.name))
return False
return True
# Interface management
#
# Interfaces are managed as strings which are simply the
# interface names, of the form 'nodeN-ethM'.
#
# To connect nodes, we create a pair of veth interfaces, and then place them
# in the pair of nodes that we want to communicate. We then update the node's
# list of interfaces and connectivity map.
#
# For the kernel datapath, switch interfaces
# live in the root namespace and thus do not have to be
# explicitly moved.
def makeIntfPair(intf1, intf2):
'''Make a veth pair.
@param intf1 string, interface
@param intf2 string, interface
@return success boolean
'''
# Delete any old interfaces with the same names
quietRun('ip link del ' + intf1)
quietRun('ip link del ' + intf2)
# Create new pair
cmd = 'ip link add name ' + intf1 + ' type veth peer name ' + intf2
return checkRun( cmd )
def moveIntf(intf, node, print_error = False):
'''Move interface to node.
@param intf string, interface
@param node Node object
@param print_error if true, print error
'''
cmd = 'ip link set ' + intf + ' netns ' + repr(node.pid)
quietRun(cmd)
links = node.cmd('ip link show')
if not intf in links:
if print_error:
lg.error('*** Error: moveIntf: % not successfully moved to %s:\n' %
(intf, node.name))
return False
return True
def retry(n, retry_delay, fn, *args):
'''Try something N times before giving up.
@param n number of times to retry
@param retry_delay seconds wait this long between tries
@param fn function to call
@param args args to apply to function call
'''
tries = 0
while not apply(fn, args) and tries < n:
sleep(retry_delay)
tries += 1
if tries >= n:
lg.error("*** gave up after %i retries\n" % tries)
exit( 1 )
# delay between interface move checks in seconds
MOVEINTF_DELAY = 0.0001
CREATE_LINK_RETRIES = 10
def createLink(node1, node2):
'''Create a link between nodes, making an interface for each.
@param node1 Node object
@param node2 Node object
'''
intf1 = node1.newIntf()
intf2 = node2.newIntf()
makeIntfPair(intf1, intf2)
if node1.inNamespace:
retry(CREATE_LINK_RETRIES, MOVEINTF_DELAY, moveIntf, intf1, node1)
if node2.inNamespace:
retry(CREATE_LINK_RETRIES, MOVEINTF_DELAY, moveIntf, intf2, node2)
node1.connection[intf1] = (node2, intf2)
node2.connection[intf2] = (node1, intf1)
return intf1, intf2
def fixLimits():
'''Fix ridiculously small resource limits.'''
setrlimit( RLIMIT_NPROC, (4096, 8192))
setrlimit( RLIMIT_NOFILE, (16384, 32768))
def macColonHex(mac):
'''Generate MAC colon-hex string from unsigned int.
@param mac MAC address as unsigned int
@return mac_str MAC colon-hex string
'''
mac_pieces = []
for i in range (5, -1, -1):
mac_pieces.append('%02x' % (((0xff << (i * 8)) & mac) >> (i * 8)))
mac_str = ':'.join(mac_pieces)
return mac_str
def ipStr(ip):
'''Generate IP address string
@return ip addr string
'''
hi = (ip & 0xff0000) >> 16
mid = (ip & 0xff00) >> 8
lo = ip & 0xff
return "10.%i.%i.%i" % (hi, mid, lo)