868965c340
This fixes the warning/errors except for the C901 Function is too complex in the ironic_inspector/rules.py's create method. Bump's max-complexity to 18 in tox.ini to workaround the C901. Story: 2001985 Task: 19604 Change-Id: I6c76a43353b1beb572dbde78dba4b4a839d45ea7
368 lines
10 KiB
Python
368 lines
10 KiB
Python
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
# implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
""" Link Layer Discovery Protocol TLVs """
|
|
|
|
import functools
|
|
|
|
# See http://construct.readthedocs.io/en/latest/index.html
|
|
import construct
|
|
from construct import core
|
|
import netaddr
|
|
|
|
from ironic_inspector import utils
|
|
|
|
LOG = utils.getProcessingLogger(__name__)
|
|
|
|
# Constants defined according to 802.1AB-2016 LLDP spec
|
|
# https://standards.ieee.org/findstds/standard/802.1AB-2016.html
|
|
|
|
# TLV types
|
|
LLDP_TLV_END_LLDPPDU = 0
|
|
LLDP_TLV_CHASSIS_ID = 1
|
|
LLDP_TLV_PORT_ID = 2
|
|
LLDP_TLV_TTL = 3
|
|
LLDP_TLV_PORT_DESCRIPTION = 4
|
|
LLDP_TLV_SYS_NAME = 5
|
|
LLDP_TLV_SYS_DESCRIPTION = 6
|
|
LLDP_TLV_SYS_CAPABILITIES = 7
|
|
LLDP_TLV_MGMT_ADDRESS = 8
|
|
LLDP_TLV_ORG_SPECIFIC = 127
|
|
|
|
# 802.1Q defines from http://www.ieee802.org/1/pages/802.1Q-2014.html, Annex D
|
|
LLDP_802dot1_OUI = "0080c2"
|
|
# subtypes
|
|
dot1_PORT_VLANID = 1
|
|
dot1_PORT_PROTOCOL_VLANID = 2
|
|
dot1_VLAN_NAME = 3
|
|
dot1_PROTOCOL_IDENTITY = 4
|
|
dot1_MANAGEMENT_VID = 6
|
|
dot1_LINK_AGGREGATION = 7
|
|
|
|
# 802.3 defines from http://standards.ieee.org/about/get/802/802.3.html,
|
|
# section 79
|
|
LLDP_802dot3_OUI = "00120f"
|
|
# Subtypes
|
|
dot3_MACPHY_CONFIG_STATUS = 1
|
|
dot3_LINK_AGGREGATION = 3 # Deprecated, but still in use
|
|
dot3_MTU = 4
|
|
|
|
|
|
def bytes_to_int(obj):
|
|
"""Convert bytes to an integer
|
|
|
|
:param: obj - array of bytes
|
|
"""
|
|
return functools.reduce(lambda x, y: x << 8 | y, obj)
|
|
|
|
|
|
def mapping_for_enum(mapping):
|
|
"""Return tuple used for keys as a dict
|
|
|
|
:param: mapping - dict with tuple as keys
|
|
"""
|
|
return dict(mapping.keys())
|
|
|
|
|
|
def mapping_for_switch(mapping):
|
|
"""Return dict from values
|
|
|
|
:param: mapping - dict with tuple as keys
|
|
"""
|
|
return {key[0]: value for key, value in mapping.items()}
|
|
|
|
|
|
IPv4Address = core.ExprAdapter(
|
|
core.Byte[4],
|
|
encoder=lambda obj, ctx: netaddr.IPAddress(obj).words,
|
|
decoder=lambda obj, ctx: str(netaddr.IPAddress(bytes_to_int(obj)))
|
|
)
|
|
|
|
IPv6Address = core.ExprAdapter(
|
|
core.Byte[16],
|
|
encoder=lambda obj, ctx: netaddr.IPAddress(obj).words,
|
|
decoder=lambda obj, ctx: str(netaddr.IPAddress(bytes_to_int(obj)))
|
|
)
|
|
|
|
MACAddress = core.ExprAdapter(
|
|
core.Byte[6],
|
|
encoder=lambda obj, ctx: netaddr.EUI(obj).words,
|
|
decoder=lambda obj, ctx: str(netaddr.EUI(bytes_to_int(obj),
|
|
dialect=netaddr.mac_unix_expanded))
|
|
)
|
|
|
|
IANA_ADDRESS_FAMILY_ID_MAPPING = {
|
|
('ipv4', 1): IPv4Address,
|
|
('ipv6', 2): IPv6Address,
|
|
('mac', 6): MACAddress,
|
|
}
|
|
|
|
IANAAddress = core.Embedded(core.Struct(
|
|
'family' / core.Enum(core.Int8ub, **mapping_for_enum(
|
|
IANA_ADDRESS_FAMILY_ID_MAPPING)),
|
|
'value' / core.Switch(construct.this.family, mapping_for_switch(
|
|
IANA_ADDRESS_FAMILY_ID_MAPPING))))
|
|
|
|
# Note that 'GreedyString()' is used in cases where string len is not defined
|
|
CHASSIS_ID_MAPPING = {
|
|
('entPhysAlias_c', 1): core.Struct('value' / core.GreedyString("utf8")),
|
|
('ifAlias', 2): core.Struct('value' / core.GreedyString("utf8")),
|
|
('entPhysAlias_p', 3): core.Struct('value' / core.GreedyString("utf8")),
|
|
('mac_address', 4): core.Struct('value' / MACAddress),
|
|
('IANA_address', 5): IANAAddress,
|
|
('ifName', 6): core.Struct('value' / core.GreedyString("utf8")),
|
|
('local', 7): core.Struct('value' / core.GreedyString("utf8"))
|
|
}
|
|
|
|
#
|
|
# Basic Management Set TLV field definitions
|
|
#
|
|
|
|
# Chassis ID value is based on the subtype
|
|
ChassisId = core.Struct(
|
|
'subtype' / core.Enum(core.Byte, **mapping_for_enum(
|
|
CHASSIS_ID_MAPPING)),
|
|
'value' /
|
|
core.Embedded(core.Switch(construct.this.subtype,
|
|
mapping_for_switch(CHASSIS_ID_MAPPING)))
|
|
)
|
|
|
|
PORT_ID_MAPPING = {
|
|
('ifAlias', 1): core.Struct('value' / core.GreedyString("utf8")),
|
|
('entPhysicalAlias', 2): core.Struct('value' / core.GreedyString("utf8")),
|
|
('mac_address', 3): core.Struct('value' / MACAddress),
|
|
('IANA_address', 4): IANAAddress,
|
|
('ifName', 5): core.Struct('value' / core.GreedyString("utf8")),
|
|
('local', 7): core.Struct('value' / core.GreedyString("utf8"))
|
|
}
|
|
|
|
# Port ID value is based on the subtype
|
|
PortId = core.Struct(
|
|
'subtype' / core.Enum(core.Byte, **mapping_for_enum(
|
|
PORT_ID_MAPPING)),
|
|
'value' /
|
|
core.Embedded(core.Switch(construct.this.subtype,
|
|
mapping_for_switch(PORT_ID_MAPPING)))
|
|
)
|
|
|
|
PortDesc = core.Struct('value' / core.GreedyString("utf8"))
|
|
|
|
SysName = core.Struct('value' / core.GreedyString("utf8"))
|
|
|
|
SysDesc = core.Struct('value' / core.GreedyString("utf8"))
|
|
|
|
MgmtAddress = core.Struct(
|
|
'len' / core.Int8ub,
|
|
'family' / core.Enum(core.Int8ub, **mapping_for_enum(
|
|
IANA_ADDRESS_FAMILY_ID_MAPPING)),
|
|
'address' / core.Switch(construct.this.family, mapping_for_switch(
|
|
IANA_ADDRESS_FAMILY_ID_MAPPING))
|
|
)
|
|
|
|
Capabilities = core.BitStruct(
|
|
core.Padding(5),
|
|
'tpmr' / core.Bit,
|
|
'svlan' / core.Bit,
|
|
'cvlan' / core.Bit,
|
|
'station' / core.Bit,
|
|
'docsis' / core.Bit,
|
|
'telephone' / core.Bit,
|
|
'router' / core.Bit,
|
|
'wlan' / core.Bit,
|
|
'bridge' / core.Bit,
|
|
'repeater' / core.Bit,
|
|
core.Padding(1)
|
|
)
|
|
|
|
SysCapabilities = core.Struct(
|
|
'system' / Capabilities,
|
|
'enabled' / Capabilities
|
|
)
|
|
|
|
OrgSpecific = core.Struct(
|
|
'oui' / core.Bytes(3),
|
|
'subtype' / core.Int8ub
|
|
)
|
|
|
|
#
|
|
# 802.1Q TLV field definitions
|
|
# See http://www.ieee802.org/1/pages/802.1Q-2014.html, Annex D
|
|
#
|
|
|
|
Dot1_UntaggedVlanId = core.Struct('value' / core.Int16ub)
|
|
|
|
Dot1_PortProtocolVlan = core.Struct(
|
|
'flags' / core.BitStruct(
|
|
core.Padding(5),
|
|
'enabled' / core.Flag,
|
|
'supported' / core.Flag,
|
|
core.Padding(1),
|
|
),
|
|
'vlanid' / core.Int16ub
|
|
)
|
|
|
|
Dot1_VlanName = core.Struct(
|
|
'vlanid' / core.Int16ub,
|
|
'name_len' / core.Rebuild(core.Int8ub,
|
|
construct.len_(construct.this.value)),
|
|
'vlan_name' / core.String(construct.this.name_len, "utf8")
|
|
)
|
|
|
|
Dot1_ProtocolIdentity = core.Struct(
|
|
'len' / core.Rebuild(core.Int8ub, construct.len_(construct.this.value)),
|
|
'protocol' / core.Bytes(construct.this.len)
|
|
)
|
|
|
|
Dot1_MgmtVlanId = core.Struct('value' / core.Int16ub)
|
|
|
|
Dot1_LinkAggregationId = core.Struct(
|
|
'status' / core.BitStruct(
|
|
core.Padding(6),
|
|
'enabled' / core.Flag,
|
|
'supported' / core.Flag
|
|
),
|
|
'portid' / core.Int32ub
|
|
)
|
|
|
|
#
|
|
# 802.3 TLV field definitions
|
|
# See http://standards.ieee.org/about/get/802/802.3.html,
|
|
# section 79
|
|
#
|
|
|
|
|
|
def get_autoneg_cap(pmd):
|
|
"""Get autonegotiated capability strings
|
|
|
|
This returns a list of capability strings from the Physical Media
|
|
Dependent (PMD) capability bits.
|
|
|
|
:param pmd: PMD bits
|
|
:return: Sorted ist containing capability strings
|
|
"""
|
|
caps_set = set()
|
|
|
|
pmd_map = [
|
|
(pmd._10base_t_hdx, '10BASE-T hdx'),
|
|
(pmd._10base_t_hdx, '10BASE-T fdx'),
|
|
(pmd._10base_t4, '10BASE-T4'),
|
|
(pmd._100base_tx_hdx, '100BASE-TX hdx'),
|
|
(pmd._100base_tx_fdx, '100BASE-TX fdx'),
|
|
(pmd._100base_t2_hdx, '100BASE-T2 hdx'),
|
|
(pmd._100base_t2_fdx, '100BASE-T2 fdx'),
|
|
(pmd.pause_fdx, 'PAUSE fdx'),
|
|
(pmd.asym_pause, 'Asym PAUSE fdx'),
|
|
(pmd.sym_pause, 'Sym PAUSE fdx'),
|
|
(pmd.asym_sym_pause, 'Asym and Sym PAUSE fdx'),
|
|
(pmd._1000base_x_hdx, '1000BASE-X hdx'),
|
|
(pmd._1000base_x_fdx, '1000BASE-X fdx'),
|
|
(pmd._1000base_t_hdx, '1000BASE-T hdx'),
|
|
(pmd._1000base_t_fdx, '1000BASE-T fdx')]
|
|
|
|
for bit, cap in pmd_map:
|
|
if bit:
|
|
caps_set.add(cap)
|
|
|
|
return sorted(caps_set)
|
|
|
|
|
|
Dot3_MACPhy_Config_Status = core.Struct(
|
|
'autoneg' / core.BitStruct(
|
|
core.Padding(6),
|
|
'enabled' / core.Flag,
|
|
'supported' / core.Flag,
|
|
),
|
|
# See IANAifMauAutoNegCapBits
|
|
# RFC 4836, Definitions of Managed Objects for IEEE 802.3
|
|
'pmd_autoneg' / core.BitStruct(
|
|
core.Padding(1),
|
|
'_10base_t_hdx' / core.Bit,
|
|
'_10base_t_fdx' / core.Bit,
|
|
'_10base_t4' / core.Bit,
|
|
'_100base_tx_hdx' / core.Bit,
|
|
'_100base_tx_fdx' / core.Bit,
|
|
'_100base_t2_hdx' / core.Bit,
|
|
'_100base_t2_fdx' / core.Bit,
|
|
'pause_fdx' / core.Bit,
|
|
'asym_pause' / core.Bit,
|
|
'sym_pause' / core.Bit,
|
|
'asym_sym_pause' / core.Bit,
|
|
'_1000base_x_hdx' / core.Bit,
|
|
'_1000base_x_fdx' / core.Bit,
|
|
'_1000base_t_hdx' / core.Bit,
|
|
'_1000base_t_fdx' / core.Bit
|
|
),
|
|
'mau_type' / core.Int16ub
|
|
)
|
|
|
|
# See ifMauTypeList in
|
|
# RFC 4836, Definitions of Managed Objects for IEEE 802.3
|
|
OPER_MAU_TYPES = {
|
|
0: "Unknown",
|
|
1: "AUI",
|
|
2: "10BASE-5",
|
|
3: "FOIRL",
|
|
4: "10BASE-2",
|
|
5: "10BASE-T duplex mode unknown",
|
|
6: "10BASE-FP",
|
|
7: "10BASE-FB",
|
|
8: "10BASE-FL duplex mode unknown",
|
|
9: "10BROAD36",
|
|
10: "10BASE-T half duplex",
|
|
11: "10BASE-T full duplex",
|
|
12: "10BASE-FL half duplex",
|
|
13: "10BASE-FL full duplex",
|
|
14: "100 BASE-T4",
|
|
15: "100BASE-TX half duplex",
|
|
16: "100BASE-TX full duplex",
|
|
17: "100BASE-FX half duplex",
|
|
18: "100BASE-FX full duplex",
|
|
19: "100BASE-T2 half duplex",
|
|
20: "100BASE-T2 full duplex",
|
|
21: "1000BASE-X half duplex",
|
|
22: "1000BASE-X full duplex",
|
|
23: "1000BASE-LX half duplex",
|
|
24: "1000BASE-LX full duplex",
|
|
25: "1000BASE-SX half duplex",
|
|
26: "1000BASE-SX full duplex",
|
|
27: "1000BASE-CX half duplex",
|
|
28: "1000BASE-CX full duplex",
|
|
29: "1000BASE-T half duplex",
|
|
30: "1000BASE-T full duplex",
|
|
31: "10GBASE-X",
|
|
32: "10GBASE-LX4",
|
|
33: "10GBASE-R",
|
|
34: "10GBASE-ER",
|
|
35: "10GBASE-LR",
|
|
36: "10GBASE-SR",
|
|
37: "10GBASE-W",
|
|
38: "10GBASE-EW",
|
|
39: "10GBASE-LW",
|
|
40: "10GBASE-SW",
|
|
41: "10GBASE-CX4",
|
|
42: "2BASE-TL",
|
|
43: "10PASS-TS",
|
|
44: "100BASE-BX10D",
|
|
45: "100BASE-BX10U",
|
|
46: "100BASE-LX10",
|
|
47: "1000BASE-BX10D",
|
|
48: "1000BASE-BX10U",
|
|
49: "1000BASE-LX10",
|
|
50: "1000BASE-PX10D",
|
|
51: "1000BASE-PX10U",
|
|
52: "1000BASE-PX20D",
|
|
53: "1000BASE-PX20U",
|
|
}
|
|
|
|
Dot3_MTU = core.Struct('value' / core.Int16ub)
|