VOL-1267 Support for VEIP UNI Type
Supports both PPTP and VEIP UNI types. Tested with ALPHA all-in-one onu/rg.
Testing likely requires configuration on the ONU/RG device to create the veip "wan" port.
I have screenshots of the steps needed.
Existing PPTP onu still work as-is.
Change-Id: Icbb05dd3da4dd0d3ccb63b5a8a9bed7afb57d29e
diff --git a/voltha/adapters/brcm_openomci_onu/brcm_openomci_onu_handler.py b/voltha/adapters/brcm_openomci_onu/brcm_openomci_onu_handler.py
index fa15830..4254bf9 100644
--- a/voltha/adapters/brcm_openomci_onu/brcm_openomci_onu_handler.py
+++ b/voltha/adapters/brcm_openomci_onu/brcm_openomci_onu_handler.py
@@ -49,24 +49,13 @@
OP = EntityOperations
RC = ReasonCodes
-
_ = third_party
log = structlog.get_logger()
-
-BRDCM_DEFAULT_VLAN = 4091
-ADMIN_STATE_LOCK = 1
-ADMIN_STATE_UNLOCK = 0
-RESERVED_VLAN_ID = 4095
_STARTUP_RETRY_WAIT = 20
_MAXIMUM_PORT = 128 # UNI ports
-
-_ = third_party
-
-
-
class BrcmOpenomciOnuHandler(object):
def __init__(self, adapter, device_id):
@@ -757,39 +746,59 @@
# the first time we received a successful (no timeout) OMCI Rx response.
try:
- ani_g = config.ani_g_entities
- uni_g = config.uni_g_entities
- pptp = config.pptp_entities
+ # sort the lists so we get consistent port ordering.
+ ani_list = sorted(config.ani_g_entities) if config.ani_g_entities else []
+ uni_list = sorted(config.uni_g_entities) if config.uni_g_entities else []
+ pptp_list = sorted(config.pptp_entities) if config.pptp_entities else []
+ veip_list = sorted(config.veip_entities) if config.veip_entities else []
- # TODO: there are onu out there that have uni ports available but no pptp. These all-in-one devices
- # likely need virtual ethernet interface point ME #329 configured rather than pptp.
- if ani_g is None or uni_g is None or pptp is None:
+ if ani_list is None or uni_list is None:
device.reason = 'onu-missing-required-elements'
+ self.log.warn("no-ani-or-unis")
self.adapter_agent.update_device(device)
raise Exception("onu-missing-required-elements")
- # Currently logging the ani and uni for information purposes. Actually act on the pptp as its ME ID
- # is the most correct one to use in later tasks.
- for key, value in ani_g.iteritems():
- self.log.debug("discovered-ani", key=key, value=value)
+ # Currently logging the ani, pptp, veip, and uni for information purposes.
+ # Actually act on the veip/pptp as its ME is the most correct one to use in later tasks.
+ for entity_id in ani_list:
+ ani_value = config.ani_g_entities[entity_id]
+ self.log.debug("discovered-ani", entity_id=entity_id, value=ani_value)
+ # TODO: currently only one OLT PON port/ANI, so this works out. With NGPON there will be 2..?
+ self._total_tcont_count = ani_value.get('total-tcont-count')
+ self.log.debug("set-total-tcont-count", tcont_count=self._total_tcont_count)
- for key, value in uni_g.iteritems():
- self.log.debug("discovered-uni", key=key, value=value)
+ for entity_id in pptp_list:
+ pptp_value = config.pptp_entities[entity_id]
+ self.log.debug("discovered-pptp", entity_id=entity_id, value=pptp_value)
- for key, value in pptp.iteritems():
- self.log.debug("discovered-pptp-uni", key=key, value=value)
- entity_id = key
- self._add_uni_port(entity_id)
+ for entity_id in veip_list:
+ veip_value = config.veip_entities[entity_id]
+ self.log.debug("discovered-veip", key=entity_id, value=veip_value)
- # TODO: only one uni/pptp for now. flow bug in openolt
- break
+ for entity_id in uni_list:
+ uni_value = config.uni_g_entities[entity_id]
+ self.log.debug("discovered-uni", entity_id=entity_id, value=uni_value)
- self._total_tcont_count = ani_g.get('total-tcont-count')
+ # TODO: can only support one UNI per ONU at this time. break out as soon as we have a good UNI
+ if entity_id in pptp_list:
+ self._add_uni_port(entity_id, uni_type=UniType.PPTP)
+ break
+ elif entity_id in veip_list:
+ self._add_uni_port(entity_id, uni_type=UniType.VEIP)
+ break
+ else:
+ self.log.warn("unable-to-find-uni-in-pptp-or-veip", key=entity_id, value=uni_value)
+
self._qos_flexibility = config.qos_configuration_flexibility or 0
self._omcc_version = config.omcc_version or OMCCVersion.Unknown
- self.log.debug("set-total-tcont-count", tcont_count=self._total_tcont_count)
- self._dev_info_loaded = True
+ if self._unis:
+ self._dev_info_loaded = True
+ else:
+ device.reason = 'no-usable-unis'
+ self.adapter_agent.update_device(device)
+ self.log.warn("no-usable-unis")
+ raise Exception("no-usable-unis")
except Exception as e:
self.log.exception('device-info-load', e=e)
@@ -829,7 +838,7 @@
self.log.info('device-info-not-loaded-skipping-mib-download')
- def _add_uni_port(self, entity_id):
+ def _add_uni_port(self, entity_id, uni_type=UniType.PPTP):
self.log.debug('function-entry')
device = self.adapter_agent.get_device(self.device_id)
@@ -837,7 +846,7 @@
parent_adapter_agent = registry('adapter_loader').get_agent(parent_device.adapter)
if parent_adapter_agent is None:
- self.log.error('openolt_adapter_agent-could-not-be-retrieved')
+ self.log.error('parent-adapter-could-not-be-retrieved')
# TODO: This knowledge is locked away in openolt. and it assumes one onu equals one uni...
parent_device = self.adapter_agent.get_device(device.parent_id)
@@ -852,13 +861,14 @@
mac_bridge_port_num = working_port + 1
- self.log.debug('live-port-number-ready', uni_no=uni_no, uni_name=uni_name)
+ self.log.debug('uni-port-inputs', uni_no=uni_no, uni_name=uni_name, uni_type=uni_type,
+ entity_id=entity_id, mac_bridge_port_num=mac_bridge_port_num)
- uni_port = UniPort.create(self, uni_name, uni_no, uni_name, device.vlan, device.vlan)
+ uni_port = UniPort.create(self, uni_name, uni_no, uni_name, uni_type)
uni_port.entity_id = entity_id
uni_port.enabled = True
uni_port.mac_bridge_port_num = mac_bridge_port_num
- uni_port.add_logical_port(uni_port.port_number, subscriber_vlan=device.vlan)
+ uni_port.add_logical_port(uni_port.port_number)
self.log.debug("created-uni-port", uni=uni_port)
diff --git a/voltha/adapters/brcm_openomci_onu/omci/brcm_mib_download_task.py b/voltha/adapters/brcm_openomci_onu/omci/brcm_mib_download_task.py
index b1394b6..ebc7492 100644
--- a/voltha/adapters/brcm_openomci_onu/omci/brcm_mib_download_task.py
+++ b/voltha/adapters/brcm_openomci_onu/omci/brcm_mib_download_task.py
@@ -20,6 +20,7 @@
from voltha.extensions.omci.omci_me import *
from voltha.extensions.omci.tasks.task import Task
from voltha.extensions.omci.omci_defs import *
+from voltha.adapters.brcm_openomci_onu.uni_port import *
OP = EntityOperations
RC = ReasonCodes
@@ -84,8 +85,6 @@
# TODO: only using a single UNI/ethernet port
self._uni_port = self._handler.uni_ports[0]
- self._uni_port_num = self._uni_port.mac_bridge_port_num
- self._ethernet_uni_entity_id = self._uni_port.entity_id
# Port numbers
self._pon_port_num = 3 # TODO why 3. maybe this is the ani port number. look at anis list
@@ -344,16 +343,26 @@
# - Nothing
# References:
# - MAC Bridge Service Profile (the bridge)
- # - PPTP Ethernet UNI
+ # - PPTP Ethernet or VEIP UNI
# TODO: do this for all uni/ports...
# TODO: magic. make a static variable for tp_type
+
+ # default to PPTP
+ tp_type = None
+ if self._uni_port.type is UniType.VEIP:
+ tp_type = 11
+ elif self._uni_port.type is UniType.PPTP:
+ tp_type = 1
+ else:
+ tp_type = 1
+
msg = MacBridgePortConfigurationDataFrame(
- self._ethernet_uni_entity_id, # Entity ID - This is read-only/set-by-create !!!
+ self._uni_port.entity_id, # Entity ID - This is read-only/set-by-create !!!
bridge_id_pointer=self._mac_bridge_service_profile_entity_id, # Bridge Entity ID
- port_num=self._uni_port_num, # Port ID
- tp_type=1, # PPTP Ethernet UNI
- tp_pointer=self._ethernet_uni_entity_id # Ethernet UNI ID
+ port_num=self._uni_port.mac_bridge_port_num, # Port ID
+ tp_type=tp_type, # PPTP Ethernet or VEIP UNI
+ tp_pointer=self._uni_port.entity_id # Ethernet UNI ID
)
frame = msg.create()
self.log.debug('openomci-msg', msg=msg)
@@ -476,14 +485,24 @@
# EntityID relates to the VLAN TCIS
# References:
# - VLAN TCIS from previously created VLAN Tagging filter data
- # - PPTP Ethernet UNI
+ # - PPTP Ethernet or VEIP UNI
#
# TODO: do this for all uni/ports...
# TODO: magic. static variable for assoc_type
+
+ # default to PPTP
+ association_type = None
+ if self._uni_port.type is UniType.VEIP:
+ association_type = 10
+ elif self._uni_port.type is UniType.PPTP:
+ association_type = 2
+ else:
+ association_type = 2
+
attributes = dict(
- association_type=2, # Assoc Type, PPTP Ethernet UNI
- associated_me_pointer=self._ethernet_uni_entity_id, # Assoc ME, PPTP Entity Id
+ association_type=association_type, # Assoc Type, PPTP/VEIP Ethernet UNI
+ associated_me_pointer=self._uni_port.entity_id # Assoc ME, PPTP/VEIP Entity Id
# Specifies the TPIDs in use and that operations in the downstream direction are
# inverse to the operations in the upstream direction
@@ -565,12 +584,21 @@
# - Nothing
try:
state = 1 if force_lock or not uni_port.enabled else 0
- msg = PptpEthernetUniFrame(uni_port.entity_id,
- attributes=dict(administrative_state=state))
- frame = msg.set()
- self.log.debug('openomci-msg', msg=msg)
- results = yield omci_cc.send(frame)
- self.check_status_and_state(results, 'set-pptp-ethernet-uni-lock-restore')
+ msg = None
+ if (uni_port.type is UniType.PPTP):
+ msg = PptpEthernetUniFrame(uni_port.entity_id,
+ attributes=dict(administrative_state=state))
+ elif (uni_port.type is UniType.VEIP):
+ msg = VeipUniFrame(uni_port.entity_id,
+ attributes=dict(administrative_state=state))
+ else:
+ self.log.warn('unknown-uni-type', uni_port=uni_port)
+
+ if msg:
+ frame = msg.set()
+ self.log.debug('openomci-msg', msg=msg)
+ results = yield omci_cc.send(frame)
+ self.check_status_and_state(results, 'set-pptp-ethernet-uni-lock-restore')
except TimeoutError as e:
self.log.warn('rx-timeout', e=e)
diff --git a/voltha/adapters/brcm_openomci_onu/omci/brcm_uni_lock_task.py b/voltha/adapters/brcm_openomci_onu/omci/brcm_uni_lock_task.py
index b998b0e..4eae51b 100644
--- a/voltha/adapters/brcm_openomci_onu/omci/brcm_uni_lock_task.py
+++ b/voltha/adapters/brcm_openomci_onu/omci/brcm_uni_lock_task.py
@@ -18,7 +18,7 @@
from twisted.internet.defer import inlineCallbacks, failure, returnValue
from voltha.extensions.omci.omci_defs import ReasonCodes, EntityOperations
from voltha.extensions.omci.omci_me import OntGFrame
-from voltha.extensions.omci.omci_me import PptpEthernetUniFrame
+from voltha.extensions.omci.omci_me import PptpEthernetUniFrame, VeipUniFrame
RC = ReasonCodes
OP = EntityOperations
@@ -72,6 +72,7 @@
super(BrcmUniLockTask, self).start()
self._local_deferred = reactor.callLater(0, self.perform_lock)
+
@inlineCallbacks
def perform_lock(self):
"""
@@ -98,24 +99,20 @@
else:
self.log.warn('cannot-set-lock-ontg', lock=self._lock)
- pptp = self._config.pptp_entities
+ pptp_list = sorted(self._config.pptp_entities) if self._config.pptp_entities else []
+ veip_list = sorted(self._config.veip_entities) if self._config.veip_entities else []
- for key, value in pptp.iteritems():
- msg = PptpEthernetUniFrame(key,
+ for entity_id in pptp_list:
+ pptp_value = self._config.pptp_entities[entity_id]
+ msg = PptpEthernetUniFrame(entity_id,
attributes=dict(administrative_state=state))
- frame = msg.set()
- self.log.debug('openomci-msg', msg=msg)
- results = yield self._device.omci_cc.send(frame)
- self.strobe_watchdog()
+ self._send_uni_lock_msg(entity_id, pptp_value, msg)
- status = results.fields['omci_message'].fields['success_code']
- self.log.info('response-status', status=status)
-
- # Success?
- if status in (RC.Success.value, RC.InstanceExists):
- self.log.debug('set-lock-uni', uni=key, value=value, lock=self._lock)
- else:
- self.log.warn('cannot-set-lock-uni', uni=key, value=value, lock=self._lock)
+ for entity_id in veip_list:
+ veip_value = self._config.veip_entities[entity_id]
+ msg = VeipUniFrame(entity_id,
+ attributes=dict(administrative_state=state))
+ self._send_uni_lock_msg(entity_id, veip_value, msg)
self.deferred.callback(self)
@@ -123,3 +120,21 @@
self.log.exception('setting-uni-lock-state', e=e)
self.deferred.errback(failure.Failure(e))
+
+ @inlineCallbacks
+ def _send_uni_lock_msg(self, entity_id, value, me_message):
+ frame = me_message.set()
+ self.log.debug('openomci-msg', msg=me_message)
+ results = yield self._device.omci_cc.send(frame)
+ self.strobe_watchdog()
+
+ status = results.fields['omci_message'].fields['success_code']
+ self.log.info('response-status', status=status)
+
+ # Success?
+ if status in (RC.Success.value, RC.InstanceExists):
+ self.log.debug('set-lock-uni', uni=entity_id, value=value, lock=self._lock)
+ else:
+ self.log.warn('cannot-set-lock-uni', uni=entity_id, value=value, lock=self._lock)
+
+ returnValue(None)
diff --git a/voltha/adapters/brcm_openomci_onu/uni_port.py b/voltha/adapters/brcm_openomci_onu/uni_port.py
index cede99d..a887531 100644
--- a/voltha/adapters/brcm_openomci_onu/uni_port.py
+++ b/voltha/adapters/brcm_openomci_onu/uni_port.py
@@ -14,6 +14,7 @@
# limitations under the License.
import structlog
+from enum import Enum
from voltha.protos.common_pb2 import OperStatus, AdminState
from voltha.protos.device_pb2 import Port
from voltha.protos.openflow_13_pb2 import OFPPF_10GB_FD
@@ -22,90 +23,73 @@
from voltha.protos.openflow_13_pb2 import OFPPS_LIVE, OFPPF_FIBER, OFPPS_LINK_DOWN
from voltha.protos.openflow_13_pb2 import ofp_port
+class UniType(Enum):
+ """
+ UNI Types Defined in G.988
+ """
+ PPTP = 'PhysicalPathTerminationPointEthernet'
+ VEIP = 'VirtualEthernetInterfacePoint'
+ # TODO: Add others as they become supported
+
class UniPort(object):
"""Wraps southbound-port(s) support for ONU"""
- DEFAULT_UNTAGGED_VLAN = 4091
- def __init__(self, handler, name, port_no, ofp_port_no, subscriber_vlan=None,
- untagged_vlan=None):
+ def __init__(self, handler, name, port_no, ofp_port_no,
+ type=UniType.PPTP):
self.log = structlog.get_logger(device_id=handler.device_id,
port_no=port_no)
- self.log.debug('function-entry')
self._enabled = False
self._handler = handler
self._name = name
self._port = None
self._port_number = port_no
- self._ofp_port_no = ofp_port_no # Set at by creator (vENET create)
- self._logical_port_number = None # Set at time of logical port creation
- self._subscriber_vlan = subscriber_vlan
- self._untagged_vlan = untagged_vlan
- self._entity_id = None # TODO: Use port number from UNI-G entity ID
+ self._ofp_port_no = ofp_port_no
+ self._logical_port_number = None
+ self._entity_id = None
self._mac_bridge_port_num = 0
+ self._type = type
self._admin_state = AdminState.ENABLED
self._oper_status = OperStatus.ACTIVE
- # TODO Add state, stats, alarm reference, ...
- pass
def __str__(self):
return "UniPort: {}:{}".format(self.name, self.port_number)
@staticmethod
- def create(handler, name, port_no, ofp_port_no, subscriber_vlan, untagged_vlan):
- log = structlog.get_logger(device_id=handler.device_id, name=name)
- log.debug('function-entry')
- port = UniPort(handler, name, port_no, ofp_port_no, subscriber_vlan, untagged_vlan)
-
+ def create(handler, name, port_no, ofp_port_no, type):
+ port = UniPort(handler, name, port_no, ofp_port_no, type)
return port
def _start(self):
- self.log.debug('function-entry')
self._cancel_deferred()
-
self._admin_state = AdminState.ENABLED
self._oper_status = OperStatus.ACTIVE
-
self._update_adapter_agent()
- # TODO: start h/w sync
- # TODO: Enable the actual physical port?
- pass
def _stop(self):
- self.log.debug('function-entry')
self._cancel_deferred()
-
self._admin_state = AdminState.DISABLED
self._oper_status = OperStatus.UNKNOWN
-
self._update_adapter_agent()
- # TODO: Disable/power-down the actual physical port?
- pass
def delete(self):
- self.log.debug('function-entry')
self.enabled = False
self._handler = None
- # TODO: anything else
def _cancel_deferred(self):
- self.log.debug('function-entry')
pass
@property
def name(self):
- self.log.debug('function-entry')
return self._name
@property
def enabled(self):
- self.log.debug('function-entry')
return self._enabled
@enabled.setter
def enabled(self, value):
- self.log.debug('function-entry')
if self._enabled != value:
self._enabled = value
@@ -120,12 +104,10 @@
Port number used when creating MacBridgePortConfigurationDataFrame port number
:return: (int) port number
"""
- self.log.debug('function-entry')
return self._mac_bridge_port_num
@mac_bridge_port_num.setter
def mac_bridge_port_num(self, value):
- self.log.debug('function-entry')
self._mac_bridge_port_num = value
@property
@@ -134,7 +116,6 @@
Physical device port number
:return: (int) port number
"""
- self.log.debug('function-entry')
return self._port_number
@property
@@ -142,38 +123,33 @@
"""
OMCI UNI_G entity ID for port
"""
- self.log.debug('function-entry')
return self._entity_id
@entity_id.setter
def entity_id(self, value):
- self.log.debug('function-entry')
assert self._entity_id is None, 'Cannot reset the Entity ID'
self._entity_id = value
@property
- def subscriber_vlan(self):
- """
- Subscriber vlan assigned to this UNI
- :return: (int) subscriber vlan
- """
- self.log.debug('function-entry')
- return self._subscriber_vlan
-
- @property
def logical_port_number(self):
"""
Logical device port number (used as OpenFlow port for UNI)
:return: (int) port number
"""
- self.log.debug('function-entry')
return self._logical_port_number
+ @property
+ def type(self):
+ """
+ UNI Type used in OMCI messaging
+ :return: (UniType) One of the enumerated types
+ """
+ return self._type
+
def _update_adapter_agent(self):
"""
Update the port status and state in the core
"""
- self.log.debug('function-entry')
self.log.debug('update-adapter-agent', admin_state=self._admin_state,
oper_status=self._oper_status)
@@ -194,8 +170,6 @@
Get the VOLTHA PORT object for this port
:return: VOLTHA Port object
"""
- self.log.debug('function-entry')
-
self._port = Port(port_no=self.port_number,
label=self.port_id_name(),
type=Port.ETHERNET_UNI,
@@ -206,7 +180,7 @@
def port_id_name(self):
return 'uni-{}'.format(self._logical_port_number)
- def add_logical_port(self, openflow_port_no, subscriber_vlan=None,
+ def add_logical_port(self, openflow_port_no,
capabilities=OFPPF_10GB_FD | OFPPF_FIBER,
speed=OFPPF_10GB_FD):
@@ -226,18 +200,12 @@
self._logical_port_number = None
port_no = openflow_port_no or self._ofp_port_no
- vlan = subscriber_vlan or self._subscriber_vlan
if self._logical_port_number is None and port_no is not None:
self._logical_port_number = port_no
- self._subscriber_vlan = vlan
device = self._handler.adapter_agent.get_device(self._handler.device_id)
- if vlan is not None and device.vlan != vlan:
- device.vlan = vlan
- self._handler.adapter_agent.update_device(device)
-
# leave the ports down until omci mib download has finished. otherwise flows push before time
openflow_port = ofp_port(
port_no=port_no,
@@ -263,4 +231,3 @@
device_port_no=self._port_number))
self.log.debug('logical-port', openflow_port=openflow_port)
- # TODO: Should we use the UNI object 'name' as the id for OpenFlow?
diff --git a/voltha/extensions/omci/omci_entities.py b/voltha/extensions/omci/omci_entities.py
index ea0e856..fa4f33a 100644
--- a/voltha/extensions/omci/omci_entities.py
+++ b/voltha/extensions/omci/omci_entities.py
@@ -1218,6 +1218,23 @@
notifications = {OP.AlarmNotification}
+class VeipUni(EntityClass):
+ class_id = 329
+ attributes = [
+ ECA(ShortField("managed_entity_id", None), {AA.R}),
+ ECA(ByteField("administrative_state", 1), {AA.R, AA.W},
+ range_check=lambda x: 0 <= x <= 1),
+ ECA(ByteField("operational_state", 1), {AA.R, AA.W},
+ range_check=lambda x: 0 <= x <= 1, optional=True, avc=True),
+ ECA(StrFixedLenField("interdomain_name", None, 25), {AA.R, AA.W},
+ optional=True),
+ ECA(ShortField("tcp_udp_pointer", None), {AA.R, AA.W}, optional=True),
+ ECA(ShortField("iana_assigned_port", 0xFFFF), {AA.R})
+ ]
+ mandatory_operations = {OP.Get, OP.Set}
+ notifications = {OP.AttributeValueChange, OP.AlarmNotification}
+
+
class EthernetFrameExtendedPerformanceMonitoring(EntityClass):
class_id = 334
hidden = True
diff --git a/voltha/extensions/omci/omci_me.py b/voltha/extensions/omci/omci_me.py
index 4f84fbb..a8a2d05 100644
--- a/voltha/extensions/omci/omci_me.py
+++ b/voltha/extensions/omci/omci_me.py
@@ -540,6 +540,25 @@
MEFrame._attr_to_data(attributes))
+class VeipUniFrame(MEFrame):
+ """
+ This managed entity represents the point a virtual UNI interfaces to a non omci management domain
+ This is typically seen in RG+ONU all-in-one type devices
+ """
+ def __init__(self, entity_id, attributes=None):
+ """
+ :param entity_id: (int) This attribute uniquely identifies each instance of
+ this managed entity. (0..65535)
+
+ :param attributes: (basestring, list, set, dict) attributes. For gets
+ a string, list, or set can be provided. For create/set
+ operations, a dictionary should be provided, for
+ deletes None may be specified.
+ """
+ super(VeipUniFrame, self).__init__(VeipUni, entity_id,
+ MEFrame._attr_to_data(attributes))
+
+
class SoftwareImageFrame(MEFrame):
"""
This managed entity models an executable software image stored in the ONU.
diff --git a/voltha/extensions/omci/onu_configuration.py b/voltha/extensions/omci/onu_configuration.py
index 2ae5836..2bd82ce 100644
--- a/voltha/extensions/omci/onu_configuration.py
+++ b/voltha/extensions/omci/onu_configuration.py
@@ -124,7 +124,8 @@
'_cardholder': None,
'_circuit_pack': None,
'_software': None,
- '_pptp': None
+ '_pptp': None,
+ '_veip': None
}
@property
@@ -485,3 +486,24 @@
'power-control': inst_data[ATTRIBUTES_KEY].get('power_control', 0)
}
return results if len(results) else None
+
+ @property
+ def veip_entities(self):
+ """
+ Returns discovered VEIP entities. TODO more detail here
+ """
+ veip = self._get_capability('_veip', VeipUni.class_id)
+ results = dict()
+
+ if veip is not None:
+ for inst, inst_data in veip.items():
+ if isinstance(inst, int):
+ results[inst] = {
+ 'entity-id': inst,
+ 'administrative-state': inst_data[ATTRIBUTES_KEY].get('administrative_state', 0),
+ 'operational-state': inst_data[ATTRIBUTES_KEY].get('operational_state', 0),
+ 'interdomain-name': inst_data[ATTRIBUTES_KEY].get('interdomain_name', ""),
+ 'tcp-udp-pointer': inst_data[ATTRIBUTES_KEY].get('tcp_udp_pointer', 0),
+ 'iana-assigned-port': inst_data[ATTRIBUTES_KEY].get('iana_assigned_port', 0)
+ }
+ return results if len(results) else None