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
9fc3b3ec
Commit
9fc3b3ec
authored
Jul 12, 2010
by
Martín Ferrari
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
This should complete the interface handling backend.
parent
a032a114
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
122 additions
and
145 deletions
+122
-145
protocol.txt
protocol.txt
+3
-2
src/netns/iproute.py
src/netns/iproute.py
+41
-136
src/netns/protocol.py
src/netns/protocol.py
+78
-7
No files found.
protocol.txt
View file @
9fc3b3ec
...
...
@@ -11,7 +11,7 @@ replies with 221 code.
Command Subcmd Arguments Response Effect
QUIT 221 Close the netns
IF LIST [if#] 200 serialised data ip link list
IF SET if# k
ey val
200/500 ip link set (1)
IF SET if# k
v k v...
200/500 ip link set (1)
IF RTRN if# ns 200/500 ip link set netns $ns
ADDR LIST [if#] 200 serialised data ip addr list
ADDR ADD if# addr_spec 200/500 ip addr add
...
...
@@ -32,7 +32,8 @@ PROC POLL <pid> 200 <code>/450/500 check if process alive
PROC WAIT <pid> 200 <code>/500 waitpid(pid)
PROC KILL <pid> <signal> 200/500 kill(pid, signal)
(1) valid arguments: mtu <n>, state <up|down>, name <name>, lladdr <addr>
(1) valid arguments: mtu <n>, up <0|1>, name <name>, lladdr <addr>,
broadcast <addr>, multicast <0|1>, arp <0|1>.
(2) After PROC CRTE, only secondary PROC cmds are accepted until finished.
The parameters are parsed as base64-encoded strings if they start with a '='
...
...
src/netns/iproute.py
View file @
9fc3b3ec
# vim:ts=4:sw=4:et:ai:sts=4
import
re
,
socket
,
subprocess
,
sys
class
interface
(
object
):
@
classmethod
def
parse_ip
(
cls
,
line
):
match
=
re
.
search
(
r'^(\
d+): (
\S+): <(\
S+)> m
tu (\
d+) qdisc
\S+'
+
r'.*link/\
S+ ([
0-9a-f:]+) brd ([0-9a-f:]+)'
,
line
)
flags
=
match
.
group
(
3
).
split
(
","
)
return
cls
(
index
=
match
.
group
(
1
),
name
=
match
.
group
(
2
),
up
=
"UP"
in
flags
,
mtu
=
match
.
group
(
4
),
lladdr
=
match
.
group
(
5
),
arp
=
not
(
"NOARP"
in
flags
),
broadcast
=
match
.
group
(
6
),
multicast
=
"MULTICAST"
in
flags
)
def
__init__
(
self
,
index
=
None
,
name
=
None
,
up
=
None
,
mtu
=
None
,
lladdr
=
None
,
broadcast
=
None
,
multicast
=
None
,
arp
=
None
):
self
.
index
=
int
(
index
)
if
index
else
None
self
.
name
=
name
self
.
up
=
up
self
.
mtu
=
int
(
mtu
)
if
mtu
else
None
self
.
lladdr
=
lladdr
self
.
broadcast
=
broadcast
self
.
multicast
=
multicast
self
.
arp
=
arp
def
__repr__
(
self
):
s
=
"%s.%s(index = %s, name = %s, up = %s, mtu = %s, lladdr = %s, "
s
+=
"broadcast = %s, multicast = %s, arp = %s)"
return
s
%
(
self
.
__module__
,
self
.
__class__
.
__name__
,
self
.
index
.
__repr__
(),
self
.
name
.
__repr__
(),
self
.
up
.
__repr__
(),
self
.
mtu
.
__repr__
(),
self
.
lladdr
.
__repr__
(),
self
.
broadcast
.
__repr__
(),
self
.
multicast
.
__repr__
(),
self
.
arp
.
__repr__
())
def
__sub__
(
self
,
o
):
"""Compare attributes and return a new object with just the attributes
that differ set (with the value they have in the first operand). The
index remains equal to the first operand."""
name
=
None
if
self
.
name
==
o
.
name
else
self
.
name
up
=
None
if
self
.
up
==
o
.
up
else
self
.
up
mtu
=
None
if
self
.
mtu
==
o
.
mtu
else
self
.
mtu
lladdr
=
None
if
self
.
lladdr
==
o
.
lladdr
else
self
.
lladdr
broadcast
=
None
if
self
.
broadcast
==
o
.
broadcast
else
self
.
broadcast
multicast
=
None
if
self
.
multicast
==
o
.
multicast
else
self
.
multicast
arp
=
None
if
self
.
arp
==
o
.
arp
else
self
.
arp
return
self
.
__class__
(
self
.
index
,
name
,
up
,
mtu
,
lladdr
,
broadcast
,
multicast
,
arp
)
class
address
(
object
):
@
classmethod
def
parse_ip
(
cls
,
line
):
match
=
re
.
search
(
r'^inet ([0-9.]+)/(\
d+)(?:
brd ([0-9.]+))?'
,
line
)
if
match
!=
None
:
return
ipv4address
(
address
=
match
.
group
(
1
),
prefix_len
=
match
.
group
(
2
),
broadcast
=
match
.
group
(
3
))
match
=
re
.
search
(
r'^inet6 ([0-9a-f:]+)/(\
d+)
', line)
if match != None:
return ipv6address(
address = match.group(1),
prefix_len = match.group(2))
raise RuntimeError("Problems parsing ip command output")
def __eq__(self, o):
if not isinstance(o, address):
return False
return (self.family == o.family and self.address == o.address and
self.prefix_len == o.prefix_len and
self.broadcast == o.broadcast)
def __hash__(self):
h = (self.address.__hash__() ^ self.prefix_len.__hash__() ^
self.family.__hash__())
if hasattr(self, '
broadcast
'):
h ^= self.broadcast.__hash__()
return h
class ipv4address(address):
def __init__(self, address, prefix_len, broadcast):
self.address = address
self.prefix_len = int(prefix_len)
self.broadcast = broadcast
self.family = socket.AF_INET
def __repr__(self):
s = "%s.%s(address = %s, prefix_len = %d, broadcast = %s)"
return s % (self.__module__, self.__class__.__name__,
self.address.__repr__(), self.prefix_len,
self.broadcast.__repr__())
class ipv6address(address):
def __init__(self, address, prefix_len):
self.address = address
self.prefix_len = int(prefix_len)
self.family = socket.AF_INET6
def __repr__(self):
s = "%s.%s(address = %s, prefix_len = %d)"
return s % (self.__module__, self.__class__.__name__,
self.address.__repr__(), self.prefix_len)
import
re
,
subprocess
,
sys
import
netns.interface
# XXX: ideally this should be replaced by netlink communication
def
get_if_data
():
...
...
@@ -128,7 +23,7 @@ def get_if_data():
continue
match
=
re
.
search
(
r'^(\
d+):
\s+(.*)'
,
line
)
idx
=
int
(
match
.
group
(
1
))
i = interface.parse_ip(line)
i
=
netns
.
interface
.
interface
.
parse_ip
(
line
)
byidx
[
idx
]
=
bynam
[
i
.
name
]
=
i
return
byidx
,
bynam
...
...
@@ -151,7 +46,7 @@ def get_addr_data():
if
match
.
group
(
3
):
bynam
[
name
]
=
byidx
[
idx
]
=
[]
continue
# link info
bynam[name].append(address.parse_ip(match.group(4)))
bynam
[
name
].
append
(
netns
.
interface
.
address
.
parse_ip
(
match
.
group
(
4
)))
return
byidx
,
bynam
def
create_if_pair
(
if1
,
if2
):
...
...
@@ -185,13 +80,13 @@ def create_if_pair(if1, if2):
return
interfaces
[
if1
.
name
],
interfaces
[
if2
.
name
]
def
del_if
(
iface
):
i
nterface = get_real_if
(iface)
execute(["
ip
", "
link
", "
del
", i
nterface.
name])
i
fname
=
get_if_name
(
iface
)
execute
([
"ip"
,
"link"
,
"del"
,
i
f
name
])
def
set_if
(
iface
,
recover
=
True
):
inter
face = get_real_if(iface)
_ils = ["
ip
", "
link
", "
set
", "
dev
",
inter
face.name]
diff = iface -
interface
orig_i
face
=
get_real_if
(
iface
)
_ils
=
[
"ip"
,
"link"
,
"set"
,
"dev"
,
orig_i
face
.
name
]
diff
=
iface
-
orig_iface
# Only set what's needed
cmds
=
[]
if
diff
.
name
:
cmds
.
append
(
_ils
+
[
"name"
,
diff
.
name
])
...
...
@@ -214,50 +109,54 @@ def set_if(iface, recover = True):
execute
(
c
)
except
:
if
recover
:
set_if(
inter
face, recover = False) # rollback
set_if
(
orig_i
face
,
recover
=
False
)
# rollback
raise
def
change_netns
(
iface
,
netns
):
ifname
=
get_if_name
(
iface
)
execute
([
"ip"
,
"link"
,
"set"
,
"dev"
,
ifname
,
"netns"
,
str
(
netns
)])
def
add_addr
(
iface
,
address
):
interface = get_real_if(iface)
assert address not in interface.addresses
cmd = ["
ip
", "
addr
", "
add
", "
dev
", interface.name, "
local
",
ifname
=
get_if_name
(
iface
)
addresses
=
get_addr_data
()[
1
][
ifname
]
assert
address
not
in
addresses
cmd
=
[
"ip"
,
"addr"
,
"add"
,
"dev"
,
ifname
,
"local"
,
"%s/%d"
%
(
address
.
address
,
int
(
address
.
prefix_len
))]
if
hasattr
(
address
,
"broadcast"
):
cmd
+=
[
"broadcast"
,
address
.
broadcast
if
address
.
broadcast
else
"+"
]
execute
(
cmd
)
interfaces = get_if_data()[0]
return interfaces[iface.index]
def
del_addr
(
iface
,
address
):
interface = get_real_if(iface)
assert address in interface.addresses
cmd = ["
ip
", "
addr
", "
del
", "
dev
", interface.name, "
local
",
ifname
=
get_if_name
(
iface
)
addresses
=
get_addr_data
()[
1
][
ifname
]
assert
address
in
addresses
cmd
=
[
"ip"
,
"addr"
,
"del"
,
"dev"
,
ifname
,
"local"
,
"%s/%d"
%
(
address
.
address
,
int
(
address
.
prefix_len
))]
execute
(
cmd
)
interfaces = get_if_data()[0]
return interfaces[iface.index]
def set_addr(iface, recover = True):
interface = get_real_if(iface)
to_remove = set(interface.addresses) - set(iface.addresses)
to_add = set(iface.addresses) - set(interface.addresses)
def
set_addr
(
iface
,
addresses
,
recover
=
True
):
ifname
=
get_if_name
(
iface
)
addresses
=
get_addr_data
()[
1
][
ifname
]
to_remove
=
set
(
orig_addresses
)
-
set
(
addresses
)
to_add
=
set
(
addresses
)
-
set
(
orig_addresses
)
for
a
in
to_remove
:
try
:
del_addr(if
ac
e, a)
del_addr
(
if
nam
e
,
a
)
except
:
if
recover
:
set_addr(
interface
, recover = False) # rollback
set_addr
(
orig_addresses
,
recover
=
False
)
# rollback
raise
for
a
in
to_add
:
try
:
add_addr(if
ac
e, a)
add_addr
(
if
nam
e
,
a
)
except
:
if
recover
:
set_addr(
interface
, recover = False) # rollback
set_addr
(
orig_addresses
,
recover
=
False
)
# rollback
raise
return get_real_if(iface)
# Useful stuff
...
...
@@ -271,7 +170,7 @@ def execute(cmd):
def
get_real_if
(
iface
):
ifdata
=
get_if_data
()
if isinstance(iface, interface):
if
isinstance
(
iface
,
netns
.
interface
.
interface
):
if
iface
.
index
!=
None
:
return
ifdata
[
0
][
iface
.
index
]
else
:
...
...
@@ -280,4 +179,10 @@ def get_real_if(iface):
return
ifdata
[
0
][
iface
]
return
ifdata
[
1
][
iface
]
def
get_if_name
(
iface
):
if
isinstance
(
iface
,
netns
.
interface
.
interface
):
if
iface
.
name
!=
None
:
return
iface
if
isinstance
(
iface
,
str
):
return
iface
return
get_real_if
(
iface
).
name
src/netns/protocol.py
View file @
9fc3b3ec
...
...
@@ -6,8 +6,10 @@ try:
from
yaml
import
CDumper
as
Dumper
except
ImportError
:
from
yaml
import
Loader
,
Dumper
import
base64
,
os
,
passfd
,
re
,
signal
,
socket
,
sys
,
traceback
,
unshare
,
yaml
import
netns.subprocess_
,
netns
.
iproute
import
base64
,
os
,
passfd
,
re
,
signal
,
sys
,
traceback
,
unshare
,
yaml
import
netns.subprocess_
,
netns
.
iproute
,
netns
.
interface
# FIXME: proper and uniform handling of errors
# ============================================================================
# Server-side protocol implementation
...
...
@@ -25,7 +27,7 @@ _proto_commands = {
"HELP"
:
{
None
:
(
""
,
""
)
},
"IF"
:
{
"LIST"
:
(
""
,
"i"
),
"SET"
:
(
"iss"
,
""
),
"SET"
:
(
"iss"
,
"
s*
"
),
"RTRN"
:
(
"ii"
,
""
)
},
"ADDR"
:
{
...
...
@@ -356,8 +358,35 @@ class Server(object):
self
.
reply
(
200
,
[
"# Interface data follows."
]
+
yaml
.
dump
(
ifdata
).
split
(
"
\
n
"
))
# def do_IF_SET(self, cmdname, ifnr, key, val):
# def do_IF_RTRN(self, cmdname, ifnr, netns):
def
do_IF_SET
(
self
,
cmdname
,
ifnr
,
*
args
):
if
len
(
args
)
%
2
:
self
.
reply
(
500
,
"Invalid number of arguments for IF SET: must be even."
)
return
d
=
{
'index'
:
ifnr
}
for
i
in
range
(
len
(
args
)
/
2
):
d
[
str
(
args
[
i
*
2
])]
=
args
[
i
*
2
+
1
]
try
:
iface
=
netns
.
interface
.
interface
(
**
d
)
except
:
self
.
reply
(
500
,
"Invalid parameters."
)
return
try
:
netns
.
iproute
.
set_if
(
iface
)
except
BaseException
,
e
:
self
.
reply
(
500
,
"Error setting interface: %s."
%
str
(
e
))
return
self
.
reply
(
200
,
"Done."
)
def
do_IF_RTRN
(
self
,
cmdname
,
ifnr
,
netns
):
try
:
netns
.
iproute
.
change_netns
(
ifnr
,
netns
)
except
BaseException
,
e
:
self
.
reply
(
500
,
"Error returning interface: %s."
%
str
(
e
))
return
self
.
reply
(
200
,
"Done."
)
def
do_ADDR_LIST
(
self
,
cmdname
,
ifnr
=
None
):
addrdata
=
netns
.
iproute
.
get_addr_data
()[
0
]
...
...
@@ -369,8 +398,22 @@ class Server(object):
self
.
reply
(
200
,
[
"# Address data follows."
]
+
yaml
.
dump
(
addrdata
).
split
(
"
\
n
"
))
# def do_ADDR_ADD(self, cmdname, ifnr, address, prefixlen, broadcast = None):
# def do_ADDR_DEL(self, cmdname, ifnr, address, prefixlen):
def
do_ADDR_ADD
(
self
,
cmdname
,
ifnr
,
address
,
prefixlen
,
broadcast
=
None
):
if
address
.
find
(
":"
)
<
0
:
# crude, I know
a
=
netns
.
interface
.
ipv4address
(
address
,
prefixlen
,
broadcast
)
else
:
a
=
netns
.
interface
.
ipv6address
(
address
,
prefixlen
)
netns
.
iproute
.
add_addr
(
ifnr
,
a
)
self
.
reply
(
200
,
"Done."
)
def
do_ADDR_DEL
(
self
,
cmdname
,
ifnr
,
address
,
prefixlen
):
if
address
.
find
(
":"
)
<
0
:
# crude, I know
a
=
netns
.
interface
.
ipv4address
(
address
,
prefixlen
,
None
)
else
:
a
=
netns
.
interface
.
ipv6address
(
address
,
prefixlen
)
netns
.
iproute
.
del_addr
(
ifnr
,
a
)
self
.
reply
(
200
,
"Done."
)
# def do_ROUT_LIST(self, cmdname):
# def do_ROUT_ADD(self, cmdname, prefix, prefixlen, nexthop, ifnr):
# def do_ROUT_DEL(self, cmdname, prefix, prefixlen, nexthop, ifnr):
...
...
@@ -528,6 +571,21 @@ class Client(object):
data
=
data
.
partition
(
"
\
n
"
)[
2
]
# ignore first line
return
yaml
.
load
(
data
)
def
set_if
(
self
,
interface
):
cmd
=
[
"IF"
,
"SET"
,
interface
.
index
]
for
k
in
(
"name"
,
"mtu"
,
"lladdr"
,
"broadcast"
,
"up"
,
"multicast"
,
"arp"
):
v
=
getattr
(
interface
,
k
)
if
v
!=
None
:
cmd
+=
[
k
,
str
(
v
)]
self
.
_send_cmd
(
*
cmd
)
self
.
_read_and_check_reply
()
def
change_netns
(
self
,
ifnr
,
netns
):
self
.
_send_cmd
(
"IF"
,
"RTRN"
,
ifnr
,
netns
)
self
.
_read_and_check_reply
()
def
get_addr_data
(
self
,
ifnr
=
None
):
if
ifnr
:
self
.
_send_cmd
(
"ADDR"
,
"LIST"
,
ifnr
)
...
...
@@ -537,6 +595,19 @@ class Client(object):
data
=
data
.
partition
(
"
\
n
"
)[
2
]
# ignore first line
return
yaml
.
load
(
data
)
def
add_addr
(
self
,
ifnr
,
address
):
if
hasattr
(
address
,
"broadcast"
)
and
address
.
broadcast
:
self
.
_send_cmd
(
"ADDR"
,
"ADD"
,
ifnr
,
address
.
address
,
address
.
prefix_len
,
address
.
broadcast
)
else
:
self
.
_send_cmd
(
"ADDR"
,
"ADD"
,
ifnr
,
address
.
address
,
address
.
prefix_len
)
self
.
_read_and_check_reply
()
def
del_addr
(
self
,
ifnr
,
address
):
self
.
_send_cmd
(
"ADDR"
,
"DEL"
,
ifnr
,
address
.
address
,
address
.
prefix_len
)
self
.
_read_and_check_reply
()
def
_b64
(
text
):
text
=
str
(
text
)
if
filter
(
lambda
x
:
ord
(
x
)
<=
ord
(
" "
)
or
ord
(
x
)
>
ord
(
"z"
)
...
...
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