Skip to content

Commit

Permalink
AE Interface for LAG should be sequential
Browse files Browse the repository at this point in the history
AE interface naming is very restrictive and must
be between ae<min-num> to ae<max-num>.
Consideration need to be given to the fact that
same name does not get repeated for a given TOR

Change-Id: Id5e5b8089a0651389dbfc06e8b05ce5bcfb8e1a5
Closes-Bug: #1778825
(cherry picked from commit dc880cb)
  • Loading branch information
sukhdevkapur authored and sathishholla committed Sep 26, 2018
1 parent 586ecf4 commit 0d8b561
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 14 deletions.
55 changes: 41 additions & 14 deletions src/config/api-server/vnc_cfg_api_server/vnc_cfg_types.py
Expand Up @@ -2181,6 +2181,12 @@ def post_dbe_create(cls, tenant_name, obj_dict, db_conn):
bindings = obj_dict.get('virtual_machine_interface_bindings', {})
kvps = bindings.get('key_value_pair', [])

bare_metal_vlan_id = 0
if ('virtual_machine_interface_properties' in obj_dict
and 'sub_interface_vlan_tag' in obj_dict['virtual_machine_interface_properties']):
vmi_properties = obj_dict['virtual_machine_interface_properties']
bare_metal_vlan_id = vmi_properties['sub_interface_vlan_tag']

# Manage baremetal provisioning here
if kvps:
kvp_dict = cls._kvp_to_dict(kvps)
Expand All @@ -2191,15 +2197,16 @@ def post_dbe_create(cls, tenant_name, obj_dict, db_conn):
if phy_links and phy_links.get('local_link_information'):
links = phy_links['local_link_information']
if len(links) > 1:
cls._manage_lag_interface(obj_dict['uuid'], api_server, db_conn, links)
cls._manage_lag_interface(obj_dict['uuid'], api_server, db_conn,
links, bare_metal_vlan_id)
else:
cls._create_logical_interface(obj_dict['uuid'], api_server, db_conn,
links[0]['switch_info'], links[0]['port_id'])
links[0]['switch_info'], links[0]['port_id'], bare_metal_vlan_id)

# Create ref to native/vn-default routing instance
vn_refs = obj_dict.get('virtual_network_refs')
if not vn_refs:
return True, ''
return True, ''

vn_fq_name = vn_refs[0].get('to')
if not vn_fq_name:
Expand Down Expand Up @@ -2352,9 +2359,13 @@ def pre_dbe_update(cls, id, fq_name, obj_dict, db_conn,

@classmethod
def _create_lag_interface(cls, api_server, db_conn, prouter_name, phy_interfaces):
if_num = ''.join([i for i in phy_interfaces[0][2:] if i.isdigit()])
if_num = str(int(if_num) % 64)
lag_interface_name = "ae" + if_num
phy_if_fq_name=['default-global-system-config', prouter_name, phy_interfaces[0]]
ae_id = cls.vnc_zk_client.alloc_ae_id(':'.join(phy_if_fq_name))
def undo_ae_id():
cls.vnc_zk_client.free_ae_id(':'.join(phy_if_fq_name))
return True, ""
get_context().push_undo(undo_ae_id)
lag_interface_name = "ae" + str(ae_id)

# create lag object
lag_obj = LinkAggregationGroup(parent_type='physical-router',
Expand Down Expand Up @@ -2393,7 +2404,7 @@ def _create_lag_interface(cls, api_server, db_conn, prouter_name, phy_interfaces
# end _create_lag_interface

@classmethod
def _manage_lag_interface(cls, vmi_id, api_server, db_conn, phy_links):
def _manage_lag_interface(cls, vmi_id, api_server, db_conn, phy_links, bare_metal_vlan_id):
tors = {}
esi = None
for link in phy_links:
Expand All @@ -2418,11 +2429,11 @@ def _manage_lag_interface(cls, vmi_id, api_server, db_conn, phy_links):
mac = result['virtual_machine_interface_mac_addresses']['mac_address']
esi = "00:00:00:00:" + mac[0]
cls._create_logical_interface(vmi_id, api_server, db_conn, tor_name,
vmi_connected_phy_interface, esi=esi)
vmi_connected_phy_interface, bare_metal_vlan_id, esi=esi)

@classmethod
def _create_logical_interface(cls, vim_id, api_server, db_conn, tor, link, esi=None):
vlan_tag = 0
def _create_logical_interface(cls, vim_id, api_server, db_conn, tor, link, bare_metal_vlan_id, esi=None):
vlan_tag = bare_metal_vlan_id
li_fq_name = ['default-global-system-config', tor, link]
li_fq_name = li_fq_name + ['%s.%s' %(link, vlan_tag)]

Expand Down Expand Up @@ -2456,6 +2467,12 @@ def post_dbe_update(cls, id, fq_name, obj_dict, db_conn,
bindings = obj_dict.get('virtual_machine_interface_bindings', {})
kvps = bindings.get('key_value_pair', [])

bare_metal_vlan_id = 0
if ('virtual_machine_interface_properties' in obj_dict
and 'sub_interface_vlan_tag' in obj_dict['virtual_machine_interface_properties']):
vmi_properties = obj_dict['virtual_machine_interface_properties']
bare_metal_vlan_id = vmi_properties['sub_interface_vlan_tag']

for oper_param in prop_collection_updates or []:
if (oper_param['field'] == 'virtual_machine_interface_bindings' and
oper_param['operation'] == 'set'):
Expand All @@ -2470,10 +2487,10 @@ def post_dbe_update(cls, id, fq_name, obj_dict, db_conn,
if phy_links and phy_links.get('local_link_information'):
links = phy_links['local_link_information']
if len(links) > 1:
cls._manage_lag_interface(id, api_server, db_conn, links)
cls._manage_lag_interface(id, api_server, db_conn, links, bare_metal_vlan_id)
else:
cls._create_logical_interface(id, api_server, db_conn,
links[0]['switch_info'], links[0]['port_id'], esi=None)
links[0]['switch_info'], links[0]['port_id'], bare_metal_vlan_id, esi=None)

return True, ''
# end post_dbe_update
Expand All @@ -2496,6 +2513,14 @@ def pre_dbe_delete(cls, id, obj_dict, db_conn):
delete_dict = {'virtual_machine_refs' : []}
cls._check_vrouter_link(obj_dict, kvp_dict, delete_dict, db_conn)

return True, ""
# end pre_dbe_delete

@classmethod
def post_dbe_delete(cls, id, obj_dict, db_conn):

api_server = db_conn.get_api_server()

# For baremetal, delete the logical interface and related objects
for lri_back_ref in obj_dict.get('logical_interface_back_refs') or []:
fqname = lri_back_ref['to'][:-1]
Expand All @@ -2510,6 +2535,9 @@ def pre_dbe_delete(cls, id, obj_dict, db_conn):
api_server.internal_request_delete('logical_interface', lri_back_ref['uuid'])
api_server.internal_request_delete('link_aggregation_group', lag_interface_uuid)
api_server.internal_request_delete('physical_interface', phy_interface_uuid)
id = int(fqname[2][2:])
ae_fqname = cls.vnc_zk_client.get_ae_from_id(id)
cls.vnc_zk_client.free_ae_id(id, ae_fqname)
else:
# Before deleting the logical interface, check if the parent physical interface
# has ESI set. If yes, clear it.
Expand All @@ -2524,8 +2552,7 @@ def pre_dbe_delete(cls, id, obj_dict, db_conn):


return True, ""
# end pre_dbe_delete

# end post_dbe_delete
# end class VirtualMachineInterfaceServer

class ServiceApplianceSetServer(Resource, ServiceApplianceSet):
Expand Down
40 changes: 40 additions & 0 deletions src/config/api-server/vnc_cfg_api_server/vnc_db.py
Expand Up @@ -413,6 +413,10 @@ class VncZkClient(object):
_VN_ID_ALLOC_PATH = "/id/virtual-networks/"
_VN_MAX_ID = 1 << 24

_AE_ID_ALLOC_PATH = "/id/aggregated-ethernet/"
_AE_MIN_ID = 0
_AE_MAX_ID = 64

_SG_ID_ALLOC_PATH = "/id/security-groups/id/"
_SG_MAX_ID = 1 << 32

Expand All @@ -437,6 +441,7 @@ def __init__(self, instance_id, zk_server_ip, reset_config, db_prefix,
self._subnet_path = zk_path_pfx + self._SUBNET_PATH
self._fq_name_to_uuid_path = zk_path_pfx + self._FQ_NAME_TO_UUID_PATH
_vn_id_alloc_path = zk_path_pfx + self._VN_ID_ALLOC_PATH
_ae_id_alloc_path = zk_path_pfx + self._AE_ID_ALLOC_PATH
_sg_id_alloc_path = zk_path_pfx + self._SG_ID_ALLOC_PATH
_tag_type_id_alloc_path = zk_path_pfx + self._TAG_TYPE_ID_ALLOC_PATH
self._tag_value_id_alloc_path = zk_path_pfx + self._TAG_VALUE_ID_ALLOC_PATH
Expand All @@ -459,12 +464,18 @@ def __init__(self, instance_id, zk_server_ip, reset_config, db_prefix,
self._zk_client.delete_node(self._subnet_path, True)
self._zk_client.delete_node(self._fq_name_to_uuid_path, True)
self._zk_client.delete_node(_vn_id_alloc_path, True)
self._zk_client.delete_node(_ae_id_alloc_path, True)
self._zk_client.delete_node(_sg_id_alloc_path, True)
self._zk_client.delete_node(
zk_path_pfx + self._TAG_ID_ALLOC_ROOT_PATH, True)

self._subnet_allocators = {}

# Initialize the Aggregated Ethernet allocator
self._ae_id_allocator = IndexAllocator(self._zk_client,
_ae_id_alloc_path,
self._AE_MAX_ID)

# Initialize the virtual network ID allocator
self._vn_id_allocator = IndexAllocator(self._zk_client,
_vn_id_alloc_path,
Expand Down Expand Up @@ -697,6 +708,35 @@ def get_vn_from_id(self, id):
if id is not None and id - VNID_MIN_ALLOC < self._VN_MAX_ID:
return self._vn_id_allocator.read(id - VNID_MIN_ALLOC)

def alloc_ae_id(self, fq_name_str, id=None):
# If ID provided, it's a notify allocation, just lock allocated ID in
# memory
if id is not None:
if self.get_ae_from_id(id) is not None:
self._ae_id_allocator.set_in_use(id - self._AE_MIN_ID)
return id
elif fq_name_str is not None:
return self._ae_id_allocator.alloc(fq_name_str) + self._AE_MIN_ID

def free_ae_id(self, id, fq_name_str, notify=False):
if id is not None and id - self._AE_MIN_ID < self._AE_MAX_ID:
# If fq_name associated to the allocated ID does not correpond to
# freed resource fq_name, keep zookeeper lock
allocated_fq_name_str = self.get_ae_from_id(id)
if (allocated_fq_name_str is not None and
allocated_fq_name_str != fq_name_str):
return
if notify:
# If notify, the ZK allocation already removed, just remove
# lock in memory
self._ae_id_allocator.reset_in_use(id - self._AE_MIN_ID)
else:
self._ae_id_allocator.delete(id - self._AE_MIN_ID)

def get_ae_from_id(self, id):
if id is not None and id - self._AE_MIN_ID < self._AE_MAX_ID:
return self._ae_id_allocator.read(id - self._AE_MIN_ID)

def alloc_sg_id(self, fq_name_str, id=None):
# If ID provided, it's a notify allocation, just lock allocated ID in
# memory
Expand Down
23 changes: 23 additions & 0 deletions src/config/vnc_openstack/vnc_openstack/tests/test_basic.py
Expand Up @@ -508,6 +508,7 @@ def test_baremetal_logical_interface_bindings_with_lag(self):
This test verifies the binidng and unbinding of these objects
takes place correctly.
"""
mock_zk = self._api_server._db_conn._zk_db
vn_obj = vnc_api.VirtualNetwork(self.id())
vn_obj.add_network_ipam(vnc_api.NetworkIpam(),
vnc_api.VnSubnetsType(
Expand Down Expand Up @@ -598,6 +599,16 @@ def test_baremetal_logical_interface_bindings_with_lag(self):

self.assertTrue(bound_logical_interface_found)

# Now verify that a zk id is reserved for LAG interface.
# First, get the interface name of first physical interface as that's
# what will be used to reserve a id in zookeeper.
zk_pi_obj = self._vnc_lib.physical_interface_read(id=pi_uuid[0])

# Compare the fq_name stored in Zookeeper with first physical interface of the LAG
# Since we are creating only one LAG, the zookeeper id will be 0.
self.assertEqual(mock_zk.get_ae_from_id(0),
zk_pi_obj.get_fq_name_str())

# Now verify the delete funtion to ensure that the resources
# created to facilitate LAG interface are deleted with the
# deleetion of portDed and/or bound.
Expand Down Expand Up @@ -628,6 +639,11 @@ def test_baremetal_logical_interface_bindings_with_lag(self):
if len(lis) > 0:
self.assertFalse(True)

# Verify that zookeeper entry was deleted.
# Compare the fq_name stored in Zookeeper with first physical interface of the LAG
self.assertNotEqual(mock_zk.get_ae_from_id(0),
zk_pi_obj.get_fq_name_str())

# Clen up the resources
for i in range(num_phy_interfaces):
self._vnc_lib.physical_interface_delete(id=pi_uuid[i])
Expand Down Expand Up @@ -836,6 +852,7 @@ def _test_multiple_bonds(tors=None, bonds=None):
Additionally, it verifies that they are cleaned it up when the
Baremetal server is decommisioned.
"""
mock_zk = self._api_server._db_conn._zk_db
vn_obj = vnc_api.VirtualNetwork(self.id())
vn_obj.add_network_ipam(vnc_api.NetworkIpam(),
vnc_api.VnSubnetsType(
Expand Down Expand Up @@ -882,6 +899,7 @@ def _test_multiple_bonds(tors=None, bonds=None):
proj_uuid = self._vnc_lib.fq_name_to_id('project',
fq_name=['default-domain', 'default-project'])

zk_index = 0
for bond, bond_info in bonds.iteritems():
context = {'operation': 'CREATE',
'user_id': '',
Expand Down Expand Up @@ -913,6 +931,11 @@ def _test_multiple_bonds(tors=None, bonds=None):
lag_obj = self._vnc_lib.link_aggregation_group_read(id=l['uuid'])
if lag_obj.parent_uuid == tors[bond_info['tors'][t]['name']]['pr_uuid']:
lag_found = True
zk_element_fq_name = ['default-global-system-config', switch_name, switch_interfaces[0]]
zk_element_fq_name_str = ':'.join(zk_element_fq_name)
self.assertEqual(mock_zk.get_ae_from_id(zk_index),
zk_element_fq_name_str)
zk_index += 1
break
self.assertTrue(lag_found)

Expand Down

0 comments on commit 0d8b561

Please sign in to comment.