Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
M
mininet
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Locked files
Deploy
Releases
Package Registry
Model registry
Operate
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Olaf Bergmann
mininet
Commits
a6bcad8f
Commit
a6bcad8f
authored
13 years ago
by
Bob Lantz
Browse files
Options
Downloads
Patches
Plain Diff
Intf and Link classes. Latter support bandwidth limits using tc.
parent
6f446f6e
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
mininet/link.py
+275
-0
275 additions, 0 deletions
mininet/link.py
mininet/net.py
+50
-31
50 additions, 31 deletions
mininet/net.py
mininet/node.py
+75
-121
75 additions, 121 deletions
mininet/node.py
mininet/topo.py
+49
-13
49 additions, 13 deletions
mininet/topo.py
with
449 additions
and
165 deletions
mininet/link.py
0 → 100644
+
275
−
0
View file @
a6bcad8f
"""
link.py: interface and link abstractions for mininet
It seems useful to bundle functionality for interfaces into a single
class.
Also it seems useful to enable the possibility of multiple flavors of
links, including:
- simple veth pairs
- tunneled links
- patchable links (which can be disconnected and reconnected via a patchbay)
- link simulators (e.g. wireless)
Basic division of labor:
Nodes: know how to execute commands
Intfs: know how to configure themselves
Links: know how to connect nodes together
"""
from
mininet.log
import
info
,
error
,
debug
from
mininet.util
import
makeIntfPair
from
time
import
sleep
import
re
class
BasicIntf
(
object
):
"
Basic interface object that can configure itself.
"
def
__init__
(
self
,
node
,
name
=
None
,
link
=
None
,
**
kwargs
):
"""
node: owning node (where this intf most likely lives)
name: interface name (e.g. h1-eth0)
link: parent link if any
other arguments are used to configure link parameters
"""
self
.
node
=
node
self
.
name
=
name
self
.
link
=
link
self
.
mac
,
self
.
ip
=
None
,
None
self
.
config
(
**
kwargs
)
def
cmd
(
self
,
*
args
,
**
kwargs
):
self
.
node
.
cmd
(
*
args
,
**
kwargs
)
def
ifconfig
(
self
,
*
args
):
"
Configure ourselves using ifconfig
"
return
self
.
cmd
(
'
ifconfig
'
,
self
.
name
,
*
args
)
def
setIP
(
self
,
ipstr
):
"""
Set our IP address
"""
# This is a sign that we should perhaps rethink our prefix
# mechanism
self
.
ip
,
self
.
prefixLen
=
ipstr
.
split
(
'
/
'
)
return
self
.
ifconfig
(
ipstr
,
'
up
'
)
def
setMAC
(
self
,
macstr
):
"""
Set the MAC address for an interface.
macstr: MAC address as string
"""
self
.
mac
=
macstr
return
(
self
.
ifconfig
(
'
down
'
)
+
self
.
ifconfig
(
'
hw
'
,
'
ether
'
,
macstr
)
+
self
.
ifconfig
(
'
up
'
)
)
_ipMatchRegex
=
re
.
compile
(
r
'
\d+\.\d+\.\d+\.\d+
'
)
_macMatchRegex
=
re
.
compile
(
r
'
..:..:..:..:..:..
'
)
def
updateIP
(
self
):
"
Return updated IP address based on ifconfig
"
ifconfig
=
self
.
ifconfig
()
ips
=
self
.
_ipMatchRegex
.
findall
(
ifconfig
)
self
.
ip
=
ips
[
0
]
if
ips
else
None
return
self
.
ip
def
updateMAC
(
self
,
intf
):
"
Return updated MAC address based on ifconfig
"
ifconfig
=
self
.
ifconfig
()
macs
=
self
.
_macMatchRegex
.
findall
(
ifconfig
)
self
.
mac
=
macs
[
0
]
if
macs
else
None
return
self
.
mac
def
IP
(
self
):
"
Return IP address
"
return
self
.
ip
def
MAC
(
self
):
"
Return MAC address
"
return
self
.
mac
def
isUp
(
self
,
set
=
False
):
"
Return whether interface is up
"
return
"
UP
"
in
self
.
ifconfig
()
# Map of config params to config methods
# Perhaps this could be more graceful, but it
# is flexible
configMap
=
{
'
mac
'
:
'
setMAC
'
,
'
ip
'
:
'
setIP
'
,
'
ifconfig
'
:
'
ifconfig
'
}
def
config
(
self
,
**
params
):
"
Configure interface based on parameters
"
self
.
__dict__
.
update
(
**
params
)
for
name
,
value
in
params
.
iteritems
():
method
=
self
.
configMap
.
get
(
name
,
None
)
if
method
:
if
type
(
value
)
is
str
:
value
=
value
.
split
(
'
,
'
)
method
(
value
)
def
delete
(
self
):
"
Delete interface
"
self
.
cmd
(
'
ip link del
'
+
self
.
name
)
# Does it help to sleep to let things run?
sleep
(
0.001
)
def
__str__
(
self
):
return
self
.
name
class
TCIntf
(
BasicIntf
):
"
Interface customized by tc (traffic control) utility
"
def
config
(
self
,
bw
=
None
,
delay
=
None
,
loss
=
0
,
disable_gro
=
True
,
speedup
=
0
,
use_hfsc
=
False
,
use_tbf
=
False
,
enable_ecn
=
False
,
enable_red
=
False
,
max_queue_size
=
1000
,
**
kwargs
):
"
Configure the port and set its properties.
"
BasicIntf
.
config
(
self
,
**
kwargs
)
# disable GRO
if
disable_gro
:
self
.
cmd
(
'
ethtool -K %s gro off
'
%
self
)
if
bw
is
None
and
not
delay
and
not
loss
:
return
if
bw
and
(
bw
<
0
or
bw
>
1000
):
error
(
'
Bandwidth
'
,
bw
,
'
is outside range 0..1000 Mbps
\n
'
)
return
if
delay
and
delay
<
0
:
error
(
'
Negative delay
'
,
delay
,
'
\n
'
)
return
if
loss
and
(
loss
<
0
or
loss
>
100
):
error
(
'
Bad loss percentage
'
,
loss
,
'
%%
\n
'
)
return
if
delay
is
None
:
delay
=
'
0ms
'
if
bw
is
not
None
and
delay
is
not
None
:
info
(
self
,
'
(bw %.2fMbit, delay %s, loss %d%%)
\n
'
%
(
bw
,
delay
,
loss
)
)
# BL: hmm... what exactly is this???
# This seems kind of brittle
if
speedup
>
0
and
self
.
node
.
name
[
0
:
2
]
==
'
sw
'
:
bw
=
speedup
tc
=
'
tc
'
# was getCmd( 'tc' )
# Bandwidth control algorithms
if
use_hfsc
:
cmds
=
[
'
%s qdisc del dev %s root
'
,
'
%s qdisc add dev %s root handle 1:0 hfsc default 1
'
]
if
bw
is
not
None
:
cmds
.
append
(
'
%s class add dev %s parent 1:0 classid 1:1 hfsc sc
'
+
'
rate %fMbit ul rate %fMbit
'
%
(
bw
,
bw
)
)
elif
use_tbf
:
latency_us
=
10
*
1500
*
8
/
bw
cmds
=
[
'
%s qdisc del dev %s root
'
,
'
%s qdisc add dev %s root handle 1: tbf
'
+
'
rate %fMbit burst 15000 latency %fus
'
%
(
bw
,
latency_us
)
]
else
:
cmds
=
[
'
%s qdisc del dev %s root
'
,
'
%s qdisc add dev %s root handle 1:0 htb default 1
'
,
'
%s class add dev %s parent 1:0 classid 1:1 htb
'
+
'
rate %fMbit burst 15k
'
%
bw
]
# ECN or RED
if
enable_ecn
:
info
(
'
Enabling ECN
\n
'
)
cmds
+=
[
'
%s qdisc add dev %s parent 1:1
'
+
'
handle 10: red limit 1000000
'
+
'
min 20000 max 25000 avpkt 1000
'
+
'
burst 20
'
+
'
bandwidth %fmbit probability 1 ecn
'
%
bw
]
elif
enable_red
:
info
(
'
Enabling RED
\n
'
)
cmds
+=
[
'
%s qdisc add dev %s parent 1:1
'
+
'
handle 10: red limit 1000000
'
+
'
min 20000 max 25000 avpkt 1000
'
+
'
burst 20
'
+
'
bandwidth %fmbit probability 1
'
%
bw
]
else
:
cmds
+=
[
'
%s qdisc add dev %s parent 1:1 handle 10:0 netem
'
+
'
delay
'
+
'
%s
'
%
delay
+
'
loss
'
+
'
%d
'
%
loss
+
'
limit %d
'
%
(
max_queue_size
)
]
# Execute all the commands in the container
debug
(
"
at map stage w/cmds: %s
\n
"
%
cmds
)
def
doConfigPort
(
s
):
c
=
s
%
(
tc
,
self
)
debug
(
"
*** executing command: %s
\n
"
%
c
)
return
self
.
cmd
(
c
)
outputs
=
[
doConfigPort
(
cmd
)
for
cmd
in
cmds
]
debug
(
"
outputs: %s
\n
"
%
outputs
)
Intf
=
TCIntf
class
Link
(
object
):
"""
A basic link is just a veth pair.
Other types of links could be tunnels, link emulators, etc..
"""
def
__init__
(
self
,
node1
,
node2
,
port1
=
None
,
port2
=
None
,
intfName1
=
None
,
intfName2
=
None
,
intf
=
Intf
,
params1
=
{},
params2
=
{}
):
"""
Create veth link to another node, making two new interfaces.
node1: first node
node2: second node
port1: node1 port number (optional)
port2: node2 port number (optional)
intfName1: node1 interface name (optional)
intfName2: node2 interface name (optional)
"""
# This is a bit awkward; it seems that having everything in
# params would be more orthogonal, but being able to specify
# in-line arguments is more convenient!
if
port1
is
None
:
port1
=
node1
.
newPort
()
if
port2
is
None
:
port2
=
node2
.
newPort
()
if
not
intfName1
:
intfName1
=
self
.
intfName
(
node1
,
port1
)
if
not
intfName2
:
intfName2
=
self
.
intfName
(
node2
,
port2
)
self
.
makeIntfPair
(
intfName1
,
intfName2
)
intf1
=
intf
(
name
=
intfName1
,
node
=
node1
,
link
=
self
,
**
params1
)
intf2
=
intf
(
name
=
intfName2
,
node
=
node2
,
link
=
self
,
**
params2
)
# Add to nodes
node1
.
addIntf
(
intf1
)
node2
.
addIntf
(
intf2
)
self
.
intf1
,
self
.
intf2
=
intf1
,
intf2
@classmethod
def
intfName
(
cls
,
node
,
n
):
"
Construct a canonical interface name node-ethN for interface n.
"
return
node
.
name
+
'
-eth
'
+
repr
(
n
)
@classmethod
def
makeIntfPair
(
cls
,
intf1
,
intf2
):
"""
Create pair of interfaces
intf1: name of interface 1
intf2: name of interface 2
(override this class method [and possibly delete()] to change link type)
"""
makeIntfPair
(
intf1
,
intf2
)
def
delete
(
self
):
"
Delete this link
"
self
.
intf1
.
delete
()
self
.
intf2
.
delete
()
def
__str__
(
self
):
return
'
%s<->%s
'
%
(
self
.
intf1
,
self
.
intf2
)
This diff is collapsed.
Click to expand it.
mininet/net.py
+
50
−
31
View file @
a6bcad8f
"""
Mininet: A simple networking testbed for OpenFlow!
Mininet: A simple networking testbed for OpenFlow
/SDN
!
author: Bob Lantz (rlantz@cs.stanford.edu)
author: Brandon Heller (brandonh@stanford.edu)
...
...
@@ -96,6 +96,7 @@
from
mininet.log
import
info
,
error
,
debug
,
output
from
mininet.node
import
Host
,
UserSwitch
,
OVSKernelSwitch
,
Controller
from
mininet.node
import
ControllerParams
from
mininet.link
import
Link
from
mininet.util
import
quietRun
,
fixLimits
from
mininet.util
import
createLink
,
macColonHex
,
ipStr
,
ipParse
from
mininet.term
import
cleanUpScreens
,
makeTerms
...
...
@@ -104,16 +105,17 @@ class Mininet( object ):
"
Network emulation with hosts spawned in network namespaces.
"
def
__init__
(
self
,
topo
=
None
,
switch
=
OVSKernelSwitch
,
host
=
Host
,
controller
=
Controller
,
controller
=
Controller
,
link
=
Link
,
cparams
=
ControllerParams
(
'
10.0.0.0
'
,
8
),
build
=
True
,
xterms
=
False
,
cleanup
=
False
,
inNamespace
=
False
,
autoSetMacs
=
False
,
autoStaticArp
=
False
,
listenPort
=
None
):
"""
Create Mininet object.
topo: Topo (topology) object or None
switch: Switch class
host: Host class
controller: Controller class
switch: default Switch class
host: default Host class/constructor
controller: default Controller class/constructor
link: default Link class/constructor
cparams: ControllerParams object
build: build now from topo?
xterms: if build now, spawn xterms?
...
...
@@ -126,6 +128,7 @@ def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host,
self
.
switch
=
switch
self
.
host
=
host
self
.
controller
=
controller
self
.
link
=
link
self
.
cparams
=
cparams
self
.
topo
=
topo
self
.
inNamespace
=
inNamespace
...
...
@@ -150,30 +153,38 @@ def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host,
if
topo
and
build
:
self
.
build
()
def
addHost
(
self
,
name
,
mac
=
None
,
ip
=
None
):
# BL Note:
# The specific items for host/switch/etc. should probably be
# handled in the node classes rather than here!!
def
addHost
(
self
,
name
,
mac
=
None
,
ip
=
None
,
host
=
None
,
**
params
):
"""
Add host.
name: name of host to add
mac: default MAC address for intf 0
ip: default IP address for intf 0
returns: added host
"""
host
=
self
.
host
(
name
,
defaultMAC
=
mac
,
defaultIP
=
ip
)
self
.
hosts
.
append
(
host
)
self
.
nameToNode
[
name
]
=
host
return
host
def
addSwitch
(
self
,
name
,
mac
=
None
,
ip
=
None
):
if
not
host
:
host
=
self
.
host
defaults
=
{
'
defaultMAC
'
:
mac
,
'
defaultIP
'
:
ip
}
defaults
.
update
(
params
)
h
=
host
(
name
,
**
defaults
)
self
.
hosts
.
append
(
h
)
self
.
nameToNode
[
name
]
=
h
return
h
def
addSwitch
(
self
,
name
,
switch
=
None
,
**
params
):
"""
Add switch.
name: name of switch to add
mac: default MAC address for kernel/OVS switch intf 0
returns: added switch
side effect: increments the listenPort member variable.
"""
if
self
.
switch
==
UserSwitch
:
sw
=
self
.
switch
(
name
,
listenPort
=
self
.
listenPort
,
defaultMAC
=
mac
,
defaultIP
=
ip
,
inNamespace
=
self
.
inNamespace
)
else
:
sw
=
self
.
switch
(
name
,
listenPort
=
self
.
listenPort
,
defaultMAC
=
mac
,
defaultIP
=
ip
,
dp
=
self
.
dps
,
inNamespace
=
self
.
inNamespace
)
side effect: increments listenPort and dps ivars.
"""
defaults
=
{
'
listenPort
'
:
self
.
listenPort
,
'
inNamespace
'
:
self
.
inNamespace
}
if
not
switch
:
switch
=
self
.
switch
if
switch
!=
UserSwitch
:
defaults
[
'
dps
'
]
=
self
.
dps
defaults
.
update
(
params
)
sw
=
self
.
switch
(
name
,
**
defaults
)
if
not
self
.
inNamespace
and
self
.
listenPort
:
self
.
listenPort
+=
1
self
.
dps
+=
1
...
...
@@ -181,12 +192,12 @@ def addSwitch( self, name, mac=None, ip=None ):
self
.
nameToNode
[
name
]
=
sw
return
sw
def
addController
(
self
,
name
=
'
c0
'
,
controller
=
None
,
**
kwarg
s
):
def
addController
(
self
,
name
=
'
c0
'
,
controller
=
None
,
**
param
s
):
"""
Add controller.
controller: Controller class
"""
if
not
controller
:
controller
=
self
.
controller
controller_new
=
controller
(
name
,
**
kwarg
s
)
controller_new
=
controller
(
name
,
**
param
s
)
if
controller_new
:
# allow controller-less setups
self
.
controllers
.
append
(
controller_new
)
self
.
nameToNode
[
name
]
=
controller_new
...
...
@@ -210,6 +221,9 @@ def addController( self, name='c0', controller=None, **kwargs ):
# 4. Even if we dispense with this in general, it could still be
# useful for people who wish to simulate a separate control
# network (since real networks may need one!)
#
# 5. Basically nobody ever uses this method, so perhaps it should be moved
# out of this core class.
def
configureControlNetwork
(
self
):
"
Configure control network.
"
...
...
@@ -221,8 +235,7 @@ def configureControlNetwork( self ):
def
configureRoutedControlNetwork
(
self
,
ip
=
'
192.168.123.1
'
,
prefixLen
=
16
):
"""
Configure a routed control network on controller and switches.
For use with the user datapath only right now.
"""
For use with the user datapath only right now.
"""
controller
=
self
.
controllers
[
0
]
info
(
controller
.
name
+
'
<->
'
)
cip
=
ip
...
...
@@ -256,8 +269,8 @@ def configHosts( self ):
"
Configure a set of hosts.
"
# params were: hosts, ips
for
host
in
self
.
hosts
:
hintf
=
host
.
intfs
[
0
]
host
.
setIP
(
hintf
,
host
.
defaultIP
,
self
.
cparams
.
prefixLen
)
hintf
=
host
.
defaultIntf
()
host
.
setIP
(
host
.
defaultIP
,
self
.
cparams
.
prefixLen
,
hintf
)
host
.
setDefaultRoute
(
hintf
)
# You're low priority, dude!
quietRun
(
'
renice +18 -p
'
+
repr
(
host
.
pid
)
)
...
...
@@ -272,9 +285,11 @@ def buildFromTopo( self, topo ):
def
addNode
(
prefix
,
addMethod
,
nodeId
):
"
Add a host or a switch.
"
name
=
prefix
+
topo
.
name
(
nodeId
)
# MAC and IP should probably be from nodeInfo...
mac
=
macColonHex
(
nodeId
)
if
self
.
setMacs
else
None
ip
=
topo
.
ip
(
nodeId
)
node
=
addMethod
(
name
,
mac
=
mac
,
ip
=
ip
)
ni
=
topo
.
nodeInfo
(
nodeId
)
node
=
addMethod
(
name
,
cls
=
ni
.
cls
,
mac
=
mac
,
ip
=
ip
,
**
ni
.
params
)
self
.
idToNode
[
nodeId
]
=
node
info
(
name
+
'
'
)
...
...
@@ -291,12 +306,16 @@ def addNode( prefix, addMethod, nodeId ):
addNode
(
'
h
'
,
self
.
addHost
,
hostId
)
info
(
'
\n
*** Adding switches:
\n
'
)
for
switchId
in
sorted
(
topo
.
switches
()
):
addNode
(
'
s
'
,
self
.
addSwitch
,
switchId
)
addNode
(
'
s
'
,
self
.
addSwitch
,
switchId
)
info
(
'
\n
*** Adding links:
\n
'
)
for
srcId
,
dstId
in
sorted
(
topo
.
edges
()
):
src
,
dst
=
self
.
idToNode
[
srcId
],
self
.
idToNode
[
dstId
]
srcPort
,
dstPort
=
topo
.
port
(
srcId
,
dstId
)
createLink
(
src
,
dst
,
srcPort
,
dstPort
)
ei
=
topo
.
edgeInfo
(
srcId
,
dstId
)
link
,
params
=
ei
.
cls
,
ei
.
params
if
not
link
:
link
=
self
.
link
link
(
src
,
dst
,
srcPort
,
dstPort
,
**
params
)
info
(
'
(%s, %s)
'
%
(
src
.
name
,
dst
.
name
)
)
info
(
'
\n
'
)
...
...
@@ -510,7 +529,7 @@ def iperf( self, hosts=None, l4Type='TCP', udpBw='10M' ):
servout
+=
server
.
monitor
()
while
'
Connected
'
not
in
client
.
cmd
(
'
sh -c
"
echo A | telnet -e A %s 5001
"'
%
server
.
IP
()):
output
(
'
waiting for iperf to start up
'
)
output
(
'
waiting for iperf to start up
...
'
)
sleep
(.
5
)
cliout
=
client
.
cmd
(
iperfArgs
+
'
-t 5 -c
'
+
server
.
IP
()
+
'
'
+
bwArgs
)
...
...
This diff is collapsed.
Click to expand it.
mininet/node.py
+
75
−
121
View file @
a6bcad8f
...
...
@@ -46,11 +46,11 @@
import
signal
import
select
from
subprocess
import
Popen
,
PIPE
,
STDOUT
from
time
import
sleep
from
mininet.log
import
info
,
error
,
debug
from
mininet.util
import
quietRun
,
errRun
,
makeIntfPair
,
moveIntf
,
isShellBuiltin
from
mininet.util
import
quietRun
,
errRun
,
moveIntf
,
isShellBuiltin
from
mininet.moduledeps
import
moduleDeps
,
pathCheck
,
OVS_KMOD
,
OF_KMOD
,
TUN
from
mininet.link
import
Link
SWITCH_PORT_BASE
=
1
# For OF > 0.9, switch ports start at 1 rather than zero
...
...
@@ -78,7 +78,7 @@ def __init__( self, name, inNamespace=True,
opts
+=
'
n
'
cmd
=
[
'
mnexec
'
,
opts
,
'
bash
'
,
'
-m
'
]
self
.
shell
=
Popen
(
cmd
,
stdin
=
PIPE
,
stdout
=
PIPE
,
stderr
=
STDOUT
,
close_fds
=
Fals
e
)
close_fds
=
Tru
e
)
self
.
stdin
=
self
.
shell
.
stdin
self
.
stdout
=
self
.
shell
.
stdout
self
.
pid
=
self
.
shell
.
pid
...
...
@@ -89,12 +89,10 @@ def __init__( self, name, inNamespace=True,
# using select.poll()
self
.
outToNode
[
self
.
stdout
.
fileno
()
]
=
self
self
.
inToNode
[
self
.
stdin
.
fileno
()
]
=
self
self
.
intfs
=
{}
# dict of port numbers to interface
name
s
self
.
ports
=
{}
# dict of interface
name
s to port numbers
self
.
intfs
=
{}
# dict of port numbers to interfaces
self
.
ports
=
{}
# dict of interfaces to port numbers
# replace with Port objects, eventually ?
self
.
ips
=
{}
# dict of interfaces to ip addresses as strings
self
.
macs
=
{}
# dict of interfacesto mac addresses as strings
self
.
connection
=
{}
# remote node connected to each interface
self
.
nameToIntf
=
{}
# dict of interface names to Intfs
self
.
execed
=
False
self
.
lastCmd
=
None
self
.
lastPid
=
None
...
...
@@ -172,7 +170,7 @@ def sendCmd( self, *args, **kwargs ):
if
len
(
args
)
>
0
:
cmd
=
args
if
not
isinstance
(
cmd
,
str
):
cmd
=
'
'
.
join
(
cmd
)
cmd
=
'
'
.
join
(
[
str
(
c
)
for
c
in
cmd
]
)
if
not
re
.
search
(
r
'
\w
'
,
cmd
):
# Replace empty commands with something harmless
cmd
=
'
echo -n
'
...
...
@@ -254,10 +252,6 @@ def cmdPrint( self, *args):
# the real interfaces are created as veth pairs, so we can't
# make a single interface at a time.
def
intfName
(
self
,
n
):
"
Construct a canonical interface name node-ethN for interface n.
"
return
self
.
name
+
'
-eth
'
+
repr
(
n
)
def
newPort
(
self
):
"
Return the next port number to allocate.
"
if
len
(
self
.
ports
)
>
0
:
...
...
@@ -266,56 +260,45 @@ def newPort( self ):
def
addIntf
(
self
,
intf
,
port
=
None
):
"""
Add an interface.
intf: interface
name (e.g. nodeN-ethM)
intf: interface
port: port number (optional, typically OpenFlow port number)
"""
if
port
is
None
:
port
=
self
.
newPort
()
self
.
intfs
[
port
]
=
intf
self
.
ports
[
intf
]
=
port
#info( '\n' )
#info( 'added intf %s:%d to node %s\n' % ( intf,port, self.name ) )
self
.
nameToIntf
[
intf
.
name
]
=
intf
info
(
'
\n
'
)
info
(
'
added intf %s:%d to node %s
\n
'
%
(
intf
,
port
,
self
.
name
)
)
if
self
.
inNamespace
:
#
info( 'moving
w/inNamespace set
\n' )
moveIntf
(
intf
,
self
)
info
(
'
moving
'
,
intf
,
'
into namespace for
'
,
self
.
name
,
'
\n
'
)
moveIntf
(
intf
.
name
,
self
)
def
registerIntf
(
self
,
intf
,
dstNode
,
dstIntf
):
"
Register connection of intf to dstIntf on dstNode.
"
self
.
connection
[
intf
]
=
(
dstNode
,
dstIntf
)
def
defaultIntf
(
self
):
"
Return interface for lowest port
"
ports
=
self
.
intfs
.
keys
()
if
ports
:
return
self
.
intfs
[
min
(
ports
)
]
def
connectionsTo
(
self
,
node
):
"
Return [(srcIntf, dstIntf)..] for connections to dstNode.
"
def
intf
(
self
,
intf
=
''
):
"""
Return our interface object with given name,x
or default intf if name is empty
"""
if
not
intf
:
return
self
.
defaultIntf
()
elif
type
(
intf
)
is
str
:
return
self
.
nameToIntf
[
intf
]
else
:
return
intf
def
linksTo
(
self
,
node
):
"
Return [ link1, link2...] for all links from self to node.
"
# We could optimize this if it is important
connections
=
[]
for
intf
in
self
.
connection
.
keys
():
dstNode
,
dstIntf
=
self
.
connection
[
intf
]
if
dstNode
==
node
:
connections
.
append
(
(
intf
,
dstIntf
)
)
return
connections
# This is a symmetric operation, but it makes sense to put
# the code here since it is tightly coupled to routines in
# this class. For a more symmetric API, you can use
# mininet.util.createLink()
def
linkTo
(
self
,
node2
,
port1
=
None
,
port2
=
None
):
"""
Create link to another node, making two new interfaces.
node2: Node to link us to
port1: our port number (optional)
port2: node2 port number (optional)
returns: intf1 name, intf2 name
"""
node1
=
self
if
port1
is
None
:
port1
=
node1
.
newPort
()
if
port2
is
None
:
port2
=
node2
.
newPort
()
intf1
=
node1
.
intfName
(
port1
)
intf2
=
node2
.
intfName
(
port2
)
makeIntfPair
(
intf1
,
intf2
)
node1
.
addIntf
(
intf1
,
port1
)
node2
.
addIntf
(
intf2
,
port2
)
node1
.
registerIntf
(
intf1
,
node2
,
intf2
)
node2
.
registerIntf
(
intf2
,
node1
,
intf1
)
return
intf1
,
intf2
links
=
[]
for
intf
in
self
.
intfs
:
link
=
intf
.
link
nodes
=
(
link
.
intf1
.
node
,
link
.
intf2
.
node
)
if
self
in
nodes
and
node
in
nodes
:
links
.
append
(
link
)
return
links
def
deleteIntfs
(
self
):
"
Delete all of our interfaces.
"
...
...
@@ -325,18 +308,10 @@ def deleteIntfs( self ):
# 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
():
quietRun
(
'
ip link del
'
+
intf
)
intf
.
delete
(
)
info
(
'
.
'
)
# Does it help to sleep to let things run?
sleep
(
0.001
)
def
setMAC
(
self
,
intf
,
mac
):
"""
Set the MAC address for an interface.
mac: MAC address as string
"""
result
=
self
.
cmd
(
'
ifconfig
'
,
intf
,
'
down
'
)
result
+=
self
.
cmd
(
'
ifconfig
'
,
intf
,
'
hw
'
,
'
ether
'
,
mac
)
result
+=
self
.
cmd
(
'
ifconfig
'
,
intf
,
'
up
'
)
return
result
# Routing support
def
setARP
(
self
,
ip
,
mac
):
"""
Add an ARP entry.
...
...
@@ -345,16 +320,6 @@ def setARP( self, ip, mac ):
result
=
self
.
cmd
(
'
arp
'
,
'
-s
'
,
ip
,
mac
)
return
result
def
setIP
(
self
,
intf
,
ip
,
prefixLen
=
8
):
"""
Set the IP address for an interface.
intf: interface name
ip: IP address as a string
prefixLen: prefix length, e.g. 8 for /8 or 16M addrs
"""
ipSub
=
'
%s/%d
'
%
(
ip
,
prefixLen
)
result
=
self
.
cmd
(
'
ifconfig
'
,
intf
,
ipSub
,
'
up
'
)
self
.
ips
[
intf
]
=
ip
return
result
def
setHostRoute
(
self
,
ip
,
intf
):
"""
Add route to host.
ip: IP address as dotted decimal
...
...
@@ -365,62 +330,52 @@ def setDefaultRoute( self, intf ):
"""
Set the default route to go through intf.
intf: string, interface name
"""
self
.
cmd
(
'
ip route flush root 0/0
'
)
return
self
.
cmd
(
'
route add default
'
+
intf
)
return
self
.
cmd
(
'
route add default
%s
'
%
intf
)
def
defaultIntf
(
self
):
"
Return interface for lowest port
"
ports
=
self
.
intfs
.
keys
()
if
ports
:
return
self
.
intfs
[
min
(
ports
)
]
# Convenience methods
_ipMatchRegex
=
re
.
compile
(
r
'
\d+\.\d+\.\d+\.\d+
'
)
_macMatchRegex
=
re
.
compile
(
r
'
..:..:..:..:..:..
'
)
def
setMAC
(
self
,
mac
,
intf
=
''
):
"""
Set the MAC address for an interface.
intf: intf or intf name
mac: MAC address as string
"""
return
self
.
intf
(
intf
).
setMAC
(
mac
)
def
setIP
(
self
,
ip
,
prefixLen
=
8
,
intf
=
''
):
"""
Set the IP address for an interface.
intf: interface name
ip: IP address as a string
prefixLen: prefix length, e.g. 8 for /8 or 16M addrs
"""
# This should probably be rethought:
ipSub
=
'
%s/%s
'
%
(
ip
,
prefixLen
)
return
self
.
intf
(
intf
).
setIP
(
ipSub
)
def
IP
(
self
,
intf
=
None
):
"
Return IP address of a node or specific interface.
"
if
intf
is
None
:
intf
=
self
.
defaultIntf
()
if
intf
and
not
self
.
waiting
:
self
.
updateIP
(
intf
)
return
self
.
ips
.
get
(
intf
,
None
)
return
self
.
intf
(
intf
).
IP
()
def
MAC
(
self
,
intf
=
None
):
"
Return MAC address of a node or specific interface.
"
if
intf
is
None
:
intf
=
self
.
defaultIntf
()
if
intf
and
not
self
.
waiting
:
self
.
updateMAC
(
intf
)
return
self
.
macs
.
get
(
intf
,
None
)
def
updateIP
(
self
,
intf
):
"
Update IP address for an interface
"
assert
not
self
.
waiting
ifconfig
=
self
.
cmd
(
'
ifconfig
'
+
intf
)
ips
=
self
.
_ipMatchRegex
.
findall
(
ifconfig
)
if
ips
:
self
.
ips
[
intf
]
=
ips
[
0
]
else
:
self
.
ips
[
intf
]
=
None
return
self
.
intf
(
intf
).
MAC
()
def
updateMAC
(
self
,
intf
):
"
Update MAC address for an interface
"
assert
not
self
.
waiting
ifconfig
=
self
.
cmd
(
'
ifconfig
'
+
intf
)
macs
=
self
.
_macMatchRegex
.
findall
(
ifconfig
)
if
macs
:
self
.
macs
[
intf
]
=
macs
[
0
]
else
:
self
.
macs
[
intf
]
=
None
def
intfIsUp
(
self
,
intf
):
def
intfIsUp
(
self
,
intf
=
None
):
"
Check if an interface is up.
"
return
'
UP
'
in
self
.
cmd
(
'
ifconfig
'
+
intf
)
return
self
.
intf
(
intf
).
isUp
()
# This is here for backward compatibility
def
linkTo
(
self
,
node
,
link
=
Link
):
"""
(Deprecated) Link to another node
replace with Link( node1, node2)
"""
return
link
(
self
,
node
)
# Other methods
def
intfNames
(
self
):
"
The names of our interfaces
"
return
[
str
(
i
)
for
i
in
sorted
(
self
.
ports
.
values
()
)
]
def
__str__
(
self
):
intfs
=
sorted
(
self
.
intfs
.
values
()
)
return
'
%s: IP=%s intfs=%s pid=%s
'
%
(
self
.
name
,
self
.
IP
(),
'
,
'
.
join
(
intfs
),
self
.
pid
)
self
.
name
,
self
.
IP
(),
'
,
'
.
join
(
self
.
intfNames
()
),
self
.
pid
)
class
Host
(
Node
):
...
...
@@ -623,10 +578,9 @@ class OVSSwitch( Switch ):
def
__init__
(
self
,
name
,
dp
=
None
,
**
kwargs
):
"""
Init.
name: name for switch
dp: netlink id (0, 1, 2, ...)
defaultMAC: default MAC as unsigned int; random value if None
"""
Switch
.
__init__
(
self
,
name
,
**
kwargs
)
self
.
dp
=
'
dp%i
'
%
dp
self
.
dp
=
name
@staticmethod
def
setup
():
...
...
@@ -671,7 +625,6 @@ def stop( self ):
OVSKernelSwitch
=
OVSSwitch
class
Controller
(
Node
):
"""
A Controller is a Node that is running (or has execed?) an
OpenFlow controller.
"""
...
...
@@ -704,8 +657,9 @@ def stop( self ):
def
IP
(
self
,
intf
=
None
):
"
Return IP address of the Controller
"
ip
=
Node
.
IP
(
self
,
intf
=
intf
)
if
ip
is
None
:
if
self
.
intfs
:
ip
=
Node
.
IP
(
self
,
intf
)
else
:
ip
=
self
.
defaultIP
return
ip
...
...
This diff is collapsed.
Click to expand it.
mininet/topo.py
+
49
−
13
View file @
a6bcad8f
...
...
@@ -16,7 +16,14 @@
# from networkx.classes.graph import Graph
from
networkx
import
Graph
from
mininet.node
import
SWITCH_PORT_BASE
from
mininet.node
import
SWITCH_PORT_BASE
,
Host
,
OVSSwitch
from
mininet.link
import
Link
# BL: it's hard to figure out how to do this right yet remain flexible
# These classes will be used as the defaults if no class is passed
# into either Topo() or Node()
TopoDefaultNode
=
Host
TopoDefaultSwitch
=
OVSSwitch
class
NodeID
(
object
):
'''
Topo node identifier.
'''
...
...
@@ -54,11 +61,12 @@ def ip_str(self):
return
"
10.%i.%i.%i
"
%
(
hi
,
mid
,
lo
)
class
Node
(
object
):
class
Node
(
object
):
'''
Node-specific vertex metadata for a Topo object.
'''
def
__init__
(
self
,
connected
=
False
,
admin_on
=
True
,
power_on
=
True
,
fault
=
False
,
is_switch
=
True
):
def
__init__
(
self
,
connected
=
False
,
admin_on
=
True
,
power_on
=
True
,
fault
=
False
,
is_switch
=
True
,
cls
=
None
,
**
params
):
'''
Init.
@param connected actively connected to controller
...
...
@@ -66,18 +74,26 @@ def __init__(self, connected = False, admin_on = True,
@param power_on powered on or off
@param fault fault seen on node
@param is_switch switch or host
@param cls node class (e.g. Host, Switch)
@param params node parameters
'''
self
.
connected
=
connected
self
.
admin_on
=
admin_on
self
.
power_on
=
power_on
self
.
fault
=
fault
self
.
is_switch
=
is_switch
# Above should be deleted and replaced by the following
# BL: is_switch is a bit annoying if we can just specify
# the node class instead!!
self
.
cls
=
cls
if
cls
else
(
TopoDefaultSwitch
if
is_switch
else
TopoDefaultNode
)
self
.
params
=
params
if
params
else
{}
class
Edge
(
object
):
'''
Edge-specific metadata for a StructuredTopo graph.
'''
def
__init__
(
self
,
admin_on
=
True
,
power_on
=
True
,
fault
=
False
):
def
__init__
(
self
,
admin_on
=
True
,
power_on
=
True
,
fault
=
False
,
cls
=
Link
,
**
params
):
'''
Init.
@param admin_on administratively on or off; defaults to True
...
...
@@ -87,31 +103,40 @@ def __init__(self, admin_on = True, power_on = True, fault = False):
self
.
admin_on
=
admin_on
self
.
power_on
=
power_on
self
.
fault
=
fault
# Above should be deleted and replaced by the following
self
.
cls
=
cls
self
.
params
=
params
class
Topo
(
object
):
'''
Data center network representation for structured multi-trees.
'''
def
__init__
(
self
):
'''
Create Topo object.
'''
def
__init__
(
self
,
node
=
Host
,
switch
=
None
,
link
=
Link
):
"""
Create Topo object.
node: default node/host class
switch: default switch class
Link: default link class
"""
self
.
g
=
Graph
()
self
.
node_info
=
{}
# dpids hash to Node objects
self
.
edge_info
=
{}
# (src_dpid, dst_dpid) tuples hash to Edge objects
self
.
ports
=
{}
# ports[src][dst] is port on src that connects to dst
self
.
id_gen
=
NodeID
# class used to generate dpid
self
.
node
=
node
self
.
switch
=
switch
self
.
link
=
link
def
add_node
(
self
,
dpid
,
node
):
def
add_node
(
self
,
dpid
,
node
=
None
):
'''
Add Node to graph.
@param dpid dpid
@param node Node object
'''
self
.
g
.
add_node
(
dpid
)
if
not
node
:
node
=
Node
(
link
=
self
.
link
)
self
.
node_info
[
dpid
]
=
node
def
add_edge
(
self
,
src
,
dst
,
edge
=
None
):
def
add_edge
(
self
,
src
,
dst
,
edge
=
None
):
'''
Add edge (Node, Node) to graph.
@param src src dpid
...
...
@@ -121,7 +146,7 @@ def add_edge(self, src, dst, edge = None):
src
,
dst
=
tuple
(
sorted
([
src
,
dst
]))
self
.
g
.
add_edge
(
src
,
dst
)
if
not
edge
:
edge
=
Edge
()
edge
=
Edge
(
link
=
self
.
link
)
self
.
edge_info
[(
src
,
dst
)]
=
edge
self
.
add_port
(
src
,
dst
)
...
...
@@ -276,6 +301,12 @@ def port(self, src, dst):
assert
dst
in
self
.
ports
and
src
in
self
.
ports
[
dst
]
return
(
self
.
ports
[
src
][
dst
],
self
.
ports
[
dst
][
src
])
def
edgeInfo
(
self
,
src
,
dst
):
"
Return edge metadata
"
# BL: Perhaps this should be rethought or we should just use the
# dicts...
return
self
.
edge_info
[
(
src
,
dst
)
]
def
enable_edges
(
self
):
'''
Enable all edges in the network graph.
...
...
@@ -321,7 +352,12 @@ def ip(self, dpid):
'''
return
self
.
id_gen
(
dpid
=
dpid
).
ip_str
()
def
nodeInfo
(
self
,
dpid
):
"
Return metadata for node
"
# BL: may wish to rethink this or just use dicts..
return
self
.
node_info
[
dpid
]
class
SingleSwitchTopo
(
Topo
):
'''
Single switch connected to k hosts.
'''
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment