Compare commits
69 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b9f723becd | |||
| 36d2b21187 | |||
| 1888001555 | |||
| fdc3156a91 | |||
| cf6da391fa | |||
| f170cc6f64 | |||
| fd96de6485 | |||
| 73f530b569 | |||
| c7a27b8876 | |||
| b7a6b8137f | |||
| d072e531c2 | |||
| 8139d7d1b4 | |||
| 273b14b771 | |||
| bfda33544a | |||
| 1f4525ed0a | |||
| 1969669f51 | |||
| c639f342e5 | |||
| 6e887d0788 | |||
| 092863f113 | |||
| 5100a38fcd | |||
| 3bcecd8e08 | |||
| 486676d617 | |||
| 9e5280b4d1 | |||
| b70eed69d3 | |||
| d96b35694a | |||
| c7deeae11c | |||
| 323989953b | |||
| 17f9756e5c | |||
| 71f3931f2f | |||
| 1e9ca5f7fc | |||
| 8933c996cb | |||
| afa83cd5ae | |||
| 3e81ea7455 | |||
| 8102704726 | |||
| f4490069ca | |||
| 2ac4f92af3 | |||
| f98154a323 | |||
| 7b48460e9e | |||
| 3a0ef258d1 | |||
| 0d9a6796df | |||
| 08a59783f4 | |||
| e37afe996b | |||
| 6a387faa04 | |||
| 1a134cb4d2 | |||
| af4921adc5 | |||
| f94ee8ec97 | |||
| 356b024d6b | |||
| 2283bb01e6 | |||
| 3eef584c6b | |||
| 2e00a7de97 | |||
| e28348f6cd | |||
| 4b744d1fb0 | |||
| 2822998cad | |||
| 853815500d | |||
| 1a2925923f | |||
| cac884a85e | |||
| f314a6626a | |||
| bf83f4f343 | |||
| 1ef12e450a | |||
| 56fc6c3955 | |||
| 88cbf4ec42 | |||
| 26b3959968 | |||
| 966dd20b4b | |||
| 82998cac8b | |||
| 34b1f4161a | |||
| dfb297901f | |||
| 67236e9db3 | |||
| 8a00c3abf8 | |||
| 037f7f5921 |
+15
-11
@@ -4,28 +4,32 @@ sudo: required
|
||||
matrix:
|
||||
include:
|
||||
- dist: trusty
|
||||
python: 2.7
|
||||
env: dist="14.04 LTS trusty"
|
||||
- dist: trusty
|
||||
python: 3.6
|
||||
env: dist="14.04 LTS trusty"
|
||||
# - dist: xenial
|
||||
# env: dist="16.04 LTS xenial"
|
||||
# Travis-CI only proposes 14.04 LTS Trusty and there is no plan to update to 16.04 xenial
|
||||
# (c.f. https://github.com/travis-ci/travis-ci/issues/5821)
|
||||
# It is useless to add a second job because it will run in the same Ubuntu version (14.04)
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq vlan
|
||||
- sudo util/install.sh -n
|
||||
- PYTHON=`which python` util/install.sh -n
|
||||
|
||||
install:
|
||||
- bash -c "if [ `lsb_release -rs` == '14.04' ]; then make codecheck; fi"
|
||||
- sudo util/install.sh -fnvw
|
||||
- pip install pexpect || pip3 install pexpect
|
||||
- util/install.sh -nfvw
|
||||
|
||||
script:
|
||||
- sudo mn --test pingall
|
||||
- sudo python mininet/test/runner.py -v -quick
|
||||
- sudo python examples/test/runner.py -v -quick
|
||||
- alias sudo="sudo env PATH=$PATH"
|
||||
- export PYTHON=`which python`
|
||||
- echo 'px import sys; print(sys.version_info)' | sudo $PYTHON bin/mn -v output
|
||||
- sudo $PYTHON bin/mn --test pingall
|
||||
- sudo $PYTHON mininet/test/runner.py -v -quick
|
||||
- sudo $PYTHON examples/test/runner.py -v -quick
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
||||
# More details: https://docs.travis-ci.com/user/notifications#Configuring-email-notifications
|
||||
|
||||
# More details: https://docs.travis-ci.com/user/notifications
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Mininet Installation/Configuration Notes
|
||||
----------------------------------------
|
||||
|
||||
Mininet 2.3.0d1
|
||||
Mininet 2.3.0d4
|
||||
---
|
||||
|
||||
The supported installation methods for Mininet are 1) using a
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Mininet 2.3.0d1 License
|
||||
Mininet 2.3.0d4 License
|
||||
|
||||
Copyright (c) 2013-2016 Open Networking Laboratory
|
||||
Copyright (c) 2013-2018 Open Networking Laboratory
|
||||
Copyright (c) 2009-2012 Bob Lantz and The Board of Trustees of
|
||||
The Leland Stanford Junior University
|
||||
|
||||
|
||||
@@ -2,14 +2,16 @@ MININET = mininet/*.py
|
||||
TEST = mininet/test/*.py
|
||||
EXAMPLES = mininet/examples/*.py
|
||||
MN = bin/mn
|
||||
PYMN = python -B bin/mn
|
||||
PYTHON ?= python
|
||||
PYMN = $(PYTHON) -B bin/mn
|
||||
BIN = $(MN)
|
||||
PYSRC = $(MININET) $(TEST) $(EXAMPLES) $(BIN)
|
||||
MNEXEC = mnexec
|
||||
MANPAGES = mn.1 mnexec.1
|
||||
P8IGN = E251,E201,E302,E202,E126,E127,E203,E226
|
||||
BINDIR = /usr/bin
|
||||
MANDIR = /usr/share/man/man1
|
||||
PREFIX ?= /usr
|
||||
BINDIR ?= $(PREFIX)/bin
|
||||
MANDIR ?= $(PREFIX)/share/man/man1
|
||||
DOCDIRS = doc/html doc/latex
|
||||
PDF = doc/latex/refman.pdf
|
||||
|
||||
@@ -46,16 +48,20 @@ slowtest: $(MININET)
|
||||
mnexec: mnexec.c $(MN) mininet/net.py
|
||||
cc $(CFLAGS) $(LDFLAGS) -DVERSION=\"`PYTHONPATH=. $(PYMN) --version`\" $< -o $@
|
||||
|
||||
install: $(MNEXEC) $(MANPAGES)
|
||||
install $(MNEXEC) $(BINDIR)
|
||||
install $(MANPAGES) $(MANDIR)
|
||||
python setup.py install
|
||||
install-mnexec: $(MNEXEC)
|
||||
install -D $(MNEXEC) $(BINDIR)/$(MNEXEC)
|
||||
|
||||
install-manpages: $(MANPAGES)
|
||||
install -D -t $(MANDIR) $(MANPAGES)
|
||||
|
||||
install: install-mnexec install-manpages
|
||||
$(PYTHON) setup.py install
|
||||
|
||||
develop: $(MNEXEC) $(MANPAGES)
|
||||
# Perhaps we should link these as well
|
||||
install $(MNEXEC) $(BINDIR)
|
||||
install $(MANPAGES) $(MANDIR)
|
||||
python setup.py develop
|
||||
$(PYTHON) setup.py develop
|
||||
|
||||
man: $(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.0d1
|
||||
Mininet 2.3.0d4
|
||||
|
||||
[![Build Status][1]](https://travis-ci.org/mininet/mininet)
|
||||
|
||||
@@ -126,7 +126,7 @@ hard work that Mininet continues to grow and improve.
|
||||
Best wishes, and we look forward to seeing what you can do with
|
||||
Mininet to change the networking world!
|
||||
|
||||
Bob Lantz
|
||||
Bob Lantz
|
||||
Mininet Core Team
|
||||
|
||||
[1]: https://travis-ci.org/mininet/mininet.svg?branch=master
|
||||
|
||||
@@ -186,8 +186,10 @@ class MininetRunner( object ):
|
||||
for fileName in files:
|
||||
customs = {}
|
||||
if os.path.isfile( fileName ):
|
||||
execfile( fileName, customs, customs )
|
||||
for name, val in customs.iteritems():
|
||||
# pylint: disable=exec-used
|
||||
exec( compile( open( fileName ).read(), fileName, 'exec' ),
|
||||
customs, customs )
|
||||
for name, val in customs.items():
|
||||
self.setCustom( name, val )
|
||||
else:
|
||||
raise Exception( 'could not find custom file: %s' % fileName )
|
||||
@@ -256,7 +258,7 @@ class MininetRunner( object ):
|
||||
opts.add_option( '--arp', action='store_true',
|
||||
default=False, help='set all-pairs ARP entries' )
|
||||
opts.add_option( '--verbosity', '-v', type='choice',
|
||||
choices=LEVELS.keys(), default = 'info',
|
||||
choices=list( LEVELS.keys() ), default = 'info',
|
||||
help = '|'.join( LEVELS.keys() ) )
|
||||
opts.add_option( '--innamespace', action='store_true',
|
||||
default=False, help='sw and ctrl in namespace?' )
|
||||
@@ -286,7 +288,7 @@ class MininetRunner( object ):
|
||||
metavar='server1,server2...',
|
||||
help=( 'run on multiple servers (experimental!)' ) )
|
||||
opts.add_option( '--placement', type='choice',
|
||||
choices=PLACEMENT.keys(), default='block',
|
||||
choices=list( PLACEMENT.keys() ), default='block',
|
||||
metavar='block|random',
|
||||
help=( 'node placement for --cluster '
|
||||
'(experimental!) ' ) )
|
||||
|
||||
@@ -13,12 +13,9 @@ from mininet.topo import Topo
|
||||
class MyTopo( Topo ):
|
||||
"Simple topology example."
|
||||
|
||||
def __init__( self ):
|
||||
def build( self ):
|
||||
"Create custom topo."
|
||||
|
||||
# Initialize topology
|
||||
Topo.__init__( self )
|
||||
|
||||
# Add hosts and switches
|
||||
leftHost = self.addHost( 'h1' )
|
||||
rightHost = self.addHost( 'h2' )
|
||||
|
||||
+21
-6
@@ -126,7 +126,7 @@ class ClusterCleanup( object ):
|
||||
def cleanup( cls ):
|
||||
"Clean up"
|
||||
info( '*** Cleaning up cluster\n' )
|
||||
for server, user in cls.serveruser.iteritems():
|
||||
for server, user in cls.serveruser.items():
|
||||
if server == 'localhost':
|
||||
# Handled by mininet.clean.cleanup()
|
||||
continue
|
||||
@@ -843,11 +843,26 @@ class MininetCluster( Mininet ):
|
||||
def addController( self, *args, **kwargs ):
|
||||
"Patch to update IP address to global IP address"
|
||||
controller = Mininet.addController( self, *args, **kwargs )
|
||||
# Update IP address for controller that may not be local
|
||||
if ( isinstance( controller, Controller)
|
||||
and controller.IP() == '127.0.0.1'
|
||||
and ' eth0:' in controller.cmd( 'ip link show' ) ):
|
||||
Intf( 'eth0', node=controller ).updateIP()
|
||||
loopback = '127.0.0.1'
|
||||
if ( not isinstance( controller, Controller ) or
|
||||
controller.IP() != loopback ):
|
||||
return
|
||||
# Find route to a different server IP address
|
||||
serverIPs = [ ip for ip in self.serverIP.values()
|
||||
if ip is not controller.IP() ]
|
||||
if not serverIPs:
|
||||
return # no remote servers - loopback is fine
|
||||
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() )
|
||||
return controller
|
||||
|
||||
def buildFromTopo( self, *args, **kwargs ):
|
||||
|
||||
@@ -30,7 +30,7 @@ class ClusterCLI( CLI ):
|
||||
global nx, plt, graphviz_layout
|
||||
if not nx:
|
||||
try:
|
||||
# pylint: disable=import-error
|
||||
# pylint: disable=import-error,no-member
|
||||
import networkx
|
||||
nx = networkx # satisfy pylint
|
||||
from matplotlib import pyplot
|
||||
@@ -42,7 +42,7 @@ class ClusterCLI( CLI ):
|
||||
graphviz_layout = nx.graphviz_layout
|
||||
else:
|
||||
graphviz_layout = nx.drawing.nx_agraph.graphviz_layout
|
||||
# pylint: enable=import-error
|
||||
# pylint: enable=import-error,no-member
|
||||
except ImportError:
|
||||
error( 'plot requires networkx, matplotlib and pygraphviz - '
|
||||
'please install them and try again\n' )
|
||||
|
||||
@@ -49,7 +49,7 @@ class MininetFacade( object ):
|
||||
args: unnamed networks passed as arguments
|
||||
kwargs: named networks passed as arguments"""
|
||||
self.net = net
|
||||
self.nets = [ net ] + list( args ) + kwargs.values()
|
||||
self.nets = [ net ] + list( args ) + list( kwargs.values() )
|
||||
self.nameToNet = kwargs
|
||||
self.nameToNet['net'] = net
|
||||
|
||||
@@ -100,10 +100,9 @@ class MininetFacade( object ):
|
||||
|
||||
class ControlNetwork( Topo ):
|
||||
"Control Network Topology"
|
||||
def __init__( self, n, dataController=DataController, **kwargs ):
|
||||
def build( self, n, dataController=DataController, **_kwargs ):
|
||||
"""n: number of data network controller nodes
|
||||
dataController: class for data network controllers"""
|
||||
Topo.__init__( self, **kwargs )
|
||||
# Connect everything to a single switch
|
||||
cs0 = self.addSwitch( 'cs0' )
|
||||
# Add hosts which will serve as data network controllers
|
||||
|
||||
+5
-4
@@ -31,9 +31,9 @@ rate includes buffering.
|
||||
from mininet.net import Mininet
|
||||
from mininet.node import CPULimitedHost
|
||||
from mininet.topolib import TreeTopo
|
||||
from mininet.util import custom, waitListening
|
||||
from mininet.util import custom, waitListening, decode
|
||||
from mininet.log import setLogLevel, info
|
||||
|
||||
from mininet.clean import cleanup
|
||||
|
||||
def bwtest( cpuLimits, period_us=100000, seconds=10 ):
|
||||
"""Example/test of link and CPU bandwidth limits
|
||||
@@ -55,7 +55,8 @@ def bwtest( cpuLimits, period_us=100000, seconds=10 ):
|
||||
net = Mininet( topo=topo, host=host )
|
||||
# pylint: disable=bare-except
|
||||
except:
|
||||
info( '*** Skipping scheduler %s\n' % sched )
|
||||
info( '*** Skipping scheduler %s and cleaning up\n' % sched )
|
||||
cleanup()
|
||||
break
|
||||
net.start()
|
||||
net.pingAll()
|
||||
@@ -70,7 +71,7 @@ def bwtest( cpuLimits, period_us=100000, seconds=10 ):
|
||||
# ignore empty result from waitListening/telnet
|
||||
popen.stdout.readline()
|
||||
client.cmd( 'iperf -yc -t %s -c %s' % ( seconds, server.IP() ) )
|
||||
result = popen.stdout.readline().split( ',' )
|
||||
result = decode( popen.stdout.readline() ).split( ',' )
|
||||
bps = float( result[ -1 ] )
|
||||
popen.terminate()
|
||||
net.stop()
|
||||
|
||||
@@ -38,11 +38,7 @@ flush = sys.stdout.flush
|
||||
class LinearTestTopo( Topo ):
|
||||
"Topology for a string of N hosts and N-1 switches."
|
||||
|
||||
def __init__( self, N, **params ):
|
||||
|
||||
# Initialize topology
|
||||
Topo.__init__( self, **params )
|
||||
|
||||
def build( self, N, **params ):
|
||||
# Create switches and hosts
|
||||
hosts = [ self.addHost( 'h%s' % h )
|
||||
for h in irange( 1, N ) ]
|
||||
|
||||
+31
-16
@@ -20,24 +20,39 @@ OpenFlow icon from https://www.opennetworking.org/
|
||||
|
||||
MINIEDIT_VERSION = '2.2.0.1'
|
||||
|
||||
import sys
|
||||
from optparse import OptionParser
|
||||
# from Tkinter import *
|
||||
from Tkinter import ( Frame, Label, LabelFrame, Entry, OptionMenu, Checkbutton,
|
||||
Menu, Toplevel, Button, BitmapImage, PhotoImage, Canvas,
|
||||
Scrollbar, Wm, TclError, StringVar, IntVar,
|
||||
E, W, EW, NW, Y, VERTICAL, SOLID, CENTER,
|
||||
RIGHT, LEFT, BOTH, TRUE, FALSE )
|
||||
from ttk import Notebook
|
||||
from tkMessageBox import showerror
|
||||
from subprocess import call
|
||||
import tkFont
|
||||
import tkFileDialog
|
||||
import tkSimpleDialog
|
||||
|
||||
# pylint: disable=import-error
|
||||
if sys.version_info[0] == 2:
|
||||
from Tkinter import ( Frame, Label, LabelFrame, Entry, OptionMenu,
|
||||
Checkbutton, Menu, Toplevel, Button, BitmapImage,
|
||||
PhotoImage, Canvas, Scrollbar, Wm, TclError,
|
||||
StringVar, IntVar, E, W, EW, NW, Y, VERTICAL, SOLID,
|
||||
CENTER, RIGHT, LEFT, BOTH, TRUE, FALSE )
|
||||
from ttk import Notebook
|
||||
from tkMessageBox import showerror
|
||||
import tkFont
|
||||
import tkFileDialog
|
||||
import tkSimpleDialog
|
||||
else:
|
||||
from tkinter import ( Frame, Label, LabelFrame, Entry, OptionMenu,
|
||||
Checkbutton, Menu, Toplevel, Button, BitmapImage,
|
||||
PhotoImage, Canvas, Scrollbar, Wm, TclError,
|
||||
StringVar, IntVar, E, W, EW, NW, Y, VERTICAL, SOLID,
|
||||
CENTER, RIGHT, LEFT, BOTH, TRUE, FALSE )
|
||||
from tkinter.ttk import Notebook
|
||||
from tkinter.messagebox import showerror
|
||||
from tkinter import font as tkFont
|
||||
from tkinter import simpledialog as tkSimpleDialog
|
||||
from tkinter import filedialog as tkFileDialog
|
||||
# pylint: enable=import-error
|
||||
|
||||
import re
|
||||
import json
|
||||
from distutils.version import StrictVersion
|
||||
import os
|
||||
import sys
|
||||
from functools import partial
|
||||
|
||||
if 'PYTHONPATH' in os.environ:
|
||||
@@ -1408,7 +1423,7 @@ class MiniEdit( Frame ):
|
||||
def convertJsonUnicode(self, text):
|
||||
"Some part of Mininet don't like Unicode"
|
||||
if isinstance(text, dict):
|
||||
return {self.convertJsonUnicode(key): self.convertJsonUnicode(value) for key, value in text.iteritems()}
|
||||
return {self.convertJsonUnicode(key): self.convertJsonUnicode(value) for key, value in text.items()}
|
||||
elif isinstance(text, list):
|
||||
return [self.convertJsonUnicode(element) for element in text]
|
||||
elif isinstance(text, unicode):
|
||||
@@ -1835,7 +1850,7 @@ class MiniEdit( Frame ):
|
||||
|
||||
# Save Links
|
||||
f.write(" info( '*** Add links\\n')\n")
|
||||
for key,linkDetail in self.links.iteritems():
|
||||
for key,linkDetail in self.links.items():
|
||||
tags = self.canvas.gettags(key)
|
||||
if 'data' in tags:
|
||||
optsExist = False
|
||||
@@ -2875,7 +2890,7 @@ class MiniEdit( Frame ):
|
||||
def buildLinks( self, net):
|
||||
# Make links
|
||||
info( "Getting Links.\n" )
|
||||
for key,link in self.links.iteritems():
|
||||
for key,link in self.links.items():
|
||||
tags = self.canvas.gettags(key)
|
||||
if 'data' in tags:
|
||||
src=link['src']
|
||||
@@ -3211,7 +3226,7 @@ class MiniEdit( Frame ):
|
||||
customs = {}
|
||||
if os.path.isfile( fileName ):
|
||||
execfile( fileName, customs, customs )
|
||||
for name, val in customs.iteritems():
|
||||
for name, val in customs.items():
|
||||
self.setCustom( name, val )
|
||||
else:
|
||||
raise Exception( 'could not find custom file: %s' % fileName )
|
||||
|
||||
@@ -21,9 +21,7 @@ def runMultiLink():
|
||||
class simpleMultiLinkTopo( Topo ):
|
||||
"Simple topology with multiple links"
|
||||
|
||||
def __init__( self, n, **kwargs ):
|
||||
Topo.__init__( self, **kwargs )
|
||||
|
||||
def build( self, n, **_kwargs ):
|
||||
h1, h2 = self.addHost( 'h1' ), self.addHost( 'h2' )
|
||||
s1 = self.addSwitch( 's1' )
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ def multiping( netsize, chunksize, seconds):
|
||||
|
||||
# Create network and identify subnets
|
||||
topo = SingleSwitchTopo( netsize )
|
||||
net = Mininet( topo=topo )
|
||||
net = Mininet( topo=topo, waitConnected=True )
|
||||
net.start()
|
||||
hosts = net.hosts
|
||||
subnets = chunks( hosts, chunksize )
|
||||
|
||||
@@ -9,6 +9,7 @@ monitoring them
|
||||
from mininet.topo import SingleSwitchTopo
|
||||
from mininet.net import Mininet
|
||||
from mininet.log import info, setLogLevel
|
||||
from mininet.util import decode
|
||||
|
||||
from time import time
|
||||
from select import poll, POLLIN
|
||||
@@ -19,7 +20,7 @@ def monitorFiles( outfiles, seconds, timeoutms ):
|
||||
"Monitor set of files and return [(host, line)...]"
|
||||
devnull = open( '/dev/null', 'w' )
|
||||
tails, fdToFile, fdToHost = {}, {}, {}
|
||||
for h, outfile in outfiles.iteritems():
|
||||
for h, outfile in outfiles.items():
|
||||
tail = Popen( [ 'tail', '-f', outfile ],
|
||||
stdout=PIPE, stderr=devnull )
|
||||
fd = tail.stdout.fileno()
|
||||
@@ -40,7 +41,7 @@ def monitorFiles( outfiles, seconds, timeoutms ):
|
||||
host = fdToHost[ fd ]
|
||||
# Wait for a line of output
|
||||
line = f.readline().strip()
|
||||
yield host, line
|
||||
yield host, decode( line )
|
||||
else:
|
||||
# If we timed out, return nothing
|
||||
yield None, ''
|
||||
|
||||
+1
-3
@@ -27,9 +27,7 @@ from mininet.util import irange
|
||||
|
||||
class InternetTopo(Topo):
|
||||
"Single switch connected to n hosts."
|
||||
def __init__(self, n=2, **opts):
|
||||
Topo.__init__(self, **opts)
|
||||
|
||||
def build(self, n=2, **_kwargs ):
|
||||
# set up inet switch
|
||||
inetSwitch = self.addSwitch('s0')
|
||||
# add inet host
|
||||
|
||||
@@ -5,8 +5,9 @@ Tests for baresshd.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
from mininet.clean import cleanup, sh
|
||||
from sys import stdout
|
||||
|
||||
class testBareSSHD( unittest.TestCase ):
|
||||
|
||||
@@ -14,7 +15,9 @@ class testBareSSHD( unittest.TestCase ):
|
||||
|
||||
def connected( self ):
|
||||
"Log into ssh server, check banner, then exit"
|
||||
p = pexpect.spawn( 'ssh 10.0.0.1 -o StrictHostKeyChecking=no -i /tmp/ssh/test_rsa exit' )
|
||||
p = pexpect.spawn( 'ssh 10.0.0.1 -o ConnectTimeout=1 '
|
||||
'-o StrictHostKeyChecking=no '
|
||||
'-i /tmp/ssh/test_rsa exit' )
|
||||
while True:
|
||||
index = p.expect( self.opts )
|
||||
if index == 0:
|
||||
@@ -22,6 +25,7 @@ class testBareSSHD( unittest.TestCase ):
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def setUp( self ):
|
||||
# verify that sshd is not running
|
||||
self.assertFalse( self.connected() )
|
||||
@@ -55,7 +59,7 @@ class testBareSSHD( unittest.TestCase ):
|
||||
|
||||
def tearDown( self ):
|
||||
# kill the ssh process
|
||||
sh( "ps aux | grep 'ssh.*Banner' | awk '{ print $2 }' | xargs kill" )
|
||||
sh( "ps aux | grep ssh |grep Banner| awk '{ print $2 }' | xargs kill" )
|
||||
cleanup()
|
||||
# remove public key pair
|
||||
sh( 'rm -rf /tmp/ssh' )
|
||||
|
||||
@@ -5,7 +5,7 @@ Tests for bind.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
class testBind( unittest.TestCase ):
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ A simple sanity check test for cluster edition
|
||||
'''
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
class clusterSanityCheck( unittest.TestCase ):
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Tests for controllers.py and controllers2.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
class testControllers( unittest.TestCase ):
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for controlnet.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
class testControlNet( unittest.TestCase ):
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ cfs 10% 1.29e+09
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
import sys
|
||||
|
||||
class testCPU( unittest.TestCase ):
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for emptynet.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
class testEmptyNet( unittest.TestCase ):
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ Test for hwintf.py
|
||||
import unittest
|
||||
import re
|
||||
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
from mininet.log import setLogLevel
|
||||
from mininet.node import Node
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for intfOptions.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
import sys
|
||||
|
||||
class testIntfOptions( unittest.TestCase ):
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for limit.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
import sys
|
||||
|
||||
class testLimit( unittest.TestCase ):
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for linearbandwidth.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
import sys
|
||||
|
||||
class testLinearBandwidth( unittest.TestCase ):
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for linuxrouter.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
from mininet.util import quietRun
|
||||
|
||||
class testLinuxRouter( unittest.TestCase ):
|
||||
|
||||
@@ -6,7 +6,7 @@ validates mininet interfaces against systems interfaces
|
||||
'''
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
class testMultiLink( unittest.TestCase ):
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for multiping.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
from collections import defaultdict
|
||||
|
||||
class testMultiPing( unittest.TestCase ):
|
||||
@@ -31,18 +31,20 @@ class testMultiPing( unittest.TestCase ):
|
||||
target = p.match.group(3)
|
||||
received = int( p.match.group(4) )
|
||||
if target == '10.0.0.200':
|
||||
self.assertEqual( received, 0 )
|
||||
self.assertEqual( received, 0, p.match.group(0) + '\n' +
|
||||
target + ' received %d != 0 packets' % received )
|
||||
else:
|
||||
self.assertEqual( received, 1 )
|
||||
self.assertEqual( received, 1, p.match.group(0) + '\n' +
|
||||
target + ' received %d != 1 packets' % received )
|
||||
try:
|
||||
pings[ name ].remove( target )
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
break
|
||||
self.assertTrue( len( pings ) > 0 )
|
||||
self.assertTrue( len( pings ) > 0, 'too few pings' )
|
||||
for t in pings.values():
|
||||
self.assertEqual( len( t ), 0 )
|
||||
self.assertEqual( len( t ), 0, 'missed ping target(s): %s' % t )
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for multipoll.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
class testMultiPoll( unittest.TestCase ):
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for multitest.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
class testMultiTest( unittest.TestCase ):
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for nat.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
from mininet.util import quietRun
|
||||
|
||||
destIP = '8.8.8.8' # Google DNS
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for natnet.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
from mininet.util import quietRun
|
||||
|
||||
class testNATNet( unittest.TestCase ):
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for numberedports.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
from collections import defaultdict
|
||||
from mininet.node import OVSSwitch
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for popen.py and popenpoll.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
class testPopen( unittest.TestCase ):
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for scratchnet.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
|
||||
class testScratchNet( unittest.TestCase ):
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for simpleperf.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
import sys
|
||||
from mininet.log import setLogLevel
|
||||
|
||||
@@ -18,7 +18,7 @@ class testSimplePerf( unittest.TestCase ):
|
||||
"Run the example and verify iperf results"
|
||||
# 10 Mb/s, plus or minus 20% tolerance
|
||||
BW = 10
|
||||
TOLERANCE = .2
|
||||
TOLERANCE = .2
|
||||
p = pexpect.spawn( 'python -m mininet.examples.simpleperf testmode' )
|
||||
# check iperf results
|
||||
p.expect( "Results: \['10M', '([\d\.]+) .bits/sec", timeout=480 )
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for sshd.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
from mininet.clean import sh
|
||||
|
||||
class testSSHD( unittest.TestCase ):
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for tree1024.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
import sys
|
||||
|
||||
class testTree1024( unittest.TestCase ):
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for treeping64.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
import sys
|
||||
|
||||
class testTreePing64( unittest.TestCase ):
|
||||
|
||||
@@ -5,7 +5,7 @@ Test for vlanhost.py
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
from mininet.util import pexpect
|
||||
import sys
|
||||
from mininet.util import quietRun
|
||||
|
||||
|
||||
+3
-3
@@ -16,12 +16,13 @@ import time
|
||||
|
||||
from mininet.log import info
|
||||
from mininet.term import cleanUpScreens
|
||||
|
||||
from mininet.util import decode
|
||||
|
||||
def sh( cmd ):
|
||||
"Print a command and send it to the shell"
|
||||
info( cmd + '\n' )
|
||||
return Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE ).communicate()[ 0 ]
|
||||
result = Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE ).communicate()[ 0 ]
|
||||
return decode( result )
|
||||
|
||||
def killprocs( pattern ):
|
||||
"Reliably terminate processes matching a pattern (including args)"
|
||||
@@ -76,7 +77,6 @@ class Cleanup( object ):
|
||||
for dp in dps:
|
||||
if dp:
|
||||
sh( 'dpctl deldp ' + dp )
|
||||
|
||||
info( "*** Removing OVS datapaths\n" )
|
||||
dps = sh("ovs-vsctl --timeout=1 list-br").strip().splitlines()
|
||||
if dps:
|
||||
|
||||
@@ -29,6 +29,8 @@ from subprocess import call
|
||||
from cmd import Cmd
|
||||
from os import isatty
|
||||
from select import poll, POLLIN
|
||||
import select
|
||||
import errno
|
||||
import sys
|
||||
import time
|
||||
import os
|
||||
@@ -459,6 +461,13 @@ class CLI( Cmd ):
|
||||
# it's possible to interrupt ourselves after we've
|
||||
# read data but before it has been printed.
|
||||
node.sendInt()
|
||||
except select.error as e:
|
||||
# pylint: disable=unpacking-non-sequence
|
||||
errno_, errmsg = e.args
|
||||
# pylint: enable=unpacking-non-sequence
|
||||
if errno_ != errno.EINTR:
|
||||
error( "select.error: %d, %s" % (errno_, errmsg) )
|
||||
node.sendInt()
|
||||
|
||||
def precmd( self, line ):
|
||||
"allow for comments in the cli"
|
||||
|
||||
+5
-6
@@ -146,6 +146,9 @@ class Intf( object ):
|
||||
|
||||
def rename( self, newname ):
|
||||
"Rename interface"
|
||||
if self.node and self.name in self.node.nameToIntf:
|
||||
# rename intf in node's nameToIntf
|
||||
self.node.nameToIntf[newname] = self.node.nameToIntf.pop(self.name)
|
||||
self.ifconfig( 'down' )
|
||||
result = self.cmd( 'ip link set', self.name, 'name', newname )
|
||||
self.name = newname
|
||||
@@ -164,7 +167,7 @@ class Intf( object ):
|
||||
method: config method name
|
||||
param: arg=value (ignore if value=None)
|
||||
value may also be list or dict"""
|
||||
name, value = param.items()[ 0 ]
|
||||
name, value = list( param.items() )[ 0 ]
|
||||
f = getattr( self, method, None )
|
||||
if not f or value is None:
|
||||
return
|
||||
@@ -285,11 +288,7 @@ class TCIntf( Intf ):
|
||||
loss=None, max_queue_size=None ):
|
||||
"Internal method: return tc commands for delay and loss"
|
||||
cmds = []
|
||||
if delay and delay < 0:
|
||||
error( 'Negative delay', delay, '\n' )
|
||||
elif jitter and jitter < 0:
|
||||
error( 'Negative jitter', jitter, '\n' )
|
||||
elif loss and ( loss < 0 or loss > 100 ):
|
||||
if loss and ( loss < 0 or loss > 100 ):
|
||||
error( 'Bad loss percentage', loss, '%%\n' )
|
||||
else:
|
||||
# Delay/jitter/loss/max queue size
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"Module dependency utility functions for Mininet."
|
||||
|
||||
from mininet.util import quietRun
|
||||
from mininet.util import quietRun, BaseString
|
||||
from mininet.log import info, error, debug
|
||||
from os import environ
|
||||
|
||||
@@ -28,9 +28,9 @@ def moduleDeps( subtract=None, add=None ):
|
||||
add: string or list of module names to add, if not already loaded"""
|
||||
subtract = subtract if subtract is not None else []
|
||||
add = add if add is not None else []
|
||||
if isinstance( subtract, basestring ):
|
||||
if isinstance( subtract, BaseString ):
|
||||
subtract = [ subtract ]
|
||||
if isinstance( add, basestring ):
|
||||
if isinstance( add, BaseString ):
|
||||
add = [ add ]
|
||||
for mod in subtract:
|
||||
if mod in lsmod():
|
||||
|
||||
+9
-7
@@ -104,11 +104,11 @@ from mininet.nodelib import NAT
|
||||
from mininet.link import Link, Intf
|
||||
from mininet.util import ( quietRun, fixLimits, numCores, ensureRoot,
|
||||
macColonHex, ipStr, ipParse, netParse, ipAdd,
|
||||
waitListening )
|
||||
waitListening, BaseString )
|
||||
from mininet.term import cleanUpScreens, makeTerms
|
||||
|
||||
# Mininet version: should be consistent with README and LICENSE
|
||||
VERSION = "2.3.0d1"
|
||||
VERSION = "2.3.0d4"
|
||||
|
||||
class Mininet( object ):
|
||||
"Network emulation with hosts spawned in network namespaces."
|
||||
@@ -190,7 +190,7 @@ class Mininet( object ):
|
||||
if not remaining:
|
||||
info( '\n' )
|
||||
return True
|
||||
if time > timeout and timeout is not None:
|
||||
if timeout is not None and time > timeout:
|
||||
break
|
||||
sleep( delay )
|
||||
time += delay
|
||||
@@ -383,8 +383,8 @@ class Mininet( object ):
|
||||
params: additional link params (optional)
|
||||
returns: link object"""
|
||||
# Accept node objects or names
|
||||
node1 = node1 if not isinstance( node1, basestring ) else self[ node1 ]
|
||||
node2 = node2 if not isinstance( node2, basestring ) else self[ node2 ]
|
||||
node1 = node1 if not isinstance( node1, BaseString ) else self[ node1 ]
|
||||
node2 = node2 if not isinstance( node2, BaseString ) else self[ node2 ]
|
||||
options = dict( params )
|
||||
# Port is optional
|
||||
if port1 is not None:
|
||||
@@ -549,7 +549,8 @@ class Mininet( object ):
|
||||
switch.start( self.controllers )
|
||||
started = {}
|
||||
for swclass, switches in groupby(
|
||||
sorted( self.switches, key=type ), type ):
|
||||
sorted( self.switches,
|
||||
key=lambda s: str( type( s ) ) ), type ):
|
||||
switches = tuple( switches )
|
||||
if hasattr( swclass, 'batchStartup' ):
|
||||
success = swclass.batchStartup( switches )
|
||||
@@ -576,7 +577,8 @@ class Mininet( object ):
|
||||
info( '*** Stopping %i switches\n' % len( self.switches ) )
|
||||
stopped = {}
|
||||
for swclass, switches in groupby(
|
||||
sorted( self.switches, key=type ), type ):
|
||||
sorted( self.switches,
|
||||
key=lambda s: str( type( s ) ) ), type ):
|
||||
switches = tuple( switches )
|
||||
if hasattr( swclass, 'batchShutdown' ):
|
||||
success = swclass.batchShutdown( switches )
|
||||
|
||||
+43
-24
@@ -62,7 +62,8 @@ from time import sleep
|
||||
|
||||
from mininet.log import info, error, warn, debug
|
||||
from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin,
|
||||
numCores, retry, mountCgroups )
|
||||
numCores, retry, mountCgroups, BaseString, decode,
|
||||
encode, Python3 )
|
||||
from mininet.moduledeps import moduleDeps, pathCheck, TUN
|
||||
from mininet.link import Link, Intf, TCIntf, OVSIntf
|
||||
from re import findall
|
||||
@@ -87,6 +88,9 @@ class Node( object ):
|
||||
self.privateDirs = params.get( 'privateDirs', [] )
|
||||
self.inNamespace = params.get( 'inNamespace', inNamespace )
|
||||
|
||||
# Python 3 complains if we don't wait for shell exit
|
||||
self.waitExited = params.get( 'waitExited', Python3 )
|
||||
|
||||
# Stash configuration parameters for future reference
|
||||
self.params = params
|
||||
|
||||
@@ -103,6 +107,7 @@ class Node( object ):
|
||||
self.readbuf = ''
|
||||
|
||||
# Start command interpreter shell
|
||||
self.master, self.slave = None, None # pylint
|
||||
self.startShell()
|
||||
self.mountPrivateDirs()
|
||||
|
||||
@@ -135,14 +140,18 @@ class Node( object ):
|
||||
# -s: pass $* to shell, and make process easy to find in ps
|
||||
# prompt is set to sentinel chr( 127 )
|
||||
cmd = [ 'mnexec', opts, 'env', 'PS1=' + chr( 127 ),
|
||||
'bash', '--norc', '-is', 'mininet:' + self.name ]
|
||||
'bash', '--norc', '--noediting',
|
||||
'-is', 'mininet:' + self.name ]
|
||||
|
||||
# Spawn a shell subprocess in a pseudo-tty, to disable buffering
|
||||
# in the subprocess and insulate it from signals (e.g. SIGINT)
|
||||
# received by the parent
|
||||
master, slave = pty.openpty()
|
||||
self.shell = self._popen( cmd, stdin=slave, stdout=slave, stderr=slave,
|
||||
close_fds=False )
|
||||
self.stdin = os.fdopen( master, 'rw' )
|
||||
self.master, self.slave = pty.openpty()
|
||||
self.shell = self._popen( cmd, stdin=self.slave, stdout=self.slave,
|
||||
stderr=self.slave, close_fds=False )
|
||||
# XXX BL: This doesn't seem right, and we should also probably
|
||||
# close our files when we exit...
|
||||
self.stdin = os.fdopen( self.master, 'r' )
|
||||
self.stdout = self.stdin
|
||||
self.pid = self.shell.pid
|
||||
self.pollOut = select.poll()
|
||||
@@ -169,7 +178,7 @@ class Node( object ):
|
||||
def mountPrivateDirs( self ):
|
||||
"mount private directories"
|
||||
# Avoid expanding a string into a list of chars
|
||||
assert not isinstance( self.privateDirs, basestring )
|
||||
assert not isinstance( self.privateDirs, BaseString )
|
||||
for directory in self.privateDirs:
|
||||
if isinstance( directory, tuple ):
|
||||
# mount given private directory
|
||||
@@ -198,7 +207,9 @@ class Node( object ):
|
||||
params: parameters to Popen()"""
|
||||
# Leave this is as an instance method for now
|
||||
assert self
|
||||
return Popen( cmd, **params )
|
||||
popen = Popen( cmd, **params )
|
||||
debug( '_popen', cmd, popen.pid )
|
||||
return popen
|
||||
|
||||
def cleanup( self ):
|
||||
"Help python collect its garbage."
|
||||
@@ -207,6 +218,13 @@ class Node( object ):
|
||||
# for intfName in self.intfNames():
|
||||
# if self.name in intfName:
|
||||
# quietRun( 'ip link del ' + intfName )
|
||||
if self.shell:
|
||||
# Close ptys
|
||||
self.stdin.close()
|
||||
os.close(self.slave)
|
||||
if self.waitExited:
|
||||
debug( 'waiting for', self.pid, 'to terminate\n' )
|
||||
self.shell.wait()
|
||||
self.shell = None
|
||||
|
||||
# Subshell I/O, commands and control
|
||||
@@ -216,7 +234,7 @@ class Node( object ):
|
||||
maxbytes: maximum number of bytes to return"""
|
||||
count = len( self.readbuf )
|
||||
if count < maxbytes:
|
||||
data = os.read( self.stdout.fileno(), maxbytes - count )
|
||||
data = decode( os.read( self.stdout.fileno(), maxbytes - count ) )
|
||||
self.readbuf += data
|
||||
if maxbytes >= len( self.readbuf ):
|
||||
result = self.readbuf
|
||||
@@ -240,7 +258,7 @@ class Node( object ):
|
||||
def write( self, data ):
|
||||
"""Write data to node.
|
||||
data: string"""
|
||||
os.write( self.stdin.fileno(), data )
|
||||
os.write( self.stdin.fileno(), encode( data ) )
|
||||
|
||||
def terminate( self ):
|
||||
"Send kill signal to Node and clean up after it."
|
||||
@@ -370,23 +388,23 @@ class Node( object ):
|
||||
'mncmd':
|
||||
[ 'mnexec', '-da', str( self.pid ) ] }
|
||||
defaults.update( kwargs )
|
||||
shell = defaults.pop( 'shell', False )
|
||||
if len( args ) == 1:
|
||||
if isinstance( args[ 0 ], list ):
|
||||
# popen([cmd, arg1, arg2...])
|
||||
cmd = args[ 0 ]
|
||||
elif isinstance( args[ 0 ], basestring ):
|
||||
elif isinstance( args[ 0 ], BaseString ):
|
||||
# popen("cmd arg1 arg2...")
|
||||
cmd = args[ 0 ].split()
|
||||
cmd = [ args[ 0 ] ] if shell else args[ 0 ].split()
|
||||
else:
|
||||
raise Exception( 'popen() requires a string or list' )
|
||||
elif len( args ) > 0:
|
||||
# popen( cmd, arg1, arg2... )
|
||||
cmd = list( args )
|
||||
if shell:
|
||||
cmd = [ os.environ[ 'SHELL' ], '-c' ] + [ ' '.join( cmd ) ]
|
||||
# Attach to our namespace using mnexec -a
|
||||
cmd = defaults.pop( 'mncmd' ) + cmd
|
||||
# Shell requires a string, not a list!
|
||||
if defaults.get( 'shell', False ):
|
||||
cmd = ' '.join( cmd )
|
||||
popen = self._popen( cmd, **defaults )
|
||||
return popen
|
||||
|
||||
@@ -398,7 +416,7 @@ class Node( object ):
|
||||
# Warning: this can fail with large numbers of fds!
|
||||
out, err = popen.communicate()
|
||||
exitcode = popen.wait()
|
||||
return out, err, exitcode
|
||||
return decode( out ), decode( err ), exitcode
|
||||
|
||||
# Interface management, configuration, and routing
|
||||
|
||||
@@ -460,7 +478,7 @@ class Node( object ):
|
||||
"""
|
||||
if not intf:
|
||||
return self.defaultIntf()
|
||||
elif isinstance( intf, basestring):
|
||||
elif isinstance( intf, BaseString):
|
||||
return self.nameToIntf[ intf ]
|
||||
else:
|
||||
return intf
|
||||
@@ -487,7 +505,7 @@ class Node( object ):
|
||||
# explicitly so that we won't get errors if we run before they
|
||||
# have been removed by the kernel. Unfortunately this is very slow,
|
||||
# at least with Linux kernels before 2.6.33
|
||||
for intf in self.intfs.values():
|
||||
for intf in list( self.intfs.values() ):
|
||||
# Protect against deleting hardware interfaces
|
||||
if ( self.name in intf.name ) or ( not checkName ):
|
||||
intf.delete()
|
||||
@@ -512,7 +530,7 @@ class Node( object ):
|
||||
"""Set the default route to go through intf.
|
||||
intf: Intf or {dev <intfname> via <gw-ip> ...}"""
|
||||
# Note setParam won't call us if intf is none
|
||||
if isinstance( intf, basestring ) and ' ' in intf:
|
||||
if isinstance( intf, BaseString ) and ' ' in intf:
|
||||
params = intf
|
||||
else:
|
||||
params = 'dev %s' % intf
|
||||
@@ -559,7 +577,7 @@ class Node( object ):
|
||||
method: config method name
|
||||
param: arg=value (ignore if value=None)
|
||||
value may also be list or dict"""
|
||||
name, value = param.items()[ 0 ]
|
||||
name, value = list( param.items() )[ 0 ]
|
||||
if value is None:
|
||||
return
|
||||
f = getattr( self, method, None )
|
||||
@@ -608,7 +626,7 @@ class Node( object ):
|
||||
|
||||
def intfList( self ):
|
||||
"List of our interfaces sorted by port number"
|
||||
return [ self.intfs[ p ] for p in sorted( self.intfs.iterkeys() ) ]
|
||||
return [ self.intfs[ p ] for p in sorted( self.intfs.keys() ) ]
|
||||
|
||||
def intfNames( self ):
|
||||
"The names of our interfaces sorted by port number"
|
||||
@@ -879,7 +897,7 @@ class Switch( Node ):
|
||||
"Return correctly formatted dpid from dpid or switch name (s1 -> 1)"
|
||||
if dpid:
|
||||
# Remove any colons and make sure it's a good hex number
|
||||
dpid = dpid.translate( None, ':' )
|
||||
dpid = dpid.replace( ':', '' )
|
||||
assert len( dpid ) <= self.dpidLen and int( dpid, 16 ) >= 0
|
||||
else:
|
||||
# Use hex of the first number in the switch name
|
||||
@@ -887,6 +905,7 @@ class Switch( Node ):
|
||||
if nums:
|
||||
dpid = hex( int( nums[ 0 ] ) )[ 2: ]
|
||||
else:
|
||||
self.terminate() # Python 3.6 crash workaround
|
||||
raise Exception( 'Unable to derive default datapath ID - '
|
||||
'please either specify a dpid or use a '
|
||||
'canonical switch name such as s23.' )
|
||||
@@ -1230,7 +1249,7 @@ class OVSSwitch( Switch ):
|
||||
run( cmds, shell=True )
|
||||
# Reapply link config if necessary...
|
||||
for switch in switches:
|
||||
for intf in switch.intfs.itervalues():
|
||||
for intf in switch.intfs.values():
|
||||
if isinstance( intf, TCIntf ):
|
||||
intf.config( **intf.params )
|
||||
return switches
|
||||
@@ -1256,7 +1275,7 @@ class OVSSwitch( Switch ):
|
||||
pids = ' '.join( str( switch.pid ) for switch in switches )
|
||||
run( 'kill -HUP ' + pids )
|
||||
for switch in switches:
|
||||
switch.shell = None
|
||||
switch.terminate()
|
||||
return switches
|
||||
|
||||
|
||||
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Regression test for pty leak in Node()
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
||||
from mininet.net import Mininet
|
||||
from mininet.clean import cleanup
|
||||
from mininet.topo import SingleSwitchTopo
|
||||
|
||||
class TestPtyLeak( unittest.TestCase ):
|
||||
"Verify that there is no pty leakage"
|
||||
|
||||
@staticmethod
|
||||
def testPtyLeak():
|
||||
"Test for pty leakage"
|
||||
net = Mininet( SingleSwitchTopo() )
|
||||
net.start()
|
||||
host = net[ 'h1' ]
|
||||
for _ in range( 0, 10 ):
|
||||
oldptys = host.slave, host.master
|
||||
net.delHost( host )
|
||||
host = net.addHost( 'h1' )
|
||||
assert ( host.slave, host.master ) == oldptys
|
||||
net.stop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
cleanup()
|
||||
@@ -30,10 +30,10 @@ class TestSwitchDpidAssignmentOVS( unittest.TestCase ):
|
||||
def testDefaultDpid( self ):
|
||||
"""Verify that the default dpid is assigned using a valid provided
|
||||
canonical switchname if no dpid is passed in switch creation."""
|
||||
switch = Mininet( Topo(),
|
||||
self.switchClass,
|
||||
Host, Controller ).addSwitch( 's1' )
|
||||
net = Mininet( Topo(), self.switchClass, Host, Controller )
|
||||
switch = net.addSwitch( 's1' )
|
||||
self.assertEqual( switch.defaultDpid(), switch.dpid )
|
||||
net.stop()
|
||||
|
||||
def dpidFrom( self, num ):
|
||||
"Compute default dpid from number"
|
||||
@@ -44,31 +44,34 @@ class TestSwitchDpidAssignmentOVS( unittest.TestCase ):
|
||||
"""Verify that Switch dpid is the actual dpid assigned if dpid is
|
||||
passed in switch creation."""
|
||||
dpid = self.dpidFrom( 0xABCD )
|
||||
switch = Mininet( Topo(), self.switchClass,
|
||||
Host, Controller ).addSwitch(
|
||||
's1', dpid=dpid )
|
||||
net = Mininet( Topo(), self.switchClass, Host, Controller )
|
||||
switch = net.addSwitch( 's1', dpid=dpid )
|
||||
self.assertEqual( switch.dpid, dpid )
|
||||
net.stop()
|
||||
|
||||
def testDefaultDpidAssignmentFailure( self ):
|
||||
"""Verify that Default dpid assignment raises an Exception if the
|
||||
name of the switch does not contin a digit. Also verify the
|
||||
exception message."""
|
||||
net = Mininet( Topo(), self.switchClass, Host, Controller )
|
||||
with self.assertRaises( Exception ) as raises_cm:
|
||||
Mininet( Topo(), self.switchClass,
|
||||
Host, Controller ).addSwitch( 'A' )
|
||||
self.assertEqual(raises_cm.exception.message, 'Unable to derive '
|
||||
net.addSwitch( 'A' )
|
||||
self.assertTrue( 'Unable to derive '
|
||||
'default datapath ID - please either specify a dpid '
|
||||
'or use a canonical switch name such as s23.')
|
||||
'or use a canonical switch name such as s23.'
|
||||
in str( raises_cm.exception ) )
|
||||
net.stop()
|
||||
|
||||
def testDefaultDpidLen( self ):
|
||||
"""Verify that Default dpid length is 16 characters consisting of
|
||||
16 - len(hex of first string of contiguous digits passed in switch
|
||||
name) 0's followed by hex of first string of contiguous digits passed
|
||||
in switch name."""
|
||||
switch = Mininet( Topo(), self.switchClass,
|
||||
Host, Controller ).addSwitch( 's123' )
|
||||
|
||||
net = Mininet( Topo(), self.switchClass, Host, Controller )
|
||||
switch = net.addSwitch( 's123' )
|
||||
self.assertEqual( switch.dpid, self.dpidFrom( 123 ) )
|
||||
net.stop()
|
||||
|
||||
|
||||
class OVSUser( OVSSwitch):
|
||||
"OVS User Switch convenience class"
|
||||
@@ -95,3 +98,4 @@ class testSwitchUserspace( TestSwitchDpidAssignmentOVS ):
|
||||
if __name__ == '__main__':
|
||||
setLogLevel( 'warning' )
|
||||
unittest.main()
|
||||
cleanup()
|
||||
|
||||
@@ -7,13 +7,13 @@ TODO: missing xterm test
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import pexpect
|
||||
import os
|
||||
import re
|
||||
from mininet.util import quietRun
|
||||
from mininet.util import quietRun, pexpect
|
||||
from distutils.version import StrictVersion
|
||||
from time import sleep
|
||||
|
||||
|
||||
def tsharkVersion():
|
||||
"Return tshark version"
|
||||
versionStr = quietRun( 'tshark -v' )
|
||||
@@ -95,7 +95,8 @@ class testWalkthrough( unittest.TestCase ):
|
||||
p = pexpect.spawn( 'mn' )
|
||||
p.expect( self.prompt )
|
||||
# Third pattern is a local interface beginning with 'eth' or 'en'
|
||||
interfaces = [ 'h1-eth0', 's1-eth1', r'[^-](eth|en)\w*\d', 'lo',
|
||||
interfaces = [ r'h1-eth0[:\s]', r's1-eth1[:\s]',
|
||||
r'[^-](eth|en)\w*\d[:\s]', r'lo[:\s]',
|
||||
self.prompt ]
|
||||
# h1 ifconfig
|
||||
p.sendline( 'h1 ifconfig -a' )
|
||||
@@ -122,7 +123,7 @@ class testWalkthrough( unittest.TestCase ):
|
||||
ifcount += 1
|
||||
else:
|
||||
break
|
||||
self.assertTrue( ifcount >= 3, 'Missing interfaces on s1')
|
||||
self.assertTrue( ifcount <= 3, 'Missing interfaces on s1')
|
||||
# h1 ps
|
||||
p.sendline( "h1 ps -a | egrep -v 'ps|grep'" )
|
||||
p.expect( self.prompt )
|
||||
@@ -156,9 +157,13 @@ class testWalkthrough( unittest.TestCase ):
|
||||
|
||||
def testSimpleHTTP( self ):
|
||||
"Start an HTTP server on h1 and wget from h2"
|
||||
if 'Python 2' in quietRun( 'python --version' ):
|
||||
httpserver = 'SimpleHTTPServer'
|
||||
else:
|
||||
httpserver = 'http.server'
|
||||
p = pexpect.spawn( 'mn' )
|
||||
p.expect( self.prompt )
|
||||
p.sendline( 'h1 python -m SimpleHTTPServer 80 &' )
|
||||
p.sendline( 'h1 python -m %s 80 &' % httpserver )
|
||||
# The walkthrough doesn't specify a delay here, and
|
||||
# we also don't read the output (also a possible problem),
|
||||
# but for now let's wait a couple of seconds to make
|
||||
@@ -222,8 +227,8 @@ class testWalkthrough( unittest.TestCase ):
|
||||
p.expect( r'rtt min/avg/max/mdev = '
|
||||
r'([\d\.]+)/([\d\.]+)/([\d\.]+)/([\d\.]+) ms' )
|
||||
delay = float( p.match.group( 2 ) )
|
||||
self.assertTrue( delay > 40, 'Delay < 40ms' )
|
||||
self.assertTrue( delay < 45, 'Delay > 40ms' )
|
||||
self.assertTrue( delay >= 40, 'Delay < 40ms' )
|
||||
self.assertTrue( delay <= 50, 'Delay > 50ms' )
|
||||
p.expect( self.prompt )
|
||||
p.sendline( 'exit' )
|
||||
p.wait()
|
||||
@@ -260,7 +265,7 @@ class testWalkthrough( unittest.TestCase ):
|
||||
p.expect( self.prompt )
|
||||
for i in range( 1, 3 ):
|
||||
p.sendline( 'h%d ifconfig' % i )
|
||||
p.expect( 'HWaddr 00:00:00:00:00:0%d' % i )
|
||||
p.expect( r'\s00:00:00:00:00:0%d\s' % i )
|
||||
p.expect( self.prompt )
|
||||
p.sendline( 'exit' )
|
||||
p.expect( pexpect.EOF )
|
||||
@@ -286,7 +291,9 @@ class testWalkthrough( unittest.TestCase ):
|
||||
"Test running user switch in its own namespace"
|
||||
p = pexpect.spawn( 'mn --innamespace --switch user' )
|
||||
p.expect( self.prompt )
|
||||
interfaces = [ 'h1-eth0', 's1-eth1', '[^-]eth0', 'lo', self.prompt ]
|
||||
interfaces = [ r'h1-eth0[:\s]', r's1-eth1[:\s]',
|
||||
r'[^-](eth|en)\w*\d[:\s]', r'lo[:\s]',
|
||||
self.prompt ]
|
||||
p.sendline( 's1 ifconfig -a' )
|
||||
ifcount = 0
|
||||
while True:
|
||||
|
||||
+4
-4
@@ -56,13 +56,13 @@ class MultiGraph( object ):
|
||||
return self.node.items() if data else self.node.keys()
|
||||
|
||||
def edges_iter( self, data=False, keys=False ):
|
||||
"Iterator: return graph edges"
|
||||
for src, entry in self.edge.iteritems():
|
||||
for dst, keys in entry.iteritems():
|
||||
"Iterator: return graph edges, optionally with data and keys"
|
||||
for src, entry in self.edge.items():
|
||||
for dst, entrykeys in entry.items():
|
||||
if src > dst:
|
||||
# Skip duplicate edges
|
||||
continue
|
||||
for k, attrs in keys.iteritems():
|
||||
for k, attrs in entrykeys.items():
|
||||
if data:
|
||||
if keys:
|
||||
yield( src, dst, k, attrs )
|
||||
|
||||
+60
-21
@@ -12,6 +12,39 @@ from fcntl import fcntl, F_GETFL, F_SETFL
|
||||
from os import O_NONBLOCK
|
||||
import os
|
||||
from functools import partial
|
||||
import sys
|
||||
|
||||
# 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
|
||||
try:
|
||||
# pylint: disable=import-error
|
||||
oldpexpect = None
|
||||
import pexpect as oldpexpect
|
||||
# pylint: enable=import-error
|
||||
|
||||
class Pexpect( object ):
|
||||
"Custom pexpect that is compatible with str"
|
||||
@staticmethod
|
||||
def spawn( *args, **kwargs):
|
||||
"pexpect.spawn that is compatible with str"
|
||||
if Python3 and 'encoding' not in kwargs:
|
||||
kwargs.update( encoding='utf-8' )
|
||||
return oldpexpect.spawn( *args, **kwargs )
|
||||
|
||||
def __getattr__( self, name ):
|
||||
return getattr( oldpexpect, name )
|
||||
pexpect = Pexpect()
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
# Command execution support
|
||||
|
||||
@@ -33,7 +66,7 @@ def oldQuietRun( *cmd ):
|
||||
cmd: list of command params"""
|
||||
if len( cmd ) == 1:
|
||||
cmd = cmd[ 0 ]
|
||||
if isinstance( cmd, str ):
|
||||
if isinstance( cmd, BaseString ):
|
||||
cmd = cmd.split( ' ' )
|
||||
popen = Popen( cmd, stdout=PIPE, stderr=STDOUT )
|
||||
# We can't use Popen.communicate() because it uses
|
||||
@@ -57,7 +90,7 @@ def oldQuietRun( *cmd ):
|
||||
# This is a bit complicated, but it enables us to
|
||||
# monitor command output as it is happening
|
||||
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-branches,too-many-statements
|
||||
def errRun( *cmd, **kwargs ):
|
||||
"""Run a command and return stdout, stderr and return code
|
||||
cmd: string or list of command and args
|
||||
@@ -74,7 +107,7 @@ def errRun( *cmd, **kwargs ):
|
||||
if len( cmd ) == 1:
|
||||
cmd = cmd[ 0 ]
|
||||
# Allow passing in a list or a string
|
||||
if isinstance( cmd, str ) and not shell:
|
||||
if isinstance( cmd, BaseString ) and not shell:
|
||||
cmd = cmd.split( ' ' )
|
||||
cmd = [ str( arg ) for arg in cmd ]
|
||||
elif isinstance( cmd, list ) and shell:
|
||||
@@ -98,6 +131,8 @@ def errRun( *cmd, **kwargs ):
|
||||
f = fdtofile[ fd ]
|
||||
if event & POLLIN:
|
||||
data = f.read( 1024 )
|
||||
if Python3:
|
||||
data = data.decode( Encoding )
|
||||
if echo:
|
||||
output( data )
|
||||
if f == popen.stdout:
|
||||
@@ -116,6 +151,10 @@ def errRun( *cmd, **kwargs ):
|
||||
poller.unregister( fd )
|
||||
|
||||
returncode = popen.wait()
|
||||
# Python 3 complains if we don't explicitly close these
|
||||
popen.stdout.close()
|
||||
if stderr == PIPE:
|
||||
popen.stderr.close()
|
||||
debug( out, err, returncode )
|
||||
return out, err, returncode
|
||||
# pylint: enable=too-many-branches
|
||||
@@ -374,30 +413,30 @@ def pmonitor(popens, timeoutms=500, readline=True,
|
||||
terminates: when all EOFs received"""
|
||||
poller = poll()
|
||||
fdToHost = {}
|
||||
for host, popen in popens.iteritems():
|
||||
for host, popen in popens.items():
|
||||
fd = popen.stdout.fileno()
|
||||
fdToHost[ fd ] = host
|
||||
poller.register( fd, POLLIN )
|
||||
if not readline:
|
||||
# Use non-blocking reads
|
||||
flags = fcntl( fd, F_GETFL )
|
||||
fcntl( fd, F_SETFL, flags | O_NONBLOCK )
|
||||
poller.register( fd, POLLIN | POLLHUP )
|
||||
flags = fcntl( fd, F_GETFL )
|
||||
fcntl( fd, F_SETFL, flags | O_NONBLOCK )
|
||||
while popens:
|
||||
fds = poller.poll( timeoutms )
|
||||
if fds:
|
||||
for fd, event in fds:
|
||||
host = fdToHost[ fd ]
|
||||
popen = popens[ host ]
|
||||
if event & POLLIN:
|
||||
if readline:
|
||||
# Attempt to read a line of output
|
||||
# This blocks until we receive a newline!
|
||||
line = popen.stdout.readline()
|
||||
else:
|
||||
line = popen.stdout.read( readmax )
|
||||
yield host, line
|
||||
# Check for EOF
|
||||
elif event & POLLHUP:
|
||||
if event & POLLIN or event & POLLHUP:
|
||||
while True:
|
||||
try:
|
||||
f = popen.stdout
|
||||
line = decode( f.readline() if readline
|
||||
else f.read( readmax ) )
|
||||
except IOError:
|
||||
line = ''
|
||||
if line == '':
|
||||
break
|
||||
yield host, line
|
||||
if event & POLLHUP:
|
||||
poller.unregister( fd )
|
||||
del popens[ host ]
|
||||
else:
|
||||
@@ -460,7 +499,7 @@ def fixLimits():
|
||||
|
||||
def mountCgroups():
|
||||
"Make sure cgroups file system is mounted"
|
||||
mounts = quietRun( 'cat /proc/mounts' )
|
||||
mounts = quietRun( 'grep cgroup /proc/mounts' )
|
||||
cgdir = '/sys/fs/cgroup'
|
||||
csdir = cgdir + '/cpuset'
|
||||
if ('cgroup %s' % cgdir not in mounts and
|
||||
@@ -600,7 +639,7 @@ def waitListening( client=None, server='127.0.0.1', port=80, timeout=None ):
|
||||
if not runCmd( 'which telnet' ):
|
||||
raise Exception('Could not find telnet' )
|
||||
# pylint: disable=maybe-no-member
|
||||
serverIP = server if isinstance( server, basestring ) else server.IP()
|
||||
serverIP = server if isinstance( server, BaseString ) else server.IP()
|
||||
cmd = ( 'echo A | telnet -e A %s %s' % ( serverIP, port ) )
|
||||
time = 0
|
||||
result = runCmd( cmd )
|
||||
|
||||
+40
-28
@@ -102,6 +102,14 @@ function version_ge {
|
||||
[ "$1" == "$latest" ]
|
||||
}
|
||||
|
||||
# Attempt to identify Python version
|
||||
PYTHON=${PYTHON:-python}
|
||||
if $PYTHON --version |& grep 'Python 2' > /dev/null; then
|
||||
PYTHON_VERSION=2; PYPKG=python
|
||||
else
|
||||
PYTHON_VERSION=3; PYPKG=python3
|
||||
fi
|
||||
echo "${PYTHON} is version ${PYTHON_VERSION}"
|
||||
|
||||
# Kernel Deb pkg to be removed:
|
||||
KERNEL_IMAGE_OLD=linux-image-2.6.26-33-generic
|
||||
@@ -145,19 +153,21 @@ function mn_deps {
|
||||
$install gcc make socat psmisc xterm openssh-clients iperf \
|
||||
iproute telnet python-setuptools libcgroup-tools \
|
||||
ethtool help2man pyflakes pylint python-pep8 python-pexpect
|
||||
elif [ "$DIST" = "SUSE LINUX" ]; then
|
||||
elif [ "$DIST" = "SUSE LINUX" ]; then
|
||||
$install gcc make socat psmisc xterm openssh iperf \
|
||||
iproute telnet python-setuptools libcgroup-tools \
|
||||
ethtool help2man python-pyflakes python3-pylint python-pep8 python-pexpect
|
||||
else
|
||||
$install gcc make socat psmisc xterm ssh iperf iproute2 telnet \
|
||||
python-setuptools cgroup-bin ethtool help2man \
|
||||
pyflakes pylint pep8 python-pexpect
|
||||
iproute telnet ${PYPKG}-setuptools libcgroup-tools \
|
||||
ethtool help2man python-pyflakes python3-pylint \
|
||||
python-pep8 ${PYPKG}-pexpect ${PYPKG}-tk
|
||||
else # Debian/Ubuntu
|
||||
$install gcc make socat psmisc xterm ssh iperf telnet \
|
||||
cgroup-bin ethtool help2man pyflakes pylint pep8 \
|
||||
${PYPKG}-setuptools ${PYPKG}-pexpect ${PYPKG}-tk
|
||||
$install iproute2 || $install iproute
|
||||
fi
|
||||
|
||||
echo "Installing Mininet core"
|
||||
pushd $MININET_DIR/mininet
|
||||
sudo make install
|
||||
sudo PYTHON=${PYTHON} make install
|
||||
popd
|
||||
}
|
||||
|
||||
@@ -204,10 +214,14 @@ function of {
|
||||
function of13 {
|
||||
echo "Installing OpenFlow 1.3 soft switch implementation..."
|
||||
cd $BUILD_DIR/
|
||||
$install git-core autoconf automake autotools-dev pkg-config \
|
||||
make gcc g++ libtool libc6-dev cmake libpcap-dev libxerces-c2-dev \
|
||||
$install git-core autoconf automake autotools-dev pkg-config \
|
||||
make gcc g++ libtool libc6-dev cmake libpcap-dev \
|
||||
unzip libpcre3-dev flex bison libboost-dev
|
||||
|
||||
if [ "$DIST" = "Ubuntu" ] && version_le $RELEASE 16.04; then
|
||||
$install libxerces-c2-dev
|
||||
else
|
||||
$install libxerces-c-dev
|
||||
fi
|
||||
if [ ! -d "ofsoftswitch13" ]; then
|
||||
git clone https://github.com/CPqD/ofsoftswitch13.git
|
||||
if [[ -n "$OF13_SWITCH_REV" ]]; then
|
||||
@@ -218,24 +232,17 @@ function of13 {
|
||||
fi
|
||||
|
||||
# Install netbee
|
||||
if [ "$DIST" = "Ubuntu" ] && version_ge $RELEASE 14.04; then
|
||||
NBEESRC="nbeesrc-feb-24-2015"
|
||||
NBEEDIR="netbee"
|
||||
else
|
||||
NBEESRC="nbeesrc-jan-10-2013"
|
||||
NBEEDIR="nbeesrc-jan-10-2013"
|
||||
if [ ! -d "netbee" ]; then
|
||||
git clone https://github.com/netgroup-polito/netbee.git
|
||||
fi
|
||||
|
||||
NBEEURL=${NBEEURL:-http://www.nbee.org/download/}
|
||||
wget -nc ${NBEEURL}${NBEESRC}.zip
|
||||
unzip ${NBEESRC}.zip
|
||||
cd ${NBEEDIR}/src
|
||||
cd netbee/src
|
||||
cmake .
|
||||
make
|
||||
cd $BUILD_DIR/
|
||||
sudo cp ${NBEEDIR}/bin/libn*.so /usr/local/lib
|
||||
|
||||
cd $BUILD_DIR
|
||||
sudo cp netbee/bin/libn*.so /usr/local/lib
|
||||
sudo ldconfig
|
||||
sudo cp -R ${NBEEDIR}/include/ /usr/
|
||||
sudo cp -R netbee/include/ /usr/
|
||||
|
||||
# Resume the install:
|
||||
cd $BUILD_DIR/ofsoftswitch13
|
||||
@@ -340,15 +347,20 @@ function ubuntuOvs {
|
||||
cd $BUILD_DIR/openvswitch/openvswitch-$OVS_RELEASE
|
||||
DEB_BUILD_OPTIONS='parallel=$parallel nocheck' fakeroot debian/rules binary
|
||||
cd ..
|
||||
# Install packages
|
||||
if [ -e libopenvswitch_$OVS_RELEASE*.deb ]; then
|
||||
$pkginst libopenvswitch_$OVS_RELEASE*.deb 2>/dev/null
|
||||
fi
|
||||
for pkg in common datapath-dkms pki switch; do
|
||||
pkg=openvswitch-${pkg}_$OVS_RELEASE*.deb
|
||||
echo "Installing $pkg"
|
||||
$pkginst $pkg
|
||||
done
|
||||
if $pkginst openvswitch-controller_$OVS_RELEASE*.deb 2>/dev/null; then
|
||||
echo "Ignoring error installing openvswitch-controller"
|
||||
if [ -e openvswitch-controller_$OVS_RELEASE*.deb ]; then
|
||||
$pkginst openvswitch-controller_$OVS_RELEASE*.deb 2>/dev/null
|
||||
fi
|
||||
|
||||
# Ubuntu/Debian will mask a service if you uninstall it
|
||||
sudo systemctl unmask openvswitch-switch || true
|
||||
/sbin/modinfo openvswitch
|
||||
sudo ovs-vsctl show
|
||||
# Switch can run on its own, but
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
from subprocess import check_output as co
|
||||
from sys import exit
|
||||
from sys import exit, version_info
|
||||
|
||||
def run(*args, **kwargs):
|
||||
"Run co and decode for python3"
|
||||
result = co(*args, **kwargs)
|
||||
return result.decode() if version_info[ 0 ] >= 3 else result
|
||||
|
||||
# Actually run bin/mn rather than importing via python path
|
||||
version = 'Mininet ' + co( 'PYTHONPATH=. bin/mn --version 2>&1', shell=True )
|
||||
version = 'Mininet ' + run( 'PYTHONPATH=. bin/mn --version 2>&1', shell=True )
|
||||
version = version.strip()
|
||||
|
||||
# Find all Mininet path references
|
||||
lines = co( "egrep -or 'Mininet [0-9\.\+]+\w*' *", shell=True )
|
||||
lines = run( "egrep -or 'Mininet [0-9\.\+]+\w*' *", shell=True )
|
||||
|
||||
error = False
|
||||
|
||||
|
||||
Reference in New Issue
Block a user