VOL-622: Enforce datapath id (DPID) to be set as a mac address of
the OLT when a logical device is creating.
Change-Id: Ief3a8b0277dfb786fcb8d30d5a6ce6113034433f
diff --git a/common/utils/id_generation.py b/common/utils/id_generation.py
index bb2e144..e0fea1c 100644
--- a/common/utils/id_generation.py
+++ b/common/utils/id_generation.py
@@ -36,16 +36,19 @@
"""
Creates a logical device id and an OpenFlow datapath id that is unique
across the Voltha cluster.
- The returned ids represents a 64 bits integer where the lower 48 bits is
- the switch id and the upper 16 bits is the core id.
+ The returned logical device id represents a 64 bits integer where the
+ lower 48 bits is the switch id and the upper 16 bits is the core id. For
+ the datapath id the core id is set to '0000' as it is not used for voltha
+ core routing
:param core_id: string
:param switch_id:int
:return: cluster logical device id and OpenFlow datapath id
"""
switch_id = format(switch_id, '012x')
core_in_hex=format(int(core_id, 16), '04x')
- id = '{}{}'.format(core_in_hex[-4:], switch_id[-12:])
- return id, int(id, 16)
+ ld_id = '{}{}'.format(core_in_hex[-4:], switch_id[-12:])
+ dpid_id = '{}{}'.format('0000', switch_id[-12:])
+ return ld_id, int(dpid_id, 16)
def is_broadcast_core_id(id):
assert id and len(id) == 16
diff --git a/voltha/adapters/simulated_olt/simulated_olt.py b/voltha/adapters/simulated_olt/simulated_olt.py
index 5e3aa97..18da5f3 100644
--- a/voltha/adapters/simulated_olt/simulated_olt.py
+++ b/voltha/adapters/simulated_olt/simulated_olt.py
@@ -539,7 +539,8 @@
),
root_device_id=device.id
)
- ld_initialized = self.adapter_agent.create_logical_device(ld)
+ ld_initialized = self.adapter_agent.create_logical_device(ld, device.mac_address)
+
cap = OFPPF_1GB_FD | OFPPF_FIBER
self.adapter_agent.add_logical_port(ld_initialized.id, LogicalPort(
id='nni',
diff --git a/voltha/core/adapter_agent.py b/voltha/core/adapter_agent.py
index 21dddec..1c3db69 100644
--- a/voltha/core/adapter_agent.py
+++ b/voltha/core/adapter_agent.py
@@ -47,6 +47,12 @@
def __init__(self, error):
self.error = error
+
+class IDError(BaseException):
+ def __init__(self, error):
+ self.error = error
+
+
@implementer(IAdapterAgent)
class AdapterAgent(object):
"""
@@ -289,7 +295,8 @@
devices = self.root_proxy.get('/devices')
# Get all child devices with the same parent ID
- children_ids = set(d.id for d in devices if d.parent_id == parent_device_id)
+ children_ids = set(
+ d.id for d in devices if d.parent_id == parent_device_id)
# Loop through all the child devices with this parent ID
for child_id in children_ids:
@@ -367,8 +374,8 @@
self.log.info('delete-image-download', img_dnld=img_dnld)
try:
root_proxy = self.core.get_proxy('/')
- path = '/devices/{}/image_downloads/{}'.\
- format(img_dnld.id, img_dnld.name)
+ path = '/devices/{}/image_downloads/{}'. \
+ format(img_dnld.id, img_dnld.name)
root_proxy.get(path)
root_proxy.remove(path)
device_agent = self.core.get_device_agent(img_dnld.id)
@@ -502,37 +509,6 @@
self._make_up_to_date('/devices/{}/ports'.format(device_id),
port.port_no, port)
- def _find_first_available_id(self, dpid=None):
-
- def _is_valid_mac_address(dpid):
- return re.match("[0-9a-f]{2}([-:])[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$",
- dpid)
-
- # If a dpid is provided then validate whether it is a MAC address
- switch_id = 1
- if dpid:
- dpid = dpid.lower()
- if not _is_valid_mac_address(dpid):
- raise MacAddressError('Invalid-mac-address-format')
- switch_id = int(dpid.replace(':', ''), 16)
-
- logical_devices = self.root_proxy.get('/logical_devices')
- existing_ids = set(ld.id for ld in logical_devices)
- existing_datapath_ids = set(ld.datapath_id for ld in logical_devices)
- core_id = registry('core').core_store_id
-
- while True:
- ld_id, dp_id = create_cluster_logical_device_ids(core_id, switch_id)
- id_exists = dp_id in existing_datapath_ids or ld_id in \
- existing_ids
- if not id_exists:
- return ld_id, dp_id
- else:
- if dpid:
- raise MacAddressError('Already-registered-mac-address')
- else:
- switch_id += 1
-
def get_logical_device(self, logical_device_id):
return self.root_proxy.get('/logical_devices/{}'.format(
logical_device_id))
@@ -541,18 +517,58 @@
return self.root_proxy.get('/logical_devices/{}/ports/{}'.format(
logical_device_id, port_id))
+ def _create_cluster_ids_from_dpid(self, dpid):
+ """
+ Create a logical device id using a datapath id.
+ :param dpid: Must be present and formatted as a mac address
+ :return: a unique logical device id and a formatted datapath id. If
+ the dpid was already registered then an exception will be raised.
+ """
+ switch_id = int(dpid.replace(':', ''), 16)
+ logical_devices = self.root_proxy.get('/logical_devices')
+ existing_ids = set(ld.id for ld in logical_devices)
+ existing_datapath_ids = set(ld.datapath_id for ld in logical_devices)
+ core_id = registry('core').core_store_id
+
+ ld_id, dp_id = create_cluster_logical_device_ids(core_id, switch_id)
+ ids_exist = dp_id in existing_datapath_ids or \
+ ld_id in existing_ids
+ if not ids_exist:
+ return ld_id, dp_id
+ else:
+ self.log.error('ID-already-registered', logical_id=ld_id,
+ dpid=dpid)
+ raise IDError('ID-already-registered')
+
+ def _is_valid_mac_address(self, data):
+ return re.match("[0-9a-f]{2}([-:])[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$",
+ data)
+
def create_logical_device(self, logical_device, dpid=None):
"""
Allow the adapters to provide their own datapath id. This must
- be the OLT MAC address.
- :param logical_device:
- :param dpid: OLT MAC address
+ be the OLT MAC address. If the dpid is None or is not a mac
+ address then an exception will be raised.
+ :param logical_device: logical device
+ :param dpid: OLT MAC address. dpid default param is None just to be
+ backward compatible with existing adapters.
:return: updated logical device
"""
assert isinstance(logical_device, LogicalDevice)
+ # Validate the dpid - it needs to be present and formatted as a mac
+ # address
+ if dpid:
+ dpid = dpid.lower()
+ if not self._is_valid_mac_address(dpid):
+ self.log.error('DPID-not-a-mac-address', dpid=dpid)
+ raise MacAddressError('DPID-not-a-mac-address')
+ else:
+ self.log.error('DPID-cannot-be-none')
+ raise MacAddressError("DPID-cannot-be-none")
+
if not logical_device.id:
- ld_id, dp_id = self._find_first_available_id(dpid)
+ ld_id, dp_id = self._create_cluster_ids_from_dpid(dpid)
logical_device.id = ld_id
logical_device.datapath_id = dp_id
@@ -582,7 +598,6 @@
callback=lambda _, p: self.receive_packet_out(logical_device_id, p)
)
-
def delete_logical_device(self, logical_device):
"""
This will remove the logical device as well as all logical ports
@@ -658,9 +673,8 @@
device_agent = self.core.get_device_agent(child.id)
device_agent.reconcile_existing_device(child)
-
- #Obselete API - discouraged to be decommissioned after
- #adapters are align to new APIs
+ # Obselete API - discouraged to be decommissioned after
+ # adapters are align to new APIs
def child_device_detected(self,
parent_device_id,
parent_port_no,
@@ -715,7 +729,6 @@
self._tx_event_subscriptions[topic] = self.event_bus.subscribe(
topic, lambda t, m: self._send_proxied_message(proxy_address, m))
-
def get_child_device_with_proxy_address(self, proxy_address):
# Proxy address is defined as {parent id, channel_id}
devices = self.root_proxy.get('/devices')
@@ -756,7 +769,8 @@
admin_state=None):
""" Update status of all child devices """
devices = self.root_proxy.get('/devices')
- children_ids = set(d.id for d in devices if d.parent_id == parent_device_id)
+ children_ids = set(
+ d.id for d in devices if d.parent_id == parent_device_id)
self.log.debug('update-devices',
parent_id=parent_device_id,
children_ids=children_ids,
@@ -780,9 +794,10 @@
if onu_device is not None:
if onu_device.parent_id == parent_device_id:
self.log.debug('deleting-child-device',
- parent_device_id=parent_device_id,
- child_device_id=child_device_id)
- topic = self._gen_tx_proxy_address_topic(onu_device.proxy_address)
+ parent_device_id=parent_device_id,
+ child_device_id=child_device_id)
+ topic = self._gen_tx_proxy_address_topic(
+ onu_device.proxy_address)
self.event_bus.unsubscribe(self._tx_event_subscriptions[topic])
del self._tx_event_subscriptions[topic]
self._remove_node('/devices', child_device_id)
@@ -824,7 +839,9 @@
def register_for_inter_adapter_messages(self):
self.event_bus.subscribe(self.adapter_name,
- lambda t, m: self.adapter.receive_inter_adapter_message(m))
+ lambda t,
+ m: self.adapter.receive_inter_adapter_message(
+ m))
def unregister_for_inter_adapter_messages(self):
self.event_bus.unsubscribe(self.adapter_name)
@@ -894,8 +911,10 @@
rule_values = {
'id': alarm_event.id,
'type': AlarmEventType.AlarmEventType.Name(alarm_event.type),
- 'category': AlarmEventCategory.AlarmEventCategory.Name(alarm_event.category),
- 'severity': AlarmEventSeverity.AlarmEventSeverity.Name(alarm_event.severity),
+ 'category': AlarmEventCategory.AlarmEventCategory.Name(
+ alarm_event.category),
+ 'severity': AlarmEventSeverity.AlarmEventSeverity.Name(
+ alarm_event.severity),
'resource_id': alarm_event.resource_id,
'device_id': device_id
}
@@ -905,12 +924,16 @@
exclude = True
for rule in alarm_filter.rules:
self.log.debug("compare-alarm-event",
- key=AlarmFilterRuleKey.AlarmFilterRuleKey.Name(rule.key),
- actual=rule_values[AlarmFilterRuleKey.AlarmFilterRuleKey.Name(rule.key)].lower(),
+ key=AlarmFilterRuleKey.AlarmFilterRuleKey.Name(
+ rule.key),
+ actual=rule_values[
+ AlarmFilterRuleKey.AlarmFilterRuleKey.Name(
+ rule.key)].lower(),
expected=rule.value.lower())
exclude = exclude and \
- (rule_values[AlarmFilterRuleKey.AlarmFilterRuleKey.Name(
- rule.key)].lower() == rule.value.lower())
+ (rule_values[
+ AlarmFilterRuleKey.AlarmFilterRuleKey.Name(
+ rule.key)].lower() == rule.value.lower())
if not exclude:
break