Skip to content

[lldp_syncd] add new OIDs - lldpRemTable & lldpLocPortTable #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jul 18, 2018

Conversation

mykolaf
Copy link
Contributor

@mykolaf mykolaf commented Jul 4, 2018

What I did:
Add support for lldpLocPortTable and lldpRemTable OIDs:

Also requires merge of sonic-net/sonic-snmpagent#70

OID SNMP counter Description
1.0.8802.1.1.2.1.3.7 lldpLocPortTable  
1.0.8802.1.1.2.1.3.7.1 lldpLocPortEntry  
1.0.8802.1.1.2.1.3.7.1.1 lldpLocPortNum The index value used to identify the port component (contained in the local chassis with the LLDP agent) associated with this entry
1.0.8802.1.1.2.1.3.7.1.2 lldpLocPortIdSubtype The type of port identifier encoding used in the associated 'lldpLocPortId' object
1.0.8802.1.1.2.1.3.7.1.4 lldpLocPortDesc The string value used to identify the 802 LAN station's port description associated with the local system. If the local agent supports IETF RFC 2863, lldpLocPortDesc object should have the same value of ifDescr object
OID SNMP counter Description
1.0.8802.1.1.2.1.4.1 lldpRemTable  
1.0.8802.1.1.2.1.4.1.1 lldpRemEntry  
1.0.8802.1.1.2.1.4.1.1.2 lldpRemLocalPortNum The index value used to identify the port component associated with this entry. The lldpRemLocalPortNum identifies the port on which the remote system information is received
1.0.8802.1.1.2.1.4.1.1.3 lldpRemIndex This object represents an arbitrary local integer value used by this agent to identify a particular connection instance, unique only for the indicated remote system
1.0.8802.1.1.2.1.4.1.1.11 lldpRemSysCapSupported The bitmap value used to identify which system capabilities are supported on the remote system
1.0.8802.1.1.2.1.4.1.1.12 lldpRemSysCapEnabled The bitmap value used to identify which system capabilities are enabled

@andriymoroz-mlnx
Copy link

andriymoroz-mlnx commented Jul 10, 2018

Hi @qiluo-msft,
could you please review this PR too?
it is related to sonic-net/sonic-snmpagent#70 #Closed

@lguohan
Copy link
Contributor

lguohan commented Jul 11, 2018

@pavel-shirshov , can you also review it.

@qiluo-msft
Copy link
Contributor

qiluo-msft commented Jul 16, 2018

Could you help resolve the conflict first? Be aware there is changes on test data, which we found in prod environment. #Closed

@@ -56,7 +56,7 @@ class LldpSyncDaemon(SonicSyncDaemon):
within the same Redis instance on a switch
"""
LLDP_ENTRY_TABLE = 'LLDP_ENTRY_TABLE'

LLDP_LOC_CHASSIS_TABLE = 'LLDP_LOC_CHASSIS'
@unique
Copy link
Contributor

@qiluo-msft qiluo-msft Jul 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you check the code format with some python lint tool? At least there are some new errors reported by http://pep8online.com/
#Closed

Copy link
Contributor Author

@mykolaf mykolaf Jul 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked with flake8, with max line length=100.
As far as i know we don't have a set of rules for code style yet. #Closed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's ok to have wide lines. thanks


In reply to: 203114714 [](ancestors = 203114714)

# [{'enabled': ..., 'type': 'capability1'}, {'enabled': ..., 'type': 'capability2'}]
capability_list = if_attributes['chassis'].values()[0]['capability']
except KeyError:
logger.error("Failed to get system capabilities")
Copy link
Contributor

@qiluo-msft qiluo-msft Jul 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logger [](start = 12, length = 6)

After logging, it continue with below logic, which seems not correct for this path. #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 124-125 covers the case when we have only 1 capability in the list, it should be above the except case. Fixed this.

return None
else:
def scrap_output(cmd):
try:
Copy link
Contributor

@qiluo-msft qiluo-msft Jul 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try [](start = 12, length = 3)

Original 2 try-except blocks are better. #Closed

Copy link
Contributor

@qiluo-msft qiluo-msft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As comments.

# [{'enabled': ..., 'type': 'capability1'}, {'enabled': ..., 'type': 'capability2'}]
capability_list = if_attributes['chassis'].values()[0]['capability']
# {'enabled': ..., 'type': 'capability'}
if not isinstance(capability_list, list):
Copy link
Contributor

@qiluo-msft qiluo-msft Jul 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

capability_list [](start = 30, length = 15)

Is this case ever possible? If not, just return None.
I am worry about the blindness to error will mess parse_sys_capabilities() #Closed

Copy link
Contributor Author

@mykolaf mykolaf Jul 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's possible for a device to have only 1 supported or enabled capability. And in the same way in tests/subproc_outputs/lldpctl_mgmt_only.json we have a dictionary of 1 interface under ['lldp]['interfaces'], where for many interfaces a list would be present. It is treated in a similar fashion in parse_update() L#169. #Closed

Copy link
Contributor

@qiluo-msft qiluo-msft Jul 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you provide proof for your thought? Either LLDPD source code or observed data. I don't see the case inside test data.

Even it is possible, I suggest test capability_list type positively instead of 'not list'.


In reply to: 203343589 [](ancestors = 203343589)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked lldpd source code, looks like capabilities are formatted https://github.com/vincentbernat/lldpd/blob/f9da7943df174f048033aeca242014855f836e3b/src/client/display.c#L265
the same way interfaces are here https://github.com/vincentbernat/lldpd/blob/f9da7943df174f048033aeca242014855f836e3b/src/client/display.c#L710 . Note that both display_cap() and display_interface() use tag_start("capability')/tag_start('interface') and tag_end() for each element. As we can see from test data for interfaces we get list for multiple https://github.com/Azure/sonic-dbsyncd/blob/master/tests/subproc_outputs/lldpctl.json#L3 , and dict for one https://github.com/Azure/sonic-dbsyncd/blob/master/tests/subproc_outputs/lldpctl_mgmt_only.json#L3 .
Checking for positive type is a good thing nevertheless.

except subprocess.CalledProcessError:
logger.exception("lldpctl exited with non-zero status")
return None
def scrap_output(cmd):
Copy link
Contributor

@qiluo-msft qiluo-msft Jul 17, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scrap_output [](start = 12, length = 12)

Could you not use embedded function? suggest a name _scrap_output to indicate it is for internal use. #Closed

Copy link
Contributor

@pavel-shirshov pavel-shirshov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as comments

capability_list = [capability_list]
except KeyError:
logger.error("Failed to get system capabilities")
return None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to return here an empty list.
It is better because

  1. :return: list of capabilities <- None value is not a list value
  2. later it would be easier to work with empty list, then always check you have a list or None value

# if chassis is incomplete, missing capabilities
# TODO check if it does not break snmpagent
if not capability_list:
return None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's return an empty string here. Below you use value of this function as it is without checking it None.

capability_list = self.get_sys_capability_list(if_attributes)
# lldpSysCapSupported
parsed_interfaces[if_name].update({'lldp_rem_sys_cap_supported':
self.parse_sys_capabilities(capability_list)})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if self.parse_sys_capabilities returns None

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will put None to redis db, which interprets it as "None" string. Now with your comments we return "" empty string, which is much better.

capability_list = self.get_sys_capability_list(if_attributes)
# lldpSysCapSupported
parsed_interfaces[if_name].update({'lldp_rem_sys_cap_supported':
self.parse_sys_capabilities(capability_list)})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if self.parse_sys_capabilities returns None

capability_list = self.get_sys_capability_list(if_attributes)
# lldpSysCapSupported
parsed_interfaces[if_name].update({'lldp_rem_sys_cap_supported':
self.parse_sys_capabilities(capability_list)})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if self.parse_sys_capabilities returns None

capability_list = self.get_sys_capability_list(if_attributes)
# lldpSysCapSupported
parsed_interfaces[if_name].update({'lldp_rem_sys_cap_supported':
self.parse_sys_capabilities(capability_list)})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if self.parse_sys_capabilities returns None

capability_list = self.get_sys_capability_list(if_attributes)
# lldpSysCapSupported
parsed_interfaces[if_name].update({'lldp_rem_sys_cap_supported':
self.parse_sys_capabilities(capability_list)})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if self.parse_sys_capabilities returns None

capability_list = self.get_sys_capability_list(if_attributes)
# lldpSysCapSupported
parsed_interfaces[if_name].update({'lldp_rem_sys_cap_supported':
self.parse_sys_capabilities(capability_list)})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if self.parse_sys_capabilities returns None

self.parse_sys_capabilities(capability_list)})
# lldpSysCapEnabled
parsed_interfaces[if_name].update({'lldp_rem_sys_cap_enabled':
self.parse_sys_capabilities(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.parse_sys_capabilities could return None here

:return: new, changed, deleted keys tuple
"""
new_keys = [key for key in update.keys() if key not in cache.keys()]
changed_keys = list(set([key for key in update.keys() + cache.keys()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can write it without square brackets
changed_keys = list(set(key for key in update.keys() + cache.keys() if update[key] != cache.get(key)))

@@ -20,6 +20,22 @@
LLDPD_UPTIME_RE_SPLIT_PATTERN = r' days?, '
MANAGEMENT_PORT_NAME = 'eth0'

def _scrap_output(cmd):
Copy link
Contributor

@qiluo-msft qiluo-msft Jul 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_scrap_output [](start = 4, length = 13)

You may define this function inside LldpSyncDaemon class. #Closed

@qiluo-msft qiluo-msft merged commit 37dbf74 into sonic-net:master Jul 18, 2018
@mykolaf mykolaf deleted the lldp_pr branch July 23, 2018 11:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants