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
Show 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
...
@@ -4,8 +4,11 @@ BUILDDIR = build
DISTDIR
=
dist
DISTDIR
=
dist
# stupid distutils, it's broken in so many ways
# 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]
)
'
)
SUBBUILDDIR
=
$(
shell
python
-c
'import distutils.util, sys; \
PYTHON25
:=
$(
shell
python
-c
'import sys; v = sys.version_info; print (1 if v[0] <= 2 and v[1] <= 5 else 0
)
'
)
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)
ifeq
($(PYTHON25),0)
BUILDDIR
:=
$(BUILDDIR)
/
$(SUBBUILDDIR)
BUILDDIR
:=
$(BUILDDIR)
/
$(SUBBUILDDIR)
...
...
benchmarks/graph.py
View file @
fa067176
sample-api.txt
View file @
fa067176
...
@@ -29,8 +29,8 @@ if1 = b.add_if(mtu = 1492)
...
@@ -29,8 +29,8 @@ if1 = b.add_if(mtu = 1492)
# for using with a tun device, to connect to the outside world
# for using with a tun device, to connect to the outside world
if2 = b.import_if('tun0')
if2 = b.import_if('tun0')
# each Switch is a linux bridge, all the parameters are applied to the
associated
# each Switch is a linux bridge, all the parameters are applied to the
# interfaces as tc qdiscs.
#
associated
interfaces as tc qdiscs.
switch0 = netns.Switch(bandwidth = 100 * 1024 * 1024,
switch0 = netns.Switch(bandwidth = 100 * 1024 * 1024,
delay = 0.01, delay_jitter = 0.001,
delay = 0.01, delay_jitter = 0.001,
delay_correlation = 0.25, delay_distribution = 'normal',
delay_correlation = 0.25, delay_distribution = 'normal',
...
...
setup.py
View file @
fa067176
...
@@ -6,7 +6,8 @@ from distutils.core import setup, Extension, Command
...
@@ -6,7 +6,8 @@ from distutils.core import setup, Extension, Command
setup
(
setup
(
name
=
'netns'
,
name
=
'netns'
,
version
=
'0.1'
,
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,
# long_description = longdesc,
author
=
'Martin Ferrari'
,
author
=
'Martin Ferrari'
,
author_email
=
'martin.ferrari@gmail.com'
,
author_email
=
'martin.ferrari@gmail.com'
,
...
...
src/netns/interface.py
View file @
fa067176
...
@@ -142,14 +142,14 @@ class NodeInterface(NSInterface):
...
@@ -142,14 +142,14 @@ class NodeInterface(NSInterface):
class
P2PInterface
(
NSInterface
):
class
P2PInterface
(
NSInterface
):
"""Class to create and handle point-to-point interfaces between name
"""Class to create and handle point-to-point interfaces between name
spaces, without using Switch objects. Those do not allow any kind of
traffic
spaces, without using Switch objects. Those do not allow any kind of
shaping.
traffic
shaping.
As two interfaces need to be created, instead of using the class
As two interfaces need to be created, instead of using the class
constructor, use the P2PInterface.create_pair() static method."""
constructor, use the P2PInterface.create_pair() static method."""
@
staticmethod
@
staticmethod
def
create_pair
(
node1
,
node2
):
def
create_pair
(
node1
,
node2
):
"""Create and return a pair of connected P2PInterface objects,
assigned
"""Create and return a pair of connected P2PInterface objects,
to name spaces represented by `node1' and `node2'."""
assigned
to name spaces represented by `node1' and `node2'."""
if1
=
netns
.
iproute
.
interface
(
name
=
P2PInterface
.
_gen_if_name
())
if1
=
netns
.
iproute
.
interface
(
name
=
P2PInterface
.
_gen_if_name
())
if2
=
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
)
pair
=
netns
.
iproute
.
create_if_pair
(
if1
,
if2
)
...
@@ -182,10 +182,10 @@ class P2PInterface(NSInterface):
...
@@ -182,10 +182,10 @@ class P2PInterface(NSInterface):
class
ImportedNodeInterface
(
NSInterface
):
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.
real devices, tun devices, etc.
The flag 'migrate' in the constructor indicates that the interface was
migrated
The flag 'migrate' in the constructor indicates that the interface was
inside the name space.
migrated inside the name space.
On destruction, the interface will be restored to the original name space
and
On destruction, the interface will be restored to the original name space
will try to restore the original state."""
and
will try to restore the original state."""
def
__init__
(
self
,
node
,
iface
,
migrate
=
False
):
def
__init__
(
self
,
node
,
iface
,
migrate
=
False
):
self
.
_slave
=
None
self
.
_slave
=
None
self
.
_migrate
=
migrate
self
.
_migrate
=
migrate
...
@@ -241,7 +241,8 @@ class TapNodeInterface(NSInterface):
...
@@ -241,7 +241,8 @@ class TapNodeInterface(NSInterface):
pass
pass
class
ExternalInterface
(
Interface
):
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
@
property
def
control
(
self
):
def
control
(
self
):
# This is *the* control interface
# This is *the* control interface
...
@@ -301,11 +302,11 @@ class SlaveInterface(ExternalInterface):
...
@@ -301,11 +302,11 @@ class SlaveInterface(ExternalInterface):
class
ImportedInterface
(
ExternalInterface
):
class
ImportedInterface
(
ExternalInterface
):
"""Class to handle already existing interfaces. Analogous to
"""Class to handle already existing interfaces. Analogous to
ImportedNodeInterface, this class only differs in that the interface is
not
ImportedNodeInterface, this class only differs in that the interface is
migrated inside the name space. This kind of interfaces can only be
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
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
destruction, the code will try to restore the interface to the state it
in before being imported into netns."""
was
in before being imported into netns."""
def
__init__
(
self
,
iface
):
def
__init__
(
self
,
iface
):
self
.
_original_state
=
None
self
.
_original_state
=
None
iface
=
netns
.
iproute
.
get_if
(
iface
)
iface
=
netns
.
iproute
.
get_if
(
iface
)
...
@@ -329,7 +330,8 @@ class Switch(ExternalInterface):
...
@@ -329,7 +330,8 @@ class Switch(ExternalInterface):
def
__init__
(
self
,
**
args
):
def
__init__
(
self
,
**
args
):
"""Creates a new Switch object, which models a linux bridge device.
"""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
())
iface
=
netns
.
iproute
.
create_bridge
(
self
.
_gen_br_name
())
super
(
Switch
,
self
).
__init__
(
iface
.
index
)
super
(
Switch
,
self
).
__init__
(
iface
.
index
)
...
...
src/netns/iproute.py
View file @
fa067176
# vim:ts=4:sw=4:et:ai:sts=4
# vim:ts=4:sw=4:et:ai:sts=4
import
copy
,
os
,
re
,
socket
,
subprocess
,
sys
,
struct
import
copy
,
fcntl
,
os
,
re
,
socket
,
struct
,
subprocess
,
sys
from
fcntl
import
ioctl
from
netns.environ
import
*
from
netns.environ
import
*
# helpers
# helpers
...
@@ -182,8 +181,9 @@ class bridge(interface):
...
@@ -182,8 +181,9 @@ class bridge(interface):
class
address
(
object
):
class
address
(
object
):
"""Class for internal use. It is mostly a data container used to easily
"""Class for internal use. It is mostly a data container used to easily
pass information around; with some convenience methods. __eq__ and __hash__
pass information around; with some convenience methods. __eq__ and
are defined just to be able to easily find duplicated addresses."""
__hash__ are defined just to be able to easily find duplicated
addresses."""
# broadcast is not taken into account for differentiating addresses
# broadcast is not taken into account for differentiating addresses
def
__eq__
(
self
,
o
):
def
__eq__
(
self
,
o
):
if
not
isinstance
(
o
,
address
):
if
not
isinstance
(
o
,
address
):
...
@@ -502,8 +502,8 @@ def _sysfs_read_br(brname):
...
@@ -502,8 +502,8 @@ def _sysfs_read_br(brname):
ports = os.listdir(p2))
ports = os.listdir(p2))
def get_bridge_data():
def get_bridge_data():
# brctl stinks too much; it is better to directly use sysfs, it is
probably
# brctl stinks too much; it is better to directly use sysfs, it is
# stable by now
#
probably
stable by now
byidx = {}
byidx = {}
bynam = {}
bynam = {}
ports = {}
ports = {}
...
@@ -912,7 +912,7 @@ def create_tap(iface):
...
@@ -912,7 +912,7 @@ def create_tap(iface):
fd = os.open("/dev/net/tun", os.O_RDWR)
fd = os.open("/dev/net/tun", os.O_RDWR)
if fd == -1:
if fd == -1:
raise RuntimeError("Could not open /dev/net/tun")
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:
if err < 0:
os.close(fd)
os.close(fd)
raise RuntimeError("Could not configure device %s" % iface.name)
raise RuntimeError("Could not configure device %s" % iface.name)
...
...
src/netns/node.py
View file @
fa067176
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
import
os
,
socket
,
sys
,
traceback
,
unshare
,
weakref
import
os
,
socket
,
sys
,
traceback
,
unshare
,
weakref
from
netns.environ
import
*
from
netns.environ
import
*
import
netns.
protocol
,
netns
.
subprocess_
,
netns
.
interface
import
netns.
interface
,
netns
.
protocol
,
netns
.
subprocess_
__all__
=
[
'Node'
,
'get_nodes'
,
'import_if'
]
__all__
=
[
'Node'
,
'get_nodes'
,
'import_if'
]
...
@@ -19,8 +19,8 @@ class Node(object):
...
@@ -19,8 +19,8 @@ class Node(object):
"""Create a new node in the emulation. Implemented as a separate
"""Create a new node in the emulation. Implemented as a separate
process in a new network name space. Requires root privileges to run.
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
If keepns is true, the network name space is not created and can be
as a normal user, for testing. If debug is true, details of the
run
as a normal user, for testing. If debug is true, details of the
communication protocol are printed on stderr."""
communication protocol are printed on stderr."""
# Initialize attributes, in case something fails during __init__
# Initialize attributes, in case something fails during __init__
...
@@ -119,7 +119,8 @@ class Node(object):
...
@@ -119,7 +119,8 @@ class Node(object):
ifaces
=
self
.
_slave
.
get_if_data
()
ifaces
=
self
.
_slave
.
get_if_data
()
for
i
in
ifaces
:
for
i
in
ifaces
:
if
i
not
in
self
.
_interfaces
:
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
.
_auto_interfaces
.
append
(
iface
)
# keep it referenced!
self
.
_interfaces
[
i
]
=
iface
self
.
_interfaces
[
i
]
=
iface
# by the way, clean up _interfaces
# by the way, clean up _interfaces
...
...
src/netns/protocol.py
View file @
fa067176
...
@@ -63,8 +63,8 @@ _proc_commands = {
...
@@ -63,8 +63,8 @@ _proc_commands = {
}
}
class
Server
(
object
):
class
Server
(
object
):
"""Class that implements the communication protocol and dispatches calls
to
"""Class that implements the communication protocol and dispatches calls
the required functions. Also works as the main loop for the slave
t
o t
he required functions. Also works as the main loop for the slave
process."""
process."""
def
__init__
(
self
,
rfd
,
wfd
,
debug
=
0
):
def
__init__
(
self
,
rfd
,
wfd
,
debug
=
0
):
# Dictionary of valid commands
# Dictionary of valid commands
...
...
test/test_core.py
View file @
fa067176
#!/usr/bin/env python
#!/usr/bin/env python
# vim:ts=4:sw=4:et:ai:sts=4
# 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
import
netns
,
test_util
class
TestConfigure
(
unittest
.
TestCase
):
class
TestConfigure
(
unittest
.
TestCase
):
...
@@ -86,8 +86,10 @@ class TestGlobal(unittest.TestCase):
...
@@ -86,8 +86,10 @@ class TestGlobal(unittest.TestCase):
i2b
.
add_v4_address
(
'10.0.1.1'
,
24
)
i2b
.
add_v4_address
(
'10.0.1.1'
,
24
)
i3
.
add_v4_address
(
'10.0.1.2'
,
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'
)
n1
.
add_route
(
prefix
=
'10.0.1.0'
,
prefix_len
=
24
,
n3
.
add_route
(
prefix
=
'10.0.0.0'
,
prefix_len
=
24
,
nexthop
=
'10.0.1.1'
)
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'
)
null
=
file
(
'/dev/null'
,
'wb'
)
a1
=
n1
.
Popen
([
'ping'
,
'-qc1'
,
'10.0.1.2'
],
stdout
=
null
)
a1
=
n1
.
Popen
([
'ping'
,
'-qc1'
,
'10.0.1.2'
],
stdout
=
null
)
...
@@ -97,7 +99,8 @@ class TestGlobal(unittest.TestCase):
...
@@ -97,7 +99,8 @@ class TestGlobal(unittest.TestCase):
@
test_util
.
skipUnless
(
os
.
getuid
()
==
0
,
"Test requires root privileges"
)
@
test_util
.
skipUnless
(
os
.
getuid
()
==
0
,
"Test requires root privileges"
)
def
test_run_ping_tap
(
self
):
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
()
n1
=
netns
.
Node
()
n2
=
netns
.
Node
()
n2
=
netns
.
Node
()
...
@@ -128,7 +131,8 @@ class TestGlobal(unittest.TestCase):
...
@@ -128,7 +131,8 @@ class TestGlobal(unittest.TestCase):
@
test_util
.
skipUnless
(
os
.
getuid
()
==
0
,
"Test requires root privileges"
)
@
test_util
.
skipUnless
(
os
.
getuid
()
==
0
,
"Test requires root privileges"
)
def
test_run_ping_tap_routing
(
self
):
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
()
n1
=
netns
.
Node
()
n2
=
netns
.
Node
()
n2
=
netns
.
Node
()
n3
=
netns
.
Node
()
n3
=
netns
.
Node
()
...
...
test/test_subprocess.py
View file @
fa067176
test/test_switch.py
View file @
fa067176
...
@@ -22,13 +22,17 @@ class TestSwitch(unittest.TestCase):
...
@@ -22,13 +22,17 @@ class TestSwitch(unittest.TestCase):
l
.
mtu
=
3000
l
.
mtu
=
3000
ifdata
=
netns
.
iproute
.
get_if_data
()[
0
]
ifdata
=
netns
.
iproute
.
get_if_data
()[
0
]
self
.
assertEquals
(
ifdata
[
l
.
index
].
mtu
,
3000
)
self
.
assertEquals
(
ifdata
[
l
.
index
].
mtu
,
3000
)
self
.
assertEquals
(
ifdata
[
i1
.
control
.
index
].
mtu
,
3000
,
"MTU propagation"
)
self
.
assertEquals
(
ifdata
[
i1
.
control
.
index
].
mtu
,
3000
,
self
.
assertEquals
(
ifdata
[
i2
.
control
.
index
].
mtu
,
3000
,
"MTU propagation"
)
"MTU propagation"
)
self
.
assertEquals
(
ifdata
[
i2
.
control
.
index
].
mtu
,
3000
,
"MTU propagation"
)
i1
.
mtu
=
i2
.
mtu
=
3000
i1
.
mtu
=
i2
.
mtu
=
3000
self
.
assertEquals
(
ifdata
[
l
.
index
].
up
,
False
)
self
.
assertEquals
(
ifdata
[
l
.
index
].
up
,
False
)
self
.
assertEquals
(
ifdata
[
i1
.
control
.
index
].
up
,
False
,
"UP propagation"
)
self
.
assertEquals
(
ifdata
[
i1
.
control
.
index
].
up
,
False
,
self
.
assertEquals
(
ifdata
[
i2
.
control
.
index
].
up
,
False
,
"UP propagation"
)
"UP propagation"
)
self
.
assertEquals
(
ifdata
[
i2
.
control
.
index
].
up
,
False
,
"UP propagation"
)
l
.
up
=
True
l
.
up
=
True
ifdata
=
netns
.
iproute
.
get_if_data
()[
0
]
ifdata
=
netns
.
iproute
.
get_if_data
()[
0
]
...
...
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