Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[hash]: Implement GH frontend #2580

Merged
merged 2 commits into from
Jul 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
273 changes: 273 additions & 0 deletions config/plugins/sonic-hash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
"""
This CLI plugin was auto-generated by using 'sonic-cli-gen' utility
"""

import click
import utilities_common.cli as clicommon

from sonic_py_common import logger
from utilities_common.switch_hash import (
CFG_SWITCH_HASH,
STATE_SWITCH_CAPABILITY,
SW_CAP_HASH_FIELD_LIST_KEY,
SW_CAP_ECMP_HASH_KEY,
SW_CAP_LAG_HASH_KEY,
SW_HASH_KEY,
SW_CAP_KEY,
HASH_FIELD_LIST,
SYSLOG_IDENTIFIER,
get_param,
get_param_hint,
get_dupes,
to_str,
)


log = logger.Logger(SYSLOG_IDENTIFIER)
log.set_min_log_priority_info()

#
# Hash validators -----------------------------------------------------------------------------------------------------
#

def hash_field_validator(ctx, param, value):
"""
Check if hash field list argument is valid
Args:
ctx: click context
param: click parameter context
value: value of parameter
Returns:
str: validated parameter
"""

for hash_field in value:
click.Choice(HASH_FIELD_LIST).convert(hash_field, param, ctx)

return list(value)


def ecmp_hash_validator(ctx, db, ecmp_hash):
"""
Check if ECMP hash argument is valid
Args:
ctx: click context
db: State DB connector object
ecmp_hash: ECMP hash field list
"""

dup_list = get_dupes(ecmp_hash)
if dup_list:
raise click.UsageError("Invalid value for {}: {} has a duplicate hash field(s) {}".format(
get_param_hint(ctx, "ecmp_hash"), to_str(ecmp_hash), to_str(dup_list)), ctx
)

entry = db.get_all(db.STATE_DB, "{}|{}".format(STATE_SWITCH_CAPABILITY, SW_CAP_KEY))
nazariig marked this conversation as resolved.
Show resolved Hide resolved

entry.setdefault(SW_CAP_HASH_FIELD_LIST_KEY, 'N/A')
entry.setdefault(SW_CAP_ECMP_HASH_KEY, 'false')

if entry[SW_CAP_ECMP_HASH_KEY] == 'false':
raise click.UsageError("Failed to configure {}: operation is not supported".format(
get_param_hint(ctx, "ecmp_hash")), ctx
)

if not entry[SW_CAP_HASH_FIELD_LIST_KEY]:
raise click.UsageError("Failed to configure {}: no hash field capabilities".format(
get_param_hint(ctx, "ecmp_hash")), ctx
)

if entry[SW_CAP_HASH_FIELD_LIST_KEY] == 'N/A':
return

cap_list = entry[SW_CAP_HASH_FIELD_LIST_KEY].split(',')

for hash_field in ecmp_hash:
click.Choice(cap_list).convert(hash_field, get_param(ctx, "ecmp_hash"), ctx)


def lag_hash_validator(ctx, db, lag_hash):
"""
Check if LAG hash argument is valid
Args:
ctx: click context
nazariig marked this conversation as resolved.
Show resolved Hide resolved
db: State DB connector object
lag_hash: LAG hash field list
"""

dup_list = get_dupes(lag_hash)
if dup_list:
raise click.UsageError("Invalid value for {}: {} has a duplicate hash field(s) {}".format(
get_param_hint(ctx, "lag_hash"), to_str(lag_hash), to_str(dup_list)), ctx
)

entry = db.get_all(db.STATE_DB, "{}|{}".format(STATE_SWITCH_CAPABILITY, SW_CAP_KEY))

entry.setdefault(SW_CAP_HASH_FIELD_LIST_KEY, 'N/A')
entry.setdefault(SW_CAP_LAG_HASH_KEY, 'false')

if entry[SW_CAP_LAG_HASH_KEY] == 'false':
raise click.UsageError("Failed to configure {}: operation is not supported".format(
get_param_hint(ctx, "lag_hash")), ctx
)

if not entry[SW_CAP_HASH_FIELD_LIST_KEY]:
raise click.UsageError("Failed to configure {}: no hash field capabilities".format(
get_param_hint(ctx, "lag_hash")), ctx
)

if entry[SW_CAP_HASH_FIELD_LIST_KEY] == 'N/A':
return

cap_list = entry[SW_CAP_HASH_FIELD_LIST_KEY].split(',')

for hash_field in lag_hash:
click.Choice(cap_list).convert(hash_field, get_param(ctx, "lag_hash"), ctx)

#
# Hash DB interface ---------------------------------------------------------------------------------------------------
#

def update_entry_validated(db, table, key, data, create_if_not_exists=False):
""" Update entry in table and validate configuration.
If attribute value in data is None, the attribute is deleted.
Args:
db (swsscommon.ConfigDBConnector): Config DB connector object.
table (str): Table name to add new entry to.
key (Union[str, Tuple]): Key name in the table.
data (Dict): Entry data.
create_if_not_exists (bool):
In case entry does not exists already a new entry
is not created if this flag is set to False and
creates a new entry if flag is set to True.
Raises:
Exception: when cfg does not satisfy YANG schema.
"""

cfg = db.get_config()
cfg.setdefault(table, {})

if not data:
raise click.ClickException(f"No field/values to update {key}")

if create_if_not_exists:
cfg[table].setdefault(key, {})

if key not in cfg[table]:
raise click.ClickException(f"{key} does not exist")

entry_changed = False
for attr, value in data.items():
if value == cfg[table][key].get(attr):
continue
entry_changed = True
if value is None:
cfg[table][key].pop(attr, None)
else:
cfg[table][key][attr] = value

if not entry_changed:
return

db.set_entry(table, key, cfg[table][key])

#
# Hash CLI ------------------------------------------------------------------------------------------------------------
#

@click.group(
name="switch-hash",
cls=clicommon.AliasedGroup
)
def SWITCH_HASH():
""" Configure switch hash feature """

pass


@SWITCH_HASH.group(
name="global",
cls=clicommon.AliasedGroup
)
def SWITCH_HASH_GLOBAL():
""" Configure switch hash global """

pass


@SWITCH_HASH_GLOBAL.command(
name="ecmp-hash"
)
@click.argument(
"ecmp-hash",
nargs=-1,
required=True,
callback=hash_field_validator,
)
@clicommon.pass_db
@click.pass_context
def SWITCH_HASH_GLOBAL_ecmp_hash(ctx, db, ecmp_hash):
""" Hash fields for hashing packets going through ECMP """

ecmp_hash_validator(ctx, db.db, ecmp_hash)

table = CFG_SWITCH_HASH
key = SW_HASH_KEY
data = {
"ecmp_hash": ecmp_hash,
}

try:
update_entry_validated(db.cfgdb, table, key, data, create_if_not_exists=True)
log.log_notice("Configured switch global ECMP hash: {}".format(to_str(ecmp_hash)))
except Exception as e:
log.log_error("Failed to configure switch global ECMP hash: {}".format(str(e)))
ctx.fail(str(e))


@SWITCH_HASH_GLOBAL.command(
name="lag-hash"
)
@click.argument(
"lag-hash",
nargs=-1,
required=True,
callback=hash_field_validator,
)
@clicommon.pass_db
@click.pass_context
def SWITCH_HASH_GLOBAL_lag_hash(ctx, db, lag_hash):
""" Hash fields for hashing packets going through LAG """

lag_hash_validator(ctx, db.db, lag_hash)

table = CFG_SWITCH_HASH
key = SW_HASH_KEY
data = {
"lag_hash": lag_hash,
}

try:
update_entry_validated(db.cfgdb, table, key, data, create_if_not_exists=True)
log.log_notice("Configured switch global LAG hash: {}".format(to_str(lag_hash)))
except Exception as err:
log.log_error("Failed to configure switch global LAG hash: {}".format(str(err)))
ctx.fail(str(err))


def register(cli):
""" Register new CLI nodes in root CLI.
Args:
cli: Root CLI node.
Raises:
Exception: when root CLI already has a command
we are trying to register.
"""
cli_node = SWITCH_HASH
if cli_node.name in cli.commands:
raise Exception(f"{cli_node.name} already exists in CLI")
cli.add_command(SWITCH_HASH)
98 changes: 98 additions & 0 deletions doc/Command-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@
* [Flow Counters config commands](#flow-counters-config-commands)
* [Gearbox](#gearbox)
* [Gearbox show commands](#gearbox-show-commands)
* [Hash](#hash)
* [Hash show commands](#hash-show-commands)
* [Hash config commands](#hash-config-commands)
* [Interfaces](#interfaces)
* [Interface Show Commands](#interface-show-commands)
* [Interface Config Commands](#interface-config-commands)
Expand Down Expand Up @@ -4087,6 +4090,101 @@ This command is used to change device hostname without traffic being impacted.
Please note loaded setting will be lost after system reboot. To preserve setting, run `config save`.
```

## Hash

This section explains the various show and configuration commands available for user.

### Hash Show Commands

This subsection explains how to display switch hash configuration.

**show switch-hash global**

This command displays switch hash global configuration.

- Usage:
```bash
show switch-hash global
```

- Example:
```bash
admin@sonic:~$ show switch-hash global
ECMP HASH LAG HASH
----------------- -----------------
DST_MAC DST_MAC
SRC_MAC SRC_MAC
ETHERTYPE ETHERTYPE
IP_PROTOCOL IP_PROTOCOL
DST_IP DST_IP
SRC_IP SRC_IP
L4_DST_PORT L4_DST_PORT
L4_SRC_PORT L4_SRC_PORT
INNER_DST_MAC INNER_DST_MAC
INNER_SRC_MAC INNER_SRC_MAC
INNER_ETHERTYPE INNER_ETHERTYPE
INNER_IP_PROTOCOL INNER_IP_PROTOCOL
INNER_DST_IP INNER_DST_IP
INNER_SRC_IP INNER_SRC_IP
INNER_L4_DST_PORT INNER_L4_DST_PORT
INNER_L4_SRC_PORT INNER_L4_SRC_PORT
```

### Hash Config Commands

This subsection explains how to configure switch hash.

**config switch-hash global**

This command is used to manage switch hash global configuration.

- Usage:
```bash
config switch-hash global ecmp-hash <hash_field_list>
config switch-hash global lag-hash <hash_field_list>
```

- Parameters:
- _hash_field_list_: hash fields for hashing packets going through ECMP/LAG

- Examples:
```bash
admin@sonic:~$ config switch-hash global ecmp-hash \
'DST_MAC' \
'SRC_MAC' \
'ETHERTYPE' \
'IP_PROTOCOL' \
'DST_IP' \
'SRC_IP' \
'L4_DST_PORT' \
'L4_SRC_PORT' \
'INNER_DST_MAC' \
'INNER_SRC_MAC' \
'INNER_ETHERTYPE' \
'INNER_IP_PROTOCOL' \
'INNER_DST_IP' \
'INNER_SRC_IP' \
'INNER_L4_DST_PORT' \
'INNER_L4_SRC_PORT'
admin@sonic:~$ config switch-hash global lag-hash \
'DST_MAC' \
'SRC_MAC' \
'ETHERTYPE' \
'IP_PROTOCOL' \
'DST_IP' \
'SRC_IP' \
'L4_DST_PORT' \
'L4_SRC_PORT' \
'INNER_DST_MAC' \
'INNER_SRC_MAC' \
'INNER_ETHERTYPE' \
'INNER_IP_PROTOCOL' \
'INNER_DST_IP' \
'INNER_SRC_IP' \
'INNER_L4_DST_PORT' \
'INNER_L4_SRC_PORT'
```

## Interfaces

### Interface Show Commands
Expand Down
Loading