Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
slapos.core
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
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
Paul Graydon
slapos.core
Commits
6272d68e
Commit
6272d68e
authored
Mar 08, 2023
by
Xavier Thompson
Browse files
Options
Browse Files
Download
Plain Diff
Slapformat: IPv6 range for partitions and tun
See merge request
nexedi/slapos.core!455
parents
7e2f8eec
c4e86b91
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
356 additions
and
120 deletions
+356
-120
slapos/cli/format.py
slapos/cli/format.py
+1
-1
slapos/format.py
slapos/format.py
+285
-105
slapos/tests/test_slapformat.py
slapos/tests/test_slapformat.py
+13
-14
slapos/util.py
slapos/util.py
+57
-0
No files found.
slapos/cli/format.py
View file @
6272d68e
...
@@ -125,7 +125,7 @@ class FormatCommand(ConfigCommand):
...
@@ -125,7 +125,7 @@ class FormatCommand(ConfigCommand):
try
:
try
:
conf
.
setConfig
()
conf
.
setConfig
()
except
UsageError
as
err
:
except
UsageError
as
err
:
sys
.
stderr
.
write
(
err
.
message
+
'
\
n
'
)
sys
.
stderr
.
write
(
str
(
err
)
+
'
\
n
'
)
sys
.
stderr
.
write
(
"For help use --help
\
n
"
)
sys
.
stderr
.
write
(
"For help use --help
\
n
"
)
sys
.
exit
(
1
)
sys
.
exit
(
1
)
...
...
slapos/format.py
View file @
6272d68e
...
@@ -58,7 +58,11 @@ import six
...
@@ -58,7 +58,11 @@ import six
import
lxml.etree
import
lxml.etree
import
xml_marshaller.xml_marshaller
import
xml_marshaller.xml_marshaller
from
slapos.util
import
dumps
,
mkdir_p
,
ipv6FromBin
,
binFromIpv6
,
lenNetmaskIpv6
from
slapos.util
import
(
dumps
,
mkdir_p
,
ipv6FromBin
,
binFromIpv6
,
lenNetmaskIpv6
,
getPartitionIpv6Addr
,
getPartitionIpv6Range
,
getTapIpv6Range
,
getTunIpv6Range
,
netmaskFromLenIPv6
,
getIpv6RangeFirstAddr
)
import
slapos.slap
as
slap
import
slapos.slap
as
slap
from
slapos
import
version
from
slapos
import
version
from
slapos
import
manager
as
slapmanager
from
slapos
import
manager
as
slapmanager
...
@@ -243,7 +247,7 @@ class Computer(object):
...
@@ -243,7 +247,7 @@ class Computer(object):
"""Object representing the computer"""
"""Object representing the computer"""
def
__init__
(
self
,
reference
,
interface
=
None
,
addr
=
None
,
netmask
=
None
,
def
__init__
(
self
,
reference
,
interface
=
None
,
addr
=
None
,
netmask
=
None
,
ipv6_interface
=
None
,
software_user
=
'slapsoft'
,
ipv6_interface
=
None
,
partition_has_ipv6_range
=
None
,
software_user
=
'slapsoft'
,
tap_gateway_interface
=
None
,
tap_ipv6
=
None
,
tap_gateway_interface
=
None
,
tap_ipv6
=
None
,
instance_root
=
None
,
software_root
=
None
,
instance_storage_home
=
None
,
instance_root
=
None
,
software_root
=
None
,
instance_storage_home
=
None
,
partition_list
=
None
,
config
=
None
):
partition_list
=
None
,
config
=
None
):
...
@@ -260,6 +264,7 @@ class Computer(object):
...
@@ -260,6 +264,7 @@ class Computer(object):
self
.
address
=
addr
self
.
address
=
addr
self
.
netmask
=
netmask
self
.
netmask
=
netmask
self
.
ipv6_interface
=
ipv6_interface
self
.
ipv6_interface
=
ipv6_interface
self
.
partition_has_ipv6_range
=
partition_has_ipv6_range
self
.
software_user
=
software_user
self
.
software_user
=
software_user
self
.
tap_gateway_interface
=
tap_gateway_interface
self
.
tap_gateway_interface
=
tap_gateway_interface
self
.
tap_ipv6
=
tap_ipv6
self
.
tap_ipv6
=
tap_ipv6
...
@@ -410,7 +415,7 @@ class Computer(object):
...
@@ -410,7 +415,7 @@ class Computer(object):
archive
.
writestr
(
saved_filename
,
xml_content
,
zipfile
.
ZIP_DEFLATED
)
archive
.
writestr
(
saved_filename
,
xml_content
,
zipfile
.
ZIP_DEFLATED
)
@
classmethod
@
classmethod
def
load
(
cls
,
path_to_xml
,
reference
,
ipv6_interface
,
tap_gateway_interface
,
def
load
(
cls
,
path_to_xml
,
reference
,
ipv6_interface
,
partition_has_ipv6_range
,
tap_gateway_interface
,
tap_ipv6
,
instance_root
=
None
,
software_root
=
None
,
config
=
None
):
tap_ipv6
,
instance_root
=
None
,
software_root
=
None
,
config
=
None
):
"""
"""
Create a computer object from a valid xml file.
Create a computer object from a valid xml file.
...
@@ -431,6 +436,7 @@ class Computer(object):
...
@@ -431,6 +436,7 @@ class Computer(object):
addr
=
dumped_dict
[
'address'
],
addr
=
dumped_dict
[
'address'
],
netmask
=
dumped_dict
[
'netmask'
],
netmask
=
dumped_dict
[
'netmask'
],
ipv6_interface
=
ipv6_interface
,
ipv6_interface
=
ipv6_interface
,
partition_has_ipv6_range
=
partition_has_ipv6_range
,
software_user
=
dumped_dict
.
get
(
'software_user'
,
'slapsoft'
),
software_user
=
dumped_dict
.
get
(
'software_user'
,
'slapsoft'
),
tap_gateway_interface
=
tap_gateway_interface
,
tap_gateway_interface
=
tap_gateway_interface
,
tap_ipv6
=
tap_ipv6
,
tap_ipv6
=
tap_ipv6
,
...
@@ -460,13 +466,28 @@ class Computer(object):
...
@@ -460,13 +466,28 @@ class Computer(object):
else
:
else
:
tap
=
Tap
(
partition_dict
[
'reference'
])
tap
=
Tap
(
partition_dict
[
'reference'
])
if
partition_dict
.
get
(
'tun'
)
is
not
None
and
partition_dict
[
'tun'
].
get
(
'ipv4_addr'
)
is
not
None
:
tun_dict
=
partition_dict
.
get
(
'tun'
)
tun
=
Tun
(
partition_dict
[
'tun'
][
'name'
],
partition_index
,
partition_amount
)
if
tun_dict
is
None
:
tun
.
ipv4_addr
=
partition_dict
[
'tun'
][
'ipv4_addr'
]
if
config
.
create_tun
:
tun
=
Tun
(
"slaptun"
+
str
(
partition_index
),
partition_index
,
partition_amount
,
config
.
tun_ipv6
)
else
:
tun
=
None
else
:
else
:
tun
=
Tun
(
"slaptun"
+
str
(
partition_index
),
partition_index
,
partition_amount
)
ipv4_addr
=
tun_dict
.
get
(
'ipv4_addr'
)
ipv6_addr
=
tun_dict
.
get
(
'ipv6_addr'
)
needs_ipv6
=
not
ipv6_addr
and
config
.
tun_ipv6
tun
=
Tun
(
tun_dict
[
'name'
],
partition_index
,
partition_amount
,
needs_ipv6
)
if
ipv4_addr
:
tun
.
ipv4_addr
=
ipv4_addr
tun
.
ipv4_netmask
=
tun_dict
[
'ipv4_netmask'
]
tun
.
ipv4_network
=
tun_dict
[
'ipv4_network'
]
if
ipv6_addr
:
tun
.
ipv6_addr
=
ipv6_addr
tun
.
ipv6_netmask
=
tun_dict
[
'ipv6_netmask'
]
tun
.
ipv6_network
=
tun_dict
[
'ipv6_network'
]
address_list
=
partition_dict
[
'address_list'
]
address_list
=
partition_dict
[
'address_list'
]
ipv6_range
=
partition_dict
.
get
(
'ipv6_range'
,
{})
external_storage_list
=
partition_dict
.
get
(
'external_storage_list'
,
[])
external_storage_list
=
partition_dict
.
get
(
'external_storage_list'
,
[])
partition
=
Partition
(
partition
=
Partition
(
...
@@ -474,8 +495,9 @@ class Computer(object):
...
@@ -474,8 +495,9 @@ class Computer(object):
path
=
partition_dict
[
'path'
],
path
=
partition_dict
[
'path'
],
user
=
user
,
user
=
user
,
address_list
=
address_list
,
address_list
=
address_list
,
ipv6_range
=
ipv6_range
,
tap
=
tap
,
tap
=
tap
,
tun
=
tun
if
config
.
create_tun
else
None
,
tun
=
tun
,
external_storage_list
=
external_storage_list
,
external_storage_list
=
external_storage_list
,
)
)
...
@@ -562,7 +584,7 @@ class Computer(object):
...
@@ -562,7 +584,7 @@ class Computer(object):
####################
####################
if
alter_network
:
if
alter_network
:
if
self
.
address
is
not
None
:
if
self
.
address
is
not
None
:
self
.
interface
.
addIPv6
Address
(
self
.
address
,
self
.
netmask
)
self
.
interface
.
_addSystem
Address
(
self
.
address
,
self
.
netmask
)
if
create_tap
and
self
.
tap_gateway_interface
:
if
create_tap
and
self
.
tap_gateway_interface
:
gateway_addr_dict
=
getIfaceAddressIPv4
(
self
.
tap_gateway_interface
)
gateway_addr_dict
=
getIfaceAddressIPv4
(
self
.
tap_gateway_interface
)
...
@@ -571,6 +593,9 @@ class Computer(object):
...
@@ -571,6 +593,9 @@ class Computer(object):
len
(
self
.
partition_list
))
len
(
self
.
partition_list
))
assert
(
len
(
self
.
partition_list
)
<=
len
(
tap_address_list
))
assert
(
len
(
self
.
partition_list
)
<=
len
(
tap_address_list
))
if
self
.
partition_has_ipv6_range
:
self
.
interface
.
allowNonlocalBind
()
self
.
_speedHackAddAllOldIpsToInterface
()
self
.
_speedHackAddAllOldIpsToInterface
()
try
:
try
:
...
@@ -614,23 +639,22 @@ class Computer(object):
...
@@ -614,23 +639,22 @@ class Computer(object):
if
self
.
tap_ipv6
:
if
self
.
tap_ipv6
:
if
not
partition
.
tap
.
ipv6_addr
:
if
not
partition
.
tap
.
ipv6_addr
:
# create a new IPv6 randomly for the tap
# create a new IPv6 randomly for the tap
ipv6_dict
=
self
.
interface
.
addIPv6Address
(
tap
=
partition
.
tap
)
ipv6_dict
=
self
.
interface
.
addIPv6Address
(
partition_index
,
tap
=
partition
.
tap
)
partition
.
tap
.
ipv6_addr
=
ipv6_dict
[
'addr'
]
partition
.
tap
.
ipv6_addr
=
ipv6_dict
[
'addr'
]
partition
.
tap
.
ipv6_netmask
=
ipv6_dict
[
'netmask'
]
partition
.
tap
.
ipv6_netmask
=
ipv6_dict
[
'netmask'
]
else
:
else
:
# make sure the tap has its IPv6
# make sure the tap has its IPv6
self
.
interface
.
addIPv6Address
(
self
.
interface
.
addIPv6Address
(
partition_index
=
partition_index
,
addr
=
partition
.
tap
.
ipv6_addr
,
addr
=
partition
.
tap
.
ipv6_addr
,
netmask
=
partition
.
tap
.
ipv6_netmask
,
netmask
=
partition
.
tap
.
ipv6_netmask
,
tap
=
partition
.
tap
)
tap
=
partition
.
tap
)
# construct ipv6_network (16 bit more than the computer network)
# construct ipv6_network (16 bit more than the computer network)
netmask_len
=
lenNetmaskIpv6
(
self
.
interface
.
getGlobalScopeAddressList
()[
0
][
'netmask'
])
+
16
prefixlen
=
lenNetmaskIpv6
(
self
.
interface
.
getGlobalScopeAddressList
()[
0
][
'netmask'
])
+
16
prefix
=
binFromIpv6
(
partition
.
tap
.
ipv6_addr
)[:
netmask_len
]
gateway_addr
=
getIpv6RangeFirstAddr
(
partition
.
tap
.
ipv6_addr
,
prefixlen
)
network_addr
=
ipv6FromBin
(
prefix
)
partition
.
tap
.
ipv6_gateway
=
gateway_addr
partition
.
tap
.
ipv6_gateway
=
"{}1"
.
format
(
network_addr
)
# address network::1 will be inside the VM
partition
.
tap
.
ipv6_network
=
"{}/{}"
.
format
(
gateway_addr
,
prefixlen
)
partition
.
tap
.
ipv6_gateway
=
ipv6FromBin
(
binFromIpv6
(
partition
.
tap
.
ipv6_gateway
))
# correctly format the IPv6
partition
.
tap
.
ipv6_network
=
"{}/{}"
.
format
(
network_addr
,
netmask_len
)
else
:
else
:
partition
.
tap
.
ipv6_addr
=
''
partition
.
tap
.
ipv6_addr
=
''
partition
.
tap
.
ipv6_netmask
=
''
partition
.
tap
.
ipv6_netmask
=
''
...
@@ -643,45 +667,72 @@ class Computer(object):
...
@@ -643,45 +667,72 @@ class Computer(object):
if
partition
.
tun
is
not
None
:
if
partition
.
tun
is
not
None
:
# create TUN interface per partition as well
# create TUN interface per partition as well
partition
.
tun
.
createWithOwner
(
owner
)
partition
.
tun
.
createWithOwner
(
owner
)
if
partition
.
tun
.
_needs_ipv6
:
ipv6_dict
=
self
.
interface
.
generateIPv6Range
(
partition_index
,
tun
=
True
)
prefixlen
=
ipv6_dict
[
'prefixlen'
]
ipv6_addr
=
getIpv6RangeFirstAddr
(
ipv6_dict
[
'addr'
],
prefixlen
)
partition
.
tun
.
ipv6_addr
=
ipv6_addr
partition
.
tun
.
ipv6_netmask
=
ipv6_dict
[
'netmask'
]
partition
.
tun
.
ipv6_network
=
"%s/%d"
%
(
ipv6_addr
,
prefixlen
)
partition
.
tun
.
createRoutes
()
partition
.
tun
.
createRoutes
()
# Reconstructing partition's address
# There should be two addresses on each Computer Partition:
# * local IPv4, took from slapformat:ipv4_local_network
# * global IPv6
if
not
partition
.
address_list
:
# generate new addresses
partition
.
address_list
.
append
(
self
.
interface
.
addIPv4LocalAddress
())
partition_ipv6_dict
=
self
.
interface
.
addIPv6Address
(
partition_index
)
# Avoid leaking prefixlen in dumped data because it is not loaded
# otherwise format dumps a different result after the first run
del
partition_ipv6_dict
[
'prefixlen'
]
partition
.
address_list
.
append
(
partition_ipv6_dict
)
else
:
# regenerate list of addresses
old_partition_address_list
=
partition
.
address_list
partition
.
address_list
=
[]
if
len
(
old_partition_address_list
)
!=
2
:
raise
ValueError
(
'There should be exactly 2 stored addresses. Got: %r'
%
(
old_partition_address_list
,))
if
not
any
(
netaddr
.
valid_ipv6
(
q
[
'addr'
])
for
q
in
old_partition_address_list
):
raise
ValueError
(
'No valid IPv6 address loaded from XML config'
)
if
not
any
(
netaddr
.
valid_ipv4
(
q
[
'addr'
])
for
q
in
old_partition_address_list
):
raise
ValueError
(
'No valid IPv4 address loaded from XML config'
)
for
address
in
old_partition_address_list
:
if
netaddr
.
valid_ipv6
(
address
[
'addr'
]):
partition
.
address_list
.
append
(
self
.
interface
.
addIPv6Address
(
partition_index
,
address
[
'addr'
],
address
[
'netmask'
]))
elif
netaddr
.
valid_ipv4
(
address
[
'addr'
]):
partition
.
address_list
.
append
(
self
.
interface
.
addIPv4LocalAddress
(
address
[
'addr'
]))
else
:
# should never happen since there are exactly 1 valid IPv6 and 1
# valid IPv4 in old_partition_address_list
raise
ValueError
(
'Address %r is incorrect'
%
address
[
'addr'
])
# Reconstructing partition's IPv6 range
if
self
.
partition_has_ipv6_range
:
if
not
partition
.
ipv6_range
:
# generate new IPv6 range
partition
.
ipv6_range
=
self
.
interface
.
generateIPv6Range
(
partition_index
)
else
:
if
not
netaddr
.
valid_ipv6
(
partition
.
ipv6_range
[
'addr'
]):
raise
ValueError
(
'existing IPv6 range %r is incorrect'
,
partition
.
ipv6_range
[
'addr'
])
self
.
interface
.
addLocalRouteIpv6Range
(
partition
.
ipv6_range
)
else
:
partition
.
ipv6_range
=
{}
# Reconstructing partition's directory
# Reconstructing partition's directory
partition
.
createPath
(
alter_user
)
partition
.
createPath
(
alter_user
)
partition
.
createExternalPath
(
alter_user
)
partition
.
createExternalPath
(
alter_user
)
# Reconstructing partition's address
# There should be two addresses on each Computer Partition:
# * local IPv4, took from slapformat:ipv4_local_network
# * global IPv6
if
not
partition
.
address_list
:
# regenerate
partition
.
address_list
.
append
(
self
.
interface
.
addIPv4LocalAddress
())
partition
.
address_list
.
append
(
self
.
interface
.
addIPv6Address
())
elif
alter_network
:
# regenerate list of addresses
old_partition_address_list
=
partition
.
address_list
partition
.
address_list
=
[]
if
len
(
old_partition_address_list
)
!=
2
:
raise
ValueError
(
'There should be exactly 2 stored addresses. Got: %r'
%
(
old_partition_address_list
,))
if
not
any
(
netaddr
.
valid_ipv6
(
q
[
'addr'
])
for
q
in
old_partition_address_list
):
raise
ValueError
(
'Not valid ipv6 addresses loaded'
)
if
not
any
(
netaddr
.
valid_ipv4
(
q
[
'addr'
])
for
q
in
old_partition_address_list
):
raise
ValueError
(
'Not valid ipv6 addresses loaded'
)
for
address
in
old_partition_address_list
:
if
netaddr
.
valid_ipv6
(
address
[
'addr'
]):
partition
.
address_list
.
append
(
self
.
interface
.
addIPv6Address
(
address
[
'addr'
],
address
[
'netmask'
]))
elif
netaddr
.
valid_ipv4
(
address
[
'addr'
]):
partition
.
address_list
.
append
(
self
.
interface
.
addIPv4LocalAddress
(
address
[
'addr'
]))
else
:
raise
ValueError
(
'Address %r is incorrect'
%
address
[
'addr'
])
finally
:
finally
:
for
manager
in
self
.
_manager_list
:
for
manager
in
self
.
_manager_list
:
manager
.
formatTearDown
(
self
)
manager
.
formatTearDown
(
self
)
...
@@ -693,13 +744,14 @@ class Partition(object):
...
@@ -693,13 +744,14 @@ class Partition(object):
resource_file
=
".slapos-resource"
resource_file
=
".slapos-resource"
def
__init__
(
self
,
reference
,
path
,
user
,
address_list
,
def
__init__
(
self
,
reference
,
path
,
user
,
address_list
,
tap
,
external_storage_list
=
[],
tun
=
None
):
ipv6_range
,
tap
,
tun
=
None
,
external_storage_list
=
[]
):
"""
"""
Attributes:
Attributes:
reference: String, the name of the partition.
reference: String, the name of the partition.
path: String, the path to the partition folder.
path: String, the path to the partition folder.
user: User, the user linked to this partition.
user: User, the user linked to this partition.
address_list: List of associated IP addresses.
address_list: List of associated IP addresses.
ipv6_range: IPv6 range given to this partition (dict with 'addr' and 'netmask').
tap: Tap, the tap interface linked to this partition e.g. used as a gateway for kvm
tap: Tap, the tap interface linked to this partition e.g. used as a gateway for kvm
tun: Tun interface used for special apps simulating ethernet connections
tun: Tun interface used for special apps simulating ethernet connections
external_storage_list: Base path list of folder to format for data storage
external_storage_list: Base path list of folder to format for data storage
...
@@ -709,12 +761,13 @@ class Partition(object):
...
@@ -709,12 +761,13 @@ class Partition(object):
self
.
path
=
str
(
path
)
self
.
path
=
str
(
path
)
self
.
user
=
user
self
.
user
=
user
self
.
address_list
=
address_list
or
[]
self
.
address_list
=
address_list
or
[]
self
.
ipv6_range
=
ipv6_range
or
{}
self
.
tap
=
tap
self
.
tap
=
tap
self
.
tun
=
tun
self
.
tun
=
tun
self
.
external_storage_list
=
[]
self
.
external_storage_list
=
[]
def
__getinitargs__
(
self
):
def
__getinitargs__
(
self
):
return
(
self
.
reference
,
self
.
path
,
self
.
user
,
self
.
address_list
,
self
.
tap
,
self
.
tun
)
return
(
self
.
reference
,
self
.
path
,
self
.
user
,
self
.
address_list
,
self
.
ipv6_range
,
self
.
tap
,
self
.
tun
)
def
createPath
(
self
,
alter_user
=
True
):
def
createPath
(
self
,
alter_user
=
True
):
"""
"""
...
@@ -925,13 +978,14 @@ class Tun(Tap):
...
@@ -925,13 +978,14 @@ class Tun(Tap):
BASE_MASK
=
12
BASE_MASK
=
12
BASE_NETWORK
=
"172.16.0.0"
BASE_NETWORK
=
"172.16.0.0"
def
__init__
(
self
,
name
,
sequence
=
None
,
partitions
=
None
):
def
__init__
(
self
,
name
,
sequence
=
None
,
partitions
=
None
,
needs_ipv6
=
False
):
"""Create TUN interface with subnet according to the optional ``sequence`` number.
"""Create TUN interface with subnet according to the optional ``sequence`` number.
:param name: name which will appear in ``ip list`` afterwards
:param name: name which will appear in ``ip list`` afterwards
:param sequence: {int} position of this TUN among all ``partitions``
:param sequence: {int} position of this TUN among all ``partitions``
"""
"""
super
(
Tun
,
self
).
__init__
(
name
)
super
(
Tun
,
self
).
__init__
(
name
)
self
.
_needs_ipv6
=
needs_ipv6
if
sequence
is
not
None
:
if
sequence
is
not
None
:
assert
0
<=
sequence
<
partitions
,
"0 <= {} < {}"
.
format
(
sequence
,
partitions
)
assert
0
<=
sequence
<
partitions
,
"0 <= {} < {}"
.
format
(
sequence
,
partitions
)
# create base IPNetwork
# create base IPNetwork
...
@@ -951,16 +1005,20 @@ class Tun(Tap):
...
@@ -951,16 +1005,20 @@ class Tun(Tap):
"""Extend for physical addition of network address because TAP let this on external class."""
"""Extend for physical addition of network address because TAP let this on external class."""
if
self
.
ipv4_network
:
if
self
.
ipv4_network
:
# add an address
# add an address
code
,
_
=
callAndRead
([
'ip'
,
'addr'
,
'add'
,
self
.
ipv4_network
,
'dev'
,
self
.
name
],
code
,
_
=
callAndRead
(
raise_on_error
=
False
)
[
'ip'
,
'addr'
,
'add'
,
self
.
ipv4_network
,
'dev'
,
self
.
name
],
raise_on_error
=
False
)
if
code
==
0
:
# address added to the interface - wait
time
.
sleep
(
1
)
if
self
.
ipv6_network
:
# add an address
code
,
_
=
callAndRead
(
[
'ip'
,
'addr'
,
'add'
,
self
.
ipv6_network
,
'dev'
,
self
.
name
],
raise_on_error
=
False
)
if
code
==
0
:
if
code
==
0
:
# address added to the interface - wait
# address added to the interface - wait
time
.
sleep
(
1
)
time
.
sleep
(
1
)
else
:
raise
RuntimeError
(
"Cannot setup address on interface {}. "
"Address is missing."
.
format
(
self
.
name
))
# create routes
super
(
Tun
,
self
).
createRoutes
()
class
Interface
(
object
):
class
Interface
(
object
):
...
@@ -975,7 +1033,8 @@ class Interface(object):
...
@@ -975,7 +1033,8 @@ class Interface(object):
self
.
_logger
=
logger
self
.
_logger
=
logger
self
.
name
=
str
(
name
)
self
.
name
=
str
(
name
)
self
.
ipv4_local_network
=
ipv4_local_network
self
.
ipv4_local_network
=
ipv4_local_network
self
.
ipv6_interface
=
ipv6_interface
self
.
ipv6_interface
=
ipv6_interface
or
name
self
.
_ipv6_ranges
=
set
()
# XXX no __getinitargs__, as instances of this class are never deserialized.
# XXX no __getinitargs__, as instances of this class are never deserialized.
...
@@ -998,7 +1057,7 @@ class Interface(object):
...
@@ -998,7 +1057,7 @@ class Interface(object):
def
getGlobalScopeAddressList
(
self
,
tap
=
None
):
def
getGlobalScopeAddressList
(
self
,
tap
=
None
):
"""Returns currently configured global scope IPv6 addresses"""
"""Returns currently configured global scope IPv6 addresses"""
interface_name
=
self
.
ipv6_interface
or
self
.
name
interface_name
=
self
.
ipv6_interface
try
:
try
:
address_list
=
[
address_list
=
[
q
q
...
@@ -1008,6 +1067,8 @@ class Interface(object):
...
@@ -1008,6 +1067,8 @@ class Interface(object):
except
KeyError
:
except
KeyError
:
raise
ValueError
(
"%s must have at least one IPv6 address assigned"
%
raise
ValueError
(
"%s must have at least one IPv6 address assigned"
%
interface_name
)
interface_name
)
if
not
address_list
:
raise
NoAddressOnInterface
(
interface_name
)
if
tap
:
if
tap
:
try
:
try
:
...
@@ -1042,13 +1103,12 @@ class Interface(object):
...
@@ -1042,13 +1103,12 @@ class Interface(object):
if
ipv6
:
if
ipv6
:
address_string
=
'%s/%s'
%
(
address
,
lenNetmaskIpv6
(
netmask
))
address_string
=
'%s/%s'
%
(
address
,
lenNetmaskIpv6
(
netmask
))
af
=
socket
.
AF_INET6
af
=
socket
.
AF_INET6
interface_name
=
self
.
ipv6_interface
or
self
.
name
interface_name
=
self
.
ipv6_interface
else
:
else
:
af
=
socket
.
AF_INET
af
=
socket
.
AF_INET
address_string
=
'%s/%s'
%
(
address
,
netmaskToPrefixIPv4
(
netmask
))
address_string
=
'%s/%s'
%
(
address
,
netmaskToPrefixIPv4
(
netmask
))
interface_name
=
self
.
name
interface_name
=
self
.
name
if
tap
:
if
tap
:
interface_name
=
tap
.
name
interface_name
=
tap
.
name
# check if address is already took by any other interface
# check if address is already took by any other interface
...
@@ -1066,13 +1126,10 @@ class Interface(object):
...
@@ -1066,13 +1126,10 @@ class Interface(object):
for
q
in
netifaces
.
ifaddresses
(
interface_name
)[
af
]
for
q
in
netifaces
.
ifaddresses
(
interface_name
)[
af
]
]:
]:
# add an address
# add an address
callAndRead
([
'ip'
,
'addr'
,
'add'
,
address_string
,
'dev'
,
interface_name
])
c
ode
,
_
=
c
allAndRead
([
'ip'
,
'addr'
,
'add'
,
address_string
,
'dev'
,
interface_name
])
# Fake success for local ipv4
if
code
!=
0
:
if
not
ipv6
:
return
False
return
True
# wait few moments
time
.
sleep
(
2
)
time
.
sleep
(
2
)
# Fake success for local ipv4
# Fake success for local ipv4
...
@@ -1126,7 +1183,47 @@ class Interface(object):
...
@@ -1126,7 +1183,47 @@ class Interface(object):
# confirmed to be configured
# confirmed to be configured
return
dict
(
addr
=
addr
,
netmask
=
netmask
)
return
dict
(
addr
=
addr
,
netmask
=
netmask
)
def
addIPv6Address
(
self
,
addr
=
None
,
netmask
=
None
,
tap
=
None
):
def
_checkIpv6Range
(
self
,
address
,
prefixlen
):
network
=
str
(
netaddr
.
IPNetwork
(
"%s/%d"
%
(
address
,
prefixlen
)).
cidr
)
if
network
in
self
.
_ipv6_ranges
:
self
.
_logger
.
warning
(
"Address range %s/%d is already attributed"
,
address
,
prefixlen
)
return
False
return
True
def
_reserveIpv6Range
(
self
,
address
,
prefixlen
):
network
=
str
(
netaddr
.
IPNetwork
(
"%s/%d"
%
(
address
,
prefixlen
)).
cidr
)
assert
(
network
not
in
self
.
_ipv6_ranges
)
self
.
_ipv6_ranges
.
add
(
network
)
def
_tryReserveIpv6Range
(
self
,
address
,
prefixlen
):
if
self
.
_checkIpv6Range
(
address
,
prefixlen
):
self
.
_reserveIpv6Range
(
address
,
prefixlen
)
return
True
return
False
def
_generateRandomIPv6Addr
(
self
,
address_dict
):
netmask
=
address_dict
[
'netmask'
]
netmask_len
=
lenNetmaskIpv6
(
netmask
)
r
=
random
.
randint
(
1
,
65000
)
addr
=
':'
.
join
(
address_dict
[
'addr'
].
split
(
':'
)[:
-
1
]
+
[
'%x'
%
r
])
socket
.
inet_pton
(
socket
.
AF_INET6
,
address
)
return
dict
(
addr
=
addr
,
netmask
=
netmask
)
def
_generateRandomIPv6Range
(
self
,
address_dict
,
suffix
):
prefixlen
=
lenNetmaskIpv6
(
address_dict
[
'netmask'
])
prefix
=
binFromIpv6
(
address_dict
[
'addr'
])[:
prefixlen
]
prefixlen
+=
16
if
prefixlen
>=
128
:
msg
=
'Address range %r is too small for IPv6 subranges'
self
.
_logger
.
error
(
msg
,
address_dict
)
raise
AddressGenerationError
(
'%s/%d'
%
(
address_dict
[
'addr'
],
prefixlen
))
addr
=
ipv6FromBin
(
prefix
+
bin
(
random
.
randint
(
1
,
65000
))[
2
:].
zfill
(
16
)
+
suffix
*
(
128
-
prefixlen
))
return
dict
(
addr
=
addr
,
prefixlen
=
prefixlen
,
netmask
=
netmaskFromLenIPv6
(
prefixlen
))
def
addIPv6Address
(
self
,
partition_index
,
addr
=
None
,
netmask
=
None
,
tap
=
None
):
"""
"""
Adds IPv6 address to interface.
Adds IPv6 address to interface.
...
@@ -1136,6 +1233,9 @@ class Interface(object):
...
@@ -1136,6 +1233,9 @@ class Interface(object):
address. If it is not possible (ex. because network changed), calculate new
address. If it is not possible (ex. because network changed), calculate new
address.
address.
If tap is specified, tap will get actually an IPv6 range (and not a single
address) 16 bits smaller than the range of the interface.
Args:
Args:
addr: Wished address to be added to interface.
addr: Wished address to be added to interface.
netmask: Wished netmask to be used.
netmask: Wished netmask to be used.
...
@@ -1150,13 +1250,10 @@ class Interface(object):
...
@@ -1150,13 +1250,10 @@ class Interface(object):
NoAddressOnInterface: There's no address on the interface to construct
NoAddressOnInterface: There's no address on the interface to construct
an address with.
an address with.
"""
"""
interface_name
=
self
.
ipv6_interface
or
self
.
name
interface_name
=
self
.
ipv6_interface
# Getting one address of the interface as base of the next addresses
# Getting one address of the interface as base of the next addresses
interface_addr_list
=
self
.
getGlobalScopeAddressList
()
interface_addr_list
=
self
.
getGlobalScopeAddressList
()
# No address found
if
len
(
interface_addr_list
)
==
0
:
raise
NoAddressOnInterface
(
interface_name
)
address_dict
=
interface_addr_list
[
0
]
address_dict
=
interface_addr_list
[
0
]
if
addr
is
not
None
:
if
addr
is
not
None
:
...
@@ -1173,7 +1270,8 @@ class Interface(object):
...
@@ -1173,7 +1270,8 @@ class Interface(object):
if
dict_addr_netmask
in
interface_addr_list
or
\
if
dict_addr_netmask
in
interface_addr_list
or
\
(
tap
and
dict_addr_netmask
in
self
.
getGlobalScopeAddressList
(
tap
=
tap
)):
(
tap
and
dict_addr_netmask
in
self
.
getGlobalScopeAddressList
(
tap
=
tap
)):
# confirmed to be configured
# confirmed to be configured
return
dict_addr_netmask
# return without len to keep format stable, as the first time len is not included
return
dict_addr_netmask_without_len
if
netmask
==
address_dict
[
'netmask'
]
or
\
if
netmask
==
address_dict
[
'netmask'
]
or
\
(
tap
and
lenNetmaskIpv6
(
netmask
)
==
128
):
(
tap
and
lenNetmaskIpv6
(
netmask
)
==
128
):
# same netmask, so there is a chance to add good one
# same netmask, so there is a chance to add good one
...
@@ -1191,39 +1289,106 @@ class Interface(object):
...
@@ -1191,39 +1289,106 @@ class Interface(object):
self
.
_logger
.
warning
(
'Impossible to add old public IPv6 %s. '
self
.
_logger
.
warning
(
'Impossible to add old public IPv6 %s. '
'Generating new IPv6 address.'
%
addr
)
'Generating new IPv6 address.'
%
addr
)
# Try 10 times to add address, raise in case if not possible
# Try to use the IPv6 mapping based on partition index
try_num
=
10
address_dict
[
'prefixlen'
]
=
lenNetmaskIpv6
(
address_dict
[
'netmask'
])
netmask
=
address_dict
[
'netmask'
]
if
tap
:
if
tap
:
netmask_len
=
lenNetmaskIpv6
(
netmask
)
result_addr
=
getTapIpv6Range
(
address_dict
,
partition_index
)
prefix
=
binFromIpv6
(
address_dict
[
'addr'
])[:
netmask_len
]
# the netmask of the tap itself is always 128 bits
netmask_len
+=
16
result_addr
[
'netmask'
]
=
netmaskFromLenIPv6
(
128
)
# we generate a subnetwork for the tap
else
:
# the subnetwork has 16 bits more than the interface network
result_addr
=
getPartitionIpv6Addr
(
address_dict
,
partition_index
)
# make sure we have at least 2 IPs in the subnetwork
result_addr
[
'netmask'
]
=
netmaskFromLenIPv6
(
result_addr
[
'prefixlen'
])
if
netmask_len
>=
128
:
if
not
tap
or
self
.
_checkIpv6Range
(
result_addr
[
'addr'
],
result_addr
[
'prefixlen'
]):
self
.
_logger
.
error
(
'Interface %s has netmask %s which is too big for generating IPv6 on taps.'
%
(
interface_name
,
netmask
))
if
self
.
_addSystemAddress
(
result_addr
[
'addr'
],
result_addr
[
'netmask'
],
tap
=
tap
):
raise
AddressGenerationError
(
addr
)
if
tap
:
netmask
=
ipv6FromBin
(
'1'
*
128
)
# the netmask of the tap itself is always 128 bits
self
.
_reserveIpv6Range
(
result_addr
[
'addr'
],
result_addr
[
'prefixlen'
])
return
result_addr
self
.
_logger
.
warning
(
"Falling back to random address selection for partition %s"
" because %s/%s is already taken"
%
(
'%s tap'
%
partition_index
if
tap
else
partition_index
,
result_addr
[
'addr'
],
result_addr
[
'prefixlen'
],
))
while
try_num
>
0
:
# Try 10 times to add address, raise in case if not possible
for
_
in
range
(
10
):
if
tap
:
if
tap
:
addr
=
ipv6FromBin
(
prefix
result_addr
=
self
.
_generateRandomIPv6Range
(
address_dict
,
suffix
=
'1'
)
+
bin
(
random
.
randint
(
1
,
65000
))[
2
:].
zfill
(
16
)
# the netmask of the tap itself is always 128 bits
+
'1'
*
(
128
-
netmask_len
)
)
result_addr
[
'netmask'
]
=
netmaskFromLenIPv6
(
128
)
else
:
else
:
addr
=
':'
.
join
(
address_dict
[
'addr'
].
split
(
':'
)[:
-
1
]
+
[
'%x'
%
(
result_addr
=
self
.
_generateRandomIPv6Addr
(
address_dict
)
random
.
randint
(
1
,
65000
),
)])
# Checking the validity of the IPv6 address
socket
.
inet_pton
(
socket
.
AF_INET6
,
addr
)
addr
=
result_addr
[
'addr'
]
if
(
dict
(
addr
=
addr
,
netmask
=
netmask
)
not
in
if
not
tap
or
self
.
_checkIpv6Range
(
addr
,
result_addr
[
'prefixlen'
]):
self
.
getGlobalScopeAddressList
(
tap
=
tap
)):
if
self
.
_addSystemAddress
(
addr
,
result_addr
[
'netmask'
],
tap
=
tap
):
# Checking the validity of the IPv6 address
if
tap
:
if
self
.
_addSystemAddress
(
addr
,
netmask
,
tap
=
tap
):
self
.
_reserveIpv6Range
(
addr
,
result_addr
[
'prefixlen'
])
return
dict
(
addr
=
addr
,
netmask
=
netmask
)
return
result_addr
try_num
-=
1
raise
AddressGenerationError
(
addr
)
raise
AddressGenerationError
(
addr
)
def
generateIPv6Range
(
self
,
i
,
tun
=
False
):
"""
Generate an IPv6 range included in the IPv6 range of the interface. The IPv6 range depends on the partition index i.
Returns:
dict(addr=address, netmask=netmask, network=addr/CIDR).
Raises:
ValueError: Couldn't construct valid address with existing
one's on the interface.
NoAddressOnInterface: There's no address on the interface to construct
an address with.
"""
interface_name
=
self
.
ipv6_interface
or
self
.
name
# Getting one address of the interface as base of the next addresses
interface_addr_list
=
self
.
getGlobalScopeAddressList
()
address_dict
=
interface_addr_list
[
0
]
address_dict
[
'prefixlen'
]
=
lenNetmaskIpv6
(
address_dict
[
'netmask'
])
if
tun
:
ipv6_range
=
getTunIpv6Range
(
address_dict
,
i
)
else
:
ipv6_range
=
getPartitionIpv6Range
(
address_dict
,
i
)
ipv6_range
[
'netmask'
]
=
netmaskFromLenIPv6
(
ipv6_range
[
'prefixlen'
])
ipv6_range
[
'network'
]
=
'%(addr)s/%(prefixlen)d'
%
ipv6_range
if
self
.
_tryReserveIpv6Range
(
ipv6_range
[
'addr'
],
ipv6_range
[
'prefixlen'
]):
return
ipv6_range
self
.
_logger
.
warning
(
"Falling back to random IPv6 range selection for partition %s"
" because %s is already taken"
%
(
'%s tun'
%
i
if
tun
else
i
,
ipv6_range
[
'network'
],
))
# Try 10 times to add address, raise in case if not possible
for
_
in
range
(
10
):
ipv6_range
=
self
.
_generateRandomIPv6Range
(
address_dict
,
suffix
=
'0'
)
if
self
.
_tryReserveIpv6Range
(
ipv6_range
[
'addr'
],
ipv6_range
[
'prefixlen'
]):
return
ipv6_range
raise
AddressGenerationError
(
ipv6_range
[
'addr'
])
def
allowNonlocalBind
(
self
):
# This will allow the usage of unexisting IPv6 adresses.
self
.
_logger
.
debug
(
'sysctl net.ipv6.ip_nonlocal_bind=1'
)
callAndRead
([
'sysctl'
,
'net.ipv6.ip_nonlocal_bind=1'
])
def
addLocalRouteIpv6Range
(
self
,
ipv6_range
):
# Add the IPv6 range to local route table
# This will allow using the addresses in the range
# even if they are not added anywhere.
network
=
ipv6_range
[
'network'
]
_
,
result
=
callAndRead
([
'ip'
,
'-6'
,
'route'
,
'show'
,
'table'
,
'local'
,
network
])
if
not
'dev lo'
in
result
:
self
.
_logger
.
debug
(
' ip -6 route add local %s dev lo'
,
network
)
callAndRead
([
'ip'
,
'-6'
,
'route'
,
'add'
,
'local'
,
network
,
'dev'
,
'lo'
])
def
parse_computer_definition
(
conf
,
definition_path
):
def
parse_computer_definition
(
conf
,
definition_path
):
conf
.
logger
.
info
(
'Using definition file %r'
%
definition_path
)
conf
.
logger
.
info
(
'Using definition file %r'
%
definition_path
)
...
@@ -1248,6 +1413,7 @@ def parse_computer_definition(conf, definition_path):
...
@@ -1248,6 +1413,7 @@ def parse_computer_definition(conf, definition_path):
addr
=
address
,
addr
=
address
,
netmask
=
netmask
,
netmask
=
netmask
,
ipv6_interface
=
conf
.
ipv6_interface
,
ipv6_interface
=
conf
.
ipv6_interface
,
partition_has_ipv6_range
=
conf
.
partition_has_ipv6_range
,
software_user
=
computer_definition
.
get
(
'computer'
,
'software_user'
),
software_user
=
computer_definition
.
get
(
'computer'
,
'software_user'
),
tap_gateway_interface
=
conf
.
tap_gateway_interface
,
tap_gateway_interface
=
conf
.
tap_gateway_interface
,
tap_ipv6
=
conf
.
tap_ipv6
,
tap_ipv6
=
conf
.
tap_ipv6
,
...
@@ -1262,15 +1428,23 @@ def parse_computer_definition(conf, definition_path):
...
@@ -1262,15 +1428,23 @@ def parse_computer_definition(conf, definition_path):
for
a
in
computer_definition
.
get
(
section
,
'address'
).
split
():
for
a
in
computer_definition
.
get
(
section
,
'address'
).
split
():
address
,
netmask
=
a
.
split
(
'/'
)
address
,
netmask
=
a
.
split
(
'/'
)
address_list
.
append
(
dict
(
addr
=
address
,
netmask
=
netmask
))
address_list
.
append
(
dict
(
addr
=
address
,
netmask
=
netmask
))
if
computer_definition
.
has_option
(
section
,
'ipv6_range'
):
ipv6_range_network
=
computer_definition
.
get
(
section
,
'ipv6_range'
)
addr
,
netmask
=
ipv6_range_network
.
split
(
'/'
)
netmask
=
netmaskFromLenIPv6
(
int
(
netmask
))
ipv6_range
=
{
'addr'
:
address
,
'netmask'
:
netmask
,
'network'
:
ipv6_range_network
}
else
:
ipv6_range
=
{}
tap
=
Tap
(
computer_definition
.
get
(
section
,
'network_interface'
))
tap
=
Tap
(
computer_definition
.
get
(
section
,
'network_interface'
))
tun
=
Tun
(
"slaptun"
+
str
(
partition_number
),
tun
=
Tun
(
"slaptun"
+
str
(
partition_number
),
partition_number
,
partition_number
,
int
(
conf
.
partition_amount
))
if
conf
.
create_tun
else
None
int
(
conf
.
partition_amount
,
conf
.
tun_ipv6
))
if
conf
.
create_tun
else
None
partition
=
Partition
(
reference
=
computer_definition
.
get
(
section
,
'pathname'
),
partition
=
Partition
(
reference
=
computer_definition
.
get
(
section
,
'pathname'
),
path
=
os
.
path
.
join
(
conf
.
instance_root
,
path
=
os
.
path
.
join
(
conf
.
instance_root
,
computer_definition
.
get
(
section
,
'pathname'
)),
computer_definition
.
get
(
section
,
'pathname'
)),
user
=
user
,
user
=
user
,
address_list
=
address_list
,
address_list
=
address_list
,
ipv6_range
=
ipv6_range
,
tap
=
tap
,
tun
=
tun
)
tap
=
tap
,
tun
=
tun
)
partition_list
.
append
(
partition
)
partition_list
.
append
(
partition
)
computer
.
partition_list
=
partition_list
computer
.
partition_list
=
partition_list
...
@@ -1288,6 +1462,7 @@ def parse_computer_xml(conf, xml_path):
...
@@ -1288,6 +1462,7 @@ def parse_computer_xml(conf, xml_path):
computer
=
Computer
.
load
(
xml_path
,
computer
=
Computer
.
load
(
xml_path
,
reference
=
conf
.
computer_id
,
reference
=
conf
.
computer_id
,
ipv6_interface
=
conf
.
ipv6_interface
,
ipv6_interface
=
conf
.
ipv6_interface
,
partition_has_ipv6_range
=
conf
.
partition_has_ipv6_range
,
tap_gateway_interface
=
conf
.
tap_gateway_interface
,
tap_gateway_interface
=
conf
.
tap_gateway_interface
,
tap_ipv6
=
conf
.
tap_ipv6
,
tap_ipv6
=
conf
.
tap_ipv6
,
software_root
=
conf
.
software_root
,
software_root
=
conf
.
software_root
,
...
@@ -1306,6 +1481,7 @@ def parse_computer_xml(conf, xml_path):
...
@@ -1306,6 +1481,7 @@ def parse_computer_xml(conf, xml_path):
addr
=
None
,
addr
=
None
,
netmask
=
None
,
netmask
=
None
,
ipv6_interface
=
conf
.
ipv6_interface
,
ipv6_interface
=
conf
.
ipv6_interface
,
partition_has_ipv6_range
=
conf
.
partition_has_ipv6_range
,
software_user
=
conf
.
software_user
,
software_user
=
conf
.
software_user
,
tap_gateway_interface
=
conf
.
tap_gateway_interface
,
tap_gateway_interface
=
conf
.
tap_gateway_interface
,
tap_ipv6
=
conf
.
tap_ipv6
,
tap_ipv6
=
conf
.
tap_ipv6
,
...
@@ -1332,8 +1508,9 @@ def parse_computer_xml(conf, xml_path):
...
@@ -1332,8 +1508,9 @@ def parse_computer_xml(conf, xml_path):
conf
.
partition_base_name
,
i
)),
conf
.
partition_base_name
,
i
)),
user
=
User
(
'%s%s'
%
(
conf
.
user_base_name
,
i
)),
user
=
User
(
'%s%s'
%
(
conf
.
user_base_name
,
i
)),
address_list
=
None
,
address_list
=
None
,
ipv6_range
=
None
,
tap
=
Tap
(
'%s%s'
%
(
conf
.
tap_base_name
,
i
)),
tap
=
Tap
(
'%s%s'
%
(
conf
.
tap_base_name
,
i
)),
tun
=
Tun
(
'slaptun'
+
str
(
i
),
i
,
partition_amount
)
if
conf
.
create_tun
else
None
tun
=
Tun
(
'slaptun'
+
str
(
i
),
i
,
partition_amount
,
conf
.
tun_ipv6
)
if
conf
.
create_tun
else
None
)
)
computer
.
partition_list
.
append
(
partition
)
computer
.
partition_list
.
append
(
partition
)
...
@@ -1353,6 +1530,7 @@ def write_computer_definition(conf, computer):
...
@@ -1353,6 +1530,7 @@ def write_computer_definition(conf, computer):
for
address
in
partition
.
address_list
:
for
address
in
partition
.
address_list
:
address_list
.
append
(
'/'
.
join
([
address
[
'addr'
],
address
[
'netmask'
]]))
address_list
.
append
(
'/'
.
join
([
address
[
'addr'
],
address
[
'netmask'
]]))
computer_definition
.
set
(
section
,
'address'
,
' '
.
join
(
address_list
))
computer_definition
.
set
(
section
,
'address'
,
' '
.
join
(
address_list
))
computer_definition
.
set
(
section
,
'ipv6_range'
,
partition
.
ipv6_range
[
'network'
])
computer_definition
.
set
(
section
,
'user'
,
partition
.
user
.
name
)
computer_definition
.
set
(
section
,
'user'
,
partition
.
user
.
name
)
computer_definition
.
set
(
section
,
'network_interface'
,
partition
.
tap
.
name
)
computer_definition
.
set
(
section
,
'network_interface'
,
partition
.
tap
.
name
)
computer_definition
.
set
(
section
,
'pathname'
,
partition
.
reference
)
computer_definition
.
set
(
section
,
'pathname'
,
partition
.
reference
)
...
@@ -1418,12 +1596,14 @@ class FormatConfig(object):
...
@@ -1418,12 +1596,14 @@ class FormatConfig(object):
alter_network
=
'True'
# modifiable by cmdline
alter_network
=
'True'
# modifiable by cmdline
interface_name
=
None
interface_name
=
None
ipv6_interface
=
None
ipv6_interface
=
None
partition_has_ipv6_range
=
True
create_tap
=
True
create_tap
=
True
create_tun
=
False
tap_base_name
=
None
tap_base_name
=
None
tap_ipv6
=
True
tap_ipv6
=
True
tap_gateway_interface
=
''
tap_gateway_interface
=
''
ipv4_local_network
=
None
ipv4_local_network
=
None
create_tun
=
False
tun_ipv6
=
True
# User options
# User options
alter_user
=
'True'
# modifiable by cmdline
alter_user
=
'True'
# modifiable by cmdline
...
@@ -1482,7 +1662,7 @@ class FormatConfig(object):
...
@@ -1482,7 +1662,7 @@ class FormatConfig(object):
raise
UsageError
(
message
)
raise
UsageError
(
message
)
# Convert strings to booleans
# Convert strings to booleans
for
option
in
[
'alter_network'
,
'alter_user'
,
'
create_tap'
,
'create_tun'
,
'tap
_ipv6'
]:
for
option
in
[
'alter_network'
,
'alter_user'
,
'
partition_has_ipv6_range'
,
'create_tap'
,
'create_tun'
,
'tap_ipv6'
,
'tun
_ipv6'
]:
attr
=
getattr
(
self
,
option
)
attr
=
getattr
(
self
,
option
)
if
isinstance
(
attr
,
str
):
if
isinstance
(
attr
,
str
):
if
attr
.
lower
()
==
'true'
:
if
attr
.
lower
()
==
'true'
:
...
...
slapos/tests/test_slapformat.py
View file @
6272d68e
...
@@ -301,7 +301,7 @@ class SlapformatMixin(unittest.TestCase):
...
@@ -301,7 +301,7 @@ class SlapformatMixin(unittest.TestCase):
raise
ValueError
(
"{} already has logger attached"
.
format
(
self
.
__class__
.
__name__
))
raise
ValueError
(
"{} already has logger attached"
.
format
(
self
.
__class__
.
__name__
))
self
.
logger
=
logger
self
.
logger
=
logger
self
.
partition
=
slapos
.
format
.
Partition
(
'partition'
,
'/part_path'
,
self
.
partition
=
slapos
.
format
.
Partition
(
'partition'
,
'/part_path'
,
slapos
.
format
.
User
(
'testuser'
),
[],
None
)
slapos
.
format
.
User
(
'testuser'
),
[],
None
,
None
)
global
USER_LIST
global
USER_LIST
USER_LIST
=
[]
USER_LIST
=
[]
global
GROUP_LIST
global
GROUP_LIST
...
@@ -423,7 +423,8 @@ class TestComputer(SlapformatMixin):
...
@@ -423,7 +423,8 @@ class TestComputer(SlapformatMixin):
logger
=
self
.
logger
,
name
=
'myinterface'
,
ipv4_local_network
=
'127.0.0.1/16'
),
logger
=
self
.
logger
,
name
=
'myinterface'
,
ipv4_local_network
=
'127.0.0.1/16'
),
partition_list
=
[
partition_list
=
[
slapos
.
format
.
Partition
(
slapos
.
format
.
Partition
(
'partition'
,
'/part_path'
,
slapos
.
format
.
User
(
'testuser'
),
[],
tap
=
slapos
.
format
.
Tap
(
'tap'
)),
'partition'
,
'/part_path'
,
slapos
.
format
.
User
(
'testuser'
),
[],
ipv6_range
=
None
,
tap
=
slapos
.
format
.
Tap
(
'tap'
)),
])
])
global
INTERFACE_DICT
global
INTERFACE_DICT
INTERFACE_DICT
[
'myinterface'
]
=
{
INTERFACE_DICT
[
'myinterface'
]
=
{
...
@@ -466,7 +467,8 @@ class TestComputer(SlapformatMixin):
...
@@ -466,7 +467,8 @@ class TestComputer(SlapformatMixin):
logger
=
self
.
logger
,
name
=
'myinterface'
,
ipv4_local_network
=
'127.0.0.1/16'
),
logger
=
self
.
logger
,
name
=
'myinterface'
,
ipv4_local_network
=
'127.0.0.1/16'
),
partition_list
=
[
partition_list
=
[
slapos
.
format
.
Partition
(
slapos
.
format
.
Partition
(
'partition'
,
'/part_path'
,
slapos
.
format
.
User
(
'testuser'
),
[],
tap
=
slapos
.
format
.
Tap
(
'tap'
)),
'partition'
,
'/part_path'
,
slapos
.
format
.
User
(
'testuser'
),
[],
ipv6_range
=
None
,
tap
=
slapos
.
format
.
Tap
(
'tap'
)),
])
])
global
USER_LIST
global
USER_LIST
USER_LIST
=
[
'testuser'
]
USER_LIST
=
[
'testuser'
]
...
@@ -517,7 +519,7 @@ class TestComputer(SlapformatMixin):
...
@@ -517,7 +519,7 @@ class TestComputer(SlapformatMixin):
partition_list
=
[
partition_list
=
[
slapos
.
format
.
Partition
(
slapos
.
format
.
Partition
(
'partition'
,
'/part_path'
,
slapos
.
format
.
User
(
'testuser'
),
[],
'partition'
,
'/part_path'
,
slapos
.
format
.
User
(
'testuser'
),
[],
tap
=
slapos
.
format
.
Tap
(
'tap'
)),
ipv6_range
=
None
,
tap
=
slapos
.
format
.
Tap
(
'tap'
)),
])
])
global
USER_LIST
global
USER_LIST
USER_LIST
=
[
'testuser'
]
USER_LIST
=
[
'testuser'
]
...
@@ -577,7 +579,7 @@ class TestComputer(SlapformatMixin):
...
@@ -577,7 +579,7 @@ class TestComputer(SlapformatMixin):
partition_list
=
[
partition_list
=
[
slapos
.
format
.
Partition
(
slapos
.
format
.
Partition
(
'partition'
,
'/part_path'
,
slapos
.
format
.
User
(
'testuser'
),
[],
'partition'
,
'/part_path'
,
slapos
.
format
.
User
(
'testuser'
),
[],
tap
=
slapos
.
format
.
Tap
(
'tap'
)),
ipv6_range
=
None
,
tap
=
slapos
.
format
.
Tap
(
'tap'
)),
])
])
global
INTERFACE_DICT
global
INTERFACE_DICT
INTERFACE_DICT
[
'myinterface'
]
=
{
INTERFACE_DICT
[
'myinterface'
]
=
{
...
@@ -618,7 +620,7 @@ class TestComputer(SlapformatMixin):
...
@@ -618,7 +620,7 @@ class TestComputer(SlapformatMixin):
partition_list
=
[
partition_list
=
[
slapos
.
format
.
Partition
(
slapos
.
format
.
Partition
(
'partition'
,
'/part_path'
,
slapos
.
format
.
User
(
'testuser'
),
[],
'partition'
,
'/part_path'
,
slapos
.
format
.
User
(
'testuser'
),
[],
tap
=
slapos
.
format
.
Tap
(
'tap'
)),
ipv6_range
=
None
,
tap
=
slapos
.
format
.
Tap
(
'tap'
)),
])
])
global
INTERFACE_DICT
global
INTERFACE_DICT
INTERFACE_DICT
[
'myinterface'
]
=
{
INTERFACE_DICT
[
'myinterface'
]
=
{
...
@@ -636,12 +638,7 @@ class TestComputer(SlapformatMixin):
...
@@ -636,12 +638,7 @@ class TestComputer(SlapformatMixin):
"chmod('/instance_root/partition', 488)"
"chmod('/instance_root/partition', 488)"
],
],
self
.
test_result
.
bucket
)
self
.
test_result
.
bucket
)
self
.
assertEqual
([
self
.
assertEqual
([],
'ip addr add ip/255.255.255.255 dev myinterface'
,
# 'ip addr list myinterface',
'ip addr add ip/ffff:ffff:ffff:ffff:: dev myinterface'
,
'ip -6 addr list myinterface'
,
],
self
.
fakeCallAndRead
.
external_command_list
)
self
.
fakeCallAndRead
.
external_command_list
)
...
@@ -660,7 +657,8 @@ class TestFormatDump(SlapformatMixin):
...
@@ -660,7 +657,8 @@ class TestFormatDump(SlapformatMixin):
logger
=
self
.
logger
,
name
=
'myinterface'
,
ipv4_local_network
=
'127.0.0.1/16'
),
logger
=
self
.
logger
,
name
=
'myinterface'
,
ipv4_local_network
=
'127.0.0.1/16'
),
partition_list
=
[
partition_list
=
[
slapos
.
format
.
Partition
(
slapos
.
format
.
Partition
(
'partition'
,
'part_path'
,
slapos
.
format
.
User
(
'testuser'
),
[],
tap
=
slapos
.
format
.
Tap
(
'tap'
)),
'partition'
,
'part_path'
,
slapos
.
format
.
User
(
'testuser'
),
[],
ipv6_range
=
None
,
tap
=
slapos
.
format
.
Tap
(
'tap'
)),
])
])
global
USER_LIST
global
USER_LIST
USER_LIST
=
[
'testuser'
]
USER_LIST
=
[
'testuser'
]
...
@@ -745,7 +743,8 @@ class TestComputerWithCPUSet(SlapformatMixin):
...
@@ -745,7 +743,8 @@ class TestComputerWithCPUSet(SlapformatMixin):
logger
=
self
.
logger
,
name
=
'lo'
,
ipv4_local_network
=
'127.0.0.1/16'
),
logger
=
self
.
logger
,
name
=
'lo'
,
ipv4_local_network
=
'127.0.0.1/16'
),
partition_list
=
[
partition_list
=
[
slapos
.
format
.
Partition
(
slapos
.
format
.
Partition
(
'partition'
,
'/tmp/slapgrid/instance_root/part1'
,
slapos
.
format
.
User
(
'testuser'
),
[],
tap
=
None
),
'partition'
,
'/tmp/slapgrid/instance_root/part1'
,
slapos
.
format
.
User
(
'testuser'
),
[],
ipv6_range
=
None
,
tap
=
None
),
],
],
config
=
{
config
=
{
"manager_list"
:
"cpuset"
,
"manager_list"
:
"cpuset"
,
...
...
slapos/util.py
View file @
6272d68e
...
@@ -205,6 +205,59 @@ def ipv6FromBin(ip, suffix=''):
...
@@ -205,6 +205,59 @@ def ipv6FromBin(ip, suffix=''):
return
socket
.
inet_ntop
(
socket
.
AF_INET6
,
return
socket
.
inet_ntop
(
socket
.
AF_INET6
,
struct
.
pack
(
'>QQ'
,
int
(
ip
[:
64
],
2
),
int
(
ip
[
64
:],
2
)))
struct
.
pack
(
'>QQ'
,
int
(
ip
[:
64
],
2
),
int
(
ip
[
64
:],
2
)))
def
getPartitionIpv6Addr
(
ipv6_range
,
partition_index
):
"""
from a IPv6 range in the form
{
'addr' : addr,
'prefixlen' : CIDR
}
returns the IPv6 addr
addr::(partition_index+2) (address 1 is is used by re6st)
"""
addr
=
ipv6_range
[
'addr'
]
prefixlen
=
ipv6_range
[
'prefixlen'
]
prefix
=
binFromIpv6
(
addr
)[:
prefixlen
]
return
dict
(
addr
=
ipv6FromBin
(
prefix
+
bin
(
partition_index
+
2
)[
2
:].
zfill
(
128
-
prefixlen
)),
prefixlen
=
prefixlen
)
def
getIpv6RangeFactory
(
k
,
s
):
def
getIpv6Range
(
ipv6_range
,
partition_index
):
"""
from a IPv6 range in the form
{
'addr' : addr,
'prefixlen' : CIDR
}
returns the IPv6 range
{
'addr' : addr:(k*(2^14) + partition_index+1)
'prefixlen' : CIDR+16
}
"""
addr
=
ipv6_range
[
'addr'
]
prefixlen
=
ipv6_range
[
'prefixlen'
]
prefix
=
binFromIpv6
(
addr
)[:
prefixlen
]
# we generate a subnetwork for the partition
# the subnetwork has 16 bits more than our IPv6 range
# make sure we have at least 2 IPs in the subnetwork
prefixlen
+=
16
if
prefixlen
>=
128
:
raise
ValueError
(
'The IPv6 range has prefixlen {} which is too big for generating IPv6 range for partitions.'
.
format
(
prefixlen
))
return
dict
(
addr
=
ipv6FromBin
(
prefix
+
bin
((
k
<<
14
)
+
partition_index
+
1
)[
2
:].
zfill
(
16
)
+
s
*
(
128
-
prefixlen
)),
prefixlen
=
prefixlen
)
return
getIpv6Range
getPartitionIpv6Range
=
getIpv6RangeFactory
(
1
,
'0'
)
getTapIpv6Range
=
getIpv6RangeFactory
(
2
,
'1'
)
getTunIpv6Range
=
getIpv6RangeFactory
(
3
,
'0'
)
def
getIpv6RangeFirstAddr
(
addr
,
prefixlen
):
addr_1
=
"%s1"
%
ipv6FromBin
(
binFromIpv6
(
addr
)[:
prefixlen
])
return
ipv6FromBin
(
binFromIpv6
(
addr_1
))
# correctly format the IPv6
def
lenNetmaskIpv6
(
netmask
):
def
lenNetmaskIpv6
(
netmask
):
"""Convert string represented netmask to its integer prefix"""
"""Convert string represented netmask to its integer prefix"""
# Since version 0.10.7 of netifaces, the netmask is something like "ffff::/16",
# Since version 0.10.7 of netifaces, the netmask is something like "ffff::/16",
...
@@ -215,6 +268,10 @@ def lenNetmaskIpv6(netmask):
...
@@ -215,6 +268,10 @@ def lenNetmaskIpv6(netmask):
except
ValueError
:
except
ValueError
:
return
netaddr
.
IPNetwork
(
netmask
).
prefixlen
return
netaddr
.
IPNetwork
(
netmask
).
prefixlen
def
netmaskFromLenIPv6
(
netmask_len
):
""" opposite of lenNetmaskIpv6"""
return
ipv6FromBin
(
'1'
*
netmask_len
)
# Used for Python 2-3 compatibility
# Used for Python 2-3 compatibility
if
str
is
bytes
:
if
str
is
bytes
:
bytes2str
=
str2bytes
=
lambda
s
:
s
bytes2str
=
str2bytes
=
lambda
s
:
s
...
...
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