[bgpmon]: Fix exception in bgpmon caused by duplicate bgp neighbor ID (#6546)

* Fix exception in bgpmon caused by duplicate keys
It is possible that BGP neighbors in IPv4 and IPv6 address families
share the same name (such as bgp monitor). However, such case is not
handled in bgpmon, and an Exception will be raised. This commit will
address the issue by Using set instead of list to avoid duplicate keys.
This commit is contained in:
bingwang-ms 2021-01-27 15:01:42 +08:00 committed by Abhishek Dosi
parent 9779560b63
commit 869b3bc415

View File

@ -5,7 +5,7 @@ Description: bgpmon.py -- populating bgp related information in stateDB.
script is started by supervisord in bgp docker when the docker is started. script is started by supervisord in bgp docker when the docker is started.
Initial creation of this daemon is to assist SNMP agent in obtaining the Initial creation of this daemon is to assist SNMP agent in obtaining the
BGP related information for its MIB support. The MIB that this daemon is BGP related information for its MIB support. The MIB that this daemon is
assiting is for the CiscoBgp4MIB (Neighbor state only). If there are other assisting is for the CiscoBgp4MIB (Neighbor state only). If there are other
BGP related items that needs to be updated in a periodic manner in the BGP related items that needs to be updated in a periodic manner in the
future, then more can be added into this process. future, then more can be added into this process.
The script check if there are any bgp activities by monitoring the bgp The script check if there are any bgp activities by monitoring the bgp
@ -32,13 +32,13 @@ PIPE_BATCH_MAX_COUNT = 50
class BgpStateGet(): class BgpStateGet():
def __init__(self): def __init__(self):
# list peer_l stores the Neighbor peer Ip address # set peer_l stores the Neighbor peer Ip address
# dic peer_state stores the Neighbor peer state entries # dic peer_state stores the Neighbor peer state entries
# list new_peer_l stores the new snapshot of Neighbor peer ip address # set new_peer_l stores the new snapshot of Neighbor peer ip address
# dic new_peer_state stores the new snapshot of Neighbor peer states # dic new_peer_state stores the new snapshot of Neighbor peer states
self.peer_l = [] self.peer_l = set()
self.peer_state = {} self.peer_state = {}
self.new_peer_l = [] self.new_peer_l = set()
self.new_peer_state = {} self.new_peer_state = {}
self.cached_timestamp = 0 self.cached_timestamp = 0
self.db = swsssdk.SonicV2Connector() self.db = swsssdk.SonicV2Connector()
@ -65,9 +65,9 @@ class BgpStateGet():
def update_new_peer_states(self, peer_dict): def update_new_peer_states(self, peer_dict):
peer_l = peer_dict["peers"].keys() peer_l = peer_dict["peers"].keys()
self.new_peer_l.extend(peer_l) self.new_peer_l.update(peer_l)
for i in range (0, len(peer_l)): for peer in peer_l:
self.new_peer_state[peer_l[i]] = peer_dict["peers"][peer_l[i]]["state"] self.new_peer_state[peer] = peer_dict["peers"][peer]["state"]
# Get a new snapshot of BGP neighbors and store them in the "new" location # Get a new snapshot of BGP neighbors and store them in the "new" location
def get_all_neigh_states(self): def get_all_neigh_states(self):
@ -78,8 +78,8 @@ class BgpStateGet():
return return
peer_info = json.loads(output) peer_info = json.loads(output)
# cmd ran successfully, safe to Clean the "new" lists/dic for new sanpshot # cmd ran successfully, safe to Clean the "new" set/dict for new snapshot
del self.new_peer_l[:] self.new_peer_l.clear()
self.new_peer_state.clear() self.new_peer_state.clear()
for key, value in peer_info.items(): for key, value in peer_info.items():
if key == "ipv4Unicast" or key == "ipv6Unicast": if key == "ipv4Unicast" or key == "ipv6Unicast":
@ -113,8 +113,7 @@ class BgpStateGet():
def update_neigh_states(self): def update_neigh_states(self):
data = {} data = {}
for i in range (0, len(self.new_peer_l)): for peer in self.new_peer_l:
peer = self.new_peer_l[i]
key = "NEIGH_STATE_TABLE|%s" % peer key = "NEIGH_STATE_TABLE|%s" % peer
if peer in self.peer_l: if peer in self.peer_l:
# only update the entry if state changed # only update the entry if state changed
@ -123,7 +122,7 @@ class BgpStateGet():
state = self.new_peer_state[peer] state = self.new_peer_state[peer]
data[key] = {'state':state} data[key] = {'state':state}
self.peer_state[peer] = state self.peer_state[peer] = state
# remove this neighbor from old list since it is accounted for # remove this neighbor from old set since it is accounted for
self.peer_l.remove(peer) self.peer_l.remove(peer)
else: else:
# New neighbor found case. Add to dictionary and state DB # New neighbor found case. Add to dictionary and state DB
@ -133,19 +132,19 @@ class BgpStateGet():
if len(data) > PIPE_BATCH_MAX_COUNT: if len(data) > PIPE_BATCH_MAX_COUNT:
self.flush_pipe(data) self.flush_pipe(data)
# Check for stale state entries to be cleaned up # Check for stale state entries to be cleaned up
while len(self.peer_l) > 0: for peer in self.peer_l:
# remove this from the stateDB and the current nighbor state entry # remove this from the stateDB and the current neighbor state entry
peer = self.peer_l.pop(0)
del_key = "NEIGH_STATE_TABLE|%s" % peer del_key = "NEIGH_STATE_TABLE|%s" % peer
data[del_key] = None data[del_key] = None
del self.peer_state[peer] if peer in self.peer_state:
del self.peer_state[peer]
if len(data) > PIPE_BATCH_MAX_COUNT: if len(data) > PIPE_BATCH_MAX_COUNT:
self.flush_pipe(data) self.flush_pipe(data)
# If anything in the pipeline not yet flushed, flush them now # If anything in the pipeline not yet flushed, flush them now
if len(data) > 0: if len(data) > 0:
self.flush_pipe(data) self.flush_pipe(data)
# Save the new List # Save the new set
self.peer_l = self.new_peer_l[:] self.peer_l = self.new_peer_l.copy()
def main(): def main():