From fa23bfc07d6b2e0fd04e7ab9bba7741af3179f00 Mon Sep 17 00:00:00 2001
From: oleksandrx-kolomeiets <oleksandrx.kolomeiets@intel.com>
Date: Fri, 14 Jan 2022 02:46:25 +0200
Subject: [PATCH] [Barefoot] Added CLI to list/set P4 profile (#1951)

#### What I did
* Added "show platform barefoot profile" command
* Added "config platform barefoot profile" command
* Updated Command Line Reference Guide

#### How I did it
* Created plugins for Barefoot in show/plugins/barefoot.py and config/plugins/barefoot.py
* Updated doc/Command-Reference.md
---
 config/plugins/barefoot.py | 57 ++++++++++++++++++++++++++++++++++++++
 doc/Command-Reference.md   | 39 ++++++++++++++++++++++++++
 show/plugins/barefoot.py   | 47 +++++++++++++++++++++++++++++++
 3 files changed, 143 insertions(+)
 create mode 100644 config/plugins/barefoot.py
 create mode 100644 show/plugins/barefoot.py

diff --git a/config/plugins/barefoot.py b/config/plugins/barefoot.py
new file mode 100644
index 000000000000..088ee8e928e3
--- /dev/null
+++ b/config/plugins/barefoot.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+
+import click
+import json
+import subprocess
+from sonic_py_common import device_info
+from swsscommon.swsscommon import ConfigDBConnector
+
+def abort_if_false(ctx, param, value):
+    if not value:
+        ctx.abort()
+
+@click.group()
+def barefoot():
+    pass
+
+@barefoot.command()
+@click.option('-y', '--yes', is_flag=True, callback=abort_if_false,
+    expose_value=False, prompt='Swss service will be restarted, continue?')
+@click.argument('profile')
+def profile(profile):
+    # Check if profile can be changed
+    completed_process = subprocess.run(['docker', 'exec', '-it', 'syncd',
+        'test', '-h', '/opt/bfn/install'])
+    if completed_process.returncode != 0:
+        click.echo('Cannot change profile: default one is in use')
+        raise click.Abort()
+    
+    # Get chip family
+    hwsku_dir = device_info.get_path_to_hwsku_dir()
+    with open(hwsku_dir + '/switch-tna-sai.conf') as file:
+        chip_family = json.load(file)['chip_list'][0]['chip_family'].lower()
+    
+    # Check if profile is supported
+    if chip_family == 'tofino' and profile[0] == 'y' or \
+        chip_family == 'tofino2' and profile[0] == 'x':
+        click.echo('Specified profile is unsupported on the system')
+        raise click.Abort()
+    
+    # Check if profile exists
+    completed_process = subprocess.run(['docker', 'exec', '-it', 'syncd',
+        'test', '-d', '/opt/bfn/install_' + profile + '_profile'])
+    if completed_process.returncode != 0:
+        click.echo('No profile with the provided name found')
+        raise click.Abort()
+    
+    # Update configuration
+    config_db = ConfigDBConnector()
+    config_db.connect()
+    config_db.mod_entry('DEVICE_METADATA', 'localhost',
+        {'p4_profile': profile + '_profile'})
+    subprocess.run(['systemctl', 'restart', 'swss'], check=True)
+
+def register(cli):
+    version_info = device_info.get_sonic_version_info()
+    if version_info and version_info.get('asic_type') == 'barefoot':
+        cli.commands['platform'].add_command(barefoot)
diff --git a/doc/Command-Reference.md b/doc/Command-Reference.md
index 89700984522c..294695a72de6 100644
--- a/doc/Command-Reference.md
+++ b/doc/Command-Reference.md
@@ -119,6 +119,8 @@
   * [Platform Component Firmware config commands](#platform-component-firmware-config-commands)
   * [Platform Component Firmware vendor specific behaviour](#platform-component-firmware-vendor-specific-behaviour)
 * [Platform Specific Commands](#platform-specific-commands)
+  * [Mellanox Platform Specific Commands](#mellanox-platform-specific-commands)
+  * [Barefoot Platform Specific Commands](#barefoot-platform-specific-commands)
 * [PortChannels](#portchannels)
   * [PortChannel Show commands](#portchannel-show-commands)
   * [PortChannel Config commands](#portchannel-config-commands)
@@ -6583,6 +6585,8 @@ Go Back To [Beginning of the document](#) or [Beginning of this section](#platfo
 
 ## Platform Specific Commands
 
+### Mellanox Platform Specific Commands
+
 There are few commands that are platform specific. Mellanox has used this feature and implemented Mellanox specific commands as follows.
 
 **show platform mlnx sniffer**
@@ -6652,6 +6656,41 @@ In order to avoid that confirmation the -y / --yes option should be used.
   NOTE: In order to avoid that confirmation the -y / --yes option should be used.
   ```
 
+### Barefoot Platform Specific Commands
+
+**show platform barefoot profile**
+
+This command displays active P4 profile and lists available ones.
+
+- Usage:
+  ```
+  show platform barefoot profile
+  ```
+
+- Example:
+  ```
+  admin@sonic:~$ show platform barefoot profile
+  Current profile: x1
+  Available profile(s):
+  x1
+  x2
+  ```
+
+**config platform barefoot profile**
+
+This command sets P4 profile.
+
+- Usage:
+  ```
+  config platform barefoot profile <p4_profile> [-y|--yes]
+  ```
+
+- Example:
+  ```
+  admin@sonic:~$ sudo config platform barefoot profile x1
+  Swss service will be restarted, continue? [y/N]: y
+  ```
+
 Go Back To [Beginning of the document](#) or [Beginning of this section](#platform-specific-commands)
 
 
diff --git a/show/plugins/barefoot.py b/show/plugins/barefoot.py
new file mode 100644
index 000000000000..bc80c47ba31a
--- /dev/null
+++ b/show/plugins/barefoot.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+import click
+import json
+import subprocess
+from sonic_py_common import device_info
+
+@click.group()
+def barefoot():
+    pass
+
+@barefoot.command()
+def profile():
+    # Check if profile can be changed
+    completed_process = subprocess.run(['docker', 'exec', '-it', 'syncd',
+        'test', '-h', '/opt/bfn/install'])
+    if completed_process.returncode != 0:
+        click.echo('Current profile: default')
+        return
+    
+    # Get chip family
+    hwsku_dir = device_info.get_path_to_hwsku_dir()
+    with open(hwsku_dir + '/switch-tna-sai.conf') as file:
+        chip_family = json.load(file)['chip_list'][0]['chip_family'].lower()
+    
+    # Print current profile
+    click.echo('Current profile: ', nl=False)
+    subprocess.run('docker exec -it syncd readlink /opt/bfn/install | sed '
+        r's/install_\\\(.\*\\\)_profile/\\1/', check=True, shell=True)
+    
+    # Exclude current and unsupported profiles
+    opts = ''
+    if chip_family == 'tofino':
+        opts = r'\! -name install_y\*_profile '
+    elif chip_family == 'tofino2':
+        opts = r'\! -name install_x\*_profile '
+    
+    # Print profile list
+    click.echo('Available profile(s):')
+    subprocess.run('docker exec -it syncd find /opt/bfn -mindepth 1 '
+        r'-maxdepth 1 -type d -name install_\*_profile ' + opts + '| sed '
+        r's%/opt/bfn/install_\\\(.\*\\\)_profile%\\1%', shell=True)
+
+def register(cli):
+    version_info = device_info.get_sonic_version_info()
+    if version_info and version_info.get('asic_type') == 'barefoot':
+        cli.commands['platform'].add_command(barefoot)