Add support for generating 16-bit ASn

Change-Id: I8b1508361fdc7541c0fc231e7e816651626596b7
This commit is contained in:
Frode Nordahl 2018-05-21 06:27:23 +02:00
parent a9ac7dc88b
commit a34640e10e
No known key found for this signature in database
GPG Key ID: 6A5D59A3BA48373F
2 changed files with 116 additions and 2 deletions

View File

@ -54,7 +54,40 @@ class BGPEndpoint(reactive.Endpoint):
return asn
def publish_info(self, asn=None, passive=False, bindings=None):
def generate_asn_16(self):
"""
Generate unique 16-bit Private Use [RFC6996] ASn.
This is useful to automate configuration of BGP routers that is part
of a Clos Network Topology with a Layer 3-Only routed design. [RFC7938]
Assumption:
- Unit has a IPv4 address and it is unique to the deployment.
Implementation:
- A private 16-bit ASn has a range of 64512 - 65534
which leaves us with 1022 possible endpoints.
- The 16-bit ASn space is limited and this implementation
will give you unique ASns for a /23
Note:
- This implementation generates ASn in the following range:
65023 - 65534
- Leaving the following range for any static configuration needs:
64512 - 65022
"""
asn_base = 65023
mask = netaddr.IPAddress('0.0.1.255')
unit_ip = netaddr.IPAddress(
ch_core.hookenv.unit_get('private-address'))
masked_ip = unit_ip & mask
asn = asn_base + int(masked_ip)
return asn
def publish_info(self, asn=None, passive=False, bindings=None,
use_16bit_asn=False):
"""
Publish the AS Number and IP address of any extra-bindings of this
BGP Endpoint over the relationship.
@ -70,7 +103,10 @@ class BGPEndpoint(reactive.Endpoint):
if asn:
myasn = asn
else:
myasn = self.generate_asn()
if use_16bit_asn:
myasn = self.generate_asn_16()
else:
myasn = self.generate_asn()
# network_get will return addresses for bindings regardless of them
# being bound to a network space. detect actual space bindings by

View File

@ -33,6 +33,40 @@ class TestBGPProvides(ut_utils.BaseTestCase):
asn = endpoint.generate_asn()
self.assertEqual(asn, 4294967294)
def test_generate_asn_16_min(self):
self.patch_object(provides, 'ch_core')
self.ch_core.hookenv.unit_get.return_value = '0.0.0.0'
endpoint = provides.BGPEndpoint('bgpserver')
asn = endpoint.generate_asn_16()
self.assertEqual(asn, 65023)
def test_generate_asn_16_collission(self):
self.patch_object(provides, 'ch_core')
self.ch_core.hookenv.unit_get.return_value = '0.0.0.0'
endpoint = provides.BGPEndpoint('bgpserver')
self.ch_core.hookenv.unit_get.return_value = '10.0.0.0'
asn0 = endpoint.generate_asn_16()
self.ch_core.hookenv.unit_get.return_value = '10.0.0.255'
asn0_255 = endpoint.generate_asn_16()
self.ch_core.hookenv.unit_get.return_value = '10.0.1.0'
asn1 = endpoint.generate_asn_16()
self.ch_core.hookenv.unit_get.return_value = '10.0.1.255'
asn1_255 = endpoint.generate_asn_16()
self.ch_core.hookenv.unit_get.return_value = '10.0.2.0'
asn2 = endpoint.generate_asn_16()
self.assertNotEqual(asn0, asn0_255)
self.assertNotEqual(asn0, asn1)
self.assertNotEqual(asn0_255, asn1_255)
self.assertNotEqual(asn1, asn1_255)
self.assertEqual(asn0, asn2)
def test_generate_asn_16_max(self):
self.patch_object(provides, 'ch_core')
self.ch_core.hookenv.unit_get.return_value = '255.255.255.255'
endpoint = provides.BGPEndpoint('bgpserver')
asn = endpoint.generate_asn_16()
self.assertEqual(asn, 65534)
_network_get_side_effect = [
yaml.load('''
bind-addresses:
@ -154,6 +188,50 @@ ingress-addresses:
}
)
def test_publish_info_16bit_asn(self):
self.maxDiff = None
self.patch_object(provides, 'ch_core')
self.ch_core.hookenv.unit_get.return_value = '172.16.122.251'
self.ch_core.hookenv.network_get.side_effect = \
self._network_get_side_effect
endpoint = provides.BGPEndpoint('bgpserver')
endpoint._relations = [self._relation]
endpoint.publish_info(bindings=['ptp0', 'ptp1', 'ptp2', 'ptp3',
'lan0'], use_16bit_asn=True)
self.assertEqual(
endpoint.relations[0].to_publish,
{
'asn': 65274,
'bindings': [
{
'address': '172.16.100.1',
'cidr': '172.16.100.0/30'
},
{
'address': '2001:db8:100::1:0:0',
'cidr': '2001:db8:100::/64'
},
{
'address': '172.16.110.1',
'cidr': '172.16.110.0/30'
},
{
'address': '2001:db8:110::1:0:0',
'cidr': '2001:db8:110::/64'
},
{
'address': '172.16.120.1',
'cidr': '172.16.120.0/30'
},
{
'address': '2001:db8:120::1:0:0',
'cidr': '2001:db8:120::/64'
},
],
'passive': False,
}
)
def test_get_received_info(self):
self.maxDiff = None
self.patch_object(provides, 'ch_core')