Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e0436642ae | |||
| c5f626ce27 | |||
| 10e758e80a | |||
| de28f67a97 | |||
| 46242acdd4 | |||
| e203808a20 | |||
| 7c0d1506e7 | |||
| c5f23b9f82 | |||
| cfb0a6d3f0 | |||
| 664ba39383 | |||
| 598d694058 | |||
| f92e3d3432 | |||
| ce4f1e0c92 | |||
| 31f44e1856 | |||
| a73e776695 |
@@ -2,7 +2,7 @@
|
||||
Mininet Installation/Configuration Notes
|
||||
----------------------------------------
|
||||
|
||||
Mininet 2.3.0d4
|
||||
Mininet 2.3.0d6
|
||||
---
|
||||
|
||||
The supported installation methods for Mininet are 1) using a
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Mininet 2.3.0d4 License
|
||||
Mininet 2.3.0d6 License
|
||||
|
||||
Copyright (c) 2013-2018 Open Networking Laboratory
|
||||
Copyright (c) 2013-2019 Open Networking Laboratory
|
||||
Copyright (c) 2009-2012 Bob Lantz and The Board of Trustees of
|
||||
The Leland Stanford Junior University
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ Mininet: Rapid Prototyping for Software Defined Networks
|
||||
========================================================
|
||||
*The best way to emulate almost any network on your laptop!*
|
||||
|
||||
Mininet 2.3.0d4
|
||||
Mininet 2.3.0d6
|
||||
|
||||
[![Build Status][1]](https://travis-ci.org/mininet/mininet)
|
||||
|
||||
|
||||
@@ -388,6 +388,10 @@ class MininetRunner( object ):
|
||||
listenPort=opts.listenport )
|
||||
|
||||
if opts.ensure_value( 'nat', False ):
|
||||
with open( '/etc/resolv.conf' ) as f:
|
||||
if 'nameserver 127.' in f.read():
|
||||
warn( '*** Warning: loopback address in /etc/resolv.conf '
|
||||
'may break host DNS over NAT\n')
|
||||
mn.addNAT( *opts.nat_args, **opts.nat_kwargs ).configDefault()
|
||||
|
||||
# --custom files can set CLI or change mininet.cli.CLI
|
||||
|
||||
+18
-22
@@ -295,7 +295,7 @@ class TCIntf( Intf ):
|
||||
netemargs = '%s%s%s%s' % (
|
||||
'delay %s ' % delay if delay is not None else '',
|
||||
'%s ' % jitter if jitter is not None else '',
|
||||
'loss %.5f ' % loss if loss is not None else '',
|
||||
'loss %.5f ' % loss if (loss is not None and loss > 0) else '',
|
||||
'limit %d' % max_queue_size if max_queue_size is not None
|
||||
else '' )
|
||||
if netemargs:
|
||||
@@ -407,7 +407,7 @@ class Link( object ):
|
||||
def __init__( self, node1, node2, port1=None, port2=None,
|
||||
intfName1=None, intfName2=None, addr1=None, addr2=None,
|
||||
intf=Intf, cls1=None, cls2=None, params1=None,
|
||||
params2=None, fast=True ):
|
||||
params2=None, fast=True, **params ):
|
||||
"""Create veth link to another node, making two new interfaces.
|
||||
node1: first node
|
||||
node2: second node
|
||||
@@ -417,18 +417,15 @@ class Link( object ):
|
||||
cls1, cls2: optional interface-specific constructors
|
||||
intfName1: node1 interface name (optional)
|
||||
intfName2: node2 interface name (optional)
|
||||
params1: parameters for interface 1
|
||||
params2: parameters for interface 2"""
|
||||
params1: parameters for interface 1 (optional)
|
||||
params2: parameters for interface 2 (optional)
|
||||
**params: additional parameters for both interfaces"""
|
||||
|
||||
# This is a bit awkward; it seems that having everything in
|
||||
# params is more orthogonal, but being able to specify
|
||||
# in-line arguments is more convenient! So we support both.
|
||||
if params1 is None:
|
||||
params1 = {}
|
||||
if params2 is None:
|
||||
params2 = {}
|
||||
# Allow passing in params1=params2
|
||||
if params2 is params1:
|
||||
params2 = dict( params1 )
|
||||
params1 = dict( params1 ) if params1 else {}
|
||||
params2 = dict( params2 ) if params2 else {}
|
||||
if port1 is not None:
|
||||
params1[ 'port' ] = port1
|
||||
if port2 is not None:
|
||||
@@ -442,6 +439,10 @@ class Link( object ):
|
||||
if not intfName2:
|
||||
intfName2 = self.intfName( node2, params2[ 'port' ] )
|
||||
|
||||
# Update with remaining parameter list
|
||||
params1.update( params )
|
||||
params2.update( params )
|
||||
|
||||
self.fast = fast
|
||||
if fast:
|
||||
params1.setdefault( 'moveIntfFn', self._ignore )
|
||||
@@ -463,6 +464,7 @@ class Link( object ):
|
||||
|
||||
# All we are is dust in the wind, and our two interfaces
|
||||
self.intf1, self.intf2 = intf1, intf2
|
||||
|
||||
# pylint: enable=too-many-branches
|
||||
|
||||
@staticmethod
|
||||
@@ -548,17 +550,11 @@ class OVSLink( Link ):
|
||||
|
||||
|
||||
class TCLink( Link ):
|
||||
"Link with symmetric TC interfaces configured via opts"
|
||||
def __init__( self, node1, node2, port1=None, port2=None,
|
||||
intfName1=None, intfName2=None,
|
||||
addr1=None, addr2=None, **params ):
|
||||
Link.__init__( self, node1, node2, port1=port1, port2=port2,
|
||||
intfName1=intfName1, intfName2=intfName2,
|
||||
cls1=TCIntf,
|
||||
cls2=TCIntf,
|
||||
addr1=addr1, addr2=addr2,
|
||||
params1=params,
|
||||
params2=params )
|
||||
"Link with TC interfaces"
|
||||
def __init__( self, *args, **kwargs):
|
||||
kwargs.setdefault( 'cls1', TCIntf )
|
||||
kwargs.setdefault( 'cls2', TCIntf )
|
||||
Link.__init__( self, *args, **kwargs)
|
||||
|
||||
|
||||
class TCULink( TCLink ):
|
||||
|
||||
+1
-1
@@ -108,7 +108,7 @@ from mininet.util import ( quietRun, fixLimits, numCores, ensureRoot,
|
||||
from mininet.term import cleanUpScreens, makeTerms
|
||||
|
||||
# Mininet version: should be consistent with README and LICENSE
|
||||
VERSION = "2.3.0d4"
|
||||
VERSION = "2.3.0d6"
|
||||
|
||||
class Mininet( object ):
|
||||
"Network emulation with hosts spawned in network namespaces."
|
||||
|
||||
+16
-13
@@ -63,7 +63,7 @@ from time import sleep
|
||||
from mininet.log import info, error, warn, debug
|
||||
from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin,
|
||||
numCores, retry, mountCgroups, BaseString, decode,
|
||||
encode, Python3 )
|
||||
encode, getincrementaldecoder, Python3, which )
|
||||
from mininet.moduledeps import moduleDeps, pathCheck, TUN
|
||||
from mininet.link import Link, Intf, TCIntf, OVSIntf
|
||||
from re import findall
|
||||
@@ -106,6 +106,9 @@ class Node( object ):
|
||||
self.waiting = False
|
||||
self.readbuf = ''
|
||||
|
||||
# Incremental decoder for buffered reading
|
||||
self.decoder = getincrementaldecoder()
|
||||
|
||||
# Start command interpreter shell
|
||||
self.master, self.slave = None, None # pylint
|
||||
self.startShell()
|
||||
@@ -229,19 +232,19 @@ class Node( object ):
|
||||
|
||||
# Subshell I/O, commands and control
|
||||
|
||||
def read( self, maxbytes=1024 ):
|
||||
def read( self, size=1024 ):
|
||||
"""Buffered read from node, potentially blocking.
|
||||
maxbytes: maximum number of bytes to return"""
|
||||
size: maximum number of characters to return"""
|
||||
count = len( self.readbuf )
|
||||
if count < maxbytes:
|
||||
data = decode( os.read( self.stdout.fileno(), maxbytes - count ) )
|
||||
self.readbuf += data
|
||||
if maxbytes >= len( self.readbuf ):
|
||||
if count < size:
|
||||
data = os.read( self.stdout.fileno(), size - count )
|
||||
self.readbuf += self.decoder.decode( data )
|
||||
if size >= len( self.readbuf ):
|
||||
result = self.readbuf
|
||||
self.readbuf = ''
|
||||
else:
|
||||
result = self.readbuf[ :maxbytes ]
|
||||
self.readbuf = self.readbuf[ maxbytes: ]
|
||||
result = self.readbuf[ :size ]
|
||||
self.readbuf = self.readbuf[ size: ]
|
||||
return result
|
||||
|
||||
def readline( self ):
|
||||
@@ -1447,7 +1450,7 @@ class Controller( Node ):
|
||||
@classmethod
|
||||
def isAvailable( cls ):
|
||||
"Is controller available?"
|
||||
return quietRun( 'which controller' )
|
||||
return which( 'controller' )
|
||||
|
||||
|
||||
class OVSController( Controller ):
|
||||
@@ -1459,9 +1462,9 @@ class OVSController( Controller ):
|
||||
|
||||
@classmethod
|
||||
def isAvailable( cls ):
|
||||
return ( quietRun( 'which ovs-controller' ) or
|
||||
quietRun( 'which test-controller' ) or
|
||||
quietRun( 'which ovs-testcontroller' ) ).strip()
|
||||
return (which( 'ovs-controller' ) or
|
||||
which( 'test-controller' ) or
|
||||
which( 'ovs-testcontroller' ))
|
||||
|
||||
class NOX( Controller ):
|
||||
"Controller to run a NOX application."
|
||||
|
||||
+62
-26
@@ -13,23 +13,48 @@ from os import O_NONBLOCK
|
||||
import os
|
||||
from functools import partial
|
||||
import sys
|
||||
import codecs
|
||||
|
||||
# Python 2/3 compatibility
|
||||
|
||||
Python3 = sys.version_info[0] == 3
|
||||
BaseString = str if Python3 else getattr( str, '__base__' )
|
||||
Encoding = 'utf-8' if Python3 else None
|
||||
def decode( s ):
|
||||
"Decode a byte string if needed for Python 3"
|
||||
return s.decode( Encoding ) if Python3 else s
|
||||
def encode( s ):
|
||||
"Encode a byte string if needed for Python 3"
|
||||
return s.encode( Encoding ) if Python3 else s
|
||||
class NullCodec( object ):
|
||||
"Null codec for Python 2"
|
||||
@staticmethod
|
||||
def decode( buf ):
|
||||
"Null decode"
|
||||
return buf
|
||||
|
||||
@staticmethod
|
||||
def encode( buf ):
|
||||
"Null encode"
|
||||
return buf
|
||||
|
||||
|
||||
if Python3:
|
||||
def decode( buf ):
|
||||
"Decode buffer for Python 3"
|
||||
return buf.decode( Encoding )
|
||||
|
||||
def encode( buf ):
|
||||
"Encode buffer for Python 3"
|
||||
return buf.encode( Encoding )
|
||||
getincrementaldecoder = codecs.getincrementaldecoder( Encoding )
|
||||
else:
|
||||
decode, encode = NullCodec.decode, NullCodec.encode
|
||||
|
||||
def getincrementaldecoder():
|
||||
"Return null codec for Python 2"
|
||||
return NullCodec
|
||||
|
||||
try:
|
||||
# pylint: disable=import-error
|
||||
oldpexpect = None
|
||||
import pexpect as oldpexpect
|
||||
# pylint: enable=import-error
|
||||
|
||||
# pylint: enable=import-error
|
||||
class Pexpect( object ):
|
||||
"Custom pexpect that is compatible with str"
|
||||
@staticmethod
|
||||
@@ -119,20 +144,21 @@ def errRun( *cmd, **kwargs ):
|
||||
out, err = '', ''
|
||||
poller = poll()
|
||||
poller.register( popen.stdout, POLLIN )
|
||||
fdtofile = { popen.stdout.fileno(): popen.stdout }
|
||||
fdToFile = { popen.stdout.fileno(): popen.stdout }
|
||||
fdToDecoder = { popen.stdout.fileno(): getincrementaldecoder() }
|
||||
outDone, errDone = False, True
|
||||
if popen.stderr:
|
||||
fdtofile[ popen.stderr.fileno() ] = popen.stderr
|
||||
fdToFile[ popen.stderr.fileno() ] = popen.stderr
|
||||
fdToDecoder[ popen.stderr.fileno() ] = getincrementaldecoder()
|
||||
poller.register( popen.stderr, POLLIN )
|
||||
errDone = False
|
||||
while not outDone or not errDone:
|
||||
readable = poller.poll()
|
||||
for fd, event in readable:
|
||||
f = fdtofile[ fd ]
|
||||
f = fdToFile[ fd ]
|
||||
decoder = fdToDecoder[ fd ]
|
||||
if event & POLLIN:
|
||||
data = f.read( 1024 )
|
||||
if Python3:
|
||||
data = data.decode( Encoding )
|
||||
data = decoder.decode( f.read( 1024 ) )
|
||||
if echo:
|
||||
output( data )
|
||||
if f == popen.stdout:
|
||||
@@ -171,19 +197,26 @@ def quietRun( cmd, **kwargs ):
|
||||
"Run a command and return merged stdout and stderr"
|
||||
return errRun( cmd, stderr=STDOUT, **kwargs )[ 0 ]
|
||||
|
||||
def which(cmd, **kwargs ):
|
||||
"Run a command and return merged stdout and stderr"
|
||||
out, _, ret = errRun( ["which", cmd], stderr=STDOUT, **kwargs )
|
||||
return out.rstrip() if ret == 0 else None
|
||||
|
||||
# pylint: enable=maybe-no-member
|
||||
|
||||
def isShellBuiltin( cmd ):
|
||||
"Return True if cmd is a bash builtin."
|
||||
if isShellBuiltin.builtIns is None:
|
||||
isShellBuiltin.builtIns = quietRun( 'bash -c enable' )
|
||||
isShellBuiltin.builtIns = set(quietRun( 'bash -c enable' ).split())
|
||||
space = cmd.find( ' ' )
|
||||
if space > 0:
|
||||
cmd = cmd[ :space]
|
||||
return cmd in isShellBuiltin.builtIns
|
||||
|
||||
|
||||
isShellBuiltin.builtIns = None
|
||||
|
||||
|
||||
# Interface management
|
||||
#
|
||||
# Interfaces are managed as strings which are simply the
|
||||
@@ -370,7 +403,7 @@ def netParse( ipstr ):
|
||||
if '/' in ipstr:
|
||||
ip, pf = ipstr.split( '/' )
|
||||
prefixLen = int( pf )
|
||||
#if no prefix is specified, set the prefix to 24
|
||||
# if no prefix is specified, set the prefix to 24
|
||||
else:
|
||||
ip = ipstr
|
||||
prefixLen = 24
|
||||
@@ -413,9 +446,11 @@ def pmonitor(popens, timeoutms=500, readline=True,
|
||||
terminates: when all EOFs received"""
|
||||
poller = poll()
|
||||
fdToHost = {}
|
||||
fdToDecoder = {}
|
||||
for host, popen in popens.items():
|
||||
fd = popen.stdout.fileno()
|
||||
fdToHost[ fd ] = host
|
||||
fdToDecoder[ fd ] = getincrementaldecoder()
|
||||
poller.register( fd, POLLIN | POLLHUP )
|
||||
flags = fcntl( fd, F_GETFL )
|
||||
fcntl( fd, F_SETFL, flags | O_NONBLOCK )
|
||||
@@ -424,13 +459,14 @@ def pmonitor(popens, timeoutms=500, readline=True,
|
||||
if fds:
|
||||
for fd, event in fds:
|
||||
host = fdToHost[ fd ]
|
||||
decoder = fdToDecoder[ fd ]
|
||||
popen = popens[ host ]
|
||||
if event & POLLIN or event & POLLHUP:
|
||||
while True:
|
||||
try:
|
||||
f = popen.stdout
|
||||
line = decode( f.readline() if readline
|
||||
else f.read( readmax ) )
|
||||
line = decoder.decode( f.readline() if readline
|
||||
else f.read( readmax ) )
|
||||
except IOError:
|
||||
line = ''
|
||||
if line == '':
|
||||
@@ -445,19 +481,19 @@ def pmonitor(popens, timeoutms=500, readline=True,
|
||||
# Other stuff we use
|
||||
def sysctlTestAndSet( name, limit ):
|
||||
"Helper function to set sysctl limits"
|
||||
#convert non-directory names into directory names
|
||||
# convert non-directory names into directory names
|
||||
if '/' not in name:
|
||||
name = '/proc/sys/' + name.replace( '.', '/' )
|
||||
#read limit
|
||||
# read limit
|
||||
with open( name, 'r' ) as readFile:
|
||||
oldLimit = readFile.readline()
|
||||
if isinstance( limit, int ):
|
||||
#compare integer limits before overriding
|
||||
# compare integer limits before overriding
|
||||
if int( oldLimit ) < limit:
|
||||
with open( name, 'w' ) as writeFile:
|
||||
writeFile.write( "%d" % limit )
|
||||
else:
|
||||
#overwrite non-integer limits
|
||||
# overwrite non-integer limits
|
||||
with open( name, 'w' ) as writeFile:
|
||||
writeFile.write( limit )
|
||||
|
||||
@@ -474,21 +510,21 @@ def fixLimits():
|
||||
try:
|
||||
rlimitTestAndSet( RLIMIT_NPROC, 8192 )
|
||||
rlimitTestAndSet( RLIMIT_NOFILE, 16384 )
|
||||
#Increase open file limit
|
||||
# Increase open file limit
|
||||
sysctlTestAndSet( 'fs.file-max', 10000 )
|
||||
#Increase network buffer space
|
||||
# Increase network buffer space
|
||||
sysctlTestAndSet( 'net.core.wmem_max', 16777216 )
|
||||
sysctlTestAndSet( 'net.core.rmem_max', 16777216 )
|
||||
sysctlTestAndSet( 'net.ipv4.tcp_rmem', '10240 87380 16777216' )
|
||||
sysctlTestAndSet( 'net.ipv4.tcp_wmem', '10240 87380 16777216' )
|
||||
sysctlTestAndSet( 'net.core.netdev_max_backlog', 5000 )
|
||||
#Increase arp cache size
|
||||
# Increase arp cache size
|
||||
sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh1', 4096 )
|
||||
sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh2', 8192 )
|
||||
sysctlTestAndSet( 'net.ipv4.neigh.default.gc_thresh3', 16384 )
|
||||
#Increase routing table size
|
||||
# Increase routing table size
|
||||
sysctlTestAndSet( 'net.ipv4.route.max_size', 32768 )
|
||||
#Increase number of PTYs for nodes
|
||||
# Increase number of PTYs for nodes
|
||||
sysctlTestAndSet( 'kernel.pty.max', 20000 )
|
||||
# pylint: disable=broad-except
|
||||
except Exception:
|
||||
|
||||
+1
-1
@@ -409,7 +409,7 @@ function ovs {
|
||||
# Switch can run on its own, but
|
||||
# Mininet should control the controller
|
||||
# This appears to only be an issue on Ubuntu/Debian
|
||||
if sudo service $OVSC stop; then
|
||||
if sudo service $OVSC stop 2>/dev/null; then
|
||||
echo "Stopped running controller"
|
||||
fi
|
||||
if [ -e /etc/init.d/$OVSC ]; then
|
||||
|
||||
Reference in New Issue
Block a user