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: Bob Lantz (rlantz@cs.stanford.edu)
author: Brandon Heller (brandonh@stanford.edu)
author: Brandon Heller (brandonh@stanford.edu)
...
@@ -96,6 +96,7 @@
...
@@ -96,6 +96,7 @@
from
mininet.log
import
info
,
error
,
debug
,
output
from
mininet.log
import
info
,
error
,
debug
,
output
from
mininet.node
import
Host
,
UserSwitch
,
OVSKernelSwitch
,
Controller
from
mininet.node
import
Host
,
UserSwitch
,
OVSKernelSwitch
,
Controller
from
mininet.node
import
ControllerParams
from
mininet.node
import
ControllerParams
from
mininet.link
import
Link
from
mininet.util
import
quietRun
,
fixLimits
from
mininet.util
import
quietRun
,
fixLimits
from
mininet.util
import
createLink
,
macColonHex
,
ipStr
,
ipParse
from
mininet.util
import
createLink
,
macColonHex
,
ipStr
,
ipParse
from
mininet.term
import
cleanUpScreens
,
makeTerms
from
mininet.term
import
cleanUpScreens
,
makeTerms
...
@@ -104,16 +105,17 @@ class Mininet( object ):
...
@@ -104,16 +105,17 @@ class Mininet( object ):
"
Network emulation with hosts spawned in network namespaces.
"
"
Network emulation with hosts spawned in network namespaces.
"
def
__init__
(
self
,
topo
=
None
,
switch
=
OVSKernelSwitch
,
host
=
Host
,
def
__init__
(
self
,
topo
=
None
,
switch
=
OVSKernelSwitch
,
host
=
Host
,
controller
=
Controller
,
controller
=
Controller
,
link
=
Link
,
cparams
=
ControllerParams
(
'
10.0.0.0
'
,
8
),
cparams
=
ControllerParams
(
'
10.0.0.0
'
,
8
),
build
=
True
,
xterms
=
False
,
cleanup
=
False
,
build
=
True
,
xterms
=
False
,
cleanup
=
False
,
inNamespace
=
False
,
inNamespace
=
False
,
autoSetMacs
=
False
,
autoStaticArp
=
False
,
listenPort
=
None
):
autoSetMacs
=
False
,
autoStaticArp
=
False
,
listenPort
=
None
):
"""
Create Mininet object.
"""
Create Mininet object.
topo: Topo (topology) object or None
topo: Topo (topology) object or None
switch: Switch class
switch: default Switch class
host: Host class
host: default Host class/constructor
controller: Controller class
controller: default Controller class/constructor
link: default Link class/constructor
cparams: ControllerParams object
cparams: ControllerParams object
build: build now from topo?
build: build now from topo?
xterms: if build now, spawn xterms?
xterms: if build now, spawn xterms?
...
@@ -126,6 +128,7 @@ def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host,
...
@@ -126,6 +128,7 @@ def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host,
self
.
switch
=
switch
self
.
switch
=
switch
self
.
host
=
host
self
.
host
=
host
self
.
controller
=
controller
self
.
controller
=
controller
self
.
link
=
link
self
.
cparams
=
cparams
self
.
cparams
=
cparams
self
.
topo
=
topo
self
.
topo
=
topo
self
.
inNamespace
=
inNamespace
self
.
inNamespace
=
inNamespace
...
@@ -150,30 +153,38 @@ def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host,
...
@@ -150,30 +153,38 @@ def __init__( self, topo=None, switch=OVSKernelSwitch, host=Host,
if
topo
and
build
:
if
topo
and
build
:
self
.
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.
"""
Add host.
name: name of host to add
name: name of host to add
mac: default MAC address for intf 0
mac: default MAC address for intf 0
ip: default IP address for intf 0
ip: default IP address for intf 0
returns: added host
"""
returns: added host
"""
host
=
self
.
host
(
name
,
defaultMAC
=
mac
,
defaultIP
=
ip
)
if
not
host
:
self
.
hosts
.
append
(
host
)
host
=
self
.
host
self
.
nameToNode
[
name
]
=
host
defaults
=
{
'
defaultMAC
'
:
mac
,
'
defaultIP
'
:
ip
}
return
host
defaults
.
update
(
params
)
h
=
host
(
name
,
**
defaults
)
def
addSwitch
(
self
,
name
,
mac
=
None
,
ip
=
None
):
self
.
hosts
.
append
(
h
)
self
.
nameToNode
[
name
]
=
h
return
h
def
addSwitch
(
self
,
name
,
switch
=
None
,
**
params
):
"""
Add switch.
"""
Add switch.
name: name of switch to add
name: name of switch to add
mac: default MAC address for kernel/OVS switch intf 0
returns: added switch
returns: added switch
side effect: increments the listenPort member variable.
"""
side effect: increments listenPort and dps ivars.
"""
if
self
.
switch
==
UserSwitch
:
defaults
=
{
'
listenPort
'
:
self
.
listenPort
,
sw
=
self
.
switch
(
name
,
listenPort
=
self
.
listenPort
,
'
inNamespace
'
:
self
.
inNamespace
}
defaultMAC
=
mac
,
defaultIP
=
ip
,
inNamespace
=
self
.
inNamespace
)
if
not
switch
:
else
:
switch
=
self
.
switch
sw
=
self
.
switch
(
name
,
listenPort
=
self
.
listenPort
,
if
switch
!=
UserSwitch
:
defaultMAC
=
mac
,
defaultIP
=
ip
,
dp
=
self
.
dps
,
defaults
[
'
dps
'
]
=
self
.
dps
inNamespace
=
self
.
inNamespace
)
defaults
.
update
(
params
)
sw
=
self
.
switch
(
name
,
**
defaults
)
if
not
self
.
inNamespace
and
self
.
listenPort
:
if
not
self
.
inNamespace
and
self
.
listenPort
:
self
.
listenPort
+=
1
self
.
listenPort
+=
1
self
.
dps
+=
1
self
.
dps
+=
1
...
@@ -181,12 +192,12 @@ def addSwitch( self, name, mac=None, ip=None ):
...
@@ -181,12 +192,12 @@ def addSwitch( self, name, mac=None, ip=None ):
self
.
nameToNode
[
name
]
=
sw
self
.
nameToNode
[
name
]
=
sw
return
sw
return
sw
def
addController
(
self
,
name
=
'
c0
'
,
controller
=
None
,
**
kwarg
s
):
def
addController
(
self
,
name
=
'
c0
'
,
controller
=
None
,
**
param
s
):
"""
Add controller.
"""
Add controller.
controller: Controller class
"""
controller: Controller class
"""
if
not
controller
:
if
not
controller
:
controller
=
self
.
controller
controller
=
self
.
controller
controller_new
=
controller
(
name
,
**
kwarg
s
)
controller_new
=
controller
(
name
,
**
param
s
)
if
controller_new
:
# allow controller-less setups
if
controller_new
:
# allow controller-less setups
self
.
controllers
.
append
(
controller_new
)
self
.
controllers
.
append
(
controller_new
)
self
.
nameToNode
[
name
]
=
controller_new
self
.
nameToNode
[
name
]
=
controller_new
...
@@ -210,6 +221,9 @@ def addController( self, name='c0', controller=None, **kwargs ):
...
@@ -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
# 4. Even if we dispense with this in general, it could still be
# useful for people who wish to simulate a separate control
# useful for people who wish to simulate a separate control
# network (since real networks may need one!)
# 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
):
def
configureControlNetwork
(
self
):
"
Configure control network.
"
"
Configure control network.
"
...
@@ -221,8 +235,7 @@ def configureControlNetwork( self ):
...
@@ -221,8 +235,7 @@ def configureControlNetwork( self ):
def
configureRoutedControlNetwork
(
self
,
ip
=
'
192.168.123.1
'
,
def
configureRoutedControlNetwork
(
self
,
ip
=
'
192.168.123.1
'
,
prefixLen
=
16
):
prefixLen
=
16
):
"""
Configure a routed control network on controller and switches.
"""
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
]
controller
=
self
.
controllers
[
0
]
info
(
controller
.
name
+
'
<->
'
)
info
(
controller
.
name
+
'
<->
'
)
cip
=
ip
cip
=
ip
...
@@ -256,8 +269,8 @@ def configHosts( self ):
...
@@ -256,8 +269,8 @@ def configHosts( self ):
"
Configure a set of hosts.
"
"
Configure a set of hosts.
"
# params were: hosts, ips
# params were: hosts, ips
for
host
in
self
.
hosts
:
for
host
in
self
.
hosts
:
hintf
=
host
.
intfs
[
0
]
hintf
=
host
.
defaultIntf
()
host
.
setIP
(
hintf
,
host
.
defaultIP
,
self
.
cparams
.
prefixLen
)
host
.
setIP
(
host
.
defaultIP
,
self
.
cparams
.
prefixLen
,
hintf
)
host
.
setDefaultRoute
(
hintf
)
host
.
setDefaultRoute
(
hintf
)
# You're low priority, dude!
# You're low priority, dude!
quietRun
(
'
renice +18 -p
'
+
repr
(
host
.
pid
)
)
quietRun
(
'
renice +18 -p
'
+
repr
(
host
.
pid
)
)
...
@@ -272,9 +285,11 @@ def buildFromTopo( self, topo ):
...
@@ -272,9 +285,11 @@ def buildFromTopo( self, topo ):
def
addNode
(
prefix
,
addMethod
,
nodeId
):
def
addNode
(
prefix
,
addMethod
,
nodeId
):
"
Add a host or a switch.
"
"
Add a host or a switch.
"
name
=
prefix
+
topo
.
name
(
nodeId
)
name
=
prefix
+
topo
.
name
(
nodeId
)
# MAC and IP should probably be from nodeInfo...
mac
=
macColonHex
(
nodeId
)
if
self
.
setMacs
else
None
mac
=
macColonHex
(
nodeId
)
if
self
.
setMacs
else
None
ip
=
topo
.
ip
(
nodeId
)
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
self
.
idToNode
[
nodeId
]
=
node
info
(
name
+
'
'
)
info
(
name
+
'
'
)
...
@@ -291,12 +306,16 @@ def addNode( prefix, addMethod, nodeId ):
...
@@ -291,12 +306,16 @@ def addNode( prefix, addMethod, nodeId ):
addNode
(
'
h
'
,
self
.
addHost
,
hostId
)
addNode
(
'
h
'
,
self
.
addHost
,
hostId
)
info
(
'
\n
*** Adding switches:
\n
'
)
info
(
'
\n
*** Adding switches:
\n
'
)
for
switchId
in
sorted
(
topo
.
switches
()
):
for
switchId
in
sorted
(
topo
.
switches
()
):
addNode
(
'
s
'
,
self
.
addSwitch
,
switchId
)
addNode
(
'
s
'
,
self
.
addSwitch
,
switchId
)
info
(
'
\n
*** Adding links:
\n
'
)
info
(
'
\n
*** Adding links:
\n
'
)
for
srcId
,
dstId
in
sorted
(
topo
.
edges
()
):
for
srcId
,
dstId
in
sorted
(
topo
.
edges
()
):
src
,
dst
=
self
.
idToNode
[
srcId
],
self
.
idToNode
[
dstId
]
src
,
dst
=
self
.
idToNode
[
srcId
],
self
.
idToNode
[
dstId
]
srcPort
,
dstPort
=
topo
.
port
(
srcId
,
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
(
'
(%s, %s)
'
%
(
src
.
name
,
dst
.
name
)
)
info
(
'
\n
'
)
info
(
'
\n
'
)
...
@@ -510,7 +529,7 @@ def iperf( self, hosts=None, l4Type='TCP', udpBw='10M' ):
...
@@ -510,7 +529,7 @@ def iperf( self, hosts=None, l4Type='TCP', udpBw='10M' ):
servout
+=
server
.
monitor
()
servout
+=
server
.
monitor
()
while
'
Connected
'
not
in
client
.
cmd
(
while
'
Connected
'
not
in
client
.
cmd
(
'
sh -c
"
echo A | telnet -e A %s 5001
"'
%
server
.
IP
()):
'
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
)
sleep
(.
5
)
cliout
=
client
.
cmd
(
iperfArgs
+
'
-t 5 -c
'
+
server
.
IP
()
+
'
'
+
cliout
=
client
.
cmd
(
iperfArgs
+
'
-t 5 -c
'
+
server
.
IP
()
+
'
'
+
bwArgs
)
bwArgs
)
...
...
This diff is collapsed.
Click to expand it.
mininet/node.py
+
75
−
121
View file @
a6bcad8f
...
@@ -46,11 +46,11 @@
...
@@ -46,11 +46,11 @@
import
signal
import
signal
import
select
import
select
from
subprocess
import
Popen
,
PIPE
,
STDOUT
from
subprocess
import
Popen
,
PIPE
,
STDOUT
from
time
import
sleep
from
mininet.log
import
info
,
error
,
debug
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.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
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,
...
@@ -78,7 +78,7 @@ def __init__( self, name, inNamespace=True,
opts
+=
'
n
'
opts
+=
'
n
'
cmd
=
[
'
mnexec
'
,
opts
,
'
bash
'
,
'
-m
'
]
cmd
=
[
'
mnexec
'
,
opts
,
'
bash
'
,
'
-m
'
]
self
.
shell
=
Popen
(
cmd
,
stdin
=
PIPE
,
stdout
=
PIPE
,
stderr
=
STDOUT
,
self
.
shell
=
Popen
(
cmd
,
stdin
=
PIPE
,
stdout
=
PIPE
,
stderr
=
STDOUT
,
close_fds
=
Fals
e
)
close_fds
=
Tru
e
)
self
.
stdin
=
self
.
shell
.
stdin
self
.
stdin
=
self
.
shell
.
stdin
self
.
stdout
=
self
.
shell
.
stdout
self
.
stdout
=
self
.
shell
.
stdout
self
.
pid
=
self
.
shell
.
pid
self
.
pid
=
self
.
shell
.
pid
...
@@ -89,12 +89,10 @@ def __init__( self, name, inNamespace=True,
...
@@ -89,12 +89,10 @@ def __init__( self, name, inNamespace=True,
# using select.poll()
# using select.poll()
self
.
outToNode
[
self
.
stdout
.
fileno
()
]
=
self
self
.
outToNode
[
self
.
stdout
.
fileno
()
]
=
self
self
.
inToNode
[
self
.
stdin
.
fileno
()
]
=
self
self
.
inToNode
[
self
.
stdin
.
fileno
()
]
=
self
self
.
intfs
=
{}
# dict of port numbers to interface
name
s
self
.
intfs
=
{}
# dict of port numbers to interfaces
self
.
ports
=
{}
# dict of interface
name
s to port numbers
self
.
ports
=
{}
# dict of interfaces to port numbers
# replace with Port objects, eventually ?
# replace with Port objects, eventually ?
self
.
ips
=
{}
# dict of interfaces to ip addresses as strings
self
.
nameToIntf
=
{}
# dict of interface names to Intfs
self
.
macs
=
{}
# dict of interfacesto mac addresses as strings
self
.
connection
=
{}
# remote node connected to each interface
self
.
execed
=
False
self
.
execed
=
False
self
.
lastCmd
=
None
self
.
lastCmd
=
None
self
.
lastPid
=
None
self
.
lastPid
=
None
...
@@ -172,7 +170,7 @@ def sendCmd( self, *args, **kwargs ):
...
@@ -172,7 +170,7 @@ def sendCmd( self, *args, **kwargs ):
if
len
(
args
)
>
0
:
if
len
(
args
)
>
0
:
cmd
=
args
cmd
=
args
if
not
isinstance
(
cmd
,
str
):
if
not
isinstance
(
cmd
,
str
):
cmd
=
'
'
.
join
(
cmd
)
cmd
=
'
'
.
join
(
[
str
(
c
)
for
c
in
cmd
]
)
if
not
re
.
search
(
r
'
\w
'
,
cmd
):
if
not
re
.
search
(
r
'
\w
'
,
cmd
):
# Replace empty commands with something harmless
# Replace empty commands with something harmless
cmd
=
'
echo -n
'
cmd
=
'
echo -n
'
...
@@ -254,10 +252,6 @@ def cmdPrint( self, *args):
...
@@ -254,10 +252,6 @@ def cmdPrint( self, *args):
# the real interfaces are created as veth pairs, so we can't
# the real interfaces are created as veth pairs, so we can't
# make a single interface at a time.
# 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
):
def
newPort
(
self
):
"
Return the next port number to allocate.
"
"
Return the next port number to allocate.
"
if
len
(
self
.
ports
)
>
0
:
if
len
(
self
.
ports
)
>
0
:
...
@@ -266,56 +260,45 @@ def newPort( self ):
...
@@ -266,56 +260,45 @@ def newPort( self ):
def
addIntf
(
self
,
intf
,
port
=
None
):
def
addIntf
(
self
,
intf
,
port
=
None
):
"""
Add an interface.
"""
Add an interface.
intf: interface
name (e.g. nodeN-ethM)
intf: interface
port: port number (optional, typically OpenFlow port number)
"""
port: port number (optional, typically OpenFlow port number)
"""
if
port
is
None
:
if
port
is
None
:
port
=
self
.
newPort
()
port
=
self
.
newPort
()
self
.
intfs
[
port
]
=
intf
self
.
intfs
[
port
]
=
intf
self
.
ports
[
intf
]
=
port
self
.
ports
[
intf
]
=
port
#info( '\n' )
self
.
nameToIntf
[
intf
.
name
]
=
intf
#info( 'added intf %s:%d to node %s\n' % ( intf,port, self.name ) )
info
(
'
\n
'
)
info
(
'
added intf %s:%d to node %s
\n
'
%
(
intf
,
port
,
self
.
name
)
)
if
self
.
inNamespace
:
if
self
.
inNamespace
:
#
info( 'moving
w/inNamespace set
\n' )
info
(
'
moving
'
,
intf
,
'
into namespace for
'
,
self
.
name
,
'
\n
'
)
moveIntf
(
intf
,
self
)
moveIntf
(
intf
.
name
,
self
)
def
registerIntf
(
self
,
intf
,
dstNode
,
dstIntf
):
def
defaultIntf
(
self
):
"
Register connection of intf to dstIntf on dstNode.
"
"
Return interface for lowest port
"
self
.
connection
[
intf
]
=
(
dstNode
,
dstIntf
)
ports
=
self
.
intfs
.
keys
()
if
ports
:
return
self
.
intfs
[
min
(
ports
)
]
def
connectionsTo
(
self
,
node
):
def
intf
(
self
,
intf
=
''
):
"
Return [(srcIntf, dstIntf)..] for connections to dstNode.
"
"""
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
# We could optimize this if it is important
connections
=
[]
links
=
[]
for
intf
in
self
.
connection
.
keys
():
for
intf
in
self
.
intfs
:
dstNode
,
dstIntf
=
self
.
connection
[
intf
]
link
=
intf
.
link
if
dstNode
==
node
:
nodes
=
(
link
.
intf1
.
node
,
link
.
intf2
.
node
)
connections
.
append
(
(
intf
,
dstIntf
)
)
if
self
in
nodes
and
node
in
nodes
:
return
connections
links
.
append
(
link
)
return
links
# 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
def
deleteIntfs
(
self
):
def
deleteIntfs
(
self
):
"
Delete all of our interfaces.
"
"
Delete all of our interfaces.
"
...
@@ -325,18 +308,10 @@ def deleteIntfs( self ):
...
@@ -325,18 +308,10 @@ def deleteIntfs( self ):
# have been removed by the kernel. Unfortunately this is very slow,
# have been removed by the kernel. Unfortunately this is very slow,
# at least with Linux kernels before 2.6.33
# at least with Linux kernels before 2.6.33
for
intf
in
self
.
intfs
.
values
():
for
intf
in
self
.
intfs
.
values
():
quietRun
(
'
ip link del
'
+
intf
)
intf
.
delete
(
)
info
(
'
.
'
)
info
(
'
.
'
)
# Does it help to sleep to let things run?
sleep
(
0.001
)
def
setMAC
(
self
,
intf
,
mac
):
# Routing support
"""
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
def
setARP
(
self
,
ip
,
mac
):
def
setARP
(
self
,
ip
,
mac
):
"""
Add an ARP entry.
"""
Add an ARP entry.
...
@@ -345,16 +320,6 @@ def setARP( self, ip, mac ):
...
@@ -345,16 +320,6 @@ def setARP( self, ip, mac ):
result
=
self
.
cmd
(
'
arp
'
,
'
-s
'
,
ip
,
mac
)
result
=
self
.
cmd
(
'
arp
'
,
'
-s
'
,
ip
,
mac
)
return
result
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
):
def
setHostRoute
(
self
,
ip
,
intf
):
"""
Add route to host.
"""
Add route to host.
ip: IP address as dotted decimal
ip: IP address as dotted decimal
...
@@ -365,62 +330,52 @@ def setDefaultRoute( self, intf ):
...
@@ -365,62 +330,52 @@ def setDefaultRoute( self, intf ):
"""
Set the default route to go through intf.
"""
Set the default route to go through intf.
intf: string, interface name
"""
intf: string, interface name
"""
self
.
cmd
(
'
ip route flush root 0/0
'
)
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
):
# Convenience methods
"
Return interface for lowest port
"
ports
=
self
.
intfs
.
keys
()
if
ports
:
return
self
.
intfs
[
min
(
ports
)
]
_ipMatchRegex
=
re
.
compile
(
r
'
\d+\.\d+\.\d+\.\d+
'
)
def
setMAC
(
self
,
mac
,
intf
=
''
):
_macMatchRegex
=
re
.
compile
(
r
'
..:..:..:..:..:..
'
)
"""
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
):
def
IP
(
self
,
intf
=
None
):
"
Return IP address of a node or specific interface.
"
"
Return IP address of a node or specific interface.
"
if
intf
is
None
:
return
self
.
intf
(
intf
).
IP
()
intf
=
self
.
defaultIntf
()
if
intf
and
not
self
.
waiting
:
self
.
updateIP
(
intf
)
return
self
.
ips
.
get
(
intf
,
None
)
def
MAC
(
self
,
intf
=
None
):
def
MAC
(
self
,
intf
=
None
):
"
Return MAC address of a node or specific interface.
"
"
Return MAC address of a node or specific interface.
"
if
intf
is
None
:
return
self
.
intf
(
intf
).
MAC
()
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
def
updateMAC
(
self
,
intf
):
def
intfIsUp
(
self
,
intf
=
None
):
"
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
):
"
Check if an interface is up.
"
"
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
# Other methods
def
intfNames
(
self
):
"
The names of our interfaces
"
return
[
str
(
i
)
for
i
in
sorted
(
self
.
ports
.
values
()
)
]
def
__str__
(
self
):
def
__str__
(
self
):
intfs
=
sorted
(
self
.
intfs
.
values
()
)
return
'
%s: IP=%s intfs=%s pid=%s
'
%
(
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
):
class
Host
(
Node
):
...
@@ -623,10 +578,9 @@ class OVSSwitch( Switch ):
...
@@ -623,10 +578,9 @@ class OVSSwitch( Switch ):
def
__init__
(
self
,
name
,
dp
=
None
,
**
kwargs
):
def
__init__
(
self
,
name
,
dp
=
None
,
**
kwargs
):
"""
Init.
"""
Init.
name: name for switch
name: name for switch
dp: netlink id (0, 1, 2, ...)
defaultMAC: default MAC as unsigned int; random value if None
"""
defaultMAC: default MAC as unsigned int; random value if None
"""
Switch
.
__init__
(
self
,
name
,
**
kwargs
)
Switch
.
__init__
(
self
,
name
,
**
kwargs
)
self
.
dp
=
'
dp%i
'
%
dp
self
.
dp
=
name
@staticmethod
@staticmethod
def
setup
():
def
setup
():
...
@@ -671,7 +625,6 @@ def stop( self ):
...
@@ -671,7 +625,6 @@ def stop( self ):
OVSKernelSwitch
=
OVSSwitch
OVSKernelSwitch
=
OVSSwitch
class
Controller
(
Node
):
class
Controller
(
Node
):
"""
A Controller is a Node that is running (or has execed?) an
"""
A Controller is a Node that is running (or has execed?) an
OpenFlow controller.
"""
OpenFlow controller.
"""
...
@@ -704,8 +657,9 @@ def stop( self ):
...
@@ -704,8 +657,9 @@ def stop( self ):
def
IP
(
self
,
intf
=
None
):
def
IP
(
self
,
intf
=
None
):
"
Return IP address of the Controller
"
"
Return IP address of the Controller
"
ip
=
Node
.
IP
(
self
,
intf
=
intf
)
if
self
.
intfs
:
if
ip
is
None
:
ip
=
Node
.
IP
(
self
,
intf
)
else
:
ip
=
self
.
defaultIP
ip
=
self
.
defaultIP
return
ip
return
ip
...
...
This diff is collapsed.
Click to expand it.
mininet/topo.py
+
49
−
13
View file @
a6bcad8f
...
@@ -16,7 +16,14 @@
...
@@ -16,7 +16,14 @@
# from networkx.classes.graph import Graph
# from networkx.classes.graph import Graph
from
networkx
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
):
class
NodeID
(
object
):
'''
Topo node identifier.
'''
'''
Topo node identifier.
'''
...
@@ -54,11 +61,12 @@ def ip_str(self):
...
@@ -54,11 +61,12 @@ def ip_str(self):
return
"
10.%i.%i.%i
"
%
(
hi
,
mid
,
lo
)
return
"
10.%i.%i.%i
"
%
(
hi
,
mid
,
lo
)
class
Node
(
object
):
class
Node
(
object
):
'''
Node-specific vertex metadata for a Topo object.
'''
'''
Node-specific vertex metadata for a Topo object.
'''
def
__init__
(
self
,
connected
=
False
,
admin_on
=
True
,
def
__init__
(
self
,
connected
=
False
,
admin_on
=
True
,
power_on
=
True
,
fault
=
False
,
is_switch
=
True
):
power_on
=
True
,
fault
=
False
,
is_switch
=
True
,
cls
=
None
,
**
params
):
'''
Init.
'''
Init.
@param connected actively connected to controller
@param connected actively connected to controller
...
@@ -66,18 +74,26 @@ def __init__(self, connected = False, admin_on = True,
...
@@ -66,18 +74,26 @@ def __init__(self, connected = False, admin_on = True,
@param power_on powered on or off
@param power_on powered on or off
@param fault fault seen on node
@param fault fault seen on node
@param is_switch switch or host
@param is_switch switch or host
@param cls node class (e.g. Host, Switch)
@param params node parameters
'''
'''
self
.
connected
=
connected
self
.
connected
=
connected
self
.
admin_on
=
admin_on
self
.
admin_on
=
admin_on
self
.
power_on
=
power_on
self
.
power_on
=
power_on
self
.
fault
=
fault
self
.
fault
=
fault
self
.
is_switch
=
is_switch
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
):
class
Edge
(
object
):
'''
Edge-specific metadata for a StructuredTopo graph.
'''
'''
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.
'''
Init.
@param admin_on administratively on or off; defaults to True
@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):
...
@@ -87,31 +103,40 @@ def __init__(self, admin_on = True, power_on = True, fault = False):
self
.
admin_on
=
admin_on
self
.
admin_on
=
admin_on
self
.
power_on
=
power_on
self
.
power_on
=
power_on
self
.
fault
=
fault
self
.
fault
=
fault
# Above should be deleted and replaced by the following
self
.
cls
=
cls
self
.
params
=
params
class
Topo
(
object
):
class
Topo
(
object
):
'''
Data center network representation for structured multi-trees.
'''
'''
Data center network representation for structured multi-trees.
'''
def
__init__
(
self
):
def
__init__
(
self
,
node
=
Host
,
switch
=
None
,
link
=
Link
):
'''
Create Topo object.
"""
Create Topo object.
node: default node/host class
'''
switch: default switch class
Link: default link class
"""
self
.
g
=
Graph
()
self
.
g
=
Graph
()
self
.
node_info
=
{}
# dpids hash to Node objects
self
.
node_info
=
{}
# dpids hash to Node objects
self
.
edge_info
=
{}
# (src_dpid, dst_dpid) tuples hash to Edge 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
.
ports
=
{}
# ports[src][dst] is port on src that connects to dst
self
.
id_gen
=
NodeID
# class used to generate dpid
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.
'''
Add Node to graph.
@param dpid dpid
@param dpid dpid
@param node Node object
@param node Node object
'''
'''
self
.
g
.
add_node
(
dpid
)
self
.
g
.
add_node
(
dpid
)
if
not
node
:
node
=
Node
(
link
=
self
.
link
)
self
.
node_info
[
dpid
]
=
node
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.
'''
Add edge (Node, Node) to graph.
@param src src dpid
@param src src dpid
...
@@ -121,7 +146,7 @@ def add_edge(self, src, dst, edge = None):
...
@@ -121,7 +146,7 @@ def add_edge(self, src, dst, edge = None):
src
,
dst
=
tuple
(
sorted
([
src
,
dst
]))
src
,
dst
=
tuple
(
sorted
([
src
,
dst
]))
self
.
g
.
add_edge
(
src
,
dst
)
self
.
g
.
add_edge
(
src
,
dst
)
if
not
edge
:
if
not
edge
:
edge
=
Edge
()
edge
=
Edge
(
link
=
self
.
link
)
self
.
edge_info
[(
src
,
dst
)]
=
edge
self
.
edge_info
[(
src
,
dst
)]
=
edge
self
.
add_port
(
src
,
dst
)
self
.
add_port
(
src
,
dst
)
...
@@ -276,6 +301,12 @@ def port(self, src, dst):
...
@@ -276,6 +301,12 @@ def port(self, src, dst):
assert
dst
in
self
.
ports
and
src
in
self
.
ports
[
dst
]
assert
dst
in
self
.
ports
and
src
in
self
.
ports
[
dst
]
return
(
self
.
ports
[
src
][
dst
],
self
.
ports
[
dst
][
src
])
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
):
def
enable_edges
(
self
):
'''
Enable all edges in the network graph.
'''
Enable all edges in the network graph.
...
@@ -321,7 +352,12 @@ def ip(self, dpid):
...
@@ -321,7 +352,12 @@ def ip(self, dpid):
'''
'''
return
self
.
id_gen
(
dpid
=
dpid
).
ip_str
()
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
):
class
SingleSwitchTopo
(
Topo
):
'''
Single switch connected to k hosts.
'''
'''
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