Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
nemu3
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
1
Issues
1
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
nemu3
Commits
fa067176
Commit
fa067176
authored
Aug 30, 2010
by
Martín Ferrari
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Style adjustments
parent
8de4982b
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
70 additions
and
55 deletions
+70
-55
Makefile
Makefile
+5
-2
benchmarks/graph.py
benchmarks/graph.py
+3
-3
sample-api.txt
sample-api.txt
+2
-2
setup.py
setup.py
+2
-1
src/netns/interface.py
src/netns/interface.py
+18
-16
src/netns/iproute.py
src/netns/iproute.py
+7
-7
src/netns/node.py
src/netns/node.py
+5
-4
src/netns/protocol.py
src/netns/protocol.py
+2
-2
test/test_core.py
test/test_core.py
+10
-6
test/test_subprocess.py
test/test_subprocess.py
+2
-2
test/test_switch.py
test/test_switch.py
+14
-10
No files found.
Makefile
View file @
fa067176
...
...
@@ -4,8 +4,11 @@ BUILDDIR = build
DISTDIR
=
dist
# stupid distutils, it's broken in so many ways
SUBBUILDDIR
=
$(
shell
python
-c
'import distutils.util, sys; print "lib.%s-%s" % (distutils.util.get_platform(
)
, sys.version[0:3]
)
'
)
PYTHON25
:=
$(
shell
python
-c
'import sys; v = sys.version_info; print (1 if v[0] <= 2 and v[1] <= 5 else 0
)
'
)
SUBBUILDDIR
=
$(
shell
python
-c
'import distutils.util, sys; \
print "lib.%s-%s" % (distutils.util.get_platform(
)
, \
sys.version[0:3]
)
'
)
PYTHON25
:=
$(
shell
python
-c
'import sys; v = sys.version_info; \
print (1 if v[0] <= 2 and v[1] <= 5 else 0
)
'
)
ifeq
($(PYTHON25),0)
BUILDDIR
:=
$(BUILDDIR)
/
$(SUBBUILDDIR)
...
...
benchmarks/graph.py
View file @
fa067176
...
...
@@ -15,7 +15,7 @@ class Graph:
lines
=
self
.
gen_output
()
lines
.
insert
(
0
,
"set terminal postscript"
)
lines
.
insert
(
0
,
"set output '%s'"
%
filename
)
gnuplot
=
subprocess
.
Popen
([
'gnuplot'
,
'-'
],
gnuplot
=
subprocess
.
Popen
([
'gnuplot'
,
'-'
],
stdin
=
subprocess
.
PIPE
,
stdout
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
STDOUT
)
...
...
@@ -27,7 +27,7 @@ class Graph:
gnuplot
=
subprocess
.
Popen
([
'gnuplot'
,
'-'
],
stdin
=
subprocess
.
PIPE
)
gnuplot
.
communicate
(
input
=
"
\
n
"
.
join
(
lines
))
def
_style_to_str
(
self
,
style
):
d
=
{
Graph
.
LINE
:
'lines'
,
Graph
.
DOT
:
'dots'
,
Graph
.
POINT
:
'points'
,
d
=
{
Graph
.
LINE
:
'lines'
,
Graph
.
DOT
:
'dots'
,
Graph
.
POINT
:
'points'
,
Graph
.
LINEPOINT
:
'linespoints'
}
return
d
[
style
]
def
gen_output
(
self
,
plots
=
None
):
...
...
@@ -84,7 +84,7 @@ class Row:
def
__len__
(
self
):
return
len
(
self
.
_data1
)
# def __repr__(self):
# return
# return
class
Data
:
def
__init__
(
self
,
rows
=
[],
colnames
=
[]):
...
...
sample-api.txt
View file @
fa067176
...
...
@@ -29,8 +29,8 @@ if1 = b.add_if(mtu = 1492)
# for using with a tun device, to connect to the outside world
if2 = b.import_if('tun0')
# each Switch is a linux bridge, all the parameters are applied to the
associated
# interfaces as tc qdiscs.
# each Switch is a linux bridge, all the parameters are applied to the
#
associated
interfaces as tc qdiscs.
switch0 = netns.Switch(bandwidth = 100 * 1024 * 1024,
delay = 0.01, delay_jitter = 0.001,
delay_correlation = 0.25, delay_distribution = 'normal',
...
...
setup.py
View file @
fa067176
...
...
@@ -6,7 +6,8 @@ from distutils.core import setup, Extension, Command
setup
(
name
=
'netns'
,
version
=
'0.1'
,
description
=
'A framework for creating emulated networks in a single host and run experiments on them'
,
description
=
'''A framework for creating emulated networks in a
single host and run experiments on them'''
,
# long_description = longdesc,
author
=
'Martin Ferrari'
,
author_email
=
'martin.ferrari@gmail.com'
,
...
...
src/netns/interface.py
View file @
fa067176
...
...
@@ -142,14 +142,14 @@ class NodeInterface(NSInterface):
class
P2PInterface
(
NSInterface
):
"""Class to create and handle point-to-point interfaces between name
spaces, without using Switch objects. Those do not allow any kind of
traffic
shaping.
spaces, without using Switch objects. Those do not allow any kind of
traffic
shaping.
As two interfaces need to be created, instead of using the class
constructor, use the P2PInterface.create_pair() static method."""
@
staticmethod
def
create_pair
(
node1
,
node2
):
"""Create and return a pair of connected P2PInterface objects,
assigned
to name spaces represented by `node1' and `node2'."""
"""Create and return a pair of connected P2PInterface objects,
assigned
to name spaces represented by `node1' and `node2'."""
if1
=
netns
.
iproute
.
interface
(
name
=
P2PInterface
.
_gen_if_name
())
if2
=
netns
.
iproute
.
interface
(
name
=
P2PInterface
.
_gen_if_name
())
pair
=
netns
.
iproute
.
create_if_pair
(
if1
,
if2
)
...
...
@@ -180,12 +180,12 @@ class P2PInterface(NSInterface):
self
.
_slave
=
None
class
ImportedNodeInterface
(
NSInterface
):
"""Class to handle already existing interfaces inside a name space:
"""Class to handle already existing interfaces inside a name space:
real devices, tun devices, etc.
The flag 'migrate' in the constructor indicates that the interface was
migrated
inside the name space.
On destruction, the interface will be restored to the original name space
and
will try to restore the original state."""
The flag 'migrate' in the constructor indicates that the interface was
migrated inside the name space.
On destruction, the interface will be restored to the original name space
and
will try to restore the original state."""
def
__init__
(
self
,
node
,
iface
,
migrate
=
False
):
self
.
_slave
=
None
self
.
_migrate
=
migrate
...
...
@@ -225,7 +225,7 @@ class TapNodeInterface(NSInterface):
self
.
_fd
=
None
self
.
_slave
=
None
iface
=
netns
.
iproute
.
interface
(
name
=
self
.
_gen_if_name
())
iface
,
self
.
_fd
=
netns
.
iproute
.
create_tap
(
iface
)
iface
,
self
.
_fd
=
netns
.
iproute
.
create_tap
(
iface
)
netns
.
iproute
.
change_netns
(
iface
.
name
,
node
.
pid
)
super
(
TapNodeInterface
,
self
).
__init__
(
node
,
iface
.
index
)
...
...
@@ -241,7 +241,8 @@ class TapNodeInterface(NSInterface):
pass
class
ExternalInterface
(
Interface
):
"""Add user-facing methods for interfaces that run in the main namespace."""
"""Add user-facing methods for interfaces that run in the main
namespace."""
@
property
def
control
(
self
):
# This is *the* control interface
...
...
@@ -301,11 +302,11 @@ class SlaveInterface(ExternalInterface):
class
ImportedInterface
(
ExternalInterface
):
"""Class to handle already existing interfaces. Analogous to
ImportedNodeInterface, this class only differs in that the interface is
not
migrated inside the name space. This kind of interfaces can only be
ImportedNodeInterface, this class only differs in that the interface is
not
migrated inside the name space. This kind of interfaces can only be
connected to Switch objects and not assigned to a name space. On
destruction, the code will try to restore the interface to the state it
was
in before being imported into netns."""
destruction, the code will try to restore the interface to the state it
was
in before being imported into netns."""
def
__init__
(
self
,
iface
):
self
.
_original_state
=
None
iface
=
netns
.
iproute
.
get_if
(
iface
)
...
...
@@ -329,7 +330,8 @@ class Switch(ExternalInterface):
def
__init__
(
self
,
**
args
):
"""Creates a new Switch object, which models a linux bridge device.
Parameters are passed to the set_parameters() method after creation."""
Parameters are passed to the set_parameters() method after
creation."""
iface
=
netns
.
iproute
.
create_bridge
(
self
.
_gen_br_name
())
super
(
Switch
,
self
).
__init__
(
iface
.
index
)
...
...
src/netns/iproute.py
View file @
fa067176
# vim:ts=4:sw=4:et:ai:sts=4
import
copy
,
os
,
re
,
socket
,
subprocess
,
sys
,
struct
from
fcntl
import
ioctl
import
copy
,
fcntl
,
os
,
re
,
socket
,
struct
,
subprocess
,
sys
from
netns.environ
import
*
# helpers
...
...
@@ -182,8 +181,9 @@ class bridge(interface):
class
address
(
object
):
"""Class for internal use. It is mostly a data container used to easily
pass information around; with some convenience methods. __eq__ and __hash__
are defined just to be able to easily find duplicated addresses."""
pass information around; with some convenience methods. __eq__ and
__hash__ are defined just to be able to easily find duplicated
addresses."""
# broadcast is not taken into account for differentiating addresses
def
__eq__
(
self
,
o
):
if
not
isinstance
(
o
,
address
):
...
...
@@ -502,8 +502,8 @@ def _sysfs_read_br(brname):
ports = os.listdir(p2))
def get_bridge_data():
# brctl stinks too much; it is better to directly use sysfs, it is
probably
# stable by now
# brctl stinks too much; it is better to directly use sysfs, it is
#
probably
stable by now
byidx = {}
bynam = {}
ports = {}
...
...
@@ -912,7 +912,7 @@ def create_tap(iface):
fd = os.open("/dev/net/tun", os.O_RDWR)
if fd == -1:
raise RuntimeError("Could not open /dev/net/tun")
err = ioctl(fd, TUNSETIFF, struct.pack("16sH", iface.name, mode))
err =
fcntl.
ioctl(fd, TUNSETIFF, struct.pack("16sH", iface.name, mode))
if err < 0:
os.close(fd)
raise RuntimeError("Could not configure device %s" % iface.name)
...
...
src/netns/node.py
View file @
fa067176
...
...
@@ -3,7 +3,7 @@
import
os
,
socket
,
sys
,
traceback
,
unshare
,
weakref
from
netns.environ
import
*
import
netns.
protocol
,
netns
.
subprocess_
,
netns
.
interface
import
netns.
interface
,
netns
.
protocol
,
netns
.
subprocess_
__all__
=
[
'Node'
,
'get_nodes'
,
'import_if'
]
...
...
@@ -19,8 +19,8 @@ class Node(object):
"""Create a new node in the emulation. Implemented as a separate
process in a new network name space. Requires root privileges to run.
If keepns is true, the network name space is not created and can be
run
as a normal user, for testing. If debug is true, details of the
If keepns is true, the network name space is not created and can be
run
as a normal user, for testing. If debug is true, details of the
communication protocol are printed on stderr."""
# Initialize attributes, in case something fails during __init__
...
...
@@ -119,7 +119,8 @@ class Node(object):
ifaces
=
self
.
_slave
.
get_if_data
()
for
i
in
ifaces
:
if
i
not
in
self
.
_interfaces
:
iface
=
netns
.
interface
.
ImportedNodeInterface
(
self
,
i
,
migrate
=
True
)
iface
=
netns
.
interface
.
ImportedNodeInterface
(
self
,
i
,
migrate
=
True
)
self
.
_auto_interfaces
.
append
(
iface
)
# keep it referenced!
self
.
_interfaces
[
i
]
=
iface
# by the way, clean up _interfaces
...
...
src/netns/protocol.py
View file @
fa067176
...
...
@@ -63,8 +63,8 @@ _proc_commands = {
}
class
Server
(
object
):
"""Class that implements the communication protocol and dispatches calls
to
the required functions. Also works as the main loop for the slave
"""Class that implements the communication protocol and dispatches calls
t
o t
he required functions. Also works as the main loop for the slave
process."""
def
__init__
(
self
,
rfd
,
wfd
,
debug
=
0
):
# Dictionary of valid commands
...
...
test/test_core.py
View file @
fa067176
#!/usr/bin/env python
# vim:ts=4:sw=4:et:ai:sts=4
import
grp
,
os
,
pwd
,
select
,
time
,
threading
,
unittest
import
grp
,
os
,
pwd
,
select
,
time
,
unittest
import
netns
,
test_util
class
TestConfigure
(
unittest
.
TestCase
):
...
...
@@ -86,8 +86,10 @@ class TestGlobal(unittest.TestCase):
i2b
.
add_v4_address
(
'10.0.1.1'
,
24
)
i3
.
add_v4_address
(
'10.0.1.2'
,
24
)
n1
.
add_route
(
prefix
=
'10.0.1.0'
,
prefix_len
=
24
,
nexthop
=
'10.0.0.2'
)
n3
.
add_route
(
prefix
=
'10.0.0.0'
,
prefix_len
=
24
,
nexthop
=
'10.0.1.1'
)
n1
.
add_route
(
prefix
=
'10.0.1.0'
,
prefix_len
=
24
,
nexthop
=
'10.0.0.2'
)
n3
.
add_route
(
prefix
=
'10.0.0.0'
,
prefix_len
=
24
,
nexthop
=
'10.0.1.1'
)
null
=
file
(
'/dev/null'
,
'wb'
)
a1
=
n1
.
Popen
([
'ping'
,
'-qc1'
,
'10.0.1.2'
],
stdout
=
null
)
...
...
@@ -97,7 +99,8 @@ class TestGlobal(unittest.TestCase):
@
test_util
.
skipUnless
(
os
.
getuid
()
==
0
,
"Test requires root privileges"
)
def
test_run_ping_tap
(
self
):
"""This test simulates a point to point connection between two hosts using two tap devices"""
"""This test simulates a point to point connection between two hosts
using two tap devices"""
n1
=
netns
.
Node
()
n2
=
netns
.
Node
()
...
...
@@ -128,7 +131,8 @@ class TestGlobal(unittest.TestCase):
@
test_util
.
skipUnless
(
os
.
getuid
()
==
0
,
"Test requires root privileges"
)
def
test_run_ping_tap_routing
(
self
):
"""This test simulates a point to point connection between two hosts using two tap devices"""
"""This test simulates a point to point connection between two hosts
using two tap devices"""
n1
=
netns
.
Node
()
n2
=
netns
.
Node
()
n3
=
netns
.
Node
()
...
...
@@ -186,4 +190,4 @@ class TestGlobal(unittest.TestCase):
self
.
assertEquals
(
a
.
wait
(),
0
)
if
__name__
==
'__main__'
:
unittest
.
main
()
unittest
.
main
()
test/test_subprocess.py
View file @
fa067176
...
...
@@ -268,7 +268,7 @@ class TestSubprocess(unittest.TestCase):
stdin
=
PIPE
,
stdout
=
PIPE
,
stderr
=
PIPE
)
self
.
assertEquals
(
p
.
communicate
(
_longstring
),
(
_longstring
,
)
*
2
)
def
test_backticks
(
self
):
def
test_backticks
(
self
):
node
=
netns
.
Node
(
nonetns
=
True
,
debug
=
0
)
self
.
assertEquals
(
backticks
(
node
,
"echo hello world"
),
"hello world
\
n
"
)
self
.
assertEquals
(
backticks
(
node
,
r"echo hello\
\ world"
),
...
...
@@ -280,7 +280,7 @@ class TestSubprocess(unittest.TestCase):
self
.
assertRaises
(
RuntimeError
,
backticks_raise
,
node
,
"false"
)
self
.
assertRaises
(
RuntimeError
,
backticks_raise
,
node
,
"kill $$"
)
def
test_system
(
self
):
def
test_system
(
self
):
node
=
netns
.
Node
(
nonetns
=
True
,
debug
=
0
)
self
.
assertEquals
(
system
(
node
,
"true"
),
0
)
self
.
assertEquals
(
system
(
node
,
"false"
),
1
)
...
...
test/test_switch.py
View file @
fa067176
...
...
@@ -18,17 +18,21 @@ class TestSwitch(unittest.TestCase):
@
test_util
.
skipUnless
(
os
.
getuid
()
==
0
,
"Test requires root privileges"
)
def
test_switch_base
(
self
):
(
n1
,
n2
,
i1
,
i2
,
l
)
=
self
.
stuff
(
n1
,
n2
,
i1
,
i2
,
l
)
=
self
.
stuff
l
.
mtu
=
3000
ifdata
=
netns
.
iproute
.
get_if_data
()[
0
]
self
.
assertEquals
(
ifdata
[
l
.
index
].
mtu
,
3000
)
self
.
assertEquals
(
ifdata
[
i1
.
control
.
index
].
mtu
,
3000
,
"MTU propagation"
)
self
.
assertEquals
(
ifdata
[
i2
.
control
.
index
].
mtu
,
3000
,
"MTU propagation"
)
self
.
assertEquals
(
ifdata
[
i1
.
control
.
index
].
mtu
,
3000
,
"MTU propagation"
)
self
.
assertEquals
(
ifdata
[
i2
.
control
.
index
].
mtu
,
3000
,
"MTU propagation"
)
i1
.
mtu
=
i2
.
mtu
=
3000
self
.
assertEquals
(
ifdata
[
l
.
index
].
up
,
False
)
self
.
assertEquals
(
ifdata
[
i1
.
control
.
index
].
up
,
False
,
"UP propagation"
)
self
.
assertEquals
(
ifdata
[
i2
.
control
.
index
].
up
,
False
,
"UP propagation"
)
self
.
assertEquals
(
ifdata
[
i1
.
control
.
index
].
up
,
False
,
"UP propagation"
)
self
.
assertEquals
(
ifdata
[
i2
.
control
.
index
].
up
,
False
,
"UP propagation"
)
l
.
up
=
True
ifdata
=
netns
.
iproute
.
get_if_data
()[
0
]
...
...
@@ -41,7 +45,7 @@ class TestSwitch(unittest.TestCase):
@
test_util
.
skipUnless
(
os
.
getuid
()
==
0
,
"Test requires root privileges"
)
def
test_switch_changes
(
self
):
(
n1
,
n2
,
i1
,
i2
,
l
)
=
self
.
stuff
(
n1
,
n2
,
i1
,
i2
,
l
)
=
self
.
stuff
# Test strange rules handling
os
.
system
((
"%s qd add dev %s root prio bands 3 "
+
...
...
@@ -70,14 +74,14 @@ class TestSwitch(unittest.TestCase):
self
.
_test_none
()
# both => none
def
_test_none
(
self
):
(
n1
,
n2
,
i1
,
i2
,
l
)
=
self
.
stuff
(
n1
,
n2
,
i1
,
i2
,
l
)
=
self
.
stuff
l
.
set_parameters
()
tcdata
=
netns
.
iproute
.
get_tc_data
()[
0
]
self
.
assertEquals
(
tcdata
[
i1
.
control
.
index
],
{
"qdiscs"
:
{}})
self
.
assertEquals
(
tcdata
[
i2
.
control
.
index
],
{
"qdiscs"
:
{}})
def
_test_tbf
(
self
):
(
n1
,
n2
,
i1
,
i2
,
l
)
=
self
.
stuff
(
n1
,
n2
,
i1
,
i2
,
l
)
=
self
.
stuff
l
.
set_parameters
(
bandwidth
=
13107200
)
# 100 mbits
tcdata
=
netns
.
iproute
.
get_tc_data
()[
0
]
self
.
assertEquals
(
tcdata
[
i1
.
control
.
index
],
...
...
@@ -87,7 +91,7 @@ class TestSwitch(unittest.TestCase):
{
"bandwidth"
:
13107000
,
"qdiscs"
:
{
"tbf"
:
"1"
}})
def
_test_netem
(
self
):
(
n1
,
n2
,
i1
,
i2
,
l
)
=
self
.
stuff
(
n1
,
n2
,
i1
,
i2
,
l
)
=
self
.
stuff
l
.
set_parameters
(
delay
=
0.001
)
# 1ms
tcdata
=
netns
.
iproute
.
get_tc_data
()[
0
]
self
.
assertEquals
(
tcdata
[
i1
.
control
.
index
],
...
...
@@ -96,7 +100,7 @@ class TestSwitch(unittest.TestCase):
{
"delay"
:
0.001
,
"qdiscs"
:
{
"netem"
:
"2"
}})
def
_test_both
(
self
):
(
n1
,
n2
,
i1
,
i2
,
l
)
=
self
.
stuff
(
n1
,
n2
,
i1
,
i2
,
l
)
=
self
.
stuff
l
.
set_parameters
(
bandwidth
=
13107200
,
delay
=
0.001
)
# 100 mbits, 1ms
tcdata
=
netns
.
iproute
.
get_tc_data
()[
0
]
self
.
assertEquals
(
tcdata
[
i1
.
control
.
index
],
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment