Add index generation for IPv6 rules for DVR

For IPv6 support with DVR the index used for rule priority and
route table needs to be generated such that the index is 32 bits
or less but greater than the system generated rule entries.

For IPv4 the numeric value of the network is used as the index.
For IPv6 the 30 bit xor-folded crc32 of the cidr is used.
Values smaller than system generated entries are extended into
the range freed up because of xor-folding.
For code modularity, index generation is wrapped into a helper
method.

Partial-bug: #1376325

Change-Id: I4bcde80257ef5fe7c744086019841cdef5e3c60c
This commit is contained in:
rajeev 2014-11-12 11:25:55 -05:00
parent fcf0322c2a
commit 7eb23f662c
2 changed files with 48 additions and 2 deletions

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import binascii
import netaddr
import os
@ -36,6 +37,8 @@ FIP_PR_START = 32768
FIP_PR_END = FIP_PR_START + 40000
# Route Table index for FIPs
FIP_RT_TBL = 16
# xor-folding mask used for IPv6 rule index
MASK_30 = 0x3fffffff
class RouterMixin(object):
@ -163,6 +166,27 @@ class AgentMixin(object):
router['id'])
return host
def _get_snat_idx(self, ip_cidr):
"""Generate index for DVR snat rules and route tables.
The index value has to be 32 bits or less but more than the system
generated entries i.e. 32768. For IPv4 use the numeric value of the
cidr. For IPv6 generate a crc32 bit hash and xor-fold to 30 bits.
Use the freed range to extend smaller values so that they become
greater than system generated entries.
"""
net = netaddr.IPNetwork(ip_cidr)
if net.version == 6:
# the crc32 & 0xffffffff is for Python 2.6 and 3.0 compatibility
snat_idx = binascii.crc32(ip_cidr) & 0xffffffff
# xor-fold the hash to reserve upper range to extend smaller values
snat_idx = (snat_idx >> 30) ^ (snat_idx & MASK_30)
if snat_idx < 32768:
snat_idx = snat_idx + MASK_30
else:
snat_idx = net.value
return snat_idx
def _map_internal_interfaces(self, ri, int_port, snat_ports):
"""Return the SNAT port for the given internal interface port."""
fixed_ip = int_port['fixed_ips'][0]
@ -378,7 +402,7 @@ class AgentMixin(object):
def _snat_redirect_add(self, ri, gateway, sn_port, sn_int):
"""Adds rules and routes for SNAT redirection."""
try:
snat_idx = netaddr.IPNetwork(sn_port['ip_cidr']).value
snat_idx = self._get_snat_idx(sn_port['ip_cidr'])
ns_ipr = ip_lib.IpRule(self.root_helper, namespace=ri.ns_name)
ns_ipd = ip_lib.IPDevice(sn_int, self.root_helper,
namespace=ri.ns_name)
@ -392,7 +416,7 @@ class AgentMixin(object):
def _snat_redirect_remove(self, ri, sn_port, sn_int):
"""Removes rules and routes for SNAT redirection."""
try:
snat_idx = netaddr.IPNetwork(sn_port['ip_cidr']).value
snat_idx = self._get_snat_idx(sn_port['ip_cidr'])
ns_ipr = ip_lib.IpRule(self.root_helper, namespace=ri.ns_name)
ns_ipd = ip_lib.IPDevice(sn_int, self.root_helper,
namespace=ri.ns_name)

View File

@ -665,6 +665,28 @@ class TestBasicRouterOperations(base.BaseTestCase):
else:
self.assertIn(r.rule, expected_rules)
def test__get_snat_idx_ipv4(self):
ip_cidr = '101.12.13.00/24'
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
snat_idx = agent._get_snat_idx(ip_cidr)
# 0x650C0D00 is numerical value of 101.12.13.00
self.assertEqual(0x650C0D00, snat_idx)
def test__get_snat_idx_ipv6(self):
ip_cidr = '2620:0:a03:e100::/64'
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
snat_idx = agent._get_snat_idx(ip_cidr)
# 0x3D345705 is 30 bit xor folded crc32 of the ip_cidr
self.assertEqual(0x3D345705, snat_idx)
def test__get_snat_idx_ipv6_below_32768(self):
ip_cidr = 'd488::/30'
# crc32 of this ip_cidr is 0x1BD7
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
snat_idx = agent._get_snat_idx(ip_cidr)
# 0x1BD7 + 0x3FFFFFFF = 0x40001BD6
self.assertEqual(0x40001BD6, snat_idx)
def test__map_internal_interfaces(self):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
router = prepare_router_data(num_internal_ports=4)