Skip to content

Commit f2c32ca

Browse files
Merge branch 'Azure:master' into storm_control
2 parents afe1122 + 288c2d8 commit f2c32ca

File tree

16 files changed

+668
-117
lines changed

16 files changed

+668
-117
lines changed

config/main.py

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -902,18 +902,36 @@ def interface_is_in_portchannel(portchannel_member_table, interface_name):
902902

903903
return False
904904

905-
def interface_has_mirror_config(mirror_table, interface_name):
906-
""" Check if port is already configured with mirror config """
907-
for _, v in mirror_table.items():
908-
if 'src_port' in v and v['src_port'] == interface_name:
905+
def check_mirror_direction_config(v, direction):
906+
""" Check if port is already configured for mirror in same direction """
907+
if direction:
908+
direction=direction.upper()
909+
if ('direction' in v and v['direction'] == 'BOTH') or (direction == 'BOTH'):
909910
return True
910-
if 'dst_port' in v and v['dst_port'] == interface_name:
911+
if 'direction' in v and v['direction'] == direction:
911912
return True
913+
else:
914+
return True
915+
916+
def interface_has_mirror_config(ctx, mirror_table, dst_port, src_port, direction):
917+
""" Check if dst/src port is already configured with mirroring in same direction """
918+
for _, v in mirror_table.items():
919+
if src_port:
920+
for port in src_port.split(","):
921+
if 'dst_port' in v and v['dst_port'] == port:
922+
ctx.fail("Error: Source Interface {} already has mirror config".format(port))
923+
if 'src_port' in v and re.search(port,v['src_port']):
924+
if check_mirror_direction_config(v, direction):
925+
ctx.fail("Error: Source Interface {} already has mirror config in same direction".format(port))
926+
if dst_port:
927+
if ('dst_port' in v and v['dst_port'] == dst_port) or ('src_port' in v and re.search(dst_port,v['src_port'])):
928+
ctx.fail("Error: Destination Interface {} already has mirror config".format(dst_port))
912929

913930
return False
914931

915932
def validate_mirror_session_config(config_db, session_name, dst_port, src_port, direction):
916933
""" Check if SPAN mirror-session config is valid """
934+
ctx = click.get_current_context()
917935
if len(config_db.get_entry('MIRROR_SESSION', session_name)) != 0:
918936
click.echo("Error: {} already exists".format(session_name))
919937
return False
@@ -924,41 +942,34 @@ def validate_mirror_session_config(config_db, session_name, dst_port, src_port,
924942

925943
if dst_port:
926944
if not interface_name_is_valid(config_db, dst_port):
927-
click.echo("Error: Destination Interface {} is invalid".format(dst_port))
928-
return False
945+
ctx.fail("Error: Destination Interface {} is invalid".format(dst_port))
946+
947+
if is_portchannel_present_in_db(config_db, dst_port):
948+
ctx.fail("Error: Destination Interface {} is not supported".format(dst_port))
929949

930950
if interface_is_in_vlan(vlan_member_table, dst_port):
931-
click.echo("Error: Destination Interface {} has vlan config".format(dst_port))
932-
return False
951+
ctx.fail("Error: Destination Interface {} has vlan config".format(dst_port))
933952

934-
if interface_has_mirror_config(mirror_table, dst_port):
935-
click.echo("Error: Destination Interface {} already has mirror config".format(dst_port))
936-
return False
937953

938954
if interface_is_in_portchannel(portchannel_member_table, dst_port):
939-
click.echo("Error: Destination Interface {} has portchannel config".format(dst_port))
940-
return False
955+
ctx.fail("Error: Destination Interface {} has portchannel config".format(dst_port))
941956

942957
if clicommon.is_port_router_interface(config_db, dst_port):
943-
click.echo("Error: Destination Interface {} is a L3 interface".format(dst_port))
944-
return False
958+
ctx.fail("Error: Destination Interface {} is a L3 interface".format(dst_port))
945959

946960
if src_port:
947961
for port in src_port.split(","):
948962
if not interface_name_is_valid(config_db, port):
949-
click.echo("Error: Source Interface {} is invalid".format(port))
950-
return False
963+
ctx.fail("Error: Source Interface {} is invalid".format(port))
951964
if dst_port and dst_port == port:
952-
click.echo("Error: Destination Interface cant be same as Source Interface")
953-
return False
954-
if interface_has_mirror_config(mirror_table, port):
955-
click.echo("Error: Source Interface {} already has mirror config".format(port))
956-
return False
965+
ctx.fail("Error: Destination Interface cant be same as Source Interface")
966+
967+
if interface_has_mirror_config(ctx, mirror_table, dst_port, src_port, direction):
968+
return False
957969

958970
if direction:
959971
if direction not in ['rx', 'tx', 'both']:
960-
click.echo("Error: Direction {} is invalid".format(direction))
961-
return False
972+
ctx.fail("Error: Direction {} is invalid".format(direction))
962973

963974
return True
964975

@@ -2159,7 +2170,7 @@ def add_span(session_name, dst_port, src_port, direction, queue, policer):
21592170
dst_port = interface_alias_to_name(None, dst_port)
21602171
if dst_port is None:
21612172
click.echo("Error: Destination Interface {} is invalid".format(dst_port))
2162-
return
2173+
return False
21632174

21642175
session_info = {
21652176
"type" : "SPAN",

doc/Command-Reference.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5281,8 +5281,11 @@ If vrf-name is also provided as part of the command, if the vrf is created it wi
52815281
default Vlan20
52825282
Vrf-red Vlan100
52835283
Loopback11
5284+
Eth0.100
52845285
Vrf-blue Loopback100
52855286
Loopback102
5287+
Ethernet0.10
5288+
PortChannel101
52865289
````
52875290
52885291
### VRF config commands

scripts/fast-reboot

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,26 @@ for service in ${SERVICES_TO_STOP}; do
738738
fi
739739
done
740740
741+
# Kill other containers to make the reboot faster
742+
# We call `docker kill ...` to ensure the container stops as quickly as possible,
743+
# then immediately call `systemctl stop ...` to prevent the service from
744+
# restarting the container automatically.
745+
debug "Stopping all remaining containers ..."
746+
if test -f /usr/local/bin/ctrmgr_tools.py
747+
then
748+
/usr/local/bin/ctrmgr_tools.py kill-all
749+
else
750+
for CONTAINER_NAME in $(docker ps --format '{{.Names}}'); do
751+
CONTAINER_STOP_RC=0
752+
docker kill $CONTAINER_NAME &> /dev/null || CONTAINER_STOP_RC=$?
753+
systemctl stop $CONTAINER_NAME || debug "Ignore stopping $CONTAINER_NAME error $?"
754+
if [[ CONTAINER_STOP_RC -ne 0 ]]; then
755+
debug "Failed killing container $CONTAINER_NAME RC $CONTAINER_STOP_RC ."
756+
fi
757+
done
758+
fi
759+
debug "Stopped all remaining containers ..."
760+
741761
# Stop the docker container engine. Otherwise we will have a broken docker storage
742762
systemctl stop docker.service || debug "Ignore stopping docker service error $?"
743763

scripts/intfutil

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ PORT_OPTICS_TYPE = "type"
4545
PORT_PFC_ASYM_STATUS = "pfc_asym"
4646
PORT_AUTONEG = 'autoneg'
4747
PORT_ADV_SPEEDS = 'adv_speeds'
48+
PORT_RMT_ADV_SPEEDS = 'rmt_adv_speeds'
4849
PORT_INTERFACE_TYPE = 'interface_type'
4950
PORT_ADV_INTERFACE_TYPES = 'adv_interface_types'
5051
PORT_TPID = "tpid"
@@ -140,8 +141,12 @@ def port_speed_parse(in_speed, optics_type):
140141
speed = int(in_speed)
141142
if optics_type == OPTICS_TYPE_RJ45 and speed <= 1000:
142143
out_speed = '{}M'.format(speed)
144+
elif speed < 1000:
145+
out_speed = '{}M'.format(speed)
146+
elif speed % 1000 >= 100:
147+
out_speed = '{:.1f}G'.format(speed / 1000)
143148
else:
144-
out_speed = '{}G'.format(int(speed/1000))
149+
out_speed = '{:.0f}G'.format(speed / 1000)
145150

146151
return out_speed
147152

@@ -165,6 +170,23 @@ def appl_db_port_status_get(appl_db, intf_name, status_type):
165170
status = ','.join(new_speed_list)
166171
return status
167172

173+
def state_db_port_status_get(db, intf_name, field):
174+
"""
175+
Get the port status
176+
"""
177+
full_table_id = PORT_STATE_TABLE_PREFIX + intf_name
178+
status = db.get(db.STATE_DB, full_table_id, field)
179+
if not status:
180+
return "N/A"
181+
if field in [PORT_RMT_ADV_SPEEDS] and status not in ["N/A", "all"]:
182+
optics_type = state_db_port_optics_get(db, intf_name, PORT_OPTICS_TYPE)
183+
speed_list = status.split(',')
184+
new_speed_list = []
185+
for s in natsorted(speed_list):
186+
new_speed_list.append(port_speed_parse(s, optics_type))
187+
status = ','.join(new_speed_list)
188+
return status
189+
168190
def port_oper_speed_get(db, intf_name):
169191
"""
170192
Get port oper speed
@@ -566,7 +588,7 @@ class IntfDescription(object):
566588

567589

568590
# ========================== interface-autoneg logic ==========================
569-
header_autoneg = ['Interface', 'Auto-Neg Mode', 'Speed', 'Adv Speeds', 'Type', 'Adv Types', 'Oper', 'Admin']
591+
header_autoneg = ['Interface', 'Auto-Neg Mode', 'Speed', 'Adv Speeds', 'Rmt Adv Speeds', 'Type', 'Adv Types', 'Oper', 'Admin']
570592

571593

572594
class IntfAutoNegStatus(object):
@@ -616,6 +638,7 @@ class IntfAutoNegStatus(object):
616638
autoneg_mode,
617639
port_oper_speed_get(self.db, key),
618640
appl_db_port_status_get(self.db, key, PORT_ADV_SPEEDS),
641+
state_db_port_status_get(self.db, key, PORT_RMT_ADV_SPEEDS),
619642
appl_db_port_status_get(self.db, key, PORT_INTERFACE_TYPE),
620643
appl_db_port_status_get(self.db, key, PORT_ADV_INTERFACE_TYPES),
621644
appl_db_port_status_get(self.db, key, PORT_OPER_STATUS),

sfputil/main.py

Lines changed: 102 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,48 @@
6363
'application_advertisement': 'Application Advertisement'
6464
}
6565

66+
QSFP_DD_DATA_MAP = {
67+
'model': 'Vendor PN',
68+
'vendor_oui': 'Vendor OUI',
69+
'vendor_date': 'Vendor Date Code(YYYY-MM-DD Lot)',
70+
'manufacturer': 'Vendor Name',
71+
'vendor_rev': 'Vendor Rev',
72+
'serial': 'Vendor SN',
73+
'type': 'Identifier',
74+
'ext_identifier': 'Extended Identifier',
75+
'ext_rateselect_compliance': 'Extended RateSelect Compliance',
76+
'cable_length': 'cable_length',
77+
'cable_type': 'Length',
78+
'nominal_bit_rate': 'Nominal Bit Rate(100Mbs)',
79+
'specification_compliance': 'Specification compliance',
80+
'encoding': 'Encoding',
81+
'connector': 'Connector',
82+
'application_advertisement': 'Application Advertisement',
83+
'active_firmware': 'Active Firmware Version',
84+
'inactive_firmware': 'Inactive Firmware Version',
85+
'hardware_rev': 'Hardware Revision',
86+
'media_interface_code': 'Media Interface Code',
87+
'host_electrical_interface': 'Host Electrical Interface',
88+
'host_lane_count': 'Host Lane Count',
89+
'media_lane_count': 'Media Lane Count',
90+
'host_lane_assignment_option': 'Host Lane Assignment Options',
91+
'media_lane_assignment_option': 'Media Lane Assignment Options',
92+
'active_apsel_hostlane1': 'Active App Selection Host Lane 1',
93+
'active_apsel_hostlane2': 'Active App Selection Host Lane 2',
94+
'active_apsel_hostlane3': 'Active App Selection Host Lane 3',
95+
'active_apsel_hostlane4': 'Active App Selection Host Lane 4',
96+
'active_apsel_hostlane5': 'Active App Selection Host Lane 5',
97+
'active_apsel_hostlane6': 'Active App Selection Host Lane 6',
98+
'active_apsel_hostlane7': 'Active App Selection Host Lane 7',
99+
'active_apsel_hostlane8': 'Active App Selection Host Lane 8',
100+
'media_interface_technology': 'Media Interface Technology',
101+
'cmis_rev': 'CMIS Revision',
102+
'supported_max_tx_power': 'Supported Max TX Power',
103+
'supported_min_tx_power': 'Supported Min TX Power',
104+
'supported_max_laser_freq': 'Supported Max Laser Frequency',
105+
'supported_min_laser_freq': 'Supported Min Laser Frequency'
106+
}
107+
66108
SFP_DOM_CHANNEL_MONITOR_MAP = {
67109
'rx1power': 'RXPower',
68110
'tx1bias': 'TXBias',
@@ -273,31 +315,68 @@ def format_dict_value_to_string(sorted_key_table,
273315
def convert_sfp_info_to_output_string(sfp_info_dict):
274316
indent = ' ' * 8
275317
output = ''
276-
277-
sorted_qsfp_data_map_keys = sorted(QSFP_DATA_MAP, key=QSFP_DATA_MAP.get)
278-
for key in sorted_qsfp_data_map_keys:
279-
if key == 'cable_type':
280-
output += '{}{}: {}\n'.format(indent, sfp_info_dict['cable_type'], sfp_info_dict['cable_length'])
281-
elif key == 'cable_length':
282-
pass
283-
elif key == 'specification_compliance':
284-
if sfp_info_dict['type'] == "QSFP-DD Double Density 8X Pluggable Transceiver" or \
285-
sfp_info_dict['type'] == "OSFP 8X Pluggable Transceiver" or \
286-
sfp_info_dict['type'] == "QSFP+ or later with CMIS":
287-
output += '{}{}: {}\n'.format(indent, QSFP_DATA_MAP[key], sfp_info_dict[key])
318+
sfp_type = sfp_info_dict['type']
319+
# CMIS supported module types include QSFP-DD and OSFP
320+
if sfp_type.startswith('QSFP-DD') or sfp_type.startswith('OSFP'):
321+
sorted_qsfp_data_map_keys = sorted(QSFP_DD_DATA_MAP, key=QSFP_DD_DATA_MAP.get)
322+
for key in sorted_qsfp_data_map_keys:
323+
if key == 'cable_type':
324+
output += '{}{}: {}\n'.format(indent, sfp_info_dict['cable_type'], sfp_info_dict['cable_length'])
325+
elif key == 'cable_length':
326+
pass
327+
elif key == 'specification_compliance':
328+
if sfp_info_dict['type'] == "QSFP-DD Double Density 8X Pluggable Transceiver" or \
329+
sfp_info_dict['type'] == "OSFP 8X Pluggable Transceiver" or \
330+
sfp_info_dict['type'] == "QSFP+ or later with CMIS":
331+
output += '{}{}: {}\n'.format(indent, QSFP_DD_DATA_MAP[key], sfp_info_dict[key])
332+
else:
333+
output += '{}{}:\n'.format(indent, QSFP_DD_DATA_MAP['specification_compliance'])
334+
335+
spec_compliance_dict = {}
336+
try:
337+
spec_compliance_dict = ast.literal_eval(sfp_info_dict['specification_compliance'])
338+
sorted_compliance_key_table = natsorted(spec_compliance_dict)
339+
for compliance_key in sorted_compliance_key_table:
340+
output += '{}{}: {}\n'.format((indent * 2), compliance_key, spec_compliance_dict[compliance_key])
341+
except ValueError as e:
342+
output += '{}N/A\n'.format((indent * 2))
343+
elif key == 'application_advertisement':
344+
pass
345+
elif key == 'supported_max_tx_power' or key == 'supported_min_tx_power':
346+
output += '{}{}: {}dBm\n'.format(indent, QSFP_DD_DATA_MAP[key], sfp_info_dict[key])
347+
elif key == 'supported_max_laser_freq' or key == 'supported_min_laser_freq':
348+
output += '{}{}: {}GHz\n'.format(indent, QSFP_DD_DATA_MAP[key], sfp_info_dict[key])
288349
else:
289-
output += '{}{}:\n'.format(indent, QSFP_DATA_MAP['specification_compliance'])
290-
291-
spec_compliance_dict = {}
292350
try:
293-
spec_compliance_dict = ast.literal_eval(sfp_info_dict['specification_compliance'])
294-
sorted_compliance_key_table = natsorted(spec_compliance_dict)
295-
for compliance_key in sorted_compliance_key_table:
296-
output += '{}{}: {}\n'.format((indent * 2), compliance_key, spec_compliance_dict[compliance_key])
297-
except ValueError as e:
298-
output += '{}N/A\n'.format((indent * 2))
299-
else:
300-
output += '{}{}: {}\n'.format(indent, QSFP_DATA_MAP[key], sfp_info_dict[key])
351+
output += '{}{}: {}\n'.format(indent, QSFP_DD_DATA_MAP[key], sfp_info_dict[key])
352+
except (KeyError, ValueError) as e:
353+
output += '{}{}: N/A\n'.format(indent, QSFP_DD_DATA_MAP[key])
354+
355+
else:
356+
sorted_qsfp_data_map_keys = sorted(QSFP_DATA_MAP, key=QSFP_DATA_MAP.get)
357+
for key in sorted_qsfp_data_map_keys:
358+
if key == 'cable_type':
359+
output += '{}{}: {}\n'.format(indent, sfp_info_dict['cable_type'], sfp_info_dict['cable_length'])
360+
elif key == 'cable_length':
361+
pass
362+
elif key == 'specification_compliance':
363+
if sfp_info_dict['type'] == "QSFP-DD Double Density 8X Pluggable Transceiver" or \
364+
sfp_info_dict['type'] == "OSFP 8X Pluggable Transceiver" or \
365+
sfp_info_dict['type'] == "QSFP+ or later with CMIS":
366+
output += '{}{}: {}\n'.format(indent, QSFP_DATA_MAP[key], sfp_info_dict[key])
367+
else:
368+
output += '{}{}:\n'.format(indent, QSFP_DATA_MAP['specification_compliance'])
369+
370+
spec_compliance_dict = {}
371+
try:
372+
spec_compliance_dict = ast.literal_eval(sfp_info_dict['specification_compliance'])
373+
sorted_compliance_key_table = natsorted(spec_compliance_dict)
374+
for compliance_key in sorted_compliance_key_table:
375+
output += '{}{}: {}\n'.format((indent * 2), compliance_key, spec_compliance_dict[compliance_key])
376+
except ValueError as e:
377+
output += '{}N/A\n'.format((indent * 2))
378+
else:
379+
output += '{}{}: {}\n'.format(indent, QSFP_DATA_MAP[key], sfp_info_dict[key])
301380

302381
return output
303382

show/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ def cli(ctx):
293293
def get_interface_bind_to_vrf(config_db, vrf_name):
294294
"""Get interfaces belong to vrf
295295
"""
296-
tables = ['INTERFACE', 'PORTCHANNEL_INTERFACE', 'VLAN_INTERFACE', 'LOOPBACK_INTERFACE']
296+
tables = ['INTERFACE', 'PORTCHANNEL_INTERFACE', 'VLAN_INTERFACE', 'LOOPBACK_INTERFACE', 'VLAN_SUB_INTERFACE']
297297
data = []
298298
for table_name in tables:
299299
interface_dict = config_db.get_table(table_name)

0 commit comments

Comments
 (0)