Skip to content

Commit 1fd2c8b

Browse files
author
Taras Keryk
committed
Added support for tofino3 P4 profiles naming
1 parent 4aa512c commit 1fd2c8b

File tree

4 files changed

+305
-37
lines changed

4 files changed

+305
-37
lines changed

config/plugins/barefoot.py

+44-19
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import subprocess
66
from sonic_py_common import device_info
77
from swsscommon.swsscommon import ConfigDBConnector
8+
from show.plugins.barefoot import check_profile, get_profile_format, get_chip_family
89

910
def abort_if_false(ctx, param, value):
1011
if not value:
@@ -14,41 +15,65 @@ def abort_if_false(ctx, param, value):
1415
def barefoot():
1516
pass
1617

18+
def check_profile_naming_tf3(profile, chip_family):
19+
"""Check if profile <profile_name>_<chip_family> exists"""
20+
return subprocess.run(['docker', 'exec', '-it', 'syncd',
21+
'test', '-d', '/opt/bfn/install_' + profile + '_' + chip_family])
22+
23+
def check_profile_naming_tf2(profile):
24+
"""Check if profile <profile_name>_profile exists"""
25+
return subprocess.run(['docker', 'exec', '-it', 'syncd',
26+
'test', '-d', '/opt/bfn/install_' + profile + '_profile'])
27+
28+
def check_supported_profile(profile, chip_family):
29+
"""Check if profile is supported"""
30+
if chip_family == 'tofino' and profile[0] != 'x' or \
31+
chip_family == 'tofino2' and profile[0] != 'y':
32+
return False
33+
return True
34+
35+
def check_profile_exist(profile, chip_family):
36+
"""Check if profile exists"""
37+
no_arch_information = False
38+
completed_process = check_profile_naming_tf3(profile, chip_family)
39+
40+
if completed_process.returncode != 0:
41+
if chip_family == 'tofino' or chip_family == 'tofino2':
42+
completed_process = check_profile_naming_tf2(profile)
43+
no_arch_information = True
44+
45+
if completed_process.returncode != 0:
46+
click.echo('No profile with the provided name found for {}'.format(chip_family))
47+
raise click.Abort()
48+
49+
return no_arch_information
50+
1751
@barefoot.command()
1852
@click.option('-y', '--yes', is_flag=True, callback=abort_if_false,
1953
expose_value=False, prompt='Swss service will be restarted, continue?')
2054
@click.argument('profile')
2155
def profile(profile):
2256
# Check if profile can be changed
23-
completed_process = subprocess.run(['docker', 'exec', '-it', 'syncd',
24-
'test', '-h', '/opt/bfn/install'])
25-
if completed_process.returncode != 0:
57+
if check_profile():
2658
click.echo('Cannot change profile: default one is in use')
2759
raise click.Abort()
28-
60+
2961
# Get chip family
30-
hwsku_dir = device_info.get_path_to_hwsku_dir()
31-
with open(hwsku_dir + '/switch-tna-sai.conf') as file:
32-
chip_family = json.load(file)['chip_list'][0]['chip_family'].lower()
33-
62+
chip_family = get_chip_family()
63+
3464
# Check if profile is supported
35-
if chip_family == 'tofino' and profile[0] == 'y' or \
36-
chip_family == 'tofino2' and profile[0] == 'x':
65+
if check_supported_profile(profile, chip_family) == False:
3766
click.echo('Specified profile is unsupported on the system')
3867
raise click.Abort()
39-
68+
4069
# Check if profile exists
41-
completed_process = subprocess.run(['docker', 'exec', '-it', 'syncd',
42-
'test', '-d', '/opt/bfn/install_' + profile + '_profile'])
43-
if completed_process.returncode != 0:
44-
click.echo('No profile with the provided name found')
45-
raise click.Abort()
46-
70+
no_arch_information = check_profile_exist(profile, chip_family)
71+
4772
# Update configuration
4873
config_db = ConfigDBConnector()
4974
config_db.connect()
50-
config_db.mod_entry('DEVICE_METADATA', 'localhost',
51-
{'p4_profile': profile + '_profile'})
75+
profile += '_profile' if no_arch_information else '_' + chip_family
76+
config_db.mod_entry('DEVICE_METADATA', 'localhost', {'p4_profile': profile})
5277
subprocess.run(['systemctl', 'restart', 'swss'], check=True)
5378

5479
def register(cli):

show/platform.py

+7
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,10 @@ def firmware(args):
154154
subprocess.check_call(cmd, shell=True)
155155
except subprocess.CalledProcessError as e:
156156
sys.exit(e.returncode)
157+
158+
# 'barefoot' subcommand ("show platform barefoot")
159+
@platform.command()
160+
def barefoot():
161+
"""Show Barefoot profile information"""
162+
cmd = "barefoot profile"
163+
clicommon.run_command(cmd)

show/plugins/barefoot.py

+51-18
Original file line numberDiff line numberDiff line change
@@ -9,37 +9,70 @@
99
def barefoot():
1010
pass
1111

12+
def check_profile():
13+
"""Check if profile can be changed"""
14+
ret = subprocess.run(['docker', 'exec', '-it', 'syncd',
15+
'test', '-h', '/opt/bfn/install'])
16+
if ret.returncode != 0:
17+
return True
18+
return False
19+
20+
def get_chip_family():
21+
"""Get chip family"""
22+
hwsku_dir = device_info.get_path_to_hwsku_dir()
23+
with open(hwsku_dir + '/switch-tna-sai.conf') as file:
24+
chip_family = json.load(file)['chip_list'][0]['chip_family'].lower()
25+
return chip_family
26+
27+
def get_current_profile():
28+
"""Get current profile"""
29+
return subprocess.run('docker exec -it syncd readlink /opt/bfn/install | sed '
30+
r's/install_\\\(.\*\\\)_profile/\\1/'
31+
r' | sed s/install_\\\(.\*\\\)_tofino.\*/\\1/', check=True, shell=True)
32+
33+
def get_profile_format(chip_family):
34+
"""Get profile naming format. Check if contains tofino family information"""
35+
output = subprocess.check_output(['docker', 'exec', '-it', 'syncd', 'ls', '/opt/bfn']).strip().decode()
36+
return '_' + chip_family if '_tofino' in output else '_profile'
37+
38+
def get_available_profiles(opts):
39+
"""Get available profiles"""
40+
return subprocess.run('docker exec -it syncd find /opt/bfn -mindepth 1 '
41+
r'-maxdepth 1 -type d,l ' + opts + '| sed '
42+
r's%/opt/bfn/install_\\\(.\*\\\)_profile%\\1%'
43+
r' | sed s%/opt/bfn/install_\\\(.\*\\\)_tofino.\*%\\1%', shell=True)
44+
1245
@barefoot.command()
1346
def profile():
1447
# Check if profile can be changed
15-
completed_process = subprocess.run(['docker', 'exec', '-it', 'syncd',
16-
'test', '-h', '/opt/bfn/install'])
17-
if completed_process.returncode != 0:
48+
if check_profile():
1849
click.echo('Current profile: default')
1950
return
20-
51+
2152
# Get chip family
22-
hwsku_dir = device_info.get_path_to_hwsku_dir()
23-
with open(hwsku_dir + '/switch-tna-sai.conf') as file:
24-
chip_family = json.load(file)['chip_list'][0]['chip_family'].lower()
25-
53+
chip_family = get_chip_family()
54+
2655
# Print current profile
2756
click.echo('Current profile: ', nl=False)
28-
subprocess.run('docker exec -it syncd readlink /opt/bfn/install | sed '
29-
r's/install_\\\(.\*\\\)_profile/\\1/', check=True, shell=True)
30-
31-
# Exclude current and unsupported profiles
57+
current_profile = get_current_profile()
58+
click.echo(current_profile.stdout, nl=False)
59+
60+
# Check if profile naming format contains tofino family information
61+
suffix = get_profile_format(chip_family)
62+
63+
# Check supported profiles
3264
opts = ''
3365
if chip_family == 'tofino':
34-
opts = r'\! -name install_y\*_profile '
66+
opts = r' -name install_x\*' + suffix
3567
elif chip_family == 'tofino2':
36-
opts = r'\! -name install_x\*_profile '
37-
68+
opts = r' -name install_y\*' + suffix
69+
else:
70+
opts = r' -name \*' + suffix
71+
3872
# Print profile list
3973
click.echo('Available profile(s):')
40-
subprocess.run('docker exec -it syncd find /opt/bfn -mindepth 1 '
41-
r'-maxdepth 1 -type d -name install_\*_profile ' + opts + '| sed '
42-
r's%/opt/bfn/install_\\\(.\*\\\)_profile%\\1%', shell=True)
74+
available_profiles = get_available_profiles(opts)
75+
click.echo(available_profiles.stdout, nl=False)
4376

4477
def register(cli):
4578
version_info = device_info.get_sonic_version_info()

tests/barefoot_test.py

+203
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
import os
2+
import sys
3+
import textwrap
4+
import json
5+
from unittest.mock import patch, mock_open
6+
7+
import pytest
8+
from click.testing import CliRunner
9+
import utilities_common.cli as cli
10+
11+
import show.main as show
12+
import config.main as config
13+
import show.plugins.barefoot as bfshow
14+
import config.plugins.barefoot as bfconfig
15+
16+
@pytest.fixture(scope='class')
17+
def config_env():
18+
os.environ["UTILITIES_UNIT_TESTING"] = "1"
19+
yield
20+
os.environ["UTILITIES_UNIT_TESTING"] = "0"
21+
22+
class TestStdout:
23+
stdout = ""
24+
25+
class TestReturncode:
26+
returncode = False
27+
28+
class TestShowPlatformBarefoot(object):
29+
30+
def test_config_barefoot(self):
31+
runner = CliRunner()
32+
expected_output = ""
33+
result = CliRunner().invoke(show.cli.commands["platform"], ["barefoot"])
34+
assert result.output == expected_output
35+
36+
def test_config_profile(self):
37+
runner = CliRunner()
38+
expected_output = "Swss service will be restarted, continue? [y/N]: \nAborted!\n"
39+
result = runner.invoke(bfconfig.barefoot.commands['profile'], ['x1'])
40+
print("result.exit_code:", result.exit_code)
41+
print("result.output:", result.output)
42+
assert result.output == expected_output
43+
44+
def test_check_profile_naming_tf3(self):
45+
with patch('config.plugins.barefoot.subprocess.run', return_value=0):
46+
result = bfconfig.check_profile_naming_tf3("y2", "tofino3")
47+
assert result == 0
48+
49+
def test_check_profile_naming_tf2(self):
50+
with patch('config.plugins.barefoot.subprocess.run', return_value=0):
51+
result = bfconfig.check_profile_naming_tf2("y2")
52+
assert result == 0
53+
54+
def test_check_profile_naming_tf3_t(self):
55+
with patch('config.plugins.barefoot.subprocess.run', return_value=1):
56+
result = bfconfig.check_profile_naming_tf3("y2", "tofino3")
57+
assert result == 1
58+
59+
def test_check_profile_naming_tf2_t(self):
60+
with patch('config.plugins.barefoot.subprocess.run', return_value=1):
61+
result = bfconfig.check_profile_naming_tf2("y2")
62+
assert result == 1
63+
64+
def test_check_profile_exist1(self):
65+
completed_process = TestReturncode()
66+
completed_process.returncode = 0
67+
with patch('config.plugins.barefoot.check_profile_naming_tf3', return_value=completed_process):
68+
result = bfconfig.check_profile_exist("x1", "tofino")
69+
assert result == 0
70+
71+
def test_check_profile_exist2(self):
72+
completed_process1 = TestReturncode()
73+
completed_process2 = TestReturncode()
74+
completed_process1.returncode = 1
75+
completed_process2.returncode = 0
76+
with patch('config.plugins.barefoot.check_profile_naming_tf3', return_value=completed_process1):
77+
with patch('config.plugins.barefoot.check_profile_naming_tf2', return_value=completed_process2):
78+
result = bfconfig.check_profile_exist("x1", "tofino")
79+
assert result == 1
80+
81+
def test_show_profile(self):
82+
runner = CliRunner()
83+
expected_output = "Current profile: default\n"
84+
result = runner.invoke(bfshow.barefoot.commands['profile'], [])
85+
print("result.exit_code:", result.exit_code)
86+
print("result.output:", result.output)
87+
assert result.output == expected_output
88+
89+
def test_get_chip_family1(self):
90+
with patch('show.plugins.barefoot.device_info.get_path_to_hwsku_dir', return_value=""):
91+
chip_family = json.dumps({"chip_list": [{"instance": 0,"chip_family": "tofino3"}]})
92+
with patch('show.plugins.barefoot.open', mock_open(read_data=chip_family)):
93+
result = bfshow.get_chip_family()
94+
assert result == "tofino3"
95+
96+
def test_get_chip_family2(self):
97+
with patch('config.plugins.barefoot.device_info.get_path_to_hwsku_dir', return_value=""):
98+
chip_family = json.dumps({"chip_list": [{"instance": 0,"chip_family": "tofino3"}]})
99+
with patch('show.plugins.barefoot.open', mock_open(read_data=chip_family)):
100+
result = bfconfig.get_chip_family()
101+
assert result == "tofino3"
102+
103+
def test_show_profile_default(self):
104+
runner = CliRunner()
105+
expected_output = "Current profile: default\n"
106+
with patch("show.plugins.barefoot.check_profile", return_value=1):
107+
print(show.plugins.barefoot.check_profile())
108+
result = runner.invoke(bfshow.barefoot.commands['profile'], [])
109+
print("result.exit_code:", result.exit_code)
110+
print("result.output:", result.output)
111+
assert result.output == expected_output
112+
113+
def test_check_profile1(self):
114+
ret = TestReturncode()
115+
ret.returncode = 1
116+
with patch('show.plugins.barefoot.subprocess.run', return_value=ret):
117+
result = bfshow.check_profile()
118+
print(result)
119+
assert result == True
120+
121+
def test_check_profile2(self):
122+
ret = TestReturncode()
123+
ret.returncode = 1
124+
with patch('config.plugins.barefoot.subprocess.run', return_value=ret):
125+
result = bfconfig.check_profile()
126+
print(result)
127+
assert result == True
128+
129+
def test_check_profile3(self):
130+
ret = TestReturncode()
131+
ret.returncode = 0
132+
with patch('show.plugins.barefoot.subprocess.run', return_value=ret):
133+
result = bfshow.check_profile()
134+
print(result)
135+
assert result == False
136+
137+
def test_check_profile4(self):
138+
ret = TestReturncode()
139+
ret.returncode = 0
140+
with patch('config.plugins.barefoot.subprocess.run', return_value=ret):
141+
result = bfconfig.check_profile()
142+
print(result)
143+
assert result == False
144+
145+
def test_check_supported_profile1(self):
146+
result = bfconfig.check_supported_profile("x1", "tofino")
147+
print(result)
148+
assert result == True
149+
150+
def test_check_supported_profile2(self):
151+
result = bfconfig.check_supported_profile("y2", "tofino2")
152+
print(result)
153+
assert result == True
154+
155+
def test_check_supported_profile3(self):
156+
result = bfconfig.check_supported_profile("x1", "tofino2")
157+
print(result)
158+
assert result == False
159+
160+
def test_check_supported_profile4(self):
161+
result = bfconfig.check_supported_profile("y2", "tofino")
162+
print(result)
163+
assert result == False
164+
165+
def test_get_current_profile(self):
166+
with patch('show.plugins.barefoot.subprocess.run', return_value="y2"):
167+
result = bfshow.get_current_profile()
168+
assert result == "y2"
169+
170+
def test_get_profile_format(self):
171+
with patch('show.plugins.barefoot.subprocess') as subprocess:
172+
subprocess.return_value = 0
173+
result = bfshow.get_profile_format("tofino")
174+
assert result == "_profile"
175+
176+
def test_get_available_profiles(self):
177+
with patch('show.plugins.barefoot.subprocess.run', return_value="x2"):
178+
result = bfshow.get_available_profiles("install_x1_tofino")
179+
assert result == "x2"
180+
181+
def test_show_profile(self):
182+
runner = CliRunner()
183+
expected_output = """\
184+
Current profile: y2
185+
Available profile(s):
186+
x1
187+
x2
188+
y2
189+
y3
190+
"""
191+
with patch("show.plugins.barefoot.check_profile", return_value=False):
192+
with patch("show.plugins.barefoot.get_chip_family", return_value="tofino"):
193+
current_profile = TestStdout()
194+
current_profile.stdout = "y2\n"
195+
with patch("show.plugins.barefoot.get_current_profile", return_value=current_profile):
196+
with patch("show.plugins.barefoot.get_profile_format", return_value="_profile"):
197+
available_profile = TestStdout()
198+
available_profile.stdout = "x1\nx2\ny2\ny3\n"
199+
with patch("show.plugins.barefoot.get_available_profiles", return_value=available_profile):
200+
result = runner.invoke(bfshow.barefoot.commands['profile'], [])
201+
print("result.exit_code:", result.exit_code)
202+
print("result.output:", result.output)
203+
assert result.output == expected_output

0 commit comments

Comments
 (0)