Merge "Enable OVS LLDP inventory"

This commit is contained in:
Zuul 2018-09-27 00:57:48 +00:00 committed by Gerrit Code Review
commit 0007569a0d
16 changed files with 999 additions and 673 deletions

View File

@ -1,2 +1,2 @@
SRC_DIR="sysinv"
TIS_PATCH_VER=281
TIS_PATCH_VER=282

View File

@ -17,3 +17,6 @@ connection=postgresql://cgts:cgtspwd@localhost/cgtsdb:
rpc_backend = sysinv.openstack.common.rpc.impl_kombu
rabbit_host = 192.168.204.3
rabbit_port = 5672
[lldp]
drivers=lldpd

View File

@ -72,6 +72,10 @@ systemconfig.puppet_plugins =
032_swift = sysinv.puppet.swift:SwiftPuppet
033_service_parameter = sysinv.puppet.service_parameter:ServiceParamPuppet
sysinv.agent.lldp.drivers =
lldpd = sysinv.agent.lldp.drivers.lldpd.driver:SysinvLldpdAgentDriver
ovs = sysinv.agent.lldp.drivers.ovs.driver:SysinvOVSAgentDriver
[pbr]
autodoc_index_modules = True

View File

@ -1,661 +0,0 @@
#
# Copyright (c) 2016 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# All Rights Reserved.
#
""" inventory lldp Utilities and helper functions."""
import simplejson as json
import subprocess
import threading
from operator import attrgetter
from sysinv.common import constants
from sysinv.openstack.common import log as logging
LOG = logging.getLogger(__name__)
class Key(object):
def __init__(self, chassisid, portid, portname):
self.chassisid = chassisid
self.portid = portid
self.portname = portname
def __hash__(self):
return hash((self.chassisid, self.portid, self.portname))
def __cmp__(self, rhs):
return (cmp(self.chassisid, rhs.chassisid) or
cmp(self.portid, rhs.portid) or
cmp(self.portname, rhs.portname))
def __eq__(self, rhs):
return (self.chassisid == rhs.chassisid and
self.portid == rhs.portid and
self.portname == rhs.portname)
def __ne__(self, rhs):
return (self.chassisid != rhs.chassisid or
self.portid != rhs.portid or
self.portname != rhs.portname)
def __str__(self):
return "%s [%s] [%s]" % (self.portname, self.chassisid, self.portid)
def __repr__(self):
return "<Key '%s'>" % str(self)
class Agent(object):
'''Class to encapsulate LLDP agent data for System Inventory'''
def __init__(self, **kwargs):
'''Construct an Agent object with the given values.'''
self.key = Key(kwargs.get(constants.LLDP_TLV_TYPE_CHASSIS_ID),
kwargs.get(constants.LLDP_TLV_TYPE_PORT_ID),
kwargs.get("name_or_uuid"))
self.status = kwargs.get('status')
self.ttl = kwargs.get(constants.LLDP_TLV_TYPE_TTL)
self.system_name = kwargs.get(constants.LLDP_TLV_TYPE_SYSTEM_NAME)
self.system_desc = kwargs.get(constants.LLDP_TLV_TYPE_SYSTEM_DESC)
self.port_desc = kwargs.get(constants.LLDP_TLV_TYPE_PORT_DESC)
self.capabilities = kwargs.get(constants.LLDP_TLV_TYPE_SYSTEM_CAP)
self.mgmt_addr = kwargs.get(constants.LLDP_TLV_TYPE_MGMT_ADDR)
self.dot1_lag = kwargs.get(constants.LLDP_TLV_TYPE_DOT1_LAG)
self.dot1_vlan_names = kwargs.get(
constants.LLDP_TLV_TYPE_DOT1_VLAN_NAMES)
self.dot3_max_frame = kwargs.get(
constants.LLDP_TLV_TYPE_DOT3_MAX_FRAME)
self.state = None
def __hash__(self):
return self.key.__hash__()
def __eq__(self, rhs):
return (self.key == rhs.key)
def __ne__(self, rhs):
return (self.key != rhs.key or
self.status != rhs.status or
self.ttl != rhs.ttl or
self.system_name != rhs.system_name or
self.system_desc != rhs.system_desc or
self.port_desc != rhs.port_desc or
self.capabilities != rhs.capabilities or
self.mgmt_addr != rhs.mgmt_addr or
self.dot1_lag != rhs.dot1_lag or
self.dot1_vlan_names != rhs.dot1_vlan_names or
self.dot3_max_frame != rhs.dot3_max_frame or
self.state != rhs.state)
def __str__(self):
return "%s: [%s] [%s] [%s], [%s], [%s], [%s], [%s], [%s]" % (
self.key, self.status, self.system_name, self.system_desc,
self.port_desc, self.capabilities,
self.mgmt_addr, self.dot1_lag,
self.dot3_max_frame)
def __repr__(self):
return "<Agent '%s'>" % str(self)
class Neighbour(object):
'''Class to encapsulate LLDP neighbour data for System Inventory'''
def __init__(self, **kwargs):
'''Construct an Neighbour object with the given values.'''
self.key = Key(kwargs.get(constants.LLDP_TLV_TYPE_CHASSIS_ID),
kwargs.get(constants.LLDP_TLV_TYPE_PORT_ID),
kwargs.get("name_or_uuid"))
self.msap = kwargs.get('msap')
self.ttl = kwargs.get(constants.LLDP_TLV_TYPE_TTL)
self.system_name = kwargs.get(constants.LLDP_TLV_TYPE_SYSTEM_NAME)
self.system_desc = kwargs.get(constants.LLDP_TLV_TYPE_SYSTEM_DESC)
self.port_desc = kwargs.get(constants.LLDP_TLV_TYPE_PORT_DESC)
self.capabilities = kwargs.get(constants.LLDP_TLV_TYPE_SYSTEM_CAP)
self.mgmt_addr = kwargs.get(constants.LLDP_TLV_TYPE_MGMT_ADDR)
self.dot1_port_vid = kwargs.get(constants.LLDP_TLV_TYPE_DOT1_PORT_VID)
self.dot1_vid_digest = kwargs.get(
constants.LLDP_TLV_TYPE_DOT1_VID_DIGEST)
self.dot1_mgmt_vid = kwargs.get(constants.LLDP_TLV_TYPE_DOT1_MGMT_VID)
self.dot1_vid_digest = kwargs.get(
constants.LLDP_TLV_TYPE_DOT1_VID_DIGEST)
self.dot1_mgmt_vid = kwargs.get(constants.LLDP_TLV_TYPE_DOT1_MGMT_VID)
self.dot1_lag = kwargs.get(constants.LLDP_TLV_TYPE_DOT1_LAG)
self.dot1_vlan_names = kwargs.get(
constants.LLDP_TLV_TYPE_DOT1_VLAN_NAMES)
self.dot1_proto_vids = kwargs.get(
constants.LLDP_TLV_TYPE_DOT1_PROTO_VIDS)
self.dot1_proto_ids = kwargs.get(
constants.LLDP_TLV_TYPE_DOT1_PROTO_IDS)
self.dot3_mac_status = kwargs.get(
constants.LLDP_TLV_TYPE_DOT3_MAC_STATUS)
self.dot3_max_frame = kwargs.get(
constants.LLDP_TLV_TYPE_DOT3_MAX_FRAME)
self.dot3_power_mdi = kwargs.get(
constants.LLDP_TLV_TYPE_DOT3_POWER_MDI)
self.state = None
def __hash__(self):
return self.key.__hash__()
def __eq__(self, rhs):
return (self.key == rhs.key)
def __ne__(self, rhs):
return (self.key != rhs.key or
self.msap != rhs.msap or
self.system_name != rhs.system_name or
self.system_desc != rhs.system_desc or
self.port_desc != rhs.port_desc or
self.capabilities != rhs.capabilities or
self.mgmt_addr != rhs.mgmt_addr or
self.dot1_port_vid != rhs.dot1_port_vid or
self.dot1_vid_digest != rhs.dot1_vid_digest or
self.dot1_mgmt_vid != rhs.dot1_mgmt_vid or
self.dot1_vid_digest != rhs.dot1_vid_digest or
self.dot1_mgmt_vid != rhs.dot1_mgmt_vid or
self.dot1_lag != rhs.dot1_lag or
self.dot1_vlan_names != rhs.dot1_vlan_names or
self.dot1_proto_vids != rhs.dot1_proto_vids or
self.dot1_proto_ids != rhs.dot1_proto_ids or
self.dot3_mac_status != rhs.dot3_mac_status or
self.dot3_max_frame != rhs.dot3_max_frame or
self.dot3_power_mdi != rhs.dot3_power_mdi)
def __str__(self):
return "%s [%s] [%s] [%s], [%s]" % (
self.key, self.system_name, self.system_desc,
self.port_desc, self.capabilities)
def __repr__(self):
return "<Neighbour '%s'>" % str(self)
class LLDPOperator(object):
'''Class to encapsulate LLDP operations for System Inventory'''
def __init__(self, **kwargs):
self._lock = threading.Lock()
self.client = ""
self.agents = []
self.neighbours = []
self.current_neighbours = []
self.previous_neighbours = []
self.current_agents = []
self.previous_agents = []
self.agent_audit_count = 0
self.neighbour_audit_count = 0
def lldpd_get_agent_status(self):
json_obj = json
p = subprocess.Popen(["lldpcli", "-f", "json", "show",
"configuration"],
stdout=subprocess.PIPE)
data = json_obj.loads(p.communicate()[0])
configuration = data['configuration'][0]
config = configuration['config'][0]
rx_only = config['rx-only'][0]
if rx_only.get("value") == "no":
return "rx=enabled,tx=enabled"
else:
return "rx=enabled,tx=disabled"
def lldpd_get_attrs(self, iface):
name_or_uuid = None
chassis_id = None
system_name = None
system_desc = None
capability = None
management_address = None
port_desc = None
dot1_lag = None
dot1_port_vid = None
dot1_vid_digest = None
dot1_mgmt_vid = None
dot1_vlan_names = None
dot1_proto_vids = None
dot1_proto_ids = None
dot3_mac_status = None
dot3_max_frame = None
dot3_power_mdi = None
ttl = None
attrs = {}
# Note: dot1_vid_digest, dot1_mgmt_vid are not currently supported
# by the lldpd daemon
name_or_uuid = iface.get("name")
chassis = iface.get("chassis")[0]
port = iface.get("port")[0]
if not chassis.get('id'):
return attrs
chassis_id = chassis['id'][0].get("value")
if not port.get('id'):
return attrs
port_id = port["id"][0].get("value")
if not port.get('ttl'):
return attrs
ttl = port['ttl'][0].get("value")
if chassis.get("name"):
system_name = chassis['name'][0].get("value")
if chassis.get("descr"):
system_desc = chassis['descr'][0].get("value")
if chassis.get("capability"):
capability = ""
for cap in chassis["capability"]:
if cap.get("enabled"):
if capability:
capability += ", "
capability += cap.get("type").lower()
if chassis.get("mgmt-ip"):
management_address = ""
for addr in chassis["mgmt-ip"]:
if management_address:
management_address += ", "
management_address += addr.get("value").lower()
if port.get("descr"):
port_desc = port["descr"][0].get("value")
if port.get("link-aggregation"):
dot1_lag_supported = port["link-aggregation"][0].get("supported")
dot1_lag_enabled = port["link-aggregation"][0].get("enabled")
dot1_lag = "capable="
if dot1_lag_supported:
dot1_lag += "y,"
else:
dot1_lag += "n,"
dot1_lag += "enabled="
if dot1_lag_enabled:
dot1_lag += "y"
else:
dot1_lag += "n"
if port.get("auto-negotiation"):
port_auto_neg_support = port["auto-negotiation"][0].get(
"supported")
port_auto_neg_enabled = port["auto-negotiation"][0].get("enabled")
dot3_mac_status = "auto-negotiation-capable="
if port_auto_neg_support:
dot3_mac_status += "y,"
else:
dot3_mac_status += "n,"
dot3_mac_status += "auto-negotiation-enabled="
if port_auto_neg_enabled:
dot3_mac_status += "y,"
else:
dot3_mac_status += "n,"
advertised = ""
if port.get("auto-negotiation")[0].get("advertised"):
for adv in port["auto-negotiation"][0].get("advertised"):
if advertised:
advertised += ", "
type = adv.get("type").lower()
if adv.get("hd") and not adv.get("fd"):
type += "hd"
elif adv.get("fd"):
type += "fd"
advertised += type
dot3_mac_status += advertised
if port.get("mfs"):
dot3_max_frame = port["mfs"][0].get("value")
if port.get("power"):
power_mdi_support = port["power"][0].get("supported")
power_mdi_enabled = port["power"][0].get("enabled")
power_mdi_devicetype = port["power"][0].get("device-type")[0].get(
"value")
power_mdi_pairs = port["power"][0].get("pairs")[0].get("value")
power_mdi_class = port["power"][0].get("class")[0].get("value")
dot3_power_mdi = "power-mdi-supported="
if power_mdi_support:
dot3_power_mdi += "y,"
else:
dot3_power_mdi += "n,"
dot3_power_mdi += "power-mdi-enabled="
if power_mdi_enabled:
dot3_power_mdi += "y,"
else:
dot3_power_mdi += "n,"
if power_mdi_support and power_mdi_enabled:
dot3_power_mdi += "device-type=" + power_mdi_devicetype
dot3_power_mdi += ",pairs=" + power_mdi_pairs
dot3_power_mdi += ",class=" + power_mdi_class
vlans = None
if iface.get("vlan"):
vlans = iface.get("vlan")
if vlans:
dot1_vlan_names = ""
for vlan in vlans:
if vlan.get("pvid"):
dot1_port_vid = vlan.get("vlan-id")
continue
if dot1_vlan_names:
dot1_vlan_names += ", "
dot1_vlan_names += vlan.get("value")
ppvids = None
if iface.get("ppvids"):
ppvids = iface.get("ppvid")
if ppvids:
dot1_proto_vids = ""
for ppvid in ppvids:
if dot1_proto_vids:
dot1_proto_vids += ", "
dot1_proto_vids += ppvid.get("value")
pids = None
if iface.get("pi"):
pids = iface.get('pi')
dot1_proto_ids = ""
for id in pids:
if dot1_proto_ids:
dot1_proto_ids += ", "
dot1_proto_ids += id.get("value")
msap = chassis_id + "," + port_id
attrs = {"name_or_uuid": name_or_uuid,
constants.LLDP_TLV_TYPE_CHASSIS_ID: chassis_id,
constants.LLDP_TLV_TYPE_PORT_ID: port_id,
constants.LLDP_TLV_TYPE_TTL: ttl,
"msap": msap,
constants.LLDP_TLV_TYPE_SYSTEM_NAME: system_name,
constants.LLDP_TLV_TYPE_SYSTEM_DESC: system_desc,
constants.LLDP_TLV_TYPE_SYSTEM_CAP: capability,
constants.LLDP_TLV_TYPE_MGMT_ADDR: management_address,
constants.LLDP_TLV_TYPE_PORT_DESC: port_desc,
constants.LLDP_TLV_TYPE_DOT1_LAG: dot1_lag,
constants.LLDP_TLV_TYPE_DOT1_PORT_VID: dot1_port_vid,
constants.LLDP_TLV_TYPE_DOT1_VID_DIGEST: dot1_vid_digest,
constants.LLDP_TLV_TYPE_DOT1_MGMT_VID: dot1_mgmt_vid,
constants.LLDP_TLV_TYPE_DOT1_VLAN_NAMES: dot1_vlan_names,
constants.LLDP_TLV_TYPE_DOT1_PROTO_VIDS: dot1_proto_vids,
constants.LLDP_TLV_TYPE_DOT1_PROTO_IDS: dot1_proto_ids,
constants.LLDP_TLV_TYPE_DOT3_MAC_STATUS: dot3_mac_status,
constants.LLDP_TLV_TYPE_DOT3_MAX_FRAME: dot3_max_frame,
constants.LLDP_TLV_TYPE_DOT3_POWER_MDI: dot3_power_mdi}
return attrs
def lldpd_has_neighbour(self, name):
'''check if the interface has LLDP neighbours'''
p = subprocess.check_output(["lldpcli", "-f", "keyvalue", "show",
"neighbors", "summary", "ports", name])
return len(p) > 0
def lldpd_agent_list(self):
json_obj = json
lldp_agents = []
p = subprocess.Popen(["lldpcli", "-f", "json", "show", "interface",
"detail"], stdout=subprocess.PIPE)
data = json_obj.loads(p.communicate()[0])
lldp = data['lldp'][0]
if not lldp.get('interface'):
return lldp_agents
for iface in lldp['interface']:
agent_attrs = self.lldpd_get_attrs(iface)
status = self.lldpd_get_agent_status()
agent_attrs.update({"status": status})
agent = Agent(**agent_attrs)
lldp_agents.append(agent)
return lldp_agents
def lldpd_neighbour_list(self):
json_obj = json
lldp_neighbours = []
p = subprocess.Popen(["lldpcli", "-f", "json", "show", "neighbor",
"detail"], stdout=subprocess.PIPE)
data = json_obj.loads(p.communicate()[0])
lldp = data['lldp'][0]
if not lldp.get('interface'):
return lldp_neighbours
for iface in lldp['interface']:
neighbour_attrs = self.lldpd_get_attrs(iface)
neighbour = Neighbour(**neighbour_attrs)
lldp_neighbours.append(neighbour)
return lldp_neighbours
def _do_request(self, callable):
"""Thread safe wrapper for executing client requests.
"""
with self._lock:
return callable()
def _execute_lldp_request(self, callable, snat=None):
try:
return self._do_request(callable)
except Exception as e:
LOG.error("Failed to execute LLDP request: %s", str(e))
def vswitch_lldp_get_status(self, admin_status):
if admin_status == "enabled":
status = "rx=enabled,tx=enabled"
elif admin_status == "tx-only":
status = "rx=disabled,tx=enabled"
elif admin_status == "rx-only":
status = "rx=enabled,tx=disabled"
else:
status = "rx=disabled,tx=disabled"
return status
def vswitch_lldp_get_attrs(self, agent_neighbour_dict):
attrs = {}
vswitch_to_db_dict = {'local-chassis':
constants.LLDP_TLV_TYPE_CHASSIS_ID,
'local-port': constants.LLDP_TLV_TYPE_PORT_ID,
'remote-chassis':
constants.LLDP_TLV_TYPE_CHASSIS_ID,
'remote-port': constants.LLDP_TLV_TYPE_PORT_ID,
'tx-ttl': constants.LLDP_TLV_TYPE_TTL,
'rx-ttl': constants.LLDP_TLV_TYPE_TTL,
'system-name':
constants.LLDP_TLV_TYPE_SYSTEM_NAME,
'system-description':
constants.LLDP_TLV_TYPE_SYSTEM_DESC,
'port-description':
constants.LLDP_TLV_TYPE_PORT_DESC,
'system-capabilities':
constants.LLDP_TLV_TYPE_SYSTEM_CAP,
'management-address':
constants.LLDP_TLV_TYPE_MGMT_ADDR,
'dot1-lag': constants.LLDP_TLV_TYPE_DOT1_LAG,
'dot1-management-vid':
constants.LLDP_TLV_TYPE_DOT1_MGMT_VID,
'dot1-port-vid':
constants.LLDP_TLV_TYPE_DOT1_PORT_VID,
'dot1-proto-ids':
constants.LLDP_TLV_TYPE_DOT1_PROTO_IDS,
'dot1-proto-vids':
constants.LLDP_TLV_TYPE_DOT1_PROTO_VIDS,
'dot1-vid-digest':
constants.LLDP_TLV_TYPE_DOT1_VID_DIGEST,
'dot1-vlan-names':
constants.LLDP_TLV_TYPE_DOT1_VLAN_NAMES,
'dot3-lag':
constants.LLDP_TLV_TYPE_DOT1_LAG,
'dot3-mac-status':
constants.LLDP_TLV_TYPE_DOT3_MAC_STATUS,
'dot3-max-frame':
constants.LLDP_TLV_TYPE_DOT3_MAX_FRAME,
'dot3-power-mdi':
constants.LLDP_TLV_TYPE_DOT3_POWER_MDI}
for k, v in vswitch_to_db_dict.iteritems():
if k in agent_neighbour_dict:
if agent_neighbour_dict[k]:
attr = {v: agent_neighbour_dict[k]}
else:
attr = {v: None}
attrs.update(attr)
msap = attrs[constants.LLDP_TLV_TYPE_CHASSIS_ID] \
+ "," + attrs[constants.LLDP_TLV_TYPE_PORT_ID]
attr = {"name_or_uuid": agent_neighbour_dict["port-uuid"],
"msap": msap}
attrs.update(attr)
return attrs
def vswitch_lldp_agent_list(self):
"""Sends a request to the vswitch requesting the full list of LLDP agent
entries.
"""
LOG.error("vswitch_lldp_agent_list is not implemented.")
return []
def vswitch_lldp_neighbour_list(self):
"""Sends a request to the vswitch requesting the full list of LLDP
neighbour entries.
"""
LOG.error("vswitch_lldp_neighbour_ist s not implemented.")
return []
def lldp_agents_list(self, do_compute=False):
self.agent_audit_count += 1
if self.agent_audit_count > constants.LLDP_FULL_AUDIT_COUNT:
LOG.debug("LLDP agent audit: triggering full sync")
self.agent_audit_count = 0
self.lldp_agents_clear()
self.previous_agents = self.current_agents
self.current_agents = self.lldpd_agent_list()
if do_compute:
self.current_agents += self.vswitch_lldp_agent_list()
current = set(self.current_agents)
previous = set(self.previous_agents)
removed = previous - current
agent_array = []
for a in self.current_agents:
agent_array.append(a)
if removed:
for r in removed:
LOG.debug("LLDP agent audit: detected removed agent")
r.state = constants.LLDP_AGENT_STATE_REMOVED
agent_array.append(r)
return agent_array
# Check that there is actual state changes and return an empty list if
# nothing changed.
if self.previous_agents:
pairs = zip(sorted(current, key=attrgetter('key')),
sorted(previous, key=attrgetter('key')))
if not any(x != y for x, y in pairs):
LOG.debug("LLDP agent audit: No changes")
return []
return agent_array
def lldp_agents_clear(self):
self.current_agents = []
self.previous_agents = []
def lldp_neighbours_list(self, do_compute=False):
self.neighbour_audit_count += 1
if self.neighbour_audit_count > constants.LLDP_FULL_AUDIT_COUNT:
LOG.debug("LLDP neighbour audit: triggering full sync")
self.neighbour_audit_count = 0
self.lldp_neighbours_clear()
self.previous_neighbours = self.current_neighbours
self.current_neighbours = self.lldpd_neighbour_list()
if do_compute:
self.current_neighbours += self.vswitch_lldp_neighbour_list()
current = set(self.current_neighbours)
previous = set(self.previous_neighbours)
removed = previous - current
neighbour_array = []
for n in self.current_neighbours:
neighbour_array.append(n)
if removed:
for r in removed:
LOG.debug("LLDP neighbour audit: detected removed neighbour")
r.state = constants.LLDP_NEIGHBOUR_STATE_REMOVED
neighbour_array.append(r)
return neighbour_array
# Check that there is actual state changes and return an empty list if
# nothing changed.
if self.previous_neighbours:
pairs = zip(sorted(current, key=attrgetter('key')),
sorted(previous, key=attrgetter('key')))
if not any(x != y for x, y in pairs):
LOG.debug("LLDP neighbour audit: No changes")
return []
return neighbour_array
def lldp_neighbours_clear(self):
self.current_neighbours = []
self.previous_neighbours = []
def lldp_update_systemname(self, context, systemname, do_compute=False):
p = subprocess.Popen(["lldpcli", "-f", "json", "show", "chassis"],
stdout=subprocess.PIPE)
data = json.loads(p.communicate()[0])
local_chassis = data['local-chassis'][0]
chassis = local_chassis['chassis'][0]
name = chassis.get('name', None)
if name is None or not name[0].get("value"):
return
name = name[0]
hostname = name.get("value").partition(':')[0]
newname = hostname + ":" + systemname
p = subprocess.Popen(["lldpcli", "configure", "system", "hostname",
newname], stdout=subprocess.PIPE)
if do_compute:
LOG.error("lldp_update_systemname failed due to lack of vswitch")

View File

@ -0,0 +1,23 @@
#
# Copyright (c) 2018 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# All Rights Reserved.
#
from oslo_config import cfg
from oslo_utils._i18n import _
SYSINV_LLDP_OPTS = [
cfg.ListOpt('drivers',
default=['lldpd'],
help=_("An ordered list of sysinv LLDP driver "
"entrypoints to be loaded from the "
"sysinv.agent namespace.")),
]
cfg.CONF.register_opts(SYSINV_LLDP_OPTS, group="lldp")

View File

@ -0,0 +1,47 @@
#
# Copyright (c) 2018 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# All Rights Reserved.
#
import abc
import six
@six.add_metaclass(abc.ABCMeta)
class SysinvLldpDriverBase(object):
"""Sysinv LLDP Driver Base Class."""
@abc.abstractmethod
def lldp_has_neighbour(self, name):
pass
@abc.abstractmethod
def lldp_update(self):
pass
@abc.abstractmethod
def lldp_agents_list(self):
pass
@abc.abstractmethod
def lldp_neighbours_list(self):
pass
@abc.abstractmethod
def lldp_agents_clear(self):
pass
@abc.abstractmethod
def lldp_neighbours_clear(self):
pass
@abc.abstractmethod
def lldp_update_systemname(self, systemname):
pass

View File

@ -0,0 +1,321 @@
#
# Copyright (c) 2018 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# All Rights Reserved.
#
from oslo_log import log as logging
import simplejson as json
import subprocess
from sysinv.agent.lldp.drivers import base
from sysinv.agent.lldp import plugin
from sysinv.common import constants
LOG = logging.getLogger(__name__)
class SysinvLldpdAgentDriver(base.SysinvLldpDriverBase):
def __init__(self, **kwargs):
self.client = ""
self.agents = []
self.neighbours = []
self.current_neighbours = []
self.previous_neighbours = []
self.current_agents = []
self.previous_agents = []
self.agent_audit_count = 0
self.neighbour_audit_count = 0
def initialize(self):
self.__init__()
@staticmethod
def _lldpd_get_agent_status():
json_obj = json
p = subprocess.Popen(["lldpcli", "-f", "json", "show",
"configuration"],
stdout=subprocess.PIPE)
data = json_obj.loads(p.communicate()[0])
configuration = data['configuration'][0]
config = configuration['config'][0]
rx_only = config['rx-only'][0]
if rx_only.get("value") == "no":
return "rx=enabled,tx=enabled"
else:
return "rx=enabled,tx=disabled"
@staticmethod
def _lldpd_get_attrs(iface):
name_or_uuid = None
chassis_id = None
system_name = None
system_desc = None
capability = None
management_address = None
port_desc = None
dot1_lag = None
dot1_port_vid = None
dot1_vid_digest = None
dot1_mgmt_vid = None
dot1_vlan_names = None
dot1_proto_vids = None
dot1_proto_ids = None
dot3_mac_status = None
dot3_max_frame = None
dot3_power_mdi = None
ttl = None
attrs = {}
# Note: dot1_vid_digest, dot1_mgmt_vid are not currently supported
# by the lldpd daemon
name_or_uuid = iface.get("name")
chassis = iface.get("chassis")[0]
port = iface.get("port")[0]
if not chassis.get('id'):
return attrs
chassis_id = chassis['id'][0].get("value")
if not port.get('id'):
return attrs
port_id = port["id"][0].get("value")
if not port.get('ttl'):
return attrs
ttl = port['ttl'][0].get("value")
if chassis.get("name"):
system_name = chassis['name'][0].get("value")
if chassis.get("descr"):
system_desc = chassis['descr'][0].get("value")
if chassis.get("capability"):
capability = ""
for cap in chassis["capability"]:
if cap.get("enabled"):
if capability:
capability += ", "
capability += cap.get("type").lower()
if chassis.get("mgmt-ip"):
management_address = ""
for addr in chassis["mgmt-ip"]:
if management_address:
management_address += ", "
management_address += addr.get("value").lower()
if port.get("descr"):
port_desc = port["descr"][0].get("value")
if port.get("link-aggregation"):
dot1_lag_supported = port["link-aggregation"][0].get("supported")
dot1_lag_enabled = port["link-aggregation"][0].get("enabled")
dot1_lag = "capable="
if dot1_lag_supported:
dot1_lag += "y,"
else:
dot1_lag += "n,"
dot1_lag += "enabled="
if dot1_lag_enabled:
dot1_lag += "y"
else:
dot1_lag += "n"
if port.get("auto-negotiation"):
port_auto_neg_support = port["auto-negotiation"][0].get(
"supported")
port_auto_neg_enabled = port["auto-negotiation"][0].get("enabled")
dot3_mac_status = "auto-negotiation-capable="
if port_auto_neg_support:
dot3_mac_status += "y,"
else:
dot3_mac_status += "n,"
dot3_mac_status += "auto-negotiation-enabled="
if port_auto_neg_enabled:
dot3_mac_status += "y,"
else:
dot3_mac_status += "n,"
advertised = ""
if port.get("auto-negotiation")[0].get("advertised"):
for adv in port["auto-negotiation"][0].get("advertised"):
if advertised:
advertised += ", "
type = adv.get("type").lower()
if adv.get("hd") and not adv.get("fd"):
type += "hd"
elif adv.get("fd"):
type += "fd"
advertised += type
dot3_mac_status += advertised
if port.get("mfs"):
dot3_max_frame = port["mfs"][0].get("value")
if port.get("power"):
power_mdi_support = port["power"][0].get("supported")
power_mdi_enabled = port["power"][0].get("enabled")
power_mdi_devicetype = port["power"][0].get("device-type")[0].get(
"value")
power_mdi_pairs = port["power"][0].get("pairs")[0].get("value")
power_mdi_class = port["power"][0].get("class")[0].get("value")
dot3_power_mdi = "power-mdi-supported="
if power_mdi_support:
dot3_power_mdi += "y,"
else:
dot3_power_mdi += "n,"
dot3_power_mdi += "power-mdi-enabled="
if power_mdi_enabled:
dot3_power_mdi += "y,"
else:
dot3_power_mdi += "n,"
if power_mdi_support and power_mdi_enabled:
dot3_power_mdi += "device-type=" + power_mdi_devicetype
dot3_power_mdi += ",pairs=" + power_mdi_pairs
dot3_power_mdi += ",class=" + power_mdi_class
vlans = None
if iface.get("vlan"):
vlans = iface.get("vlan")
if vlans:
dot1_vlan_names = ""
for vlan in vlans:
if vlan.get("pvid"):
dot1_port_vid = vlan.get("vlan-id")
continue
if dot1_vlan_names:
dot1_vlan_names += ", "
dot1_vlan_names += vlan.get("value")
ppvids = None
if iface.get("ppvids"):
ppvids = iface.get("ppvid")
if ppvids:
dot1_proto_vids = ""
for ppvid in ppvids:
if dot1_proto_vids:
dot1_proto_vids += ", "
dot1_proto_vids += ppvid.get("value")
pids = None
if iface.get("pi"):
pids = iface.get('pi')
dot1_proto_ids = ""
for id in pids:
if dot1_proto_ids:
dot1_proto_ids += ", "
dot1_proto_ids += id.get("value")
msap = chassis_id + "," + port_id
attrs = {"name_or_uuid": name_or_uuid,
constants.LLDP_TLV_TYPE_CHASSIS_ID: chassis_id,
constants.LLDP_TLV_TYPE_PORT_ID: port_id,
constants.LLDP_TLV_TYPE_TTL: ttl,
"msap": msap,
constants.LLDP_TLV_TYPE_SYSTEM_NAME: system_name,
constants.LLDP_TLV_TYPE_SYSTEM_DESC: system_desc,
constants.LLDP_TLV_TYPE_SYSTEM_CAP: capability,
constants.LLDP_TLV_TYPE_MGMT_ADDR: management_address,
constants.LLDP_TLV_TYPE_PORT_DESC: port_desc,
constants.LLDP_TLV_TYPE_DOT1_LAG: dot1_lag,
constants.LLDP_TLV_TYPE_DOT1_PORT_VID: dot1_port_vid,
constants.LLDP_TLV_TYPE_DOT1_VID_DIGEST: dot1_vid_digest,
constants.LLDP_TLV_TYPE_DOT1_MGMT_VID: dot1_mgmt_vid,
constants.LLDP_TLV_TYPE_DOT1_VLAN_NAMES: dot1_vlan_names,
constants.LLDP_TLV_TYPE_DOT1_PROTO_VIDS: dot1_proto_vids,
constants.LLDP_TLV_TYPE_DOT1_PROTO_IDS: dot1_proto_ids,
constants.LLDP_TLV_TYPE_DOT3_MAC_STATUS: dot3_mac_status,
constants.LLDP_TLV_TYPE_DOT3_MAX_FRAME: dot3_max_frame,
constants.LLDP_TLV_TYPE_DOT3_POWER_MDI: dot3_power_mdi}
return attrs
def lldp_has_neighbour(self, name):
p = subprocess.check_output(["lldpcli", "-f", "keyvalue", "show",
"neighbors", "summary", "ports", name])
return len(p) > 0
def lldp_update(self):
subprocess.call(['lldpcli', 'update'])
def lldp_agents_list(self):
json_obj = json
lldp_agents = []
p = subprocess.Popen(["lldpcli", "-f", "json", "show", "interface",
"detail"], stdout=subprocess.PIPE)
data = json_obj.loads(p.communicate()[0])
lldp = data['lldp'][0]
if not lldp.get('interface'):
return lldp_agents
for iface in lldp['interface']:
agent_attrs = self._lldpd_get_attrs(iface)
status = self._lldpd_get_agent_status()
agent_attrs.update({"status": status})
agent = plugin.Agent(**agent_attrs)
lldp_agents.append(agent)
return lldp_agents
def lldp_agents_clear(self):
self.current_agents = []
self.previous_agents = []
def lldp_neighbours_list(self):
json_obj = json
lldp_neighbours = []
p = subprocess.Popen(["lldpcli", "-f", "json", "show", "neighbor",
"detail"], stdout=subprocess.PIPE)
data = json_obj.loads(p.communicate()[0])
lldp = data['lldp'][0]
if not lldp.get('interface'):
return lldp_neighbours
for iface in lldp['interface']:
neighbour_attrs = self._lldpd_get_attrs(iface)
neighbour = plugin.Neighbour(**neighbour_attrs)
lldp_neighbours.append(neighbour)
return lldp_neighbours
def lldp_neighbours_clear(self):
self.current_neighbours = []
self.previous_neighbours = []
def lldp_update_systemname(self, systemname):
p = subprocess.Popen(["lldpcli", "-f", "json", "show", "chassis"],
stdout=subprocess.PIPE)
data = json.loads(p.communicate()[0])
local_chassis = data['local-chassis'][0]
chassis = local_chassis['chassis'][0]
name = chassis.get('name', None)
if name is None or not name[0].get("value"):
return
name = name[0]
hostname = name.get("value").partition(':')[0]
newname = hostname + ":" + systemname
p = subprocess.Popen(["lldpcli", "configure", "system", "hostname",
newname], stdout=subprocess.PIPE)

View File

@ -0,0 +1,166 @@
#
# Copyright (c) 2018 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# All Rights Reserved.
#
import simplejson as json
import subprocess
from oslo_log import log as logging
from sysinv.agent.lldp.drivers.lldpd import driver as lldpd_driver
from sysinv.common import constants
LOG = logging.getLogger(__name__)
class SysinvOVSAgentDriver(lldpd_driver.SysinvLldpdAgentDriver):
def run_cmd(self, cmd):
p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
p.wait()
output, error = p.communicate()
if p.returncode != 0:
LOG.error("Failed to run command %s: error: %s", cmd, error)
return None
return output
def lldp_ovs_get_interface_port_map(self):
interface_port_map = {}
cmd = "ovs-vsctl --timeout 10 --format json "\
"--columns name,_uuid,interfaces list Port"
output = self.run_cmd(cmd)
if not output:
return
ports = json.loads(output)
ports = ports['data']
for port in ports:
port_uuid = port[1][1]
interfaces = port[2][1]
if isinstance(interfaces, list):
for interface in interfaces:
interface_uuid = interface[1]
interface_port_map[interface_uuid] = port_uuid
else:
interface_uuid = interfaces
interface_port_map[interface_uuid] = port_uuid
return interface_port_map
def lldp_ovs_get_port_bridge_map(self):
port_bridge_map = {}
cmd = "ovs-vsctl --timeout 10 --format json "\
"--columns name,ports list Bridge"
output = self.run_cmd(cmd)
if not output:
return
bridges = json.loads(output)
bridges = bridges['data']
for bridge in bridges:
bridge_name = bridge[0]
port_set = bridge[1][1]
for port in port_set:
value = port[1]
port_bridge_map[value] = bridge_name
return port_bridge_map
def lldp_ovs_lldp_flow_exists(self, brname, in_port):
cmd = "ovs-ofctl dump-flows {} in_port={},dl_dst={},dl_type={}".format(
brname, in_port, constants.LLDP_MULTICAST_ADDRESS,
constants.LLDP_ETHER_TYPE)
output = self.run_cmd(cmd)
if not output:
return None
return (output.count("\n") > 1)
def lldp_ovs_add_flows(self, brname, in_port, out_port):
cmd = ("ovs-ofctl add-flow {} in_port={},dl_dst={},dl_type={},"
"actions=output:{}".format(
brname, in_port, constants.LLDP_MULTICAST_ADDRESS,
constants.LLDP_ETHER_TYPE, out_port))
output = self.run_cmd(cmd)
if not output:
return
cmd = ("ovs-ofctl add-flow {} in_port={},dl_dst={},dl_type={},"
"actions=output:{}".format(
brname, out_port, constants.LLDP_MULTICAST_ADDRESS,
constants.LLDP_ETHER_TYPE, in_port))
output = self.run_cmd(cmd)
if not output:
return
def lldp_ovs_update_flows(self):
port_bridge_map = self.lldp_ovs_get_port_bridge_map()
if not port_bridge_map:
return
interface_port_map = self.lldp_ovs_get_interface_port_map()
if not interface_port_map:
return
cmd = "ovs-vsctl --timeout 10 --format json "\
"--columns name,_uuid,type,other_config list Interface"
output = self.run_cmd(cmd)
if not output:
return
data = json.loads(output)
data = data['data']
for interface in data:
name = interface[0]
uuid = interface[1][1]
type = interface[2]
other_config = interface[3]
if type != 'internal':
continue
config_map = other_config[1]
for config in config_map:
key = config[0]
value = config[1]
if key != 'lldp_phy_peer':
continue
phy_peer = value
brname = port_bridge_map[interface_port_map[uuid]]
if not self.lldp_ovs_lldp_flow_exists(brname, name):
LOG.info("Adding missing LLDP flow from %s to %s",
name, phy_peer)
self.lldp_ovs_add_flows(brname, name, phy_peer)
if not self.lldp_ovs_lldp_flow_exists(brname, value):
LOG.info("Adding missing LLDP flow from %s to %s",
phy_peer, name)
self.lldp_ovs_add_flows(brname, phy_peer, name)
def lldp_agents_list(self):
self.lldp_ovs_update_flows()
return lldpd_driver.SysinvLldpdAgentDriver.lldp_agents_list(self)
def lldp_neighbours_list(self):
self.lldp_ovs_update_flows()
return lldpd_driver.SysinvLldpdAgentDriver.lldp_neighbours_list(self)

View File

@ -0,0 +1,176 @@
#
# Copyright (c) 2018 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# All Rights Reserved.
#
from oslo_config import cfg
from oslo_log import log
from stevedore.named import NamedExtensionManager
from sysinv.common import exception
LOG = log.getLogger(__name__)
cfg.CONF.import_opt('drivers',
'sysinv.agent.lldp.config',
group='lldp')
class SysinvLldpDriverManager(NamedExtensionManager):
"""Implementation of Sysinv LLDP drivers."""
def __init__(self, namespace='sysinv.agent.lldp.drivers'):
# Registered sysinv lldp agent drivers, keyed by name.
self.drivers = {}
# Ordered list of sysinv lldp agent drivers, defining
# the order in which the drivers are called.
self.ordered_drivers = []
names = cfg.CONF.lldp.drivers
LOG.info("Configured sysinv LLDP agent drivers: %s", names)
super(SysinvLldpDriverManager, self).__init__(
namespace,
names,
invoke_on_load=True,
name_order=True)
LOG.info("Loaded sysinv LLDP agent drivers: %s", self.names())
self._register_drivers()
def _register_drivers(self):
"""Register all sysinv LLDP agent drivers.
This method should only be called once in the
SysinvLldpDriverManager constructor.
"""
for ext in self:
self.drivers[ext.name] = ext
self.ordered_drivers.append(ext)
LOG.info("Registered sysinv LLDP agent drivers: %s",
[driver.name for driver in self.ordered_drivers])
def _call_drivers_and_return_array(self, method_name, attr=None,
raise_orig_exc=False):
"""Helper method for calling a method across all drivers.
:param method_name: name of the method to call
:param attr: an optional attribute to provide to the drivers
:param raise_orig_exc: whether or not to raise the original
driver exception, or use a general one
"""
ret = []
for driver in self.ordered_drivers:
try:
method = getattr(driver.obj, method_name)
if attr:
ret = ret + method(attr)
else:
ret = ret + method()
except Exception as e:
LOG.exception(e)
LOG.error(
"Sysinv LLDP agent driver '%(name)s' "
"failed in %(method)s",
{'name': driver.name, 'method': method_name}
)
if raise_orig_exc:
raise
else:
raise exception.LLDPDriverError(
method=method_name
)
return list(set(ret))
def _call_drivers(self, method_name, attr=None, raise_orig_exc=False):
"""Helper method for calling a method across all drivers.
:param method_name: name of the method to call
:param attr: an optional attribute to provide to the drivers
:param raise_orig_exc: whether or not to raise the original
driver exception, or use a general one
"""
for driver in self.ordered_drivers:
try:
method = getattr(driver.obj, method_name)
if attr:
return method(attr)
else:
return method()
except Exception as e:
LOG.exception(e)
LOG.error(
"Sysinv LLDP agent driver '%(name)s' "
"failed in %(method)s",
{'name': driver.name, 'method': method_name}
)
if raise_orig_exc:
raise
else:
raise exception.LLDPDriverError(
method=method_name
)
def lldp_has_neighbour(self, name):
try:
return self._call_drivers("lldp_has_neighbour",
attr=name,
raise_orig_exc=True)
except Exception as e:
LOG.exception(e)
return []
def lldp_update(self):
try:
return self._call_drivers("lldp_update",
raise_orig_exc=True)
except Exception as e:
LOG.exception(e)
return []
def lldp_agents_list(self):
try:
return self._call_drivers_and_return_array("lldp_agents_list",
raise_orig_exc=True)
except Exception as e:
LOG.exception(e)
return []
def lldp_neighbours_list(self):
try:
return self._call_drivers_and_return_array("lldp_neighbours_list",
raise_orig_exc=True)
except Exception as e:
LOG.exception(e)
return []
def lldp_agents_clear(self):
try:
return self._call_drivers("lldp_agents_clear",
raise_orig_exc=True)
except Exception as e:
LOG.exception(e)
return
def lldp_neighbours_clear(self):
try:
return self._call_drivers("lldp_neighbours_clear",
raise_orig_exc=True)
except Exception as e:
LOG.exception(e)
return
def lldp_update_systemname(self, systemname):
try:
return self._call_drivers("lldp_update_systemname",
attr=systemname,
raise_orig_exc=True)
except Exception as e:
LOG.exception(e)
return

View File

@ -0,0 +1,245 @@
#
# Copyright (c) 2018 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# All Rights Reserved.
#
from oslo_log import log as logging
from sysinv.agent.lldp import manager
from sysinv.common import exception
from sysinv.common import constants
from sysinv.openstack.common import excutils
LOG = logging.getLogger(__name__)
class Key(object):
def __init__(self, chassisid, portid, portname):
self.chassisid = chassisid
self.portid = portid
self.portname = portname
def __hash__(self):
return hash((self.chassisid, self.portid, self.portname))
def __cmp__(self, rhs):
return (cmp(self.chassisid, rhs.chassisid) or
cmp(self.portid, rhs.portid) or
cmp(self.portname, rhs.portname))
def __eq__(self, rhs):
return (self.chassisid == rhs.chassisid and
self.portid == rhs.portid and
self.portname == rhs.portname)
def __ne__(self, rhs):
return (self.chassisid != rhs.chassisid or
self.portid != rhs.portid or
self.portname != rhs.portname)
def __str__(self):
return "%s [%s] [%s]" % (self.portname, self.chassisid, self.portid)
def __repr__(self):
return "<Key '%s'>" % str(self)
class Agent(object):
'''Class to encapsulate LLDP agent data for System Inventory'''
def __init__(self, **kwargs):
'''Construct an Agent object with the given values.'''
self.key = Key(kwargs.get(constants.LLDP_TLV_TYPE_CHASSIS_ID),
kwargs.get(constants.LLDP_TLV_TYPE_PORT_ID),
kwargs.get("name_or_uuid"))
self.status = kwargs.get('status')
self.ttl = kwargs.get(constants.LLDP_TLV_TYPE_TTL)
self.system_name = kwargs.get(constants.LLDP_TLV_TYPE_SYSTEM_NAME)
self.system_desc = kwargs.get(constants.LLDP_TLV_TYPE_SYSTEM_DESC)
self.port_desc = kwargs.get(constants.LLDP_TLV_TYPE_PORT_DESC)
self.capabilities = kwargs.get(constants.LLDP_TLV_TYPE_SYSTEM_CAP)
self.mgmt_addr = kwargs.get(constants.LLDP_TLV_TYPE_MGMT_ADDR)
self.dot1_lag = kwargs.get(constants.LLDP_TLV_TYPE_DOT1_LAG)
self.dot1_vlan_names = kwargs.get(
constants.LLDP_TLV_TYPE_DOT1_VLAN_NAMES)
self.dot3_max_frame = kwargs.get(
constants.LLDP_TLV_TYPE_DOT3_MAX_FRAME)
self.state = None
def __hash__(self):
return self.key.__hash__()
def __eq__(self, rhs):
return (self.key == rhs.key)
def __ne__(self, rhs):
return (self.key != rhs.key or
self.status != rhs.status or
self.ttl != rhs.ttl or
self.system_name != rhs.system_name or
self.system_desc != rhs.system_desc or
self.port_desc != rhs.port_desc or
self.capabilities != rhs.capabilities or
self.mgmt_addr != rhs.mgmt_addr or
self.dot1_lag != rhs.dot1_lag or
self.dot1_vlan_names != rhs.dot1_vlan_names or
self.dot3_max_frame != rhs.dot3_max_frame or
self.state != rhs.state)
def __str__(self):
return "%s: [%s] [%s] [%s], [%s], [%s], [%s], [%s], [%s]" % (
self.key, self.status, self.system_name, self.system_desc,
self.port_desc, self.capabilities,
self.mgmt_addr, self.dot1_lag,
self.dot3_max_frame)
def __repr__(self):
return "<Agent '%s'>" % str(self)
class Neighbour(object):
'''Class to encapsulate LLDP neighbour data for System Inventory'''
def __init__(self, **kwargs):
'''Construct an Neighbour object with the given values.'''
self.key = Key(kwargs.get(constants.LLDP_TLV_TYPE_CHASSIS_ID),
kwargs.get(constants.LLDP_TLV_TYPE_PORT_ID),
kwargs.get("name_or_uuid"))
self.msap = kwargs.get('msap')
self.ttl = kwargs.get(constants.LLDP_TLV_TYPE_TTL)
self.system_name = kwargs.get(constants.LLDP_TLV_TYPE_SYSTEM_NAME)
self.system_desc = kwargs.get(constants.LLDP_TLV_TYPE_SYSTEM_DESC)
self.port_desc = kwargs.get(constants.LLDP_TLV_TYPE_PORT_DESC)
self.capabilities = kwargs.get(constants.LLDP_TLV_TYPE_SYSTEM_CAP)
self.mgmt_addr = kwargs.get(constants.LLDP_TLV_TYPE_MGMT_ADDR)
self.dot1_port_vid = kwargs.get(constants.LLDP_TLV_TYPE_DOT1_PORT_VID)
self.dot1_vid_digest = kwargs.get(
constants.LLDP_TLV_TYPE_DOT1_VID_DIGEST)
self.dot1_mgmt_vid = kwargs.get(constants.LLDP_TLV_TYPE_DOT1_MGMT_VID)
self.dot1_vid_digest = kwargs.get(
constants.LLDP_TLV_TYPE_DOT1_VID_DIGEST)
self.dot1_mgmt_vid = kwargs.get(constants.LLDP_TLV_TYPE_DOT1_MGMT_VID)
self.dot1_lag = kwargs.get(constants.LLDP_TLV_TYPE_DOT1_LAG)
self.dot1_vlan_names = kwargs.get(
constants.LLDP_TLV_TYPE_DOT1_VLAN_NAMES)
self.dot1_proto_vids = kwargs.get(
constants.LLDP_TLV_TYPE_DOT1_PROTO_VIDS)
self.dot1_proto_ids = kwargs.get(
constants.LLDP_TLV_TYPE_DOT1_PROTO_IDS)
self.dot3_mac_status = kwargs.get(
constants.LLDP_TLV_TYPE_DOT3_MAC_STATUS)
self.dot3_max_frame = kwargs.get(
constants.LLDP_TLV_TYPE_DOT3_MAX_FRAME)
self.dot3_power_mdi = kwargs.get(
constants.LLDP_TLV_TYPE_DOT3_POWER_MDI)
self.state = None
def __hash__(self):
return self.key.__hash__()
def __eq__(self, rhs):
return (self.key == rhs.key)
def __ne__(self, rhs):
return (self.key != rhs.key or
self.msap != rhs.msap or
self.system_name != rhs.system_name or
self.system_desc != rhs.system_desc or
self.port_desc != rhs.port_desc or
self.capabilities != rhs.capabilities or
self.mgmt_addr != rhs.mgmt_addr or
self.dot1_port_vid != rhs.dot1_port_vid or
self.dot1_vid_digest != rhs.dot1_vid_digest or
self.dot1_mgmt_vid != rhs.dot1_mgmt_vid or
self.dot1_vid_digest != rhs.dot1_vid_digest or
self.dot1_mgmt_vid != rhs.dot1_mgmt_vid or
self.dot1_lag != rhs.dot1_lag or
self.dot1_vlan_names != rhs.dot1_vlan_names or
self.dot1_proto_vids != rhs.dot1_proto_vids or
self.dot1_proto_ids != rhs.dot1_proto_ids or
self.dot3_mac_status != rhs.dot3_mac_status or
self.dot3_max_frame != rhs.dot3_max_frame or
self.dot3_power_mdi != rhs.dot3_power_mdi)
def __str__(self):
return "%s [%s] [%s] [%s], [%s]" % (
self.key, self.system_name, self.system_desc,
self.port_desc, self.capabilities)
def __repr__(self):
return "<Neighbour '%s'>" % str(self)
class SysinvLldpPlugin():
"""Implementation of the Plugin."""
def __init__(self):
self.manager = manager.SysinvLldpDriverManager()
def lldp_has_neighbour(self, name):
try:
return self.manager.lldp_has_neighbour(name)
except exception.LLDPDriverError as e:
LOG.exception(e)
with excutils.save_and_reraise_exception():
LOG.error("LLDP has neighbour failed")
def lldp_update(self):
try:
self.manager.lldp_update()
except exception.LLDPDriverError as e:
LOG.exception(e)
with excutils.save_and_reraise_exception():
LOG.error("LLDP update failed")
def lldp_agents_list(self):
try:
agents = self.manager.lldp_agents_list()
except exception.LLDPDriverError as e:
LOG.exception(e)
with excutils.save_and_reraise_exception():
LOG.error("LLDP agents list failed")
return agents
def lldp_agents_clear(self):
try:
self.manager.lldp_agents_clear()
except exception.LLDPDriverError as e:
LOG.exception(e)
with excutils.save_and_reraise_exception():
LOG.error("LLDP agents clear failed")
def lldp_neighbours_list(self):
try:
neighbours = self.manager.lldp_neighbours_list()
except exception.LLDPDriverError as e:
LOG.exception(e)
with excutils.save_and_reraise_exception():
LOG.error("LLDP neighbours list failed")
return neighbours
def lldp_neighbours_clear(self):
try:
self.manager.lldp_neighbours_clear()
except exception.LLDPDriverError as e:
LOG.exception(e)
with excutils.save_and_reraise_exception():
LOG.error("LLDP neighbours clear failed")
def lldp_update_systemname(self, systemname):
try:
self.manager.lldp_update_systemname(systemname)
except exception.LLDPDriverError as e:
LOG.exception(e)
with excutils.save_and_reraise_exception():
LOG.error("LLDP update systemname failed")

View File

@ -53,7 +53,7 @@ from sysinv.agent import pv
from sysinv.agent import lvg
from sysinv.agent import pci
from sysinv.agent import node
from sysinv.agent import lldp
from sysinv.agent.lldp import plugin as lldp_plugin
from sysinv.common import constants
from sysinv.common import exception
from sysinv.common import service
@ -138,7 +138,7 @@ class AgentManager(service.PeriodicService):
self._ipv_operator = pv.PVOperator()
self._ipartition_operator = partition.PartitionOperator()
self._ilvg_operator = lvg.LVGOperator()
self._lldp_operator = lldp.LLDPOperator()
self._lldp_operator = lldp_plugin.SysinvLldpPlugin()
self._iconfig_read_config_reported = None
self._ihost_personality = None
self._ihost_uuid = ""
@ -363,10 +363,8 @@ class AgentManager(service.PeriodicService):
neighbours = []
agents = []
do_compute = constants.COMPUTE in self.subfunctions_list_get()
try:
neighbours = self._lldp_operator.lldp_neighbours_list(do_compute)
neighbours = self._lldp_operator.lldp_neighbours_list()
except Exception as e:
LOG.error("Failed to get LLDP neighbours: %s", str(e))
@ -408,7 +406,7 @@ class AgentManager(service.PeriodicService):
pass
try:
agents = self._lldp_operator.lldp_agents_list(do_compute)
agents = self._lldp_operator.lldp_agents_list()
except Exception as e:
LOG.error("Failed to get LLDP agents: %s", str(e))
@ -470,7 +468,8 @@ class AgentManager(service.PeriodicService):
subprocess.call(['ip', 'link', 'set', interface, 'up'])
links_down.append(interface)
LOG.info('interface %s enabled to receive LLDP PDUs' % interface)
subprocess.call(['lldpcli', 'update'])
self._lldp_operator.lldp_update()
# delay maximum 30 seconds for lldpd to receive LLDP PDU
timeout = 0
link_wait_for_lldp = True
@ -478,8 +477,9 @@ class AgentManager(service.PeriodicService):
time.sleep(5)
timeout = timeout + 5
link_wait_for_lldp = False
for link in links_down:
if not self._lldp_operator.lldpd_has_neighbour(link):
if not self._lldp_operator.lldp_has_neighbour(link):
link_wait_for_lldp = True
break
self.host_lldp_get_and_report(context, rpcapi, host_uuid)
@ -1261,12 +1261,10 @@ class AgentManager(service.PeriodicService):
:param systemname: the systemname
"""
do_compute = constants.COMPUTE in self.subfunctions_list_get()
rpcapi = conductor_rpcapi.ConductorAPI(
topic=conductor_rpcapi.MANAGER_TOPIC)
# Update the lldp agent
self._lldp_operator.lldp_update_systemname(context, systemname,
do_compute)
self._lldp_operator.lldp_update_systemname(systemname)
# Trigger an audit to ensure the db is up to date
self.host_lldp_get_and_report(context, rpcapi, self._ihost_uuid)

View File

@ -566,6 +566,10 @@ class LLDPTlvExists(Conflict):
message = _("An LLDP TLV with type %(type) already exists.")
class LLDPDriverError(Conflict):
message = _("An LLDP driver error has occurred. method=%(method)")
class SDNControllerAlreadyExists(Conflict):
message = _("An SDN Controller with uuid %(uuid)s already exists.")