Merge "Add complete LLDP fields to Port.Ethernet.LLDPReceive per DMTF Redfish v1.12.0"
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Enhances the existing LLDPReceiveField class by adding new LLDP receive data
|
||||
fields as specified in Redfish Port Schema v1.12.0. The existing class already
|
||||
contained chassis_id and port_id fields, and this enhancement adds 9 additional
|
||||
LLDP receive properties.
|
||||
|
||||
New LLDP receive fields added:
|
||||
- chassis_id_subtype: IEEE 802 chassis ID subtype identification
|
||||
- port_id_subtype: IEEE 802 port ID subtype with MAC address handling
|
||||
- system_name: System name received from remote link partner
|
||||
- system_description: System description from remote link partner
|
||||
- system_capabilities: Network device capabilities mapping
|
||||
- management_address_ipv4: IPv4 management address
|
||||
- management_address_ipv6: IPv6 management address
|
||||
- management_address_mac: MAC management address
|
||||
- management_vlan_id: Management VLAN ID configuration (0-4095)
|
||||
|
||||
This enhancement provides LLDP receive information through
|
||||
the EthernetField.lldp_receive property, enabling better network topology
|
||||
discovery.
|
||||
@@ -137,3 +137,71 @@ class PortLinkStatus(enum.Enum):
|
||||
|
||||
TRAINING = 'Training'
|
||||
"""This physical link on this interface is training."""
|
||||
|
||||
|
||||
class IEEE802IdSubtype(enum.Enum):
|
||||
"""IEEE 802.1AB ID Subtypes for Chassis ID and Port ID.
|
||||
|
||||
Based on IEEE 802.1AB-2009 and DMTF Redfish Port Schema v1.12.0
|
||||
"""
|
||||
|
||||
CHASSIS_COMP = 'ChassisComp'
|
||||
"""Chassis component, based on entPhysicalAlias in RFC4133."""
|
||||
|
||||
IF_ALIAS = 'IfAlias'
|
||||
"""Interface alias, based on the ifAlias MIB object."""
|
||||
|
||||
PORT_COMP = 'PortComp'
|
||||
"""Port component, based on entPhysicalAlias in RFC4133."""
|
||||
|
||||
MAC_ADDR = 'MacAddr'
|
||||
"""MAC address, based on agent-detected unicast source (IEEE 802)."""
|
||||
|
||||
NETWORK_ADDR = 'NetworkAddr'
|
||||
"""Network address, based on agent-detected network address."""
|
||||
|
||||
IF_NAME = 'IfName'
|
||||
"""Interface name, based on the ifName MIB object."""
|
||||
|
||||
AGENT_ID = 'AgentId'
|
||||
"""Agent circuit ID, based on agent-local identifier (RFC3046)."""
|
||||
|
||||
LOCAL_ASSIGN = 'LocalAssign'
|
||||
"""Locally assigned, based on alphanumeric value."""
|
||||
|
||||
NOT_TRANSMITTED = 'NotTransmitted'
|
||||
"""No data to be sent to/received from remote partner."""
|
||||
|
||||
|
||||
class LLDPSystemCapabilities(enum.Enum):
|
||||
"""LLDP System Capabilities.
|
||||
|
||||
Based on IEEE 802.1AB and DMTF Redfish Port Schema v1.12.0
|
||||
"""
|
||||
|
||||
NONE = 'None'
|
||||
"""System capabilities are transmitted, but no capabilities are set."""
|
||||
|
||||
BRIDGE = 'Bridge'
|
||||
"""'bridge' capability."""
|
||||
|
||||
DOCSIS_CABLE_DEVICE = 'DOCSISCableDevice'
|
||||
"""'DOCSIS cable device' capability."""
|
||||
|
||||
OTHER = 'Other'
|
||||
"""'other' capability."""
|
||||
|
||||
REPEATER = 'Repeater'
|
||||
"""'repeater' capability."""
|
||||
|
||||
ROUTER = 'Router'
|
||||
"""'router' capability."""
|
||||
|
||||
STATION = 'Station'
|
||||
"""'station' capability."""
|
||||
|
||||
TELEPHONE = 'Telephone'
|
||||
"""'telephone' capability."""
|
||||
|
||||
WLAN_ACCESS_POINT = 'WLANAccessPoint'
|
||||
"""'WLAN access point' capability."""
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# This is referred from Redfish standard schema.
|
||||
# https://redfish.dmtf.org/schemas/v1/Port.v1_8_0.json
|
||||
# https://redfish.dmtf.org/schemas/v1/Port.v1_12_0.json
|
||||
|
||||
from sushy.resources import base
|
||||
from sushy.resources import common
|
||||
@@ -18,12 +18,56 @@ from sushy.resources.system.network import constants
|
||||
|
||||
|
||||
class LLDPReceiveField(base.CompositeField):
|
||||
"""LLDP data being received on this link.
|
||||
|
||||
Based on DMTF Redfish Port Schema v1.12.0
|
||||
https://redfish.dmtf.org/schemas/v1/Port.v1_12_0.json#/definitions/LLDPReceive
|
||||
"""
|
||||
|
||||
chassis_id = base.Field("ChassisId")
|
||||
"""chassis ID received from the remote partner across this link."""
|
||||
|
||||
chassis_id_subtype = base.MappedField("ChassisIdSubtype",
|
||||
constants.IEEE802IdSubtype)
|
||||
"""The type of identifier used for the chassis ID"""
|
||||
|
||||
port_id = base.Field("PortId")
|
||||
"""A colon delimited string of hexadecimal octets identifying a port."""
|
||||
|
||||
port_id_subtype = base.MappedField("PortIdSubtype",
|
||||
constants.IEEE802IdSubtype)
|
||||
"""The port ID subtype received from the remote partner"""
|
||||
|
||||
# TLV Type 3 - Time To Live not in current schema
|
||||
|
||||
# TLV Type 4 - Port Description ,not in schema
|
||||
|
||||
# TLV Type 5 - System Name
|
||||
system_name = base.Field("SystemName")
|
||||
"""The system name received from the remote partner across this link."""
|
||||
|
||||
# TLV Type 6 - System Description
|
||||
system_description = base.Field("SystemDescription")
|
||||
"""The system description received from the remote partner."""
|
||||
|
||||
# TLV Type 7 - System Capabilities
|
||||
system_capabilities = base.MappedListField(
|
||||
"SystemCapabilities", constants.LLDPSystemCapabilities)
|
||||
"""The system capabilities received from the remote partner."""
|
||||
|
||||
# TLV Type 8 - Management Addresses
|
||||
management_address_ipv4 = base.Field("ManagementAddressIPv4")
|
||||
"""The IPv4 management address received from the remote partner."""
|
||||
|
||||
management_address_ipv6 = base.Field("ManagementAddressIPv6")
|
||||
"""The IPv6 management address received from the remote partner."""
|
||||
|
||||
management_address_mac = base.Field("ManagementAddressMAC")
|
||||
"""The management MAC address received from the remote partner."""
|
||||
|
||||
management_vlan_id = base.Field("ManagementVlanId", adapter=int)
|
||||
"""The management VLAN ID received from the remote partner (0-4095)."""
|
||||
|
||||
|
||||
class EthernetField(base.CompositeField):
|
||||
associated_mac_addresses = base.Field(
|
||||
|
||||
@@ -13,10 +13,17 @@
|
||||
"FlowControlConfiguration": "None",
|
||||
"FlowControlStatus": "None",
|
||||
"LLDPReceive": {
|
||||
"ChassisId": "Not Available",
|
||||
"ChassisIdSubtype": null,
|
||||
"ChassisId": "c4:7e:e0:e4:55:3f",
|
||||
"ChassisIdSubtype": "MacAddr",
|
||||
"PortId": "0A:1B:2C:3D:4E:5F:6A:7B:8C:9D:0E:1F:2A",
|
||||
"PortIdSubtype": null
|
||||
"PortIdSubtype": "IfName",
|
||||
"SystemName": "switch-00.example.com",
|
||||
"SystemDescription": "Test Software, Version 00.00.00",
|
||||
"SystemCapabilities": ["Bridge", "Router"],
|
||||
"ManagementAddressIPv4": "192.168.1.1",
|
||||
"ManagementAddressIPv6": "fe80::1",
|
||||
"ManagementAddressMAC": "c4:7e:e0:e4:55:40",
|
||||
"ManagementVlanId": 100
|
||||
},
|
||||
"WakeOnLANEnabled": false
|
||||
},
|
||||
|
||||
@@ -53,6 +53,80 @@ class PortTestCase(base.TestCase):
|
||||
self.port.ethernet.flow_control_status)
|
||||
self.assertEqual(net_cons.PortLinkStatus.LINKUP, self.port.link_status)
|
||||
|
||||
def test_lldp_receive_all_fields(self):
|
||||
"""Test all enhanced LLDP fields are parsed correctly"""
|
||||
self.port._parse_attributes(self.json_doc)
|
||||
|
||||
lldp = self.port.ethernet.lldp_receive
|
||||
|
||||
# Test TLV Type 1 - Chassis ID with subtype
|
||||
self.assertEqual('c4:7e:e0:e4:55:3f', lldp.chassis_id)
|
||||
self.assertEqual(net_cons.IEEE802IdSubtype.MAC_ADDR,
|
||||
lldp.chassis_id_subtype)
|
||||
|
||||
# Test TLV Type 2 - Port ID with subtype
|
||||
self.assertEqual('0A:1B:2C:3D:4E:5F:6A:7B:8C:9D:0E:1F:2A',
|
||||
lldp.port_id)
|
||||
self.assertEqual(net_cons.IEEE802IdSubtype.IF_NAME,
|
||||
lldp.port_id_subtype)
|
||||
|
||||
# Test TLV Type 5 - System Name
|
||||
self.assertEqual('switch-00.example.com', lldp.system_name)
|
||||
|
||||
# Test TLV Type 6 - System Description
|
||||
self.assertEqual('Test Software, Version 00.00.00',
|
||||
lldp.system_description)
|
||||
|
||||
# Test TLV Type 7 - System Capabilities
|
||||
self.assertIsNotNone(lldp.system_capabilities)
|
||||
self.assertEqual(2, len(lldp.system_capabilities))
|
||||
self.assertIn(net_cons.LLDPSystemCapabilities.BRIDGE,
|
||||
lldp.system_capabilities)
|
||||
self.assertIn(net_cons.LLDPSystemCapabilities.ROUTER,
|
||||
lldp.system_capabilities)
|
||||
|
||||
# Test TLV Type 8 - Management Addresses
|
||||
self.assertEqual('192.168.1.1', lldp.management_address_ipv4)
|
||||
self.assertEqual('fe80::1', lldp.management_address_ipv6)
|
||||
self.assertEqual('c4:7e:e0:e4:55:40', lldp.management_address_mac)
|
||||
self.assertEqual(100, lldp.management_vlan_id)
|
||||
|
||||
def test_lldp_receive_minimal_data(self):
|
||||
"""Test LLDP with minimal data (only mandatory fields)"""
|
||||
minimal_doc = self.json_doc.copy()
|
||||
minimal_doc['Ethernet']['LLDPReceive'] = {
|
||||
"ChassisId": "aa:bb:cc:dd:ee:ff",
|
||||
"PortId": "port-1"
|
||||
}
|
||||
|
||||
self.port._parse_attributes(minimal_doc)
|
||||
lldp = self.port.ethernet.lldp_receive
|
||||
|
||||
# Mandatory fields present
|
||||
self.assertEqual('aa:bb:cc:dd:ee:ff', lldp.chassis_id)
|
||||
self.assertEqual('port-1', lldp.port_id)
|
||||
|
||||
# Optional fields None
|
||||
self.assertIsNone(lldp.chassis_id_subtype)
|
||||
self.assertIsNone(lldp.port_id_subtype)
|
||||
self.assertIsNone(lldp.system_name)
|
||||
self.assertIsNone(lldp.system_description)
|
||||
self.assertIsNone(lldp.system_capabilities)
|
||||
self.assertIsNone(lldp.management_address_ipv4)
|
||||
|
||||
def test_lldp_receive_empty(self):
|
||||
"""Test empty LLDPReceive (Dell scenario)"""
|
||||
empty_doc = self.json_doc.copy()
|
||||
empty_doc['Ethernet']['LLDPReceive'] = {}
|
||||
|
||||
self.port._parse_attributes(empty_doc)
|
||||
lldp = self.port.ethernet.lldp_receive
|
||||
|
||||
# All fields should be None
|
||||
self.assertIsNone(lldp.chassis_id)
|
||||
self.assertIsNone(lldp.port_id)
|
||||
self.assertIsNone(lldp.system_name)
|
||||
|
||||
|
||||
class PortCollectionTestCase(base.TestCase):
|
||||
|
||||
|
||||
Reference in New Issue
Block a user