From eee827e84dfdf9d9d39302afcee256cf919a94d2 Mon Sep 17 00:00:00 2001 From: anilkpandey <47642449+anilkpandey@users.noreply.github.com> Date: Thu, 9 May 2019 16:22:09 -0700 Subject: [PATCH 01/42] Update main.py --- config/main.py | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/config/main.py b/config/main.py index 177b49bc3b..493d160ea8 100755 --- a/config/main.py +++ b/config/main.py @@ -109,6 +109,15 @@ def interface_name_is_valid(interface_name): return True return False +def vlan_id_is_valid(vid): + """Check if the vlan id is in acceptable range (between 1 and 4094) + """ + + if vid<1 or vid>4094: + return False + + return True + def interface_name_to_alias(interface_name): """Return alias interface name if default name is given as argument """ @@ -487,6 +496,19 @@ def add_portchannel(ctx, portchannel_name, min_links, fallback): def remove_portchannel(ctx, portchannel_name): """Remove port channel""" db = ctx.obj['db'] + # Dont let to remove port channel if IP adress, vlan membership, or have members configured + for k,v in db.get_table('PORTCHANNEL_INTERFACE'): + if k == portchannel_name: + print"Error %s configured with ip %s, remove adress to proceed" %(portchannel_name, str(v)) + return + for k,v in db.get_table('PORTCHANNEL_MEMBER'): + if k == portchannel_name: + print"Error %s has members configured, remove members first to proceed" %(portchannel_name) + return + for k,v in db.get_table('VLAN_MEMBER'): + if v == portchannel_name: + print"Error %s has vlan %s configured, remove vlan membership to proceed" %(portchannel_name, str(k)) + return db.set_entry('PORTCHANNEL', portchannel_name, None) @portchannel.group('member') @@ -691,6 +713,8 @@ def vlan(ctx, redis_unix_socket_path): @click.pass_context def add_vlan(ctx, vid): db = ctx.obj['db'] + if vlan_id_is_valid(vid) is False: + ctx.fail(" Invalid Vlan Id , Valid Range : 1 to 4094 ") vlan = 'Vlan{}'.format(vid) if len(db.get_entry('VLAN', vlan)) != 0: ctx.fail("{} already exists".format(vlan)) @@ -744,6 +768,25 @@ def add_vlan_member(ctx, vid, interface_name, untagged): else: ctx.fail("{} is already a member of {}".format(interface_name, vlan_name)) + #Validate If the interface is already untagged member any other Vlan + if untagged is True: + keys = [ (k, v) for k, v in db.get_table('VLAN_MEMBER') if v == interface_name ] + for k in keys: + if db.get_entry('VLAN_MEMBER',k).get('tagging_mode',)== 'untagged': + ctx.fail("Interface {} is already untagged member of {} ".format(interface_name,k[0])) + return + + # Validate if member is IP interface + for k,v in db.get_table('INTERFACE'): + if k == interface_name: + ctx.fail(" {} has ip address configured".format(interface_name)) + return + # Validate if ip interface + for k,v in db.get_table('PORTCHANNEL_INTERFACE'): + if k == interface_name: + ctx.fail(" {} has ip address configured".format(interface_name)) + return + members.append(interface_name) vlan['members'] = members db.set_entry('VLAN', vlan_name, vlan) @@ -946,6 +989,12 @@ def add(ctx, interface_name, ip_addr): if interface_name is None: ctx.fail("'interface_name' is None!") + #Validate if member of VLAN + for k,v in config_db.get_table('VLAN_MEMBER'): + if v == interface_name: + print"Error: %s Interface configured as VLAN_MEMBER under vlan : %s" %(interface_name,str(k)) + return + if interface_name.startswith("Ethernet"): config_db.set_entry("INTERFACE", (interface_name, ip_addr), {"NULL": "NULL"}) elif interface_name.startswith("PortChannel"): From d4e5346861a035526bc22f3cb31a41f71e3057eb Mon Sep 17 00:00:00 2001 From: anilkpandey <47642449+anilkpandey@users.noreply.github.com> Date: Thu, 9 May 2019 16:41:35 -0700 Subject: [PATCH 02/42] Update main.py --- config/main.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/config/main.py b/config/main.py index 493d160ea8..0628d0974c 100755 --- a/config/main.py +++ b/config/main.py @@ -763,11 +763,9 @@ def add_vlan_member(ctx, vid, interface_name, untagged): interface_name = interface_name_to_alias(interface_name) if interface_name is None: ctx.fail("'interface_name' is None!") - ctx.fail("{} is already a member of {}".format(interface_name, - vlan_name)) + ctx.fail("{} is already a member of {}".format(interface_name,vlan_name)) else: - ctx.fail("{} is already a member of {}".format(interface_name, - vlan_name)) + ctx.fail("{} is already a member of {}".format(interface_name,vlan_name)) #Validate If the interface is already untagged member any other Vlan if untagged is True: keys = [ (k, v) for k, v in db.get_table('VLAN_MEMBER') if v == interface_name ] From b63e7956f0bbb4ac326b9d9d82709c01ff685de9 Mon Sep 17 00:00:00 2001 From: anilkpandey <47642449+anilkpandey@users.noreply.github.com> Date: Thu, 9 May 2019 16:50:43 -0700 Subject: [PATCH 03/42] Update main.py --- config/main.py | 35 +++++------------------------------ 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/config/main.py b/config/main.py index 0628d0974c..f508f94d4c 100755 --- a/config/main.py +++ b/config/main.py @@ -109,15 +109,6 @@ def interface_name_is_valid(interface_name): return True return False -def vlan_id_is_valid(vid): - """Check if the vlan id is in acceptable range (between 1 and 4094) - """ - - if vid<1 or vid>4094: - return False - - return True - def interface_name_to_alias(interface_name): """Return alias interface name if default name is given as argument """ @@ -496,19 +487,6 @@ def add_portchannel(ctx, portchannel_name, min_links, fallback): def remove_portchannel(ctx, portchannel_name): """Remove port channel""" db = ctx.obj['db'] - # Dont let to remove port channel if IP adress, vlan membership, or have members configured - for k,v in db.get_table('PORTCHANNEL_INTERFACE'): - if k == portchannel_name: - print"Error %s configured with ip %s, remove adress to proceed" %(portchannel_name, str(v)) - return - for k,v in db.get_table('PORTCHANNEL_MEMBER'): - if k == portchannel_name: - print"Error %s has members configured, remove members first to proceed" %(portchannel_name) - return - for k,v in db.get_table('VLAN_MEMBER'): - if v == portchannel_name: - print"Error %s has vlan %s configured, remove vlan membership to proceed" %(portchannel_name, str(k)) - return db.set_entry('PORTCHANNEL', portchannel_name, None) @portchannel.group('member') @@ -713,8 +691,6 @@ def vlan(ctx, redis_unix_socket_path): @click.pass_context def add_vlan(ctx, vid): db = ctx.obj['db'] - if vlan_id_is_valid(vid) is False: - ctx.fail(" Invalid Vlan Id , Valid Range : 1 to 4094 ") vlan = 'Vlan{}'.format(vid) if len(db.get_entry('VLAN', vlan)) != 0: ctx.fail("{} already exists".format(vlan)) @@ -765,6 +741,7 @@ def add_vlan_member(ctx, vid, interface_name, untagged): ctx.fail("'interface_name' is None!") ctx.fail("{} is already a member of {}".format(interface_name,vlan_name)) else: +<<<<<<< HEAD ctx.fail("{} is already a member of {}".format(interface_name,vlan_name)) #Validate If the interface is already untagged member any other Vlan if untagged is True: @@ -785,6 +762,10 @@ def add_vlan_member(ctx, vid, interface_name, untagged): ctx.fail(" {} has ip address configured".format(interface_name)) return +======= + ctx.fail("{} is already a member of {}".format(interface_name, + vlan_name)) +>>>>>>> parent of eee827e... Update main.py members.append(interface_name) vlan['members'] = members db.set_entry('VLAN', vlan_name, vlan) @@ -987,12 +968,6 @@ def add(ctx, interface_name, ip_addr): if interface_name is None: ctx.fail("'interface_name' is None!") - #Validate if member of VLAN - for k,v in config_db.get_table('VLAN_MEMBER'): - if v == interface_name: - print"Error: %s Interface configured as VLAN_MEMBER under vlan : %s" %(interface_name,str(k)) - return - if interface_name.startswith("Ethernet"): config_db.set_entry("INTERFACE", (interface_name, ip_addr), {"NULL": "NULL"}) elif interface_name.startswith("PortChannel"): From a4beefc454ffb989fc6afeecc82c3aef160bdbbf Mon Sep 17 00:00:00 2001 From: anilkpandey <47642449+anilkpandey@users.noreply.github.com> Date: Thu, 9 May 2019 17:08:32 -0700 Subject: [PATCH 04/42] added configuration validations - validate vlan id for vlan creation - verify that port is not part of vlan when assigning IP address and vice versa - verify that portchannel has no member and portchannel is not member of vlan when deleting the portchannel - verify that port is not already untagged member of vlan when adding the port as untagged member of a vlan - --- config/main.py | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/config/main.py b/config/main.py index f508f94d4c..0628d0974c 100755 --- a/config/main.py +++ b/config/main.py @@ -109,6 +109,15 @@ def interface_name_is_valid(interface_name): return True return False +def vlan_id_is_valid(vid): + """Check if the vlan id is in acceptable range (between 1 and 4094) + """ + + if vid<1 or vid>4094: + return False + + return True + def interface_name_to_alias(interface_name): """Return alias interface name if default name is given as argument """ @@ -487,6 +496,19 @@ def add_portchannel(ctx, portchannel_name, min_links, fallback): def remove_portchannel(ctx, portchannel_name): """Remove port channel""" db = ctx.obj['db'] + # Dont let to remove port channel if IP adress, vlan membership, or have members configured + for k,v in db.get_table('PORTCHANNEL_INTERFACE'): + if k == portchannel_name: + print"Error %s configured with ip %s, remove adress to proceed" %(portchannel_name, str(v)) + return + for k,v in db.get_table('PORTCHANNEL_MEMBER'): + if k == portchannel_name: + print"Error %s has members configured, remove members first to proceed" %(portchannel_name) + return + for k,v in db.get_table('VLAN_MEMBER'): + if v == portchannel_name: + print"Error %s has vlan %s configured, remove vlan membership to proceed" %(portchannel_name, str(k)) + return db.set_entry('PORTCHANNEL', portchannel_name, None) @portchannel.group('member') @@ -691,6 +713,8 @@ def vlan(ctx, redis_unix_socket_path): @click.pass_context def add_vlan(ctx, vid): db = ctx.obj['db'] + if vlan_id_is_valid(vid) is False: + ctx.fail(" Invalid Vlan Id , Valid Range : 1 to 4094 ") vlan = 'Vlan{}'.format(vid) if len(db.get_entry('VLAN', vlan)) != 0: ctx.fail("{} already exists".format(vlan)) @@ -741,7 +765,6 @@ def add_vlan_member(ctx, vid, interface_name, untagged): ctx.fail("'interface_name' is None!") ctx.fail("{} is already a member of {}".format(interface_name,vlan_name)) else: -<<<<<<< HEAD ctx.fail("{} is already a member of {}".format(interface_name,vlan_name)) #Validate If the interface is already untagged member any other Vlan if untagged is True: @@ -762,10 +785,6 @@ def add_vlan_member(ctx, vid, interface_name, untagged): ctx.fail(" {} has ip address configured".format(interface_name)) return -======= - ctx.fail("{} is already a member of {}".format(interface_name, - vlan_name)) ->>>>>>> parent of eee827e... Update main.py members.append(interface_name) vlan['members'] = members db.set_entry('VLAN', vlan_name, vlan) @@ -968,6 +987,12 @@ def add(ctx, interface_name, ip_addr): if interface_name is None: ctx.fail("'interface_name' is None!") + #Validate if member of VLAN + for k,v in config_db.get_table('VLAN_MEMBER'): + if v == interface_name: + print"Error: %s Interface configured as VLAN_MEMBER under vlan : %s" %(interface_name,str(k)) + return + if interface_name.startswith("Ethernet"): config_db.set_entry("INTERFACE", (interface_name, ip_addr), {"NULL": "NULL"}) elif interface_name.startswith("PortChannel"): From 15643029f540a29e79434198517fda00b7b83ef0 Mon Sep 17 00:00:00 2001 From: anilkpandey <47642449+anilkpandey@users.noreply.github.com> Date: Wed, 5 Jun 2019 11:41:00 -0700 Subject: [PATCH 05/42] 'show mac' performance improvement 'show mac' was taking a lot of time to display the fdb entries when a large number of entries are present. Using redis pipeline, reduced the time significantly. Earlier it used to take about 10 minutes to show 32K MAC. After the fix it takes about 17-20 seconds. --- .DS_Store | Bin 0 -> 8196 bytes scripts/fdbshow | 36 +++++++++++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..b5007ad61cacd40718658befb3debc6b9aa19f81 GIT binary patch literal 8196 zcmeHMU2GIp6h3EL+PQ_=TjZy+SXgOFE4I=$l!E+i+l5koQe<2DL#52_40PgjrtHji zfm%}&jW1%UK2-aWGbfIWG$9iR>XG`fW3OR2g`5qfdmQDR}w5|T*%05+V;6#VIo<7Mu! zjyfU)A_O7?A_O7?A_VRQ1nA5bMO)4bP|hnUUFn%Bd%(~Y!xRIRJLwa`oMbYT^GYgrK;;e?j*MZ3f^u~7 zOGtCTq>@n`ArK*OCjugOuYfFg;KIq0{QY`n+Ohqht?fIEm6b24sMNG7t*W}}$@HXG zNC!rc_j`=oF>!a;2qrUOd(iWog|?A7YFmW~zM|K21H*Q$oOHHLi%iCcZP)Y)Jzm~5 zefgZUQfL~}*aX*SXE%3jZb@`>bk4OTX4~7g(oI)a$J`v#RyVfq>_0Je_T22#bI)8* zfnm5gKut-Y7fYjb{Fz?$l_K^=G0N|YQ8Knv@85sm-~{J+-#TJBMqtlaDI>7_30~t< zxcynrJ)E;fSk+SD}J-PEkJL7$@FMrhd5%Glsjw4U6jDTs-;cQAd( zF*26JO{UzobTNH+Muo}`gq_=WFnuKJO-)gVel50y-N|lUKQ2Z-X!yavwB^#QKBM7f zbnEm!O&b;3ZquY$H6)wWl1msGl5Ogai(^HH7T5)QVT@?*LIGZc^Y9W}fJ<-{-h~h0 zQ}`UdgsJGvLvvt$MTNhQf2 zMG#4xA~EC=-o{3;=6ZY$t6z-KL&Q7lj3&s#E0uL3zFs4~a7h?F-WYGvh}1kLwQOUY zEDep9DdSD7T_ck6B}%)QZDB-XUaqv;*mjNB$}5z17fUknqH$37jqw!II4;J)MH%=O zT!w4#30x=UeG9kXC-?>aM8FEiHr02EHUwUd?DoGYxp|8iI+;4*I(qEl6a+*c{Ayp>v--d z>KAOS1fSld932+Z5P)y`StmnVev!!PDN%jzBT%NMSSRxTJ&S+;zxM-)W*8w5A@Hve z!17c&)kE%!ZQ&xVQtypqy|Dw&Rxl<7Fhg+C0bogh=;lMLm&lGH=xKmQOQ VeoI8>KdqR;A0RsaB@yql>Tj!?>Q(>% literal 0 HcmV?d00001 diff --git a/scripts/fdbshow b/scripts/fdbshow index 13d3630868..7de56ff868 100755 --- a/scripts/fdbshow +++ b/scripts/fdbshow @@ -63,25 +63,51 @@ class FdbShow(object): return oid_pfx = len("oid:0x") + + client = self.db.redis_clients["ASIC_DB"] + pipe = client.pipeline() + values = [] + fdb_list = [] for s in fdb_str: fdb_entry = s.decode() fdb = json.loads(fdb_entry .split(":", 2)[-1]) if not fdb: continue - - ent = self.db.get_all('ASIC_DB', s, blocking=True) + fdb_list.append(fdb) + pipe.hgetall(s) + values = pipe.execute() + client = self.db.redis_clients["ASIC_DB"] + pipe = client.pipeline() + vlans = [] + vlan_keys = self.db.keys('ASIC_DB', "ASIC_STATE:SAI_OBJECT_TYPE_VLAN:*") + for v in vlan_keys: + pipe.hgetall(v) + vlans = pipe.execute() + + posi = 0 + for ent in values: + if 'SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID' not in ent: + posi = posi + 1 + continue br_port_id = ent[b"SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID"][oid_pfx:] ent_type = ent[b"SAI_FDB_ENTRY_ATTR_TYPE"] fdb_type = ['Dynamic','Static'][ent_type == "SAI_FDB_ENTRY_TYPE_STATIC"] if br_port_id not in self.if_br_oid_map: + posi = posi + 1 continue port_id = self.if_br_oid_map[br_port_id] - if_name = self.if_oid_map[port_id] + #When if_name not mapped to port_id in DB, using port_id as if_name in the display. + try: + if_name = self.if_oid_map[port_id] + except : + if_name = port_id + if 'vlan' in fdb: vlan_id = fdb["vlan"] elif 'bvid' in fdb: - vlan_id = port_util.get_vlan_id_from_bvid(self.db, fdb["bvid"]) - self.bridge_mac_list.append((int(vlan_id),) + (fdb["mac"],) + (if_name,) + (fdb_type,)) + vlan_id = vlans[vlan_keys.index("ASIC_STATE:SAI_OBJECT_TYPE_VLAN:{}".format(fdb_list[posi][u'bvid']))] [b"SAI_VLAN_ATTR_VLAN_ID"] + self.bridge_mac_list.append((int(vlan_id),) + (fdb_list[posi]["mac"],) + (if_name,) + (fdb_type,)) + posi = posi + 1 self.bridge_mac_list.sort(key = lambda x: x[0]) return From f567fbbad75b63e43d66bc44618b25e86ebb2a5d Mon Sep 17 00:00:00 2001 From: anilkpandey <47642449+anilkpandey@users.noreply.github.com> Date: Wed, 5 Jun 2019 11:47:54 -0700 Subject: [PATCH 06/42] revert changes revert changes --- config/main.py | 35 +++++------------------------------ 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/config/main.py b/config/main.py index 0628d0974c..f508f94d4c 100755 --- a/config/main.py +++ b/config/main.py @@ -109,15 +109,6 @@ def interface_name_is_valid(interface_name): return True return False -def vlan_id_is_valid(vid): - """Check if the vlan id is in acceptable range (between 1 and 4094) - """ - - if vid<1 or vid>4094: - return False - - return True - def interface_name_to_alias(interface_name): """Return alias interface name if default name is given as argument """ @@ -496,19 +487,6 @@ def add_portchannel(ctx, portchannel_name, min_links, fallback): def remove_portchannel(ctx, portchannel_name): """Remove port channel""" db = ctx.obj['db'] - # Dont let to remove port channel if IP adress, vlan membership, or have members configured - for k,v in db.get_table('PORTCHANNEL_INTERFACE'): - if k == portchannel_name: - print"Error %s configured with ip %s, remove adress to proceed" %(portchannel_name, str(v)) - return - for k,v in db.get_table('PORTCHANNEL_MEMBER'): - if k == portchannel_name: - print"Error %s has members configured, remove members first to proceed" %(portchannel_name) - return - for k,v in db.get_table('VLAN_MEMBER'): - if v == portchannel_name: - print"Error %s has vlan %s configured, remove vlan membership to proceed" %(portchannel_name, str(k)) - return db.set_entry('PORTCHANNEL', portchannel_name, None) @portchannel.group('member') @@ -713,8 +691,6 @@ def vlan(ctx, redis_unix_socket_path): @click.pass_context def add_vlan(ctx, vid): db = ctx.obj['db'] - if vlan_id_is_valid(vid) is False: - ctx.fail(" Invalid Vlan Id , Valid Range : 1 to 4094 ") vlan = 'Vlan{}'.format(vid) if len(db.get_entry('VLAN', vlan)) != 0: ctx.fail("{} already exists".format(vlan)) @@ -765,6 +741,7 @@ def add_vlan_member(ctx, vid, interface_name, untagged): ctx.fail("'interface_name' is None!") ctx.fail("{} is already a member of {}".format(interface_name,vlan_name)) else: +<<<<<<< HEAD ctx.fail("{} is already a member of {}".format(interface_name,vlan_name)) #Validate If the interface is already untagged member any other Vlan if untagged is True: @@ -785,6 +762,10 @@ def add_vlan_member(ctx, vid, interface_name, untagged): ctx.fail(" {} has ip address configured".format(interface_name)) return +======= + ctx.fail("{} is already a member of {}".format(interface_name, + vlan_name)) +>>>>>>> parent of eee827e... Update main.py members.append(interface_name) vlan['members'] = members db.set_entry('VLAN', vlan_name, vlan) @@ -987,12 +968,6 @@ def add(ctx, interface_name, ip_addr): if interface_name is None: ctx.fail("'interface_name' is None!") - #Validate if member of VLAN - for k,v in config_db.get_table('VLAN_MEMBER'): - if v == interface_name: - print"Error: %s Interface configured as VLAN_MEMBER under vlan : %s" %(interface_name,str(k)) - return - if interface_name.startswith("Ethernet"): config_db.set_entry("INTERFACE", (interface_name, ip_addr), {"NULL": "NULL"}) elif interface_name.startswith("PortChannel"): From 0bfb742d618ca89afeb45e66f86a9581719022c4 Mon Sep 17 00:00:00 2001 From: anilkpandey <47642449+anilkpandey@users.noreply.github.com> Date: Wed, 5 Jun 2019 16:27:30 -0700 Subject: [PATCH 07/42] Delete .DS_Store --- .DS_Store | Bin 8196 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index b5007ad61cacd40718658befb3debc6b9aa19f81..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMU2GIp6h3EL+PQ_=TjZy+SXgOFE4I=$l!E+i+l5koQe<2DL#52_40PgjrtHji zfm%}&jW1%UK2-aWGbfIWG$9iR>XG`fW3OR2g`5qfdmQDR}w5|T*%05+V;6#VIo<7Mu! zjyfU)A_O7?A_O7?A_VRQ1nA5bMO)4bP|hnUUFn%Bd%(~Y!xRIRJLwa`oMbYT^GYgrK;;e?j*MZ3f^u~7 zOGtCTq>@n`ArK*OCjugOuYfFg;KIq0{QY`n+Ohqht?fIEm6b24sMNG7t*W}}$@HXG zNC!rc_j`=oF>!a;2qrUOd(iWog|?A7YFmW~zM|K21H*Q$oOHHLi%iCcZP)Y)Jzm~5 zefgZUQfL~}*aX*SXE%3jZb@`>bk4OTX4~7g(oI)a$J`v#RyVfq>_0Je_T22#bI)8* zfnm5gKut-Y7fYjb{Fz?$l_K^=G0N|YQ8Knv@85sm-~{J+-#TJBMqtlaDI>7_30~t< zxcynrJ)E;fSk+SD}J-PEkJL7$@FMrhd5%Glsjw4U6jDTs-;cQAd( zF*26JO{UzobTNH+Muo}`gq_=WFnuKJO-)gVel50y-N|lUKQ2Z-X!yavwB^#QKBM7f zbnEm!O&b;3ZquY$H6)wWl1msGl5Ogai(^HH7T5)QVT@?*LIGZc^Y9W}fJ<-{-h~h0 zQ}`UdgsJGvLvvt$MTNhQf2 zMG#4xA~EC=-o{3;=6ZY$t6z-KL&Q7lj3&s#E0uL3zFs4~a7h?F-WYGvh}1kLwQOUY zEDep9DdSD7T_ck6B}%)QZDB-XUaqv;*mjNB$}5z17fUknqH$37jqw!II4;J)MH%=O zT!w4#30x=UeG9kXC-?>aM8FEiHr02EHUwUd?DoGYxp|8iI+;4*I(qEl6a+*c{Ayp>v--d z>KAOS1fSld932+Z5P)y`StmnVev!!PDN%jzBT%NMSSRxTJ&S+;zxM-)W*8w5A@Hve z!17c&)kE%!ZQ&xVQtypqy|Dw&Rxl<7Fhg+C0bogh=;lMLm&lGH=xKmQOQ VeoI8>KdqR;A0RsaB@yql>Tj!?>Q(>% From d54420342a18c18a8c29c9f06b8f09d87ac93e06 Mon Sep 17 00:00:00 2001 From: anilkpandey <47642449+anilkpandey@users.noreply.github.com> Date: Wed, 5 Jun 2019 17:21:18 -0700 Subject: [PATCH 08/42] revert validation related changes reverted changes made as part of validations --- config/main.py | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/config/main.py b/config/main.py index f508f94d4c..7437bed150 100755 --- a/config/main.py +++ b/config/main.py @@ -739,33 +739,11 @@ def add_vlan_member(ctx, vid, interface_name, untagged): interface_name = interface_name_to_alias(interface_name) if interface_name is None: ctx.fail("'interface_name' is None!") - ctx.fail("{} is already a member of {}".format(interface_name,vlan_name)) + ctx.fail("{} is already a member of {}".format(interface_name, + vlan_name)) else: -<<<<<<< HEAD - ctx.fail("{} is already a member of {}".format(interface_name,vlan_name)) - #Validate If the interface is already untagged member any other Vlan - if untagged is True: - keys = [ (k, v) for k, v in db.get_table('VLAN_MEMBER') if v == interface_name ] - for k in keys: - if db.get_entry('VLAN_MEMBER',k).get('tagging_mode',)== 'untagged': - ctx.fail("Interface {} is already untagged member of {} ".format(interface_name,k[0])) - return - - # Validate if member is IP interface - for k,v in db.get_table('INTERFACE'): - if k == interface_name: - ctx.fail(" {} has ip address configured".format(interface_name)) - return - # Validate if ip interface - for k,v in db.get_table('PORTCHANNEL_INTERFACE'): - if k == interface_name: - ctx.fail(" {} has ip address configured".format(interface_name)) - return - -======= ctx.fail("{} is already a member of {}".format(interface_name, vlan_name)) ->>>>>>> parent of eee827e... Update main.py members.append(interface_name) vlan['members'] = members db.set_entry('VLAN', vlan_name, vlan) @@ -1146,4 +1124,4 @@ def naming_mode_alias(): if __name__ == '__main__': - config() + config() \ No newline at end of file From 186b295bcc389ba96e37c9087eb902e0b2cc8197 Mon Sep 17 00:00:00 2001 From: anilkpandey <47642449+anilkpandey@users.noreply.github.com> Date: Wed, 26 Jun 2019 16:18:28 -0700 Subject: [PATCH 09/42] removed code repetition --- scripts/fdbshow | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/fdbshow b/scripts/fdbshow index 7de56ff868..b4f3fd17b1 100755 --- a/scripts/fdbshow +++ b/scripts/fdbshow @@ -76,8 +76,6 @@ class FdbShow(object): fdb_list.append(fdb) pipe.hgetall(s) values = pipe.execute() - client = self.db.redis_clients["ASIC_DB"] - pipe = client.pipeline() vlans = [] vlan_keys = self.db.keys('ASIC_DB', "ASIC_STATE:SAI_OBJECT_TYPE_VLAN:*") for v in vlan_keys: From a8935aff8ef59ecc65d50aa187cf89393d6612e9 Mon Sep 17 00:00:00 2001 From: anilkpandey <47642449+anilkpandey@users.noreply.github.com> Date: Sat, 7 Sep 2019 17:21:56 -0700 Subject: [PATCH 10/42] Layer 2 Forwarding Enhancements Layer 2 Forwarding Enhancements --- clear/main.py | 3 - config/main.py | 494 ++++++++++++++++++++++++++++++++++-- scripts/fast-reboot-dump.py | 109 +++++++- scripts/fdbclear | 11 +- show/main.py | 58 +++++ 5 files changed, 649 insertions(+), 26 deletions(-) diff --git a/clear/main.py b/clear/main.py index af71975ad4..4bd6289d95 100755 --- a/clear/main.py +++ b/clear/main.py @@ -361,8 +361,6 @@ def clear_all_fdb(): command = 'fdbclear' run_command(command) -# 'sonic-clear fdb port' and 'sonic-clear fdb vlan' will be added later -''' @fdb.command('port') @click.argument('portid', required=True) def clear_port_fdb(portid): @@ -376,7 +374,6 @@ def clear_vlan_fdb(vlanid): """Clear FDB entries learned in one VLAN""" command = 'fdbclear' + ' -v ' + vlanid run_command(command) -''' # # 'line' command diff --git a/config/main.py b/config/main.py index 1bc759d1fb..2969b6b56b 100755 --- a/config/main.py +++ b/config/main.py @@ -8,12 +8,14 @@ import netaddr import re import syslog +import logging import sonic_device_util import ipaddress from swsssdk import ConfigDBConnector from swsssdk import SonicV2Connector from minigraph import parse_device_desc_xml +from itertools import count, groupby import aaa import mlnx @@ -86,30 +88,40 @@ def interface_alias_to_name(interface_alias): return interface_alias -def interface_name_is_valid(interface_name): +def interface_name_is_valid(config_db, interface_name): """Check if the interface name is valid """ - config_db = ConfigDBConnector() - config_db.connect() - port_dict = config_db.get_table('PORT') - port_channel_dict = config_db.get_table('PORTCHANNEL') - if get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(interface_name) if interface_name is not None: - if not port_dict: - click.echo("port_dict is None!") - raise click.Abort() - for port_name in port_dict.keys(): - if interface_name == port_name: - return True - if port_channel_dict: - for port_channel_name in port_channel_dict.keys(): - if interface_name == port_channel_name: + if interface_name.startswith("Ethernet"): + port_dict = config_db.get_table('PORT') + if not port_dict: + click.echo("port_dict is None!") + raise click.Abort() + + for port_name in port_dict.keys(): + if interface_name == port_name: return True + + if interface_name.startswith("PortChannel"): + port_channel_dict = config_db.get_table('PORTCHANNEL') + if port_channel_dict: + for port_channel_name in port_channel_dict.keys(): + if interface_name == port_channel_name: + return True return False +def vlan_id_is_valid(vid): + """Check if the vlan id is in acceptable range (between 1 and 4094) + """ + + if vid<1 or vid>4094: + return False + + return True + def interface_name_to_alias(interface_name): """Return alias interface name if default name is given as argument """ @@ -743,9 +755,12 @@ def vlan(ctx, redis_unix_socket_path): @click.pass_context def add_vlan(ctx, vid): db = ctx.obj['db'] + if vlan_id_is_valid(vid) is False: + ctx.fail(" Invalid Vlan Id , Valid Range : 1 to 4094 ") vlan = 'Vlan{}'.format(vid) if len(db.get_entry('VLAN', vlan)) != 0: - ctx.fail("{} already exists".format(vlan)) + click.echo("{} already exists".format(vlan)) + return db.set_entry('VLAN', vlan, {'vlanid': vid}) @vlan.command('del') @@ -895,6 +910,446 @@ def del_vlan_dhcp_relay_destination(ctx, vid, dhcp_relay_destination_ip): else: ctx.fail("{} is not a DHCP relay destination for {}".format(dhcp_relay_destination_ip, vlan_name)) +# Validate VLAN range. +# +def vlan_range_validate(ctx, vid1, vid2): + vlan1 = 'Vlan{}'.format(vid1) + vlan2 = 'Vlan{}'.format(vid2) + + if vlan_id_is_valid(vid1) is False: + ctx.fail("{} is not within allowed range of 1 through 4094".format(vlan1)) + if vlan_id_is_valid(vid2) is False: + ctx.fail("{} is not within allowed range of 1 through 4094".format(vlan2)) + + if vid2 <= vid1: + ctx.fail(" vid2 should be greater than vid1") + +# +# Return a string with ranges separated by hyphen. +# +def get_hyphenated_string(vlan_list): + vlan_list.sort() + G = (list(x) for _,x in groupby(vlan_list, lambda x,c=count(): next(c)-x)) + hyphenated_string = ",".join("-".join(map(str,(g[0],g[-1])[:len(g)])) for g in G) + return hyphenated_string + +# +# 'range' group ('config vlan range ...') +# +@vlan.group('range') +@click.pass_context +def vlan_range(ctx): + """VLAN-range related configuration tasks""" + pass + +@vlan_range.command('add') +@click.argument('vid1', metavar='', required=True, type=int) +@click.argument('vid2', metavar='', required=True, type=int) +@click.option('-w', "--warning", is_flag=True, help='warnings are not suppressed') +@click.pass_context +def add_vlan_range(ctx, vid1, vid2, warning): + db = ctx.obj['db'] + + vlan_range_validate(ctx, vid1, vid2) + + vid2 = vid2+1 + + warning_vlans_list = [] + curr_vlan_count = 0 + clients = db.redis_clients["CONFIG_DB"] + pipe = clients.pipeline() + for vid in range (vid1, vid2): + vlan = 'Vlan{}'.format(vid) + + if len(db.get_entry('VLAN', vlan)) != 0: + if warning is True: + warning_vlans_list.append(vid) + continue + + pipe.hmset('VLAN|{}'.format(vlan), {'vlanid': vid}) + curr_vlan_count += 1 + pipe.execute() + # Log warning messages if 'warning' option is enabled + if warning is True: + if len(warning_vlans_list) != 0: + logging.warning('VLANs already existing: {}'.format(get_hyphenated_string(warning_vlans_list))) + +@vlan_range.command('del') +@click.argument('vid1', metavar='', required=True, type=int) +@click.argument('vid2', metavar='', required=True, type=int) +@click.option('-w', "--warning", is_flag=True, help='warnings are not suppressed') +@click.pass_context +def del_vlan_range(ctx, vid1, vid2, warning): + db = ctx.obj['db'] + + vlan_range_validate(ctx, vid1, vid2) + + vid2 = vid2+1 + + warning_vlans_list = [] + warning_membership_list = [] + warning_ip_list = [] + clients = db.redis_clients["CONFIG_DB"] + pipe = clients.pipeline() + vlan_members = [] + vlan_member_keys = db.keys('CONFIG_DB', "*VLAN_MEMBER*") + vlan_temp_member_keys = db.keys('CONFIG_DB', "*VLAN_MEMBER*") + vlan_ip_members = [] + vlan_ip_keys = db.keys('CONFIG_DB', "*VLAN_INTERFACE*") + + # Fetch the interfaces from config_db associated with *VLAN_MEMBER* + stored_intf_list = [] + if vlan_temp_member_keys is not None: + for x in range(len(vlan_temp_member_keys)): + member_list = vlan_temp_member_keys[x].split('|',2) + stored_intf_list.append(str(member_list[2])) + + stored_intf_list = list(set(stored_intf_list)) + list_length = len(stored_intf_list) + + # Fetch VLAN participation list for each interface + vid = range(vid1, vid2) + if vlan_temp_member_keys is not None and list_length != 0: + for i in range(list_length): + stored_vlan_list = [] + for x in list(vlan_temp_member_keys): + member_list = x.split('|',2) + fetched_vlan = int(re.search(r'\d+', member_list[1]).group()) + if stored_intf_list[i] == str(member_list[2]): + if fetched_vlan in vid: + stored_vlan_list.append(fetched_vlan) + vlan_temp_member_keys.remove(x) + + if len(stored_vlan_list) != 0: + warning_string = str(stored_intf_list[i]) + ' is member of ' + get_hyphenated_string(stored_vlan_list) + warning_membership_list.append(warning_string) + + if vlan_ip_keys is None and vlan_member_keys is None: + for vid in range(vid1, vid2): + vlan = 'Vlan{}'.format(vid) + if len(db.get_entry('VLAN', vlan)) == 0: + if warning is True: + warning_vlans_list.append(vid) + continue + + pipe.delete('VLAN|{}'.format(vlan)) + pipe.execute() + else: + if vlan_ip_keys is not None: + for v in vlan_ip_keys: + pipe.hgetall(v) + vlan_ip_members = pipe.execute() + if vlan_member_keys is not None: + for v in vlan_member_keys: + pipe.hgetall(v) + vlan_members = pipe.execute() + for vid in range(vid1, vid2): + vlan_member_configured = False + ip_configured = False + vlan = 'Vlan{}'.format(vid) + + if len(db.get_entry('VLAN', vlan)) == 0: + if warning is True: + warning_vlans_list.append(vid) + continue + + if vlan_member_keys is not None: + for x in range(len(vlan_member_keys)): + vlan_member_configured = False + member_list = vlan_member_keys[x].split('|',2) + fetched_vlan = int(re.search(r'\d+', member_list[1]).group()) + if(fetched_vlan == vid): + if "Ethernet" or "PortChannel" in str(member_list[2]): + vlan_member_configured = True + break + + if vlan_member_configured is True: + continue + + if vlan_ip_keys is not None: + for x in range(len(vlan_ip_keys)): + ip_configured = False + member_list = vlan_ip_keys[x].split('|',2) + fetched_vlan = int(re.search(r'\d+', member_list[1]).group()) + if(fetched_vlan == vid): + if warning is True: + warning_ip_list.append(vid) + ip_configured = True + break + + if ip_configured is True: + continue + + vlan = 'Vlan{}'.format(vid) + pipe.delete('VLAN|{}'.format(vlan)) + pipe.execute() + + # Log warning messages if 'warning' option is enabled + if warning is True and len(warning_vlans_list) != 0: + logging.warning('Non-existent VLANs: {}'.format(get_hyphenated_string(warning_vlans_list))) + if warning is True and len(warning_membership_list) != 0: + logging.warning('Remove VLAN membership before removing VLAN: {}'.format(warning_membership_list)) + if warning is True and len(warning_ip_list) != 0: + warning_string = 'Vlans configured with IP: ' + get_hyphenated_string(warning_ip_list) + logging.warning('Remove IP configuration before removing VLAN: {}'.format(warning_string)) + +# +# 'member range' group ('config vlan member range ...') +# +@vlan_member.group('range') +@click.pass_context +def vlan_member_range(ctx): + """VLAN member range related configuration tasks""" + pass + +# +# Returns VLAN data in a format required to perform redisDB operations. +# +def vlan_member_data(member_list): + vlan_data = {} + for key in member_list: + value = member_list[key] + if type(value) is list: + vlan_data[key+'@'] = ','.join(value) + else: + vlan_data[key] = str(value) + return vlan_data + +@vlan_member_range.command('add') +@click.argument('vid1', metavar='', required=True, type=int) +@click.argument('vid2', metavar='', required=True, type=int) +@click.argument('interface_name', metavar='', required=True) +@click.option('-u', '--untagged', is_flag=True) +@click.option('-w', "--warning", is_flag=True, help='warnings are not suppressed') +@click.pass_context +def add_vlan_member_range(ctx, vid1, vid2, interface_name, untagged, warning): + db = ctx.obj['db'] + + vlan_range_validate(ctx, vid1, vid2) + + if get_interface_naming_mode() == "alias": + interface_name = interface_alias_to_name(interface_name) + if interface_name is None: + ctx.fail("'interface_name' is None!") + + if interface_name_is_valid(db, interface_name) is False: + ctx.fail("Interface name is invalid!!") + + vid2 = vid2+1 + vlan_count = vid2-vid1 + if untagged is True and (vlan_count >= 2): + ctx.fail("Same interface {} cannot be untagged member of more than one VLAN".format(interface_name)) + + warning_vlans_list = [] + warning_membership_list = [] + clients = db.redis_clients["CONFIG_DB"] + pipe = clients.pipeline() + + # Validate if interface has IP configured + # in physical and port channel tables + for k,v in db.get_table('INTERFACE').iteritems(): + if k == interface_name: + ctx.fail(" {} has ip address configured".format(interface_name)) + + for k,v in db.get_table('PORTCHANNEL_INTERFACE').iteritems(): + if k == interface_name: + ctx.fail(" {} has ip address configured".format(interface_name)) + + for k,v in db.get_table('PORTCHANNEL_MEMBER'): + if v == interface_name: + ctx.fail(" {} is configured as a port channel member".format(interface_name)) + + for vid in range(vid1, vid2): + vlan_name = 'Vlan{}'.format(vid) + vlan = db.get_entry('VLAN', vlan_name) + + if len(vlan) == 0: + if warning is True: + warning_vlans_list.append(vid) + continue + + members = vlan.get('members', []) + if interface_name in members: + if warning is True: + warning_membership_list.append(vid) + if get_interface_naming_mode() == "alias": + interface_name = interface_name_to_alias(interface_name) + if interface_name is None: + ctx.fail("'interface_name' is None!") + continue + else: + continue + + members.append(interface_name) + vlan['members'] = members + pipe.hmset('VLAN|{}'.format(vlan_name), vlan_member_data(vlan)) + pipe.hmset('VLAN_MEMBER|{}'.format(vlan_name+'|'+interface_name), {'tagging_mode': "untagged" if untagged else "tagged" }) + # If port is being made L2 port, enable STP + pipe.execute() + # Log warning messages if 'warning' option is enabled + if warning is True and len(warning_vlans_list) != 0: + logging.warning('Non-existent VLANs: {}'.format(get_hyphenated_string(warning_vlans_list))) + if warning is True and len(warning_membership_list) != 0: + if(len(warning_membership_list) == 1): + vlan_string = 'Vlan: ' + else: + vlan_string = 'Vlans: ' + warning_string = str(interface_name) + ' is already a member of ' + vlan_string + get_hyphenated_string(warning_membership_list) + logging.warning('Membership exists already: {}'.format(warning_string)) + +@vlan_member_range.command('del') +@click.argument('vid1', metavar='', required=True, type=int) +@click.argument('vid2', metavar='', required=True, type=int) +@click.argument('interface_name', metavar='', required=True) +@click.option('-w', "--warning", is_flag=True, help='warnings are not suppressed') +@click.pass_context +def del_vlan_member_range(ctx, vid1, vid2, interface_name, warning): + db = ctx.obj['db'] + + vlan_range_validate(ctx, vid1, vid2) + + if get_interface_naming_mode() == "alias": + interface_name = interface_alias_to_name(interface_name) + if interface_name is None: + ctx.fail("'interface_name' is None!") + + if interface_name_is_valid(db, interface_name) is False: + ctx.fail("Interface name is invalid!!") + + vid2 = vid2+1 + + warning_vlans_list = [] + warning_membership_list = [] + clients = db.redis_clients["CONFIG_DB"] + pipe = clients.pipeline() + + for vid in range(vid1, vid2): + vlan_name = 'Vlan{}'.format(vid) + vlan = db.get_entry('VLAN', vlan_name) + + if len(vlan) == 0: + if warning is True: + warning_vlans_list.append(vid) + continue + + members = vlan.get('members', []) + if interface_name not in members: + if warning is True: + warning_membership_list.append(vid) + if get_interface_naming_mode() == "alias": + interface_name = interface_name_to_alias(interface_name) + if interface_name is None: + ctx.fail("'interface_name' is None!") + continue + else: + continue + + members.remove(interface_name) + if len(members) == 0: + pipe.hdel('VLAN|{}'.format(vlan_name), 'members@') + else: + vlan['members'] = members + pipe.hmset('VLAN|{}'.format(vlan_name), vlan_member_data(vlan)) + + pipe.delete('VLAN_MEMBER|{}'.format(vlan_name+'|'+interface_name)) + pipe.delete('STP_VLAN_INTF|{}'.format(vlan_name + '|' + interface_name)) + pipe.execute() + # Log warning messages if 'warning' option is enabled + if warning is True and len(warning_vlans_list) != 0: + logging.warning('Non-existent VLANs: {}'.format(get_hyphenated_string(warning_vlans_list))) + if warning is True and len(warning_membership_list) != 0: + if(len(warning_membership_list) == 1): + vlan_string = 'Vlan: ' + else: + vlan_string = 'Vlans: ' + warning_string = str(interface_name) + ' is not a member of ' + vlan_string + get_hyphenated_string(warning_membership_list) + logging.warning('Non-existent membership: {}'.format(warning_string)) + +# +# 'mac' group ('config mac ...') +# +@config.group() +@click.pass_context +@click.option('-s', '--redis-unix-socket-path', help='unix socket path for redis connection') +def mac(ctx, redis_unix_socket_path): + """Mac-related configuration tasks""" + kwargs = {} + if redis_unix_socket_path: + kwargs['unix_socket_path'] = redis_unix_socket_path + config_db = ConfigDBConnector(**kwargs) + config_db.connect(wait_for_init=False) + ctx.obj = {'db': config_db} + pass + +@mac.command('aging_time') +@click.argument('interval', metavar='', required=True, type=int) +@click.pass_context +def set_aging_time(ctx, interval): + db = ctx.obj['db'] + if interval not in range(0,1000001): + ctx.fail("Aging timer must be in range [0-1000000]") + db.set_entry('SWITCH', 'switch', {'fdb_aging_time': interval}) + +@mac.command('add') +@click.argument('mac', metavar='', required=True) +@click.argument('vlan', metavar='', required=True, type=int) +@click.argument('interface_name', metavar='', required=True) +@click.pass_context +def add_mac(ctx, mac, vlan, interface_name): + db = ctx.obj['db'] + + mac_valid = bool(re.match('^' + '[\:\-]'.join(['([0-9a-f]{2})']*6) + '$', mac.lower())) + if mac_valid == False: + ctx.fail("Incorrect mac-address format!!") + + mac_valid = not bool(re.match('^' + '[\:\-]'.join(['([00]{2})']*6) + '$', mac.lower())) + if mac_valid == False: + ctx.fail("Invalid (Zero) mac-address!!") + + mac_valid = not bool(re.match('^' + '[\:\-]'.join(['([ff]{2})']*6) + '$', mac.lower())) + if mac_valid == False: + ctx.fail("Invalid (Bcast) mac-address!!") + + mac_is_multicast = int(mac[:2]) & 1; + if mac_is_multicast == True: + ctx.fail("Invalid (Multicast) mac-address!!") + + vlan_valid = bool(vlan_id_is_valid(vlan)) + if vlan_valid == False: + ctx.fail("Invalid VlanId!!") + + vlan_name = 'Vlan{}'.format(vlan) + + if get_interface_naming_mode() == "alias": + interface_name = interface_alias_to_name(interface_name) + if interface_name is None: + ctx.fail("'interface_name' is None!") + + if interface_name_is_valid(db, interface_name) is False: + ctx.fail("Interface name is invalid!!") + + db.set_entry('FDB', (vlan_name, mac), {'port': interface_name }) + +@mac.command('del') +@click.argument('mac', metavar='', required=True) +@click.argument('vlan', metavar='', required=True, type=int) +@click.pass_context +def del_mac(ctx, mac, vlan): + db = ctx.obj['db'] + + mac_valid = bool(re.match('^' + '[\:\-]'.join(['([0-9a-f]{2})']*6) + '$', mac.lower())) + if mac_valid == False: + ctx.fail("Incorrect mac-address format!!") + + vlan_valid = bool(vlan_id_is_valid(vlan)) + if vlan_valid == False: + ctx.fail("Invalid VlanId!!") + + vlan_name = 'Vlan{}'.format(vlan) + + db.set_entry('FDB', (vlan_name, mac), None) + + # # 'bgp' group ('config bgp ...') # @@ -980,7 +1435,7 @@ def startup(ctx, interface_name): if interface_name is None: ctx.fail("'interface_name' is None!") - if interface_name_is_valid(interface_name) is False: + if interface_name_is_valid(config_db, interface_name) is False: ctx.fail("Interface name is invalid. Please enter a valid interface name!!") if interface_name.startswith("Ethernet"): @@ -1002,7 +1457,7 @@ def shutdown(ctx, interface_name): if interface_name is None: ctx.fail("'interface_name' is None!") - if interface_name_is_valid(interface_name) is False: + if interface_name_is_valid(config_db, interface_name) is False: ctx.fail("Interface name is invalid. Please enter a valid interface name!!") if interface_name.startswith("Ethernet"): @@ -1355,6 +1810,7 @@ def naming_mode_alias(): """Set CLI interface naming mode to ALIAS (Vendor port alias)""" set_interface_naming_mode('alias') + # # 'syslog' group ('config syslog ...') # @@ -1462,4 +1918,4 @@ def del_ntp_server(ctx, ntp_ip_address): ctx.fail("Restart service ntp-config failed with error {}".format(e)) if __name__ == '__main__': - config() \ No newline at end of file + config() diff --git a/scripts/fast-reboot-dump.py b/scripts/fast-reboot-dump.py index 83387ad755..82203f0322 100644 --- a/scripts/fast-reboot-dump.py +++ b/scripts/fast-reboot-dump.py @@ -11,6 +11,7 @@ import argparse import syslog import traceback +import datetime ARP_CHUNK = binascii.unhexlify('08060001080006040001') # defines a part of the packet for ARP Request @@ -147,6 +148,108 @@ def get_fdb(db, vlan_name, vlan_id, bridge_id_2_iface): return fdb_entries, available_macs, map_mac_ip +def generate_fdb_entries_2(filename): + #print("START generate_fdb_entries_2 " + datetime.datetime.now().strftime("%H:%M:%S.%f")) + fdb_entries = [] + map_vlan_oid_to_vlan_id = {} + map_vlan_id_to_vlan_oid = {} + vlan_oid_list = [] + all_available_macs = set() + map_mac_ip_per_vlan = {} + + db = swsssdk.SonicV2Connector(host='127.0.0.1') + db.connect(db.ASIC_DB, False) # Make one attempt only + + bridge_id_2_iface = get_map_bridge_port_id_2_iface_name(db) + + vlan_ifaces = get_vlan_ifaces() + for vlan in vlan_ifaces: + map_mac_ip_per_vlan[vlan] = {} + + client = db.redis_clients["ASIC_DB"] + pipe = client.pipeline() + + #print("generate_fdb_entries_2 before vlan-key-getall" + datetime.datetime.now().strftime("%H:%M:%S.%f")) + vlan_list = db.keys(db.ASIC_DB, 'ASIC_STATE:SAI_OBJECT_TYPE_VLAN:oid:*') + vlan_list = [] if vlan_list is None else vlan_list + for vlan_entry in vlan_list: + vlan_oid = vlan_entry.replace('ASIC_STATE:SAI_OBJECT_TYPE_VLAN:', '') + map_vlan_oid_to_vlan_id[vlan_oid] = 0 + vlan_oid_list.append(vlan_oid) + pipe.hgetall(vlan_entry) + vlan_values = pipe.execute() + #print("generate_fdb_entries_2 after vlan-key-getall" + datetime.datetime.now().strftime("%H:%M:%S.%f")) + + #print("generate_fdb_entries_2 before vlan-map" + datetime.datetime.now().strftime("%H:%M:%S.%f")) + posi = 0 + for vlan_ent in vlan_values: + if 'SAI_VLAN_ATTR_VLAN_ID' not in vlan_ent: + posi = posi + 1 + continue + vlan_id = int(vlan_ent['SAI_VLAN_ATTR_VLAN_ID']) + vlan_oid = vlan_oid_list[posi] + map_vlan_id_to_vlan_oid[vlan_id] = vlan_oid + map_vlan_oid_to_vlan_id[vlan_oid] = vlan_id + posi = posi + 1 + #print("generate_fdb_entries_2 after vlan-map" + datetime.datetime.now().strftime("%H:%M:%S.%f")) + + #print("generate_fdb_entries_2 before fdb-key-getall" + datetime.datetime.now().strftime("%H:%M:%S.%f")) + pipe = client.pipeline() + fdb_list = db.keys(db.ASIC_DB, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY:*") + fdb_list = [] if fdb_list is None else fdb_list + for s in fdb_list: + pipe.hgetall(s) + fdb_values = pipe.execute() + #print("generate_fdb_entries_2 after fdb-key-getall" + datetime.datetime.now().strftime("%H:%M:%S.%f")) + + #print("generate_fdb_entries_2 before fdb-process" + datetime.datetime.now().strftime("%H:%M:%S.%f")) + posi = 0 + for fdb_ent in fdb_values: + if 'SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID' not in fdb_ent: + posi = posi + 1 + continue + br_port_id = fdb_ent[b"SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID"] + if br_port_id not in bridge_id_2_iface: + posi = posi + 1 + continue + fdb_port = bridge_id_2_iface[br_port_id] + ent_type = fdb_ent[b"SAI_FDB_ENTRY_ATTR_TYPE"] + fdb_type = ['dynamic','static'][ent_type == "SAI_FDB_ENTRY_TYPE_STATIC"] + key = fdb_list[posi] + key_obj = json.loads(key.replace('ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY:', '')) + mac = str(key_obj['mac']) + vlan_id = map_vlan_oid_to_vlan_id[key_obj['bvid']] + vlan_name = "Vlan" + str(vlan_id) + if not is_mac_unicast(mac): + posi = posi + 1 + continue + all_available_macs.add((vlan_name, mac.lower())) + fdb_mac = mac.replace(':', '-') + obj = { + 'FDB_TABLE:Vlan%d:%s' % (vlan_id, fdb_mac) : { + 'type': fdb_type, + 'port': fdb_port, + }, + 'OP': 'SET' + } + + fdb_entries.append(obj) + if map_mac_ip_per_vlan.get(vlan_name) is None: + map_mac_ip_per_vlan[vlan_name] = {} + map_mac_ip_per_vlan[vlan_name][mac.lower()] = fdb_port + posi = posi + 1 + + #print("generate_fdb_entries_2 after fdb-process" + datetime.datetime.now().strftime("%H:%M:%S.%f")) + db.close(db.ASIC_DB) + + with open(filename, 'w') as fp: + json.dump(fdb_entries, fp, indent=2, separators=(',', ': ')) + + #print("map_mac_ip_per_vlan :" + str(map_mac_ip_per_vlan)) + #print("all_available_macs :" + str(all_available_macs)) + #print("END generate_fdb_entries_2 " + datetime.datetime.now().strftime("%H:%M:%S.%f")) + return all_available_macs, map_mac_ip_per_vlan + def generate_fdb_entries(filename): fdb_entries = [] @@ -270,10 +373,14 @@ def main(): if not os.path.isdir(root_dir): print "Target directory '%s' not found" % root_dir return 3 - all_available_macs, map_mac_ip_per_vlan = generate_fdb_entries(root_dir + '/fdb.json') + #start_time = datetime.datetime.now().strftime("%H:%M:%S.%f") + all_available_macs, map_mac_ip_per_vlan = generate_fdb_entries_2(root_dir + '/fdb.json') + #print("all available macs : " + str(all_available_macs)) arp_entries = generate_arp_entries(root_dir + '/arp.json', all_available_macs) generate_default_route_entries(root_dir + '/default_routes.json') garp_send(arp_entries, map_mac_ip_per_vlan) + #end_time = datetime.datetime.now().strftime("%H:%M:%S.%f") + #print("START :" + start_time + "====" + "END :" + end_time) return 0 if __name__ == '__main__': diff --git a/scripts/fdbclear b/scripts/fdbclear index a8100af2cb..e1d07938a8 100644 --- a/scripts/fdbclear +++ b/scripts/fdbclear @@ -44,12 +44,17 @@ def main(): try: fdb = FdbClear() if args.vlan is not None: - print("command not supported yet.") + if (args.vlan.find("Vlan",0,4) == -1): + print ("error:vlan id is not in 'Vlan...' format") + else: + fdb.send_notification("VLAN", args.vlan) + print("Dynamic FDB entries are cleared on VLAN.", args.vlan) elif args.port is not None: - print("command not supported yet.") + fdb.send_notification("PORT", args.port) + print("Dynamic FDB entries are cleared on Port.", args.port) else: fdb.send_notification("ALL", "ALL") - print("FDB entries are cleared.") + print("Dynamic FDB entries are cleared.") except Exception as e: print e.message sys.exit(1) diff --git a/show/main.py b/show/main.py index da4e3ae879..4e16dae0fe 100755 --- a/show/main.py +++ b/show/main.py @@ -869,6 +869,46 @@ def mac(vlan, port, verbose): run_command(cmd, display_cmd=verbose) +@mac.command() +def aging_time(): + """Show MAC Aging-Time""" + config_db = ConfigDBConnector() + config_db.connect() + + # Fetching data from config_db for SWITCH + switch_table = config_db.get_table('SWITCH') + switch_keys = switch_table.keys() + + age_time = 0 + for key in switch_keys: + if key == "switch": + try: + age_time = switch_table[key]['fdb_aging_time'] + except KeyError: + age_time = '0' + pass + output = 'Mac Aging-Time : ' + output += ('%s seconds\n' % (str(age_time))) + click.echo(output) + +@mac.command() +def count(): + """Show MAC count""" + db = SonicV2Connector(host="127.0.0.1") + db.connect(db.ASIC_DB) + + # Fetching FDB keys from ASIC DB + fdb_keys = db.keys('ASIC_DB', "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY:*") + + if not fdb_keys: + fdb_count = 0 + else: + fdb_count = len(fdb_keys) + + output = 'Total MAC count:' + output += ('%s \n' % (str(fdb_count))) + click.echo(output) + # # 'show route-map' command ("show route-map") # @@ -1707,6 +1747,24 @@ def tablelize(keys, data): header = ['Name', 'VID', 'Member', 'Mode'] click.echo(tabulate(tablelize(keys, data), header)) +@vlan.command() +def count(): + """Show Vlan count""" + config_db = ConfigDBConnector() + config_db.connect() + + # Fetching Vlan keys from config DB + vlan_keys = config_db.keys('CONFIG_DB', "VLAN|*") + + if not vlan_keys: + vlan_count = 0 + else: + vlan_count = len(vlan_keys) + + output = 'Total Vlan count:' + output += ('%s \n' % (str(vlan_count))) + click.echo(output) + @cli.command('services') def services(): """Show all daemon services""" From 7d272ed5dfb3674380e630882f74397fb443d708 Mon Sep 17 00:00:00 2001 From: anilkpandey <47642449+anilkpandey@users.noreply.github.com> Date: Sat, 7 Sep 2019 18:21:49 -0700 Subject: [PATCH 11/42] Layer 2 Forwarding Enhancements --- show/main.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/show/main.py b/show/main.py index 4e16dae0fe..a1f04038ef 100755 --- a/show/main.py +++ b/show/main.py @@ -852,22 +852,20 @@ def pwm_buffer_pool(): # 'mac' command ("show mac ...") # -@cli.command() +@cli.group(invoke_without_command=True) +@click.pass_context @click.option('-v', '--vlan') @click.option('-p', '--port') @click.option('--verbose', is_flag=True, help="Enable verbose output") -def mac(vlan, port, verbose): +def mac(ctx, vlan, port, verbose): """Show MAC (FDB) entries""" - - cmd = "fdbshow" - - if vlan is not None: - cmd += " -v {}".format(vlan) - - if port is not None: - cmd += " -p {}".format(port) - - run_command(cmd, display_cmd=verbose) + if ctx.invoked_subcommand is None: + cmd = "fdbshow" + if vlan is not None: + cmd += " -v {}".format(vlan) + if port is not None: + cmd += " -p {}".format(port) + run_command(cmd, display_cmd=verbose) @mac.command() def aging_time(): From 2c504a310e6e6e503f27e03247d29a5d0d82cfe0 Mon Sep 17 00:00:00 2001 From: anilkpandey <47642449+anilkpandey@users.noreply.github.com> Date: Fri, 8 Nov 2019 11:28:40 -0800 Subject: [PATCH 12/42] Update main.py --- config/main.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/config/main.py b/config/main.py index 112dcc5202..dc3647090d 100755 --- a/config/main.py +++ b/config/main.py @@ -2368,11 +2368,11 @@ def interface(ctx): @click.argument('ifname', metavar='', required=True, type=str) @click.pass_context def enable(ctx, ifname): - if not interface_name_is_valid(ifname) and ifname != 'all': + config_db = ctx.obj['db'] + if not interface_name_is_valid(config_db, ifname) and ifname != 'all': click.echo("Invalid interface name") return - config_db = ctx.obj['db'] intf_dict = config_db.get_table('SFLOW_SESSION') if intf_dict and ifname in intf_dict.keys(): @@ -2388,11 +2388,11 @@ def enable(ctx, ifname): @click.argument('ifname', metavar='', required=True, type=str) @click.pass_context def disable(ctx, ifname): - if not interface_name_is_valid(ifname) and ifname != 'all': + config_db = ctx.obj['db'] + if not interface_name_is_valid(config_db, ifname) and ifname != 'all': click.echo("Invalid interface name") return - config_db = ctx.obj['db'] intf_dict = config_db.get_table('SFLOW_SESSION') if intf_dict and ifname in intf_dict.keys(): @@ -2410,14 +2410,14 @@ def disable(ctx, ifname): @click.argument('rate', metavar='', required=True, type=int) @click.pass_context def sample_rate(ctx, ifname, rate): - if not interface_name_is_valid(ifname) and ifname != 'all': + config_db = ctx.obj['db'] + if not interface_name_is_valid(config_db, ifname) and ifname != 'all': click.echo('Invalid interface name') return if not is_valid_sample_rate(rate): click.echo('Error: Sample rate must be between 256 and 8388608') return - config_db = ctx.obj['db'] sess_dict = config_db.get_table('SFLOW_SESSION') if sess_dict and ifname in sess_dict.keys(): From 714001d64bfb9bd7c93cd822c7bb4f189ba7f5ca Mon Sep 17 00:00:00 2001 From: anilkpandey <47642449+anilkpandey@users.noreply.github.com> Date: Fri, 8 Nov 2019 13:50:29 -0800 Subject: [PATCH 13/42] Update main.py --- config/main.py | 56 +++++++++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/config/main.py b/config/main.py index dc3647090d..6c1f644a6e 100755 --- a/config/main.py +++ b/config/main.py @@ -112,37 +112,33 @@ def interface_alias_to_name(interface_alias): return interface_alias if sub_intf_sep_idx == -1 else interface_alias + VLAN_SUB_INTERFACE_SEPARATOR + vlan_id -def interface_name_is_valid(config_db, interface_name): +def interface_name_is_valid(interface_name): """Check if the interface name is valid """ + config_db = ConfigDBConnector() + config_db.connect() + port_dict = config_db.get_table('PORT') + port_channel_dict = config_db.get_table('PORTCHANNEL') sub_port_intf_dict = config_db.get_table('VLAN_SUB_INTERFACE') if get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(interface_name) if interface_name is not None: - if interface_name.startswith("Ethernet"): - port_dict = config_db.get_table('PORT') - if not port_dict: - click.echo("port_dict is None!") - raise click.Abort() - - for port_name in port_dict.keys(): - if interface_name == port_name: + if not port_dict: + click.echo("port_dict is None!") + raise click.Abort() + for port_name in port_dict.keys(): + if interface_name == port_name: + return True + if port_channel_dict: + for port_channel_name in port_channel_dict.keys(): + if interface_name == port_channel_name: return True - - if interface_name.startswith("PortChannel"): - port_channel_dict = config_db.get_table('PORTCHANNEL') - if port_channel_dict: - for port_channel_name in port_channel_dict.keys(): - if interface_name == port_channel_name: - return True - if sub_port_intf_dict: for sub_port_intf_name in sub_port_intf_dict.keys(): if interface_name == sub_port_intf_name: return True - return False def vlan_id_is_valid(vid): @@ -1396,7 +1392,7 @@ def add_vlan_member_range(ctx, vid1, vid2, interface_name, untagged, warning): if interface_name is None: ctx.fail("'interface_name' is None!") - if interface_name_is_valid(db, interface_name) is False: + if interface_name_is_valid(interface_name) is False: ctx.fail("Interface name is invalid!!") vid2 = vid2+1 @@ -1477,7 +1473,7 @@ def del_vlan_member_range(ctx, vid1, vid2, interface_name, warning): if interface_name is None: ctx.fail("'interface_name' is None!") - if interface_name_is_valid(db, interface_name) is False: + if interface_name_is_valid(interface_name) is False: ctx.fail("Interface name is invalid!!") vid2 = vid2+1 @@ -1589,7 +1585,7 @@ def add_mac(ctx, mac, vlan, interface_name): if interface_name is None: ctx.fail("'interface_name' is None!") - if interface_name_is_valid(db, interface_name) is False: + if interface_name_is_valid(interface_name) is False: ctx.fail("Interface name is invalid!!") db.set_entry('FDB', (vlan_name, mac), {'port': interface_name }) @@ -1714,7 +1710,7 @@ def startup(ctx, interface_name): if interface_name is None: ctx.fail("'interface_name' is None!") - if interface_name_is_valid(config_db, interface_name) is False: + if interface_name_is_valid(interface_name) is False: ctx.fail("Interface name is invalid. Please enter a valid interface name!!") if interface_name.startswith("Ethernet"): @@ -1742,7 +1738,7 @@ def shutdown(ctx, interface_name): if interface_name is None: ctx.fail("'interface_name' is None!") - if interface_name_is_valid(config_db, interface_name) is False: + if interface_name_is_valid(interface_name) is False: ctx.fail("Interface name is invalid. Please enter a valid interface name!!") if interface_name.startswith("Ethernet"): @@ -2368,11 +2364,11 @@ def interface(ctx): @click.argument('ifname', metavar='', required=True, type=str) @click.pass_context def enable(ctx, ifname): - config_db = ctx.obj['db'] - if not interface_name_is_valid(config_db, ifname) and ifname != 'all': + if not interface_name_is_valid(ifname) and ifname != 'all': click.echo("Invalid interface name") return - + + config_db = ctx.obj['db'] intf_dict = config_db.get_table('SFLOW_SESSION') if intf_dict and ifname in intf_dict.keys(): @@ -2388,11 +2384,11 @@ def enable(ctx, ifname): @click.argument('ifname', metavar='', required=True, type=str) @click.pass_context def disable(ctx, ifname): - config_db = ctx.obj['db'] - if not interface_name_is_valid(config_db, ifname) and ifname != 'all': + if not interface_name_is_valid(ifname) and ifname != 'all': click.echo("Invalid interface name") return - + + config_db = ctx.obj['db'] intf_dict = config_db.get_table('SFLOW_SESSION') if intf_dict and ifname in intf_dict.keys(): @@ -2410,7 +2406,6 @@ def disable(ctx, ifname): @click.argument('rate', metavar='', required=True, type=int) @click.pass_context def sample_rate(ctx, ifname, rate): - config_db = ctx.obj['db'] if not interface_name_is_valid(config_db, ifname) and ifname != 'all': click.echo('Invalid interface name') return @@ -2418,6 +2413,7 @@ def sample_rate(ctx, ifname, rate): click.echo('Error: Sample rate must be between 256 and 8388608') return + config_db = ctx.obj['db'] sess_dict = config_db.get_table('SFLOW_SESSION') if sess_dict and ifname in sess_dict.keys(): From 83cbba420580f6345caf136016dc609cb667919a Mon Sep 17 00:00:00 2001 From: anilkpandey <47642449+anilkpandey@users.noreply.github.com> Date: Fri, 8 Nov 2019 14:23:42 -0800 Subject: [PATCH 14/42] Update main.py --- config/main.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/config/main.py b/config/main.py index 6c1f644a6e..545ab18225 100755 --- a/config/main.py +++ b/config/main.py @@ -2170,7 +2170,6 @@ def naming_mode_alias(): """Set CLI interface naming mode to ALIAS (Vendor port alias)""" set_interface_naming_mode('alias') - # # 'syslog' group ('config syslog ...') # @@ -2367,7 +2366,8 @@ def enable(ctx, ifname): if not interface_name_is_valid(ifname) and ifname != 'all': click.echo("Invalid interface name") return - + + config_db = ctx.obj['db'] intf_dict = config_db.get_table('SFLOW_SESSION') @@ -2387,7 +2387,8 @@ def disable(ctx, ifname): if not interface_name_is_valid(ifname) and ifname != 'all': click.echo("Invalid interface name") return - + + config_db = ctx.obj['db'] intf_dict = config_db.get_table('SFLOW_SESSION') @@ -2406,7 +2407,7 @@ def disable(ctx, ifname): @click.argument('rate', metavar='', required=True, type=int) @click.pass_context def sample_rate(ctx, ifname, rate): - if not interface_name_is_valid(config_db, ifname) and ifname != 'all': + if not interface_name_is_valid(ifname) and ifname != 'all': click.echo('Invalid interface name') return if not is_valid_sample_rate(rate): From ff828a8e5c60b910aeb5581e3454d3c055ab0c6c Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Thu, 13 Aug 2020 19:23:06 -0700 Subject: [PATCH 15/42] move "show vlan count" command to vlan.py --- show/main.py | 18 ------------------ show/vlan.py | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/show/main.py b/show/main.py index 8f110a2571..c44519c934 100755 --- a/show/main.py +++ b/show/main.py @@ -1773,24 +1773,6 @@ def tablelize(keys, data): header = ['Name', 'VID', 'Member', 'Mode'] click.echo(tabulate(tablelize(keys, data), header)) -@vlan.command() -def count(): - """Show Vlan count""" - config_db = ConfigDBConnector() - config_db.connect() - - # Fetching Vlan keys from config DB - vlan_keys = config_db.keys('CONFIG_DB', "VLAN|*") - - if not vlan_keys: - vlan_count = 0 - else: - vlan_count = len(vlan_keys) - - output = 'Total Vlan count:' - output += ('%s \n' % (str(vlan_count))) - click.echo(output) - @cli.command('services') def services(): """Show all daemon services""" diff --git a/show/vlan.py b/show/vlan.py index fa0eb524fd..a34842d3bf 100644 --- a/show/vlan.py +++ b/show/vlan.py @@ -130,3 +130,21 @@ def tablelize(keys, data): header = ['Name', 'VID', 'Member', 'Mode'] click.echo(tabulate(tablelize(keys, data), header)) + +@vlan.command() +def count(): + """Show Vlan count""" + config_db = ConfigDBConnector() + config_db.connect() + + # Fetching Vlan keys from config DB + vlan_keys = config_db.keys('CONFIG_DB', "VLAN|*") + + if not vlan_keys: + vlan_count = 0 + else: + vlan_count = len(vlan_keys) + + output = 'Total Vlan count:' + output += ('%s \n' % (str(vlan_count))) + click.echo(output) From 1289a590ec2c2dda3055c5ceb1d14ed9cb29407c Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Thu, 13 Aug 2020 19:38:29 -0700 Subject: [PATCH 16/42] Update main.py --- show/main.py | 128 --------------------------------------------------- 1 file changed, 128 deletions(-) diff --git a/show/main.py b/show/main.py index c44519c934..80d38256be 100755 --- a/show/main.py +++ b/show/main.py @@ -1645,134 +1645,6 @@ def log(record, lines): else: run_command("sonic-kdump-config --file %s --lines %s" % (record, lines)) -@vlan.command() -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def brief(verbose): - """Show all bridge information""" - config_db = ConfigDBConnector() - config_db.connect() - header = ['VLAN ID', 'IP Address', 'Ports', 'Port Tagging', 'DHCP Helper Address'] - body = [] - vlan_keys = [] - - # Fetching data from config_db for VLAN, VLAN_INTERFACE and VLAN_MEMBER - vlan_dhcp_helper_data = config_db.get_table('VLAN') - vlan_ip_data = config_db.get_table('VLAN_INTERFACE') - vlan_ports_data = config_db.get_table('VLAN_MEMBER') - - # Defining dictionaries for DHCP Helper address, Interface Gateway IP, - # VLAN ports and port tagging - vlan_dhcp_helper_dict = {} - vlan_ip_dict = {} - vlan_ports_dict = {} - vlan_tagging_dict = {} - - # Parsing DHCP Helpers info - for key in natsorted(vlan_dhcp_helper_data.keys()): - try: - if vlan_dhcp_helper_data[key]['dhcp_servers']: - vlan_dhcp_helper_dict[str(key.strip('Vlan'))] = vlan_dhcp_helper_data[key]['dhcp_servers'] - except KeyError: - vlan_dhcp_helper_dict[str(key.strip('Vlan'))] = " " - - # Parsing VLAN Gateway info - for key in natsorted(vlan_ip_data.keys()): - if not is_ip_prefix_in_key(key): - continue - interface_key = str(key[0].strip("Vlan")) - interface_value = str(key[1]) - if interface_key in vlan_ip_dict: - vlan_ip_dict[interface_key].append(interface_value) - else: - vlan_ip_dict[interface_key] = [interface_value] - - # Parsing VLAN Ports info - for key in natsorted(vlan_ports_data.keys()): - ports_key = str(key[0].strip("Vlan")) - ports_value = str(key[1]) - ports_tagging = vlan_ports_data[key]['tagging_mode'] - if ports_key in vlan_ports_dict: - if get_interface_mode() == "alias": - ports_value = iface_alias_converter.name_to_alias(ports_value) - vlan_ports_dict[ports_key].append(ports_value) - else: - if get_interface_mode() == "alias": - ports_value = iface_alias_converter.name_to_alias(ports_value) - vlan_ports_dict[ports_key] = [ports_value] - if ports_key in vlan_tagging_dict: - vlan_tagging_dict[ports_key].append(ports_tagging) - else: - vlan_tagging_dict[ports_key] = [ports_tagging] - - # Printing the following dictionaries in tablular forms: - # vlan_dhcp_helper_dict={}, vlan_ip_dict = {}, vlan_ports_dict = {} - # vlan_tagging_dict = {} - for key in natsorted(vlan_dhcp_helper_dict.keys()): - if key not in vlan_ip_dict: - ip_address = "" - else: - ip_address = ','.replace(',', '\n').join(vlan_ip_dict[key]) - if key not in vlan_ports_dict: - vlan_ports = "" - else: - vlan_ports = ','.replace(',', '\n').join((vlan_ports_dict[key])) - if key not in vlan_dhcp_helper_dict: - dhcp_helpers = "" - else: - dhcp_helpers = ','.replace(',', '\n').join(vlan_dhcp_helper_dict[key]) - if key not in vlan_tagging_dict: - vlan_tagging = "" - else: - vlan_tagging = ','.replace(',', '\n').join((vlan_tagging_dict[key])) - body.append([key, ip_address, vlan_ports, vlan_tagging, dhcp_helpers]) - click.echo(tabulate(body, header, tablefmt="grid")) - -@vlan.command() -@click.option('-s', '--redis-unix-socket-path', help='unix socket path for redis connection') -def config(redis_unix_socket_path): - kwargs = {} - if redis_unix_socket_path: - kwargs['unix_socket_path'] = redis_unix_socket_path - config_db = ConfigDBConnector(**kwargs) - config_db.connect(wait_for_init=False) - data = config_db.get_table('VLAN') - keys = data.keys() - - def tablelize(keys, data): - table = [] - - for k in natsorted(keys): - if 'members' not in data[k] : - r = [] - r.append(k) - r.append(data[k]['vlanid']) - table.append(r) - continue - - for m in data[k].get('members', []): - r = [] - r.append(k) - r.append(data[k]['vlanid']) - if get_interface_mode() == "alias": - alias = iface_alias_converter.name_to_alias(m) - r.append(alias) - else: - r.append(m) - - entry = config_db.get_entry('VLAN_MEMBER', (k, m)) - mode = entry.get('tagging_mode') - if mode is None: - r.append('?') - else: - r.append(mode) - - table.append(r) - - return table - - header = ['Name', 'VID', 'Member', 'Mode'] - click.echo(tabulate(tablelize(keys, data), header)) - @cli.command('services') def services(): """Show all daemon services""" From 91ffc2c2c6fded8f4e39e89d38d4a78cc0e73206 Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Thu, 13 Aug 2020 21:08:19 -0700 Subject: [PATCH 17/42] Update main.py --- config/main.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/config/main.py b/config/main.py index 07d5b94fe0..e5804a7bb2 100755 --- a/config/main.py +++ b/config/main.py @@ -1844,11 +1844,6 @@ def delete_snmptrap_server(ctx, ver): cmd="systemctl restart snmp" os.system (cmd) -@vlan.group(cls=AbbreviationGroup, name='dhcp_relay') -@click.pass_context -def vlan_dhcp_relay(ctx): - pass - @vlan_dhcp_relay.command('add') @click.argument('vid', metavar='', required=True, type=int) @click.argument('dhcp_relay_destination_ip', metavar='', required=True) From 463f73801858f904e1c413ccfd5da16f5c4789f0 Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Sun, 16 Aug 2020 00:15:12 -0700 Subject: [PATCH 18/42] Update main.py --- config/main.py | 60 -------------------------------------------------- 1 file changed, 60 deletions(-) diff --git a/config/main.py b/config/main.py index e5804a7bb2..815cf873ed 100755 --- a/config/main.py +++ b/config/main.py @@ -1844,66 +1844,6 @@ def delete_snmptrap_server(ctx, ver): cmd="systemctl restart snmp" os.system (cmd) -@vlan_dhcp_relay.command('add') -@click.argument('vid', metavar='', required=True, type=int) -@click.argument('dhcp_relay_destination_ip', metavar='', required=True) -@click.pass_context -def add_vlan_dhcp_relay_destination(ctx, vid, dhcp_relay_destination_ip): - """ Add a destination IP address to the VLAN's DHCP relay """ - if not is_ipaddress(dhcp_relay_destination_ip): - ctx.fail('Invalid IP address') - db = ctx.obj['db'] - vlan_name = 'Vlan{}'.format(vid) - vlan = db.get_entry('VLAN', vlan_name) - - if len(vlan) == 0: - ctx.fail("{} doesn't exist".format(vlan_name)) - dhcp_relay_dests = vlan.get('dhcp_servers', []) - if dhcp_relay_destination_ip in dhcp_relay_dests: - click.echo("{} is already a DHCP relay destination for {}".format(dhcp_relay_destination_ip, vlan_name)) - return - else: - dhcp_relay_dests.append(dhcp_relay_destination_ip) - vlan['dhcp_servers'] = dhcp_relay_dests - db.set_entry('VLAN', vlan_name, vlan) - click.echo("Added DHCP relay destination address {} to {}".format(dhcp_relay_destination_ip, vlan_name)) - try: - click.echo("Restarting DHCP relay service...") - run_command("systemctl restart dhcp_relay", display_cmd=False) - except SystemExit as e: - ctx.fail("Restart service dhcp_relay failed with error {}".format(e)) - -@vlan_dhcp_relay.command('del') -@click.argument('vid', metavar='', required=True, type=int) -@click.argument('dhcp_relay_destination_ip', metavar='', required=True) -@click.pass_context -def del_vlan_dhcp_relay_destination(ctx, vid, dhcp_relay_destination_ip): - """ Remove a destination IP address from the VLAN's DHCP relay """ - if not is_ipaddress(dhcp_relay_destination_ip): - ctx.fail('Invalid IP address') - db = ctx.obj['db'] - vlan_name = 'Vlan{}'.format(vid) - vlan = db.get_entry('VLAN', vlan_name) - - if len(vlan) == 0: - ctx.fail("{} doesn't exist".format(vlan_name)) - dhcp_relay_dests = vlan.get('dhcp_servers', []) - if dhcp_relay_destination_ip in dhcp_relay_dests: - dhcp_relay_dests.remove(dhcp_relay_destination_ip) - if len(dhcp_relay_dests) == 0: - del vlan['dhcp_servers'] - else: - vlan['dhcp_servers'] = dhcp_relay_dests - db.set_entry('VLAN', vlan_name, vlan) - click.echo("Removed DHCP relay destination address {} from {}".format(dhcp_relay_destination_ip, vlan_name)) - try: - click.echo("Restarting DHCP relay service...") - run_command("systemctl restart dhcp_relay", display_cmd=False) - except SystemExit as e: - ctx.fail("Restart service dhcp_relay failed with error {}".format(e)) - else: - ctx.fail("{} is not a DHCP relay destination for {}".format(dhcp_relay_destination_ip, vlan_name)) - # Validate VLAN range. # def vlan_range_validate(ctx, vid1, vid2): From 325327d1aa9b69c20be57f3cf4d5f917c041ba44 Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Sun, 16 Aug 2020 21:09:45 -0700 Subject: [PATCH 19/42] moved vlan commands to vlan.py --- config/main.py | 332 ------------------------------------------------- config/vlan.py | 332 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 332 insertions(+), 332 deletions(-) diff --git a/config/main.py b/config/main.py index 815cf873ed..a9e0beb139 100755 --- a/config/main.py +++ b/config/main.py @@ -1867,338 +1867,6 @@ def get_hyphenated_string(vlan_list): hyphenated_string = ",".join("-".join(map(str,(g[0],g[-1])[:len(g)])) for g in G) return hyphenated_string -# -# 'range' group ('config vlan range ...') -# -@vlan.group('range') -@click.pass_context -def vlan_range(ctx): - """VLAN-range related configuration tasks""" - pass - -@vlan_range.command('add') -@click.argument('vid1', metavar='', required=True, type=int) -@click.argument('vid2', metavar='', required=True, type=int) -@click.option('-w', "--warning", is_flag=True, help='warnings are not suppressed') -@click.pass_context -def add_vlan_range(ctx, vid1, vid2, warning): - db = ctx.obj['db'] - - vlan_range_validate(ctx, vid1, vid2) - - vid2 = vid2+1 - - warning_vlans_list = [] - curr_vlan_count = 0 - clients = db.redis_clients["CONFIG_DB"] - pipe = clients.pipeline() - for vid in range (vid1, vid2): - vlan = 'Vlan{}'.format(vid) - - if len(db.get_entry('VLAN', vlan)) != 0: - if warning is True: - warning_vlans_list.append(vid) - continue - - pipe.hmset('VLAN|{}'.format(vlan), {'vlanid': vid}) - curr_vlan_count += 1 - pipe.execute() - # Log warning messages if 'warning' option is enabled - if warning is True: - if len(warning_vlans_list) != 0: - logging.warning('VLANs already existing: {}'.format(get_hyphenated_string(warning_vlans_list))) - -@vlan_range.command('del') -@click.argument('vid1', metavar='', required=True, type=int) -@click.argument('vid2', metavar='', required=True, type=int) -@click.option('-w', "--warning", is_flag=True, help='warnings are not suppressed') -@click.pass_context -def del_vlan_range(ctx, vid1, vid2, warning): - db = ctx.obj['db'] - - vlan_range_validate(ctx, vid1, vid2) - - vid2 = vid2+1 - - warning_vlans_list = [] - warning_membership_list = [] - warning_ip_list = [] - clients = db.redis_clients["CONFIG_DB"] - pipe = clients.pipeline() - vlan_members = [] - vlan_member_keys = db.keys('CONFIG_DB', "*VLAN_MEMBER*") - vlan_temp_member_keys = db.keys('CONFIG_DB', "*VLAN_MEMBER*") - vlan_ip_members = [] - vlan_ip_keys = db.keys('CONFIG_DB', "*VLAN_INTERFACE*") - - # Fetch the interfaces from config_db associated with *VLAN_MEMBER* - stored_intf_list = [] - if vlan_temp_member_keys is not None: - for x in range(len(vlan_temp_member_keys)): - member_list = vlan_temp_member_keys[x].split('|',2) - stored_intf_list.append(str(member_list[2])) - - stored_intf_list = list(set(stored_intf_list)) - list_length = len(stored_intf_list) - - # Fetch VLAN participation list for each interface - vid = range(vid1, vid2) - if vlan_temp_member_keys is not None and list_length != 0: - for i in range(list_length): - stored_vlan_list = [] - for x in list(vlan_temp_member_keys): - member_list = x.split('|',2) - fetched_vlan = int(re.search(r'\d+', member_list[1]).group()) - if stored_intf_list[i] == str(member_list[2]): - if fetched_vlan in vid: - stored_vlan_list.append(fetched_vlan) - vlan_temp_member_keys.remove(x) - - if len(stored_vlan_list) != 0: - warning_string = str(stored_intf_list[i]) + ' is member of ' + get_hyphenated_string(stored_vlan_list) - warning_membership_list.append(warning_string) - - if vlan_ip_keys is None and vlan_member_keys is None: - for vid in range(vid1, vid2): - vlan = 'Vlan{}'.format(vid) - if len(db.get_entry('VLAN', vlan)) == 0: - if warning is True: - warning_vlans_list.append(vid) - continue - - pipe.delete('VLAN|{}'.format(vlan)) - pipe.execute() - else: - if vlan_ip_keys is not None: - for v in vlan_ip_keys: - pipe.hgetall(v) - vlan_ip_members = pipe.execute() - if vlan_member_keys is not None: - for v in vlan_member_keys: - pipe.hgetall(v) - vlan_members = pipe.execute() - for vid in range(vid1, vid2): - vlan_member_configured = False - ip_configured = False - vlan = 'Vlan{}'.format(vid) - - if len(db.get_entry('VLAN', vlan)) == 0: - if warning is True: - warning_vlans_list.append(vid) - continue - - if vlan_member_keys is not None: - for x in range(len(vlan_member_keys)): - vlan_member_configured = False - member_list = vlan_member_keys[x].split('|',2) - fetched_vlan = int(re.search(r'\d+', member_list[1]).group()) - if(fetched_vlan == vid): - if "Ethernet" or "PortChannel" in str(member_list[2]): - vlan_member_configured = True - break - - if vlan_member_configured is True: - continue - - if vlan_ip_keys is not None: - for x in range(len(vlan_ip_keys)): - ip_configured = False - member_list = vlan_ip_keys[x].split('|',2) - fetched_vlan = int(re.search(r'\d+', member_list[1]).group()) - if(fetched_vlan == vid): - if warning is True: - warning_ip_list.append(vid) - ip_configured = True - break - - if ip_configured is True: - continue - - vlan = 'Vlan{}'.format(vid) - pipe.delete('VLAN|{}'.format(vlan)) - pipe.execute() - - # Log warning messages if 'warning' option is enabled - if warning is True and len(warning_vlans_list) != 0: - logging.warning('Non-existent VLANs: {}'.format(get_hyphenated_string(warning_vlans_list))) - if warning is True and len(warning_membership_list) != 0: - logging.warning('Remove VLAN membership before removing VLAN: {}'.format(warning_membership_list)) - if warning is True and len(warning_ip_list) != 0: - warning_string = 'Vlans configured with IP: ' + get_hyphenated_string(warning_ip_list) - logging.warning('Remove IP configuration before removing VLAN: {}'.format(warning_string)) - -# -# 'member range' group ('config vlan member range ...') -# -@vlan_member.group('range') -@click.pass_context -def vlan_member_range(ctx): - """VLAN member range related configuration tasks""" - pass - -# -# Returns VLAN data in a format required to perform redisDB operations. -# -def vlan_member_data(member_list): - vlan_data = {} - for key in member_list: - value = member_list[key] - if type(value) is list: - vlan_data[key+'@'] = ','.join(value) - else: - vlan_data[key] = str(value) - return vlan_data - -@vlan_member_range.command('add') -@click.argument('vid1', metavar='', required=True, type=int) -@click.argument('vid2', metavar='', required=True, type=int) -@click.argument('interface_name', metavar='', required=True) -@click.option('-u', '--untagged', is_flag=True) -@click.option('-w', "--warning", is_flag=True, help='warnings are not suppressed') -@click.pass_context -def add_vlan_member_range(ctx, vid1, vid2, interface_name, untagged, warning): - db = ctx.obj['db'] - - vlan_range_validate(ctx, vid1, vid2) - - if get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(interface_name) - if interface_name is None: - ctx.fail("'interface_name' is None!") - - if interface_name_is_valid(interface_name) is False: - ctx.fail("Interface name is invalid!!") - - vid2 = vid2+1 - vlan_count = vid2-vid1 - if untagged is True and (vlan_count >= 2): - ctx.fail("Same interface {} cannot be untagged member of more than one VLAN".format(interface_name)) - - warning_vlans_list = [] - warning_membership_list = [] - clients = db.redis_clients["CONFIG_DB"] - pipe = clients.pipeline() - - # Validate if interface has IP configured - # in physical and port channel tables - for k,v in db.get_table('INTERFACE').iteritems(): - if k == interface_name: - ctx.fail(" {} has ip address configured".format(interface_name)) - - for k,v in db.get_table('PORTCHANNEL_INTERFACE').iteritems(): - if k == interface_name: - ctx.fail(" {} has ip address configured".format(interface_name)) - - for k,v in db.get_table('PORTCHANNEL_MEMBER'): - if v == interface_name: - ctx.fail(" {} is configured as a port channel member".format(interface_name)) - - for vid in range(vid1, vid2): - vlan_name = 'Vlan{}'.format(vid) - vlan = db.get_entry('VLAN', vlan_name) - - if len(vlan) == 0: - if warning is True: - warning_vlans_list.append(vid) - continue - - members = vlan.get('members', []) - if interface_name in members: - if warning is True: - warning_membership_list.append(vid) - if get_interface_naming_mode() == "alias": - interface_name = interface_name_to_alias(interface_name) - if interface_name is None: - ctx.fail("'interface_name' is None!") - continue - else: - continue - - members.append(interface_name) - vlan['members'] = members - pipe.hmset('VLAN|{}'.format(vlan_name), vlan_member_data(vlan)) - pipe.hmset('VLAN_MEMBER|{}'.format(vlan_name+'|'+interface_name), {'tagging_mode': "untagged" if untagged else "tagged" }) - # If port is being made L2 port, enable STP - pipe.execute() - # Log warning messages if 'warning' option is enabled - if warning is True and len(warning_vlans_list) != 0: - logging.warning('Non-existent VLANs: {}'.format(get_hyphenated_string(warning_vlans_list))) - if warning is True and len(warning_membership_list) != 0: - if(len(warning_membership_list) == 1): - vlan_string = 'Vlan: ' - else: - vlan_string = 'Vlans: ' - warning_string = str(interface_name) + ' is already a member of ' + vlan_string + get_hyphenated_string(warning_membership_list) - logging.warning('Membership exists already: {}'.format(warning_string)) - -@vlan_member_range.command('del') -@click.argument('vid1', metavar='', required=True, type=int) -@click.argument('vid2', metavar='', required=True, type=int) -@click.argument('interface_name', metavar='', required=True) -@click.option('-w', "--warning", is_flag=True, help='warnings are not suppressed') -@click.pass_context -def del_vlan_member_range(ctx, vid1, vid2, interface_name, warning): - db = ctx.obj['db'] - - vlan_range_validate(ctx, vid1, vid2) - - if get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(interface_name) - if interface_name is None: - ctx.fail("'interface_name' is None!") - - if interface_name_is_valid(interface_name) is False: - ctx.fail("Interface name is invalid!!") - - vid2 = vid2+1 - - warning_vlans_list = [] - warning_membership_list = [] - clients = db.redis_clients["CONFIG_DB"] - pipe = clients.pipeline() - - for vid in range(vid1, vid2): - vlan_name = 'Vlan{}'.format(vid) - vlan = db.get_entry('VLAN', vlan_name) - - if len(vlan) == 0: - if warning is True: - warning_vlans_list.append(vid) - continue - - members = vlan.get('members', []) - if interface_name not in members: - if warning is True: - warning_membership_list.append(vid) - if get_interface_naming_mode() == "alias": - interface_name = interface_name_to_alias(interface_name) - if interface_name is None: - ctx.fail("'interface_name' is None!") - continue - else: - continue - - members.remove(interface_name) - if len(members) == 0: - pipe.hdel('VLAN|{}'.format(vlan_name), 'members@') - else: - vlan['members'] = members - pipe.hmset('VLAN|{}'.format(vlan_name), vlan_member_data(vlan)) - - pipe.delete('VLAN_MEMBER|{}'.format(vlan_name+'|'+interface_name)) - pipe.delete('STP_VLAN_INTF|{}'.format(vlan_name + '|' + interface_name)) - pipe.execute() - # Log warning messages if 'warning' option is enabled - if warning is True and len(warning_vlans_list) != 0: - logging.warning('Non-existent VLANs: {}'.format(get_hyphenated_string(warning_vlans_list))) - if warning is True and len(warning_membership_list) != 0: - if(len(warning_membership_list) == 1): - vlan_string = 'Vlan: ' - else: - vlan_string = 'Vlans: ' - warning_string = str(interface_name) + ' is not a member of ' + vlan_string + get_hyphenated_string(warning_membership_list) - logging.warning('Non-existent membership: {}'.format(warning_string)) - # # 'mac' group ('config mac ...') # diff --git a/config/vlan.py b/config/vlan.py index a43a374495..a81b322f39 100644 --- a/config/vlan.py +++ b/config/vlan.py @@ -201,3 +201,335 @@ def del_vlan_dhcp_relay_destination(db, vid, dhcp_relay_destination_ip): clicommon.run_command("systemctl restart dhcp_relay", display_cmd=False) except SystemExit as e: ctx.fail("Restart service dhcp_relay failed with error {}".format(e)) + +# +# 'range' group ('config vlan range ...') +# +@vlan.group('range') +@click.pass_context +def vlan_range(ctx): + """VLAN-range related configuration tasks""" + pass + +@vlan_range.command('add') +@click.argument('vid1', metavar='', required=True, type=int) +@click.argument('vid2', metavar='', required=True, type=int) +@click.option('-w', "--warning", is_flag=True, help='warnings are not suppressed') +@click.pass_context +def add_vlan_range(ctx, vid1, vid2, warning): + db = ctx.obj['db'] + + vlan_range_validate(ctx, vid1, vid2) + + vid2 = vid2+1 + + warning_vlans_list = [] + curr_vlan_count = 0 + clients = db.redis_clients["CONFIG_DB"] + pipe = clients.pipeline() + for vid in range (vid1, vid2): + vlan = 'Vlan{}'.format(vid) + + if len(db.get_entry('VLAN', vlan)) != 0: + if warning is True: + warning_vlans_list.append(vid) + continue + + pipe.hmset('VLAN|{}'.format(vlan), {'vlanid': vid}) + curr_vlan_count += 1 + pipe.execute() + # Log warning messages if 'warning' option is enabled + if warning is True: + if len(warning_vlans_list) != 0: + logging.warning('VLANs already existing: {}'.format(get_hyphenated_string(warning_vlans_list))) + +@vlan_range.command('del') +@click.argument('vid1', metavar='', required=True, type=int) +@click.argument('vid2', metavar='', required=True, type=int) +@click.option('-w', "--warning", is_flag=True, help='warnings are not suppressed') +@click.pass_context +def del_vlan_range(ctx, vid1, vid2, warning): + db = ctx.obj['db'] + + vlan_range_validate(ctx, vid1, vid2) + + vid2 = vid2+1 + + warning_vlans_list = [] + warning_membership_list = [] + warning_ip_list = [] + clients = db.redis_clients["CONFIG_DB"] + pipe = clients.pipeline() + vlan_members = [] + vlan_member_keys = db.keys('CONFIG_DB', "*VLAN_MEMBER*") + vlan_temp_member_keys = db.keys('CONFIG_DB', "*VLAN_MEMBER*") + vlan_ip_members = [] + vlan_ip_keys = db.keys('CONFIG_DB', "*VLAN_INTERFACE*") + + # Fetch the interfaces from config_db associated with *VLAN_MEMBER* + stored_intf_list = [] + if vlan_temp_member_keys is not None: + for x in range(len(vlan_temp_member_keys)): + member_list = vlan_temp_member_keys[x].split('|',2) + stored_intf_list.append(str(member_list[2])) + + stored_intf_list = list(set(stored_intf_list)) + list_length = len(stored_intf_list) + + # Fetch VLAN participation list for each interface + vid = range(vid1, vid2) + if vlan_temp_member_keys is not None and list_length != 0: + for i in range(list_length): + stored_vlan_list = [] + for x in list(vlan_temp_member_keys): + member_list = x.split('|',2) + fetched_vlan = int(re.search(r'\d+', member_list[1]).group()) + if stored_intf_list[i] == str(member_list[2]): + if fetched_vlan in vid: + stored_vlan_list.append(fetched_vlan) + vlan_temp_member_keys.remove(x) + + if len(stored_vlan_list) != 0: + warning_string = str(stored_intf_list[i]) + ' is member of ' + get_hyphenated_string(stored_vlan_list) + warning_membership_list.append(warning_string) + + if vlan_ip_keys is None and vlan_member_keys is None: + for vid in range(vid1, vid2): + vlan = 'Vlan{}'.format(vid) + if len(db.get_entry('VLAN', vlan)) == 0: + if warning is True: + warning_vlans_list.append(vid) + continue + + pipe.delete('VLAN|{}'.format(vlan)) + pipe.execute() + else: + if vlan_ip_keys is not None: + for v in vlan_ip_keys: + pipe.hgetall(v) + vlan_ip_members = pipe.execute() + if vlan_member_keys is not None: + for v in vlan_member_keys: + pipe.hgetall(v) + vlan_members = pipe.execute() + for vid in range(vid1, vid2): + vlan_member_configured = False + ip_configured = False + vlan = 'Vlan{}'.format(vid) + + if len(db.get_entry('VLAN', vlan)) == 0: + if warning is True: + warning_vlans_list.append(vid) + continue + + if vlan_member_keys is not None: + for x in range(len(vlan_member_keys)): + vlan_member_configured = False + member_list = vlan_member_keys[x].split('|',2) + fetched_vlan = int(re.search(r'\d+', member_list[1]).group()) + if(fetched_vlan == vid): + if "Ethernet" or "PortChannel" in str(member_list[2]): + vlan_member_configured = True + break + + if vlan_member_configured is True: + continue + + if vlan_ip_keys is not None: + for x in range(len(vlan_ip_keys)): + ip_configured = False + member_list = vlan_ip_keys[x].split('|',2) + fetched_vlan = int(re.search(r'\d+', member_list[1]).group()) + if(fetched_vlan == vid): + if warning is True: + warning_ip_list.append(vid) + ip_configured = True + break + + if ip_configured is True: + continue + + vlan = 'Vlan{}'.format(vid) + pipe.delete('VLAN|{}'.format(vlan)) + pipe.execute() + + # Log warning messages if 'warning' option is enabled + if warning is True and len(warning_vlans_list) != 0: + logging.warning('Non-existent VLANs: {}'.format(get_hyphenated_string(warning_vlans_list))) + if warning is True and len(warning_membership_list) != 0: + logging.warning('Remove VLAN membership before removing VLAN: {}'.format(warning_membership_list)) + if warning is True and len(warning_ip_list) != 0: + warning_string = 'Vlans configured with IP: ' + get_hyphenated_string(warning_ip_list) + logging.warning('Remove IP configuration before removing VLAN: {}'.format(warning_string)) + +# +# 'member range' group ('config vlan member range ...') +# +@vlan_member.group('range') +@click.pass_context +def vlan_member_range(ctx): + """VLAN member range related configuration tasks""" + pass + +# +# Returns VLAN data in a format required to perform redisDB operations. +# +def vlan_member_data(member_list): + vlan_data = {} + for key in member_list: + value = member_list[key] + if type(value) is list: + vlan_data[key+'@'] = ','.join(value) + else: + vlan_data[key] = str(value) + return vlan_data + +@vlan_member_range.command('add') +@click.argument('vid1', metavar='', required=True, type=int) +@click.argument('vid2', metavar='', required=True, type=int) +@click.argument('interface_name', metavar='', required=True) +@click.option('-u', '--untagged', is_flag=True) +@click.option('-w', "--warning", is_flag=True, help='warnings are not suppressed') +@click.pass_context +def add_vlan_member_range(ctx, vid1, vid2, interface_name, untagged, warning): + db = ctx.obj['db'] + + vlan_range_validate(ctx, vid1, vid2) + + if get_interface_naming_mode() == "alias": + interface_name = interface_alias_to_name(interface_name) + if interface_name is None: + ctx.fail("'interface_name' is None!") + + if interface_name_is_valid(interface_name) is False: + ctx.fail("Interface name is invalid!!") + + vid2 = vid2+1 + vlan_count = vid2-vid1 + if untagged is True and (vlan_count >= 2): + ctx.fail("Same interface {} cannot be untagged member of more than one VLAN".format(interface_name)) + + warning_vlans_list = [] + warning_membership_list = [] + clients = db.redis_clients["CONFIG_DB"] + pipe = clients.pipeline() + + # Validate if interface has IP configured + # in physical and port channel tables + for k,v in db.get_table('INTERFACE').iteritems(): + if k == interface_name: + ctx.fail(" {} has ip address configured".format(interface_name)) + + for k,v in db.get_table('PORTCHANNEL_INTERFACE').iteritems(): + if k == interface_name: + ctx.fail(" {} has ip address configured".format(interface_name)) + + for k,v in db.get_table('PORTCHANNEL_MEMBER'): + if v == interface_name: + ctx.fail(" {} is configured as a port channel member".format(interface_name)) + + for vid in range(vid1, vid2): + vlan_name = 'Vlan{}'.format(vid) + vlan = db.get_entry('VLAN', vlan_name) + + if len(vlan) == 0: + if warning is True: + warning_vlans_list.append(vid) + continue + + members = vlan.get('members', []) + if interface_name in members: + if warning is True: + warning_membership_list.append(vid) + if get_interface_naming_mode() == "alias": + interface_name = interface_name_to_alias(interface_name) + if interface_name is None: + ctx.fail("'interface_name' is None!") + continue + else: + continue + + members.append(interface_name) + vlan['members'] = members + pipe.hmset('VLAN|{}'.format(vlan_name), vlan_member_data(vlan)) + pipe.hmset('VLAN_MEMBER|{}'.format(vlan_name+'|'+interface_name), {'tagging_mode': "untagged" if untagged else "tagged" }) + # If port is being made L2 port, enable STP + pipe.execute() + # Log warning messages if 'warning' option is enabled + if warning is True and len(warning_vlans_list) != 0: + logging.warning('Non-existent VLANs: {}'.format(get_hyphenated_string(warning_vlans_list))) + if warning is True and len(warning_membership_list) != 0: + if(len(warning_membership_list) == 1): + vlan_string = 'Vlan: ' + else: + vlan_string = 'Vlans: ' + warning_string = str(interface_name) + ' is already a member of ' + vlan_string + get_hyphenated_string(warning_membership_list) + logging.warning('Membership exists already: {}'.format(warning_string)) + +@vlan_member_range.command('del') +@click.argument('vid1', metavar='', required=True, type=int) +@click.argument('vid2', metavar='', required=True, type=int) +@click.argument('interface_name', metavar='', required=True) +@click.option('-w', "--warning", is_flag=True, help='warnings are not suppressed') +@click.pass_context +def del_vlan_member_range(ctx, vid1, vid2, interface_name, warning): + db = ctx.obj['db'] + + vlan_range_validate(ctx, vid1, vid2) + + if get_interface_naming_mode() == "alias": + interface_name = interface_alias_to_name(interface_name) + if interface_name is None: + ctx.fail("'interface_name' is None!") + + if interface_name_is_valid(interface_name) is False: + ctx.fail("Interface name is invalid!!") + + vid2 = vid2+1 + + warning_vlans_list = [] + warning_membership_list = [] + clients = db.redis_clients["CONFIG_DB"] + pipe = clients.pipeline() + + for vid in range(vid1, vid2): + vlan_name = 'Vlan{}'.format(vid) + vlan = db.get_entry('VLAN', vlan_name) + + if len(vlan) == 0: + if warning is True: + warning_vlans_list.append(vid) + continue + + members = vlan.get('members', []) + if interface_name not in members: + if warning is True: + warning_membership_list.append(vid) + if get_interface_naming_mode() == "alias": + interface_name = interface_name_to_alias(interface_name) + if interface_name is None: + ctx.fail("'interface_name' is None!") + continue + else: + continue + + members.remove(interface_name) + if len(members) == 0: + pipe.hdel('VLAN|{}'.format(vlan_name), 'members@') + else: + vlan['members'] = members + pipe.hmset('VLAN|{}'.format(vlan_name), vlan_member_data(vlan)) + + pipe.delete('VLAN_MEMBER|{}'.format(vlan_name+'|'+interface_name)) + pipe.delete('STP_VLAN_INTF|{}'.format(vlan_name + '|' + interface_name)) + pipe.execute() + # Log warning messages if 'warning' option is enabled + if warning is True and len(warning_vlans_list) != 0: + logging.warning('Non-existent VLANs: {}'.format(get_hyphenated_string(warning_vlans_list))) + if warning is True and len(warning_membership_list) != 0: + if(len(warning_membership_list) == 1): + vlan_string = 'Vlan: ' + else: + vlan_string = 'Vlans: ' + warning_string = str(interface_name) + ' is not a member of ' + vlan_string + get_hyphenated_string(warning_membership_list) + logging.warning('Non-existent membership: {}'.format(warning_string)) \ No newline at end of file From 4eda4a5ab841941ab5544f4031eb1957ff5206e4 Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Mon, 17 Aug 2020 01:28:20 -0700 Subject: [PATCH 20/42] fixed lgtm --- config/main.py | 4 ---- config/vlan.py | 4 ++-- scripts/fast-reboot-dump.py | 1 - scripts/fdbshow | 2 +- show/main.py | 1 - 5 files changed, 3 insertions(+), 9 deletions(-) diff --git a/config/main.py b/config/main.py index a9e0beb139..5601f6f2df 100755 --- a/config/main.py +++ b/config/main.py @@ -4,8 +4,6 @@ import ipaddress import json import netaddr -import syslog -import logging import time import netifaces import os @@ -19,7 +17,6 @@ from itertools import count, groupby from config_mgmt import ConfigMgmtDPB from utilities_common.intf_filter import parse_interface_in_filter -from utilities_common.util_base import UtilHelper from portconfig import get_child_ports, get_port_config_file_name from sonic_py_common import device_info from swsssdk import ConfigDBConnector, SonicV2Connector, SonicDBConfig @@ -1881,7 +1878,6 @@ def mac(ctx, redis_unix_socket_path): config_db = ConfigDBConnector(**kwargs) config_db.connect(wait_for_init=False) ctx.obj = {'db': config_db} - pass @mac.command('aging_time') @click.argument('interval', metavar='', required=True, type=int) diff --git a/config/vlan.py b/config/vlan.py index a81b322f39..d28e61051b 100644 --- a/config/vlan.py +++ b/config/vlan.py @@ -307,11 +307,11 @@ def del_vlan_range(ctx, vid1, vid2, warning): if vlan_ip_keys is not None: for v in vlan_ip_keys: pipe.hgetall(v) - vlan_ip_members = pipe.execute() + pipe.execute() if vlan_member_keys is not None: for v in vlan_member_keys: pipe.hgetall(v) - vlan_members = pipe.execute() + pipe.execute() for vid in range(vid1, vid2): vlan_member_configured = False ip_configured = False diff --git a/scripts/fast-reboot-dump.py b/scripts/fast-reboot-dump.py index 7eb3629de8..4f91146879 100644 --- a/scripts/fast-reboot-dump.py +++ b/scripts/fast-reboot-dump.py @@ -11,7 +11,6 @@ import argparse import syslog import traceback -import datetime ARP_CHUNK = binascii.unhexlify('08060001080006040001') # defines a part of the packet for ARP Request diff --git a/scripts/fdbshow b/scripts/fdbshow index 4fe2033215..6a2040467a 100755 --- a/scripts/fdbshow +++ b/scripts/fdbshow @@ -80,7 +80,7 @@ class FdbShow(object): vlan_keys = self.db.keys('ASIC_DB', "ASIC_STATE:SAI_OBJECT_TYPE_VLAN:*") for v in vlan_keys: pipe.hgetall(v) - vlans = pipe.execute() + pipe.execute() posi = 0 for ent in values: diff --git a/show/main.py b/show/main.py index 80d38256be..5596f74136 100755 --- a/show/main.py +++ b/show/main.py @@ -748,7 +748,6 @@ def aging_time(): age_time = switch_table[key]['fdb_aging_time'] except KeyError: age_time = '0' - pass output = 'Mac Aging-Time : ' output += ('%s seconds\n' % (str(age_time))) click.echo(output) From 3689a4debbc91e9aef8a77b960d06cbfee55f44f Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Mon, 17 Aug 2020 01:40:40 -0700 Subject: [PATCH 21/42] fixed lgtm --- config/vlan.py | 2 -- scripts/fdbshow | 1 - 2 files changed, 3 deletions(-) diff --git a/config/vlan.py b/config/vlan.py index d28e61051b..3a6f803095 100644 --- a/config/vlan.py +++ b/config/vlan.py @@ -260,10 +260,8 @@ def del_vlan_range(ctx, vid1, vid2, warning): warning_ip_list = [] clients = db.redis_clients["CONFIG_DB"] pipe = clients.pipeline() - vlan_members = [] vlan_member_keys = db.keys('CONFIG_DB', "*VLAN_MEMBER*") vlan_temp_member_keys = db.keys('CONFIG_DB', "*VLAN_MEMBER*") - vlan_ip_members = [] vlan_ip_keys = db.keys('CONFIG_DB', "*VLAN_INTERFACE*") # Fetch the interfaces from config_db associated with *VLAN_MEMBER* diff --git a/scripts/fdbshow b/scripts/fdbshow index 6a2040467a..f677d308a5 100755 --- a/scripts/fdbshow +++ b/scripts/fdbshow @@ -76,7 +76,6 @@ class FdbShow(object): fdb_list.append(fdb) pipe.hgetall(s) values = pipe.execute() - vlans = [] vlan_keys = self.db.keys('ASIC_DB', "ASIC_STATE:SAI_OBJECT_TYPE_VLAN:*") for v in vlan_keys: pipe.hgetall(v) From e642d83f7ca03c0d2a5362cd1fb100ab8bb51826 Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Mon, 17 Aug 2020 11:32:31 -0700 Subject: [PATCH 22/42] fix lgtm --- scripts/fdbshow | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/fdbshow b/scripts/fdbshow index f677d308a5..f98ad47388 100755 --- a/scripts/fdbshow +++ b/scripts/fdbshow @@ -97,7 +97,7 @@ class FdbShow(object): #When if_name not mapped to port_id in DB, using port_id as if_name in the display. try: if_name = self.if_oid_map[port_id] - except : + except Exception: if_name = port_id if 'vlan' in fdb: From e9ab1d6ff11eef2f529011716e6835e18fb57ce5 Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Fri, 21 Aug 2020 14:05:14 -0700 Subject: [PATCH 23/42] updated as per review comments --- config/main.py | 15 ++++++++++----- show/main.py | 8 +++----- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/config/main.py b/config/main.py index 5601f6f2df..0d5b5aff5a 100755 --- a/config/main.py +++ b/config/main.py @@ -359,10 +359,10 @@ def vlan_id_is_valid(vid): """Check if the vlan id is in acceptable range (between 1 and 4094) """ - if vid<1 or vid>4094: - return False + if vid>0 and vid<4095: + return True - return True + return False def interface_name_to_alias(interface_name): """Return alias interface name if default name is given as argument @@ -1888,6 +1888,11 @@ def set_aging_time(ctx, interval): ctx.fail("Aging timer must be in range [0-1000000]") db.set_entry('SWITCH', 'switch', {'fdb_aging_time': interval}) +def mac_address_is_valid(mac): + """Check if the mac address is valid + """ + return bool(re.match('^' + '[\:\-]'.join(['([0-9a-f]{2})']*6) + '$', mac.lower())) + @mac.command('add') @click.argument('mac', metavar='', required=True) @click.argument('vlan', metavar='', required=True, type=int) @@ -1896,7 +1901,7 @@ def set_aging_time(ctx, interval): def add_mac(ctx, mac, vlan, interface_name): db = ctx.obj['db'] - mac_valid = bool(re.match('^' + '[\:\-]'.join(['([0-9a-f]{2})']*6) + '$', mac.lower())) + mac_valid = bool(mac_address_is_valid(mac)) if mac_valid == False: ctx.fail("Incorrect mac-address format!!") @@ -1935,7 +1940,7 @@ def add_mac(ctx, mac, vlan, interface_name): def del_mac(ctx, mac, vlan): db = ctx.obj['db'] - mac_valid = bool(re.match('^' + '[\:\-]'.join(['([0-9a-f]{2})']*6) + '$', mac.lower())) + mac_valid = bool(mac_address_is_valid(mac)) if mac_valid == False: ctx.fail("Incorrect mac-address format!!") diff --git a/show/main.py b/show/main.py index 5596f74136..581f7df8b2 100755 --- a/show/main.py +++ b/show/main.py @@ -734,12 +734,10 @@ def mac(ctx, vlan, port, verbose): @mac.command() def aging_time(): """Show MAC Aging-Time""" - config_db = ConfigDBConnector() - config_db.connect() - # Fetching data from config_db for SWITCH - switch_table = config_db.get_table('SWITCH') - switch_keys = switch_table.keys() + app_db = SonicV2Connector(host='127.0.0.1') + app_db.connect(app_db.APPL_DB) + switch_keys = app_db.keys(app_db.APPL_DB, 'SWITCH_TABLE:*') age_time = 0 for key in switch_keys: From b49e6af46d1f4f3633f0b60327bc8bbb2925ed18 Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Fri, 11 Sep 2020 13:11:43 -0700 Subject: [PATCH 24/42] Update main.py --- config/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/main.py b/config/main.py index bb2592e1b8..710579359d 100755 --- a/config/main.py +++ b/config/main.py @@ -17,7 +17,7 @@ from itertools import count, groupby from config_mgmt import ConfigMgmtDPB from utilities_common.intf_filter import parse_interface_in_filter -from portconfig import get_child_ports, get_port_config_file_name +from portconfig import get_child_ports from sonic_py_common import device_info from portconfig import get_child_ports from sonic_py_common import device_info, multi_asic @@ -1951,7 +1951,7 @@ def add_mac(ctx, mac, vlan, interface_name): vlan_name = 'Vlan{}'.format(vlan) if get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(interface_name) + interface_name = interface_alias_to_name(db, interface_name) if interface_name is None: ctx.fail("'interface_name' is None!") From 4b4d16d017334c5518c42233be7ed88113aecece Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Fri, 11 Sep 2020 13:32:23 -0700 Subject: [PATCH 25/42] Update main.py --- config/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/main.py b/config/main.py index 710579359d..414e5103ad 100755 --- a/config/main.py +++ b/config/main.py @@ -1955,7 +1955,7 @@ def add_mac(ctx, mac, vlan, interface_name): if interface_name is None: ctx.fail("'interface_name' is None!") - if interface_name_is_valid(interface_name) is False: + if interface_name_is_valid(db, interface_name) is False: ctx.fail("Interface name is invalid!!") db.set_entry('FDB', (vlan_name, mac), {'port': interface_name }) From aa927ce532671c68324ae21a68680c0cca6025ec Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Fri, 18 Sep 2020 15:39:48 -0700 Subject: [PATCH 26/42] addressed review comments --- config/vlan.py | 149 ++++++++++++++++++++++++++---------- scripts/fast-reboot-dump.py | 5 ++ 2 files changed, 113 insertions(+), 41 deletions(-) diff --git a/config/vlan.py b/config/vlan.py index 3a6f803095..fc33be253d 100644 --- a/config/vlan.py +++ b/config/vlan.py @@ -202,6 +202,29 @@ def del_vlan_dhcp_relay_destination(db, vid, dhcp_relay_destination_ip): except SystemExit as e: ctx.fail("Restart service dhcp_relay failed with error {}".format(e)) +def vlan_id_is_valid(vid): + """Check if the vlan id is in acceptable range (between 1 and 4094) + """ + + if vid>0 and vid<4095: + return True + + return False + +# Validate VLAN range. +# +def vlan_range_validate(vid1, vid2): + vlan1 = 'Vlan{}'.format(vid1) + vlan2 = 'Vlan{}'.format(vid2) + + if vlan_id_is_valid(vid1) is False: + ctx.fail("{} is not within allowed range of 1 through 4094".format(vlan1)) + if vlan_id_is_valid(vid2) is False: + ctx.fail("{} is not within allowed range of 1 through 4094".format(vlan2)) + + if vid2 <= vid1: + ctx.fail(" vid2 should be greater than vid1") + # # 'range' group ('config vlan range ...') # @@ -215,22 +238,21 @@ def vlan_range(ctx): @click.argument('vid1', metavar='', required=True, type=int) @click.argument('vid2', metavar='', required=True, type=int) @click.option('-w', "--warning", is_flag=True, help='warnings are not suppressed') -@click.pass_context -def add_vlan_range(ctx, vid1, vid2, warning): - db = ctx.obj['db'] +@clicommon.pass_db +def add_vlan_range(db, vid1, vid2, warning): - vlan_range_validate(ctx, vid1, vid2) + vlan_range_validate(vid1, vid2) vid2 = vid2+1 warning_vlans_list = [] curr_vlan_count = 0 - clients = db.redis_clients["CONFIG_DB"] + clients = db.cfgdb.get_redis_client(db.cfgdb.CONFIG_DB) pipe = clients.pipeline() for vid in range (vid1, vid2): vlan = 'Vlan{}'.format(vid) - if len(db.get_entry('VLAN', vlan)) != 0: + if len(db.cfgdb.get_entry('VLAN', vlan)) != 0: if warning is True: warning_vlans_list.append(vid) continue @@ -247,22 +269,33 @@ def add_vlan_range(ctx, vid1, vid2, warning): @click.argument('vid1', metavar='', required=True, type=int) @click.argument('vid2', metavar='', required=True, type=int) @click.option('-w', "--warning", is_flag=True, help='warnings are not suppressed') -@click.pass_context -def del_vlan_range(ctx, vid1, vid2, warning): - db = ctx.obj['db'] +@clicommon.pass_db +def del_vlan_range(db, vid1, vid2, warning): - vlan_range_validate(ctx, vid1, vid2) + vlan_range_validate(vid1, vid2) vid2 = vid2+1 warning_vlans_list = [] warning_membership_list = [] warning_ip_list = [] - clients = db.redis_clients["CONFIG_DB"] - pipe = clients.pipeline() - vlan_member_keys = db.keys('CONFIG_DB', "*VLAN_MEMBER*") - vlan_temp_member_keys = db.keys('CONFIG_DB', "*VLAN_MEMBER*") - vlan_ip_keys = db.keys('CONFIG_DB', "*VLAN_INTERFACE*") + client = db.cfgdb.get_redis_client(db.cfgdb.CONFIG_DB) + pipe = client.pipeline() + + cur, vlan_member_keys = client.scan(cursor=0, match='*VLAN_MEMBER*', count=50) + while cur != 0: + cur, keys = client.scan(cursor=cur, match='*VLAN_MEMBER*', count=50) + vlan_member_keys.extend(keys) + + cur, vlan_temp_member_keys = client.scan(cursor=0, match='*VLAN_MEMBER*', count=50) + while cur != 0: + cur, keys = client.scan(cursor=cur, match='*VLAN_MEMBER*', count=50) + vlan_temp_member_keys.extend(keys) + + cur, vlan_ip_keys = client.scan(cursor=0, match='*VLAN_INTERFACE*', count=50) + while cur != 0: + cur, keys = client.scan(cursor=cur, match='*VLAN_INTERFACE*', count=50) + vlan_ip_keys.extend(keys) # Fetch the interfaces from config_db associated with *VLAN_MEMBER* stored_intf_list = [] @@ -294,7 +327,7 @@ def del_vlan_range(ctx, vid1, vid2, warning): if vlan_ip_keys is None and vlan_member_keys is None: for vid in range(vid1, vid2): vlan = 'Vlan{}'.format(vid) - if len(db.get_entry('VLAN', vlan)) == 0: + if len(db.cfgdb.get_entry('VLAN', vlan)) == 0: if warning is True: warning_vlans_list.append(vid) continue @@ -315,7 +348,7 @@ def del_vlan_range(ctx, vid1, vid2, warning): ip_configured = False vlan = 'Vlan{}'.format(vid) - if len(db.get_entry('VLAN', vlan)) == 0: + if len(db.cfgdb.get_entry('VLAN', vlan)) == 0: if warning is True: warning_vlans_list.append(vid) continue @@ -382,24 +415,59 @@ def vlan_member_data(member_list): vlan_data[key] = str(value) return vlan_data +def interface_name_is_valid(config_db, interface_name): + """Check if the interface name is valid + """ + # If the input parameter config_db is None, derive it from interface. + # In single ASIC platform, get_port_namespace() returns DEFAULT_NAMESPACE. + if config_db is None: + namespace = get_port_namespace(interface_name) + if namespace is None: + return False + config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) + + config_db.connect() + port_dict = config_db.get_table('PORT') + port_channel_dict = config_db.get_table('PORTCHANNEL') + sub_port_intf_dict = config_db.get_table('VLAN_SUB_INTERFACE') + + if clicommon.get_interface_naming_mode() == "alias": + interface_name = interface_alias_to_name(config_db, interface_name) + + if interface_name is not None: + if not port_dict: + click.echo("port_dict is None!") + raise click.Abort() + for port_name in port_dict.keys(): + if interface_name == port_name: + return True + if port_channel_dict: + for port_channel_name in port_channel_dict.keys(): + if interface_name == port_channel_name: + return True + if sub_port_intf_dict: + for sub_port_intf_name in sub_port_intf_dict.keys(): + if interface_name == sub_port_intf_name: + return True + return False + @vlan_member_range.command('add') @click.argument('vid1', metavar='', required=True, type=int) @click.argument('vid2', metavar='', required=True, type=int) @click.argument('interface_name', metavar='', required=True) @click.option('-u', '--untagged', is_flag=True) @click.option('-w', "--warning", is_flag=True, help='warnings are not suppressed') -@click.pass_context -def add_vlan_member_range(ctx, vid1, vid2, interface_name, untagged, warning): - db = ctx.obj['db'] - - vlan_range_validate(ctx, vid1, vid2) +@clicommon.pass_db +def add_vlan_member_range(db, vid1, vid2, interface_name, untagged, warning): + vlan_range_validate(vid1, vid2) + ctx = click.get_current_context() - if get_interface_naming_mode() == "alias": + if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(interface_name) if interface_name is None: ctx.fail("'interface_name' is None!") - if interface_name_is_valid(interface_name) is False: + if interface_name_is_valid(db.cfgdb, interface_name) is False: ctx.fail("Interface name is invalid!!") vid2 = vid2+1 @@ -409,26 +477,26 @@ def add_vlan_member_range(ctx, vid1, vid2, interface_name, untagged, warning): warning_vlans_list = [] warning_membership_list = [] - clients = db.redis_clients["CONFIG_DB"] + clients = db.cfgdb.get_redis_client(db.cfgdb.CONFIG_DB) pipe = clients.pipeline() # Validate if interface has IP configured # in physical and port channel tables - for k,v in db.get_table('INTERFACE').iteritems(): + for k,v in db.cfgdb.get_table('INTERFACE').iteritems(): if k == interface_name: ctx.fail(" {} has ip address configured".format(interface_name)) - for k,v in db.get_table('PORTCHANNEL_INTERFACE').iteritems(): + for k,v in db.cfgdb.get_table('PORTCHANNEL_INTERFACE').iteritems(): if k == interface_name: ctx.fail(" {} has ip address configured".format(interface_name)) - for k,v in db.get_table('PORTCHANNEL_MEMBER'): + for k,v in db.cfgdb.get_table('PORTCHANNEL_MEMBER'): if v == interface_name: ctx.fail(" {} is configured as a port channel member".format(interface_name)) for vid in range(vid1, vid2): vlan_name = 'Vlan{}'.format(vid) - vlan = db.get_entry('VLAN', vlan_name) + vlan = db.cfgdb.get_entry('VLAN', vlan_name) if len(vlan) == 0: if warning is True: @@ -439,7 +507,7 @@ def add_vlan_member_range(ctx, vid1, vid2, interface_name, untagged, warning): if interface_name in members: if warning is True: warning_membership_list.append(vid) - if get_interface_naming_mode() == "alias": + if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_name_to_alias(interface_name) if interface_name is None: ctx.fail("'interface_name' is None!") @@ -469,30 +537,29 @@ def add_vlan_member_range(ctx, vid1, vid2, interface_name, untagged, warning): @click.argument('vid2', metavar='', required=True, type=int) @click.argument('interface_name', metavar='', required=True) @click.option('-w', "--warning", is_flag=True, help='warnings are not suppressed') -@click.pass_context -def del_vlan_member_range(ctx, vid1, vid2, interface_name, warning): - db = ctx.obj['db'] - - vlan_range_validate(ctx, vid1, vid2) +@clicommon.pass_db +def del_vlan_member_range(db, vid1, vid2, interface_name, warning): + vlan_range_validate(vid1, vid2) + ctx = click.get_current_context() - if get_interface_naming_mode() == "alias": + if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(interface_name) if interface_name is None: ctx.fail("'interface_name' is None!") - if interface_name_is_valid(interface_name) is False: + if interface_name_is_valid(db.cfgdb, interface_name) is False: ctx.fail("Interface name is invalid!!") vid2 = vid2+1 warning_vlans_list = [] warning_membership_list = [] - clients = db.redis_clients["CONFIG_DB"] + clients = db.cfgdb.get_redis_client(db.cfgdb.CONFIG_DB) pipe = clients.pipeline() for vid in range(vid1, vid2): vlan_name = 'Vlan{}'.format(vid) - vlan = db.get_entry('VLAN', vlan_name) + vlan = db.cfgdb.get_entry('VLAN', vlan_name) if len(vlan) == 0: if warning is True: @@ -503,7 +570,7 @@ def del_vlan_member_range(ctx, vid1, vid2, interface_name, warning): if interface_name not in members: if warning is True: warning_membership_list.append(vid) - if get_interface_naming_mode() == "alias": + if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_name_to_alias(interface_name) if interface_name is None: ctx.fail("'interface_name' is None!") @@ -530,4 +597,4 @@ def del_vlan_member_range(ctx, vid1, vid2, interface_name, warning): else: vlan_string = 'Vlans: ' warning_string = str(interface_name) + ' is not a member of ' + vlan_string + get_hyphenated_string(warning_membership_list) - logging.warning('Non-existent membership: {}'.format(warning_string)) \ No newline at end of file + logging.warning('Non-existent membership: {}'.format(warning_string)) diff --git a/scripts/fast-reboot-dump.py b/scripts/fast-reboot-dump.py index ffd5bc8b22..72c40a8593 100644 --- a/scripts/fast-reboot-dump.py +++ b/scripts/fast-reboot-dump.py @@ -202,6 +202,11 @@ def generate_fdb_entries_2(filename): #print("generate_fdb_entries_2 before fdb-key-getall" + datetime.datetime.now().strftime("%H:%M:%S.%f")) pipe = client.pipeline() fdb_list = db.keys(db.ASIC_DB, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY:*") + cur, fdb_list = client.scan(cursor=0, match='ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY:*', count=50) + while cur != 0: + cur, keys = client.scan(cursor=cur, match='ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY:*', count=50) + fdb_list.extend(keys) + fdb_list = [] if fdb_list is None else fdb_list for s in fdb_list: pipe.hgetall(s) From d98e16cf05d7f0912c3e5da863614273724c9d2d Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Thu, 1 Oct 2020 14:03:19 -0700 Subject: [PATCH 27/42] Update main.py --- config/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/main.py b/config/main.py index 414e5103ad..0c53120107 100755 --- a/config/main.py +++ b/config/main.py @@ -1950,7 +1950,7 @@ def add_mac(ctx, mac, vlan, interface_name): vlan_name = 'Vlan{}'.format(vlan) - if get_interface_naming_mode() == "alias": + if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(db, interface_name) if interface_name is None: ctx.fail("'interface_name' is None!") From c3252ea4b20c204cdc86bf52bb8eef8d7a208727 Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Thu, 1 Oct 2020 14:15:09 -0700 Subject: [PATCH 28/42] Update fast-reboot-dump.py --- scripts/fast-reboot-dump.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/fast-reboot-dump.py b/scripts/fast-reboot-dump.py index 72c40a8593..ba5f38d965 100644 --- a/scripts/fast-reboot-dump.py +++ b/scripts/fast-reboot-dump.py @@ -201,7 +201,6 @@ def generate_fdb_entries_2(filename): #print("generate_fdb_entries_2 before fdb-key-getall" + datetime.datetime.now().strftime("%H:%M:%S.%f")) pipe = client.pipeline() - fdb_list = db.keys(db.ASIC_DB, "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY:*") cur, fdb_list = client.scan(cursor=0, match='ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY:*', count=50) while cur != 0: cur, keys = client.scan(cursor=cur, match='ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY:*', count=50) From cb7a37d0ec9f06fb1c11e493cda914a6469f385d Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Thu, 3 Dec 2020 16:02:11 -0800 Subject: [PATCH 29/42] include latest changes after syncing to master --- clear/main.py | 31 +- config/main.py | 216 ++++----- config/vlan.py | 44 +- scripts/fdbclear | 5 +- scripts/fdbshow | 47 +- show/main.py | 1188 +++++----------------------------------------- show/vlan.py | 67 +-- 7 files changed, 324 insertions(+), 1274 deletions(-) diff --git a/clear/main.py b/clear/main.py index 69b2a7fa62..fe0c2ab25c 100755 --- a/clear/main.py +++ b/clear/main.py @@ -1,15 +1,9 @@ -#! /usr/bin/python -u - -import click +import configparser import os import subprocess +import sys -try: - # noinspection PyPep8Naming - import ConfigParser as configparser -except ImportError: - # noinspection PyUnresolvedReferences - import configparser +import click # This is from the aliases example: @@ -84,6 +78,7 @@ def get_routing_stack(): proc = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True, + text=True, stderr=subprocess.STDOUT) stdout = proc.communicate()[0] proc.wait() @@ -99,11 +94,12 @@ def get_routing_stack(): routing_stack = get_routing_stack() -def run_command(command, pager=False, return_output=False): +def run_command(command, pager=False, return_output=False, return_exitstatus=False): # Provide option for caller function to Process the output. - proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) + proc = subprocess.Popen(command, shell=True, text=True, stdout=subprocess.PIPE) if return_output: - return proc.communicate() + output = proc.communicate() + return output if not return_exitstatus else output + (proc.returncode,) elif pager: #click.echo(click.style("Command: ", fg='cyan') + click.style(command, fg='green')) click.echo_via_pager(proc.stdout.read()) @@ -365,11 +361,14 @@ def clear_vlan_fdb(vlanid): # 'line' command # @cli.command('line') -@click.argument('linenum') -def line(linenum): +@click.argument('target') +@click.option('--devicename', '-d', is_flag=True, help="clear by name - if flag is set, interpret target as device name instead") +def line(target, devicename): """Clear preexisting connection to line""" - cmd = "consutil clear " + str(linenum) - run_command(cmd) + cmd = "consutil clear {}".format("--devicename " if devicename else "") + str(target) + (output, _, exitstatus) = run_command(cmd, return_output=True, return_exitstatus=True) + click.echo(output) + sys.exit(exitstatus) # # 'nat' group ("clear nat ...") diff --git a/config/main.py b/config/main.py index 61074d3612..28ea16c7f3 100755 --- a/config/main.py +++ b/config/main.py @@ -15,28 +15,30 @@ from minigraph import parse_device_desc_xml from itertools import count, groupby -from config_mgmt import ConfigMgmtDPB from utilities_common.intf_filter import parse_interface_in_filter from portconfig import get_child_ports from sonic_py_common import device_info from portconfig import get_child_ports from sonic_py_common import device_info, multi_asic from sonic_py_common.interface import get_interface_table_name, get_port_table_name -from swsssdk import ConfigDBConnector, SonicV2Connector, SonicDBConfig +from swsssdk import ConfigDBConnector, SonicDBConfig +from swsscommon.swsscommon import SonicV2Connector from utilities_common.db import Db from utilities_common.intf_filter import parse_interface_in_filter import utilities_common.cli as clicommon from .utils import log -import aaa -import console -import feature -import kube -import mlnx -import nat -import vlan -from config_mgmt import ConfigMgmtDPB +from . import aaa +from . import chassis_modules +from . import console +from . import feature +from . import kube +from . import mlnx +from . import muxcable +from . import nat +from . import vlan +from .config_mgmt import ConfigMgmtDPB CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help', '-?']) @@ -89,7 +91,7 @@ def _get_breakout_options(ctx, args, incomplete): else: breakout_file_input = readJsonFile(breakout_cfg_file) if interface_name in breakout_file_input[INTF_KEY]: - breakout_mode_list = [v["breakout_modes"] for i ,v in breakout_file_input[INTF_KEY].items() if i == interface_name][0] + breakout_mode_list = [v["breakout_modes"] for i, v in breakout_file_input[INTF_KEY].items() if i == interface_name][0] breakout_mode_options = [] for i in breakout_mode_list.split(','): breakout_mode_options.append(i) @@ -98,7 +100,7 @@ def _get_breakout_options(ctx, args, incomplete): def shutdown_interfaces(ctx, del_intf_dict): """ shut down all the interfaces before deletion """ - for intf in del_intf_dict.keys(): + for intf in del_intf_dict: config_db = ctx.obj['config_db'] if clicommon.get_interface_naming_mode() == "alias": interface_name = interface_alias_to_name(config_db, intf) @@ -115,7 +117,7 @@ def shutdown_interfaces(ctx, del_intf_dict): click.echo("port_dict is None!") return False - if intf in port_dict.keys(): + if intf in port_dict: config_db.mod_entry("PORT", intf, {"admin_status": "down"}) else: click.secho("[ERROR] Could not get the correct interface name, exiting", fg='red') @@ -145,7 +147,7 @@ def _validate_interface_mode(ctx, breakout_cfg_file, interface_name, target_brko return False # Check whether the user-selected interface is part of 'port' table in config db. - if interface_name not in port_dict.keys(): + if interface_name not in port_dict: click.secho("[ERROR] {} is not in port_dict".format(interface_name)) return False click.echo("\nRunning Breakout Mode : {} \nTarget Breakout Mode : {}".format(cur_brkout_mode, target_brkout_mode)) @@ -262,7 +264,7 @@ def _get_device_type(): """ command = "{} -m -v DEVICE_METADATA.localhost.type".format(SONIC_CFGGEN_PATH) - proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) + proc = subprocess.Popen(command, shell=True, text=True, stdout=subprocess.PIPE) device_type, err = proc.communicate() if err: click.echo("Could not get the device type from minigraph, setting device type to Unknown") @@ -299,7 +301,7 @@ def interface_alias_to_name(config_db, interface_alias): if not port_dict: click.echo("port_dict is None!") raise click.Abort() - for port_name in port_dict.keys(): + for port_name in port_dict: if interface_alias == port_dict[port_name]['alias']: return port_name if sub_intf_sep_idx == -1 else port_name + VLAN_SUB_INTERFACE_SEPARATOR + vlan_id @@ -330,15 +332,15 @@ def interface_name_is_valid(config_db, interface_name): if not port_dict: click.echo("port_dict is None!") raise click.Abort() - for port_name in port_dict.keys(): + for port_name in port_dict: if interface_name == port_name: return True if port_channel_dict: - for port_channel_name in port_channel_dict.keys(): + for port_channel_name in port_channel_dict: if interface_name == port_channel_name: return True if sub_port_intf_dict: - for sub_port_intf_name in sub_port_intf_dict.keys(): + for sub_port_intf_name in sub_port_intf_dict: if interface_name == sub_port_intf_name: return True return False @@ -352,7 +354,6 @@ def vlan_id_is_valid(vid): return False - def interface_name_to_alias(config_db, interface_name): """Return alias interface name if default name is given as argument """ @@ -371,7 +372,7 @@ def interface_name_to_alias(config_db, interface_name): if not port_dict: click.echo("port_dict is None!") raise click.Abort() - for port_name in port_dict.keys(): + for port_name in port_dict: if interface_name == port_name: return port_dict[port_name]['alias'] @@ -424,7 +425,7 @@ def get_port_namespace(port): if clicommon.get_interface_naming_mode() == "alias": port_dict = config_db.get_table(table_name) if port_dict: - for port_name in port_dict.keys(): + for port_name in port_dict: if port == port_dict[port_name]['alias']: return namespace else: @@ -441,8 +442,8 @@ def del_interface_bind_to_vrf(config_db, vrf_name): for table_name in tables: interface_dict = config_db.get_table(table_name) if interface_dict: - for interface_name in interface_dict.keys(): - if interface_dict[interface_name].has_key('vrf_name') and vrf_name == interface_dict[interface_name]['vrf_name']: + for interface_name in interface_dict: + if 'vrf_name' in interface_dict[interface_name] and vrf_name == interface_dict[interface_name]['vrf_name']: interface_dependent = interface_ipaddr_dependent_on_interface(config_db, interface_name) for interface_del in interface_dependent: config_db.set_entry(table_name, interface_del, None) @@ -473,7 +474,7 @@ def set_interface_naming_mode(mode): click.echo("port_dict is None!") raise click.Abort() - for port_name in port_dict.keys(): + for port_name in port_dict: try: if port_dict[port_name]['alias']: pass @@ -505,28 +506,19 @@ def set_interface_naming_mode(mode): click.echo("Please logout and log back in for changes take effect.") -# Get the local BGP ASN from DEVICE_METADATA -def get_local_bgp_asn(config_db): - metadata = config_db.get_table('DEVICE_METADATA') - return metadata['localhost']['bgp_asn'] - def _is_neighbor_ipaddress(config_db, ipaddress): """Returns True if a neighbor has the IP address , False if not """ entry = config_db.get_entry('BGP_NEIGHBOR', ipaddress) return True if entry else False -def _get_all_neighbor_ipaddresses(config_db, ignore_local_hosts=False): +def _get_all_neighbor_ipaddresses(config_db): """Returns list of strings containing IP addresses of all BGP neighbors - if the flag ignore_local_hosts is set to True, additional check to see if - if the BGP neighbor AS number is same as local BGP AS number, if so ignore that neigbor. """ addrs = [] bgp_sessions = config_db.get_table('BGP_NEIGHBOR') - local_as = get_local_bgp_asn(config_db) - for addr, session in bgp_sessions.iteritems(): - if not ignore_local_hosts or (ignore_local_hosts and local_as != session['asn']): - addrs.append(addr) + for addr, session in bgp_sessions.items(): + addrs.append(addr) return addrs def _get_neighbor_ipaddress_list_by_hostname(config_db, hostname): @@ -535,8 +527,8 @@ def _get_neighbor_ipaddress_list_by_hostname(config_db, hostname): """ addrs = [] bgp_sessions = config_db.get_table('BGP_NEIGHBOR') - for addr, session in bgp_sessions.iteritems(): - if session.has_key('name') and session['name'] == hostname: + for addr, session in bgp_sessions.items(): + if 'name' in session and session['name'] == hostname: addrs.append(addr) return addrs @@ -662,7 +654,7 @@ def _get_disabled_services_list(config_db): feature_table = config_db.get_table('FEATURE') if feature_table is not None: - for feature_name in feature_table.keys(): + for feature_name in feature_table: if not feature_name: log.log_warning("Feature is None") continue @@ -773,8 +765,8 @@ def _restart_services(config_db): def interface_is_in_vlan(vlan_member_table, interface_name): - """ Check if an interface is in a vlan """ - for _,intf in vlan_member_table.keys(): + """ Check if an interface is in a vlan """ + for _, intf in vlan_member_table: if intf == interface_name: return True @@ -782,7 +774,7 @@ def interface_is_in_vlan(vlan_member_table, interface_name): def interface_is_in_portchannel(portchannel_member_table, interface_name): """ Check if an interface is part of portchannel """ - for _,intf in portchannel_member_table.keys(): + for _, intf in portchannel_member_table: if intf == interface_name: return True @@ -790,7 +782,7 @@ def interface_is_in_portchannel(portchannel_member_table, interface_name): def interface_has_mirror_config(mirror_table, interface_name): """ Check if port is already configured with mirror config """ - for _,v in mirror_table.items(): + for _, v in mirror_table.items(): if 'src_port' in v and v['src_port'] == interface_name: return True if 'dst_port' in v and v['dst_port'] == interface_name: @@ -897,13 +889,14 @@ def config(ctx): # Add groups from other modules config.add_command(aaa.aaa) config.add_command(aaa.tacacs) +config.add_command(chassis_modules.chassis_modules) config.add_command(console.console) config.add_command(feature.feature) config.add_command(kube.kubernetes) +config.add_command(muxcable.muxcable) config.add_command(nat.nat) config.add_command(vlan.vlan) - @config.command() @click.option('-y', '--yes', is_flag=True, callback=_abort_if_false, expose_value=False, prompt='Existing files will be overwritten, continue?') @@ -1052,7 +1045,7 @@ def reload(db, filename, yes, load_sysinfo, no_service_restart): if load_sysinfo: command = "{} -j {} -v DEVICE_METADATA.localhost.hwsku".format(SONIC_CFGGEN_PATH, filename) - proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) + proc = subprocess.Popen(command, shell=True, text=True, stdout=subprocess.PIPE) cfg_hwsku, err = proc.communicate() if err: click.echo("Could not get the HWSKU from config file, exiting") @@ -1065,7 +1058,7 @@ def reload(db, filename, yes, load_sysinfo, no_service_restart): log.log_info("'reload' stopping services...") _stop_services(db.cfgdb) - # In Single AISC platforms we have single DB service. In multi-ASIC platforms we have a global DB + # In Single ASIC platforms we have single DB service. In multi-ASIC platforms we have a global DB # service running in the host + DB services running in each ASIC namespace created per ASIC. # In the below logic, we get all namespaces in this platform and add an empty namespace '' # denoting the current namespace which we are in ( the linux host ) @@ -1151,8 +1144,8 @@ def load_mgmt_config(filename): config_data = parse_device_desc_xml(filename) hostname = config_data['DEVICE_METADATA']['localhost']['hostname'] _change_hostname(hostname) - mgmt_conf = netaddr.IPNetwork(config_data['MGMT_INTERFACE'].keys()[0][1]) - gw_addr = config_data['MGMT_INTERFACE'].values()[0]['gwaddr'] + mgmt_conf = netaddr.IPNetwork(list(config_data['MGMT_INTERFACE'].keys())[0][1]) + gw_addr = list(config_data['MGMT_INTERFACE'].values())[0]['gwaddr'] command = "ifconfig eth0 {} netmask {}".format(str(mgmt_conf.ip), str(mgmt_conf.netmask)) clicommon.run_command(command, display_cmd=True) command = "ip route add default via {} dev eth0 table default".format(gw_addr) @@ -1742,7 +1735,7 @@ def warm_restart_enable(ctx, module): @click.pass_context def warm_restart_neighsyncd_timer(ctx, seconds): db = ctx.obj['db'] - if seconds not in range(1,9999): + if seconds not in range(1, 9999): ctx.fail("neighsyncd warm restart timer must be in range 1-9999") db.mod_entry('WARM_RESTART', 'swss', {'neighsyncd_timer': seconds}) @@ -1751,7 +1744,7 @@ def warm_restart_neighsyncd_timer(ctx, seconds): @click.pass_context def warm_restart_bgp_timer(ctx, seconds): db = ctx.obj['db'] - if seconds not in range(1,3600): + if seconds not in range(1, 3600): ctx.fail("bgp warm restart timer must be in range 1-3600") db.mod_entry('WARM_RESTART', 'bgp', {'bgp_timer': seconds}) @@ -1760,7 +1753,7 @@ def warm_restart_bgp_timer(ctx, seconds): @click.pass_context def warm_restart_teamsyncd_timer(ctx, seconds): db = ctx.obj['db'] - if seconds not in range(1,3600): + if seconds not in range(1, 3600): ctx.fail("teamsyncd warm restart timer must be in range 1-3600") db.mod_entry('WARM_RESTART', 'teamd', {'teamsyncd_timer': seconds}) @@ -1795,7 +1788,7 @@ def vrf_add_management_vrf(config_db): if entry and entry['mgmtVrfEnabled'] == 'true' : click.echo("ManagementVRF is already Enabled.") return None - config_db.mod_entry('MGMT_VRF_CONFIG',"vrf_global",{"mgmtVrfEnabled": "true"}) + config_db.mod_entry('MGMT_VRF_CONFIG', "vrf_global", {"mgmtVrfEnabled": "true"}) mvrf_restart_services() def vrf_delete_management_vrf(config_db): @@ -1805,7 +1798,7 @@ def vrf_delete_management_vrf(config_db): if not entry or entry['mgmtVrfEnabled'] == 'false' : click.echo("ManagementVRF is already Disabled.") return None - config_db.mod_entry('MGMT_VRF_CONFIG',"vrf_global",{"mgmtVrfEnabled": "false"}) + config_db.mod_entry('MGMT_VRF_CONFIG', "vrf_global", {"mgmtVrfEnabled": "false"}) mvrf_restart_services() @config.group(cls=clicommon.AbbreviationGroup) @@ -1879,11 +1872,11 @@ def modify_snmptrap_server(ctx, ver, serverip, port, vrf, comm): config_db = ctx.obj['db'] if ver == "1": #By default, v1TrapDest value in snmp.yml is "NotConfigured". Modify it. - config_db.mod_entry('SNMP_TRAP_CONFIG',"v1TrapDest",{"DestIp": serverip, "DestPort": port, "vrf": vrf, "Community": comm}) + config_db.mod_entry('SNMP_TRAP_CONFIG', "v1TrapDest", {"DestIp": serverip, "DestPort": port, "vrf": vrf, "Community": comm}) elif ver == "2": - config_db.mod_entry('SNMP_TRAP_CONFIG',"v2TrapDest",{"DestIp": serverip, "DestPort": port, "vrf": vrf, "Community": comm}) + config_db.mod_entry('SNMP_TRAP_CONFIG', "v2TrapDest", {"DestIp": serverip, "DestPort": port, "vrf": vrf, "Community": comm}) else: - config_db.mod_entry('SNMP_TRAP_CONFIG',"v3TrapDest",{"DestIp": serverip, "DestPort": port, "vrf": vrf, "Community": comm}) + config_db.mod_entry('SNMP_TRAP_CONFIG', "v3TrapDest", {"DestIp": serverip, "DestPort": port, "vrf": vrf, "Community": comm}) cmd="systemctl restart snmp" os.system (cmd) @@ -1896,11 +1889,11 @@ def delete_snmptrap_server(ctx, ver): config_db = ctx.obj['db'] if ver == "1": - config_db.mod_entry('SNMP_TRAP_CONFIG',"v1TrapDest",None) + config_db.mod_entry('SNMP_TRAP_CONFIG', "v1TrapDest", None) elif ver == "2": - config_db.mod_entry('SNMP_TRAP_CONFIG',"v2TrapDest",None) + config_db.mod_entry('SNMP_TRAP_CONFIG', "v2TrapDest", None) else: - config_db.mod_entry('SNMP_TRAP_CONFIG',"v3TrapDest",None) + config_db.mod_entry('SNMP_TRAP_CONFIG', "v3TrapDest", None) cmd="systemctl restart snmp" os.system (cmd) @@ -2015,7 +2008,6 @@ def del_mac(ctx, mac, vlan): db.set_entry('FDB', (vlan_name, mac), None) - # # 'bgp' group ('config bgp ...') # @@ -2087,19 +2079,17 @@ def all(verbose): """ log.log_info("'bgp shutdown all' executing...") namespaces = [DEFAULT_NAMESPACE] - ignore_local_hosts = False if multi_asic.is_multi_asic(): ns_list = multi_asic.get_all_namespaces() namespaces = ns_list['front_ns'] - ignore_local_hosts = True # Connect to CONFIG_DB in linux host (in case of single ASIC) or CONFIG_DB in all the # namespaces (in case of multi ASIC) and do the sepcified "action" on the BGP neighbor(s) for namespace in namespaces: config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) config_db.connect() - bgp_neighbor_ip_list = _get_all_neighbor_ipaddresses(config_db, ignore_local_hosts) + bgp_neighbor_ip_list = _get_all_neighbor_ipaddresses(config_db) for ipaddress in bgp_neighbor_ip_list: _change_bgp_session_status_by_addr(config_db, ipaddress, 'down', verbose) @@ -2144,19 +2134,17 @@ def all(verbose): """ log.log_info("'bgp startup all' executing...") namespaces = [DEFAULT_NAMESPACE] - ignore_local_hosts = False if multi_asic.is_multi_asic(): ns_list = multi_asic.get_all_namespaces() namespaces = ns_list['front_ns'] - ignore_local_hosts = True # Connect to CONFIG_DB in linux host (in case of single ASIC) or CONFIG_DB in all the # namespaces (in case of multi ASIC) and do the sepcified "action" on the BGP neighbor(s) for namespace in namespaces: config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace) config_db.connect() - bgp_neighbor_ip_list = _get_all_neighbor_ipaddresses(config_db, ignore_local_hosts) + bgp_neighbor_ip_list = _get_all_neighbor_ipaddresses(config_db) for ipaddress in bgp_neighbor_ip_list: _change_bgp_session_status_by_addr(config_db, ipaddress, 'up', verbose) @@ -2263,17 +2251,17 @@ def startup(ctx, interface_name): log.log_info("'interface startup {}' executing...".format(interface_name)) port_dict = config_db.get_table('PORT') - for port_name in port_dict.keys(): + for port_name in port_dict: if port_name in intf_fs: config_db.mod_entry("PORT", port_name, {"admin_status": "up"}) portchannel_list = config_db.get_table("PORTCHANNEL") - for po_name in portchannel_list.keys(): + for po_name in portchannel_list: if po_name in intf_fs: config_db.mod_entry("PORTCHANNEL", po_name, {"admin_status": "up"}) subport_list = config_db.get_table("VLAN_SUB_INTERFACE") - for sp_name in subport_list.keys(): + for sp_name in subport_list: if sp_name in intf_fs: config_db.mod_entry("VLAN_SUB_INTERFACE", sp_name, {"admin_status": "up"}) @@ -2303,17 +2291,17 @@ def shutdown(ctx, interface_name): ctx.fail("Interface name is invalid. Please enter a valid interface name!!") port_dict = config_db.get_table('PORT') - for port_name in port_dict.keys(): + for port_name in port_dict: if port_name in intf_fs: config_db.mod_entry("PORT", port_name, {"admin_status": "down"}) portchannel_list = config_db.get_table("PORTCHANNEL") - for po_name in portchannel_list.keys(): + for po_name in portchannel_list: if po_name in intf_fs: config_db.mod_entry("PORTCHANNEL", po_name, {"admin_status": "down"}) subport_list = config_db.get_table("VLAN_SUB_INTERFACE") - for sp_name in subport_list.keys(): + for sp_name in subport_list: if sp_name in intf_fs: config_db.mod_entry("VLAN_SUB_INTERFACE", sp_name, {"admin_status": "down"}) @@ -2411,20 +2399,21 @@ def breakout(ctx, interface_name, mode, verbose, force_remove_dependencies, load remains unchanged to limit the traffic impact """ click.secho("\nAfter running Logic to limit the impact", fg="cyan", underline=True) - matched_item = [intf for intf, speed in del_intf_dict.items() if intf in add_intf_dict.keys() and speed == add_intf_dict[intf]] + matched_items = [intf for intf in del_intf_dict if intf in add_intf_dict and del_intf_dict[intf] == add_intf_dict[intf]] # Remove the interface which remains unchanged from both del_intf_dict and add_intf_dict - map(del_intf_dict.pop, matched_item) - map(add_intf_dict.pop, matched_item) + for item in matched_items: + del_intf_dict.pop(item) + add_intf_dict.pop(item) click.secho("\nFinal list of ports to be deleted : \n {} \nFinal list of ports to be added : \n {}".format(json.dumps(del_intf_dict, indent=4), json.dumps(add_intf_dict, indent=4), fg='green', blink=True)) - if len(add_intf_dict.keys()) == 0: - click.secho("[ERROR] add_intf_dict is None! No interfaces are there to be added", fg='red') + if not add_intf_dict: + click.secho("[ERROR] add_intf_dict is None or empty! No interfaces are there to be added", fg='red') raise click.Abort() port_dict = {} for intf in add_intf_dict: - if intf in add_ports.keys(): + if intf in add_ports: port_dict[intf] = add_ports[intf] # writing JSON object @@ -2437,7 +2426,7 @@ def breakout(ctx, interface_name, mode, verbose, force_remove_dependencies, load cm = load_ConfigMgmt(verbose) """ Delete all ports if forced else print dependencies using ConfigMgmt API """ - final_delPorts = [intf for intf in del_intf_dict.keys()] + final_delPorts = [intf for intf in del_intf_dict] """ Warn user if tables without yang models exist and have final_delPorts """ breakout_warnUser_extraTables(cm, final_delPorts, confirm=True) @@ -2445,24 +2434,21 @@ def breakout(ctx, interface_name, mode, verbose, force_remove_dependencies, load portJson = dict(); portJson['PORT'] = port_dict # breakout_Ports will abort operation on failure, So no need to check return - breakout_Ports(cm, delPorts=final_delPorts, portJson=portJson, force=force_remove_dependencies, \ - loadDefConfig=load_predefined_config, verbose=verbose) + breakout_Ports(cm, delPorts=final_delPorts, portJson=portJson, force=force_remove_dependencies, + loadDefConfig=load_predefined_config, verbose=verbose) # Set Current Breakout mode in config DB brkout_cfg_keys = config_db.get_keys('BREAKOUT_CFG') if interface_name.decode("utf-8") not in brkout_cfg_keys: - click.secho("[ERROR] {} is not present in 'BREAKOUT_CFG' Table!".\ - format(interface_name), fg='red') + click.secho("[ERROR] {} is not present in 'BREAKOUT_CFG' Table!".format(interface_name), fg='red') raise click.Abort() - config_db.set_entry("BREAKOUT_CFG", interface_name,\ - {'brkout_mode': target_brkout_mode}) - click.secho("Breakout process got successfully completed.".\ - format(interface_name), fg="cyan", underline=True) + config_db.set_entry("BREAKOUT_CFG", interface_name, {'brkout_mode': target_brkout_mode}) + click.secho("Breakout process got successfully completed." + .format(interface_name), fg="cyan", underline=True) click.echo("Please note loaded setting will be lost after system reboot. To preserve setting, run `config save`.") except Exception as e: - click.secho("Failed to break out Port. Error: {}".format(str(e)), \ - fg='magenta') + click.secho("Failed to break out Port. Error: {}".format(str(e)), fg='magenta') sys.exit(0) def _get_all_mgmtinterface_keys(): @@ -2470,7 +2456,7 @@ def _get_all_mgmtinterface_keys(): """ config_db = ConfigDBConnector() config_db.connect() - return config_db.get_table('MGMT_INTERFACE').keys() + return list(config_db.get_table('MGMT_INTERFACE').keys()) def mgmt_ip_restart_services(): """Restart the required services when mgmt inteface IP address is changed""" @@ -2570,7 +2556,7 @@ def add(ctx, interface_name, ip_addr, gw): ctx.fail("'interface_name' is None!") try: - net = ipaddress.ip_network(unicode(ip_addr), strict=False) + net = ipaddress.ip_network(ip_addr, strict=False) if '/' not in ip_addr: ip_addr = str(net) @@ -2631,7 +2617,7 @@ def remove(ctx, interface_name, ip_addr): ctx.fail("'interface_name' is None!") try: - net = ipaddress.ip_network(unicode(ip_addr), strict=False) + net = ipaddress.ip_network(ip_addr, strict=False) if '/' not in ip_addr: ip_addr = str(net) @@ -2847,7 +2833,7 @@ def route(ctx): """route-related configuration tasks""" pass -@route.command('add',context_settings={"ignore_unknown_options":True}) +@route.command('add', context_settings={"ignore_unknown_options":True}) @click.argument('command_str', metavar='prefix [vrf ] nexthop <[vrf ] >|>', nargs=-1, type=click.Path()) @click.pass_context def add_route(ctx, command_str): @@ -2858,7 +2844,7 @@ def add_route(ctx, command_str): ctx.fail("argument is incomplete, prefix not found!") if "nexthop" not in command_str: ctx.fail("argument is incomplete, nexthop not found!") - for i in range(0,len(command_str)): + for i in range(0, len(command_str)): if "nexthop" == command_str[i]: prefix_str = command_str[:i] nexthop_str = command_str[i:] @@ -2899,7 +2885,7 @@ def add_route(ctx, command_str): cmd += '"' clicommon.run_command(cmd) -@route.command('del',context_settings={"ignore_unknown_options":True}) +@route.command('del', context_settings={"ignore_unknown_options":True}) @click.argument('command_str', metavar='prefix [vrf ] nexthop <[vrf ] >|>', nargs=-1, type=click.Path()) @click.pass_context def del_route(ctx, command_str): @@ -2910,7 +2896,7 @@ def del_route(ctx, command_str): ctx.fail("argument is incomplete, prefix not found!") if "nexthop" not in command_str: ctx.fail("argument is incomplete, nexthop not found!") - for i in range(0,len(command_str)): + for i in range(0, len(command_str)): if "nexthop" == command_str[i]: prefix_str = command_str[:i] nexthop_str = command_str[i:] @@ -3327,7 +3313,6 @@ def naming_mode_alias(): """Set CLI interface naming mode to ALIAS (Vendor port alias)""" set_interface_naming_mode('alias') -@config.group() def is_loopback_name_valid(loopback_name): """Loopback name validation """ @@ -3365,7 +3350,7 @@ def add_loopback(ctx, loopback_name): ctx.fail("{} is invalid, name should have prefix '{}' and suffix '{}' " .format(loopback_name, CFG_LOOPBACK_PREFIX, CFG_LOOPBACK_NO)) - lo_intfs = [k for k,v in config_db.get_table('LOOPBACK_INTERFACE').iteritems() if type(k) != tuple] + lo_intfs = [k for k, v in config_db.get_table('LOOPBACK_INTERFACE').items() if type(k) != tuple] if loopback_name in lo_intfs: ctx.fail("{} already exists".format(loopback_name)) @@ -3381,7 +3366,7 @@ def del_loopback(ctx, loopback_name): .format(loopback_name, CFG_LOOPBACK_PREFIX, CFG_LOOPBACK_NO)) lo_config_db = config_db.get_table('LOOPBACK_INTERFACE') - lo_intfs = [k for k,v in lo_config_db.iteritems() if type(k) != tuple] + lo_intfs = [k for k, v in lo_config_db.items() if type(k) != tuple] if loopback_name not in lo_intfs: ctx.fail("{} does not exists".format(loopback_name)) @@ -3559,7 +3544,7 @@ def enable(ctx): config_db.mod_entry('SFLOW', 'global', sflow_tbl['global']) try: - proc = subprocess.Popen("systemctl is-active sflow", shell=True, stdout=subprocess.PIPE) + proc = subprocess.Popen("systemctl is-active sflow", shell=True, text=True, stdout=subprocess.PIPE) (out, err) = proc.communicate() except SystemExit as e: ctx.fail("Unable to check sflow status {}".format(e)) @@ -3634,7 +3619,7 @@ def enable(ctx, ifname): intf_dict = config_db.get_table('SFLOW_SESSION') - if intf_dict and ifname in intf_dict.keys(): + if intf_dict and ifname in intf_dict: intf_dict[ifname]['admin_state'] = 'up' config_db.mod_entry('SFLOW_SESSION', ifname, intf_dict[ifname]) else: @@ -3654,7 +3639,7 @@ def disable(ctx, ifname): intf_dict = config_db.get_table('SFLOW_SESSION') - if intf_dict and ifname in intf_dict.keys(): + if intf_dict and ifname in intf_dict: intf_dict[ifname]['admin_state'] = 'down' config_db.mod_entry('SFLOW_SESSION', ifname, intf_dict[ifname]) else: @@ -3679,7 +3664,7 @@ def sample_rate(ctx, ifname, rate): sess_dict = config_db.get_table('SFLOW_SESSION') - if sess_dict and ifname in sess_dict.keys(): + if sess_dict and ifname in sess_dict: sess_dict[ifname]['sample_rate'] = rate config_db.mod_entry('SFLOW_SESSION', ifname, sess_dict[ifname]) else: @@ -3695,7 +3680,7 @@ def collector(ctx): """Add/Delete a sFlow collector""" pass -def is_valid_collector_info(name, ip, port): +def is_valid_collector_info(name, ip, port, vrf_name): if len(name) > 16: click.echo("Collector name must not exceed 16 characters") return False @@ -3708,6 +3693,10 @@ def is_valid_collector_info(name, ip, port): click.echo("Invalid IP address") return False + if vrf_name != 'default' and vrf_name != 'mgmt': + click.echo("Only 'default' and 'mgmt' VRF are supported") + return False + return True # @@ -3716,25 +3705,28 @@ def is_valid_collector_info(name, ip, port): @collector.command() @click.option('--port', required=False, type=int, default=6343, help='Collector port number') +@click.option('--vrf', required=False, type=str, default='default', + help='Collector VRF') @click.argument('name', metavar='', required=True) @click.argument('ipaddr', metavar='', required=True) @click.pass_context -def add(ctx, name, ipaddr, port): +def add(ctx, name, ipaddr, port, vrf): """Add a sFlow collector""" ipaddr = ipaddr.lower() - if not is_valid_collector_info(name, ipaddr, port): + if not is_valid_collector_info(name, ipaddr, port, vrf): return config_db = ctx.obj['db'] collector_tbl = config_db.get_table('SFLOW_COLLECTOR') - if (collector_tbl and name not in collector_tbl.keys() and len(collector_tbl) == 2): + if (collector_tbl and name not in collector_tbl and len(collector_tbl) == 2): click.echo("Only 2 collectors can be configured, please delete one") return config_db.mod_entry('SFLOW_COLLECTOR', name, - {"collector_ip": ipaddr, "collector_port": port}) + {"collector_ip": ipaddr, "collector_port": port, + "collector_vrf": vrf}) return # @@ -3748,7 +3740,7 @@ def del_collector(ctx, name): config_db = ctx.obj['db'] collector_tbl = config_db.get_table('SFLOW_COLLECTOR') - if name not in collector_tbl.keys(): + if name not in collector_tbl: click.echo("Collector: {} not configured".format(name)) return @@ -3781,7 +3773,7 @@ def add(ctx, ifname): if not sflow_tbl: sflow_tbl = {'global': {'admin_state': 'down'}} - if 'agent_id' in sflow_tbl['global'].keys(): + if 'agent_id' in sflow_tbl['global']: click.echo("Agent already configured. Please delete it first.") return @@ -3801,7 +3793,7 @@ def delete(ctx): if not sflow_tbl: sflow_tbl = {'global': {'admin_state': 'down'}} - if 'agent_id' not in sflow_tbl['global'].keys(): + if 'agent_id' not in sflow_tbl['global']: click.echo("sFlow agent not configured.") return diff --git a/config/vlan.py b/config/vlan.py index 338f46974f..5895b798b3 100644 --- a/config/vlan.py +++ b/config/vlan.py @@ -1,5 +1,8 @@ import click import utilities_common.cli as clicommon +import re +import logging +from itertools import count, groupby from time import sleep from .utils import log @@ -137,6 +140,11 @@ def add_vlan_member(db, vid, port, untagged): (not is_port and clicommon.is_pc_router_interface(db.cfgdb, port)): ctx.fail("{} is a router interface!".format(port)) + vlan_in_db = db.cfgdb.get_entry('VLAN', vlan) + members = vlan_in_db.get('members', []) + members.append(port) + vlan_in_db['members'] = members + db.cfgdb.set_entry('VLAN', vlan, vlan_in_db) db.cfgdb.set_entry('VLAN_MEMBER', (vlan, port), {'tagging_mode': "untagged" if untagged else "tagged" }) @vlan_member.command('del') @@ -167,6 +175,15 @@ def del_vlan_member(db, vid, port): if not clicommon.is_port_vlan_member(db.cfgdb, port, vlan): ctx.fail("{} is not a member of {}".format(port, vlan)) + vlan_in_db = db.cfgdb.get_entry('VLAN', vlan) + members = vlan_in_db.get('members', []) + vlan_in_db['members'] = members + members.remove(port) + if len(members) == 0: + del vlan_in_db['members'] + else: + vlan_in_db['members'] = members + db.cfgdb.set_entry('VLAN', vlan, vlan_in_db) db.cfgdb.set_entry('VLAN_MEMBER', (vlan, port), None) @vlan.group(cls=clicommon.AbbreviationGroup, name='dhcp_relay') @@ -201,7 +218,9 @@ def add_vlan_dhcp_relay_destination(db, vid, dhcp_relay_destination_ip): click.echo("Added DHCP relay destination address {} to {}".format(dhcp_relay_destination_ip, vlan_name)) try: click.echo("Restarting DHCP relay service...") - clicommon.run_command("systemctl restart dhcp_relay", display_cmd=False) + clicommon.run_command("systemctl stop dhcp_relay", display_cmd=False) + clicommon.run_command("systemctl reset-failed dhcp_relay", display_cmd=False) + clicommon.run_command("systemctl start dhcp_relay", display_cmd=False) except SystemExit as e: ctx.fail("Restart service dhcp_relay failed with error {}".format(e)) @@ -235,7 +254,9 @@ def del_vlan_dhcp_relay_destination(db, vid, dhcp_relay_destination_ip): click.echo("Removed DHCP relay destination address {} from {}".format(dhcp_relay_destination_ip, vlan_name)) try: click.echo("Restarting DHCP relay service...") - clicommon.run_command("systemctl restart dhcp_relay", display_cmd=False) + clicommon.run_command("systemctl stop dhcp_relay", display_cmd=False) + clicommon.run_command("systemctl reset-failed dhcp_relay", display_cmd=False) + clicommon.run_command("systemctl start dhcp_relay", display_cmd=False) except SystemExit as e: ctx.fail("Restart service dhcp_relay failed with error {}".format(e)) @@ -262,6 +283,15 @@ def vlan_range_validate(vid1, vid2): if vid2 <= vid1: ctx.fail(" vid2 should be greater than vid1") +# +# Return a string with ranges separated by hyphen. +# +def get_hyphenated_string(vlan_list): + vlan_list.sort() + G = (list(x) for _,x in groupby(vlan_list, lambda x,c=count(): next(c)-x)) + hyphenated_string = ",".join("-".join(map(str,(g[0],g[-1])[:len(g)])) for g in G) + return hyphenated_string + # # 'range' group ('config vlan range ...') # @@ -517,16 +547,6 @@ def add_vlan_member_range(db, vid1, vid2, interface_name, untagged, warning): clients = db.cfgdb.get_redis_client(db.cfgdb.CONFIG_DB) pipe = clients.pipeline() - # Validate if interface has IP configured - # in physical and port channel tables - for k,v in db.cfgdb.get_table('INTERFACE').iteritems(): - if k == interface_name: - ctx.fail(" {} has ip address configured".format(interface_name)) - - for k,v in db.cfgdb.get_table('PORTCHANNEL_INTERFACE').iteritems(): - if k == interface_name: - ctx.fail(" {} has ip address configured".format(interface_name)) - for k,v in db.cfgdb.get_table('PORTCHANNEL_MEMBER'): if v == interface_name: ctx.fail(" {} is configured as a port channel member".format(interface_name)) diff --git a/scripts/fdbclear b/scripts/fdbclear index 40bb848164..f3cad967ef 100644 --- a/scripts/fdbclear +++ b/scripts/fdbclear @@ -1,4 +1,5 @@ -#!/usr/bin/python +#!/usr/bin/env python3 + """ Script to clear MAC/FDB entries learnt in Hardware @@ -15,7 +16,7 @@ import argparse import json import sys -from swsssdk import SonicV2Connector +from swsscommon.swsscommon import SonicV2Connector class FdbClear(object): diff --git a/scripts/fdbshow b/scripts/fdbshow index ac4916cd50..08fddd592a 100755 --- a/scripts/fdbshow +++ b/scripts/fdbshow @@ -1,4 +1,5 @@ -#!/usr/bin/python +#!/usr/bin/python3 + """ Script to show MAC/FDB entries learnt in Hardware @@ -31,6 +32,7 @@ import sys from natsort import natsorted from swsssdk import SonicV2Connector, port_util +#from swsscommon.swsscommon import SonicV2Connector from tabulate import tabulate class FdbShow(object): @@ -40,7 +42,7 @@ class FdbShow(object): def __init__(self): super(FdbShow,self).__init__() - self.db = SonicV2Connector(host="127.0.0.1", decode_responses=True) + self.db = SonicV2Connector(host="127.0.0.1") self.if_name_map, \ self.if_oid_map = port_util.get_interface_oid_map(self.db) self.if_br_oid_map = port_util.get_bridge_port_map(self.db) @@ -50,7 +52,7 @@ class FdbShow(object): def fetch_fdb_data(self): """ Fetch FDB entries from ASIC DB. - FDB entries are sorted on "VlanID" and stored as a list of tuples + FDB entries are sorted on "VlanID" plus MAC addr, and stored as a list of tuples """ self.db.connect(self.db.ASIC_DB) self.bridge_mac_list = [] @@ -64,7 +66,7 @@ class FdbShow(object): oid_pfx = len("oid:0x") - client = self.db.redis_clients["ASIC_DB"] + client = self.db.get_redis_client(self.db.ASIC_DB) pipe = client.pipeline() values = [] fdb_list = [] @@ -76,44 +78,49 @@ class FdbShow(object): fdb_list.append(fdb) pipe.hgetall(s) values = pipe.execute() + client = self.db.get_redis_client(self.db.ASIC_DB) + pipe = client.pipeline() + vlans = [] vlan_keys = self.db.keys('ASIC_DB', "ASIC_STATE:SAI_OBJECT_TYPE_VLAN:*") for v in vlan_keys: pipe.hgetall(v) - pipe.execute() + vlans = pipe.execute() posi = 0 for ent in values: if 'SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID' not in ent: posi = posi + 1 continue - br_port_id = ent[b"SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID"][oid_pfx:] - ent_type = ent[b"SAI_FDB_ENTRY_ATTR_TYPE"] + br_port_id = ent["SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID"][oid_pfx:] + ent_type = ent["SAI_FDB_ENTRY_ATTR_TYPE"] fdb_type = ['Dynamic','Static'][ent_type == "SAI_FDB_ENTRY_TYPE_STATIC"] - if br_port_id not in self.if_br_oid_map: + if (br_port_id not in self.if_br_oid_map): posi = posi + 1 continue + port_id = self.if_br_oid_map[br_port_id] - #When if_name not mapped to port_id in DB, using port_id as if_name in the display. + #FIXME: When if_name not mapped to port_id in DB, using port_id as if_name in the display. try: if_name = self.if_oid_map[port_id] - except Exception: + except: if_name = port_id - + + #FIXME: When VLAN Id for fdb entry not present in DB, then not displaying the fdb entry. if 'vlan' in fdb: vlan_id = fdb["vlan"] elif 'bvid' in fdb: try: - vlan_id = port_util.get_vlan_id_from_bvid(self.db, fdb["bvid"]) - except Exception: - vlan_id = fdb["bvid"] - print("Failed to get Vlan id for bvid {}\n".format(fdb["bvid"])) - self.bridge_mac_list.append((int(vlan_id),) + (fdb["mac"],) + (if_name,) + (fdb_type,)) - - self.bridge_mac_list.sort(key = lambda x: x[0]) + vlan_id = vlans[vlan_keys.index("ASIC_STATE:SAI_OBJECT_TYPE_VLAN:{}".format(fdb_list[posi][u'bvid']))] ["SAI_VLAN_ATTR_VLAN_ID"] + except: + posi = posi + 1 + continue + self.bridge_mac_list.append((int(vlan_id),) + (fdb_list[posi]["mac"],) + (if_name,) + (fdb_type,)) + posi = posi + 1 + + self.bridge_mac_list.sort(key = lambda x: (x[0], x[1])) return - def get_iter_index(self, key_value=0, pos=0): """ Get the starting index of matched entry @@ -150,7 +157,7 @@ class FdbShow(object): output.append([self.FDB_COUNT, fdb[0], fdb[1], fdb[2], fdb[3]]) print(tabulate(output, self.HEADER)) - print("Total number of entries {0}".format(self.FDB_COUNT)) + print("Total number of entries {0} ".format(self.FDB_COUNT)) def main(): diff --git a/show/main.py b/show/main.py index c112534d1c..7df6a26514 100755 --- a/show/main.py +++ b/show/main.py @@ -1,5 +1,3 @@ -#! /usr/bin/python -u - import json import netaddr import os @@ -7,23 +5,39 @@ import sys import click -from natsort import natsorted import netifaces -from pkg_resources import parse_version - -import feature -import interfaces -import kube -import mlnx import utilities_common.cli as clicommon -import vlan -import system_health - +import utilities_common.multi_asic as multi_asic_util +from natsort import natsorted +from pkg_resources import parse_version from sonic_py_common import device_info, multi_asic -from swsssdk import ConfigDBConnector, SonicV2Connector +from swsssdk import ConfigDBConnector +from swsscommon.swsscommon import SonicV2Connector from tabulate import tabulate from utilities_common.db import Db -import utilities_common.multi_asic as multi_asic_util + +from . import acl +from . import bgp_common +from . import chassis_modules +from . import dropcounters +from . import feature +from . import fgnhg +from . import gearbox +from . import interfaces +from . import kdump +from . import kube +from . import mlnx +from . import muxcable +from . import nat +from . import platform +from . import processes +from . import reboot_cause +from . import sflow +from . import vlan +from . import vnet +from . import vxlan +from . import system_health +from . import warm_restart # Global Variables @@ -43,6 +57,7 @@ def get_routing_stack(): proc = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True, + text=True, stderr=subprocess.STDOUT) stdout = proc.communicate()[0] proc.wait() @@ -77,11 +92,11 @@ def run_command(command, display_cmd=False, return_cmd=False): clicommon.run_command_in_alias_mode(command) raise sys.exit(0) - proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) + proc = subprocess.Popen(command, shell=True, text=True, stdout=subprocess.PIPE) while True: if return_cmd: - output = proc.communicate()[0].decode("utf-8") + output = proc.communicate()[0] return output output = proc.stdout.readline() if output == "" and proc.poll() is not None: @@ -125,11 +140,33 @@ def cli(ctx): # Add groups from other modules +cli.add_command(acl.acl) +cli.add_command(chassis_modules.chassis_modules) +cli.add_command(dropcounters.dropcounters) cli.add_command(feature.feature) +cli.add_command(fgnhg.fgnhg) cli.add_command(interfaces.interfaces) +cli.add_command(kdump.kdump) cli.add_command(kube.kubernetes) +cli.add_command(muxcable.muxcable) +cli.add_command(nat.nat) +cli.add_command(platform.platform) +cli.add_command(processes.processes) +cli.add_command(reboot_cause.reboot_cause) +cli.add_command(sflow.sflow) cli.add_command(vlan.vlan) +cli.add_command(vnet.vnet) +cli.add_command(vxlan.vxlan) cli.add_command(system_health.system_health) +cli.add_command(warm_restart.warm_restart) + +# Add greabox commands only if GEARBOX is configured +# TODO: Find a cleaner way to do this +app_db = SonicV2Connector(host='127.0.0.1') +app_db.connect(app_db.APPL_DB) +if app_db.keys(app_db.APPL_DB, '_GEARBOX_TABLE:phy:*'): + cli.add_command(gearbox.gearbox) + # # 'vrf' command ("show vrf") @@ -143,8 +180,8 @@ def get_interface_bind_to_vrf(config_db, vrf_name): for table_name in tables: interface_dict = config_db.get_table(table_name) if interface_dict: - for interface in interface_dict.keys(): - if interface_dict[interface].has_key('vrf_name') and vrf_name == interface_dict[interface]['vrf_name']: + for interface in interface_dict: + if 'vrf_name' in interface_dict[interface] and vrf_name == interface_dict[interface]['vrf_name']: data.append(interface) return data @@ -160,8 +197,8 @@ def vrf(vrf_name): if vrf_dict: vrfs = [] if vrf_name is None: - vrfs = vrf_dict.keys() - elif vrf_name in vrf_dict.keys(): + vrfs = list(vrf_dict.keys()) + elif vrf_name in vrf_dict: vrfs = [vrf_name] for vrf in vrfs: intfs = get_interface_bind_to_vrf(config_db, vrf) @@ -223,7 +260,7 @@ def is_mgmt_vrf_enabled(ctx): if ctx.invoked_subcommand is None: cmd = 'sonic-cfggen -d --var-json "MGMT_VRF_CONFIG"' - p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + p = subprocess.Popen(cmd, shell=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) try : mvrf_dict = json.loads(p.stdout.read()) except ValueError: @@ -284,7 +321,7 @@ def address (): # Fetching data from config_db for MGMT_INTERFACE mgmt_ip_data = config_db.get_table('MGMT_INTERFACE') - for key in natsorted(mgmt_ip_data.keys()): + for key in natsorted(list(mgmt_ip_data.keys())): click.echo("Management IP address = {0}".format(key[1])) click.echo("Management Network Default Gateway = {0}".format(mgmt_ip_data[key]['gwaddr'])) @@ -302,7 +339,7 @@ def snmpagentaddress (ctx): header = ['ListenIP', 'ListenPort', 'ListenVrf'] body = [] - for agent in agenttable.keys(): + for agent in agenttable: body.append([agent[0], agent[1], agent[2]]) click.echo(tabulate(body, header)) @@ -320,7 +357,7 @@ def snmptrap (ctx): header = ['Version', 'TrapReceiverIP', 'Port', 'VRF', 'Community'] body = [] - for row in traptable.keys(): + for row in traptable: if row == "v1TrapDest": ver=1 elif row == "v2TrapDest": @@ -597,7 +634,6 @@ def pwm_buffer_pool(): command = 'watermarkstat -p -t buffer_pool' run_command(command) - # # 'mac' command ("show mac ...") # @@ -620,10 +656,12 @@ def mac(ctx, vlan, port, verbose): @mac.command() def aging_time(): """Show MAC Aging-Time""" + config_db = ConfigDBConnector() + config_db.connect() - app_db = SonicV2Connector(host='127.0.0.1') - app_db.connect(app_db.APPL_DB) - switch_keys = app_db.keys(app_db.APPL_DB, 'SWITCH_TABLE:*') + # Fetching data from config_db for SWITCH + switch_table = config_db.get_table('SWITCH') + switch_keys = switch_table.keys() age_time = 0 for key in switch_keys: @@ -632,6 +670,7 @@ def aging_time(): age_time = switch_table[key]['fdb_aging_time'] except KeyError: age_time = '0' + pass output = 'Mac Aging-Time : ' output += ('%s seconds\n' % (str(age_time))) click.echo(output) @@ -804,13 +843,16 @@ def get_bgp_peer(): """ config_db = ConfigDBConnector() config_db.connect() - data = config_db.get_table('BGP_NEIGHBOR') bgp_peer = {} + bgp_neighbor_tables = ['BGP_NEIGHBOR', 'BGP_INTERNAL_NEIGHBOR'] + + for table in bgp_neighbor_tables: + data = config_db.get_table(table) + for neighbor_ip in data: + local_addr = data[neighbor_ip]['local_addr'] + neighbor_name = data[neighbor_ip]['name'] + bgp_peer.setdefault(local_addr, [neighbor_name, neighbor_ip]) - for neighbor_ip in data.keys(): - local_addr = data[neighbor_ip]['local_addr'] - neighbor_name = data[neighbor_ip]['name'] - bgp_peer.setdefault(local_addr, [neighbor_name, neighbor_ip]) return bgp_peer # @@ -819,17 +861,13 @@ def get_bgp_peer(): @ip.command() @click.argument('args', metavar='[IPADDRESS] [vrf ] [...]', nargs=-1, required=False) +@click.option('--display', '-d', 'display', default=None, show_default=False, type=str, help='all|frontend') +@click.option('--namespace', '-n', 'namespace', default=None, type=str, show_default=False, help='Namespace name or all') @click.option('--verbose', is_flag=True, help="Enable verbose output") -def route(args, verbose): +def route(args, namespace, display, verbose): """Show IP (IPv4) routing table""" - cmd = 'sudo vtysh -c "show ip route' - - for arg in args: - cmd += " " + str(arg) - - cmd += '"' - - run_command(cmd, display_cmd=verbose) + # Call common handler to handle the show ip route cmd + bgp_common.show_routes(args, namespace, display, verbose, "ip") # # 'prefix-list' subcommand ("show ip prefix-list") @@ -942,17 +980,13 @@ def interfaces(): @ipv6.command() @click.argument('args', metavar='[IPADDRESS] [vrf ] [...]', nargs=-1, required=False) +@click.option('--display', '-d', 'display', default=None, show_default=False, type=str, help='all|frontend') +@click.option('--namespace', '-n', 'namespace', default=None, type=str, show_default=False, help='Namespace name or all') @click.option('--verbose', is_flag=True, help="Enable verbose output") -def route(args, verbose): +def route(args, namespace, display, verbose): """Show IPv6 routing table""" - cmd = 'sudo vtysh -c "show ipv6 route' - - for arg in args: - cmd += " " + str(arg) - - cmd += '"' - - run_command(cmd, display_cmd=verbose) + # Call common handler to handle the show ipv6 route cmd + bgp_common.show_routes(args, namespace, display, verbose, "ipv6") # 'protocol' command @@ -1011,125 +1045,6 @@ def table(verbose): cmd = "sudo lldpshow" run_command(cmd, display_cmd=verbose) -# -# 'platform' group ("show platform ...") -# - -def get_hw_info_dict(): - """ - This function is used to get the HW info helper function - """ - hw_info_dict = {} - - version_info = device_info.get_sonic_version_info() - - hw_info_dict['platform'] = device_info.get_platform() - hw_info_dict['hwsku'] = device_info.get_hwsku() - hw_info_dict['asic_type'] = version_info['asic_type'] - hw_info_dict['asic_count'] = multi_asic.get_num_asics() - - return hw_info_dict - -@cli.group(cls=clicommon.AliasedGroup) -def platform(): - """Show platform-specific hardware info""" - pass - -version_info = device_info.get_sonic_version_info() -if (version_info and version_info.get('asic_type') == 'mellanox'): - platform.add_command(mlnx.mlnx) - -# 'summary' subcommand ("show platform summary") -@platform.command() -@click.option('--json', is_flag=True, help="JSON output") -def summary(json): - """Show hardware platform information""" - - hw_info_dict = get_hw_info_dict() - if json: - click.echo(clicommon.json_dump(hw_info_dict)) - else: - click.echo("Platform: {}".format(hw_info_dict['platform'])) - click.echo("HwSKU: {}".format(hw_info_dict['hwsku'])) - click.echo("ASIC: {}".format(hw_info_dict['asic_type'])) - click.echo("ASIC Count: {}".format(hw_info_dict['asic_count'])) - -# 'syseeprom' subcommand ("show platform syseeprom") -@platform.command() -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def syseeprom(verbose): - """Show system EEPROM information""" - cmd = "sudo decode-syseeprom -d" - run_command(cmd, display_cmd=verbose) - -# 'psustatus' subcommand ("show platform psustatus") -@platform.command() -@click.option('-i', '--index', default=-1, type=int, help="the index of PSU") -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def psustatus(index, verbose): - """Show PSU status information""" - cmd = "psushow -s" - - if index >= 0: - cmd += " -i {}".format(index) - - run_command(cmd, display_cmd=verbose) - -# 'ssdhealth' subcommand ("show platform ssdhealth [--verbose/--vendor]") -@platform.command() -@click.argument('device', required=False) -@click.option('--verbose', is_flag=True, help="Enable verbose output") -@click.option('--vendor', is_flag=True, help="Enable vendor specific output") -def ssdhealth(device, verbose, vendor): - """Show SSD Health information""" - if not device: - device = os.popen("lsblk -o NAME,TYPE -p | grep disk").readline().strip().split()[0] - cmd = "ssdutil -d " + device - options = " -v" if verbose else "" - options += " -e" if vendor else "" - run_command(cmd + options, display_cmd=verbose) - -@platform.command() -@click.option('--verbose', is_flag=True, help="Enable verbose output") -@click.option('-c', '--check', is_flag=True, help="Check the platfome pcie device") -def pcieinfo(check, verbose): - """Show Device PCIe Info""" - cmd = "pcieutil pcie_show" - if check: - cmd = "pcieutil pcie_check" - run_command(cmd, display_cmd=verbose) - -# 'fan' subcommand ("show platform fan") -@platform.command() -def fan(): - """Show fan status information""" - cmd = 'fanshow' - run_command(cmd) - -# 'temperature' subcommand ("show platform temperature") -@platform.command() -def temperature(): - """Show device temperature information""" - cmd = 'tempershow' - run_command(cmd) - -# 'firmware' subcommand ("show platform firmware") -@platform.command( - context_settings=dict( - ignore_unknown_options=True, - allow_extra_args=True - ), - add_help_option=False -) -@click.argument('args', nargs=-1, type=click.UNPROCESSED) -def firmware(args): - """Show firmware information""" - cmd = "fwutil show {}".format(" ".join(args)) - - try: - subprocess.check_call(cmd, shell=True) - except subprocess.CalledProcessError as e: - sys.exit(e.returncode) # # 'logging' command ("show logging") @@ -1169,25 +1084,33 @@ def logging(process, lines, follow, verbose): def version(verbose): """Show version information""" version_info = device_info.get_sonic_version_info() - hw_info_dict = get_hw_info_dict() + + platform = device_info.get_platform() + hwsku = device_info.get_hwsku() + asic_type = version_info['asic_type'] + asic_count = multi_asic.get_num_asics() + serial_number_cmd = "sudo decode-syseeprom -s" - serial_number = subprocess.Popen(serial_number_cmd, shell=True, stdout=subprocess.PIPE) + serial_number = subprocess.Popen(serial_number_cmd, shell=True, text=True, stdout=subprocess.PIPE) + sys_uptime_cmd = "uptime" - sys_uptime = subprocess.Popen(sys_uptime_cmd, shell=True, stdout=subprocess.PIPE) + sys_uptime = subprocess.Popen(sys_uptime_cmd, shell=True, text=True, stdout=subprocess.PIPE) + click.echo("\nSONiC Software Version: SONiC.{}".format(version_info['build_version'])) click.echo("Distribution: Debian {}".format(version_info['debian_version'])) click.echo("Kernel: {}".format(version_info['kernel_version'])) click.echo("Build commit: {}".format(version_info['commit_id'])) click.echo("Build date: {}".format(version_info['build_date'])) click.echo("Built by: {}".format(version_info['built_by'])) - click.echo("\nPlatform: {}".format(hw_info_dict['platform'])) - click.echo("HwSKU: {}".format(hw_info_dict['hwsku'])) - click.echo("ASIC: {}".format(hw_info_dict['asic_type'])) + click.echo("\nPlatform: {}".format(platform)) + click.echo("HwSKU: {}".format(hwsku)) + click.echo("ASIC: {}".format(asic_type)) + click.echo("ASIC Count: {}".format(asic_count)) click.echo("Serial Number: {}".format(serial_number.stdout.read().strip())) click.echo("Uptime: {}".format(sys_uptime.stdout.read().strip())) click.echo("\nDocker images:") cmd = 'sudo docker images --format "table {{.Repository}}\\t{{.Tag}}\\t{{.ID}}\\t{{.Size}}"' - p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) + p = subprocess.Popen(cmd, shell=True, text=True, stdout=subprocess.PIPE) click.echo(p.stdout.read()) # @@ -1202,42 +1125,6 @@ def environment(verbose): run_command(cmd, display_cmd=verbose) -# -# 'processes' group ("show processes ...") -# - -@cli.group(cls=clicommon.AliasedGroup) -def processes(): - """Display process information""" - pass - -@processes.command() -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def summary(verbose): - """Show processes info""" - # Run top batch mode to prevent unexpected newline after each newline - cmd = "ps -eo pid,ppid,cmd,%mem,%cpu " - run_command(cmd, display_cmd=verbose) - - -# 'cpu' subcommand ("show processes cpu") -@processes.command() -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def cpu(verbose): - """Show processes CPU info""" - # Run top in batch mode to prevent unexpected newline after each newline - cmd = "top -bn 1 -o %CPU" - run_command(cmd, display_cmd=verbose) - -# 'memory' subcommand -@processes.command() -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def memory(verbose): - """Show processes memory info""" - # Run top batch mode to prevent unexpected newline after each newline - cmd = "top -bn 1 -o %MEM" - run_command(cmd, display_cmd=verbose) - # # 'users' command ("show users") # @@ -1358,7 +1245,7 @@ def ntp(verbose): ntp_server = line.split(" ")[1] ntp_servers.append(ntp_server) ntp_dict['NTP Servers'] = ntp_servers - print(tabulate(ntp_dict, headers=ntp_dict.keys(), tablefmt="simple", stralign='left', missingval="")) + print(tabulate(ntp_dict, headers=list(ntp_dict.keys()), tablefmt="simple", stralign='left', missingval="")) # 'syslog' subcommand ("show runningconfiguration syslog") @@ -1376,7 +1263,7 @@ def syslog(verbose): server = line[0][5:] syslog_servers.append(server) syslog_dict['Syslog Servers'] = syslog_servers - print(tabulate(syslog_dict, headers=syslog_dict.keys(), tablefmt="simple", stralign='left', missingval="")) + print(tabulate(syslog_dict, headers=list(syslog_dict.keys()), tablefmt="simple", stralign='left', missingval="")) # @@ -1395,7 +1282,7 @@ def startupconfiguration(): def bgp(verbose): """Show BGP startup configuration""" cmd = "sudo docker ps | grep bgp | awk '{print$2}' | cut -d'-' -f3 | cut -d':' -f1" - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True, text=True) result = proc.stdout.read().rstrip() click.echo("Routing-Stack is: {}".format(result)) if result == "quagga": @@ -1457,99 +1344,19 @@ def system_memory(verbose): cmd = "free -m" run_command(cmd, display_cmd=verbose) -# -# 'kdump command ("show kdump ...") -# -@cli.group(cls=clicommon.AliasedGroup) -def kdump(): - """Show kdump configuration, status and information """ - pass - -@kdump.command('enabled') -def enabled(): - """Show if kdump is enabled or disabled""" - kdump_is_enabled = False - config_db = ConfigDBConnector() - if config_db is not None: - config_db.connect() - table_data = config_db.get_table('KDUMP') - if table_data is not None: - config_data = table_data.get('config') - if config_data is not None: - if config_data.get('enabled').lower() == 'true': - kdump_is_enabled = True - if kdump_is_enabled: - click.echo("kdump is enabled") - else: - click.echo("kdump is disabled") - -@kdump.command('status') -def status(): - """Show kdump status""" - run_command("sonic-kdump-config --status") - run_command("sonic-kdump-config --memory") - run_command("sonic-kdump-config --num_dumps") - run_command("sonic-kdump-config --files") - -@kdump.command('memory') -def memory(): - """Show kdump memory information""" - kdump_memory = "0M-2G:256M,2G-4G:320M,4G-8G:384M,8G-:448M" - config_db = ConfigDBConnector() - if config_db is not None: - config_db.connect() - table_data = config_db.get_table('KDUMP') - if table_data is not None: - config_data = table_data.get('config') - if config_data is not None: - kdump_memory_from_db = config_data.get('memory') - if kdump_memory_from_db is not None: - kdump_memory = kdump_memory_from_db - click.echo("Memory Reserved: %s" % kdump_memory) - -@kdump.command('num_dumps') -def num_dumps(): - """Show kdump max number of dump files""" - kdump_num_dumps = "3" - config_db = ConfigDBConnector() - if config_db is not None: - config_db.connect() - table_data = config_db.get_table('KDUMP') - if table_data is not None: - config_data = table_data.get('config') - if config_data is not None: - kdump_num_dumps_from_db = config_data.get('num_dumps') - if kdump_num_dumps_from_db is not None: - kdump_num_dumps = kdump_num_dumps_from_db - click.echo("Maximum number of Kernel Core files Stored: %s" % kdump_num_dumps) - -@kdump.command('files') -def files(): - """Show kdump kernel core dump files""" - run_command("sonic-kdump-config --files") - -@kdump.command() -@click.argument('record', required=True) -@click.argument('lines', metavar='', required=False) -def log(record, lines): - """Show kdump kernel core dump file kernel log""" - if lines is None: - run_command("sonic-kdump-config --file %s" % record) - else: - run_command("sonic-kdump-config --file %s --lines %s" % (record, lines)) @cli.command('services') def services(): """Show all daemon services""" cmd = "sudo docker ps --format '{{.Names}}'" - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True, text=True) while True: line = proc.stdout.readline() if line != '': print(line.rstrip()+'\t'+"docker") print("---------------------------") cmd = "sudo docker exec {} ps aux | sed '$d'".format(line.rstrip()) - proc1 = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) + proc1 = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True, text=True) print(proc1.stdout.read()) else: break @@ -1638,181 +1445,6 @@ def policer(policer_name, verbose): run_command(cmd, display_cmd=verbose) -# -# 'sflow command ("show sflow ...") -# -@cli.group(invoke_without_command=True) -@clicommon.pass_db -@click.pass_context -def sflow(ctx, db): - """Show sFlow related information""" - if ctx.invoked_subcommand is None: - show_sflow_global(db.cfgdb) - -# -# 'sflow command ("show sflow interface ...") -# -@sflow.command('interface') -@clicommon.pass_db -def sflow_interface(db): - """Show sFlow interface information""" - show_sflow_interface(db.cfgdb) - -def sflow_appDB_connect(): - db = SonicV2Connector(host='127.0.0.1') - db.connect(db.APPL_DB, False) - return db - -def show_sflow_interface(config_db): - sess_db = sflow_appDB_connect() - if not sess_db: - click.echo("sflow AppDB error") - return - - port_tbl = config_db.get_table('PORT') - if not port_tbl: - click.echo("No ports configured") - return - - click.echo("\nsFlow interface configurations") - header = ['Interface', 'Admin State', 'Sampling Rate'] - body = [] - for pname in natsorted(port_tbl.keys()): - intf_key = 'SFLOW_SESSION_TABLE:' + pname - sess_info = sess_db.get_all(sess_db.APPL_DB, intf_key) - if sess_info is None: - continue - body_info = [pname] - body_info.append(sess_info['admin_state']) - body_info.append(sess_info['sample_rate']) - body.append(body_info) - click.echo(tabulate(body, header, tablefmt='grid')) - -def show_sflow_global(config_db): - - sflow_info = config_db.get_table('SFLOW') - global_admin_state = 'down' - if sflow_info: - global_admin_state = sflow_info['global']['admin_state'] - - click.echo("\nsFlow Global Information:") - click.echo(" sFlow Admin State:".ljust(30) + "{}".format(global_admin_state)) - - - click.echo(" sFlow Polling Interval:".ljust(30), nl=False) - if (sflow_info and 'polling_interval' in sflow_info['global'].keys()): - click.echo("{}".format(sflow_info['global']['polling_interval'])) - else: - click.echo("default") - - click.echo(" sFlow AgentID:".ljust(30), nl=False) - if (sflow_info and 'agent_id' in sflow_info['global'].keys()): - click.echo("{}".format(sflow_info['global']['agent_id'])) - else: - click.echo("default") - - sflow_info = config_db.get_table('SFLOW_COLLECTOR') - click.echo("\n {} Collectors configured:".format(len(sflow_info))) - for collector_name in sorted(sflow_info.keys()): - click.echo(" Name: {}".format(collector_name).ljust(30) + - "IP addr: {} ".format(sflow_info[collector_name]['collector_ip']).ljust(25) + - "UDP port: {}".format(sflow_info[collector_name]['collector_port'])) - - -# -# 'acl' group ### -# - -@cli.group(cls=clicommon.AliasedGroup) -def acl(): - """Show ACL related information""" - pass - - -# 'rule' subcommand ("show acl rule") -@acl.command() -@click.argument('table_name', required=False) -@click.argument('rule_id', required=False) -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def rule(table_name, rule_id, verbose): - """Show existing ACL rules""" - cmd = "acl-loader show rule" - - if table_name is not None: - cmd += " {}".format(table_name) - - if rule_id is not None: - cmd += " {}".format(rule_id) - - run_command(cmd, display_cmd=verbose) - - -# 'table' subcommand ("show acl table") -@acl.command() -@click.argument('table_name', required=False) -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def table(table_name, verbose): - """Show existing ACL tables""" - cmd = "acl-loader show table" - - if table_name is not None: - cmd += " {}".format(table_name) - - run_command(cmd, display_cmd=verbose) - - -# -# 'dropcounters' group ### -# - -@cli.group(cls=clicommon.AliasedGroup) -def dropcounters(): - """Show drop counter related information""" - pass - - -# 'configuration' subcommand ("show dropcounters configuration") -@dropcounters.command() -@click.option('-g', '--group', required=False) -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def configuration(group, verbose): - """Show current drop counter configuration""" - cmd = "dropconfig -c show_config" - - if group: - cmd += " -g '{}'".format(group) - - run_command(cmd, display_cmd=verbose) - - -# 'capabilities' subcommand ("show dropcounters capabilities") -@dropcounters.command() -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def capabilities(verbose): - """Show device drop counter capabilities""" - cmd = "dropconfig -c show_capabilities" - - run_command(cmd, display_cmd=verbose) - - -# 'counts' subcommand ("show dropcounters counts") -@dropcounters.command() -@click.option('-g', '--group', required=False) -@click.option('-t', '--counter_type', required=False) -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def counts(group, counter_type, verbose): - """Show drop counts""" - cmd = "dropstat -c show" - - if group: - cmd += " -g '{}'".format(group) - - if counter_type: - cmd += " -t '{}'".format(counter_type) - - run_command(cmd, display_cmd=verbose) - - # # 'ecn' command ("show ecn") # @@ -1820,7 +1452,7 @@ def counts(group, counter_type, verbose): def ecn(): """Show ECN configuration""" cmd = "ecnconfig -l" - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True, text=True) click.echo(proc.stdout.read()) @@ -1831,7 +1463,7 @@ def ecn(): def boot(): """Show boot configuration""" cmd = "sudo sonic-installer list" - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True, text=True) click.echo(proc.stdout.read()) @@ -1841,30 +1473,9 @@ def boot(): def mmu(): """Show mmu configuration""" cmd = "mmuconfig -l" - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True, text=True) click.echo(proc.stdout.read()) - -# -# 'reboot-cause' command ("show reboot-cause") -# -@cli.command('reboot-cause') -def reboot_cause(): - """Show cause of most recent reboot""" - PREVIOUS_REBOOT_CAUSE_FILE = "/host/reboot-cause/previous-reboot-cause.txt" - - # At boot time, PREVIOUS_REBOOT_CAUSE_FILE is generated based on - # the contents of the 'reboot cause' file as it was left when the device - # went down for reboot. This file should always be created at boot, - # but check first just in case it's not present. - if not os.path.isfile(PREVIOUS_REBOOT_CAUSE_FILE): - click.echo("Unable to determine cause of previous reboot\n") - else: - cmd = "cat {}".format(PREVIOUS_REBOOT_CAUSE_FILE) - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) - click.echo(proc.stdout.read()) - - # # 'line' command ("show line") # @@ -1878,271 +1489,6 @@ def line(brief, verbose): return -@cli.group(name='warm_restart', cls=clicommon.AliasedGroup) -def warm_restart(): - """Show warm restart configuration and state""" - pass - -@warm_restart.command() -@click.option('-s', '--redis-unix-socket-path', help='unix socket path for redis connection') -def state(redis_unix_socket_path): - """Show warm restart state""" - kwargs = {} - if redis_unix_socket_path: - kwargs['unix_socket_path'] = redis_unix_socket_path - - db = SonicV2Connector(host='127.0.0.1') - db.connect(db.STATE_DB, False) # Make one attempt only - - TABLE_NAME_SEPARATOR = '|' - prefix = 'WARM_RESTART_TABLE' + TABLE_NAME_SEPARATOR - _hash = '{}{}'.format(prefix, '*') - table_keys = db.keys(db.STATE_DB, _hash) - - def remove_prefix(text, prefix): - if text.startswith(prefix): - return text[len(prefix):] - return text - - table = [] - for tk in table_keys: - entry = db.get_all(db.STATE_DB, tk) - r = [] - r.append(remove_prefix(tk, prefix)) - if 'restore_count' not in entry: - r.append("") - else: - r.append(entry['restore_count']) - - if 'state' not in entry: - r.append("") - else: - r.append(entry['state']) - - table.append(r) - - header = ['name', 'restore_count', 'state'] - click.echo(tabulate(table, header)) - -@warm_restart.command() -@click.option('-s', '--redis-unix-socket-path', help='unix socket path for redis connection') -def config(redis_unix_socket_path): - """Show warm restart config""" - kwargs = {} - if redis_unix_socket_path: - kwargs['unix_socket_path'] = redis_unix_socket_path - config_db = ConfigDBConnector(**kwargs) - config_db.connect(wait_for_init=False) - data = config_db.get_table('WARM_RESTART') - # Python dictionary keys() Method - keys = data.keys() - - state_db = SonicV2Connector(host='127.0.0.1') - state_db.connect(state_db.STATE_DB, False) # Make one attempt only - TABLE_NAME_SEPARATOR = '|' - prefix = 'WARM_RESTART_ENABLE_TABLE' + TABLE_NAME_SEPARATOR - _hash = '{}{}'.format(prefix, '*') - # DBInterface keys() method - enable_table_keys = state_db.keys(state_db.STATE_DB, _hash) - - def tablelize(keys, data, enable_table_keys, prefix): - table = [] - - if enable_table_keys is not None: - for k in enable_table_keys: - k = k.replace(prefix, "") - if k not in keys: - keys.append(k) - - for k in keys: - r = [] - r.append(k) - - enable_k = prefix + k - if enable_table_keys is None or enable_k not in enable_table_keys: - r.append("false") - else: - r.append(state_db.get(state_db.STATE_DB, enable_k, "enable")) - - if k not in data: - r.append("NULL") - r.append("NULL") - r.append("NULL") - elif 'neighsyncd_timer' in data[k]: - r.append("neighsyncd_timer") - r.append(data[k]['neighsyncd_timer']) - r.append("NULL") - elif 'bgp_timer' in data[k] or 'bgp_eoiu' in data[k]: - if 'bgp_timer' in data[k]: - r.append("bgp_timer") - r.append(data[k]['bgp_timer']) - else: - r.append("NULL") - r.append("NULL") - if 'bgp_eoiu' in data[k]: - r.append(data[k]['bgp_eoiu']) - else: - r.append("NULL") - elif 'teamsyncd_timer' in data[k]: - r.append("teamsyncd_timer") - r.append(data[k]['teamsyncd_timer']) - r.append("NULL") - else: - r.append("NULL") - r.append("NULL") - r.append("NULL") - - table.append(r) - - return table - - header = ['name', 'enable', 'timer_name', 'timer_duration', 'eoiu_enable'] - click.echo(tabulate(tablelize(keys, data, enable_table_keys, prefix), header)) - state_db.close(state_db.STATE_DB) - -# -# 'nat' group ("show nat ...") -# - -@cli.group(cls=clicommon.AliasedGroup) -def nat(): - """Show details of the nat """ - pass - -# 'statistics' subcommand ("show nat statistics") -@nat.command() -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def statistics(verbose): - """ Show NAT statistics """ - - cmd = "sudo natshow -s" - run_command(cmd, display_cmd=verbose) - -# 'translations' subcommand ("show nat translations") -@nat.group(invoke_without_command=True) -@click.pass_context -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def translations(ctx, verbose): - """ Show NAT translations """ - - if ctx.invoked_subcommand is None: - cmd = "sudo natshow -t" - run_command(cmd, display_cmd=verbose) - -# 'count' subcommand ("show nat translations count") -@translations.command() -def count(): - """ Show NAT translations count """ - - cmd = "sudo natshow -c" - run_command(cmd) - -# 'config' subcommand ("show nat config") -@nat.group(invoke_without_command=True) -@click.pass_context -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def config(ctx, verbose): - """Show NAT config related information""" - if ctx.invoked_subcommand is None: - click.echo("\nGlobal Values") - cmd = "sudo natconfig -g" - run_command(cmd, display_cmd=verbose) - click.echo("Static Entries") - cmd = "sudo natconfig -s" - run_command(cmd, display_cmd=verbose) - click.echo("Pool Entries") - cmd = "sudo natconfig -p" - run_command(cmd, display_cmd=verbose) - click.echo("NAT Bindings") - cmd = "sudo natconfig -b" - run_command(cmd, display_cmd=verbose) - click.echo("NAT Zones") - cmd = "sudo natconfig -z" - run_command(cmd, display_cmd=verbose) - -# 'static' subcommand ("show nat config static") -@config.command() -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def static(verbose): - """Show static NAT configuration""" - - cmd = "sudo natconfig -s" - run_command(cmd, display_cmd=verbose) - -# 'pool' subcommand ("show nat config pool") -@config.command() -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def pool(verbose): - """Show NAT Pool configuration""" - - cmd = "sudo natconfig -p" - run_command(cmd, display_cmd=verbose) - -# Define GEARBOX commands only if GEARBOX is configured -app_db = SonicV2Connector(host='127.0.0.1') -app_db.connect(app_db.APPL_DB) -if app_db.keys(app_db.APPL_DB, '_GEARBOX_TABLE:phy:*'): - - @cli.group(cls=clicommon.AliasedGroup) - def gearbox(): - """Show gearbox info""" - pass - - # 'phys' subcommand ("show gearbox phys") - @gearbox.group(cls=clicommon.AliasedGroup) - def phys(): - """Show external PHY information""" - pass - - # 'status' subcommand ("show gearbox phys status") - @phys.command() - @click.pass_context - def status(ctx): - """Show gearbox phys status""" - run_command("gearboxutil phys status") - return - - # 'interfaces' subcommand ("show gearbox interfaces") - @gearbox.group(cls=clicommon.AliasedGroup) - def interfaces(): - """Show gearbox interfaces information""" - pass - - # 'status' subcommand ("show gearbox interfaces status") - @interfaces.command() - @click.pass_context - def status(ctx): - """Show gearbox interfaces status""" - run_command("gearboxutil interfaces status") - return - -# 'bindings' subcommand ("show nat config bindings") -@config.command() -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def bindings(verbose): - """Show NAT binding configuration""" - - cmd = "sudo natconfig -b" - run_command(cmd, display_cmd=verbose) - -# 'globalvalues' subcommand ("show nat config globalvalues") -@config.command() -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def globalvalues(verbose): - """Show NAT Global configuration""" - - cmd = "sudo natconfig -g" - run_command(cmd, display_cmd=verbose) - -# 'zones' subcommand ("show nat config zones") -@config.command() -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def zones(verbose): - """Show NAT Zone configuration""" - - cmd = "sudo natconfig -z" - run_command(cmd, display_cmd=verbose) - # # 'ztp status' command ("show ztp status") # @@ -2159,324 +1505,6 @@ def ztp(status, verbose): cmd = cmd + " --verbose" run_command(cmd, display_cmd=verbose) -# -# 'vnet' command ("show vnet") -# -@cli.group(cls=clicommon.AliasedGroup) -def vnet(): - """Show vnet related information""" - pass - -@vnet.command() -@click.argument('vnet_name', required=True) -def name(vnet_name): - """Show vnet name information""" - config_db = ConfigDBConnector() - config_db.connect() - header = ['vnet name', 'vxlan tunnel', 'vni', 'peer list'] - - # Fetching data from config_db for VNET - vnet_data = config_db.get_entry('VNET', vnet_name) - - def tablelize(vnet_key, vnet_data): - table = [] - if vnet_data: - r = [] - r.append(vnet_key) - r.append(vnet_data.get('vxlan_tunnel')) - r.append(vnet_data.get('vni')) - r.append(vnet_data.get('peer_list')) - table.append(r) - return table - - click.echo(tabulate(tablelize(vnet_name, vnet_data), header)) - -@vnet.command() -def brief(): - """Show vnet brief information""" - config_db = ConfigDBConnector() - config_db.connect() - header = ['vnet name', 'vxlan tunnel', 'vni', 'peer list'] - - # Fetching data from config_db for VNET - vnet_data = config_db.get_table('VNET') - vnet_keys = natsorted(vnet_data.keys()) - - def tablelize(vnet_keys, vnet_data): - table = [] - for k in vnet_keys: - r = [] - r.append(k) - r.append(vnet_data[k].get('vxlan_tunnel')) - r.append(vnet_data[k].get('vni')) - r.append(vnet_data[k].get('peer_list')) - table.append(r) - return table - - click.echo(tabulate(tablelize(vnet_keys, vnet_data), header)) - -@vnet.command() -@click.argument('vnet_alias', required=False) -def alias(vnet_alias): - """Show vnet alias to name information""" - config_db = ConfigDBConnector() - config_db.connect() - header = ['Alias', 'Name'] - - # Fetching data from config_db for VNET - vnet_data = config_db.get_table('VNET') - vnet_keys = natsorted(vnet_data.keys()) - - def tablelize(vnet_keys, vnet_data, vnet_alias): - table = [] - for k in vnet_keys: - r = [] - if vnet_alias is not None: - if vnet_data[k].get('guid') == vnet_alias: - r.append(vnet_data[k].get('guid')) - r.append(k) - table.append(r) - return table - else: - continue - - r.append(vnet_data[k].get('guid')) - r.append(k) - table.append(r) - return table - - click.echo(tabulate(tablelize(vnet_keys, vnet_data, vnet_alias), header)) - -@vnet.command() -def interfaces(): - """Show vnet interfaces information""" - config_db = ConfigDBConnector() - config_db.connect() - - header = ['vnet name', 'interfaces'] - - # Fetching data from config_db for interfaces - intfs_data = config_db.get_table("INTERFACE") - vlan_intfs_data = config_db.get_table("VLAN_INTERFACE") - - vnet_intfs = {} - for k, v in intfs_data.items(): - if 'vnet_name' in v: - vnet_name = v['vnet_name'] - if vnet_name in vnet_intfs: - vnet_intfs[vnet_name].append(k) - else: - vnet_intfs[vnet_name] = [k] - - for k, v in vlan_intfs_data.items(): - if 'vnet_name' in v: - vnet_name = v['vnet_name'] - if vnet_name in vnet_intfs: - vnet_intfs[vnet_name].append(k) - else: - vnet_intfs[vnet_name] = [k] - - table = [] - for k, v in vnet_intfs.items(): - r = [] - r.append(k) - r.append(",".join(natsorted(v))) - table.append(r) - - click.echo(tabulate(table, header)) - -@vnet.command() -def neighbors(): - """Show vnet neighbors information""" - config_db = ConfigDBConnector() - config_db.connect() - - header = ['', 'neighbor', 'mac_address', 'interfaces'] - - # Fetching data from config_db for interfaces - intfs_data = config_db.get_table("INTERFACE") - vlan_intfs_data = config_db.get_table("VLAN_INTERFACE") - - vnet_intfs = {} - for k, v in intfs_data.items(): - if 'vnet_name' in v: - vnet_name = v['vnet_name'] - if vnet_name in vnet_intfs: - vnet_intfs[vnet_name].append(k) - else: - vnet_intfs[vnet_name] = [k] - - for k, v in vlan_intfs_data.items(): - if 'vnet_name' in v: - vnet_name = v['vnet_name'] - if vnet_name in vnet_intfs: - vnet_intfs[vnet_name].append(k) - else: - vnet_intfs[vnet_name] = [k] - - appl_db = SonicV2Connector() - appl_db.connect(appl_db.APPL_DB) - - # Fetching data from appl_db for neighbors - nbrs = appl_db.keys(appl_db.APPL_DB, "NEIGH_TABLE*") - nbrs_data = {} - for nbr in nbrs if nbrs else []: - tbl, intf, ip = nbr.split(":", 2) - mac = appl_db.get(appl_db.APPL_DB, nbr, 'neigh') - if intf in nbrs_data: - nbrs_data[intf].append((ip, mac)) - else: - nbrs_data[intf] = [(ip, mac)] - - table = [] - for k, v in vnet_intfs.items(): - v = natsorted(v) - header[0] = k - table = [] - for intf in v: - if intf in nbrs_data: - for ip, mac in nbrs_data[intf]: - r = ["", ip, mac, intf] - table.append(r) - click.echo(tabulate(table, header)) - click.echo() - - if not bool(vnet_intfs): - click.echo(tabulate(table, header)) - -@vnet.group() -def routes(): - """Show vnet routes related information""" - pass - -@routes.command() -def all(): - """Show all vnet routes""" - appl_db = SonicV2Connector() - appl_db.connect(appl_db.APPL_DB) - - header = ['vnet name', 'prefix', 'nexthop', 'interface'] - - # Fetching data from appl_db for VNET ROUTES - vnet_rt_keys = appl_db.keys(appl_db.APPL_DB, "VNET_ROUTE_TABLE*") - vnet_rt_keys = natsorted(vnet_rt_keys) if vnet_rt_keys else [] - - table = [] - for k in vnet_rt_keys: - r = [] - r.extend(k.split(":", 2)[1:]) - val = appl_db.get_all(appl_db.APPL_DB, k) - r.append(val.get('nexthop')) - r.append(val.get('ifname')) - table.append(r) - - click.echo(tabulate(table, header)) - - click.echo() - - header = ['vnet name', 'prefix', 'endpoint', 'mac address', 'vni'] - - # Fetching data from appl_db for VNET TUNNEL ROUTES - vnet_rt_keys = appl_db.keys(appl_db.APPL_DB, "VNET_ROUTE_TUNNEL_TABLE*") - vnet_rt_keys = natsorted(vnet_rt_keys) if vnet_rt_keys else [] - - table = [] - for k in vnet_rt_keys: - r = [] - r.extend(k.split(":", 2)[1:]) - val = appl_db.get_all(appl_db.APPL_DB, k) - r.append(val.get('endpoint')) - r.append(val.get('mac_address')) - r.append(val.get('vni')) - table.append(r) - - click.echo(tabulate(table, header)) - -@routes.command() -def tunnel(): - """Show vnet tunnel routes""" - appl_db = SonicV2Connector() - appl_db.connect(appl_db.APPL_DB) - - header = ['vnet name', 'prefix', 'endpoint', 'mac address', 'vni'] - - # Fetching data from appl_db for VNET TUNNEL ROUTES - vnet_rt_keys = appl_db.keys(appl_db.APPL_DB, "VNET_ROUTE_TUNNEL_TABLE*") - vnet_rt_keys = natsorted(vnet_rt_keys) if vnet_rt_keys else [] - - table = [] - for k in vnet_rt_keys: - r = [] - r.extend(k.split(":", 2)[1:]) - val = appl_db.get_all(appl_db.APPL_DB, k) - r.append(val.get('endpoint')) - r.append(val.get('mac_address')) - r.append(val.get('vni')) - table.append(r) - - click.echo(tabulate(table, header)) - -# -# 'vxlan' command ("show vxlan") -# -@cli.group(cls=clicommon.AliasedGroup) -def vxlan(): - """Show vxlan related information""" - pass - -@vxlan.command() -@click.argument('vxlan_name', required=True) -def name(vxlan_name): - """Show vxlan name information""" - config_db = ConfigDBConnector() - config_db.connect() - header = ['vxlan tunnel name', 'source ip', 'destination ip', 'tunnel map name', 'tunnel map mapping(vni -> vlan)'] - - # Fetching data from config_db for VXLAN TUNNEL - vxlan_data = config_db.get_entry('VXLAN_TUNNEL', vxlan_name) - - table = [] - if vxlan_data: - r = [] - r.append(vxlan_name) - r.append(vxlan_data.get('src_ip')) - r.append(vxlan_data.get('dst_ip')) - vxlan_map_keys = config_db.keys(config_db.CONFIG_DB, - 'VXLAN_TUNNEL_MAP{}{}{}*'.format(config_db.KEY_SEPARATOR, vxlan_name, config_db.KEY_SEPARATOR)) - if vxlan_map_keys: - vxlan_map_mapping = config_db.get_all(config_db.CONFIG_DB, vxlan_map_keys[0]) - r.append(vxlan_map_keys[0].split(config_db.KEY_SEPARATOR, 2)[2]) - r.append("{} -> {}".format(vxlan_map_mapping.get('vni'), vxlan_map_mapping.get('vlan'))) - table.append(r) - - click.echo(tabulate(table, header)) - -@vxlan.command() -def tunnel(): - """Show vxlan tunnel information""" - config_db = ConfigDBConnector() - config_db.connect() - header = ['vxlan tunnel name', 'source ip', 'destination ip', 'tunnel map name', 'tunnel map mapping(vni -> vlan)'] - - # Fetching data from config_db for VXLAN TUNNEL - vxlan_data = config_db.get_table('VXLAN_TUNNEL') - vxlan_keys = natsorted(vxlan_data.keys()) - - table = [] - for k in vxlan_keys: - r = [] - r.append(k) - r.append(vxlan_data[k].get('src_ip')) - r.append(vxlan_data[k].get('dst_ip')) - vxlan_map_keys = config_db.keys(config_db.CONFIG_DB, - 'VXLAN_TUNNEL_MAP{}{}{}*'.format(config_db.KEY_SEPARATOR,k, config_db.KEY_SEPARATOR)) - if vxlan_map_keys: - vxlan_map_mapping = config_db.get_all(config_db.CONFIG_DB, vxlan_map_keys[0]) - r.append(vxlan_map_keys[0].split(config_db.KEY_SEPARATOR, 2)[2]) - r.append("{} -> {}".format(vxlan_map_mapping.get('vni'), vxlan_map_mapping.get('vlan'))) - table.append(r) - - click.echo(tabulate(table, header)) if __name__ == '__main__': cli() diff --git a/show/vlan.py b/show/vlan.py index 76418ed6e1..dc86a1dec1 100644 --- a/show/vlan.py +++ b/show/vlan.py @@ -31,26 +31,25 @@ def brief(db, verbose): vlan_proxy_arp_dict = {} # Parsing DHCP Helpers info - for key in natsorted(vlan_dhcp_helper_data.keys()): + for key in natsorted(list(vlan_dhcp_helper_data.keys())): try: if vlan_dhcp_helper_data[key]['dhcp_servers']: - vlan_dhcp_helper_dict[str(key.strip('Vlan'))] = vlan_dhcp_helper_data[key]['dhcp_servers'] + vlan_dhcp_helper_dict[key.strip('Vlan')] = vlan_dhcp_helper_data[key]['dhcp_servers'] except KeyError: - vlan_dhcp_helper_dict[str(key.strip('Vlan'))] = " " + vlan_dhcp_helper_dict[key.strip('Vlan')] = " " # Parsing VLAN Gateway info - for key in natsorted(vlan_ip_data.keys()): - + for key in vlan_ip_data: if clicommon.is_ip_prefix_in_key(key): - interface_key = str(key[0].strip("Vlan")) - interface_value = str(key[1]) + interface_key = key[0].strip("Vlan") + interface_value = key[1] if interface_key in vlan_ip_dict: vlan_ip_dict[interface_key].append(interface_value) else: vlan_ip_dict[interface_key] = [interface_value] else: - interface_key = str(key.strip("Vlan")) + interface_key = key.strip("Vlan") if 'proxy_arp' in vlan_ip_data[key]: proxy_arp_status = vlan_ip_data[key]['proxy_arp'] else: @@ -63,9 +62,9 @@ def brief(db, verbose): iface_alias_converter = clicommon.InterfaceAliasConverter(db) # Parsing VLAN Ports info - for key in natsorted(vlan_ports_data.keys()): - ports_key = str(key[0].strip("Vlan")) - ports_value = str(key[1]) + for key in natsorted(list(vlan_ports_data.keys())): + ports_key = key[0].strip("Vlan") + ports_value = key[1] ports_tagging = vlan_ports_data[key]['tagging_mode'] if ports_key in vlan_ports_dict: if clicommon.get_interface_naming_mode() == "alias": @@ -83,7 +82,7 @@ def brief(db, verbose): # Printing the following dictionaries in tablular forms: # vlan_dhcp_helper_dict={}, vlan_ip_dict = {}, vlan_ports_dict = {} # vlan_tagging_dict = {} - for key in natsorted(vlan_dhcp_helper_dict.keys()): + for key in natsorted(list(vlan_dhcp_helper_dict.keys())): if key not in vlan_ip_dict: ip_address = "" else: @@ -119,24 +118,29 @@ def tablelize(keys, data): for (vlan, interface_name) in member_data: if vlan == k: members.add(interface_name) - - for m in members: + if members: + for m in natsorted(list(members)): + r = [] + r.append(k) + r.append(data[k]['vlanid']) + if clicommon.get_interface_naming_mode() == "alias": + alias = clicommon.InterfaceAliasConverter(db).name_to_alias(m) + r.append(alias) + else: + r.append(m) + + entry = db.cfgdb.get_entry('VLAN_MEMBER', (k, m)) + mode = entry.get('tagging_mode') + if mode is None: + r.append('?') + else: + r.append(mode) + + table.append(r) + else: r = [] r.append(k) r.append(data[k]['vlanid']) - if clicommon.get_interface_naming_mode() == "alias": - alias = clicommon.InterfaceAliasConverter(db).name_to_alias(m) - r.append(alias) - else: - r.append(m) - - entry = db.cfgdb.get_entry('VLAN_MEMBER', (k, m)) - mode = entry.get('tagging_mode') - if mode is None: - r.append('?') - else: - r.append(mode) - table.append(r) return table @@ -145,13 +149,12 @@ def tablelize(keys, data): click.echo(tabulate(tablelize(keys, data), header)) @vlan.command() -def count(): +@clicommon.pass_db +def count(db): """Show Vlan count""" - config_db = ConfigDBConnector() - config_db.connect() - # Fetching Vlan keys from config DB - vlan_keys = config_db.keys('CONFIG_DB', "VLAN|*") + data = db.cfgdb.get_table('VLAN') + vlan_keys = data.keys() if not vlan_keys: vlan_count = 0 From afc53212b70df28ebc72c99c247df5fd6a25d635 Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Thu, 3 Dec 2020 16:28:00 -0800 Subject: [PATCH 30/42] Update vlan.py --- show/vlan.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/show/vlan.py b/show/vlan.py index efb9615073..066ef7ee26 100644 --- a/show/vlan.py +++ b/show/vlan.py @@ -118,8 +118,26 @@ def tablelize(keys, data): for (vlan, interface_name) in member_data: if vlan == k: members.add(interface_name) - - for m in natsorted(list(members)): + if members: + for m in natsorted(list(members)): + r = [] + r.append(k) + r.append(data[k]['vlanid']) + if clicommon.get_interface_naming_mode() == "alias": + alias = clicommon.InterfaceAliasConverter(db).name_to_alias(m) + r.append(alias) + else: + r.append(m) + + entry = db.cfgdb.get_entry('VLAN_MEMBER', (k, m)) + mode = entry.get('tagging_mode') + if mode is None: + r.append('?') + else: + r.append(mode) + + table.append(r) + else: r = [] r.append(k) r.append(data[k]['vlanid']) From 82d8c88073b997ecc5a41f0ad45dee7e6255f269 Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Thu, 3 Dec 2020 16:34:43 -0800 Subject: [PATCH 31/42] Update fdbshow --- scripts/fdbshow | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/fdbshow b/scripts/fdbshow index e67e51fe55..1c525f2316 100755 --- a/scripts/fdbshow +++ b/scripts/fdbshow @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 """ Script to show MAC/FDB entries learnt in Hardware From 588db3750b01d30967fdf11dfe61c8202af0b79c Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Thu, 3 Dec 2020 16:48:33 -0800 Subject: [PATCH 32/42] Update vlan.py --- show/vlan.py | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/show/vlan.py b/show/vlan.py index 066ef7ee26..4c7d24f9c7 100644 --- a/show/vlan.py +++ b/show/vlan.py @@ -118,36 +118,31 @@ def tablelize(keys, data): for (vlan, interface_name) in member_data: if vlan == k: members.add(interface_name) - if members: - for m in natsorted(list(members)): - r = [] - r.append(k) - r.append(data[k]['vlanid']) - if clicommon.get_interface_naming_mode() == "alias": - alias = clicommon.InterfaceAliasConverter(db).name_to_alias(m) - r.append(alias) - else: - r.append(m) - - entry = db.cfgdb.get_entry('VLAN_MEMBER', (k, m)) - mode = entry.get('tagging_mode') - if mode is None: - r.append('?') - else: - r.append(mode) - - table.append(r) - else: + + for m in natsorted(list(members)): r = [] r.append(k) r.append(data[k]['vlanid']) + if clicommon.get_interface_naming_mode() == "alias": + alias = clicommon.InterfaceAliasConverter(db).name_to_alias(m) + r.append(alias) + else: + r.append(m) + + entry = db.cfgdb.get_entry('VLAN_MEMBER', (k, m)) + mode = entry.get('tagging_mode') + if mode is None: + r.append('?') + else: + r.append(mode) + table.append(r) return table header = ['Name', 'VID', 'Member', 'Mode'] click.echo(tabulate(tablelize(keys, data), header)) - + @vlan.command() @clicommon.pass_db def count(db): From 349c5a1d4ddd7209400d7334045991a11627e36c Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Sun, 6 Dec 2020 22:40:57 -0800 Subject: [PATCH 33/42] Update fdbshow --- scripts/fdbshow | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/scripts/fdbshow b/scripts/fdbshow index 1c525f2316..08fddd592a 100755 --- a/scripts/fdbshow +++ b/scripts/fdbshow @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/python3 """ Script to show MAC/FDB entries learnt in Hardware @@ -31,8 +31,8 @@ import json import sys from natsort import natsorted -from swsssdk import port_util -from swsscommon.swsscommon import SonicV2Connector +from swsssdk import SonicV2Connector, port_util +#from swsscommon.swsscommon import SonicV2Connector from tabulate import tabulate class FdbShow(object): @@ -75,8 +75,22 @@ class FdbShow(object): fdb = json.loads(fdb_entry .split(":", 2)[-1]) if not fdb: continue - - ent = self.db.get_all('ASIC_DB', s, blocking=True) + fdb_list.append(fdb) + pipe.hgetall(s) + values = pipe.execute() + client = self.db.get_redis_client(self.db.ASIC_DB) + pipe = client.pipeline() + vlans = [] + vlan_keys = self.db.keys('ASIC_DB', "ASIC_STATE:SAI_OBJECT_TYPE_VLAN:*") + for v in vlan_keys: + pipe.hgetall(v) + vlans = pipe.execute() + + posi = 0 + for ent in values: + if 'SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID' not in ent: + posi = posi + 1 + continue br_port_id = ent["SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID"][oid_pfx:] ent_type = ent["SAI_FDB_ENTRY_ATTR_TYPE"] fdb_type = ['Dynamic','Static'][ent_type == "SAI_FDB_ENTRY_TYPE_STATIC"] From 243c85a120d40347d828b690a8584ce1a19a892e Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Sun, 6 Dec 2020 23:06:52 -0800 Subject: [PATCH 34/42] Update fdbshow --- scripts/fdbshow | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/fdbshow b/scripts/fdbshow index 08fddd592a..3fcf9a40b8 100755 --- a/scripts/fdbshow +++ b/scripts/fdbshow @@ -103,7 +103,7 @@ class FdbShow(object): #FIXME: When if_name not mapped to port_id in DB, using port_id as if_name in the display. try: if_name = self.if_oid_map[port_id] - except: + except Exception as e: if_name = port_id #FIXME: When VLAN Id for fdb entry not present in DB, then not displaying the fdb entry. @@ -112,9 +112,10 @@ class FdbShow(object): elif 'bvid' in fdb: try: vlan_id = vlans[vlan_keys.index("ASIC_STATE:SAI_OBJECT_TYPE_VLAN:{}".format(fdb_list[posi][u'bvid']))] ["SAI_VLAN_ATTR_VLAN_ID"] - except: + except Exception as e: posi = posi + 1 continue + self.bridge_mac_list.append((int(vlan_id),) + (fdb_list[posi]["mac"],) + (if_name,) + (fdb_type,)) posi = posi + 1 From 36fa108421523e7e6322228ffa126316c930ac2a Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Mon, 7 Dec 2020 00:07:32 -0800 Subject: [PATCH 35/42] Update main.py --- show/main.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/show/main.py b/show/main.py index 6110c8389c..daf8560960 100755 --- a/show/main.py +++ b/show/main.py @@ -8,7 +8,6 @@ import utilities_common.cli as clicommon import utilities_common.multi_asic as multi_asic_util from natsort import natsorted -from pkg_resources import parse_version from sonic_py_common import device_info, multi_asic from swsssdk import ConfigDBConnector from swsscommon.swsscommon import SonicV2Connector @@ -637,20 +636,22 @@ def pwm_buffer_pool(): # 'mac' command ("show mac ...") # -@cli.group(invoke_without_command=True) -@click.pass_context +@cli.command() @click.option('-v', '--vlan') @click.option('-p', '--port') @click.option('--verbose', is_flag=True, help="Enable verbose output") -def mac(ctx, vlan, port, verbose): +def mac(vlan, port, verbose): """Show MAC (FDB) entries""" - if ctx.invoked_subcommand is None: - cmd = "fdbshow" - if vlan is not None: - cmd += " -v {}".format(vlan) - if port is not None: - cmd += " -p {}".format(port) - run_command(cmd, display_cmd=verbose) + + cmd = "fdbshow" + + if vlan is not None: + cmd += " -v {}".format(vlan) + + if port is not None: + cmd += " -p {}".format(port) + + run_command(cmd, display_cmd=verbose) @mac.command() def aging_time(): From 12e7482bab29fa8a7a6804c5affd4493e9ef4d6e Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Mon, 7 Dec 2020 00:32:06 -0800 Subject: [PATCH 36/42] Update main.py --- show/main.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/show/main.py b/show/main.py index daf8560960..765e0923a5 100755 --- a/show/main.py +++ b/show/main.py @@ -636,22 +636,20 @@ def pwm_buffer_pool(): # 'mac' command ("show mac ...") # -@cli.command() +@cli.group(invoke_without_command=True) +@click.pass_context @click.option('-v', '--vlan') @click.option('-p', '--port') @click.option('--verbose', is_flag=True, help="Enable verbose output") -def mac(vlan, port, verbose): +def mac(ctx, vlan, port, verbose): """Show MAC (FDB) entries""" - - cmd = "fdbshow" - - if vlan is not None: - cmd += " -v {}".format(vlan) - - if port is not None: - cmd += " -p {}".format(port) - - run_command(cmd, display_cmd=verbose) + if ctx.invoked_subcommand is None: + cmd = "fdbshow" + if vlan is not None: + cmd += " -v {}".format(vlan) + if port is not None: + cmd += " -p {}".format(port) + run_command(cmd, display_cmd=verbose) @mac.command() def aging_time(): From 65b1b18130ba9273e7cd6ea7a2eb1c277dcdb7a4 Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Mon, 7 Dec 2020 11:30:43 -0800 Subject: [PATCH 37/42] fixed LGTM issue --- show/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/show/main.py b/show/main.py index 765e0923a5..11b9c2f0a4 100755 --- a/show/main.py +++ b/show/main.py @@ -668,7 +668,6 @@ def aging_time(): age_time = switch_table[key]['fdb_aging_time'] except KeyError: age_time = '0' - pass output = 'Mac Aging-Time : ' output += ('%s seconds\n' % (str(age_time))) click.echo(output) From 2a9ab88ecec3a10cb68630be740cf2d5b809ebb2 Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Wed, 9 Dec 2020 00:56:19 -0800 Subject: [PATCH 38/42] added pytests --- config/main.py | 7 +++---- show/main.py | 8 ++++---- tests/fdb_test.py | 38 ++++++++++++++++++++++++++++++++++++++ tests/vlan_test.py | 38 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 8 deletions(-) create mode 100644 tests/fdb_test.py diff --git a/config/main.py b/config/main.py index 25b6c396cc..070dfb488e 100755 --- a/config/main.py +++ b/config/main.py @@ -1939,12 +1939,11 @@ def mac(ctx, redis_unix_socket_path): @mac.command('aging_time') @click.argument('interval', metavar='', required=True, type=int) -@click.pass_context -def set_aging_time(ctx, interval): - db = ctx.obj['db'] +@clicommon.pass_db +def set_aging_time(db, interval): if interval not in range(0,1000001): ctx.fail("Aging timer must be in range [0-1000000]") - db.set_entry('SWITCH', 'switch', {'fdb_aging_time': interval}) + db.cfgdb.set_entry('SWITCH', 'switch', {'fdb_aging_time': interval}) def mac_address_is_valid(mac): """Check if the mac address is valid diff --git a/show/main.py b/show/main.py index a762a1928c..e7bbcff003 100755 --- a/show/main.py +++ b/show/main.py @@ -653,13 +653,12 @@ def mac(ctx, vlan, port, verbose): run_command(cmd, display_cmd=verbose) @mac.command() -def aging_time(): +@clicommon.pass_db +def aging_time(db): """Show MAC Aging-Time""" - config_db = ConfigDBConnector() - config_db.connect() # Fetching data from config_db for SWITCH - switch_table = config_db.get_table('SWITCH') + switch_table = db.cfgdb.get_table('SWITCH') switch_keys = switch_table.keys() age_time = 0 @@ -669,6 +668,7 @@ def aging_time(): age_time = switch_table[key]['fdb_aging_time'] except KeyError: age_time = '0' + pass output = 'Mac Aging-Time : ' output += ('%s seconds\n' % (str(age_time))) click.echo(output) diff --git a/tests/fdb_test.py b/tests/fdb_test.py new file mode 100644 index 0000000000..f97f8f77af --- /dev/null +++ b/tests/fdb_test.py @@ -0,0 +1,38 @@ +import os +import traceback +from unittest import mock + +from click.testing import CliRunner + +import config.main as config +import show.main as show +from utilities_common.db import Db + +show_mac_aging_time="""\ +Mac Aging-Time : 300 seconds + +""" + +class TestFdb(object): + @classmethod + def setup_class(cls): + os.environ['UTILITIES_UNIT_TESTING'] = "1" + print("SETUP") + + def test_fdb_aging_time(self): + runner = CliRunner() + db = Db() + result = runner.invoke(config.config.commands["mac"].commands["aging_time"], ["300"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + result = runner.invoke(show.cli.commands["mac"].commands["aging-time"], [], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == show_mac_aging_time + + @classmethod + def teardown_class(cls): + os.environ['UTILITIES_UNIT_TESTING'] = "0" + print("TEARDOWN") diff --git a/tests/vlan_test.py b/tests/vlan_test.py index dedcbc7e23..20f180d745 100644 --- a/tests/vlan_test.py +++ b/tests/vlan_test.py @@ -79,6 +79,23 @@ Vlan2000 2000 Ethernet28 untagged """ +show_vlan_config_output_range="""\ +Name VID Member Mode +-------- ----- ---------- -------- +Vlan1000 1000 Ethernet4 untagged +Vlan1000 1000 Ethernet8 untagged +Vlan1000 1000 Ethernet12 untagged +Vlan1000 1000 Ethernet16 untagged +Vlan2000 2000 Ethernet24 untagged +Vlan2000 2000 Ethernet28 untagged +Vlan3001 3001 Ethernet4 tagged +Vlan3001 3001 Ethernet8 tagged +Vlan3002 3002 Ethernet4 tagged +Vlan3002 3002 Ethernet8 tagged +Vlan3003 3003 Ethernet4 tagged +Vlan3003 3003 Ethernet8 tagged +""" + show_vlan_config_in_alias_mode_output="""\ Name VID Member Mode -------- ----- -------- -------- @@ -519,6 +536,27 @@ def test_config_vlan_add_del_dhcp_relay_dest(self): print(result.output) assert result.output == show_vlan_brief_output + def test_vlan_config_range(self): + runner = CliRunner() + db = Db() + result = runner.invoke(config.config.commands["vlan"].commands["range"].commands["add"], ["3001", "3003"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + result = runner.invoke(config.config.commands["vlan"].commands["member"].commands["range"].commands["add"], ["3001", "3003", "Ethernet4"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + result = runner.invoke(config.config.commands["vlan"].commands["member"].commands["range"].commands["add"], ["3001", "3003", "Ethernet8"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + result = runner.invoke(show.cli.commands["vlan"].commands["config"], [], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == show_vlan_config_output_range + def test_config_vlan_remove_nonexist_dhcp_relay_dest(self): runner = CliRunner() From a8c651e6650bd69efcfd1e56695e125c702f25a9 Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Thu, 17 Dec 2020 15:57:58 -0800 Subject: [PATCH 39/42] added more tests for vlan range and fdb config commands added more tests for vlan range and fdb config commands --- config/main.py | 38 +++++++++++++++++--------------------- show/main.py | 22 ++++++++++++++++++++++ tests/fdb_test.py | 35 +++++++++++++++++++++++++++++++++++ tests/vlan_test.py | 13 +++++++++++++ 4 files changed, 87 insertions(+), 21 deletions(-) diff --git a/config/main.py b/config/main.py index 070dfb488e..608de75184 100755 --- a/config/main.py +++ b/config/main.py @@ -1954,60 +1954,56 @@ def mac_address_is_valid(mac): @click.argument('mac', metavar='', required=True) @click.argument('vlan', metavar='', required=True, type=int) @click.argument('interface_name', metavar='', required=True) -@click.pass_context -def add_mac(ctx, mac, vlan, interface_name): - db = ctx.obj['db'] - +@clicommon.pass_db +def add_mac(db, mac, vlan, interface_name): mac_valid = bool(mac_address_is_valid(mac)) if mac_valid == False: - ctx.fail("Incorrect mac-address format!!") + click.echo("Incorrect mac-address format!!") mac_valid = not bool(re.match('^' + '[\:\-]'.join(['([00]{2})']*6) + '$', mac.lower())) if mac_valid == False: - ctx.fail("Invalid (Zero) mac-address!!") + click.echo("Invalid (Zero) mac-address!!") mac_valid = not bool(re.match('^' + '[\:\-]'.join(['([ff]{2})']*6) + '$', mac.lower())) if mac_valid == False: - ctx.fail("Invalid (Bcast) mac-address!!") + click.echo("Invalid (Bcast) mac-address!!") mac_is_multicast = int(mac[:2]) & 1; if mac_is_multicast == True: - ctx.fail("Invalid (Multicast) mac-address!!") + click.echo("Invalid (Multicast) mac-address!!") vlan_valid = bool(vlan_id_is_valid(vlan)) if vlan_valid == False: - ctx.fail("Invalid VlanId!!") + click.echo("Invalid VlanId!!") vlan_name = 'Vlan{}'.format(vlan) if clicommon.get_interface_naming_mode() == "alias": - interface_name = interface_alias_to_name(db, interface_name) + interface_name = interface_alias_to_name(db.cfgdb, interface_name) if interface_name is None: - ctx.fail("'interface_name' is None!") + click.echo("'interface_name' is None!") - if interface_name_is_valid(db, interface_name) is False: - ctx.fail("Interface name is invalid!!") + if interface_name_is_valid(db.cfgdb, interface_name) is False: + click.echo("Interface name is invalid!!") - db.set_entry('FDB', (vlan_name, mac), {'port': interface_name }) + db.cfgdb.set_entry('FDB', (vlan_name, mac), {'port': interface_name }) @mac.command('del') @click.argument('mac', metavar='', required=True) @click.argument('vlan', metavar='', required=True, type=int) -@click.pass_context -def del_mac(ctx, mac, vlan): - db = ctx.obj['db'] - +@clicommon.pass_db +def del_mac(db, mac, vlan): mac_valid = bool(mac_address_is_valid(mac)) if mac_valid == False: - ctx.fail("Incorrect mac-address format!!") + click.echo("Incorrect mac-address format!!") vlan_valid = bool(vlan_id_is_valid(vlan)) if vlan_valid == False: - ctx.fail("Invalid VlanId!!") + click.echo("Invalid VlanId!!") vlan_name = 'Vlan{}'.format(vlan) - db.set_entry('FDB', (vlan_name, mac), None) + db.cfgdb.set_entry('FDB', (vlan_name, mac), None) # # 'bgp' group ('config bgp ...') diff --git a/show/main.py b/show/main.py index e7bbcff003..3e5d975989 100755 --- a/show/main.py +++ b/show/main.py @@ -691,6 +691,28 @@ def count(): output += ('%s \n' % (str(fdb_count))) click.echo(output) +@mac.command() +@clicommon.pass_db +def config(db): + data = db.cfgdb.get_table('FDB') + keys = list(data.keys()) + + def tablelize(keys, data): + table = [] + + for k in natsorted(keys): + entry = db.cfgdb.get_entry('FDB', k) + r = [] + r.append(k[0]) + r.append(k[1]) + r.append(data[k]['port']) + table.append(r) + + return table + + header = ['Vlan', 'MAC', 'Port'] + click.echo(tabulate(tablelize(keys, data), header)) + # # 'show route-map' command ("show route-map") # diff --git a/tests/fdb_test.py b/tests/fdb_test.py index f97f8f77af..5cc1223d31 100644 --- a/tests/fdb_test.py +++ b/tests/fdb_test.py @@ -13,6 +13,17 @@ """ +show_mac_config_add="""\ +Vlan MAC Port +------- ----------------- --------- +Vlan100 00:00:00:00:00:01 Ethernet4 +""" + +show_mac_config_del="""\ +Vlan MAC Port +------ ----- ------ +""" + class TestFdb(object): @classmethod def setup_class(cls): @@ -32,6 +43,30 @@ def test_fdb_aging_time(self): assert result.exit_code == 0 assert result.output == show_mac_aging_time + def test_fdb_mac_add(self): + runner = CliRunner() + db = Db() + result = runner.invoke(config.config.commands["vlan"].commands["add"], ["100"], obj=db) + result = runner.invoke(config.config.commands["vlan"].commands["member"].commands["add"], ["100", "Ethernet4"], obj=db) + result = runner.invoke(config.config.commands["mac"].commands["add"], ["00:00:00:00:00:01", "100", "Ethernet4"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + result = runner.invoke(show.cli.commands["mac"].commands["config"], [], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == show_mac_config_add + result = runner.invoke(config.config.commands["mac"].commands["del"], ["00:00:00:00:00:01", "100"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + result = runner.invoke(show.cli.commands["mac"].commands["config"], [], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == show_mac_config_del + @classmethod def teardown_class(cls): os.environ['UTILITIES_UNIT_TESTING'] = "0" diff --git a/tests/vlan_test.py b/tests/vlan_test.py index 20f180d745..7490340568 100644 --- a/tests/vlan_test.py +++ b/tests/vlan_test.py @@ -556,6 +556,19 @@ def test_vlan_config_range(self): print(result.output) assert result.exit_code == 0 assert result.output == show_vlan_config_output_range + result = runner.invoke(config.config.commands["vlan"].commands["member"].commands["range"].commands["del"], ["3001", "3003", "Ethernet4"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + result = runner.invoke(config.config.commands["vlan"].commands["member"].commands["range"].commands["del"], ["3001", "3003", "Ethernet8"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + result = runner.invoke(show.cli.commands["vlan"].commands["config"], [], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == show_vlan_config_output def test_config_vlan_remove_nonexist_dhcp_relay_dest(self): runner = CliRunner() From 280017119dcf848e1c3296ffbc21c08f3b99c107 Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Fri, 18 Dec 2020 15:18:40 -0800 Subject: [PATCH 40/42] fix lgtm --- show/main.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/show/main.py b/show/main.py index 3e5d975989..1a0a69ccd2 100755 --- a/show/main.py +++ b/show/main.py @@ -668,7 +668,6 @@ def aging_time(db): age_time = switch_table[key]['fdb_aging_time'] except KeyError: age_time = '0' - pass output = 'Mac Aging-Time : ' output += ('%s seconds\n' % (str(age_time))) click.echo(output) @@ -701,7 +700,6 @@ def tablelize(keys, data): table = [] for k in natsorted(keys): - entry = db.cfgdb.get_entry('FDB', k) r = [] r.append(k[0]) r.append(k[1]) From b037b7d7fd04cabd3e33a1e063f7d1c5d0cb6f26 Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Mon, 8 Nov 2021 16:16:35 -0800 Subject: [PATCH 41/42] fixed test failures --- config/vlan.py | 132 +++++++------------------------------ scripts/fdbshow | 75 +++++++++------------ tests/vlan_test.py | 160 ++++++++++----------------------------------- 3 files changed, 85 insertions(+), 282 deletions(-) diff --git a/config/vlan.py b/config/vlan.py index 78e77f6820..ddc2cdfc60 100644 --- a/config/vlan.py +++ b/config/vlan.py @@ -156,11 +156,6 @@ def add_vlan_member(db, vid, port, untagged): if (clicommon.interface_is_untagged_member(db.cfgdb, port) and untagged): ctx.fail("{} is already untagged member!".format(port)) - vlan_in_db = db.cfgdb.get_entry('VLAN', vlan) - members = vlan_in_db.get('members', []) - members.append(port) - vlan_in_db['members'] = members - db.cfgdb.set_entry('VLAN', vlan, vlan_in_db) db.cfgdb.set_entry('VLAN_MEMBER', (vlan, port), {'tagging_mode': "untagged" if untagged else "tagged" }) @vlan_member.command('del') @@ -191,91 +186,8 @@ def del_vlan_member(db, vid, port): if not clicommon.is_port_vlan_member(db.cfgdb, port, vlan): ctx.fail("{} is not a member of {}".format(port, vlan)) - vlan_in_db = db.cfgdb.get_entry('VLAN', vlan) - members = vlan_in_db.get('members', []) - vlan_in_db['members'] = members - members.remove(port) - if len(members) == 0: - del vlan_in_db['members'] - else: - vlan_in_db['members'] = members - db.cfgdb.set_entry('VLAN', vlan, vlan_in_db) db.cfgdb.set_entry('VLAN_MEMBER', (vlan, port), None) -@vlan.group(cls=clicommon.AbbreviationGroup, name='dhcp_relay') -def vlan_dhcp_relay(): - pass - -@vlan_dhcp_relay.command('add') -@click.argument('vid', metavar='', required=True, type=int) -@click.argument('dhcp_relay_destination_ip', metavar='', required=True) -@clicommon.pass_db -def add_vlan_dhcp_relay_destination(db, vid, dhcp_relay_destination_ip): - """ Add a destination IP address to the VLAN's DHCP relay """ - - ctx = click.get_current_context() - - if not clicommon.is_ipaddress(dhcp_relay_destination_ip): - ctx.fail('{} is invalid IP address'.format(dhcp_relay_destination_ip)) - - vlan_name = 'Vlan{}'.format(vid) - vlan = db.cfgdb.get_entry('VLAN', vlan_name) - if len(vlan) == 0: - ctx.fail("{} doesn't exist".format(vlan_name)) - - dhcp_relay_dests = vlan.get('dhcp_servers', []) - if dhcp_relay_destination_ip in dhcp_relay_dests: - click.echo("{} is already a DHCP relay destination for {}".format(dhcp_relay_destination_ip, vlan_name)) - return - - dhcp_relay_dests.append(dhcp_relay_destination_ip) - vlan['dhcp_servers'] = dhcp_relay_dests - db.cfgdb.set_entry('VLAN', vlan_name, vlan) - click.echo("Added DHCP relay destination address {} to {}".format(dhcp_relay_destination_ip, vlan_name)) - try: - click.echo("Restarting DHCP relay service...") - clicommon.run_command("systemctl stop dhcp_relay", display_cmd=False) - clicommon.run_command("systemctl reset-failed dhcp_relay", display_cmd=False) - clicommon.run_command("systemctl start dhcp_relay", display_cmd=False) - except SystemExit as e: - ctx.fail("Restart service dhcp_relay failed with error {}".format(e)) - -@vlan_dhcp_relay.command('del') -@click.argument('vid', metavar='', required=True, type=int) -@click.argument('dhcp_relay_destination_ip', metavar='', required=True) -@clicommon.pass_db -def del_vlan_dhcp_relay_destination(db, vid, dhcp_relay_destination_ip): - """ Remove a destination IP address from the VLAN's DHCP relay """ - - ctx = click.get_current_context() - - if not clicommon.is_ipaddress(dhcp_relay_destination_ip): - ctx.fail('{} is invalid IP address'.format(dhcp_relay_destination_ip)) - - vlan_name = 'Vlan{}'.format(vid) - vlan = db.cfgdb.get_entry('VLAN', vlan_name) - if len(vlan) == 0: - ctx.fail("{} doesn't exist".format(vlan_name)) - - dhcp_relay_dests = vlan.get('dhcp_servers', []) - if not dhcp_relay_destination_ip in dhcp_relay_dests: - ctx.fail("{} is not a DHCP relay destination for {}".format(dhcp_relay_destination_ip, vlan_name)) - - dhcp_relay_dests.remove(dhcp_relay_destination_ip) - if len(dhcp_relay_dests) == 0: - del vlan['dhcp_servers'] - else: - vlan['dhcp_servers'] = dhcp_relay_dests - db.cfgdb.set_entry('VLAN', vlan_name, vlan) - click.echo("Removed DHCP relay destination address {} from {}".format(dhcp_relay_destination_ip, vlan_name)) - try: - click.echo("Restarting DHCP relay service...") - clicommon.run_command("systemctl stop dhcp_relay", display_cmd=False) - clicommon.run_command("systemctl reset-failed dhcp_relay", display_cmd=False) - clicommon.run_command("systemctl start dhcp_relay", display_cmd=False) - except SystemExit as e: - ctx.fail("Restart service dhcp_relay failed with error {}".format(e)) - def vlan_id_is_valid(vid): """Check if the vlan id is in acceptable range (between 1 and 4094) """ @@ -329,6 +241,9 @@ def add_vlan_range(db, vid1, vid2, warning): vid2 = vid2+1 warning_vlans_list = [] + ctx = click.get_current_context() + ctx.obj = {'db': db.cfgdb} + curr_vlan_count = 0 clients = db.cfgdb.get_redis_client(db.cfgdb.CONFIG_DB) pipe = clients.pipeline() @@ -362,25 +277,27 @@ def del_vlan_range(db, vid1, vid2, warning): warning_vlans_list = [] warning_membership_list = [] warning_ip_list = [] + ctx = click.get_current_context() + ctx.obj = {'db': db.cfgdb} client = db.cfgdb.get_redis_client(db.cfgdb.CONFIG_DB) pipe = client.pipeline() - cur, vlan_member_keys = client.scan(cursor=0, match='*VLAN_MEMBER*', count=50) + cur, vlan_member_keys = client.scan(cursor=0, match='VLAN_MEMBER*', count=50) while cur != 0: - cur, keys = client.scan(cursor=cur, match='*VLAN_MEMBER*', count=50) + cur, keys = client.scan(cursor=cur, match='VLAN_MEMBER*', count=50) vlan_member_keys.extend(keys) - - cur, vlan_temp_member_keys = client.scan(cursor=0, match='*VLAN_MEMBER*', count=50) + + cur, vlan_temp_member_keys = client.scan(cursor=0, match='VLAN_MEMBER*', count=50) while cur != 0: - cur, keys = client.scan(cursor=cur, match='*VLAN_MEMBER*', count=50) + cur, keys = client.scan(cursor=cur, match='VLAN_MEMBER*', count=50) vlan_temp_member_keys.extend(keys) - cur, vlan_ip_keys = client.scan(cursor=0, match='*VLAN_INTERFACE*', count=50) + cur, vlan_ip_keys = client.scan(cursor=0, match='VLAN_INTERFACE*', count=50) while cur != 0: - cur, keys = client.scan(cursor=cur, match='*VLAN_INTERFACE*', count=50) + cur, keys = client.scan(cursor=cur, match='VLAN_INTERFACE*', count=50) vlan_ip_keys.extend(keys) - # Fetch the interfaces from config_db associated with *VLAN_MEMBER* + # Fetch the interfaces from config_db associated with VLAN_MEMBER* stored_intf_list = [] if vlan_temp_member_keys is not None: for x in range(len(vlan_temp_member_keys)): @@ -390,7 +307,7 @@ def del_vlan_range(db, vid1, vid2, warning): stored_intf_list = list(set(stored_intf_list)) list_length = len(stored_intf_list) - # Fetch VLAN participation list for each interface + # Fetch VLAN participation list for each interface vid = range(vid1, vid2) if vlan_temp_member_keys is not None and list_length != 0: for i in range(list_length): @@ -567,6 +484,7 @@ def add_vlan_member_range(db, vid1, vid2, interface_name, untagged, warning): if v == interface_name: ctx.fail(" {} is configured as a port channel member".format(interface_name)) + vlan_ports_data = db.cfgdb.get_table('VLAN_MEMBER') for vid in range(vid1, vid2): vlan_name = 'Vlan{}'.format(vid) vlan = db.cfgdb.get_entry('VLAN', vlan_name) @@ -576,8 +494,7 @@ def add_vlan_member_range(db, vid1, vid2, interface_name, untagged, warning): warning_vlans_list.append(vid) continue - members = vlan.get('members', []) - if interface_name in members: + if (vlan_name, interface_name) in vlan_ports_data.keys(): if warning is True: warning_membership_list.append(vid) if clicommon.get_interface_naming_mode() == "alias": @@ -588,11 +505,9 @@ def add_vlan_member_range(db, vid1, vid2, interface_name, untagged, warning): else: continue - members.append(interface_name) - vlan['members'] = members - pipe.hmset('VLAN|{}'.format(vlan_name), vlan_member_data(vlan)) pipe.hmset('VLAN_MEMBER|{}'.format(vlan_name+'|'+interface_name), {'tagging_mode': "untagged" if untagged else "tagged" }) # If port is being made L2 port, enable STP + ctx.obj = {'db': db.cfgdb} pipe.execute() # Log warning messages if 'warning' option is enabled if warning is True and len(warning_vlans_list) != 0: @@ -630,6 +545,7 @@ def del_vlan_member_range(db, vid1, vid2, interface_name, warning): clients = db.cfgdb.get_redis_client(db.cfgdb.CONFIG_DB) pipe = clients.pipeline() + vlan_ports_data = db.cfgdb.get_table('VLAN_MEMBER') for vid in range(vid1, vid2): vlan_name = 'Vlan{}'.format(vid) vlan = db.cfgdb.get_entry('VLAN', vlan_name) @@ -639,8 +555,7 @@ def del_vlan_member_range(db, vid1, vid2, interface_name, warning): warning_vlans_list.append(vid) continue - members = vlan.get('members', []) - if interface_name not in members: + if (vlan_name, interface_name) not in vlan_ports_data.keys(): if warning is True: warning_membership_list.append(vid) if clicommon.get_interface_naming_mode() == "alias": @@ -651,16 +566,13 @@ def del_vlan_member_range(db, vid1, vid2, interface_name, warning): else: continue - members.remove(interface_name) - if len(members) == 0: - pipe.hdel('VLAN|{}'.format(vlan_name), 'members@') - else: - vlan['members'] = members pipe.hmset('VLAN|{}'.format(vlan_name), vlan_member_data(vlan)) pipe.delete('VLAN_MEMBER|{}'.format(vlan_name+'|'+interface_name)) - pipe.delete('STP_VLAN_INTF|{}'.format(vlan_name + '|' + interface_name)) + pipe.delete('STP_VLAN_PORT|{}'.format(vlan_name + '|' + interface_name)) pipe.execute() + # If port is being made non-L2 port, disable STP on interface + ctx.obj = {'db': db.cfgdb} # Log warning messages if 'warning' option is enabled if warning is True and len(warning_vlans_list) != 0: logging.warning('Non-existent VLANs: {}'.format(get_hyphenated_string(warning_vlans_list))) diff --git a/scripts/fdbshow b/scripts/fdbshow index 68f72ee70a..9b83b07191 100755 --- a/scripts/fdbshow +++ b/scripts/fdbshow @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 """ Script to show MAC/FDB entries learnt in Hardware @@ -54,8 +54,8 @@ except KeyError: # pragma: no cover pass from natsort import natsorted -from swsssdk import SonicV2Connector, port_util -#from swsscommon.swsscommon import SonicV2Connector +from swsssdk import port_util +from swsscommon.swsscommon import SonicV2Connector from tabulate import tabulate class FdbShow(object): @@ -75,7 +75,7 @@ class FdbShow(object): def fetch_fdb_data(self): """ Fetch FDB entries from ASIC DB. - FDB entries are sorted on "VlanID" plus MAC addr, and stored as a list of tuples + FDB entries are sorted on "VlanID" and stored as a list of tuples """ self.db.connect(self.db.ASIC_DB) self.bridge_mac_list = [] @@ -89,61 +89,46 @@ class FdbShow(object): bvid_tlb = {} oid_pfx = len("oid:0x") - - client = self.db.get_redis_client(self.db.ASIC_DB) - pipe = client.pipeline() - values = [] - fdb_list = [] for s in fdb_str: fdb_entry = s fdb = json.loads(fdb_entry .split(":", 2)[-1]) if not fdb: continue - fdb_list.append(fdb) - pipe.hgetall(s) - values = pipe.execute() - client = self.db.get_redis_client(self.db.ASIC_DB) - pipe = client.pipeline() - vlans = [] - vlan_keys = self.db.keys('ASIC_DB', "ASIC_STATE:SAI_OBJECT_TYPE_VLAN:*") - for v in vlan_keys: - pipe.hgetall(v) - vlans = pipe.execute() - - posi = 0 - for ent in values: - if 'SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID' not in ent: - posi = posi + 1 - continue + + ent = self.db.get_all('ASIC_DB', s, blocking=True) br_port_id = ent["SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID"][oid_pfx:] ent_type = ent["SAI_FDB_ENTRY_ATTR_TYPE"] fdb_type = ['Dynamic','Static'][ent_type == "SAI_FDB_ENTRY_TYPE_STATIC"] - if (br_port_id not in self.if_br_oid_map): - posi = posi + 1 + if br_port_id not in self.if_br_oid_map: continue - port_id = self.if_br_oid_map[br_port_id] - - #FIXME: When if_name not mapped to port_id in DB, using port_id as if_name in the display. - try: + if port_id in self.if_oid_map: if_name = self.if_oid_map[port_id] - except Exception as e: + else: if_name = port_id - - #FIXME: When VLAN Id for fdb entry not present in DB, then not displaying the fdb entry. if 'vlan' in fdb: vlan_id = fdb["vlan"] - elif 'bvid' in fdb: - try: - vlan_id = vlans[vlan_keys.index("ASIC_STATE:SAI_OBJECT_TYPE_VLAN:{}".format(fdb_list[posi][u'bvid']))] ["SAI_VLAN_ATTR_VLAN_ID"] - except Exception as e: - posi = posi + 1 + else: + if 'bvid' not in fdb: + # no possibility to find the Vlan id. skip the FDB entry continue - - self.bridge_mac_list.append((int(vlan_id),) + (fdb_list[posi]["mac"],) + (if_name,) + (fdb_type,)) - posi = posi + 1 - - self.bridge_mac_list.sort(key = lambda x: (x[0], x[1])) + bvid = fdb["bvid"] + if bvid in bvid_tlb: + vlan_id = bvid_tlb[bvid] + else: + try: + vlan_id = port_util.get_vlan_id_from_bvid(self.db, bvid) + bvid_tlb[bvid] = vlan_id + if vlan_id is None: + # the situation could be faced if the system has an FDB entries, + # which are linked to default Vlan(caused by untagged traffic) + continue + except Exception: + vlan_id = bvid + print("Failed to get Vlan id for bvid {}\n".format(bvid)) + self.bridge_mac_list.append((int(vlan_id),) + (fdb["mac"],) + (if_name,) + (fdb_type,)) + + self.bridge_mac_list.sort(key = lambda x: x[0]) return @@ -180,7 +165,7 @@ class FdbShow(object): output.append([self.FDB_COUNT, fdb[0], fdb[1], fdb[2], fdb[3]]) print(tabulate(output, self.HEADER)) - print("Total number of entries {0} ".format(self.FDB_COUNT)) + print("Total number of entries {0}".format(self.FDB_COUNT)) def main(): diff --git a/tests/vlan_test.py b/tests/vlan_test.py index 99140e43c3..a861de79d5 100644 --- a/tests/vlan_test.py +++ b/tests/vlan_test.py @@ -91,20 +91,38 @@ """ show_vlan_config_output_range="""\ -Name VID Member Mode --------- ----- ---------- -------- -Vlan1000 1000 Ethernet4 untagged -Vlan1000 1000 Ethernet8 untagged -Vlan1000 1000 Ethernet12 untagged -Vlan1000 1000 Ethernet16 untagged -Vlan2000 2000 Ethernet24 untagged -Vlan2000 2000 Ethernet28 untagged -Vlan3001 3001 Ethernet4 tagged -Vlan3001 3001 Ethernet8 tagged -Vlan3002 3002 Ethernet4 tagged -Vlan3002 3002 Ethernet8 tagged -Vlan3003 3003 Ethernet4 tagged -Vlan3003 3003 Ethernet8 tagged +Name VID Member Mode +-------- ----- --------------- -------- +Vlan1000 1000 Ethernet4 untagged +Vlan1000 1000 Ethernet8 untagged +Vlan1000 1000 Ethernet12 untagged +Vlan1000 1000 Ethernet16 untagged +Vlan2000 2000 Ethernet24 untagged +Vlan2000 2000 Ethernet28 untagged +Vlan3000 3000 +Vlan3001 3001 Ethernet4 tagged +Vlan3001 3001 Ethernet8 tagged +Vlan3002 3002 Ethernet4 tagged +Vlan3002 3002 Ethernet8 tagged +Vlan3003 3003 Ethernet4 tagged +Vlan3003 3003 Ethernet8 tagged +Vlan4000 4000 PortChannel1001 tagged +""" + +show_vlan_config_output_range_after_del="""\ +Name VID Member Mode +-------- ----- --------------- -------- +Vlan1000 1000 Ethernet4 untagged +Vlan1000 1000 Ethernet8 untagged +Vlan1000 1000 Ethernet12 untagged +Vlan1000 1000 Ethernet16 untagged +Vlan2000 2000 Ethernet24 untagged +Vlan2000 2000 Ethernet28 untagged +Vlan3000 3000 +Vlan3001 3001 +Vlan3002 3002 +Vlan3003 3003 +Vlan4000 4000 PortChannel1001 tagged """ show_vlan_config_in_alias_mode_output="""\ @@ -477,92 +495,6 @@ def test_config_add_del_vlan_and_vlan_member_in_alias_mode(self): os.environ['SONIC_CLI_IFACE_MODE'] = "default" - def test_config_vlan_add_dhcp_relay_with_nonexist_vlanid(self): - runner = CliRunner() - - with mock.patch('utilities_common.cli.run_command') as mock_run_command: - result = runner.invoke(config.config.commands["vlan"].commands["dhcp_relay"].commands["add"], - ["1001", "192.0.0.100"]) - print(result.exit_code) - print(result.output) - # traceback.print_tb(result.exc_info[2]) - assert result.exit_code != 0 - assert "Error: Vlan1001 doesn't exist" in result.output - assert mock_run_command.call_count == 0 - - def test_config_vlan_add_dhcp_relay_with_invalid_vlanid(self): - runner = CliRunner() - - with mock.patch('utilities_common.cli.run_command') as mock_run_command: - result = runner.invoke(config.config.commands["vlan"].commands["dhcp_relay"].commands["add"], - ["4096", "192.0.0.100"]) - print(result.exit_code) - print(result.output) - # traceback.print_tb(result.exc_info[2]) - assert result.exit_code != 0 - assert "Error: Vlan4096 doesn't exist" in result.output - assert mock_run_command.call_count == 0 - - def test_config_vlan_add_dhcp_relay_with_invalid_ip(self): - runner = CliRunner() - - with mock.patch('utilities_common.cli.run_command') as mock_run_command: - result = runner.invoke(config.config.commands["vlan"].commands["dhcp_relay"].commands["add"], - ["1000", "192.0.0.1000"]) - print(result.exit_code) - print(result.output) - # traceback.print_tb(result.exc_info[2]) - assert result.exit_code != 0 - assert "Error: 192.0.0.1000 is invalid IP address" in result.output - assert mock_run_command.call_count == 0 - - def test_config_vlan_add_dhcp_relay_with_exist_ip(self): - runner = CliRunner() - - with mock.patch('utilities_common.cli.run_command') as mock_run_command: - result = runner.invoke(config.config.commands["vlan"].commands["dhcp_relay"].commands["add"], - ["1000", "192.0.0.1"]) - print(result.exit_code) - print(result.output) - # traceback.print_tb(result.exc_info[2]) - assert result.exit_code == 0 - assert "192.0.0.1 is already a DHCP relay destination for Vlan1000" in result.output - assert mock_run_command.call_count == 0 - - def test_config_vlan_add_del_dhcp_relay_dest(self): - runner = CliRunner() - db = Db() - - # add new relay dest - with mock.patch("utilities_common.cli.run_command") as mock_run_command: - result = runner.invoke(config.config.commands["vlan"].commands["dhcp_relay"].commands["add"], - ["1000", "192.0.0.100"], obj=db) - print(result.exit_code) - print(result.output) - assert result.exit_code == 0 - assert result.output == config_vlan_add_dhcp_relay_output - assert mock_run_command.call_count == 3 - - # show output - result = runner.invoke(show.cli.commands["vlan"].commands["brief"], [], obj=db) - print(result.output) - assert result.output == show_vlan_brief_output_with_new_dhcp_relay_address - - # del relay dest - with mock.patch("utilities_common.cli.run_command") as mock_run_command: - result = runner.invoke(config.config.commands["vlan"].commands["dhcp_relay"].commands["del"], - ["1000", "192.0.0.100"], obj=db) - print(result.exit_code) - print(result.output) - assert result.exit_code == 0 - assert result.output == config_vlan_del_dhcp_relay_output - assert mock_run_command.call_count == 3 - - # show output - result = runner.invoke(show.cli.commands["vlan"].commands["brief"], [], obj=db) - print(result.output) - assert result.output == show_vlan_brief_output - def test_vlan_config_range(self): runner = CliRunner() db = Db() @@ -595,33 +527,7 @@ def test_vlan_config_range(self): print(result.exit_code) print(result.output) assert result.exit_code == 0 - assert result.output == show_vlan_config_output - - def test_config_vlan_remove_nonexist_dhcp_relay_dest(self): - runner = CliRunner() - - with mock.patch('utilities_common.cli.run_command') as mock_run_command: - result = runner.invoke(config.config.commands["vlan"].commands["dhcp_relay"].commands["del"], - ["1000", "192.0.0.100"]) - print(result.exit_code) - print(result.output) - # traceback.print_tb(result.exc_info[2]) - assert result.exit_code != 0 - assert "Error: 192.0.0.100 is not a DHCP relay destination for Vlan1000" in result.output - assert mock_run_command.call_count == 0 - - def test_config_vlan_remove_dhcp_relay_dest_with_nonexist_vlanid(self): - runner = CliRunner() - - with mock.patch('utilities_common.cli.run_command') as mock_run_command: - result = runner.invoke(config.config.commands["vlan"].commands["dhcp_relay"].commands["del"], - ["1001", "192.0.0.1"]) - print(result.exit_code) - print(result.output) - # traceback.print_tb(result.exc_info[2]) - assert result.exit_code != 0 - assert "Error: Vlan1001 doesn't exist" in result.output - assert mock_run_command.call_count == 0 + assert result.output == show_vlan_config_output_range_after_del def test_config_vlan_proxy_arp_with_nonexist_vlan_intf_table(self): modes = ["enabled", "disabled"] From 3a28e0600fd276856aeb76f52eb4f3aa810429cd Mon Sep 17 00:00:00 2001 From: anilkpan <47642449+anilkpan@users.noreply.github.com> Date: Mon, 8 Nov 2021 16:46:31 -0800 Subject: [PATCH 42/42] Fix lgtm error --- config/vlan.py | 2 -- scripts/fast-reboot-dump.py | 7 ++++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/config/vlan.py b/config/vlan.py index ddc2cdfc60..d8355dbdcb 100644 --- a/config/vlan.py +++ b/config/vlan.py @@ -566,8 +566,6 @@ def del_vlan_member_range(db, vid1, vid2, interface_name, warning): else: continue - pipe.hmset('VLAN|{}'.format(vlan_name), vlan_member_data(vlan)) - pipe.delete('VLAN_MEMBER|{}'.format(vlan_name+'|'+interface_name)) pipe.delete('STP_VLAN_PORT|{}'.format(vlan_name + '|' + interface_name)) pipe.execute() diff --git a/scripts/fast-reboot-dump.py b/scripts/fast-reboot-dump.py index 50c4c1059a..92a2966282 100644 --- a/scripts/fast-reboot-dump.py +++ b/scripts/fast-reboot-dump.py @@ -198,10 +198,11 @@ def generate_fdb_entries_2(filename): all_available_macs = set() map_mac_ip_per_vlan = {} - db = swsssdk.SonicV2Connector(host='127.0.0.1') + db = SonicV2Connector(use_unix_socket_path=False) + app_db = SonicV2Connector(use_unix_socket_path=False) db.connect(db.ASIC_DB, False) # Make one attempt only - - bridge_id_2_iface = get_map_bridge_port_id_2_iface_name(db) + app_db.connect(app_db.APPL_DB, False) # Make one attempt only + bridge_id_2_iface = get_map_bridge_port_id_2_iface_name(db, app_db) vlan_ifaces = get_vlan_ifaces() for vlan in vlan_ifaces: