Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 008f62f6ce | |||
| f33a8f0eea |
@@ -2,7 +2,7 @@
|
||||
Mininet Installation/Configuration Notes
|
||||
----------------------------------------
|
||||
|
||||
Mininet 2.3.0rc1
|
||||
Mininet 2.3.0b2
|
||||
---
|
||||
|
||||
The supported installation methods for Mininet are 1) using a
|
||||
@@ -137,7 +137,9 @@ like to contribute an installation script, we would welcome it!)
|
||||
|
||||
This takes about 4 minutes on our test system.
|
||||
|
||||
3.2. (Experimental) Native installation from source on Fedora:
|
||||
3.2. Native installation from source on Fedora 18+.
|
||||
|
||||
*This may be out of date.*
|
||||
|
||||
As root execute the following operations:
|
||||
|
||||
@@ -145,6 +147,18 @@ like to contribute an installation script, we would welcome it!)
|
||||
|
||||
yum install git
|
||||
|
||||
* create an user account (e.g. mininet) and add it to the wheel group
|
||||
|
||||
useradd [...] mininet
|
||||
usermod -a -G wheel mininet
|
||||
|
||||
* change the SElinux setting to permissive. It can be done
|
||||
temporarily with:
|
||||
|
||||
setenforce 0
|
||||
|
||||
then login with the new account (e.g. mininet) and do the following:
|
||||
|
||||
* clone the Mininet repository
|
||||
|
||||
git clone git://github.com/mininet/mininet.git
|
||||
@@ -163,10 +177,7 @@ like to contribute an installation script, we would welcome it!)
|
||||
|
||||
sudo mn --test pingall
|
||||
|
||||
Note that `install.sh -fnv `may not install all dependencies on Fedora,
|
||||
and many tests may still fail.
|
||||
|
||||
4. Creating your own Mininet/OpenFlow tutorial VM on Ubuntu/Debian
|
||||
4. Creating your own Mininet/OpenFlow tutorial VM
|
||||
|
||||
Creating your own Ubuntu Mininet VM for use with the OpenFlow tutorial
|
||||
is easy! First, create a new Ubuntu VM. Next, run two commands in it:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Mininet 2.3.0rc1 License
|
||||
Mininet 2.3.0b2 License
|
||||
|
||||
Copyright (c) 2013-2020 Open Networking Foundation
|
||||
Copyright (c) 2009-2012 Bob Lantz and The Board of Trustees of
|
||||
|
||||
@@ -56,8 +56,6 @@ install-manpages: $(MANPAGES)
|
||||
install -D -t $(MANDIR) $(MANPAGES)
|
||||
|
||||
install: install-mnexec install-manpages
|
||||
# This seems to work on all pip versions
|
||||
$(PYTHON) -m pip uninstall mininet || true
|
||||
$(PYTHON) -m pip install .
|
||||
|
||||
develop: $(MNEXEC) $(MANPAGES)
|
||||
|
||||
@@ -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.0rc1
|
||||
Mininet 2.3.0b2
|
||||
|
||||
[![Build Status][1]](https://github.com/mininet/mininet/actions)
|
||||
|
||||
@@ -70,7 +70,7 @@ Mininet includes:
|
||||
|
||||
### Python 3 Support
|
||||
|
||||
- Mininet 2.3.0rc1 supports Python 3 and Python 2!
|
||||
- Mininet 2.3.0b2 supports Python 3 and Python 2!
|
||||
|
||||
- You can install both the Python 3 and Python 2 versions of
|
||||
Mininet side by side, but the most recent installation will
|
||||
@@ -84,7 +84,7 @@ determine which Python version is used by default by `mn`.
|
||||
|
||||
- More information regarding Python 3 and Python 2 support
|
||||
may be found in the release notes on http://docs.mininet.org.
|
||||
|
||||
|
||||
### Other Enhancements and Information
|
||||
|
||||
- Support for Ubuntu 20.04 LTS (and 18.04 and 16.04)
|
||||
@@ -117,7 +117,7 @@ Mininet mailing list, `mininet-discuss` at:
|
||||
|
||||
### Join Us
|
||||
|
||||
Thanks again to all of the Mininet contributors and users!
|
||||
Thanks again to all of the Mininet contributors!
|
||||
|
||||
Mininet is an open source project and is currently hosted
|
||||
at <https://github.com/mininet>. You are encouraged to download
|
||||
@@ -129,10 +129,10 @@ hard work that Mininet continues to grow and improve.
|
||||
|
||||
### Enjoy Mininet
|
||||
|
||||
Have fun! We look forward to seeing what you will do with Mininet
|
||||
Have fun! We look forward to seeing what you will do with Mininet
|
||||
to change the networking world.
|
||||
|
||||
Bob Lantz,
|
||||
Bob Lantz
|
||||
on behalf of the Mininet Contributors
|
||||
|
||||
[1]: https://github.com/mininet/mininet/workflows/mininet-tests/badge.svg
|
||||
|
||||
@@ -290,9 +290,6 @@ class MininetRunner( object ):
|
||||
help='prints the version and exits' )
|
||||
opts.add_option( '--wait', '-w', action='store_true',
|
||||
default=False, help='wait for switches to connect' )
|
||||
opts.add_option( '--twait', '-t', action='store', type='int',
|
||||
dest='wait',
|
||||
help='timed wait (s) for switches to connect' )
|
||||
opts.add_option( '--cluster', type='string', default=None,
|
||||
metavar='server1,server2...',
|
||||
help=( 'run on multiple servers (experimental!)' ) )
|
||||
|
||||
+830
-1936
File diff suppressed because it is too large
Load Diff
+31
-57
@@ -89,7 +89,7 @@ from mininet.link import Link, Intf
|
||||
from mininet.net import Mininet
|
||||
from mininet.topo import LinearTopo
|
||||
from mininet.topolib import TreeTopo
|
||||
from mininet.util import quietRun, errRun, decode
|
||||
from mininet.util import quietRun, errRun
|
||||
from mininet.examples.clustercli import CLI
|
||||
from mininet.log import setLogLevel, debug, info, error
|
||||
from mininet.clean import addCleanupCallback
|
||||
@@ -247,7 +247,7 @@ class RemoteMixin( object ):
|
||||
result = ''
|
||||
while True:
|
||||
poll = popen.poll()
|
||||
result += decode( popen.stdout.read() )
|
||||
result += popen.stdout.read()
|
||||
if poll is not None:
|
||||
break
|
||||
return result
|
||||
@@ -440,16 +440,13 @@ class RemoteLink( Link ):
|
||||
# When we receive the character '@', it means that our
|
||||
# tunnel should be set up
|
||||
debug( 'Waiting for tunnel to come up...\n' )
|
||||
ch = decode( tunnel.stdout.read( 1 ) )
|
||||
ch = tunnel.stdout.read( 1 )
|
||||
if ch != '@':
|
||||
ch += decode( tunnel.stdout.read() )
|
||||
cmd = ' '.join( cmd )
|
||||
raise Exception( 'makeTunnel:\n'
|
||||
'Tunnel setup failed for '
|
||||
'%s:%s' % ( node1, node1.dest ) + ' to '
|
||||
'%s:%s\n' % ( node2, node2.dest ) +
|
||||
'command was: %s' % cmd + '\n' +
|
||||
'result was: ' + ch )
|
||||
raise Exception( 'makeTunnel:\n',
|
||||
'Tunnel setup failed for',
|
||||
'%s:%s' % ( node1, node1.dest ), 'to',
|
||||
'%s:%s\n' % ( node2, node2.dest ),
|
||||
'command was:', cmd, '\n' )
|
||||
# 3. Move interfaces if necessary
|
||||
for node in node1, node2:
|
||||
if not self.moveIntf( 'tap9', node ):
|
||||
@@ -851,37 +848,27 @@ class MininetCluster( Mininet ):
|
||||
if cfile:
|
||||
config.setdefault( 'controlPath', cfile )
|
||||
|
||||
@staticmethod
|
||||
def isLoopback( ipaddr ):
|
||||
"Is ipaddr an IPv4 loopback address?"
|
||||
return ipaddr.startswith( '127.' )
|
||||
|
||||
# pylint: disable=arguments-differ,signature-differs
|
||||
def addController( self, *args, **kwargs ):
|
||||
"Patch to update IP address to global IP address"
|
||||
controller = Mininet.addController( self, *args, **kwargs )
|
||||
controllerIP = controller.IP()
|
||||
loopback = '127.0.0.1'
|
||||
if ( not isinstance( controller, Controller ) or
|
||||
not self.isLoopback( controller.IP() ) ):
|
||||
return controller
|
||||
controller.IP() != loopback ):
|
||||
return None
|
||||
# Find route to a different server IP address
|
||||
serverIPs = [ ip for ip in self.serverIP.values()
|
||||
if ip != controllerIP ]
|
||||
if ip is not controller.IP() ]
|
||||
if not serverIPs:
|
||||
return None # no remote servers - loopback is fine
|
||||
for remoteIP in serverIPs:
|
||||
# Route should contain 'dev <intfname>'
|
||||
route = controller.cmd( 'ip route get', remoteIP,
|
||||
r'| egrep -o "dev\s[^[:space:]]+"' )
|
||||
if not route:
|
||||
raise Exception('addController: no route from', controller,
|
||||
'to', remoteIP )
|
||||
intf = route.split()[ 1 ].strip()
|
||||
if intf != 'lo':
|
||||
break
|
||||
if intf == 'lo':
|
||||
raise Exception( 'addController: could not find external '
|
||||
'interface/IP for %s' % controller )
|
||||
remoteIP = serverIPs[ 0 ]
|
||||
# Route should contain 'dev <intfname>'
|
||||
route = controller.cmd( 'ip route get', remoteIP,
|
||||
r'| egrep -o "dev\s[^[:space:]]+"' )
|
||||
if not route:
|
||||
raise Exception('addController: no route from', controller,
|
||||
'to', remoteIP )
|
||||
intf = route.split()[ 1 ].strip()
|
||||
debug( 'adding', intf, 'to', controller )
|
||||
Intf( intf, node=controller ).updateIP()
|
||||
debug( controller, 'IP address updated to', controller.IP() )
|
||||
@@ -896,10 +883,7 @@ class MininetCluster( Mininet ):
|
||||
Mininet.buildFromTopo( self, *args, **kwargs )
|
||||
|
||||
|
||||
# Default remote server for tests
|
||||
remoteServer = 'ubuntu2'
|
||||
|
||||
def testNsTunnels( remote=remoteServer, link=RemoteGRELink ):
|
||||
def testNsTunnels( remote='ubuntu2', link=RemoteGRELink ):
|
||||
"Test tunnels between nodes in namespaces"
|
||||
net = Mininet( host=RemoteHost, link=link, waitConnected=True )
|
||||
h1 = net.addHost( 'h1')
|
||||
@@ -914,14 +898,14 @@ def testNsTunnels( remote=remoteServer, link=RemoteGRELink ):
|
||||
# This shows how node options may be used to manage
|
||||
# cluster placement using the net.add*() API
|
||||
|
||||
def testRemoteNet( remote=remoteServer, link=RemoteGRELink ):
|
||||
def testRemoteNet( remote='ubuntu2', link=RemoteGRELink ):
|
||||
"Test remote Node classes"
|
||||
info( '*** Remote Node Test\n' )
|
||||
net = Mininet( host=RemoteHost, switch=RemoteOVSSwitch,
|
||||
link=link, controller=ClusterController,
|
||||
net = Mininet( host=RemoteHost, switch=RemoteOVSSwitch, link=link,
|
||||
waitConnected=True )
|
||||
c0 = net.addController( 'c0' )
|
||||
# Make sure controller knows its non-loopback address
|
||||
Intf( 'eth0', node=c0 ).updateIP()
|
||||
info( "*** Creating local h1\n" )
|
||||
h1 = net.addHost( 'h1' )
|
||||
info( "*** Creating remote h2\n" )
|
||||
@@ -953,7 +937,7 @@ def testRemoteNet( remote=remoteServer, link=RemoteGRELink ):
|
||||
|
||||
remoteHosts = [ 'h2' ]
|
||||
remoteSwitches = [ 's2' ]
|
||||
|
||||
remoteServer = 'ubuntu2'
|
||||
|
||||
def HostPlacer( name, *args, **params ):
|
||||
"Custom Host() constructor which places hosts on servers"
|
||||
@@ -970,21 +954,10 @@ def SwitchPlacer( name, *args, **params ):
|
||||
return RemoteOVSSwitch( name, *args, **params )
|
||||
|
||||
def ClusterController( *args, **kwargs):
|
||||
"Custom Controller() constructor which updates its intf IP address"
|
||||
intf = kwargs.pop( 'intf', '' )
|
||||
"Custom Controller() constructor which updates its eth0 IP address"
|
||||
controller = Controller( *args, **kwargs )
|
||||
# Find out its IP address so that cluster switches can connect
|
||||
if not intf:
|
||||
output = controller.cmd(
|
||||
r"ip a | egrep -o '\w+:\s\w+'" ).split( '\n' )
|
||||
for line in output:
|
||||
intf = line.split()[ -1 ]
|
||||
if intf != 'lo':
|
||||
break
|
||||
if intf == 'lo':
|
||||
raise Exception( 'Could not find non-loopback interface'
|
||||
'for %s' % controller )
|
||||
Intf( intf, node=controller ).updateIP()
|
||||
Intf( 'eth0', node=controller ).updateIP()
|
||||
return controller
|
||||
|
||||
def testRemoteTopo( link=RemoteGRELink ):
|
||||
@@ -1001,7 +974,7 @@ def testRemoteTopo( link=RemoteGRELink ):
|
||||
# do random switch placement rather than completely random
|
||||
# host placement.
|
||||
|
||||
def testRemoteSwitches( remote=remoteServer, link=RemoteGRELink ):
|
||||
def testRemoteSwitches( remote='ubuntu2', link=RemoteGRELink ):
|
||||
"Test with local hosts and remote switches"
|
||||
servers = [ 'localhost', remote]
|
||||
topo = TreeTopo( depth=4, fanout=2 )
|
||||
@@ -1019,7 +992,7 @@ def testRemoteSwitches( remote=remoteServer, link=RemoteGRELink ):
|
||||
# functions, for maximum ease of use. MininetCluster() also
|
||||
# pre-flights and multiplexes server connections.
|
||||
|
||||
def testMininetCluster( remote=remoteServer, link=RemoteGRELink ):
|
||||
def testMininetCluster( remote='ubuntu2', link=RemoteGRELink ):
|
||||
"Test MininetCluster()"
|
||||
servers = [ 'localhost', remote ]
|
||||
topo = TreeTopo( depth=3, fanout=3 )
|
||||
@@ -1029,7 +1002,7 @@ def testMininetCluster( remote=remoteServer, link=RemoteGRELink ):
|
||||
net.pingAll()
|
||||
net.stop()
|
||||
|
||||
def signalTest( remote=remoteServer):
|
||||
def signalTest( remote='ubuntu2'):
|
||||
"Make sure hosts are robust to signals"
|
||||
h = RemoteHost( 'h0', server=remote )
|
||||
h.shell.send_signal( SIGINT )
|
||||
@@ -1044,6 +1017,7 @@ def signalTest( remote=remoteServer):
|
||||
|
||||
if __name__ == '__main__':
|
||||
setLogLevel( 'info' )
|
||||
remoteServer = 'ubuntu2'
|
||||
remoteLink = RemoteSSHLink
|
||||
testRemoteTopo(link=remoteLink)
|
||||
testNsTunnels( remote=remoteServer, link=remoteLink )
|
||||
|
||||
@@ -2703,13 +2703,14 @@ class MiniEdit( Frame ):
|
||||
tags = self.canvas.gettags(item)
|
||||
if 'Controller' in tags:
|
||||
# remove from switch controller lists
|
||||
for searchwidget in self.widgetToItem:
|
||||
name = searchwidget[ 'text' ]
|
||||
tags = self.canvas.gettags( self.widgetToItem[ searchwidget ] )
|
||||
for serachwidget in self.widgetToItem:
|
||||
name = serachwidget[ 'text' ]
|
||||
tags = self.canvas.gettags( self.widgetToItem[ serachwidget ] )
|
||||
if 'Switch' in tags:
|
||||
if widget['text'] in self.switchOpts[name]['controllers']:
|
||||
self.switchOpts[name]['controllers'].remove(widget['text'])
|
||||
for link in tuple( widget.links.values() ):
|
||||
|
||||
for link in widget.links.values():
|
||||
# Delete from view and model
|
||||
self.deleteItem( link )
|
||||
del self.itemToWidget[ item ]
|
||||
|
||||
+1
-9
@@ -89,15 +89,7 @@ class CLI( Cmd ):
|
||||
if os.path.isfile( history_path ):
|
||||
read_history_file( history_path )
|
||||
set_history_length( 1000 )
|
||||
|
||||
def writeHistory():
|
||||
"Write out history file"
|
||||
try:
|
||||
write_history_file( history_path )
|
||||
except IOError:
|
||||
# Ignore probably spurious IOError
|
||||
pass
|
||||
atexit.register( writeHistory )
|
||||
atexit.register( lambda: write_history_file( history_path ) )
|
||||
|
||||
def run( self ):
|
||||
"Run our cmdloop(), catching KeyboardInterrupt"
|
||||
|
||||
+7
-9
@@ -109,7 +109,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.0rc1"
|
||||
VERSION = "2.3.0b2"
|
||||
|
||||
class Mininet( object ):
|
||||
"Network emulation with hosts spawned in network namespaces."
|
||||
@@ -137,9 +137,7 @@ class Mininet( object ):
|
||||
autoStaticArp: set all-pairs static MAC addrs?
|
||||
autoPinCpus: pin hosts to (real) cores (requires CPULimitedHost)?
|
||||
listenPort: base listening port to open; will be incremented for
|
||||
each additional switch in the net if inNamespace=False
|
||||
waitConnected: wait for switches to Connect?
|
||||
(False; True/None=wait indefinitely; time(s)=timed wait)"""
|
||||
each additional switch in the net if inNamespace=False"""
|
||||
self.topo = topo
|
||||
self.switch = switch
|
||||
self.host = host
|
||||
@@ -177,9 +175,10 @@ class Mininet( object ):
|
||||
if topo and build:
|
||||
self.build()
|
||||
|
||||
def waitConnected( self, timeout=None, delay=.5 ):
|
||||
"""wait for each switch to connect to a controller
|
||||
timeout: time to wait, or None or True to wait indefinitely
|
||||
def waitConnected( self, timeout=5, delay=.5 ):
|
||||
"""wait for each switch to connect to a controller,
|
||||
up to 5 seconds
|
||||
timeout: time to wait, or None to wait indefinitely
|
||||
delay: seconds to sleep per iteration
|
||||
returns: True if all switches are connected"""
|
||||
info( '*** Waiting for switches to connect\n' )
|
||||
@@ -193,8 +192,7 @@ class Mininet( object ):
|
||||
if not remaining:
|
||||
info( '\n' )
|
||||
return True
|
||||
# Still allow None to preserve 2.2 behavior
|
||||
if timeout not in ( None, True ) and time > timeout:
|
||||
if timeout is not None and time > timeout:
|
||||
break
|
||||
sleep( delay )
|
||||
time += delay
|
||||
|
||||
+20
-14
@@ -1505,26 +1505,32 @@ class NOX( Controller ):
|
||||
|
||||
Controller.__init__( self, name,
|
||||
command=noxCoreDir + '/nox_core',
|
||||
cargs='--libdir=/usr/local/lib -v '
|
||||
'-i ptcp:%s ' +
|
||||
cargs='--libdir=/usr/local/lib -v -i ptcp:%s ' +
|
||||
' '.join( noxArgs ),
|
||||
cdir=noxCoreDir,
|
||||
**kwargs )
|
||||
|
||||
class Ryu( Controller ):
|
||||
"Ryu OpenFlow Controller"
|
||||
def __init__( self, name, ryuArgs='ryu.app.simple_switch',
|
||||
command='ryu run', **kwargs ):
|
||||
"Controller to run Ryu application"
|
||||
def __init__( self, name, *ryuArgs, **kwargs ):
|
||||
"""Init.
|
||||
name: name to give controller.
|
||||
ryuArgs: modules to pass to Ryu (ryu.app.simple_switch)
|
||||
command: comand to run Ryu ('ryu run')"""
|
||||
if isinstance( ryuArgs, ( list, tuple ) ):
|
||||
ryuArgs = ' '.join( ryuArgs )
|
||||
cargs = kwargs.pop(
|
||||
'cargs', ryuArgs + ' --ofp-tcp-listen-port %s' )
|
||||
Controller.__init__( self, name, command=command,
|
||||
cargs=cargs, **kwargs )
|
||||
name: name to give controller.
|
||||
ryuArgs: arguments and modules to pass to Ryu"""
|
||||
homeDir = quietRun( 'printenv HOME' ).strip( '\r\n' )
|
||||
ryuCoreDir = '%s/ryu/ryu/app/' % homeDir
|
||||
if not ryuArgs:
|
||||
warn( 'warning: no Ryu modules specified; '
|
||||
'running simple_switch only\n' )
|
||||
ryuArgs = [ ryuCoreDir + 'simple_switch.py' ]
|
||||
elif not isinstance( ryuArgs, ( list, tuple ) ):
|
||||
ryuArgs = [ ryuArgs ]
|
||||
|
||||
Controller.__init__( self, name,
|
||||
command='ryu-manager',
|
||||
cargs='--ofp-tcp-listen-port %s ' +
|
||||
' '.join( ryuArgs ),
|
||||
cdir=ryuCoreDir,
|
||||
**kwargs )
|
||||
|
||||
|
||||
class RemoteController( Controller ):
|
||||
|
||||
+3
-9
@@ -164,9 +164,7 @@ function mn_deps {
|
||||
if [ "$DIST" = "Fedora" -o "$DIST" = "RedHatEnterpriseServer" ]; then
|
||||
$install gcc make socat psmisc xterm openssh-clients iperf \
|
||||
iproute telnet python-setuptools libcgroup-tools \
|
||||
ethtool help2man net-tools
|
||||
$install ${PYPKG}-pyflakes pylint ${PYPKG}-pep8-naming \
|
||||
${PYPKG}-pexpect
|
||||
ethtool help2man pyflakes pylint python-pep8 python-pexpect
|
||||
elif [ "$DIST" = "SUSE LINUX" ]; then
|
||||
$install gcc make socat psmisc xterm openssh iperf \
|
||||
iproute telnet ${PYPKG}-setuptools libcgroup-tools \
|
||||
@@ -207,11 +205,10 @@ function mn_deps {
|
||||
# Install Mininet documentation dependencies
|
||||
function mn_doc {
|
||||
echo "Installing Mininet documentation dependencies"
|
||||
$install doxygen texlive-fonts-recommended
|
||||
$install doxygen doxypy texlive-fonts-recommended
|
||||
if ! $install doxygen-latex; then
|
||||
echo "doxygen-latex not needed"
|
||||
fi
|
||||
sudo pip install doxypy
|
||||
}
|
||||
|
||||
# The following will cause a full OF install, covering:
|
||||
@@ -410,10 +407,7 @@ function ovs {
|
||||
echo "Installing Open vSwitch..."
|
||||
|
||||
if [ "$DIST" = "Fedora" -o "$DIST" = "RedHatEnterpriseServer" ]; then
|
||||
$install openvswitch
|
||||
if ! $install openvswitch-controller; then
|
||||
echo "openvswitch-controller not installed"
|
||||
fi
|
||||
$install openvswitch openvswitch-controller
|
||||
return
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user