1
1
#!/usr/bin/env python3
2
+ import os
2
3
import click
3
- from swsscommon .swsscommon import ConfigDBConnector
4
+ import json
5
+ from sonic_py_common import multi_asic
4
6
from tabulate import tabulate
5
7
from natsort import natsorted
8
+ from utilities_common import multi_asic as multi_asic_util
6
9
10
+ # Constants
7
11
ALL_PRIORITIES = [str (x ) for x in range (8 )]
8
12
PRIORITY_STATUS = ['on' , 'off' ]
13
+ PORT_TABLE_NAME = "PORT"
14
+ PORT_QOS_MAP_TABLE_NAME = "PORT_QOS_MAP"
9
15
10
16
11
17
class Pfc (object ):
12
- def __init__ (self , cfgdb = None ):
13
- self .cfgdb = cfgdb
18
+ def __init__ (self , namespace = None ):
19
+ self .multi_asic = multi_asic_util .MultiAsic (namespace_option = namespace )
20
+ self .config_db = None
14
21
22
+ # For unit testing
23
+ self .updated_port_tables = {}
24
+ self .test_filename = '/tmp/pfc_testdata.json'
25
+
26
+ def dump_config_to_json (self , table_name , namespace ):
27
+ """
28
+ This function dumps the current config in a JSON file for unit testing.
29
+ """
30
+ # Only dump files in unit testing mode
31
+ if os .environ ["UTILITIES_UNIT_TESTING" ] != "2" :
32
+ return
33
+
34
+ if namespace not in self .updated_port_tables .keys ():
35
+ self .updated_port_tables [namespace ] = {}
36
+
37
+ self .updated_port_tables [namespace ][table_name ] = self .config_db .get_table (table_name )
38
+ with open (self .test_filename , "w" ) as fd :
39
+ json .dump (self .updated_port_tables , fd )
40
+
41
+ @multi_asic_util .run_on_multi_asic
15
42
def configPfcAsym (self , interface , pfc_asym ):
16
43
"""
17
44
PFC handler to configure asymmetric PFC.
18
45
"""
19
- configdb = ConfigDBConnector () if self .cfgdb is None else self .cfgdb
20
- configdb .connect ()
21
-
22
- configdb .mod_entry ("PORT" , interface , {'pfc_asym' : pfc_asym })
46
+ self .config_db .mod_entry (PORT_TABLE_NAME , interface , {'pfc_asym' : pfc_asym })
47
+ self .dump_config_to_json (PORT_TABLE_NAME , self .multi_asic .current_namespace )
23
48
49
+ @multi_asic_util .run_on_multi_asic
24
50
def showPfcAsym (self , interface ):
25
51
"""
26
52
PFC handler to display asymmetric PFC information.
27
53
"""
54
+ namespace_str = f"Namespace { self .multi_asic .current_namespace } " if multi_asic .is_multi_asic () else ''
28
55
header = ('Interface' , 'Asymmetric' )
29
56
30
- configdb = ConfigDBConnector () if self .cfgdb is None else self .cfgdb
31
- configdb .connect ()
32
-
33
57
if interface :
34
- db_keys = configdb . keys (configdb .CONFIG_DB , 'PORT|{0}' .format (interface ))
58
+ db_keys = self . config_db . keys (self . config_db .CONFIG_DB , 'PORT|{0}' .format (interface ))
35
59
else :
36
- db_keys = configdb . keys (configdb .CONFIG_DB , 'PORT|*' )
60
+ db_keys = self . config_db . keys (self . config_db .CONFIG_DB , 'PORT|*' )
37
61
38
62
table = []
39
63
@@ -43,36 +67,35 @@ def showPfcAsym(self, interface):
43
67
key = i .split ('|' )[- 1 ]
44
68
45
69
if key and key .startswith ('Ethernet' ):
46
- entry = configdb . get_entry ('PORT' , key )
70
+ entry = self . config_db . get_entry (PORT_TABLE_NAME , key )
47
71
table .append ([key , entry .get ('pfc_asym' , 'N/A' )])
48
72
49
73
sorted_table = natsorted (table )
50
74
51
- click .echo ()
75
+ click .echo (namespace_str )
52
76
click .echo (tabulate (sorted_table , headers = header , tablefmt = "simple" , missingval = "" ))
53
77
click .echo ()
54
78
79
+ @multi_asic_util .run_on_multi_asic
55
80
def configPfcPrio (self , status , interface , priority ):
56
- configdb = ConfigDBConnector () if self .cfgdb is None else self .cfgdb
57
- configdb .connect ()
58
-
59
- if interface not in configdb .get_keys ('PORT_QOS_MAP' ):
81
+ if interface not in self .config_db .get_keys (PORT_QOS_MAP_TABLE_NAME ):
60
82
click .echo ('Cannot find interface {0}' .format (interface ))
61
83
return
62
84
63
85
"""Current lossless priorities on the interface"""
64
- entry = configdb .get_entry ('PORT_QOS_MAP' , interface )
86
+ entry = self . config_db .get_entry ('PORT_QOS_MAP' , interface )
65
87
enable_prio = entry .get ('pfc_enable' ).split (',' )
66
88
67
89
"""Avoid '' in enable_prio"""
68
90
enable_prio = [x .strip () for x in enable_prio if x .strip ()]
69
91
92
+ namespace_str = f" for namespace { self .multi_asic .current_namespace } " if multi_asic .is_multi_asic () else ''
70
93
if status == 'on' and priority in enable_prio :
71
- click .echo ('Priority {0} has already been enabled on {1}' .format (priority , interface ))
94
+ click .echo ('Priority {0} has already been enabled on {1}{2} ' .format (priority , interface , namespace_str ))
72
95
return
73
96
74
97
if status == 'off' and priority not in enable_prio :
75
- click .echo ('Priority {0} is not enabled on {1}' .format (priority , interface ))
98
+ click .echo ('Priority {0} is not enabled on {1}{2} ' .format (priority , interface , namespace_str ))
76
99
return
77
100
78
101
if status == 'on' :
@@ -82,92 +105,93 @@ def configPfcPrio(self, status, interface, priority):
82
105
enable_prio .remove (priority )
83
106
84
107
enable_prio .sort ()
85
- configdb .mod_entry ("PORT_QOS_MAP" , interface , {'pfc_enable' : ',' .join (enable_prio )})
108
+ self .config_db .mod_entry (PORT_QOS_MAP_TABLE_NAME , interface , {'pfc_enable' : ',' .join (enable_prio )})
109
+ self .dump_config_to_json (PORT_QOS_MAP_TABLE_NAME , self .multi_asic .current_namespace )
86
110
87
- """Show the latest PFC configuration"""
88
- self .showPfcPrio (interface )
89
-
111
+ @multi_asic_util .run_on_multi_asic
90
112
def showPfcPrio (self , interface ):
91
113
"""
92
114
PFC handler to display PFC enabled priority information.
93
115
"""
94
116
header = ('Interface' , 'Lossless priorities' )
95
117
table = []
96
118
97
- configdb = ConfigDBConnector () if self .cfgdb is None else self .cfgdb
98
- configdb .connect ()
99
-
100
119
"""Get all the interfaces with QoS map information"""
101
- intfs = configdb .get_keys ('PORT_QOS_MAP' )
120
+ intfs = self . config_db .get_keys ('PORT_QOS_MAP' )
102
121
103
122
"""The user specifies an interface but we cannot find it"""
123
+ namespace_str = f"Namespace { self .multi_asic .current_namespace } " if multi_asic .is_multi_asic () else ''
104
124
if interface and interface not in intfs :
105
- click .echo ('Cannot find interface {0}' .format (interface ))
125
+ if multi_asic .is_multi_asic ():
126
+ click .echo ('Cannot find interface {0} for {1}' .format (interface , namespace_str ))
127
+ else :
128
+ click .echo ('Cannot find interface {0}' .format (interface ))
106
129
return
107
130
108
131
if interface :
109
132
intfs = [interface ]
110
133
111
134
for intf in intfs :
112
- entry = configdb .get_entry ('PORT_QOS_MAP' , intf )
135
+ entry = self . config_db .get_entry ('PORT_QOS_MAP' , intf )
113
136
table .append ([intf , entry .get ('pfc_enable' , 'N/A' )])
114
137
115
138
sorted_table = natsorted (table )
116
- click .echo ()
139
+ click .echo (namespace_str )
117
140
click .echo (tabulate (sorted_table , headers = header , tablefmt = "simple" , missingval = "" ))
118
141
click .echo ()
119
-
142
+
143
+
120
144
@click .group ()
121
- @click .pass_context
122
- def cli (ctx ):
145
+ def cli ():
123
146
"""PFC Command Line"""
124
- # Use the cfgdb object if given as input.
125
- cfgdb = None if ctx .obj is None else ctx .obj .cfgdb
126
147
127
- ctx .obj = {'pfc' : Pfc (cfgdb )}
128
148
129
149
@cli .group ()
130
- @click .pass_context
131
- def config (ctx ):
150
+ def config ():
132
151
"""Config PFC"""
133
152
pass
134
153
154
+
135
155
@cli .group ()
136
- @click .pass_context
137
- def show (ctx ):
156
+ def show ():
138
157
"""Show PFC information"""
139
158
pass
140
159
160
+
141
161
@click .command ()
142
162
@click .argument ('status' , type = click .Choice (PRIORITY_STATUS ))
143
163
@click .argument ('interface' , type = click .STRING )
144
- @click . pass_context
145
- def configAsym (ctx , status , interface ):
164
+ @multi_asic_util . multi_asic_click_option_namespace
165
+ def configAsym (status , interface , namespace ):
146
166
"""Configure asymmetric PFC on a given port."""
147
- ctx .obj ['pfc' ].configPfcAsym (interface , status )
167
+ Pfc (namespace ).configPfcAsym (interface , status )
168
+
148
169
149
170
@click .command ()
150
171
@click .argument ('status' , type = click .Choice (PRIORITY_STATUS ))
151
172
@click .argument ('interface' , type = click .STRING )
152
173
@click .argument ('priority' , type = click .Choice (ALL_PRIORITIES ))
153
- @click . pass_context
154
- def configPrio (ctx , status , interface , priority ):
174
+ @multi_asic_util . multi_asic_click_option_namespace
175
+ def configPrio (status , interface , priority , namespace ):
155
176
"""Configure PFC on a given priority."""
156
- ctx .obj ['pfc' ].configPfcPrio (status , interface , priority )
177
+ Pfc (namespace ).configPfcPrio (status , interface , priority )
178
+
157
179
158
180
@click .command ()
159
181
@click .argument ('interface' , type = click .STRING , required = False )
160
- @click . pass_context
161
- def showAsym (ctx , interface ):
182
+ @multi_asic_util . multi_asic_click_option_namespace
183
+ def showAsym (interface , namespace ):
162
184
"""Show asymmetric PFC information"""
163
- ctx .obj ['pfc' ].showPfcAsym (interface )
185
+ Pfc (namespace ).showPfcAsym (interface )
186
+
164
187
165
188
@click .command ()
166
189
@click .argument ('interface' , type = click .STRING , required = False )
167
- @click . pass_context
168
- def showPrio (ctx , interface ):
190
+ @multi_asic_util . multi_asic_click_option_namespace
191
+ def showPrio (interface , namespace ):
169
192
"""Show PFC priority information"""
170
- ctx .obj ['pfc' ].showPfcPrio (interface )
193
+ Pfc (namespace ).showPfcPrio (interface )
194
+
171
195
172
196
config .add_command (configAsym , "asymmetric" )
173
197
config .add_command (configPrio , "priority" )
0 commit comments