Enable LLDP information on initial install

Periodically turn on network interfaces to collect LLDP information.
This fix enables LLDP neighbor collection before node unlock. The
interfaces retore to their original states after LLDP information
collection. During LLDP collection time, /var/apply_network_config.lock
is locked.

Once the node is unlocked, the new LLDP collection method no longer
executes.

Story: 2002851
Task: 22800

Change-Id: I74452ba0fdd0342a6fa09767448a6777052ce953
Signed-off-by: Jack Ding <jack.ding@windriver.com>
This commit is contained in:
Jianqiang Shi 2018-06-26 13:29:38 -04:00 committed by Jack Ding
parent 3347cd311a
commit 767988e440
3 changed files with 76 additions and 3 deletions

View File

@ -402,6 +402,12 @@ class LLDPOperator(object):
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 = []

View File

@ -438,6 +438,55 @@ class AgentManager(service.PeriodicService):
self._lldp_operator.lldp_agents_clear()
pass
def synchronized_network_config(func):
""" Synchronization decorator to acquire and release
network_config_lock.
"""
def wrap(self, *args, **kwargs):
try:
# Get lock to avoid conflict with apply_network_config.sh
lockfd = self._acquire_network_config_lock()
return func(self, *args, **kwargs)
finally:
self._release_network_config_lock(lockfd)
return wrap
@synchronized_network_config
def _lldp_enable_and_report(self, context, rpcapi, host_uuid):
""" Temporarily enable interfaces and get lldp neighbor information.
This method should only be called before
INITIAL_CONFIG_COMPLETE_FLAG is set.
"""
link_down = []
try:
# Turn on interfaces, so that lldpd can show all neighbors
for interface in self._ipci_operator.pci_get_net_names():
flag = self._ipci_operator.pci_get_net_flags(interface)
# If administrative state is down, bring it up momentarily
if not (flag & pci.IFF_UP):
subprocess.call(['ip', 'link', 'set', interface, 'up'])
link_down.append(interface)
LOG.info('interface %s enabled to receive LLDP PDUs' % interface)
subprocess.call(['lldpcli', 'update'])
# delay maximum 30 seconds for lldpd to receive LLDP PDU
timeout = 0
passed = 0
while timeout < 30 and passed < len(link_down):
time.sleep(5)
timeout = timeout + 5
# Count the number of interfaces that have collected LLDP neighbors.
m = map(lambda link: self._lldp_operator.lldpd_has_neighbour(link), link_down)
passed = reduce(lambda x, y: x + 1 if y else x, m)
self.host_lldp_get_and_report(context, rpcapi, host_uuid)
except Exception as e:
LOG.exception(e)
pass
finally:
# restore interface administrative state
for interface in link_down:
subprocess.call(['ip', 'link', 'set', interface, 'down'])
LOG.info('interface %s disabled after querying LLDP neighbors' % interface)
def platform_update_by_host(self, rpcapi, context, host_uuid, msg_dict):
""" Update host platform information.
If this is the first boot (kickstart), then also update the Host
@ -1077,7 +1126,10 @@ class AgentManager(service.PeriodicService):
rpcapi.imemory_update_by_ihost(icontext,
self._ihost_uuid,
imemory)
self.host_lldp_get_and_report(icontext, rpcapi, self._ihost_uuid)
if os.path.isfile(tsc.INITIAL_CONFIG_COMPLETE_FLAG):
self.host_lldp_get_and_report(icontext, rpcapi, self._ihost_uuid)
else:
self._lldp_enable_and_report(icontext, rpcapi, self._ihost_uuid)
self._agent_throttle += 1
if self._ihost_personality == constants.CONTROLLER:

View File

@ -399,8 +399,7 @@ class PCIOperator(object):
"sub-directories".format(pciaddr))
return results[0]
def _get_netdev_flags(self, dirpcinet, pci):
fflags = dirpcinet + pci + '/' + "flags"
def _read_flags(self, fflags):
try:
with open(fflags, 'r') as f:
hex_str = f.readline().rstrip()
@ -409,6 +408,22 @@ class PCIOperator(object):
flags = None
return flags
def _get_netdev_flags(self, dirpcinet, pci):
fflags = dirpcinet + pci + '/flags'
return self._read_flags(fflags)
def pci_get_net_flags(self, name):
fflags = '/sys/class/net/' + name + '/flags'
return self._read_flags(fflags)
def pci_get_net_names(self):
'''build a list of network device names.'''
names = []
for name in os.listdir('/sys/class/net/'):
if os.path.isdir('/sys/class/net/' + name):
names.append(name)
return names
def pci_get_net_attrs(self, pciaddr):
''' For this pciaddr, build a list of network attributes per port '''
pci_attrs_array = []