From 559d2109fcd32a0fb728657c01645cdff1c6ac28 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 1 Jun 2021 14:53:22 +0000 Subject: [PATCH 01/79] Fixed codestyle Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 724 +++++++++++++++++++++++++++++++ show/plugins/sonic-pbh_yang.py | 267 ++++++++++++ 2 files changed, 991 insertions(+) create mode 100644 config/plugins/sonic-pbh_yang.py create mode 100644 show/plugins/sonic-pbh_yang.py diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py new file mode 100644 index 0000000000..93829c574d --- /dev/null +++ b/config/plugins/sonic-pbh_yang.py @@ -0,0 +1,724 @@ +""" +Autogenerated config CLI plugin. +""" + +import click +import utilities_common.cli as clicommon +import utilities_common.general as general +from config import config_mgmt + + +# Load sonic-cfggen from source since /usr/local/bin/sonic-cfggen does not have .py extension. +sonic_cfggen = general.load_module_from_source('sonic_cfggen', '/usr/local/bin/sonic-cfggen') + + +def exit_with_error(*args, **kwargs): + """ Print a message and abort CLI. """ + + click.secho(*args, **kwargs) + raise click.Abort() + + +def validate_config_or_raise(cfg): + """ Validate config db data using ConfigMgmt """ + + try: + cfg = sonic_cfggen.FormatConverter.to_serialized(cfg) + config_mgmt.ConfigMgmt().loadData(cfg) + except Exception as err: + raise Exception('Failed to validate configuration: {}'.format(err)) + + +def add_entry_validated(db, table, key, data): + """ Add new entry in table and validate configuration """ + + cfg = db.get_config() + cfg.setdefault(table, {}) + if key in cfg[table]: + raise Exception(f"{key} already exists") + + cfg[table][key] = data + + validate_config_or_raise(cfg) + db.set_entry(table, key, data) + + +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. + """ + + cfg = db.get_config() + cfg.setdefault(table, {}) + + if create_if_not_exists: + cfg[table].setdefault(key, {}) + + if key not in cfg[table]: + raise Exception(f"{key} does not exist") + + for attr, value in data.items(): + if value is None and attr in cfg[table][key]: + cfg[table][key].pop(attr) + else: + cfg[table][key][attr] = value + + validate_config_or_raise(cfg) + db.set_entry(table, key, cfg[table][key]) + + +def del_entry_validated(db, table, key): + """ Delete entry in table and validate configuration """ + + cfg = db.get_config() + cfg.setdefault(table, {}) + if key not in cfg[table]: + raise Exception(f"{key} does not exist") + + cfg[table].pop(key) + + validate_config_or_raise(cfg) + db.set_entry(table, key, None) + + +def add_list_entry_validated(db, table, key, attr, data): + """ Add new entry into list in table and validate configuration""" + + cfg = db.get_config() + cfg.setdefault(table, {}) + if key not in cfg[table]: + raise Exception(f"{key} does not exist") + cfg[table][key].setdefault(attr, []) + for entry in data: + if entry in cfg[table][key][attr]: + raise Exception(f"{entry} already exists") + cfg[table][key][attr].append(entry) + + validate_config_or_raise(cfg) + db.set_entry(table, key, cfg[table][key]) + + +def del_list_entry_validated(db, table, key, attr, data): + """ Delete entry from list in table and validate configuration""" + + cfg = db.get_config() + cfg.setdefault(table, {}) + if key not in cfg[table]: + raise Exception(f"{key} does not exist") + cfg[table][key].setdefault(attr, []) + for entry in data: + if entry not in cfg[table][key][attr]: + raise Exception(f"{entry} does not exist") + cfg[table][key][attr].remove(entry) + if not cfg[table][key][attr]: + cfg[table][key].pop(attr) + + validate_config_or_raise(cfg) + db.set_entry(table, key, cfg[table][key]) + + +def clear_list_entry_validated(db, table, key, attr): + """ Clear list in object and validate configuration""" + + update_entry_validated(db, table, key, {attr: None}) + + +@click.group(name="pbh-hash", + cls=clicommon.AliasedGroup) +def PBH_HASH(): + """ PBH_HASH part of config_db.json """ + + pass + + +@PBH_HASH.command(name="add") +@click.argument( + "hash-name", + nargs=1, + required=True, +) +@click.option( + "--hash-field", + help="Configures native hash field for this hash[mandatory]", +) +@click.option( + "--ipv4-mask", + help="Configures IPv4 address mask for this hash[mandatory]", +) +@click.option( + "--ipv6-mask", + help="Configures IPv6 address mask for this hash[mandatory]", +) +@click.option( + "--sequence-id", + help="Configures in which order the fields are hashed and defines which fields should be associative[mandatory]", +) +@clicommon.pass_db +def PBH_HASH_add(db, hash_name, hash_field, ipv4_mask, ipv6_mask, sequence_id): + """ Add object in PBH_HASH. """ + + table = "PBH_HASH" + key = hash_name + data = {} + if hash_field is not None: + data["hash_field"] = hash_field + if ipv4_mask is not None: + data["ipv4_mask"] = ipv4_mask + if ipv6_mask is not None: + data["ipv6_mask"] = ipv6_mask + if sequence_id is not None: + data["sequence_id"] = sequence_id + + try: + add_entry_validated(db.cfgdb, table, key, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@PBH_HASH.command(name="update") +@click.argument( + "hash-name", + nargs=1, + required=True, +) +@click.option( + "--hash-field", + help="Configures native hash field for this hash[mandatory]", +) +@click.option( + "--ipv4-mask", + help="Configures IPv4 address mask for this hash[mandatory]", +) +@click.option( + "--ipv6-mask", + help="Configures IPv6 address mask for this hash[mandatory]", +) +@click.option( + "--sequence-id", + help="Configures in which order the fields are hashed and defines which fields should be associative[mandatory]", +) +@clicommon.pass_db +def PBH_HASH_update(db, hash_name, hash_field, ipv4_mask, ipv6_mask, sequence_id): + """ Add object in PBH_HASH. """ + + table = "PBH_HASH" + key = hash_name + data = {} + if hash_field is not None: + data["hash_field"] = hash_field + if ipv4_mask is not None: + data["ipv4_mask"] = ipv4_mask + if ipv6_mask is not None: + data["ipv6_mask"] = ipv6_mask + if sequence_id is not None: + data["sequence_id"] = sequence_id + + try: + update_entry_validated(db.cfgdb, table, key, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@PBH_HASH.command(name="delete") +@click.argument( + "hash-name", + nargs=1, + required=True, +) +@clicommon.pass_db +def PBH_HASH_delete(db, hash_name): + """ Delete object in PBH_HASH. """ + + table = "PBH_HASH" + key = hash_name + try: + del_entry_validated(db.cfgdb, table, key) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@click.group(name="pbh-rule", + cls=clicommon.AliasedGroup) +def PBH_RULE(): + """ PBH_RULE part of config_db.json """ + + pass + + +@PBH_RULE.command(name="add") +@click.argument( + "table-name", + nargs=1, + required=True, +) +@click.argument( + "rule-name", + nargs=1, + required=True, +) +@click.option( + "--priority", + help="Configures priority for this rule[mandatory]", +) +@click.option( + "--gre-key", + help="Configures packet match for this rule: GRE key", +) +@click.option( + "--ip-protocol", + help="Configures packet match for this rule: IP protocol", +) +@click.option( + "--ipv6-next-header", + help="Configures packet match for this rule: IPv6 Next header", +) +@click.option( + "--l4-dst-port", + help="Configures packet match for this rule: L4 destination port", +) +@click.option( + "--inner-ether-type", + help="Configures packet match for this rule: inner EtherType", +) +@click.option( + "--packet-action", + help="Configures packet action for this rule", +) +@click.option( + "--flow-counter", + help="Enables/Disables packet/byte counter for this rule", +) +@click.option( + "--hash-list", + help="The list of hash fields to apply with this rule", +) +@clicommon.pass_db +def PBH_RULE_add(db, table_name, rule_name, priority, gre_key, ip_protocol, ipv6_next_header, l4_dst_port, inner_ether_type, packet_action, flow_counter, hash_list): + """ Add object in PBH_RULE. """ + + table = "PBH_RULE" + key = table_name, rule_name + data = {} + if priority is not None: + data["priority"] = priority + if gre_key is not None: + data["gre_key"] = gre_key + if ip_protocol is not None: + data["ip_protocol"] = ip_protocol + if ipv6_next_header is not None: + data["ipv6_next_header"] = ipv6_next_header + if l4_dst_port is not None: + data["l4_dst_port"] = l4_dst_port + if inner_ether_type is not None: + data["inner_ether_type"] = inner_ether_type + if packet_action is not None: + data["packet_action"] = packet_action + if flow_counter is not None: + data["flow_counter"] = flow_counter + if hash_list is not None: + data["hash_list"] = hash_list.split(",") + + try: + add_entry_validated(db.cfgdb, table, key, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@PBH_RULE.command(name="update") +@click.argument( + "table-name", + nargs=1, + required=True, +) +@click.argument( + "rule-name", + nargs=1, + required=True, +) +@click.option( + "--priority", + help="Configures priority for this rule[mandatory]", +) +@click.option( + "--gre-key", + help="Configures packet match for this rule: GRE key", +) +@click.option( + "--ip-protocol", + help="Configures packet match for this rule: IP protocol", +) +@click.option( + "--ipv6-next-header", + help="Configures packet match for this rule: IPv6 Next header", +) +@click.option( + "--l4-dst-port", + help="Configures packet match for this rule: L4 destination port", +) +@click.option( + "--inner-ether-type", + help="Configures packet match for this rule: inner EtherType", +) +@click.option( + "--packet-action", + help="Configures packet action for this rule", +) +@click.option( + "--flow-counter", + help="Enables/Disables packet/byte counter for this rule", +) +@click.option( + "--hash-list", + help="The list of hash fields to apply with this rule", +) +@clicommon.pass_db +def PBH_RULE_update(db, table_name, rule_name, priority, gre_key, ip_protocol, ipv6_next_header, l4_dst_port, inner_ether_type, packet_action, flow_counter, hash_list): + """ Add object in PBH_RULE. """ + + table = "PBH_RULE" + key = table_name, rule_name + data = {} + if priority is not None: + data["priority"] = priority + if gre_key is not None: + data["gre_key"] = gre_key + if ip_protocol is not None: + data["ip_protocol"] = ip_protocol + if ipv6_next_header is not None: + data["ipv6_next_header"] = ipv6_next_header + if l4_dst_port is not None: + data["l4_dst_port"] = l4_dst_port + if inner_ether_type is not None: + data["inner_ether_type"] = inner_ether_type + if packet_action is not None: + data["packet_action"] = packet_action + if flow_counter is not None: + data["flow_counter"] = flow_counter + if hash_list is not None: + data["hash_list"] = hash_list.split(",") + + try: + update_entry_validated(db.cfgdb, table, key, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@PBH_RULE.command(name="delete") +@click.argument( + "table-name", + nargs=1, + required=True, +) +@click.argument( + "rule-name", + nargs=1, + required=True, +) +@clicommon.pass_db +def PBH_RULE_delete(db, table_name, rule_name): + """ Delete object in PBH_RULE. """ + + table = "PBH_RULE" + key = table_name, rule_name + try: + del_entry_validated(db.cfgdb, table, key) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@PBH_RULE.group(name="hash-list", + cls=clicommon.AliasedGroup) +def PBH_RULE_hash_list(): + """ Add/Delete hash_list in PBH_RULE """ + + pass + + +@PBH_RULE_hash_list.command(name="add") +@click.argument( + "table-name", + nargs=1, + required=True, +) +@click.argument( + "rule-name", + nargs=1, + required=True, +) +@click.argument( + "hash-list", + nargs=-1, + required=True, +) +@clicommon.pass_db +def PBH_RULE_hash_list_add( + db, + table_name, rule_name, hash_list +): + """ Add hash_list in PBH_RULE """ + + table = "PBH_RULE" + key = table_name, rule_name + attr = "hash_list" + data = hash_list + + try: + add_list_entry_validated(db.cfgdb, table, key, attr, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@PBH_RULE_hash_list.command(name="delete") +@click.argument( + "table-name", + nargs=1, + required=True, +) +@click.argument( + "rule-name", + nargs=1, + required=True, +) +@click.argument( + "hash-list", + nargs=-1, + required=True, +) +@clicommon.pass_db +def PBH_RULE_hash_list_delete( + db, + table_name, rule_name, hash_list +): + """ Delete hash_list in PBH_RULE """ + + table = "PBH_RULE" + key = table_name, rule_name + attr = "hash_list" + data = hash_list + + try: + del_list_entry_validated(db.cfgdb, table, key, attr, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@PBH_RULE_hash_list.command(name="clear") +@click.argument( + "table-name", + nargs=1, + required=True, +) +@click.argument( + "rule-name", + nargs=1, + required=True, +) +@clicommon.pass_db +def PBH_RULE_hash_list_clear( + db, + table_name, rule_name +): + """ Clear hash_list in PBH_RULE """ + + table = "PBH_RULE" + key = table_name, rule_name + attr = "hash_list" + + try: + clear_list_entry_validated(db.cfgdb, table, key, attr) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@click.group(name="pbh-table", + cls=clicommon.AliasedGroup) +def PBH_TABLE(): + """ PBH_TABLE part of config_db.json """ + + pass + + +@PBH_TABLE.command(name="add") +@click.argument( + "table-name", + nargs=1, + required=True, +) +@click.option( + "--description", + help="The description of this table[mandatory]", +) +@click.option( + "--interface-list", + help="Interfaces to which this table is applied", +) +@clicommon.pass_db +def PBH_TABLE_add(db, table_name, description, interface_list): + """ Add object in PBH_TABLE. """ + + table = "PBH_TABLE" + key = table_name + data = {} + if description is not None: + data["description"] = description + if interface_list is not None: + data["interface_list"] = interface_list.split(",") + + try: + add_entry_validated(db.cfgdb, table, key, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@PBH_TABLE.command(name="update") +@click.argument( + "table-name", + nargs=1, + required=True, +) +@click.option( + "--description", + help="The description of this table[mandatory]", +) +@click.option( + "--interface-list", + help="Interfaces to which this table is applied", +) +@clicommon.pass_db +def PBH_TABLE_update(db, table_name, description, interface_list): + """ Add object in PBH_TABLE. """ + + table = "PBH_TABLE" + key = table_name + data = {} + if description is not None: + data["description"] = description + if interface_list is not None: + data["interface_list"] = interface_list.split(",") + + try: + update_entry_validated(db.cfgdb, table, key, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@PBH_TABLE.command(name="delete") +@click.argument( + "table-name", + nargs=1, + required=True, +) +@clicommon.pass_db +def PBH_TABLE_delete(db, table_name): + """ Delete object in PBH_TABLE. """ + + table = "PBH_TABLE" + key = table_name + try: + del_entry_validated(db.cfgdb, table, key) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@PBH_TABLE.group(name="interface-list", + cls=clicommon.AliasedGroup) +def PBH_TABLE_interface_list(): + """ Add/Delete interface_list in PBH_TABLE """ + + pass + + +@PBH_TABLE_interface_list.command(name="add") +@click.argument( + "table-name", + nargs=1, + required=True, +) +@click.argument( + "interface-list", + nargs=-1, + required=True, +) +@clicommon.pass_db +def PBH_TABLE_interface_list_add( + db, + table_name, interface_list +): + """ Add interface_list in PBH_TABLE """ + + table = "PBH_TABLE" + key = table_name + attr = "interface_list" + data = interface_list + + try: + add_list_entry_validated(db.cfgdb, table, key, attr, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@PBH_TABLE_interface_list.command(name="delete") +@click.argument( + "table-name", + nargs=1, + required=True, +) +@click.argument( + "interface-list", + nargs=-1, + required=True, +) +@clicommon.pass_db +def PBH_TABLE_interface_list_delete( + db, + table_name, interface_list +): + """ Delete interface_list in PBH_TABLE """ + + table = "PBH_TABLE" + key = table_name + attr = "interface_list" + data = interface_list + + try: + del_list_entry_validated(db.cfgdb, table, key, attr, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@PBH_TABLE_interface_list.command(name="clear") +@click.argument( + "table-name", + nargs=1, + required=True, +) +@clicommon.pass_db +def PBH_TABLE_interface_list_clear( + db, + table_name +): + """ Clear interface_list in PBH_TABLE """ + + table = "PBH_TABLE" + key = table_name + attr = "interface_list" + + try: + clear_list_entry_validated(db.cfgdb, table, key, attr) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +def register(cli): + cli_node = PBH_HASH + if cli_node.name in cli.commands: + raise Exception(f"{cli_node.name} already exists in CLI") + cli.add_command(PBH_HASH) + cli_node = PBH_RULE + if cli_node.name in cli.commands: + raise Exception(f"{cli_node.name} already exists in CLI") + cli.add_command(PBH_RULE) + cli_node = PBH_TABLE + if cli_node.name in cli.commands: + raise Exception(f"{cli_node.name} already exists in CLI") + cli.add_command(PBH_TABLE) diff --git a/show/plugins/sonic-pbh_yang.py b/show/plugins/sonic-pbh_yang.py new file mode 100644 index 0000000000..0051106e52 --- /dev/null +++ b/show/plugins/sonic-pbh_yang.py @@ -0,0 +1,267 @@ +""" +Auto-generated show CLI plugin. +""" + +import click +import tabulate +import natsort +import utilities_common.cli as clicommon + +def format_attr_value(entry, attr): + """ Helper that formats attribute to be presented in the table output. + + Args: + entry (Dict[str, str]): CONFIG DB entry configuration. + attr (Dict): Attribute metadata. + + Returns: + str: fomatted attribute value. + """ + + if attr["is-leaf-list"]: + return "\n".join(entry.get(attr["name"], [])) + return entry.get(attr["name"], "N/A") + +def format_group_value(entry, attrs): + """ Helper that formats grouped attribute to be presented in the table output. + + Args: + entry (Dict[str, str]): CONFIG DB entry configuration. + attrs (List[Dict]): Attributes metadata that belongs to the same group. + + Returns: + str: fomatted group attributes. + """ + + data = [] + for attr in attrs: + if entry.get(attr["name"]): + data.append((attr["name"] + ":", format_attr_value(entry, attr))) + return tabulate.tabulate(data, tablefmt="plain") + +@click.group(name="pbh-hash", + cls=clicommon.AliasedGroup, + invoke_without_command=True) +@clicommon.pass_db +def PBH_HASH(db): + """ [Callable command group] """ + + header = [ + "HASH NAME", + "HASH FIELD", + "IPV4 MASK", + "IPV6 MASK", + "SEQUENCE ID", + ] + + body = [] + + table = db.cfgdb.get_table("PBH_HASH") + for key in natsort.natsorted(table): + entry = table[key] + if not isinstance(key, tuple): + key = (key,) + + row = [*key] + [ + format_attr_value( + entry, + {'name': 'hash_field', + 'description': 'Configures native hash field for this hash', + 'is-leaf-list': False, + 'is-mandatory': True, + 'group': ''} + ), + format_attr_value( + entry, + {'name': 'ipv4_mask', + 'description': 'Configures IPv4 address mask for this hash', + 'is-leaf-list': False, + 'is-mandatory': True, + 'group': ''} + ), + format_attr_value( + entry, + {'name': 'ipv6_mask', + 'description': 'Configures IPv6 address mask for this hash', + 'is-leaf-list': False, + 'is-mandatory': True, + 'group': ''} + ), + format_attr_value( + entry, + {'name': 'sequence_id', + 'description': 'Configures in which order the fields are hashed and defines which fields should be associative', + 'is-leaf-list': False, + 'is-mandatory': True, + 'group': ''} + ), + ] + + body.append(row) + click.echo(tabulate.tabulate(body, header)) + + +@click.group(name="pbh-rule", + cls=clicommon.AliasedGroup, + invoke_without_command=True) +@clicommon.pass_db +def PBH_RULE(db): + """ [Callable command group] """ + + header = [ + "TABLE NAME", + "RULE NAME", + "PRIORITY", + "GRE KEY", + "IP PROTOCOL", + "IPV6 NEXT HEADER", + "L4 DST PORT", + "INNER ETHER TYPE", + "PACKET ACTION", + "FLOW COUNTER", + "HASH LIST", + ] + + body = [] + + table = db.cfgdb.get_table("PBH_RULE") + for key in natsort.natsorted(table): + entry = table[key] + if not isinstance(key, tuple): + key = (key,) + + row = [*key] + [ + format_attr_value( + entry, + {'name': 'priority', + 'description': 'Configures priority for this rule', + 'is-leaf-list': False, + 'is-mandatory': True, + 'group': ''} + ), + format_attr_value( + entry, + {'name': 'gre_key', + 'description': 'Configures packet match for this rule: GRE key', + 'is-leaf-list': False, + 'is-mandatory': False, 'group': ''} + ), + format_attr_value( + entry, + {'name': 'ip_protocol', + 'description': 'Configures packet match for this rule: IP protocol', + 'is-leaf-list': False, + 'is-mandatory': False, + 'group': ''} + ), + format_attr_value( + entry, + {'name': 'ipv6_next_header', + 'description': 'Configures packet match for this rule: IPv6 Next header', + 'is-leaf-list': False, + 'is-mandatory': False, + 'group': ''} + ), + format_attr_value( + entry, + {'name': 'l4_dst_port', + 'description':'Configures packet match for this rule: L4 destination port', + 'is-leaf-list': False, + 'is-mandatory': False, + 'group': ''} + ), + format_attr_value( + entry, + {'name': 'inner_ether_type', + 'description': 'Configures packet match for this rule: inner EtherType', + 'is-leaf-list': False, + 'is-mandatory': False, + 'group': ''} + ), + format_attr_value( + entry, + {'name': 'packet_action', + 'description': 'Configures packet action for this rule', + 'is-leaf-list': False, + 'is-mandatory': False, + 'group': ''} + ), + format_attr_value( + entry, + {'name': 'flow_counter', + 'description': 'Enables/Disables packet/byte counter for this rule', + 'is-leaf-list': False, + 'is-mandatory': False, + 'group': ''} + ), + format_attr_value( + entry, + {'name': 'hash_list', + 'description': 'The list of hash fields to apply with this rule', + 'is-leaf-list': True, + 'is-mandatory': False, + 'group': ''} + ), + ] + + body.append(row) + click.echo(tabulate.tabulate(body, header)) + + +@click.group(name="pbh-table", + cls=clicommon.AliasedGroup, + invoke_without_command=True) +@clicommon.pass_db +def PBH_TABLE(db): + """ [Callable command group] """ + + header = [ + "TABLE NAME", + "DESCRIPTION", + "INTERFACE LIST", + ] + + body = [] + + table = db.cfgdb.get_table("PBH_TABLE") + for key in natsort.natsorted(table): + entry = table[key] + if not isinstance(key, tuple): + key = (key,) + + row = [*key] + [ + format_attr_value( + entry, + {'name': 'description', + 'description': 'The description of this table', + 'is-leaf-list': False, + 'is-mandatory': True, + 'group': ''} + ), + format_attr_value( + entry, + {'name': 'interface_list', + 'description': 'Interfaces to which this table is applied', + 'is-leaf-list': True, + 'is-mandatory': False, + 'group': ''} + ), + ] + + body.append(row) + click.echo(tabulate.tabulate(body, header)) + + +def register(cli): + cli_node = PBH_HASH + if cli_node.name in cli.commands: + raise Exception(f"{cli_node.name} already exists in CLI") + cli.add_command(PBH_HASH) + cli_node = PBH_RULE + if cli_node.name in cli.commands: + raise Exception(f"{cli_node.name} already exists in CLI") + cli.add_command(PBH_RULE) + cli_node = PBH_TABLE + if cli_node.name in cli.commands: + raise Exception(f"{cli_node.name} already exists in CLI") + cli.add_command(PBH_TABLE) From e20b2d0feec52b000cbf0253f9e5fd379e71d9b0 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Wed, 2 Jun 2021 12:35:58 +0000 Subject: [PATCH 02/79] Removed YANG validation from 'config' Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 78 ++++++++++++-------------------- 1 file changed, 29 insertions(+), 49 deletions(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index 93829c574d..1933a291e9 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -5,11 +5,6 @@ import click import utilities_common.cli as clicommon import utilities_common.general as general -from config import config_mgmt - - -# Load sonic-cfggen from source since /usr/local/bin/sonic-cfggen does not have .py extension. -sonic_cfggen = general.load_module_from_source('sonic_cfggen', '/usr/local/bin/sonic-cfggen') def exit_with_error(*args, **kwargs): @@ -19,18 +14,8 @@ def exit_with_error(*args, **kwargs): raise click.Abort() -def validate_config_or_raise(cfg): - """ Validate config db data using ConfigMgmt """ - - try: - cfg = sonic_cfggen.FormatConverter.to_serialized(cfg) - config_mgmt.ConfigMgmt().loadData(cfg) - except Exception as err: - raise Exception('Failed to validate configuration: {}'.format(err)) - - -def add_entry_validated(db, table, key, data): - """ Add new entry in table and validate configuration """ +def add_entry(db, table, key, data): + """ Add new entry in table. """ cfg = db.get_config() cfg.setdefault(table, {}) @@ -39,13 +24,12 @@ def add_entry_validated(db, table, key, data): cfg[table][key] = data - validate_config_or_raise(cfg) db.set_entry(table, key, data) -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. +def update_entry(db, table, key, data, create_if_not_exists=False): + """ Update entry in table. + If attribute value in data is None, the attribute is deleted. """ cfg = db.get_config() @@ -63,12 +47,11 @@ def update_entry_validated(db, table, key, data, create_if_not_exists=False): else: cfg[table][key][attr] = value - validate_config_or_raise(cfg) db.set_entry(table, key, cfg[table][key]) -def del_entry_validated(db, table, key): - """ Delete entry in table and validate configuration """ +def del_entry(db, table, key): + """ Delete entry in table. """ cfg = db.get_config() cfg.setdefault(table, {}) @@ -77,12 +60,11 @@ def del_entry_validated(db, table, key): cfg[table].pop(key) - validate_config_or_raise(cfg) db.set_entry(table, key, None) -def add_list_entry_validated(db, table, key, attr, data): - """ Add new entry into list in table and validate configuration""" +def add_list_entry(db, table, key, attr, data): + """ Add new entry into list in table """ cfg = db.get_config() cfg.setdefault(table, {}) @@ -94,12 +76,11 @@ def add_list_entry_validated(db, table, key, attr, data): raise Exception(f"{entry} already exists") cfg[table][key][attr].append(entry) - validate_config_or_raise(cfg) db.set_entry(table, key, cfg[table][key]) -def del_list_entry_validated(db, table, key, attr, data): - """ Delete entry from list in table and validate configuration""" +def del_list_entry(db, table, key, attr, data): + """ Delete entry from list in table. """ cfg = db.get_config() cfg.setdefault(table, {}) @@ -113,14 +94,13 @@ def del_list_entry_validated(db, table, key, attr, data): if not cfg[table][key][attr]: cfg[table][key].pop(attr) - validate_config_or_raise(cfg) db.set_entry(table, key, cfg[table][key]) -def clear_list_entry_validated(db, table, key, attr): - """ Clear list in object and validate configuration""" +def clear_list_entry(db, table, key, attr): + """ Clear list in object. """ - update_entry_validated(db, table, key, {attr: None}) + update_entry(db, table, key, {attr: None}) @click.group(name="pbh-hash", @@ -170,7 +150,7 @@ def PBH_HASH_add(db, hash_name, hash_field, ipv4_mask, ipv6_mask, sequence_id): data["sequence_id"] = sequence_id try: - add_entry_validated(db.cfgdb, table, key, data) + add_entry(db.cfgdb, table, key, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @@ -214,7 +194,7 @@ def PBH_HASH_update(db, hash_name, hash_field, ipv4_mask, ipv6_mask, sequence_id data["sequence_id"] = sequence_id try: - update_entry_validated(db.cfgdb, table, key, data) + update_entry(db.cfgdb, table, key, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @@ -232,7 +212,7 @@ def PBH_HASH_delete(db, hash_name): table = "PBH_HASH" key = hash_name try: - del_entry_validated(db.cfgdb, table, key) + del_entry(db.cfgdb, table, key) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @@ -319,7 +299,7 @@ def PBH_RULE_add(db, table_name, rule_name, priority, gre_key, ip_protocol, ipv6 data["hash_list"] = hash_list.split(",") try: - add_entry_validated(db.cfgdb, table, key, data) + add_entry(db.cfgdb, table, key, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @@ -398,7 +378,7 @@ def PBH_RULE_update(db, table_name, rule_name, priority, gre_key, ip_protocol, i data["hash_list"] = hash_list.split(",") try: - update_entry_validated(db.cfgdb, table, key, data) + update_entry(db.cfgdb, table, key, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @@ -421,7 +401,7 @@ def PBH_RULE_delete(db, table_name, rule_name): table = "PBH_RULE" key = table_name, rule_name try: - del_entry_validated(db.cfgdb, table, key) + del_entry(db.cfgdb, table, key) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @@ -463,7 +443,7 @@ def PBH_RULE_hash_list_add( data = hash_list try: - add_list_entry_validated(db.cfgdb, table, key, attr, data) + add_list_entry(db.cfgdb, table, key, attr, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @@ -497,7 +477,7 @@ def PBH_RULE_hash_list_delete( data = hash_list try: - del_list_entry_validated(db.cfgdb, table, key, attr, data) + del_list_entry(db.cfgdb, table, key, attr, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @@ -525,7 +505,7 @@ def PBH_RULE_hash_list_clear( attr = "hash_list" try: - clear_list_entry_validated(db.cfgdb, table, key, attr) + clear_list_entry(db.cfgdb, table, key, attr) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @@ -565,7 +545,7 @@ def PBH_TABLE_add(db, table_name, description, interface_list): data["interface_list"] = interface_list.split(",") try: - add_entry_validated(db.cfgdb, table, key, data) + add_entry(db.cfgdb, table, key, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @@ -597,7 +577,7 @@ def PBH_TABLE_update(db, table_name, description, interface_list): data["interface_list"] = interface_list.split(",") try: - update_entry_validated(db.cfgdb, table, key, data) + update_entry(db.cfgdb, table, key, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @@ -615,7 +595,7 @@ def PBH_TABLE_delete(db, table_name): table = "PBH_TABLE" key = table_name try: - del_entry_validated(db.cfgdb, table, key) + del_entry(db.cfgdb, table, key) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @@ -652,7 +632,7 @@ def PBH_TABLE_interface_list_add( data = interface_list try: - add_list_entry_validated(db.cfgdb, table, key, attr, data) + add_list_entry(db.cfgdb, table, key, attr, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @@ -681,7 +661,7 @@ def PBH_TABLE_interface_list_delete( data = interface_list try: - del_list_entry_validated(db.cfgdb, table, key, attr, data) + del_list_entry(db.cfgdb, table, key, attr, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @@ -704,7 +684,7 @@ def PBH_TABLE_interface_list_clear( attr = "interface_list" try: - clear_list_entry_validated(db.cfgdb, table, key, attr) + clear_list_entry(db.cfgdb, table, key, attr) except Exception as err: exit_with_error(f"Error: {err}", fg="red") From 0e44abe703f47145fa71f2a01364c30804c4d7b6 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Mon, 7 Jun 2021 09:00:31 +0000 Subject: [PATCH 03/79] Generated from updated YANG model show CLI for PBH & fixed codestyle Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 704 ------------------------------- show/plugins/sonic-pbh_yang.py | 111 +++-- 2 files changed, 75 insertions(+), 740 deletions(-) delete mode 100644 config/plugins/sonic-pbh_yang.py diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py deleted file mode 100644 index 1933a291e9..0000000000 --- a/config/plugins/sonic-pbh_yang.py +++ /dev/null @@ -1,704 +0,0 @@ -""" -Autogenerated config CLI plugin. -""" - -import click -import utilities_common.cli as clicommon -import utilities_common.general as general - - -def exit_with_error(*args, **kwargs): - """ Print a message and abort CLI. """ - - click.secho(*args, **kwargs) - raise click.Abort() - - -def add_entry(db, table, key, data): - """ Add new entry in table. """ - - cfg = db.get_config() - cfg.setdefault(table, {}) - if key in cfg[table]: - raise Exception(f"{key} already exists") - - cfg[table][key] = data - - db.set_entry(table, key, data) - - -def update_entry(db, table, key, data, create_if_not_exists=False): - """ Update entry in table. - If attribute value in data is None, the attribute is deleted. - """ - - cfg = db.get_config() - cfg.setdefault(table, {}) - - if create_if_not_exists: - cfg[table].setdefault(key, {}) - - if key not in cfg[table]: - raise Exception(f"{key} does not exist") - - for attr, value in data.items(): - if value is None and attr in cfg[table][key]: - cfg[table][key].pop(attr) - else: - cfg[table][key][attr] = value - - db.set_entry(table, key, cfg[table][key]) - - -def del_entry(db, table, key): - """ Delete entry in table. """ - - cfg = db.get_config() - cfg.setdefault(table, {}) - if key not in cfg[table]: - raise Exception(f"{key} does not exist") - - cfg[table].pop(key) - - db.set_entry(table, key, None) - - -def add_list_entry(db, table, key, attr, data): - """ Add new entry into list in table """ - - cfg = db.get_config() - cfg.setdefault(table, {}) - if key not in cfg[table]: - raise Exception(f"{key} does not exist") - cfg[table][key].setdefault(attr, []) - for entry in data: - if entry in cfg[table][key][attr]: - raise Exception(f"{entry} already exists") - cfg[table][key][attr].append(entry) - - db.set_entry(table, key, cfg[table][key]) - - -def del_list_entry(db, table, key, attr, data): - """ Delete entry from list in table. """ - - cfg = db.get_config() - cfg.setdefault(table, {}) - if key not in cfg[table]: - raise Exception(f"{key} does not exist") - cfg[table][key].setdefault(attr, []) - for entry in data: - if entry not in cfg[table][key][attr]: - raise Exception(f"{entry} does not exist") - cfg[table][key][attr].remove(entry) - if not cfg[table][key][attr]: - cfg[table][key].pop(attr) - - db.set_entry(table, key, cfg[table][key]) - - -def clear_list_entry(db, table, key, attr): - """ Clear list in object. """ - - update_entry(db, table, key, {attr: None}) - - -@click.group(name="pbh-hash", - cls=clicommon.AliasedGroup) -def PBH_HASH(): - """ PBH_HASH part of config_db.json """ - - pass - - -@PBH_HASH.command(name="add") -@click.argument( - "hash-name", - nargs=1, - required=True, -) -@click.option( - "--hash-field", - help="Configures native hash field for this hash[mandatory]", -) -@click.option( - "--ipv4-mask", - help="Configures IPv4 address mask for this hash[mandatory]", -) -@click.option( - "--ipv6-mask", - help="Configures IPv6 address mask for this hash[mandatory]", -) -@click.option( - "--sequence-id", - help="Configures in which order the fields are hashed and defines which fields should be associative[mandatory]", -) -@clicommon.pass_db -def PBH_HASH_add(db, hash_name, hash_field, ipv4_mask, ipv6_mask, sequence_id): - """ Add object in PBH_HASH. """ - - table = "PBH_HASH" - key = hash_name - data = {} - if hash_field is not None: - data["hash_field"] = hash_field - if ipv4_mask is not None: - data["ipv4_mask"] = ipv4_mask - if ipv6_mask is not None: - data["ipv6_mask"] = ipv6_mask - if sequence_id is not None: - data["sequence_id"] = sequence_id - - try: - add_entry(db.cfgdb, table, key, data) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - -@PBH_HASH.command(name="update") -@click.argument( - "hash-name", - nargs=1, - required=True, -) -@click.option( - "--hash-field", - help="Configures native hash field for this hash[mandatory]", -) -@click.option( - "--ipv4-mask", - help="Configures IPv4 address mask for this hash[mandatory]", -) -@click.option( - "--ipv6-mask", - help="Configures IPv6 address mask for this hash[mandatory]", -) -@click.option( - "--sequence-id", - help="Configures in which order the fields are hashed and defines which fields should be associative[mandatory]", -) -@clicommon.pass_db -def PBH_HASH_update(db, hash_name, hash_field, ipv4_mask, ipv6_mask, sequence_id): - """ Add object in PBH_HASH. """ - - table = "PBH_HASH" - key = hash_name - data = {} - if hash_field is not None: - data["hash_field"] = hash_field - if ipv4_mask is not None: - data["ipv4_mask"] = ipv4_mask - if ipv6_mask is not None: - data["ipv6_mask"] = ipv6_mask - if sequence_id is not None: - data["sequence_id"] = sequence_id - - try: - update_entry(db.cfgdb, table, key, data) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - -@PBH_HASH.command(name="delete") -@click.argument( - "hash-name", - nargs=1, - required=True, -) -@clicommon.pass_db -def PBH_HASH_delete(db, hash_name): - """ Delete object in PBH_HASH. """ - - table = "PBH_HASH" - key = hash_name - try: - del_entry(db.cfgdb, table, key) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - -@click.group(name="pbh-rule", - cls=clicommon.AliasedGroup) -def PBH_RULE(): - """ PBH_RULE part of config_db.json """ - - pass - - -@PBH_RULE.command(name="add") -@click.argument( - "table-name", - nargs=1, - required=True, -) -@click.argument( - "rule-name", - nargs=1, - required=True, -) -@click.option( - "--priority", - help="Configures priority for this rule[mandatory]", -) -@click.option( - "--gre-key", - help="Configures packet match for this rule: GRE key", -) -@click.option( - "--ip-protocol", - help="Configures packet match for this rule: IP protocol", -) -@click.option( - "--ipv6-next-header", - help="Configures packet match for this rule: IPv6 Next header", -) -@click.option( - "--l4-dst-port", - help="Configures packet match for this rule: L4 destination port", -) -@click.option( - "--inner-ether-type", - help="Configures packet match for this rule: inner EtherType", -) -@click.option( - "--packet-action", - help="Configures packet action for this rule", -) -@click.option( - "--flow-counter", - help="Enables/Disables packet/byte counter for this rule", -) -@click.option( - "--hash-list", - help="The list of hash fields to apply with this rule", -) -@clicommon.pass_db -def PBH_RULE_add(db, table_name, rule_name, priority, gre_key, ip_protocol, ipv6_next_header, l4_dst_port, inner_ether_type, packet_action, flow_counter, hash_list): - """ Add object in PBH_RULE. """ - - table = "PBH_RULE" - key = table_name, rule_name - data = {} - if priority is not None: - data["priority"] = priority - if gre_key is not None: - data["gre_key"] = gre_key - if ip_protocol is not None: - data["ip_protocol"] = ip_protocol - if ipv6_next_header is not None: - data["ipv6_next_header"] = ipv6_next_header - if l4_dst_port is not None: - data["l4_dst_port"] = l4_dst_port - if inner_ether_type is not None: - data["inner_ether_type"] = inner_ether_type - if packet_action is not None: - data["packet_action"] = packet_action - if flow_counter is not None: - data["flow_counter"] = flow_counter - if hash_list is not None: - data["hash_list"] = hash_list.split(",") - - try: - add_entry(db.cfgdb, table, key, data) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - -@PBH_RULE.command(name="update") -@click.argument( - "table-name", - nargs=1, - required=True, -) -@click.argument( - "rule-name", - nargs=1, - required=True, -) -@click.option( - "--priority", - help="Configures priority for this rule[mandatory]", -) -@click.option( - "--gre-key", - help="Configures packet match for this rule: GRE key", -) -@click.option( - "--ip-protocol", - help="Configures packet match for this rule: IP protocol", -) -@click.option( - "--ipv6-next-header", - help="Configures packet match for this rule: IPv6 Next header", -) -@click.option( - "--l4-dst-port", - help="Configures packet match for this rule: L4 destination port", -) -@click.option( - "--inner-ether-type", - help="Configures packet match for this rule: inner EtherType", -) -@click.option( - "--packet-action", - help="Configures packet action for this rule", -) -@click.option( - "--flow-counter", - help="Enables/Disables packet/byte counter for this rule", -) -@click.option( - "--hash-list", - help="The list of hash fields to apply with this rule", -) -@clicommon.pass_db -def PBH_RULE_update(db, table_name, rule_name, priority, gre_key, ip_protocol, ipv6_next_header, l4_dst_port, inner_ether_type, packet_action, flow_counter, hash_list): - """ Add object in PBH_RULE. """ - - table = "PBH_RULE" - key = table_name, rule_name - data = {} - if priority is not None: - data["priority"] = priority - if gre_key is not None: - data["gre_key"] = gre_key - if ip_protocol is not None: - data["ip_protocol"] = ip_protocol - if ipv6_next_header is not None: - data["ipv6_next_header"] = ipv6_next_header - if l4_dst_port is not None: - data["l4_dst_port"] = l4_dst_port - if inner_ether_type is not None: - data["inner_ether_type"] = inner_ether_type - if packet_action is not None: - data["packet_action"] = packet_action - if flow_counter is not None: - data["flow_counter"] = flow_counter - if hash_list is not None: - data["hash_list"] = hash_list.split(",") - - try: - update_entry(db.cfgdb, table, key, data) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - -@PBH_RULE.command(name="delete") -@click.argument( - "table-name", - nargs=1, - required=True, -) -@click.argument( - "rule-name", - nargs=1, - required=True, -) -@clicommon.pass_db -def PBH_RULE_delete(db, table_name, rule_name): - """ Delete object in PBH_RULE. """ - - table = "PBH_RULE" - key = table_name, rule_name - try: - del_entry(db.cfgdb, table, key) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - -@PBH_RULE.group(name="hash-list", - cls=clicommon.AliasedGroup) -def PBH_RULE_hash_list(): - """ Add/Delete hash_list in PBH_RULE """ - - pass - - -@PBH_RULE_hash_list.command(name="add") -@click.argument( - "table-name", - nargs=1, - required=True, -) -@click.argument( - "rule-name", - nargs=1, - required=True, -) -@click.argument( - "hash-list", - nargs=-1, - required=True, -) -@clicommon.pass_db -def PBH_RULE_hash_list_add( - db, - table_name, rule_name, hash_list -): - """ Add hash_list in PBH_RULE """ - - table = "PBH_RULE" - key = table_name, rule_name - attr = "hash_list" - data = hash_list - - try: - add_list_entry(db.cfgdb, table, key, attr, data) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - -@PBH_RULE_hash_list.command(name="delete") -@click.argument( - "table-name", - nargs=1, - required=True, -) -@click.argument( - "rule-name", - nargs=1, - required=True, -) -@click.argument( - "hash-list", - nargs=-1, - required=True, -) -@clicommon.pass_db -def PBH_RULE_hash_list_delete( - db, - table_name, rule_name, hash_list -): - """ Delete hash_list in PBH_RULE """ - - table = "PBH_RULE" - key = table_name, rule_name - attr = "hash_list" - data = hash_list - - try: - del_list_entry(db.cfgdb, table, key, attr, data) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - -@PBH_RULE_hash_list.command(name="clear") -@click.argument( - "table-name", - nargs=1, - required=True, -) -@click.argument( - "rule-name", - nargs=1, - required=True, -) -@clicommon.pass_db -def PBH_RULE_hash_list_clear( - db, - table_name, rule_name -): - """ Clear hash_list in PBH_RULE """ - - table = "PBH_RULE" - key = table_name, rule_name - attr = "hash_list" - - try: - clear_list_entry(db.cfgdb, table, key, attr) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - -@click.group(name="pbh-table", - cls=clicommon.AliasedGroup) -def PBH_TABLE(): - """ PBH_TABLE part of config_db.json """ - - pass - - -@PBH_TABLE.command(name="add") -@click.argument( - "table-name", - nargs=1, - required=True, -) -@click.option( - "--description", - help="The description of this table[mandatory]", -) -@click.option( - "--interface-list", - help="Interfaces to which this table is applied", -) -@clicommon.pass_db -def PBH_TABLE_add(db, table_name, description, interface_list): - """ Add object in PBH_TABLE. """ - - table = "PBH_TABLE" - key = table_name - data = {} - if description is not None: - data["description"] = description - if interface_list is not None: - data["interface_list"] = interface_list.split(",") - - try: - add_entry(db.cfgdb, table, key, data) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - -@PBH_TABLE.command(name="update") -@click.argument( - "table-name", - nargs=1, - required=True, -) -@click.option( - "--description", - help="The description of this table[mandatory]", -) -@click.option( - "--interface-list", - help="Interfaces to which this table is applied", -) -@clicommon.pass_db -def PBH_TABLE_update(db, table_name, description, interface_list): - """ Add object in PBH_TABLE. """ - - table = "PBH_TABLE" - key = table_name - data = {} - if description is not None: - data["description"] = description - if interface_list is not None: - data["interface_list"] = interface_list.split(",") - - try: - update_entry(db.cfgdb, table, key, data) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - -@PBH_TABLE.command(name="delete") -@click.argument( - "table-name", - nargs=1, - required=True, -) -@clicommon.pass_db -def PBH_TABLE_delete(db, table_name): - """ Delete object in PBH_TABLE. """ - - table = "PBH_TABLE" - key = table_name - try: - del_entry(db.cfgdb, table, key) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - -@PBH_TABLE.group(name="interface-list", - cls=clicommon.AliasedGroup) -def PBH_TABLE_interface_list(): - """ Add/Delete interface_list in PBH_TABLE """ - - pass - - -@PBH_TABLE_interface_list.command(name="add") -@click.argument( - "table-name", - nargs=1, - required=True, -) -@click.argument( - "interface-list", - nargs=-1, - required=True, -) -@clicommon.pass_db -def PBH_TABLE_interface_list_add( - db, - table_name, interface_list -): - """ Add interface_list in PBH_TABLE """ - - table = "PBH_TABLE" - key = table_name - attr = "interface_list" - data = interface_list - - try: - add_list_entry(db.cfgdb, table, key, attr, data) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - -@PBH_TABLE_interface_list.command(name="delete") -@click.argument( - "table-name", - nargs=1, - required=True, -) -@click.argument( - "interface-list", - nargs=-1, - required=True, -) -@clicommon.pass_db -def PBH_TABLE_interface_list_delete( - db, - table_name, interface_list -): - """ Delete interface_list in PBH_TABLE """ - - table = "PBH_TABLE" - key = table_name - attr = "interface_list" - data = interface_list - - try: - del_list_entry(db.cfgdb, table, key, attr, data) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - -@PBH_TABLE_interface_list.command(name="clear") -@click.argument( - "table-name", - nargs=1, - required=True, -) -@clicommon.pass_db -def PBH_TABLE_interface_list_clear( - db, - table_name -): - """ Clear interface_list in PBH_TABLE """ - - table = "PBH_TABLE" - key = table_name - attr = "interface_list" - - try: - clear_list_entry(db.cfgdb, table, key, attr) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - -def register(cli): - cli_node = PBH_HASH - if cli_node.name in cli.commands: - raise Exception(f"{cli_node.name} already exists in CLI") - cli.add_command(PBH_HASH) - cli_node = PBH_RULE - if cli_node.name in cli.commands: - raise Exception(f"{cli_node.name} already exists in CLI") - cli.add_command(PBH_RULE) - cli_node = PBH_TABLE - if cli_node.name in cli.commands: - raise Exception(f"{cli_node.name} already exists in CLI") - cli.add_command(PBH_TABLE) diff --git a/show/plugins/sonic-pbh_yang.py b/show/plugins/sonic-pbh_yang.py index 0051106e52..9cf04d0a2a 100644 --- a/show/plugins/sonic-pbh_yang.py +++ b/show/plugins/sonic-pbh_yang.py @@ -1,5 +1,9 @@ """ -Auto-generated show CLI plugin. +This CLI plugin was auto-generated by using 'sonic-cli-gen' utility, BUT +it was manually modified to meet the PBH HLD requirements. + +PBH HLD - https://github.com/Azure/SONiC/pull/773 +CLI Auto-generation tool HLD - https://github.com/Azure/SONiC/pull/78 """ import click @@ -7,6 +11,7 @@ import natsort import utilities_common.cli as clicommon + def format_attr_value(entry, attr): """ Helper that formats attribute to be presented in the table output. @@ -22,6 +27,7 @@ def format_attr_value(entry, attr): return "\n".join(entry.get(attr["name"], [])) return entry.get(attr["name"], "N/A") + def format_group_value(entry, attrs): """ Helper that formats grouped attribute to be presented in the table output. @@ -39,24 +45,24 @@ def format_group_value(entry, attrs): data.append((attr["name"] + ":", format_attr_value(entry, attr))) return tabulate.tabulate(data, tablefmt="plain") -@click.group(name="pbh-hash", + +@click.group(name="pbh-hash-field", cls=clicommon.AliasedGroup, invoke_without_command=True) @clicommon.pass_db -def PBH_HASH(db): +def PBH_HASH_FIELD(db): """ [Callable command group] """ header = [ - "HASH NAME", + "HASH FIELD NAME", "HASH FIELD", - "IPV4 MASK", - "IPV6 MASK", + "IP MASK", "SEQUENCE ID", ] body = [] - table = db.cfgdb.get_table("PBH_HASH") + table = db.cfgdb.get_table("PBH_HASH_FIELD") for key in natsort.natsorted(table): entry = table[key] if not isinstance(key, tuple): @@ -66,38 +72,67 @@ def PBH_HASH(db): format_attr_value( entry, {'name': 'hash_field', - 'description': 'Configures native hash field for this hash', + 'description': 'Configures native hash field for this hash field', 'is-leaf-list': False, 'is-mandatory': True, 'group': ''} ), format_attr_value( entry, - {'name': 'ipv4_mask', - 'description': 'Configures IPv4 address mask for this hash', + {'name': 'ip_mask', + 'description': 'Configures IPv4/IPv6 address mask for this hash field', 'is-leaf-list': False, 'is-mandatory': True, 'group': ''} ), format_attr_value( entry, - {'name': 'ipv6_mask', - 'description': 'Configures IPv6 address mask for this hash', + {'name': 'sequence_id', + 'description': 'Configures in which order the fields are hashed and defines which fields should be associative', 'is-leaf-list': False, 'is-mandatory': True, 'group': ''} ), + ] + + body.append(row) + + click.echo(tabulate.tabulate(body, header)) + + +@click.group(name="pbh-hash", + cls=clicommon.AliasedGroup, + invoke_without_command=True) +@clicommon.pass_db +def PBH_HASH(db): + """ [Callable command group] """ + + header = [ + "HASH NAME", + "HASH FIELD LIST", + ] + + body = [] + + table = db.cfgdb.get_table("PBH_HASH") + for key in natsort.natsorted(table): + entry = table[key] + if not isinstance(key, tuple): + key = (key,) + + row = [*key] + [ format_attr_value( entry, - {'name': 'sequence_id', - 'description': 'Configures in which order the fields are hashed and defines which fields should be associative', - 'is-leaf-list': False, - 'is-mandatory': True, + {'name': 'hash_field_list', + 'description': 'The list of hash fields to apply with this hash', + 'is-leaf-list': True, + 'is-mandatory': False, 'group': ''} ), ] - body.append(row) + body.append(row) + click.echo(tabulate.tabulate(body, header)) @@ -117,9 +152,9 @@ def PBH_RULE(db): "IPV6 NEXT HEADER", "L4 DST PORT", "INNER ETHER TYPE", + "HASH", "PACKET ACTION", "FLOW COUNTER", - "HASH LIST", ] body = [] @@ -142,14 +177,15 @@ def PBH_RULE(db): format_attr_value( entry, {'name': 'gre_key', - 'description': 'Configures packet match for this rule: GRE key', + 'description': 'Configures packet match for this rule: GRE key (value/mask)', 'is-leaf-list': False, - 'is-mandatory': False, 'group': ''} + 'is-mandatory': False, + 'group': ''} ), format_attr_value( entry, {'name': 'ip_protocol', - 'description': 'Configures packet match for this rule: IP protocol', + 'description': 'Configures packet match for this rule: IP protocol (value/mask)', 'is-leaf-list': False, 'is-mandatory': False, 'group': ''} @@ -157,7 +193,7 @@ def PBH_RULE(db): format_attr_value( entry, {'name': 'ipv6_next_header', - 'description': 'Configures packet match for this rule: IPv6 Next header', + 'description': 'Configures packet match for this rule: IPv6 Next header (value/mask)', 'is-leaf-list': False, 'is-mandatory': False, 'group': ''} @@ -165,7 +201,7 @@ def PBH_RULE(db): format_attr_value( entry, {'name': 'l4_dst_port', - 'description':'Configures packet match for this rule: L4 destination port', + 'description': 'Configures packet match for this rule: L4 destination port (value/mask)', 'is-leaf-list': False, 'is-mandatory': False, 'group': ''} @@ -173,11 +209,16 @@ def PBH_RULE(db): format_attr_value( entry, {'name': 'inner_ether_type', - 'description': 'Configures packet match for this rule: inner EtherType', + 'description': 'Configures packet match for this rule: inner EtherType (value/mask)', 'is-leaf-list': False, 'is-mandatory': False, 'group': ''} ), + format_attr_value( + entry, + {'name': 'hash', + 'description': 'The hash to apply with this rule', 'is-leaf-list': False, 'is-mandatory': True, 'group': ''} + ), format_attr_value( entry, {'name': 'packet_action', @@ -194,17 +235,10 @@ def PBH_RULE(db): 'is-mandatory': False, 'group': ''} ), - format_attr_value( - entry, - {'name': 'hash_list', - 'description': 'The list of hash fields to apply with this rule', - 'is-leaf-list': True, - 'is-mandatory': False, - 'group': ''} - ), ] - body.append(row) + body.append(row) + click.echo(tabulate.tabulate(body, header)) @@ -235,7 +269,7 @@ def PBH_TABLE(db): {'name': 'description', 'description': 'The description of this table', 'is-leaf-list': False, - 'is-mandatory': True, + 'is-mandatory': True, 'group': ''} ), format_attr_value( @@ -248,11 +282,16 @@ def PBH_TABLE(db): ), ] - body.append(row) + body.append(row) + click.echo(tabulate.tabulate(body, header)) def register(cli): + cli_node = PBH_HASH_FIELD + if cli_node.name in cli.commands: + raise Exception(f"{cli_node.name} already exists in CLI") + cli.add_command(PBH_HASH_FIELD) cli_node = PBH_HASH if cli_node.name in cli.commands: raise Exception(f"{cli_node.name} already exists in CLI") @@ -264,4 +303,4 @@ def register(cli): cli_node = PBH_TABLE if cli_node.name in cli.commands: raise Exception(f"{cli_node.name} already exists in CLI") - cli.add_command(PBH_TABLE) + cli.add_command(PBH_TABLE) \ No newline at end of file From c5fe537bdf4aaca0f7777fe71c3539c2a5383213 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Mon, 7 Jun 2021 09:19:53 +0000 Subject: [PATCH 04/79] Added generated config CLI for PBH Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 953 +++++++++++++++++++++++++++++++ 1 file changed, 953 insertions(+) create mode 100644 config/plugins/sonic-pbh_yang.py diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py new file mode 100644 index 0000000000..53ea923567 --- /dev/null +++ b/config/plugins/sonic-pbh_yang.py @@ -0,0 +1,953 @@ +""" +Autogenerated config CLI plugin. + + +""" + +import click +import utilities_common.cli as clicommon +import utilities_common.general as general +from config import config_mgmt + + +# Load sonic-cfggen from source since /usr/local/bin/sonic-cfggen does not have .py extension. +sonic_cfggen = general.load_module_from_source('sonic_cfggen', '/usr/local/bin/sonic-cfggen') + + +def exit_with_error(*args, **kwargs): + """ Print a message and abort CLI. """ + + click.secho(*args, **kwargs) + raise click.Abort() + + +def validate_config_or_raise(cfg): + """ Validate config db data using ConfigMgmt """ + + try: + cfg = sonic_cfggen.FormatConverter.to_serialized(cfg) + config_mgmt.ConfigMgmt().loadData(cfg) + except Exception as err: + raise Exception('Failed to validate configuration: {}'.format(err)) + + +def add_entry_validated(db, table, key, data): + """ Add new entry in table and validate configuration """ + + cfg = db.get_config() + cfg.setdefault(table, {}) + if key in cfg[table]: + raise Exception(f"{key} already exists") + + cfg[table][key] = data + + validate_config_or_raise(cfg) + db.set_entry(table, key, data) + + +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. + """ + + cfg = db.get_config() + cfg.setdefault(table, {}) + + if create_if_not_exists: + cfg[table].setdefault(key, {}) + + if key not in cfg[table]: + raise Exception(f"{key} does not exist") + + for attr, value in data.items(): + if value is None and attr in cfg[table][key]: + cfg[table][key].pop(attr) + else: + cfg[table][key][attr] = value + + validate_config_or_raise(cfg) + db.set_entry(table, key, cfg[table][key]) + + +def del_entry_validated(db, table, key): + """ Delete entry in table and validate configuration """ + + cfg = db.get_config() + cfg.setdefault(table, {}) + if key not in cfg[table]: + raise Exception(f"{key} does not exist") + + cfg[table].pop(key) + + validate_config_or_raise(cfg) + db.set_entry(table, key, None) + + +def add_list_entry_validated(db, table, key, attr, data): + """ Add new entry into list in table and validate configuration""" + + cfg = db.get_config() + cfg.setdefault(table, {}) + if key not in cfg[table]: + raise Exception(f"{key} does not exist") + cfg[table][key].setdefault(attr, []) + for entry in data: + if entry in cfg[table][key][attr]: + raise Exception(f"{entry} already exists") + cfg[table][key][attr].append(entry) + + validate_config_or_raise(cfg) + db.set_entry(table, key, cfg[table][key]) + + +def del_list_entry_validated(db, table, key, attr, data): + """ Delete entry from list in table and validate configuration""" + + cfg = db.get_config() + cfg.setdefault(table, {}) + if key not in cfg[table]: + raise Exception(f"{key} does not exist") + cfg[table][key].setdefault(attr, []) + for entry in data: + if entry not in cfg[table][key][attr]: + raise Exception(f"{entry} does not exist") + cfg[table][key][attr].remove(entry) + if not cfg[table][key][attr]: + cfg[table][key].pop(attr) + + validate_config_or_raise(cfg) + db.set_entry(table, key, cfg[table][key]) + + +def clear_list_entry_validated(db, table, key, attr): + """ Clear list in object and validate configuration""" + + update_entry_validated(db, table, key, {attr: None}) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +@click.group(name="pbh-hash-field", + cls=clicommon.AliasedGroup) +def PBH_HASH_FIELD(): + """ PBH_HASH_FIELD part of config_db.json """ + + pass + + + + + + + + + + + + +@PBH_HASH_FIELD.command(name="add") + +@click.argument( + "hash-field-name", + nargs=1, + required=True, +) + +@click.option( + "--hash-field", + help="Configures native hash field for this hash field[mandatory]", +) +@click.option( + "--ip-mask", + help="Configures IPv4/IPv6 address mask for this hash field[mandatory]", +) +@click.option( + "--sequence-id", + help="Configures in which order the fields are hashed and defines which fields should be associative[mandatory]", +) +@clicommon.pass_db +def PBH_HASH_FIELD_add(db, hash_field_name, hash_field, ip_mask, sequence_id): + """ Add object in PBH_HASH_FIELD. """ + + table = "PBH_HASH_FIELD" + key = hash_field_name + data = {} + if hash_field is not None: + data["hash_field"] = hash_field + if ip_mask is not None: + data["ip_mask"] = ip_mask + if sequence_id is not None: + data["sequence_id"] = sequence_id + + try: + add_entry_validated(db.cfgdb, table, key, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@PBH_HASH_FIELD.command(name="update") + +@click.argument( + "hash-field-name", + nargs=1, + required=True, +) + +@click.option( + "--hash-field", + help="Configures native hash field for this hash field[mandatory]", +) +@click.option( + "--ip-mask", + help="Configures IPv4/IPv6 address mask for this hash field[mandatory]", +) +@click.option( + "--sequence-id", + help="Configures in which order the fields are hashed and defines which fields should be associative[mandatory]", +) +@clicommon.pass_db +def PBH_HASH_FIELD_update(db, hash_field_name, hash_field, ip_mask, sequence_id): + """ Add object in PBH_HASH_FIELD. """ + + table = "PBH_HASH_FIELD" + key = hash_field_name + data = {} + if hash_field is not None: + data["hash_field"] = hash_field + if ip_mask is not None: + data["ip_mask"] = ip_mask + if sequence_id is not None: + data["sequence_id"] = sequence_id + + try: + update_entry_validated(db.cfgdb, table, key, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@PBH_HASH_FIELD.command(name="delete") + +@click.argument( + "hash-field-name", + nargs=1, + required=True, +) +@clicommon.pass_db +def PBH_HASH_FIELD_delete(db, hash_field_name): + """ Delete object in PBH_HASH_FIELD. """ + + table = "PBH_HASH_FIELD" + key = hash_field_name + try: + del_entry_validated(db.cfgdb, table, key) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + + + + + + + + + + + + + + +@click.group(name="pbh-hash", + cls=clicommon.AliasedGroup) +def PBH_HASH(): + """ PBH_HASH part of config_db.json """ + + pass + + + + + + + + + + + + +@PBH_HASH.command(name="add") + +@click.argument( + "hash-name", + nargs=1, + required=True, +) + +@click.option( + "--hash-field-list", + help="The list of hash fields to apply with this hash", +) +@clicommon.pass_db +def PBH_HASH_add(db, hash_name, hash_field_list): + """ Add object in PBH_HASH. """ + + table = "PBH_HASH" + key = hash_name + data = {} + if hash_field_list is not None: + data["hash_field_list"] = hash_field_list.split(",") + + try: + add_entry_validated(db.cfgdb, table, key, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@PBH_HASH.command(name="update") + +@click.argument( + "hash-name", + nargs=1, + required=True, +) + +@click.option( + "--hash-field-list", + help="The list of hash fields to apply with this hash", +) +@clicommon.pass_db +def PBH_HASH_update(db, hash_name, hash_field_list): + """ Add object in PBH_HASH. """ + + table = "PBH_HASH" + key = hash_name + data = {} + if hash_field_list is not None: + data["hash_field_list"] = hash_field_list.split(",") + + try: + update_entry_validated(db.cfgdb, table, key, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@PBH_HASH.command(name="delete") + +@click.argument( + "hash-name", + nargs=1, + required=True, +) +@clicommon.pass_db +def PBH_HASH_delete(db, hash_name): + """ Delete object in PBH_HASH. """ + + table = "PBH_HASH" + key = hash_name + try: + del_entry_validated(db.cfgdb, table, key) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + + + + + + +@PBH_HASH.group(name="hash-field-list", + cls=clicommon.AliasedGroup) +def PBH_HASH_hash_field_list(): + """ Add/Delete hash_field_list in PBH_HASH """ + + pass + + +@PBH_HASH_hash_field_list.command(name="add") + +@click.argument( + "hash-name", + nargs=1, + required=True, +) +@click.argument( + "hash-field-list", + nargs=-1, + required=True, +) +@clicommon.pass_db +def PBH_HASH_hash_field_list_add( + db, + hash_name, hash_field_list +): + """ Add hash_field_list in PBH_HASH """ + + table = "PBH_HASH" + key = hash_name + attr = "hash_field_list" + data = hash_field_list + + try: + add_list_entry_validated(db.cfgdb, table, key, attr, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + + +@PBH_HASH_hash_field_list.command(name="delete") + +@click.argument( + "hash-name", + nargs=1, + required=True, +) +@click.argument( + "hash-field-list", + nargs=-1, + required=True, +) +@clicommon.pass_db +def PBH_HASH_hash_field_list_delete( + db, + hash_name, hash_field_list +): + """ Delete hash_field_list in PBH_HASH """ + + table = "PBH_HASH" + key = hash_name + attr = "hash_field_list" + data = hash_field_list + + try: + del_list_entry_validated(db.cfgdb, table, key, attr, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + + +@PBH_HASH_hash_field_list.command(name="clear") + +@click.argument( + "hash-name", + nargs=1, + required=True, +) +@clicommon.pass_db +def PBH_HASH_hash_field_list_clear( + db, + hash_name +): + """ Clear hash_field_list in PBH_HASH """ + + table = "PBH_HASH" + key = hash_name + attr = "hash_field_list" + + try: + clear_list_entry_validated(db.cfgdb, table, key, attr) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + + + + + + + + + +@click.group(name="pbh-rule", + cls=clicommon.AliasedGroup) +def PBH_RULE(): + """ PBH_RULE part of config_db.json """ + + pass + + + + + + + + + + + + +@PBH_RULE.command(name="add") + +@click.argument( + "table-name", + nargs=1, + required=True, +) +@click.argument( + "rule-name", + nargs=1, + required=True, +) + +@click.option( + "--priority", + help="Configures priority for this rule[mandatory]", +) +@click.option( + "--gre-key", + help="Configures packet match for this rule: GRE key (value/mask)", +) +@click.option( + "--ip-protocol", + help="Configures packet match for this rule: IP protocol (value/mask)", +) +@click.option( + "--ipv6-next-header", + help="Configures packet match for this rule: IPv6 Next header (value/mask)", +) +@click.option( + "--l4-dst-port", + help="Configures packet match for this rule: L4 destination port (value/mask)", +) +@click.option( + "--inner-ether-type", + help="Configures packet match for this rule: inner EtherType (value/mask)", +) +@click.option( + "--hash", + help="The hash to apply with this rule[mandatory]", +) +@click.option( + "--packet-action", + help="Configures packet action for this rule", +) +@click.option( + "--flow-counter", + help="Enables/Disables packet/byte counter for this rule", +) +@clicommon.pass_db +def PBH_RULE_add(db, table_name, rule_name, priority, gre_key, ip_protocol, ipv6_next_header, l4_dst_port, inner_ether_type, hash, packet_action, flow_counter): + """ Add object in PBH_RULE. """ + + table = "PBH_RULE" + key = table_name, rule_name + data = {} + if priority is not None: + data["priority"] = priority + if gre_key is not None: + data["gre_key"] = gre_key + if ip_protocol is not None: + data["ip_protocol"] = ip_protocol + if ipv6_next_header is not None: + data["ipv6_next_header"] = ipv6_next_header + if l4_dst_port is not None: + data["l4_dst_port"] = l4_dst_port + if inner_ether_type is not None: + data["inner_ether_type"] = inner_ether_type + if hash is not None: + data["hash"] = hash + if packet_action is not None: + data["packet_action"] = packet_action + if flow_counter is not None: + data["flow_counter"] = flow_counter + + try: + add_entry_validated(db.cfgdb, table, key, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@PBH_RULE.command(name="update") + +@click.argument( + "table-name", + nargs=1, + required=True, +) +@click.argument( + "rule-name", + nargs=1, + required=True, +) + +@click.option( + "--priority", + help="Configures priority for this rule[mandatory]", +) +@click.option( + "--gre-key", + help="Configures packet match for this rule: GRE key (value/mask)", +) +@click.option( + "--ip-protocol", + help="Configures packet match for this rule: IP protocol (value/mask)", +) +@click.option( + "--ipv6-next-header", + help="Configures packet match for this rule: IPv6 Next header (value/mask)", +) +@click.option( + "--l4-dst-port", + help="Configures packet match for this rule: L4 destination port (value/mask)", +) +@click.option( + "--inner-ether-type", + help="Configures packet match for this rule: inner EtherType (value/mask)", +) +@click.option( + "--hash", + help="The hash to apply with this rule[mandatory]", +) +@click.option( + "--packet-action", + help="Configures packet action for this rule", +) +@click.option( + "--flow-counter", + help="Enables/Disables packet/byte counter for this rule", +) +@clicommon.pass_db +def PBH_RULE_update(db, table_name, rule_name, priority, gre_key, ip_protocol, ipv6_next_header, l4_dst_port, inner_ether_type, hash, packet_action, flow_counter): + """ Add object in PBH_RULE. """ + + table = "PBH_RULE" + key = table_name, rule_name + data = {} + if priority is not None: + data["priority"] = priority + if gre_key is not None: + data["gre_key"] = gre_key + if ip_protocol is not None: + data["ip_protocol"] = ip_protocol + if ipv6_next_header is not None: + data["ipv6_next_header"] = ipv6_next_header + if l4_dst_port is not None: + data["l4_dst_port"] = l4_dst_port + if inner_ether_type is not None: + data["inner_ether_type"] = inner_ether_type + if hash is not None: + data["hash"] = hash + if packet_action is not None: + data["packet_action"] = packet_action + if flow_counter is not None: + data["flow_counter"] = flow_counter + + try: + update_entry_validated(db.cfgdb, table, key, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@PBH_RULE.command(name="delete") + +@click.argument( + "table-name", + nargs=1, + required=True, +) +@click.argument( + "rule-name", + nargs=1, + required=True, +) +@clicommon.pass_db +def PBH_RULE_delete(db, table_name, rule_name): + """ Delete object in PBH_RULE. """ + + table = "PBH_RULE" + key = table_name, rule_name + try: + del_entry_validated(db.cfgdb, table, key) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + + + + + + + + + + + + + + + + + + + + + + + + + + +@click.group(name="pbh-table", + cls=clicommon.AliasedGroup) +def PBH_TABLE(): + """ PBH_TABLE part of config_db.json """ + + pass + + + + + + + + + + + + +@PBH_TABLE.command(name="add") + +@click.argument( + "table-name", + nargs=1, + required=True, +) + +@click.option( + "--description", + help="The description of this table[mandatory]", +) +@click.option( + "--interface-list", + help="Interfaces to which this table is applied", +) +@clicommon.pass_db +def PBH_TABLE_add(db, table_name, description, interface_list): + """ Add object in PBH_TABLE. """ + + table = "PBH_TABLE" + key = table_name + data = {} + if description is not None: + data["description"] = description + if interface_list is not None: + data["interface_list"] = interface_list.split(",") + + try: + add_entry_validated(db.cfgdb, table, key, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@PBH_TABLE.command(name="update") + +@click.argument( + "table-name", + nargs=1, + required=True, +) + +@click.option( + "--description", + help="The description of this table[mandatory]", +) +@click.option( + "--interface-list", + help="Interfaces to which this table is applied", +) +@clicommon.pass_db +def PBH_TABLE_update(db, table_name, description, interface_list): + """ Add object in PBH_TABLE. """ + + table = "PBH_TABLE" + key = table_name + data = {} + if description is not None: + data["description"] = description + if interface_list is not None: + data["interface_list"] = interface_list.split(",") + + try: + update_entry_validated(db.cfgdb, table, key, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + +@PBH_TABLE.command(name="delete") + +@click.argument( + "table-name", + nargs=1, + required=True, +) +@clicommon.pass_db +def PBH_TABLE_delete(db, table_name): + """ Delete object in PBH_TABLE. """ + + table = "PBH_TABLE" + key = table_name + try: + del_entry_validated(db.cfgdb, table, key) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + + + + + + + + +@PBH_TABLE.group(name="interface-list", + cls=clicommon.AliasedGroup) +def PBH_TABLE_interface_list(): + """ Add/Delete interface_list in PBH_TABLE """ + + pass + + +@PBH_TABLE_interface_list.command(name="add") + +@click.argument( + "table-name", + nargs=1, + required=True, +) +@click.argument( + "interface-list", + nargs=-1, + required=True, +) +@clicommon.pass_db +def PBH_TABLE_interface_list_add( + db, + table_name, interface_list +): + """ Add interface_list in PBH_TABLE """ + + table = "PBH_TABLE" + key = table_name + attr = "interface_list" + data = interface_list + + try: + add_list_entry_validated(db.cfgdb, table, key, attr, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + + +@PBH_TABLE_interface_list.command(name="delete") + +@click.argument( + "table-name", + nargs=1, + required=True, +) +@click.argument( + "interface-list", + nargs=-1, + required=True, +) +@clicommon.pass_db +def PBH_TABLE_interface_list_delete( + db, + table_name, interface_list +): + """ Delete interface_list in PBH_TABLE """ + + table = "PBH_TABLE" + key = table_name + attr = "interface_list" + data = interface_list + + try: + del_list_entry_validated(db.cfgdb, table, key, attr, data) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + + +@PBH_TABLE_interface_list.command(name="clear") + +@click.argument( + "table-name", + nargs=1, + required=True, +) +@clicommon.pass_db +def PBH_TABLE_interface_list_clear( + db, + table_name +): + """ Clear interface_list in PBH_TABLE """ + + table = "PBH_TABLE" + key = table_name + attr = "interface_list" + + try: + clear_list_entry_validated(db.cfgdb, table, key, attr) + except Exception as err: + exit_with_error(f"Error: {err}", fg="red") + + + + + + + + + + + +def register(cli): + cli_node = PBH_HASH_FIELD + if cli_node.name in cli.commands: + raise Exception(f"{cli_node.name} already exists in CLI") + cli.add_command(PBH_HASH_FIELD) + cli_node = PBH_HASH + if cli_node.name in cli.commands: + raise Exception(f"{cli_node.name} already exists in CLI") + cli.add_command(PBH_HASH) + cli_node = PBH_RULE + if cli_node.name in cli.commands: + raise Exception(f"{cli_node.name} already exists in CLI") + cli.add_command(PBH_RULE) + cli_node = PBH_TABLE + if cli_node.name in cli.commands: + raise Exception(f"{cli_node.name} already exists in CLI") + cli.add_command(PBH_TABLE) \ No newline at end of file From 77754cf09e28f7479884859100a3e1c3ea08309e Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Mon, 7 Jun 2021 09:28:00 +0000 Subject: [PATCH 05/79] Fixed codestyle for config Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 313 +++++++------------------------ 1 file changed, 64 insertions(+), 249 deletions(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index 53ea923567..beef53b74c 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -1,17 +1,14 @@ """ -Autogenerated config CLI plugin. - +This CLI plugin was auto-generated by using 'sonic-cli-gen' utility, BUT +it was manually modified to meet the PBH HLD requirements. +PBH HLD - https://github.com/Azure/SONiC/pull/773 +CLI Auto-generation tool HLD - https://github.com/Azure/SONiC/pull/78 """ import click import utilities_common.cli as clicommon import utilities_common.general as general -from config import config_mgmt - - -# Load sonic-cfggen from source since /usr/local/bin/sonic-cfggen does not have .py extension. -sonic_cfggen = general.load_module_from_source('sonic_cfggen', '/usr/local/bin/sonic-cfggen') def exit_with_error(*args, **kwargs): @@ -21,18 +18,8 @@ def exit_with_error(*args, **kwargs): raise click.Abort() -def validate_config_or_raise(cfg): - """ Validate config db data using ConfigMgmt """ - - try: - cfg = sonic_cfggen.FormatConverter.to_serialized(cfg) - config_mgmt.ConfigMgmt().loadData(cfg) - except Exception as err: - raise Exception('Failed to validate configuration: {}'.format(err)) - - -def add_entry_validated(db, table, key, data): - """ Add new entry in table and validate configuration """ +def add_entry(db, table, key, data): + """ Add new entry in table """ cfg = db.get_config() cfg.setdefault(table, {}) @@ -41,11 +28,10 @@ def add_entry_validated(db, table, key, data): cfg[table][key] = data - validate_config_or_raise(cfg) db.set_entry(table, key, data) -def update_entry_validated(db, table, key, data, create_if_not_exists=False): +def update_entry(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. """ @@ -65,12 +51,11 @@ def update_entry_validated(db, table, key, data, create_if_not_exists=False): else: cfg[table][key][attr] = value - validate_config_or_raise(cfg) db.set_entry(table, key, cfg[table][key]) -def del_entry_validated(db, table, key): - """ Delete entry in table and validate configuration """ +def del_entry(db, table, key): + """ Delete entry in table """ cfg = db.get_config() cfg.setdefault(table, {}) @@ -79,11 +64,10 @@ def del_entry_validated(db, table, key): cfg[table].pop(key) - validate_config_or_raise(cfg) db.set_entry(table, key, None) -def add_list_entry_validated(db, table, key, attr, data): +def add_list_entry(db, table, key, attr, data): """ Add new entry into list in table and validate configuration""" cfg = db.get_config() @@ -96,11 +80,10 @@ def add_list_entry_validated(db, table, key, attr, data): raise Exception(f"{entry} already exists") cfg[table][key][attr].append(entry) - validate_config_or_raise(cfg) db.set_entry(table, key, cfg[table][key]) -def del_list_entry_validated(db, table, key, attr, data): +def del_list_entry(db, table, key, attr, data): """ Delete entry from list in table and validate configuration""" cfg = db.get_config() @@ -115,49 +98,13 @@ def del_list_entry_validated(db, table, key, attr, data): if not cfg[table][key][attr]: cfg[table][key].pop(attr) - validate_config_or_raise(cfg) db.set_entry(table, key, cfg[table][key]) -def clear_list_entry_validated(db, table, key, attr): +def clear_list_entry(db, table, key, attr): """ Clear list in object and validate configuration""" - update_entry_validated(db, table, key, {attr: None}) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + update_entry(db, table, key, {attr: None}) @click.group(name="pbh-hash-field", @@ -168,24 +115,12 @@ def PBH_HASH_FIELD(): pass - - - - - - - - - - @PBH_HASH_FIELD.command(name="add") - @click.argument( "hash-field-name", nargs=1, required=True, ) - @click.option( "--hash-field", help="Configures native hash field for this hash field[mandatory]", @@ -213,19 +148,17 @@ def PBH_HASH_FIELD_add(db, hash_field_name, hash_field, ip_mask, sequence_id): data["sequence_id"] = sequence_id try: - add_entry_validated(db.cfgdb, table, key, data) + add_entry(db.cfgdb, table, key, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @PBH_HASH_FIELD.command(name="update") - @click.argument( "hash-field-name", nargs=1, required=True, ) - @click.option( "--hash-field", help="Configures native hash field for this hash field[mandatory]", @@ -253,13 +186,12 @@ def PBH_HASH_FIELD_update(db, hash_field_name, hash_field, ip_mask, sequence_id) data["sequence_id"] = sequence_id try: - update_entry_validated(db.cfgdb, table, key, data) + update_entry(db.cfgdb, table, key, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @PBH_HASH_FIELD.command(name="delete") - @click.argument( "hash-field-name", nargs=1, @@ -272,24 +204,11 @@ def PBH_HASH_FIELD_delete(db, hash_field_name): table = "PBH_HASH_FIELD" key = hash_field_name try: - del_entry_validated(db.cfgdb, table, key) + del_entry(db.cfgdb, table, key) except Exception as err: exit_with_error(f"Error: {err}", fg="red") - - - - - - - - - - - - - @click.group(name="pbh-hash", cls=clicommon.AliasedGroup) def PBH_HASH(): @@ -298,24 +217,12 @@ def PBH_HASH(): pass - - - - - - - - - - @PBH_HASH.command(name="add") - @click.argument( "hash-name", nargs=1, required=True, ) - @click.option( "--hash-field-list", help="The list of hash fields to apply with this hash", @@ -331,19 +238,17 @@ def PBH_HASH_add(db, hash_name, hash_field_list): data["hash_field_list"] = hash_field_list.split(",") try: - add_entry_validated(db.cfgdb, table, key, data) + add_entry(db.cfgdb, table, key, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @PBH_HASH.command(name="update") - @click.argument( "hash-name", nargs=1, required=True, ) - @click.option( "--hash-field-list", help="The list of hash fields to apply with this hash", @@ -359,13 +264,12 @@ def PBH_HASH_update(db, hash_name, hash_field_list): data["hash_field_list"] = hash_field_list.split(",") try: - update_entry_validated(db.cfgdb, table, key, data) + update_entry(db.cfgdb, table, key, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @PBH_HASH.command(name="delete") - @click.argument( "hash-name", nargs=1, @@ -378,18 +282,13 @@ def PBH_HASH_delete(db, hash_name): table = "PBH_HASH" key = hash_name try: - del_entry_validated(db.cfgdb, table, key) + del_entry(db.cfgdb, table, key) except Exception as err: exit_with_error(f"Error: {err}", fg="red") - - - - - @PBH_HASH.group(name="hash-field-list", - cls=clicommon.AliasedGroup) + cls=clicommon.AliasedGroup) def PBH_HASH_hash_field_list(): """ Add/Delete hash_field_list in PBH_HASH """ @@ -397,7 +296,6 @@ def PBH_HASH_hash_field_list(): @PBH_HASH_hash_field_list.command(name="add") - @click.argument( "hash-name", nargs=1, @@ -409,10 +307,7 @@ def PBH_HASH_hash_field_list(): required=True, ) @clicommon.pass_db -def PBH_HASH_hash_field_list_add( - db, - hash_name, hash_field_list -): +def PBH_HASH_hash_field_list_add(db, hash_name, hash_field_list): """ Add hash_field_list in PBH_HASH """ table = "PBH_HASH" @@ -421,14 +316,12 @@ def PBH_HASH_hash_field_list_add( data = hash_field_list try: - add_list_entry_validated(db.cfgdb, table, key, attr, data) + add_list_entry(db.cfgdb, table, key, attr, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") - @PBH_HASH_hash_field_list.command(name="delete") - @click.argument( "hash-name", nargs=1, @@ -440,10 +333,7 @@ def PBH_HASH_hash_field_list_add( required=True, ) @clicommon.pass_db -def PBH_HASH_hash_field_list_delete( - db, - hash_name, hash_field_list -): +def PBH_HASH_hash_field_list_delete(db, hash_name, hash_field_list): """ Delete hash_field_list in PBH_HASH """ table = "PBH_HASH" @@ -452,24 +342,19 @@ def PBH_HASH_hash_field_list_delete( data = hash_field_list try: - del_list_entry_validated(db.cfgdb, table, key, attr, data) + del_list_entry(db.cfgdb, table, key, attr, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") - @PBH_HASH_hash_field_list.command(name="clear") - @click.argument( "hash-name", nargs=1, required=True, ) @clicommon.pass_db -def PBH_HASH_hash_field_list_clear( - db, - hash_name -): +def PBH_HASH_hash_field_list_clear(db, hash_name): """ Clear hash_field_list in PBH_HASH """ table = "PBH_HASH" @@ -477,19 +362,11 @@ def PBH_HASH_hash_field_list_clear( attr = "hash_field_list" try: - clear_list_entry_validated(db.cfgdb, table, key, attr) + clear_list_entry(db.cfgdb, table, key, attr) except Exception as err: exit_with_error(f"Error: {err}", fg="red") - - - - - - - - @click.group(name="pbh-rule", cls=clicommon.AliasedGroup) def PBH_RULE(): @@ -498,18 +375,7 @@ def PBH_RULE(): pass - - - - - - - - - - @PBH_RULE.command(name="add") - @click.argument( "table-name", nargs=1, @@ -520,7 +386,6 @@ def PBH_RULE(): nargs=1, required=True, ) - @click.option( "--priority", help="Configures priority for this rule[mandatory]", @@ -558,7 +423,18 @@ def PBH_RULE(): help="Enables/Disables packet/byte counter for this rule", ) @clicommon.pass_db -def PBH_RULE_add(db, table_name, rule_name, priority, gre_key, ip_protocol, ipv6_next_header, l4_dst_port, inner_ether_type, hash, packet_action, flow_counter): +def PBH_RULE_add(db, + table_name, + rule_name, + priority, + gre_key, + ip_protocol, + ipv6_next_header, + l4_dst_port, + inner_ether_type, + hash, + packet_action, + flow_counter): """ Add object in PBH_RULE. """ table = "PBH_RULE" @@ -584,13 +460,12 @@ def PBH_RULE_add(db, table_name, rule_name, priority, gre_key, ip_protocol, ipv6 data["flow_counter"] = flow_counter try: - add_entry_validated(db.cfgdb, table, key, data) + add_entry(db.cfgdb, table, key, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @PBH_RULE.command(name="update") - @click.argument( "table-name", nargs=1, @@ -601,7 +476,6 @@ def PBH_RULE_add(db, table_name, rule_name, priority, gre_key, ip_protocol, ipv6 nargs=1, required=True, ) - @click.option( "--priority", help="Configures priority for this rule[mandatory]", @@ -639,7 +513,18 @@ def PBH_RULE_add(db, table_name, rule_name, priority, gre_key, ip_protocol, ipv6 help="Enables/Disables packet/byte counter for this rule", ) @clicommon.pass_db -def PBH_RULE_update(db, table_name, rule_name, priority, gre_key, ip_protocol, ipv6_next_header, l4_dst_port, inner_ether_type, hash, packet_action, flow_counter): +def PBH_RULE_update(db, + table_name, + rule_name, + priority, + gre_key, + ip_protocol, + ipv6_next_header, + l4_dst_port, + inner_ether_type, + hash, + packet_action, + flow_counter): """ Add object in PBH_RULE. """ table = "PBH_RULE" @@ -665,13 +550,12 @@ def PBH_RULE_update(db, table_name, rule_name, priority, gre_key, ip_protocol, i data["flow_counter"] = flow_counter try: - update_entry_validated(db.cfgdb, table, key, data) + update_entry(db.cfgdb, table, key, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @PBH_RULE.command(name="delete") - @click.argument( "table-name", nargs=1, @@ -689,36 +573,11 @@ def PBH_RULE_delete(db, table_name, rule_name): table = "PBH_RULE" key = table_name, rule_name try: - del_entry_validated(db.cfgdb, table, key) + del_entry(db.cfgdb, table, key) except Exception as err: exit_with_error(f"Error: {err}", fg="red") - - - - - - - - - - - - - - - - - - - - - - - - - @click.group(name="pbh-table", cls=clicommon.AliasedGroup) def PBH_TABLE(): @@ -727,24 +586,12 @@ def PBH_TABLE(): pass - - - - - - - - - - @PBH_TABLE.command(name="add") - @click.argument( "table-name", nargs=1, required=True, ) - @click.option( "--description", help="The description of this table[mandatory]", @@ -766,19 +613,17 @@ def PBH_TABLE_add(db, table_name, description, interface_list): data["interface_list"] = interface_list.split(",") try: - add_entry_validated(db.cfgdb, table, key, data) + add_entry(db.cfgdb, table, key, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @PBH_TABLE.command(name="update") - @click.argument( "table-name", nargs=1, required=True, ) - @click.option( "--description", help="The description of this table[mandatory]", @@ -800,13 +645,12 @@ def PBH_TABLE_update(db, table_name, description, interface_list): data["interface_list"] = interface_list.split(",") try: - update_entry_validated(db.cfgdb, table, key, data) + update_entry(db.cfgdb, table, key, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @PBH_TABLE.command(name="delete") - @click.argument( "table-name", nargs=1, @@ -819,20 +663,13 @@ def PBH_TABLE_delete(db, table_name): table = "PBH_TABLE" key = table_name try: - del_entry_validated(db.cfgdb, table, key) + del_entry(db.cfgdb, table, key) except Exception as err: exit_with_error(f"Error: {err}", fg="red") - - - - - - - @PBH_TABLE.group(name="interface-list", - cls=clicommon.AliasedGroup) + cls=clicommon.AliasedGroup) def PBH_TABLE_interface_list(): """ Add/Delete interface_list in PBH_TABLE """ @@ -840,7 +677,6 @@ def PBH_TABLE_interface_list(): @PBH_TABLE_interface_list.command(name="add") - @click.argument( "table-name", nargs=1, @@ -852,10 +688,7 @@ def PBH_TABLE_interface_list(): required=True, ) @clicommon.pass_db -def PBH_TABLE_interface_list_add( - db, - table_name, interface_list -): +def PBH_TABLE_interface_list_add(db, table_name, interface_list): """ Add interface_list in PBH_TABLE """ table = "PBH_TABLE" @@ -864,14 +697,12 @@ def PBH_TABLE_interface_list_add( data = interface_list try: - add_list_entry_validated(db.cfgdb, table, key, attr, data) + add_list_entry(db.cfgdb, table, key, attr, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") - @PBH_TABLE_interface_list.command(name="delete") - @click.argument( "table-name", nargs=1, @@ -883,10 +714,7 @@ def PBH_TABLE_interface_list_add( required=True, ) @clicommon.pass_db -def PBH_TABLE_interface_list_delete( - db, - table_name, interface_list -): +def PBH_TABLE_interface_list_delete(db, table_name, interface_list): """ Delete interface_list in PBH_TABLE """ table = "PBH_TABLE" @@ -895,24 +723,20 @@ def PBH_TABLE_interface_list_delete( data = interface_list try: - del_list_entry_validated(db.cfgdb, table, key, attr, data) + del_list_entry(db.cfgdb, table, key, attr, data) except Exception as err: exit_with_error(f"Error: {err}", fg="red") @PBH_TABLE_interface_list.command(name="clear") - @click.argument( "table-name", nargs=1, required=True, ) @clicommon.pass_db -def PBH_TABLE_interface_list_clear( - db, - table_name -): +def PBH_TABLE_interface_list_clear(db, table_name): """ Clear interface_list in PBH_TABLE """ table = "PBH_TABLE" @@ -920,20 +744,11 @@ def PBH_TABLE_interface_list_clear( attr = "interface_list" try: - clear_list_entry_validated(db.cfgdb, table, key, attr) + clear_list_entry(db.cfgdb, table, key, attr) except Exception as err: exit_with_error(f"Error: {err}", fg="red") - - - - - - - - - def register(cli): cli_node = PBH_HASH_FIELD if cli_node.name in cli.commands: @@ -950,4 +765,4 @@ def register(cli): cli_node = PBH_TABLE if cli_node.name in cli.commands: raise Exception(f"{cli_node.name} already exists in CLI") - cli.add_command(PBH_TABLE) \ No newline at end of file + cli.add_command(PBH_TABLE) From 2d0167fdbcb3a2ca1036a0ece41d3993568f9196 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Mon, 7 Jun 2021 09:42:38 +0000 Subject: [PATCH 06/79] Added 'pbh' subcommand & removed 'hash-field-list' subcommand Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 111 ++++--------------------------- 1 file changed, 13 insertions(+), 98 deletions(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index beef53b74c..f3825d0396 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -106,8 +106,14 @@ def clear_list_entry(db, table, key, attr): update_entry(db, table, key, {attr: None}) +@click.group(name='pbh', + cls=clicommon.AliasedGroup) +def PBH(): + """ Configure PBH (Policy based hashing) feature """ + + pass -@click.group(name="pbh-hash-field", +@PBH.group(name="hash-field", cls=clicommon.AliasedGroup) def PBH_HASH_FIELD(): """ PBH_HASH_FIELD part of config_db.json """ @@ -209,7 +215,7 @@ def PBH_HASH_FIELD_delete(db, hash_field_name): exit_with_error(f"Error: {err}", fg="red") -@click.group(name="pbh-hash", +@PBH.group(name="hash", cls=clicommon.AliasedGroup) def PBH_HASH(): """ PBH_HASH part of config_db.json """ @@ -287,87 +293,7 @@ def PBH_HASH_delete(db, hash_name): exit_with_error(f"Error: {err}", fg="red") -@PBH_HASH.group(name="hash-field-list", - cls=clicommon.AliasedGroup) -def PBH_HASH_hash_field_list(): - """ Add/Delete hash_field_list in PBH_HASH """ - - pass - - -@PBH_HASH_hash_field_list.command(name="add") -@click.argument( - "hash-name", - nargs=1, - required=True, -) -@click.argument( - "hash-field-list", - nargs=-1, - required=True, -) -@clicommon.pass_db -def PBH_HASH_hash_field_list_add(db, hash_name, hash_field_list): - """ Add hash_field_list in PBH_HASH """ - - table = "PBH_HASH" - key = hash_name - attr = "hash_field_list" - data = hash_field_list - - try: - add_list_entry(db.cfgdb, table, key, attr, data) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - -@PBH_HASH_hash_field_list.command(name="delete") -@click.argument( - "hash-name", - nargs=1, - required=True, -) -@click.argument( - "hash-field-list", - nargs=-1, - required=True, -) -@clicommon.pass_db -def PBH_HASH_hash_field_list_delete(db, hash_name, hash_field_list): - """ Delete hash_field_list in PBH_HASH """ - - table = "PBH_HASH" - key = hash_name - attr = "hash_field_list" - data = hash_field_list - - try: - del_list_entry(db.cfgdb, table, key, attr, data) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - -@PBH_HASH_hash_field_list.command(name="clear") -@click.argument( - "hash-name", - nargs=1, - required=True, -) -@clicommon.pass_db -def PBH_HASH_hash_field_list_clear(db, hash_name): - """ Clear hash_field_list in PBH_HASH """ - - table = "PBH_HASH" - key = hash_name - attr = "hash_field_list" - - try: - clear_list_entry(db.cfgdb, table, key, attr) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - -@click.group(name="pbh-rule", +@PBH.group(name="rule", cls=clicommon.AliasedGroup) def PBH_RULE(): """ PBH_RULE part of config_db.json """ @@ -578,7 +504,7 @@ def PBH_RULE_delete(db, table_name, rule_name): exit_with_error(f"Error: {err}", fg="red") -@click.group(name="pbh-table", +@PBH.group(name="table", cls=clicommon.AliasedGroup) def PBH_TABLE(): """ PBH_TABLE part of config_db.json """ @@ -750,19 +676,8 @@ def PBH_TABLE_interface_list_clear(db, table_name): def register(cli): - cli_node = PBH_HASH_FIELD - if cli_node.name in cli.commands: - raise Exception(f"{cli_node.name} already exists in CLI") - cli.add_command(PBH_HASH_FIELD) - cli_node = PBH_HASH - if cli_node.name in cli.commands: - raise Exception(f"{cli_node.name} already exists in CLI") - cli.add_command(PBH_HASH) - cli_node = PBH_RULE - if cli_node.name in cli.commands: - raise Exception(f"{cli_node.name} already exists in CLI") - cli.add_command(PBH_RULE) - cli_node = PBH_TABLE + cli_node = PBH if cli_node.name in cli.commands: raise Exception(f"{cli_node.name} already exists in CLI") - cli.add_command(PBH_TABLE) + cli.add_command(PBH) + From 5a6ea76881cbda38073509cdf9cc5b325ecafa01 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 8 Jun 2021 08:58:30 +0000 Subject: [PATCH 07/79] Removed leaf-lists CLI commands, added example of validation click options Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 137 ++++--------------------------- 1 file changed, 15 insertions(+), 122 deletions(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index f3825d0396..0e80f5921b 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -7,6 +7,7 @@ """ import click +import ipaddress import utilities_common.cli as clicommon import utilities_common.general as general @@ -67,45 +68,6 @@ def del_entry(db, table, key): db.set_entry(table, key, None) -def add_list_entry(db, table, key, attr, data): - """ Add new entry into list in table and validate configuration""" - - cfg = db.get_config() - cfg.setdefault(table, {}) - if key not in cfg[table]: - raise Exception(f"{key} does not exist") - cfg[table][key].setdefault(attr, []) - for entry in data: - if entry in cfg[table][key][attr]: - raise Exception(f"{entry} already exists") - cfg[table][key][attr].append(entry) - - db.set_entry(table, key, cfg[table][key]) - - -def del_list_entry(db, table, key, attr, data): - """ Delete entry from list in table and validate configuration""" - - cfg = db.get_config() - cfg.setdefault(table, {}) - if key not in cfg[table]: - raise Exception(f"{key} does not exist") - cfg[table][key].setdefault(attr, []) - for entry in data: - if entry not in cfg[table][key][attr]: - raise Exception(f"{entry} does not exist") - cfg[table][key][attr].remove(entry) - if not cfg[table][key][attr]: - cfg[table][key].pop(attr) - - db.set_entry(table, key, cfg[table][key]) - - -def clear_list_entry(db, table, key, attr): - """ Clear list in object and validate configuration""" - - update_entry(db, table, key, {attr: None}) - @click.group(name='pbh', cls=clicommon.AliasedGroup) def PBH(): @@ -113,8 +75,9 @@ def PBH(): pass + @PBH.group(name="hash-field", - cls=clicommon.AliasedGroup) + cls=clicommon.AliasedGroup) def PBH_HASH_FIELD(): """ PBH_HASH_FIELD part of config_db.json """ @@ -126,10 +89,21 @@ def PBH_HASH_FIELD(): "hash-field-name", nargs=1, required=True, + # add callback ) @click.option( "--hash-field", - help="Configures native hash field for this hash field[mandatory]", + help="Configure native hash field for this hash field [mandatory] \ + Acceptable values: INNER_IP_PROTOCOL; INNER_L4_DST_PORT; \ + INNER_L4_SRC_PORT; INNER_DST_IPV4; INNER_SRC_IPV4; \ + INNER_DST_IPV6; INNER_SRC_IPV6", + type=click.Choice(["INNER_IP_PROTOCOL", + "INNER_L4_DST_PORT", + "INNER_L4_SRC_PORT", + "INNER_DST_IPV4", + "INNER_SRC_IPV4", + "INNER_DST_IPV6", + "INNER_SRC_IPV6"]), ) @click.option( "--ip-mask", @@ -594,87 +568,6 @@ def PBH_TABLE_delete(db, table_name): exit_with_error(f"Error: {err}", fg="red") -@PBH_TABLE.group(name="interface-list", - cls=clicommon.AliasedGroup) -def PBH_TABLE_interface_list(): - """ Add/Delete interface_list in PBH_TABLE """ - - pass - - -@PBH_TABLE_interface_list.command(name="add") -@click.argument( - "table-name", - nargs=1, - required=True, -) -@click.argument( - "interface-list", - nargs=-1, - required=True, -) -@clicommon.pass_db -def PBH_TABLE_interface_list_add(db, table_name, interface_list): - """ Add interface_list in PBH_TABLE """ - - table = "PBH_TABLE" - key = table_name - attr = "interface_list" - data = interface_list - - try: - add_list_entry(db.cfgdb, table, key, attr, data) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - -@PBH_TABLE_interface_list.command(name="delete") -@click.argument( - "table-name", - nargs=1, - required=True, -) -@click.argument( - "interface-list", - nargs=-1, - required=True, -) -@clicommon.pass_db -def PBH_TABLE_interface_list_delete(db, table_name, interface_list): - """ Delete interface_list in PBH_TABLE """ - - table = "PBH_TABLE" - key = table_name - attr = "interface_list" - data = interface_list - - try: - del_list_entry(db.cfgdb, table, key, attr, data) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - - -@PBH_TABLE_interface_list.command(name="clear") -@click.argument( - "table-name", - nargs=1, - required=True, -) -@clicommon.pass_db -def PBH_TABLE_interface_list_clear(db, table_name): - """ Clear interface_list in PBH_TABLE """ - - table = "PBH_TABLE" - key = table_name - attr = "interface_list" - - try: - clear_list_entry(db.cfgdb, table, key, attr) - except Exception as err: - exit_with_error(f"Error: {err}", fg="red") - - def register(cli): cli_node = PBH if cli_node.name in cli.commands: From f94e0f0057f003364e63703e8e677f5c7c5481a0 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 8 Jun 2021 09:58:47 +0000 Subject: [PATCH 08/79] Added new data enums from YANG model Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index 0e80f5921b..40028f22fc 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -12,6 +12,19 @@ import utilities_common.general as general +hash_field_types = ['INNER_IP_PROTOCOL', + 'INNER_L4_DST_PORT', + 'INNER_L4_SRC_PORT', + 'INNER_DST_IPV4', + 'INNER_SRC_IPV4', + 'INNER_DST_IPV6', + 'INNER_SRC_IPV6'] + +packet_action_types = ['SET_ECMP_HASH', 'SET_LAG_HASH'] + +flow_counter_state = ['DISABLED', 'ENABLED'] + + def exit_with_error(*args, **kwargs): """ Print a message and abort CLI. """ @@ -93,17 +106,8 @@ def PBH_HASH_FIELD(): ) @click.option( "--hash-field", - help="Configure native hash field for this hash field [mandatory] \ - Acceptable values: INNER_IP_PROTOCOL; INNER_L4_DST_PORT; \ - INNER_L4_SRC_PORT; INNER_DST_IPV4; INNER_SRC_IPV4; \ - INNER_DST_IPV6; INNER_SRC_IPV6", - type=click.Choice(["INNER_IP_PROTOCOL", - "INNER_L4_DST_PORT", - "INNER_L4_SRC_PORT", - "INNER_DST_IPV4", - "INNER_SRC_IPV4", - "INNER_DST_IPV6", - "INNER_SRC_IPV6"]), + help="Configure native hash field for this hash field [mandatory]", + type=click.Choice(hash_field_types) ) @click.option( "--ip-mask", From 8dd0e7b7167cb1fffe76c56b21ea3b6865adde2b Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 8 Jun 2021 09:59:28 +0000 Subject: [PATCH 09/79] Added show pbh ... Signed-off-by: Vadym Hlushko --- show/plugins/sonic-pbh_yang.py | 46 +++++++++++++++++----------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/show/plugins/sonic-pbh_yang.py b/show/plugins/sonic-pbh_yang.py index 9cf04d0a2a..3f5f517292 100644 --- a/show/plugins/sonic-pbh_yang.py +++ b/show/plugins/sonic-pbh_yang.py @@ -46,7 +46,15 @@ def format_group_value(entry, attrs): return tabulate.tabulate(data, tablefmt="plain") -@click.group(name="pbh-hash-field", +@click.group(name='pbh', + cls=clicommon.AliasedGroup) +def PBH(): + """ Show PBH (Policy based hashing) feature configuration """ + + pass + + +@PBH.group(name="hash-field", cls=clicommon.AliasedGroup, invoke_without_command=True) @clicommon.pass_db @@ -100,7 +108,7 @@ def PBH_HASH_FIELD(db): click.echo(tabulate.tabulate(body, header)) -@click.group(name="pbh-hash", +@PBH.group(name="hash", cls=clicommon.AliasedGroup, invoke_without_command=True) @clicommon.pass_db @@ -136,9 +144,9 @@ def PBH_HASH(db): click.echo(tabulate.tabulate(body, header)) -@click.group(name="pbh-rule", - cls=clicommon.AliasedGroup, - invoke_without_command=True) +@PBH.group(name="rule", + cls=clicommon.AliasedGroup, + invoke_without_command=True) @clicommon.pass_db def PBH_RULE(db): """ [Callable command group] """ @@ -217,7 +225,10 @@ def PBH_RULE(db): format_attr_value( entry, {'name': 'hash', - 'description': 'The hash to apply with this rule', 'is-leaf-list': False, 'is-mandatory': True, 'group': ''} + 'description': 'The hash to apply with this rule', + 'is-leaf-list': False, + 'is-mandatory': True, + 'group': ''} ), format_attr_value( entry, @@ -242,9 +253,9 @@ def PBH_RULE(db): click.echo(tabulate.tabulate(body, header)) -@click.group(name="pbh-table", - cls=clicommon.AliasedGroup, - invoke_without_command=True) +@PBH.group(name="table", + cls=clicommon.AliasedGroup, + invoke_without_command=True) @clicommon.pass_db def PBH_TABLE(db): """ [Callable command group] """ @@ -288,19 +299,8 @@ def PBH_TABLE(db): def register(cli): - cli_node = PBH_HASH_FIELD - if cli_node.name in cli.commands: - raise Exception(f"{cli_node.name} already exists in CLI") - cli.add_command(PBH_HASH_FIELD) - cli_node = PBH_HASH - if cli_node.name in cli.commands: - raise Exception(f"{cli_node.name} already exists in CLI") - cli.add_command(PBH_HASH) - cli_node = PBH_RULE - if cli_node.name in cli.commands: - raise Exception(f"{cli_node.name} already exists in CLI") - cli.add_command(PBH_RULE) - cli_node = PBH_TABLE + cli_node = PBH if cli_node.name in cli.commands: raise Exception(f"{cli_node.name} already exists in CLI") - cli.add_command(PBH_TABLE) \ No newline at end of file + cli.add_command(PBH) + From 32615027e4a55fc90125693724a8075e9392c034 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 8 Jun 2021 10:00:00 +0000 Subject: [PATCH 10/79] Added sceleton for PBH UT Signed-off-by: Vadym Hlushko --- tests/pbh_test.py | 56 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 tests/pbh_test.py diff --git a/tests/pbh_test.py b/tests/pbh_test.py new file mode 100644 index 0000000000..2ff4fbdabf --- /dev/null +++ b/tests/pbh_test.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python + +import os +import logging +import show.main as show +import config.main as config + +from utilities_common.db import Db +from click.testing import CliRunner + + +logger = logging.getLogger(__name__) +test_path = os.path.dirname(os.path.abspath(__file__)) + + +class TestPBH: + @classmethod + def setup_class(cls): + logger.info("SETUP") + os.environ['UTILITIES_UNIT_TESTING'] = "1" + + + def test_config_pbh_table_add(self): + db = Db() + obj = { 'db': db.cfgdb } + runner = CliRunner() + result = runner.invoke(config.config.commands["pbh"]. + commands["table"].commands["add"], + ["pbh_table", "--interface-list", "Ethernet0,Ethernet4", + "--description", "NVGRE"], obj=obj) + logger.debug(result.exit_code) + logger.debug(result.output) + #import pdb; pdb.set_trace() + assert result.exit_code == 0 + # assert for dict + + def test_config_pbh_hash_field(self): + db = Db() + obj = { 'db': db.cfgdb } + runner = CliRunner() + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["add"], + ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", + "--sequence-id", "1"], obj=obj) + logger.debug(result.exit_code) + logger.debug(result.output) + #import pdb; pdb.set_trace() + assert result.exit_code == 0 + # assert for dict + + + @classmethod + def teardown_class(cls): + logger.info("TEARDOWN") + os.environ['UTILITIES_UNIT_TESTING'] = "0" + From bb0a710213a68d347de365970c5cee723e69dedb Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 8 Jun 2021 10:06:08 +0000 Subject: [PATCH 11/79] Fixed show pbh table output Signed-off-by: Vadym Hlushko --- show/plugins/sonic-pbh_yang.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/show/plugins/sonic-pbh_yang.py b/show/plugins/sonic-pbh_yang.py index 3f5f517292..c82a998d79 100644 --- a/show/plugins/sonic-pbh_yang.py +++ b/show/plugins/sonic-pbh_yang.py @@ -261,9 +261,9 @@ def PBH_TABLE(db): """ [Callable command group] """ header = [ - "TABLE NAME", - "DESCRIPTION", - "INTERFACE LIST", + "Name", + "Interface", + "Description", ] body = [] @@ -275,14 +275,6 @@ def PBH_TABLE(db): key = (key,) row = [*key] + [ - format_attr_value( - entry, - {'name': 'description', - 'description': 'The description of this table', - 'is-leaf-list': False, - 'is-mandatory': True, - 'group': ''} - ), format_attr_value( entry, {'name': 'interface_list', @@ -291,6 +283,14 @@ def PBH_TABLE(db): 'is-mandatory': False, 'group': ''} ), + format_attr_value( + entry, + {'name': 'description', + 'description': 'The description of this table', + 'is-leaf-list': False, + 'is-mandatory': True, + 'group': ''} + ), ] body.append(row) From 6a0c248e5d75d1932bf32a8d4324ea6565af5fb8 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 8 Jun 2021 11:54:19 +0000 Subject: [PATCH 12/79] Added 'Symmetric' field to the 'show pbh hash-field' command Signed-off-by: Vadym Hlushko --- show/plugins/sonic-pbh_yang.py | 50 +++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/show/plugins/sonic-pbh_yang.py b/show/plugins/sonic-pbh_yang.py index c82a998d79..ef9bab45a6 100644 --- a/show/plugins/sonic-pbh_yang.py +++ b/show/plugins/sonic-pbh_yang.py @@ -55,24 +55,29 @@ def PBH(): @PBH.group(name="hash-field", - cls=clicommon.AliasedGroup, - invoke_without_command=True) + cls=clicommon.AliasedGroup, + invoke_without_command=True) @clicommon.pass_db def PBH_HASH_FIELD(db): - """ [Callable command group] """ + """ Show PBH hash fields configuration """ header = [ - "HASH FIELD NAME", - "HASH FIELD", - "IP MASK", - "SEQUENCE ID", + "Name", + "Field", + "Mask", + "Sequence", + "Symmetric", ] body = [] table = db.cfgdb.get_table("PBH_HASH_FIELD") for key in natsort.natsorted(table): + + is_pbh_hash_field_symmetric(table, key) + entry = table[key] + if not isinstance(key, tuple): key = (key,) @@ -101,6 +106,14 @@ def PBH_HASH_FIELD(db): 'is-mandatory': True, 'group': ''} ), + format_attr_value( + entry, + {'name': 'symmetric', + 'description': 'symmetric', + 'is-leaf-list': False, + 'is-mandatory': False, + 'group': ''} + ), ] body.append(row) @@ -304,3 +317,26 @@ def register(cli): raise Exception(f"{cli_node.name} already exists in CLI") cli.add_command(PBH) + +def is_pbh_hash_field_symmetric(table: dict, key_to_check: str): + """ The 'Symmetric' parameter will have 'Yes' value + if there are 2 'pbh hash fields' with identical 'sequence_id' value + + Args: + table: 'PBH_HASH_FIELD' table from CONFIG DB. + key_to_check: key from the table above to check + """ + + if table[key_to_check].get('symmetric') is None: + counter = 0 + + for key in table: + if key_to_check != key: + if table[key_to_check].get('sequence_id') == table[key].get('sequence_id'): + counter += 1 + + if counter == 1: + table[key_to_check]['symmetric'] = 'Yes' + else: + table[key_to_check]['symmetric'] = 'No' + From 0e20bc02def88477a6b23ddc87c7da5cd71eedcd Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 8 Jun 2021 12:08:37 +0000 Subject: [PATCH 13/79] Fixed 'show pbh hash' output Signed-off-by: Vadym Hlushko --- show/plugins/sonic-pbh_yang.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/show/plugins/sonic-pbh_yang.py b/show/plugins/sonic-pbh_yang.py index ef9bab45a6..57e53d088c 100644 --- a/show/plugins/sonic-pbh_yang.py +++ b/show/plugins/sonic-pbh_yang.py @@ -59,7 +59,7 @@ def PBH(): invoke_without_command=True) @clicommon.pass_db def PBH_HASH_FIELD(db): - """ Show PBH hash fields configuration """ + """ Show the PBH 'hash field' configuration """ header = [ "Name", @@ -126,11 +126,11 @@ def PBH_HASH_FIELD(db): invoke_without_command=True) @clicommon.pass_db def PBH_HASH(db): - """ [Callable command group] """ + """ Show the PBH 'hash' configuration """ header = [ - "HASH NAME", - "HASH FIELD LIST", + "Hash", + "Hash field", ] body = [] From 466862d2ef3b5e0f0b335eecac3618b364e073f4 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 8 Jun 2021 14:25:45 +0000 Subject: [PATCH 14/79] Fixed 'show pbh rule' output Signed-off-by: Vadym Hlushko --- show/plugins/sonic-pbh_yang.py | 151 ++++++++++++++++----------------- 1 file changed, 75 insertions(+), 76 deletions(-) diff --git a/show/plugins/sonic-pbh_yang.py b/show/plugins/sonic-pbh_yang.py index 57e53d088c..5be423cf37 100644 --- a/show/plugins/sonic-pbh_yang.py +++ b/show/plugins/sonic-pbh_yang.py @@ -59,7 +59,7 @@ def PBH(): invoke_without_command=True) @clicommon.pass_db def PBH_HASH_FIELD(db): - """ Show the PBH 'hash field' configuration """ + """ Show the PBH hash field configuration """ header = [ "Name", @@ -126,7 +126,7 @@ def PBH_HASH_FIELD(db): invoke_without_command=True) @clicommon.pass_db def PBH_HASH(db): - """ Show the PBH 'hash' configuration """ + """ Show the PBH hash configuration """ header = [ "Hash", @@ -162,20 +162,15 @@ def PBH_HASH(db): invoke_without_command=True) @clicommon.pass_db def PBH_RULE(db): - """ [Callable command group] """ + """ Show the PBH rules configuration """ header = [ - "TABLE NAME", - "RULE NAME", - "PRIORITY", - "GRE KEY", - "IP PROTOCOL", - "IPV6 NEXT HEADER", - "L4 DST PORT", - "INNER ETHER TYPE", - "HASH", - "PACKET ACTION", - "FLOW COUNTER", + "Table", + "Rule", + "Priority", + "Match", + "Hash", + "Action", ] body = [] @@ -189,75 +184,79 @@ def PBH_RULE(db): row = [*key] + [ format_attr_value( entry, - {'name': 'priority', - 'description': 'Configures priority for this rule', - 'is-leaf-list': False, - 'is-mandatory': True, - 'group': ''} - ), - format_attr_value( - entry, - {'name': 'gre_key', - 'description': 'Configures packet match for this rule: GRE key (value/mask)', - 'is-leaf-list': False, - 'is-mandatory': False, - 'group': ''} - ), - format_attr_value( - entry, - {'name': 'ip_protocol', - 'description': 'Configures packet match for this rule: IP protocol (value/mask)', - 'is-leaf-list': False, - 'is-mandatory': False, - 'group': ''} - ), - format_attr_value( - entry, - {'name': 'ipv6_next_header', - 'description': 'Configures packet match for this rule: IPv6 Next header (value/mask)', - 'is-leaf-list': False, - 'is-mandatory': False, - 'group': ''} - ), - format_attr_value( - entry, - {'name': 'l4_dst_port', - 'description': 'Configures packet match for this rule: L4 destination port (value/mask)', - 'is-leaf-list': False, - 'is-mandatory': False, - 'group': ''} - ), - format_attr_value( - entry, - {'name': 'inner_ether_type', - 'description': 'Configures packet match for this rule: inner EtherType (value/mask)', - 'is-leaf-list': False, - 'is-mandatory': False, - 'group': ''} + { + 'name': 'priority', + 'description': 'Configures priority for this rule', + 'is-leaf-list': False, + 'is-mandatory': True, + 'group': '' + } ), - format_attr_value( + format_group_value( entry, - {'name': 'hash', - 'description': 'The hash to apply with this rule', - 'is-leaf-list': False, - 'is-mandatory': True, - 'group': ''} + [ + { + 'name': 'gre_key', + 'description': 'Configures packet match for this rule: GRE key (value/mask)', + 'is-leaf-list':False, + 'is-mandatory': False, + 'group': 'Match' + }, + { + 'name': 'ip_protocol', + 'description': 'Configures packet match for this rule: IP protocol (value/mask)', + 'is-leaf-list': False, + 'is-mandatory': False, + 'group': 'Match' + }, + { + 'name': 'ipv6_next_header', + 'description': 'Configures packet match for this rule: IPv6 Next header (value/mask)', + 'is-leaf-list': False, + 'is-mandatory': False, + 'group': 'Match' + }, + { + 'name': 'l4_dst_port', + 'description': 'Configures packet match for this rule: L4 destination port (value/mask)', + 'is-leaf-list': False, + 'is-mandatory': False, + 'group': 'Match' + }, + { + 'name': 'inner_ether_type', + 'description': 'Configures packet match for this rule: inner EtherType (value/mask)', + 'is-leaf-list': False, + 'is-mandatory': False, + 'group': 'Match' + }, + { + 'name': 'flow_counter', + 'description': 'Enables/Disables packet/byte counter for this rule', + 'is-leaf-list': False, + 'is-mandatory': False, + 'group': 'Match' + }, + ] ), format_attr_value( entry, - {'name': 'packet_action', - 'description': 'Configures packet action for this rule', - 'is-leaf-list': False, - 'is-mandatory': False, - 'group': ''} + { + 'name': 'hash', + 'description':'The hash to apply with this rule', + 'is-leaf-list': False, + 'is-mandatory': True, + 'group': ''} ), format_attr_value( entry, - {'name': 'flow_counter', - 'description': 'Enables/Disables packet/byte counter for this rule', - 'is-leaf-list': False, - 'is-mandatory': False, - 'group': ''} + { + 'name': 'packet_action', + 'description': 'Configures packet action for this rule', + 'is-leaf-list': False, + 'is-mandatory': False, + 'group': '' + } ), ] @@ -271,7 +270,7 @@ def PBH_RULE(db): invoke_without_command=True) @clicommon.pass_db def PBH_TABLE(db): - """ [Callable command group] """ + """ Show the PBH table configuration """ header = [ "Name", From 07000a6994c7a8e708d66450ae931793ff466fdd Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 8 Jun 2021 15:30:45 +0000 Subject: [PATCH 15/79] Fixed codestyle for show CLI plugin Signed-off-by: Vadym Hlushko --- show/plugins/sonic-pbh_yang.py | 110 +++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 47 deletions(-) diff --git a/show/plugins/sonic-pbh_yang.py b/show/plugins/sonic-pbh_yang.py index 5be423cf37..95c8a46ad1 100644 --- a/show/plugins/sonic-pbh_yang.py +++ b/show/plugins/sonic-pbh_yang.py @@ -15,34 +15,36 @@ def format_attr_value(entry, attr): """ Helper that formats attribute to be presented in the table output. - Args: - entry (Dict[str, str]): CONFIG DB entry configuration. - attr (Dict): Attribute metadata. + Args: + entry (Dict[str, str]): CONFIG DB entry configuration. + attr (Dict): Attribute metadata. - Returns: - str: fomatted attribute value. + Returns: + str: fomatted attribute value. """ if attr["is-leaf-list"]: return "\n".join(entry.get(attr["name"], [])) + return entry.get(attr["name"], "N/A") def format_group_value(entry, attrs): """ Helper that formats grouped attribute to be presented in the table output. - Args: - entry (Dict[str, str]): CONFIG DB entry configuration. - attrs (List[Dict]): Attributes metadata that belongs to the same group. + Args: + entry (Dict[str, str]): CONFIG DB entry configuration. + attrs (List[Dict]): Attributes metadata that belongs to the same group. - Returns: - str: fomatted group attributes. + Returns: + str: fomatted group attributes. """ data = [] for attr in attrs: if entry.get(attr["name"]): data.append((attr["name"] + ":", format_attr_value(entry, attr))) + return tabulate.tabulate(data, tablefmt="plain") @@ -84,35 +86,43 @@ def PBH_HASH_FIELD(db): row = [*key] + [ format_attr_value( entry, - {'name': 'hash_field', - 'description': 'Configures native hash field for this hash field', - 'is-leaf-list': False, - 'is-mandatory': True, - 'group': ''} + { + 'name': 'hash_field', + 'description': 'Configures native hash field for this hash field', + 'is-leaf-list': False, + 'is-mandatory': True, + 'group': '' + } ), format_attr_value( entry, - {'name': 'ip_mask', - 'description': 'Configures IPv4/IPv6 address mask for this hash field', - 'is-leaf-list': False, - 'is-mandatory': True, - 'group': ''} + { + 'name': 'ip_mask', + 'description': 'Configures IPv4/IPv6 address mask for this hash field', + 'is-leaf-list': False, + 'is-mandatory': True, + 'group': '' + } ), format_attr_value( entry, - {'name': 'sequence_id', - 'description': 'Configures in which order the fields are hashed and defines which fields should be associative', - 'is-leaf-list': False, - 'is-mandatory': True, - 'group': ''} + { + 'name': 'sequence_id', + 'description': 'Configures in which order the fields are hashed and defines which fields should be associative', + 'is-leaf-list': False, + 'is-mandatory': True, + 'group': '' + } ), format_attr_value( entry, - {'name': 'symmetric', - 'description': 'symmetric', - 'is-leaf-list': False, - 'is-mandatory': False, - 'group': ''} + { + 'name': 'symmetric', + 'description': 'symmetric', + 'is-leaf-list': False, + 'is-mandatory': False, + 'group': '' + } ), ] @@ -122,8 +132,8 @@ def PBH_HASH_FIELD(db): @PBH.group(name="hash", - cls=clicommon.AliasedGroup, - invoke_without_command=True) + cls=clicommon.AliasedGroup, + invoke_without_command=True) @clicommon.pass_db def PBH_HASH(db): """ Show the PBH hash configuration """ @@ -144,11 +154,13 @@ def PBH_HASH(db): row = [*key] + [ format_attr_value( entry, - {'name': 'hash_field_list', - 'description': 'The list of hash fields to apply with this hash', - 'is-leaf-list': True, - 'is-mandatory': False, - 'group': ''} + { + 'name': 'hash_field_list', + 'description': 'The list of hash fields to apply with this hash', + 'is-leaf-list': True, + 'is-mandatory': False, + 'group': '' + } ), ] @@ -289,19 +301,23 @@ def PBH_TABLE(db): row = [*key] + [ format_attr_value( entry, - {'name': 'interface_list', - 'description': 'Interfaces to which this table is applied', - 'is-leaf-list': True, - 'is-mandatory': False, - 'group': ''} + { + 'name': 'interface_list', + 'description': 'Interfaces to which this table is applied', + 'is-leaf-list': True, + 'is-mandatory': False, + 'group': '' + } ), format_attr_value( entry, - {'name': 'description', - 'description': 'The description of this table', - 'is-leaf-list': False, - 'is-mandatory': True, - 'group': ''} + { + 'name': 'description', + 'description': 'The description of this table', + 'is-leaf-list': False, + 'is-mandatory': True, + 'group': '' + } ), ] From 0305909c3c48df34d5767a568cc3dcbec9de3b98 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Thu, 10 Jun 2021 08:05:50 +0000 Subject: [PATCH 16/79] Added 'show pbh statistics' Signed-off-by: Vadym Hlushko --- show/plugins/sonic-pbh_yang.py | 43 ++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/show/plugins/sonic-pbh_yang.py b/show/plugins/sonic-pbh_yang.py index 95c8a46ad1..65fa996f31 100644 --- a/show/plugins/sonic-pbh_yang.py +++ b/show/plugins/sonic-pbh_yang.py @@ -10,6 +10,7 @@ import tabulate import natsort import utilities_common.cli as clicommon +from swsscommon.swsscommon import SonicV2Connector, ConfigDBConnector def format_attr_value(entry, attr): @@ -325,6 +326,44 @@ def PBH_TABLE(db): click.echo(tabulate.tabulate(body, header)) +@PBH.group(name="statistics", + cls=clicommon.AliasedGroup, + invoke_without_command=True) +@clicommon.pass_db +def PBH_STATISTICS(db): + """ Show the PBH counters """ + + header = [ + "Table", + "Rule", + "Packets count", + "Bytes count", + ] + + body = [] + + db_connector = SonicV2Connector(use_unix_socket_path=False) + db_connector.connect(db_connector.COUNTERS_DB) + + pbh_counters = {} + pbh_rules = db.cfgdb.get_table("PBH_RULE") + + if pbh_rules is not None: + for table, rule in natsort.natsorted(pbh_rules): + counter_props = lowercase_keys(db_connector.get_all(db_connector.COUNTERS_DB, "COUNTERS:%s:%s" % (table, rule))) + row = [] + if counter_props is not None: + row = [ + table, + rule, + counter_props['packets'], + counter_props['bytes'] + ] + + body.append(row) + + click.echo(tabulate.tabulate(body, header)) + def register(cli): cli_node = PBH @@ -355,3 +394,7 @@ def is_pbh_hash_field_symmetric(table: dict, key_to_check: str): else: table[key_to_check]['symmetric'] = 'No' + +def lowercase_keys(dictionary): + return dict((k.lower(), v) for k, v in dictionary.items()) if dictionary else None + From 68b07b254126c7baa3bed4835f473adaae1c91f2 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Thu, 10 Jun 2021 08:12:56 +0000 Subject: [PATCH 17/79] Added 'flow counter' column to 'show pbh rule' Signed-off-by: Vadym Hlushko --- show/plugins/sonic-pbh_yang.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/show/plugins/sonic-pbh_yang.py b/show/plugins/sonic-pbh_yang.py index 65fa996f31..0650805561 100644 --- a/show/plugins/sonic-pbh_yang.py +++ b/show/plugins/sonic-pbh_yang.py @@ -184,6 +184,7 @@ def PBH_RULE(db): "Match", "Hash", "Action", + "Flow counter", ] body = [] @@ -243,13 +244,6 @@ def PBH_RULE(db): 'is-mandatory': False, 'group': 'Match' }, - { - 'name': 'flow_counter', - 'description': 'Enables/Disables packet/byte counter for this rule', - 'is-leaf-list': False, - 'is-mandatory': False, - 'group': 'Match' - }, ] ), format_attr_value( @@ -271,6 +265,16 @@ def PBH_RULE(db): 'group': '' } ), + format_attr_value( + entry, + { + 'name': 'flow_counter', + 'description': 'Configures packet action for this rule', + 'is-leaf-list': False, + 'is-mandatory': False, + 'group': '' + } + ), ] body.append(row) From 186ae9b3cd210b9b672004cf9b89f45f77bd309b Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Thu, 10 Jun 2021 12:28:13 +0000 Subject: [PATCH 18/79] Added sort, changed symmetric check, removed unused check Signed-off-by: Vadym Hlushko --- show/plugins/sonic-pbh_yang.py | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/show/plugins/sonic-pbh_yang.py b/show/plugins/sonic-pbh_yang.py index 0650805561..a88a2a8d33 100644 --- a/show/plugins/sonic-pbh_yang.py +++ b/show/plugins/sonic-pbh_yang.py @@ -10,6 +10,7 @@ import tabulate import natsort import utilities_common.cli as clicommon +from operator import itemgetter from swsscommon.swsscommon import SonicV2Connector, ConfigDBConnector @@ -129,7 +130,9 @@ def PBH_HASH_FIELD(db): body.append(row) - click.echo(tabulate.tabulate(body, header)) + # sorted by 'sequence_id' + body_sorted = sorted(body, key=itemgetter(3)) + click.echo(tabulate.tabulate(body_sorted, header)) @PBH.group(name="hash", @@ -279,7 +282,9 @@ def PBH_RULE(db): body.append(row) - click.echo(tabulate.tabulate(body, header)) + # sorted by 'Priority' + body_sorted = sorted(body, key=itemgetter(2)) + click.echo(tabulate.tabulate(body_sorted, header)) @PBH.group(name="table", @@ -352,19 +357,18 @@ def PBH_STATISTICS(db): pbh_counters = {} pbh_rules = db.cfgdb.get_table("PBH_RULE") - if pbh_rules is not None: - for table, rule in natsort.natsorted(pbh_rules): - counter_props = lowercase_keys(db_connector.get_all(db_connector.COUNTERS_DB, "COUNTERS:%s:%s" % (table, rule))) - row = [] - if counter_props is not None: - row = [ - table, - rule, - counter_props['packets'], - counter_props['bytes'] - ] + for table, rule in natsort.natsorted(pbh_rules): + counter_props = lowercase_keys(db_connector.get_all(db_connector.COUNTERS_DB, "COUNTERS:%s:%s" % (table, rule))) + row = [] + if counter_props is not None: + row = [ + table, + rule, + counter_props['packets'], + counter_props['bytes'] + ] - body.append(row) + body.append(row) click.echo(tabulate.tabulate(body, header)) @@ -393,7 +397,7 @@ def is_pbh_hash_field_symmetric(table: dict, key_to_check: str): if table[key_to_check].get('sequence_id') == table[key].get('sequence_id'): counter += 1 - if counter == 1: + if counter >= 1: table[key_to_check]['symmetric'] = 'Yes' else: table[key_to_check]['symmetric'] = 'No' From 9f2b52f6cc8990e317786e9e46b0a9fdf54ea796 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Thu, 10 Jun 2021 14:03:45 +0000 Subject: [PATCH 19/79] Added validation for --hash-field-list, --ip-mask Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 49 ++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index 40028f22fc..22a7feeec5 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -81,6 +81,36 @@ def del_entry(db, table, key): db.set_entry(table, key, None) +def is_valid_ip_address(ctx, param, value): + """ Check if the given ip address is valid """ + + # need to clarify + ip = ipaddress.ip_address(value) + if (ip.is_reserved) or (ip.is_multicast) or (ip.is_global) or (ip.is_link_local): + raise ipaddress.AddressValueError + + return str(ip) + + +def is_hash_field_list_valid(db, hash_field_list): + """ Check if --hash-field-list values are valid, + i.e was previously added by 'config pbh hash-field ...' command + + Args: + db: reference to Config DB, + hash_field_list: value of --hash-field-list option + """ + pbh_hash_field_table = db.cfgdb.get_table("PBH_HASH_FIELD") + correct_hash_fields = list(pbh_hash_field_table.keys()) + + hash_fields = hash_field_list.split(',') + + for hf in hash_fields: + if hf not in correct_hash_fields: + exit_with_error("Error: invalid --hash-field-list value, \ + please use {}".format(correct_hash_fields), fg="red") + + @click.group(name='pbh', cls=clicommon.AliasedGroup) def PBH(): @@ -92,7 +122,7 @@ def PBH(): @PBH.group(name="hash-field", cls=clicommon.AliasedGroup) def PBH_HASH_FIELD(): - """ PBH_HASH_FIELD part of config_db.json """ + """ Configure PBH hash field """ pass @@ -102,20 +132,22 @@ def PBH_HASH_FIELD(): "hash-field-name", nargs=1, required=True, - # add callback ) @click.option( "--hash-field", help="Configure native hash field for this hash field [mandatory]", + required=True, type=click.Choice(hash_field_types) ) @click.option( "--ip-mask", - help="Configures IPv4/IPv6 address mask for this hash field[mandatory]", + help="Configures IPv4/IPv6 address mask for this hash field [mandatory]", + callback=is_valid_ip_address ) @click.option( "--sequence-id", - help="Configures in which order the fields are hashed and defines which fields should be associative[mandatory]", + help="Configures in which order the fields are hashed and defines which fields should be associative [mandatory]", + type=click.INT, ) @clicommon.pass_db def PBH_HASH_FIELD_add(db, hash_field_name, hash_field, ip_mask, sequence_id): @@ -146,14 +178,17 @@ def PBH_HASH_FIELD_add(db, hash_field_name, hash_field, ip_mask, sequence_id): @click.option( "--hash-field", help="Configures native hash field for this hash field[mandatory]", + type=click.Choice(hash_field_types) ) @click.option( "--ip-mask", help="Configures IPv4/IPv6 address mask for this hash field[mandatory]", + callback=is_valid_ip_address ) @click.option( "--sequence-id", help="Configures in which order the fields are hashed and defines which fields should be associative[mandatory]", + type=click.INT, ) @clicommon.pass_db def PBH_HASH_FIELD_update(db, hash_field_name, hash_field, ip_mask, sequence_id): @@ -196,7 +231,7 @@ def PBH_HASH_FIELD_delete(db, hash_field_name): @PBH.group(name="hash", cls=clicommon.AliasedGroup) def PBH_HASH(): - """ PBH_HASH part of config_db.json """ + """ Configure PBH hash """ pass @@ -215,6 +250,8 @@ def PBH_HASH(): def PBH_HASH_add(db, hash_name, hash_field_list): """ Add object in PBH_HASH. """ + is_hash_field_list_valid(db, hash_field_list) + table = "PBH_HASH" key = hash_name data = {} @@ -241,6 +278,8 @@ def PBH_HASH_add(db, hash_name, hash_field_list): def PBH_HASH_update(db, hash_name, hash_field_list): """ Add object in PBH_HASH. """ + is_hash_field_list_valid(db, hash_field_list) + table = "PBH_HASH" key = hash_name data = {} From b2b547273c96de5dd8cfcb53bffd0195e4cfefd7 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Thu, 10 Jun 2021 16:44:31 +0000 Subject: [PATCH 20/79] Added is_exist_in_db() Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 43 +++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index 22a7feeec5..0fc7236c94 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -92,23 +92,26 @@ def is_valid_ip_address(ctx, param, value): return str(ip) -def is_hash_field_list_valid(db, hash_field_list): - """ Check if --hash-field-list values are valid, - i.e was previously added by 'config pbh hash-field ...' command +def is_exist_in_db(db, _list, conf_db_key, option_name): + """ Check if provided CLI option already exist in Config DB, + i.g in case of --hash-field-list option it will check + if 'hash-field' was previously added by + 'config pbh hash-field ...' CLI command Args: db: reference to Config DB, - hash_field_list: value of --hash-field-list option + _list: value of 'click' option + conf_db_key: key to search in Config DB + option_name: name of 'click' option """ - pbh_hash_field_table = db.cfgdb.get_table("PBH_HASH_FIELD") - correct_hash_fields = list(pbh_hash_field_table.keys()) + table = db.cfgdb.get_table(conf_db_key) + correct_list = list(table.keys()) - hash_fields = hash_field_list.split(',') + splited_list = _list.split(',') - for hf in hash_fields: - if hf not in correct_hash_fields: - exit_with_error("Error: invalid --hash-field-list value, \ - please use {}".format(correct_hash_fields), fg="red") + for elem in splited_list: + if elem not in correct_list: + exit_with_error("Error: invalid value for {}, please use {}".format(option_name, correct_list), fg="red") @click.group(name='pbh', @@ -250,7 +253,7 @@ def PBH_HASH(): def PBH_HASH_add(db, hash_name, hash_field_list): """ Add object in PBH_HASH. """ - is_hash_field_list_valid(db, hash_field_list) + is_exist_in_db(db, hash_field_list, "PBH_HASH_FIELD", "--hash-field-list") table = "PBH_HASH" key = hash_name @@ -278,7 +281,7 @@ def PBH_HASH_add(db, hash_name, hash_field_list): def PBH_HASH_update(db, hash_name, hash_field_list): """ Add object in PBH_HASH. """ - is_hash_field_list_valid(db, hash_field_list) + is_exist_in_db(db, hash_field_list, "PBH_HASH_FIELD", "--hash-field-list") table = "PBH_HASH" key = hash_name @@ -331,7 +334,8 @@ def PBH_RULE(): ) @click.option( "--priority", - help="Configures priority for this rule[mandatory]", + help="Configures priority for this rule [mandatory]", + type=click.INT, ) @click.option( "--gre-key", @@ -360,10 +364,12 @@ def PBH_RULE(): @click.option( "--packet-action", help="Configures packet action for this rule", + type=click.Choice(packet_action_types) ) @click.option( "--flow-counter", help="Enables/Disables packet/byte counter for this rule", + type=click.Choice(flow_counter_state) ) @clicommon.pass_db def PBH_RULE_add(db, @@ -380,6 +386,9 @@ def PBH_RULE_add(db, flow_counter): """ Add object in PBH_RULE. """ + is_exist_in_db(db, table_name, "PBH_TABLE", "--table-name") + is_exist_in_db(db, hash, "PBH_HASH", "--hash") + table = "PBH_RULE" key = table_name, rule_name data = {} @@ -422,6 +431,7 @@ def PBH_RULE_add(db, @click.option( "--priority", help="Configures priority for this rule[mandatory]", + type=click.INT, ) @click.option( "--gre-key", @@ -450,10 +460,12 @@ def PBH_RULE_add(db, @click.option( "--packet-action", help="Configures packet action for this rule", + type=click.Choice(packet_action_types) ) @click.option( "--flow-counter", help="Enables/Disables packet/byte counter for this rule", + type=click.Choice(flow_counter_state) ) @clicommon.pass_db def PBH_RULE_update(db, @@ -470,6 +482,9 @@ def PBH_RULE_update(db, flow_counter): """ Add object in PBH_RULE. """ + is_exist_in_db(db, table_name, "PBH_TABLE", "--table-name") + is_exist_in_db(db, hash, "PBH_HASH", "--hash") + table = "PBH_RULE" key = table_name, rule_name data = {} From 4dca1221a1f2e4ce840a522c675a3dba9916d4d3 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Fri, 11 Jun 2021 12:29:06 +0000 Subject: [PATCH 21/79] Added is_match, interface_validator Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 91 ++++++++++++++++++++++++-------- 1 file changed, 69 insertions(+), 22 deletions(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index 0fc7236c94..7bef4db067 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -8,6 +8,7 @@ import click import ipaddress +import re import utilities_common.cli as clicommon import utilities_common.general as general @@ -24,6 +25,8 @@ flow_counter_state = ['DISABLED', 'ENABLED'] +pbh_pattern = r"(0x){1}[a-fA-F0-9]+/(0x){1}[a-fA-F0-9]+" + def exit_with_error(*args, **kwargs): """ Print a message and abort CLI. """ @@ -91,6 +94,13 @@ def is_valid_ip_address(ctx, param, value): return str(ip) +def is_match(ctx, param, value): + """ Check if PBH rule options is valid """ + + if value is not None: + if re.match(pbh_pattern, str(value)) is None: + exit_with_error("Error: invalid value for {}".format(param.name), fg="red") + def is_exist_in_db(db, _list, conf_db_key, option_name): """ Check if provided CLI option already exist in Config DB, @@ -111,7 +121,8 @@ def is_exist_in_db(db, _list, conf_db_key, option_name): for elem in splited_list: if elem not in correct_list: - exit_with_error("Error: invalid value for {}, please use {}".format(option_name, correct_list), fg="red") + exit_with_error("Error: invalid value for {}, \ + please use {}".format(option_name, correct_list), fg="red") @click.group(name='pbh', @@ -334,41 +345,48 @@ def PBH_RULE(): ) @click.option( "--priority", - help="Configures priority for this rule [mandatory]", + help="[MANDATORY] Configures priority", + required=True, type=click.INT, ) @click.option( "--gre-key", - help="Configures packet match for this rule: GRE key (value/mask)", + help="Configures packet match: GRE key (value/mask)", + callback=is_match, ) @click.option( "--ip-protocol", - help="Configures packet match for this rule: IP protocol (value/mask)", + help="Configures packet match: IP protocol (value/mask)", + callback=is_match, ) @click.option( "--ipv6-next-header", - help="Configures packet match for this rule: IPv6 Next header (value/mask)", + help="Configures packet match: IPv6 Next header (value/mask)", + callback=is_match, ) @click.option( "--l4-dst-port", - help="Configures packet match for this rule: L4 destination port (value/mask)", + help="Configures packet match: L4 destination port (value/mask)", + callback=is_match, ) @click.option( "--inner-ether-type", - help="Configures packet match for this rule: inner EtherType (value/mask)", + help="Configures packet match: inner EtherType (value/mask)", + callback=is_match, ) @click.option( "--hash", - help="The hash to apply with this rule[mandatory]", + required=True, + help="[MANDATORY] Configures the hash to apply", ) @click.option( "--packet-action", - help="Configures packet action for this rule", + help="Configures packet action", type=click.Choice(packet_action_types) ) @click.option( "--flow-counter", - help="Enables/Disables packet/byte counter for this rule", + help="Enables/Disables packet/byte counter", type=click.Choice(flow_counter_state) ) @clicommon.pass_db @@ -430,41 +448,48 @@ def PBH_RULE_add(db, ) @click.option( "--priority", - help="Configures priority for this rule[mandatory]", + help="[MANDATORY] Configures priority", + required=True, type=click.INT, ) @click.option( "--gre-key", - help="Configures packet match for this rule: GRE key (value/mask)", + help="Configures packet match: GRE key (value/mask)", + callback=is_match, ) @click.option( "--ip-protocol", - help="Configures packet match for this rule: IP protocol (value/mask)", + help="Configures packet match: IP protocol (value/mask)", + callback=is_match, ) @click.option( "--ipv6-next-header", - help="Configures packet match for this rule: IPv6 Next header (value/mask)", + help="Configures packet match: IPv6 Next header (value/mask)", + callback=is_match, ) @click.option( "--l4-dst-port", - help="Configures packet match for this rule: L4 destination port (value/mask)", + help="Configures packet match: L4 destination port (value/mask)", + callback=is_match, ) @click.option( "--inner-ether-type", - help="Configures packet match for this rule: inner EtherType (value/mask)", + help="Configures packet match: inner EtherType (value/mask)", + callback=is_match, ) @click.option( "--hash", - help="The hash to apply with this rule[mandatory]", + required=True, + help="[MANDATORY] The hash to apply with this rule", ) @click.option( "--packet-action", - help="Configures packet action for this rule", + help="Configures packet action", type=click.Choice(packet_action_types) ) @click.option( "--flow-counter", - help="Enables/Disables packet/byte counter for this rule", + help="Enables/Disables packet/byte counter", type=click.Choice(flow_counter_state) ) @clicommon.pass_db @@ -539,10 +564,27 @@ def PBH_RULE_delete(db, table_name, rule_name): @PBH.group(name="table", cls=clicommon.AliasedGroup) def PBH_TABLE(): - """ PBH_TABLE part of config_db.json """ + """ Configure PBH table""" pass +def interfaces_list_validator(db, interface_list): + error = False + interfaces = interface_list.split(',') + + for intf in interfaces: + if intf.startswith('Ethernet'): + if not clicommon.is_valid_port(db.cfgdb, intf): + error = True + elif intf.startswith('PortChannel'): + if not clicommon.is_valid_portchannel(db.cfgdb, intf): + error = True + else: + error = True + + if error: + exit_with_error("Error: invaliad value {}, for --interface-list option".format(interface_list), fg="red") + @PBH_TABLE.command(name="add") @click.argument( @@ -552,16 +594,20 @@ def PBH_TABLE(): ) @click.option( "--description", - help="The description of this table[mandatory]", + help="[MANDATORY] The description of this table", + required=True, ) @click.option( "--interface-list", help="Interfaces to which this table is applied", + required=True, ) @clicommon.pass_db def PBH_TABLE_add(db, table_name, description, interface_list): """ Add object in PBH_TABLE. """ + interfaces_list_validator(db, interface_list) + table = "PBH_TABLE" key = table_name data = {} @@ -584,7 +630,8 @@ def PBH_TABLE_add(db, table_name, description, interface_list): ) @click.option( "--description", - help="The description of this table[mandatory]", + help="[MANDATORY] The description of this table", + required=True, ) @click.option( "--interface-list", From e232188573eb95d65dd27f1436b0fe36909a2b9a Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Fri, 11 Jun 2021 13:00:55 +0000 Subject: [PATCH 22/79] Fixed codestyle Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 83 ++++++++++++++++---------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index 7bef4db067..0ca0dcef6f 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -50,7 +50,7 @@ def add_entry(db, table, key, data): def update_entry(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. + If attribute value in data is None, the attribute is deleted. """ cfg = db.get_config() @@ -84,7 +84,7 @@ def del_entry(db, table, key): db.set_entry(table, key, None) -def is_valid_ip_address(ctx, param, value): +def ip_address_validator(ctx, param, value): """ Check if the given ip address is valid """ # need to clarify @@ -94,7 +94,7 @@ def is_valid_ip_address(ctx, param, value): return str(ip) -def is_match(ctx, param, value): +def pbh_match(ctx, param, value): """ Check if PBH rule options is valid """ if value is not None: @@ -149,23 +149,24 @@ def PBH_HASH_FIELD(): ) @click.option( "--hash-field", - help="Configure native hash field for this hash field [mandatory]", + help="Configure native hash field for this hash field", required=True, type=click.Choice(hash_field_types) ) @click.option( "--ip-mask", - help="Configures IPv4/IPv6 address mask for this hash field [mandatory]", - callback=is_valid_ip_address + help="Configures IPv4/IPv6 address mask for this hash field", + callback=ip_address_validator ) @click.option( "--sequence-id", - help="Configures in which order the fields are hashed and defines which fields should be associative [mandatory]", + help="Configures in which order the fields are hashed and defines which fields should be associative", + required=True, type=click.INT, ) @clicommon.pass_db def PBH_HASH_FIELD_add(db, hash_field_name, hash_field, ip_mask, sequence_id): - """ Add object in PBH_HASH_FIELD. """ + """ Add object in PBH_HASH_FIELD table. """ table = "PBH_HASH_FIELD" key = hash_field_name @@ -191,22 +192,22 @@ def PBH_HASH_FIELD_add(db, hash_field_name, hash_field, ip_mask, sequence_id): ) @click.option( "--hash-field", - help="Configures native hash field for this hash field[mandatory]", + help="Configures native hash field for this hash field", type=click.Choice(hash_field_types) ) @click.option( "--ip-mask", - help="Configures IPv4/IPv6 address mask for this hash field[mandatory]", - callback=is_valid_ip_address + help="Configures IPv4/IPv6 address mask for this hash field", + callback=ip_address_validator ) @click.option( "--sequence-id", - help="Configures in which order the fields are hashed and defines which fields should be associative[mandatory]", + help="Configures in which order the fields are hashed and defines which fields should be associative", type=click.INT, ) @clicommon.pass_db def PBH_HASH_FIELD_update(db, hash_field_name, hash_field, ip_mask, sequence_id): - """ Add object in PBH_HASH_FIELD. """ + """ Update object in PBH_HASH_FIELD table """ table = "PBH_HASH_FIELD" key = hash_field_name @@ -232,7 +233,7 @@ def PBH_HASH_FIELD_update(db, hash_field_name, hash_field, ip_mask, sequence_id) ) @clicommon.pass_db def PBH_HASH_FIELD_delete(db, hash_field_name): - """ Delete object in PBH_HASH_FIELD. """ + """ Delete object from PBH_HASH_FIELD table """ table = "PBH_HASH_FIELD" key = hash_field_name @@ -259,10 +260,11 @@ def PBH_HASH(): @click.option( "--hash-field-list", help="The list of hash fields to apply with this hash", + required=True, ) @clicommon.pass_db def PBH_HASH_add(db, hash_name, hash_field_list): - """ Add object in PBH_HASH. """ + """ Add object in PBH_HASH table """ is_exist_in_db(db, hash_field_list, "PBH_HASH_FIELD", "--hash-field-list") @@ -290,7 +292,7 @@ def PBH_HASH_add(db, hash_name, hash_field_list): ) @clicommon.pass_db def PBH_HASH_update(db, hash_name, hash_field_list): - """ Add object in PBH_HASH. """ + """ Update object in PBH_HASH table """ is_exist_in_db(db, hash_field_list, "PBH_HASH_FIELD", "--hash-field-list") @@ -314,7 +316,7 @@ def PBH_HASH_update(db, hash_name, hash_field_list): ) @clicommon.pass_db def PBH_HASH_delete(db, hash_name): - """ Delete object in PBH_HASH. """ + """ Delete object from PBH_HASH table """ table = "PBH_HASH" key = hash_name @@ -327,7 +329,7 @@ def PBH_HASH_delete(db, hash_name): @PBH.group(name="rule", cls=clicommon.AliasedGroup) def PBH_RULE(): - """ PBH_RULE part of config_db.json """ + """ Configure PBH rule """ pass @@ -345,39 +347,39 @@ def PBH_RULE(): ) @click.option( "--priority", - help="[MANDATORY] Configures priority", + help="Configures priority", required=True, type=click.INT, ) @click.option( "--gre-key", help="Configures packet match: GRE key (value/mask)", - callback=is_match, + callback=pbh_match, ) @click.option( "--ip-protocol", help="Configures packet match: IP protocol (value/mask)", - callback=is_match, + callback=pbh_match, ) @click.option( "--ipv6-next-header", help="Configures packet match: IPv6 Next header (value/mask)", - callback=is_match, + callback=pbh_match, ) @click.option( "--l4-dst-port", help="Configures packet match: L4 destination port (value/mask)", - callback=is_match, + callback=pbh_match, ) @click.option( "--inner-ether-type", help="Configures packet match: inner EtherType (value/mask)", - callback=is_match, + callback=pbh_match, ) @click.option( "--hash", required=True, - help="[MANDATORY] Configures the hash to apply", + help="Configures the hash to apply", ) @click.option( "--packet-action", @@ -402,7 +404,7 @@ def PBH_RULE_add(db, hash, packet_action, flow_counter): - """ Add object in PBH_RULE. """ + """ Add object in PBH_RULE table """ is_exist_in_db(db, table_name, "PBH_TABLE", "--table-name") is_exist_in_db(db, hash, "PBH_HASH", "--hash") @@ -448,39 +450,39 @@ def PBH_RULE_add(db, ) @click.option( "--priority", - help="[MANDATORY] Configures priority", + help="Configures priority", required=True, type=click.INT, ) @click.option( "--gre-key", help="Configures packet match: GRE key (value/mask)", - callback=is_match, + callback=pbh_match, ) @click.option( "--ip-protocol", help="Configures packet match: IP protocol (value/mask)", - callback=is_match, + callback=pbh_match, ) @click.option( "--ipv6-next-header", help="Configures packet match: IPv6 Next header (value/mask)", - callback=is_match, + callback=pbh_match, ) @click.option( "--l4-dst-port", help="Configures packet match: L4 destination port (value/mask)", - callback=is_match, + callback=pbh_match, ) @click.option( "--inner-ether-type", help="Configures packet match: inner EtherType (value/mask)", - callback=is_match, + callback=pbh_match, ) @click.option( "--hash", required=True, - help="[MANDATORY] The hash to apply with this rule", + help="The hash to apply with this rule", ) @click.option( "--packet-action", @@ -505,7 +507,7 @@ def PBH_RULE_update(db, hash, packet_action, flow_counter): - """ Add object in PBH_RULE. """ + """ Update object in PBH_RULE table """ is_exist_in_db(db, table_name, "PBH_TABLE", "--table-name") is_exist_in_db(db, hash, "PBH_HASH", "--hash") @@ -551,7 +553,7 @@ def PBH_RULE_update(db, ) @clicommon.pass_db def PBH_RULE_delete(db, table_name, rule_name): - """ Delete object in PBH_RULE. """ + """ Delete object from PBH_RULE table """ table = "PBH_RULE" key = table_name, rule_name @@ -594,7 +596,7 @@ def interfaces_list_validator(db, interface_list): ) @click.option( "--description", - help="[MANDATORY] The description of this table", + help="The description of this table", required=True, ) @click.option( @@ -604,7 +606,7 @@ def interfaces_list_validator(db, interface_list): ) @clicommon.pass_db def PBH_TABLE_add(db, table_name, description, interface_list): - """ Add object in PBH_TABLE. """ + """ Add object in PBH_TABLE table """ interfaces_list_validator(db, interface_list) @@ -630,8 +632,7 @@ def PBH_TABLE_add(db, table_name, description, interface_list): ) @click.option( "--description", - help="[MANDATORY] The description of this table", - required=True, + help="The description of this table", ) @click.option( "--interface-list", @@ -639,7 +640,7 @@ def PBH_TABLE_add(db, table_name, description, interface_list): ) @clicommon.pass_db def PBH_TABLE_update(db, table_name, description, interface_list): - """ Add object in PBH_TABLE. """ + """ Update object in PBH_TABLE table """ table = "PBH_TABLE" key = table_name @@ -663,7 +664,7 @@ def PBH_TABLE_update(db, table_name, description, interface_list): ) @clicommon.pass_db def PBH_TABLE_delete(db, table_name): - """ Delete object in PBH_TABLE. """ + """ Delete object from PBH_TABLE table """ table = "PBH_TABLE" key = table_name From eff1729bd6f12e64b4b5986b8e9de4a0cafafafa Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Fri, 11 Jun 2021 14:15:16 +0000 Subject: [PATCH 23/79] HOT FIX Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 24 ++++++++++++++---------- show/plugins/sonic-pbh_yang.py | 4 ++-- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index 0ca0dcef6f..4562b9a23c 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -88,11 +88,13 @@ def ip_address_validator(ctx, param, value): """ Check if the given ip address is valid """ # need to clarify - ip = ipaddress.ip_address(value) - if (ip.is_reserved) or (ip.is_multicast) or (ip.is_global) or (ip.is_link_local): - raise ipaddress.AddressValueError + if value is not None: + ip = ipaddress.ip_address(value) + if (ip.is_reserved) or (ip.is_multicast) or (ip.is_global) or (ip.is_link_local): + exit_with_error("Error: invalid value for {}".format(param.name), fg="red") + + return value - return str(ip) def pbh_match(ctx, param, value): """ Check if PBH rule options is valid """ @@ -101,6 +103,8 @@ def pbh_match(ctx, param, value): if re.match(pbh_pattern, str(value)) is None: exit_with_error("Error: invalid value for {}".format(param.name), fg="red") + return value + def is_exist_in_db(db, _list, conf_db_key, option_name): """ Check if provided CLI option already exist in Config DB, @@ -156,7 +160,7 @@ def PBH_HASH_FIELD(): @click.option( "--ip-mask", help="Configures IPv4/IPv6 address mask for this hash field", - callback=ip_address_validator + callback=ip_address_validator, ) @click.option( "--sequence-id", @@ -166,7 +170,7 @@ def PBH_HASH_FIELD(): ) @clicommon.pass_db def PBH_HASH_FIELD_add(db, hash_field_name, hash_field, ip_mask, sequence_id): - """ Add object in PBH_HASH_FIELD table. """ + """ Add object to PBH_HASH_FIELD table """ table = "PBH_HASH_FIELD" key = hash_field_name @@ -198,7 +202,7 @@ def PBH_HASH_FIELD_add(db, hash_field_name, hash_field, ip_mask, sequence_id): @click.option( "--ip-mask", help="Configures IPv4/IPv6 address mask for this hash field", - callback=ip_address_validator + callback=ip_address_validator, ) @click.option( "--sequence-id", @@ -264,7 +268,7 @@ def PBH_HASH(): ) @clicommon.pass_db def PBH_HASH_add(db, hash_name, hash_field_list): - """ Add object in PBH_HASH table """ + """ Add object to PBH_HASH table """ is_exist_in_db(db, hash_field_list, "PBH_HASH_FIELD", "--hash-field-list") @@ -404,7 +408,7 @@ def PBH_RULE_add(db, hash, packet_action, flow_counter): - """ Add object in PBH_RULE table """ + """ Add object to PBH_RULE table """ is_exist_in_db(db, table_name, "PBH_TABLE", "--table-name") is_exist_in_db(db, hash, "PBH_HASH", "--hash") @@ -606,7 +610,7 @@ def interfaces_list_validator(db, interface_list): ) @clicommon.pass_db def PBH_TABLE_add(db, table_name, description, interface_list): - """ Add object in PBH_TABLE table """ + """ Add object to PBH_TABLE table """ interfaces_list_validator(db, interface_list) diff --git a/show/plugins/sonic-pbh_yang.py b/show/plugins/sonic-pbh_yang.py index a88a2a8d33..10e1eb7b87 100644 --- a/show/plugins/sonic-pbh_yang.py +++ b/show/plugins/sonic-pbh_yang.py @@ -143,7 +143,7 @@ def PBH_HASH(db): """ Show the PBH hash configuration """ header = [ - "Hash", + "Name", "Hash field", ] @@ -187,7 +187,7 @@ def PBH_RULE(db): "Match", "Hash", "Action", - "Flow counter", + "Counter", ] body = [] From 096602e44d16de2e7bb074ca0f7a6cfa77ccbf4b Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Sun, 13 Jun 2021 09:14:34 +0000 Subject: [PATCH 24/79] Fixed issue with click callbacks Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index 4562b9a23c..90362cd802 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -87,13 +87,13 @@ def del_entry(db, table, key): def ip_address_validator(ctx, param, value): """ Check if the given ip address is valid """ - # need to clarify if value is not None: - ip = ipaddress.ip_address(value) - if (ip.is_reserved) or (ip.is_multicast) or (ip.is_global) or (ip.is_link_local): - exit_with_error("Error: invalid value for {}".format(param.name), fg="red") + try: + ip = ipaddress.ip_address(value) + except Exception as e: + exit_with_error("Error: invalid value for <{}>\n{}".format(param.name, e), fg="red") - return value + return str(ip) def pbh_match(ctx, param, value): @@ -101,9 +101,9 @@ def pbh_match(ctx, param, value): if value is not None: if re.match(pbh_pattern, str(value)) is None: - exit_with_error("Error: invalid value for {}".format(param.name), fg="red") + exit_with_error("Error: invalid value for <{}>".format(param.name), fg="red") - return value + return value def is_exist_in_db(db, _list, conf_db_key, option_name): @@ -125,7 +125,7 @@ def is_exist_in_db(db, _list, conf_db_key, option_name): for elem in splited_list: if elem not in correct_list: - exit_with_error("Error: invalid value for {}, \ + exit_with_error("Error: invalid value for <{}>, \ please use {}".format(option_name, correct_list), fg="red") From be744a0e114210f3a3e6556350932d3333ec02a2 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Mon, 14 Jun 2021 14:45:18 +0000 Subject: [PATCH 25/79] Fixed sort output for show CLI, typo fixes Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 3 +-- show/plugins/sonic-pbh_yang.py | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index 90362cd802..3cb4f8eb05 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -125,8 +125,7 @@ def is_exist_in_db(db, _list, conf_db_key, option_name): for elem in splited_list: if elem not in correct_list: - exit_with_error("Error: invalid value for <{}>, \ - please use {}".format(option_name, correct_list), fg="red") + exit_with_error("Error: invalid value for <{}>, please use {}".format(option_name, correct_list), fg="red") @click.group(name='pbh', diff --git a/show/plugins/sonic-pbh_yang.py b/show/plugins/sonic-pbh_yang.py index 10e1eb7b87..37fbf697e2 100644 --- a/show/plugins/sonic-pbh_yang.py +++ b/show/plugins/sonic-pbh_yang.py @@ -131,7 +131,7 @@ def PBH_HASH_FIELD(db): body.append(row) # sorted by 'sequence_id' - body_sorted = sorted(body, key=itemgetter(3)) + body_sorted = sorted(body, key=lambda e: int(e[3])) click.echo(tabulate.tabulate(body_sorted, header)) @@ -283,7 +283,7 @@ def PBH_RULE(db): body.append(row) # sorted by 'Priority' - body_sorted = sorted(body, key=itemgetter(2)) + body_sorted = sorted(body, key=lambda e: int(e[2])) click.echo(tabulate.tabulate(body_sorted, header)) From 37397575b4f90c49cf08b30a254867cf33d9de2f Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Mon, 14 Jun 2021 14:45:44 +0000 Subject: [PATCH 26/79] Added few 'hash-field' tests Signed-off-by: Vadym Hlushko --- tests/pbh_test.py | 94 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 82 insertions(+), 12 deletions(-) diff --git a/tests/pbh_test.py b/tests/pbh_test.py index 2ff4fbdabf..7207f7f196 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -19,34 +19,104 @@ def setup_class(cls): logger.info("SETUP") os.environ['UTILITIES_UNIT_TESTING'] = "1" + ########## HASH-FIELD ########## - def test_config_pbh_table_add(self): + def test_hash_field_add_no_ip_mask(self): db = Db() obj = { 'db': db.cfgdb } runner = CliRunner() + result = runner.invoke(config.config.commands["pbh"]. - commands["table"].commands["add"], - ["pbh_table", "--interface-list", "Ethernet0,Ethernet4", - "--description", "NVGRE"], obj=obj) - logger.debug(result.exit_code) + commands["hash-field"].commands["add"], + ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", + "--sequence-id", "1"], obj=obj) + logger.debug(result.output) - #import pdb; pdb.set_trace() + logger.debug(result.exit_code) + logger.debug(result.stdout) + assert result.exit_code == 0 - # assert for dict - def test_config_pbh_hash_field(self): + def test_hash_field_add_ip4_mask(self): db = Db() obj = { 'db': db.cfgdb } runner = CliRunner() + result = runner.invoke(config.config.commands["pbh"]. commands["hash-field"].commands["add"], - ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", - "--sequence-id", "1"], obj=obj) + ["inner_dst_ipv4", "--hash-field", "INNER_DST_IPV4", + "--ip-mask", "255.0.0.0", + "--sequence-id", "3"], obj=obj) + + logger.debug(result.output) logger.debug(result.exit_code) + logger.debug(result.stdout) + + assert result.exit_code == 0 + + def test_hash_field_add_ip6_mask(self): + db = Db() + obj = { 'db': db.cfgdb } + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["add"], + ["inner_dst_ipv6", "--hash-field", "INNER_DST_IPV6", + "--ip-mask", "ffff::", + "--sequence-id", "4"], obj=obj) + logger.debug(result.output) - #import pdb; pdb.set_trace() + logger.debug(result.exit_code) + logger.debug(result.stdout) + assert result.exit_code == 0 - # assert for dict + + ########## HASH-FIELD ########## + + #def test_config_pbh_table_add(self): + # db = Db() + # obj = { 'db': db.cfgdb } + # runner = CliRunner() + # result = runner.invoke(config.config.commands["pbh"]. + # commands["table"].commands["add"], + # ["pbh_table", "--interface-list", "Ethernet0,Ethernet4", + # "--description", "NVGRE"], obj=obj) + # logger.debug(result.exit_code) + # logger.debug(result.output) + # #import pdb; pdb.set_trace() + # assert result.exit_code == 0 + # #assert result.outup == correct_dict + + #def test_(self): + # db = Db() + # obj = { 'db': db.cfgdb } + # runner = CliRunner() + + # result = runner.invoke(config.config.commands["pbh"]. + # commands[""].commands["add"], + # ["", "--", "", + # "--", ""], obj=obj) + + # logger.debug(result.stdout) + # logger.debug(result.exit_code) + # logger.debug(result.output) + + # #assert result.exit_code == 0 + # #assert result.outup == correct_dict + + #def test_config_pbh_hash_field(self): + # db = Db() + # obj = { 'db': db.cfgdb } + # runner = CliRunner() + # result = runner.invoke(config.config.commands["pbh"]. + # commands["hash-field"].commands["add"], + # ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", + # "--sequence-id", "1"], obj=obj) + # logger.debug(result.exit_code) + # logger.debug(result.output) + # #import pdb; pdb.set_trace() + # assert result.exit_code == 0 + # # assert for dict @classmethod From 4d005d89bfea8db40b02bac8c688bb6215acff8e Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Mon, 14 Jun 2021 16:42:02 +0000 Subject: [PATCH 27/79] Fixed issue with 'config pbh rule update' Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index 3cb4f8eb05..7b10f3d370 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -454,7 +454,6 @@ def PBH_RULE_add(db, @click.option( "--priority", help="Configures priority", - required=True, type=click.INT, ) @click.option( @@ -484,7 +483,6 @@ def PBH_RULE_add(db, ) @click.option( "--hash", - required=True, help="The hash to apply with this rule", ) @click.option( From cf971b5b7254dce0b8efd986ef3e6a2366534e32 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Mon, 14 Jun 2021 16:46:42 +0000 Subject: [PATCH 28/79] HOTFIX for 'config pbh rule update' is_exist_in_db() Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index 7b10f3d370..4599502741 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -118,6 +118,10 @@ def is_exist_in_db(db, _list, conf_db_key, option_name): conf_db_key: key to search in Config DB option_name: name of 'click' option """ + + if _list is None: + return + table = db.cfgdb.get_table(conf_db_key) correct_list = list(table.keys()) From e864d1274e6adf74a9a8a7df9c2a8a83db6c1630 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 15 Jun 2021 07:36:23 +0000 Subject: [PATCH 29/79] Added proper description for --ip-mask Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index 4599502741..eef1075702 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -162,7 +162,8 @@ def PBH_HASH_FIELD(): ) @click.option( "--ip-mask", - help="Configures IPv4/IPv6 address mask for this hash field", + help="""Configures IPv4/IPv6 address mask for this hash field required when the value of --hash-field are - INNER_DST_IPV4 or + INNER_SRC_IPV4 or INNER_SRC_IPV4 or INNER_SRC_IPV4 """, callback=ip_address_validator, ) @click.option( From 305021261a5e7ba64be1d18e8d601b2cc25953f7 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 15 Jun 2021 15:47:00 +0000 Subject: [PATCH 30/79] Added ip_mask & hash-field validation for ADD flow Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index eef1075702..4c5a05550a 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -11,6 +11,7 @@ import re import utilities_common.cli as clicommon import utilities_common.general as general +from ipaddress import IPv4Address, IPv6Address hash_field_types = ['INNER_IP_PROTOCOL', @@ -91,7 +92,7 @@ def ip_address_validator(ctx, param, value): try: ip = ipaddress.ip_address(value) except Exception as e: - exit_with_error("Error: invalid value for <{}>\n{}".format(param.name, e), fg="red") + exit_with_error("Error: invalid value for '{}'\n{}".format(param.name, e), fg="red") return str(ip) @@ -101,7 +102,7 @@ def pbh_match(ctx, param, value): if value is not None: if re.match(pbh_pattern, str(value)) is None: - exit_with_error("Error: invalid value for <{}>".format(param.name), fg="red") + exit_with_error("Error: invalid value for '{}'".format(param.name), fg="red") return value @@ -129,7 +130,23 @@ def is_exist_in_db(db, _list, conf_db_key, option_name): for elem in splited_list: if elem not in correct_list: - exit_with_error("Error: invalid value for <{}>, please use {}".format(option_name, correct_list), fg="red") + exit_with_error("Error: invalid value for '{}', please use {}".format(option_name, correct_list), fg="red") + + +def ip_mask_hash_field_correspondence(ip_mask, hash_field): + + # ask Nazarii + if ((hash_field == 'INNER_IP_PROTOCOL' or hash_field == 'INNER_L4_DST_PORT' or + hash_field == 'INNER_L4_SRC_PORT') and (ip_mask is not None)): + exit_with_error("Error: if the --hash-field value is '{}', the value of --ip-mask shoud be empty".format(hash_field)) + + if ((hash_field == 'INNER_DST_IPV4' or hash_field == 'INNER_SRC_IPV4') and + (not isinstance(ipaddress.ip_address(ip_mask), IPv4Address))): + exit_with_error("Error: --hash-field value '{}' not correspond to --ip-mask value '{}'".format(hash_field, ip_mask)) + + if ((hash_field == 'INNER_DST_IPV6' or hash_field == 'INNER_SRC_IPV6') and + (not isinstance(ipaddress.ip_address(ip_mask), IPv6Address))): + exit_with_error("Error: --hash-field value '{}' not correspond to --ip-mask value '{}'".format(hash_field, ip_mask)) @click.group(name='pbh', @@ -176,6 +193,8 @@ def PBH_HASH_FIELD(): def PBH_HASH_FIELD_add(db, hash_field_name, hash_field, ip_mask, sequence_id): """ Add object to PBH_HASH_FIELD table """ + ip_mask_hash_field_correspondence(ip_mask, hash_field) + table = "PBH_HASH_FIELD" key = hash_field_name data = {} From d97465fecf1e8c37c003380527cfe9d8a649616c Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 15 Jun 2021 15:47:35 +0000 Subject: [PATCH 31/79] Added tests for 'config pbh hash-field add' flow Signed-off-by: Vadym Hlushko --- tests/pbh_test.py | 156 +++++++++++++++++++++++++++++++--------------- 1 file changed, 105 insertions(+), 51 deletions(-) diff --git a/tests/pbh_test.py b/tests/pbh_test.py index 7207f7f196..3a4c9021d2 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -12,6 +12,9 @@ logger = logging.getLogger(__name__) test_path = os.path.dirname(os.path.abspath(__file__)) +SUCCESS = 0 +ERROR = 1 + class TestPBH: @classmethod @@ -33,9 +36,8 @@ def test_hash_field_add_no_ip_mask(self): logger.debug(result.output) logger.debug(result.exit_code) - logger.debug(result.stdout) - assert result.exit_code == 0 + assert result.exit_code == SUCCESS def test_hash_field_add_ip4_mask(self): db = Db() @@ -50,9 +52,8 @@ def test_hash_field_add_ip4_mask(self): logger.debug(result.output) logger.debug(result.exit_code) - logger.debug(result.stdout) - assert result.exit_code == 0 + assert result.exit_code == SUCCESS def test_hash_field_add_ip6_mask(self): db = Db() @@ -67,57 +68,110 @@ def test_hash_field_add_ip6_mask(self): logger.debug(result.output) logger.debug(result.exit_code) - logger.debug(result.stdout) - assert result.exit_code == 0 + assert result.exit_code == SUCCESS - ########## HASH-FIELD ########## + # negative add: --hash-field & --ip-mask mismatch + def test_hash_field_add_hash_field_with_ip(self): + db = Db() + obj = { 'db': db.cfgdb } + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["add"], + ["inner_ip_protocol", "--hash-field", "INNER_IP_PROTOCOL", + "--ip-mask", "255.0.0.0", + "--sequence-id", "1"], obj=obj) + + logger.debug(result.output) + logger.debug(result.exit_code) + + assert result.exit_code == ERROR + + # negative add: --hash-field v6 & --ip-mask v4 mismatch + def test_hash_field_add_ipv4_mismatch(self): + db = Db() + obj = { 'db': db.cfgdb } + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["add"], + ["inner_src_ipv6", "--hash-field", "INNER_SRC_IPV6", + "--ip-mask", "255.0.0.0", + "--sequence-id", "4"], obj=obj) + + logger.debug(result.output) + logger.debug(result.exit_code) + + assert result.exit_code == ERROR + + # negative add: --hash-field v4 & --ip-mask v6 mismatch + def test_hash_field_add_ipv6_mismatch(self): + db = Db() + obj = { 'db': db.cfgdb } + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["add"], + ["inner_src_ipv4", "--hash-field", "INNER_SRC_IPV4", + "--ip-mask", "ffff::", + "--sequence-id", "2"], obj=obj) + + logger.debug(result.output) + logger.debug(result.exit_code) + + assert result.exit_code == ERROR + + # negative add: invalid --ip-mask + def test_hash_field_add_invalid_ip(self): + db = Db() + obj = { 'db': db.cfgdb } + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["add"], + ["inner_src_ipv4", "--hash-field", "INNER_SRC_IPV4", + "--ip-mask", "WRONG", + "--sequence-id", "2"], obj=obj) + + logger.debug(result.output) + logger.debug(result.exit_code) + + assert result.exit_code == ERROR + + # negative add: None --ip-mask + def test_hash_field_add_none_ipv4(self): + db = Db() + obj = { 'db': db.cfgdb } + runner = CliRunner() - #def test_config_pbh_table_add(self): - # db = Db() - # obj = { 'db': db.cfgdb } - # runner = CliRunner() - # result = runner.invoke(config.config.commands["pbh"]. - # commands["table"].commands["add"], - # ["pbh_table", "--interface-list", "Ethernet0,Ethernet4", - # "--description", "NVGRE"], obj=obj) - # logger.debug(result.exit_code) - # logger.debug(result.output) - # #import pdb; pdb.set_trace() - # assert result.exit_code == 0 - # #assert result.outup == correct_dict - - #def test_(self): - # db = Db() - # obj = { 'db': db.cfgdb } - # runner = CliRunner() - - # result = runner.invoke(config.config.commands["pbh"]. - # commands[""].commands["add"], - # ["", "--", "", - # "--", ""], obj=obj) - - # logger.debug(result.stdout) - # logger.debug(result.exit_code) - # logger.debug(result.output) - - # #assert result.exit_code == 0 - # #assert result.outup == correct_dict - - #def test_config_pbh_hash_field(self): - # db = Db() - # obj = { 'db': db.cfgdb } - # runner = CliRunner() - # result = runner.invoke(config.config.commands["pbh"]. - # commands["hash-field"].commands["add"], - # ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", - # "--sequence-id", "1"], obj=obj) - # logger.debug(result.exit_code) - # logger.debug(result.output) - # #import pdb; pdb.set_trace() - # assert result.exit_code == 0 - # # assert for dict + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["add"], + ["inner_src_ipv4", "--hash-field", "INNER_SRC_IPV4", + "--sequence-id", "2"], obj=obj) + + logger.debug(result.output) + logger.debug(result.exit_code) + + assert result.exit_code == ERROR + + # negative add: None --ip-mask + def test_hash_field_add_none_ipv6(self): + db = Db() + obj = { 'db': db.cfgdb } + runner = CliRunner() + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["add"], + ["inner_src_ipv6", "--hash-field", "INNER_SRC_IPV6", + "--sequence-id", "2"], obj=obj) + + logger.debug(result.output) + logger.debug(result.exit_code) + + assert result.exit_code == ERROR + + ########## HASH-FIELD ########## @classmethod def teardown_class(cls): From 8ae9fbf43b7af7460b830ae15a0df6bb00669f74 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Wed, 16 Jun 2021 12:50:41 +0000 Subject: [PATCH 32/79] Fixed 'hash-field' add/update, added UT Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 51 ++++++-- tests/pbh_test.py | 208 ++++++++++++++++++++++++++++--- 2 files changed, 232 insertions(+), 27 deletions(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index 4c5a05550a..14dee411b4 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -134,19 +134,54 @@ def is_exist_in_db(db, _list, conf_db_key, option_name): def ip_mask_hash_field_correspondence(ip_mask, hash_field): + # at this point + # --ip_mask value can be None or VALID IP + # --hash_field always valid - # ask Nazarii - if ((hash_field == 'INNER_IP_PROTOCOL' or hash_field == 'INNER_L4_DST_PORT' or - hash_field == 'INNER_L4_SRC_PORT') and (ip_mask is not None)): - exit_with_error("Error: if the --hash-field value is '{}', the value of --ip-mask shoud be empty".format(hash_field)) + if ((ip_mask is None) and + (hash_field == 'INNER_DST_IPV4' or hash_field == 'INNER_SRC_IPV4' or + hash_field == 'INNER_DST_IPV6' or hash_field == 'INNER_SRC_IPV6')): + exit_with_error("Error: the value of --hash-field='{}' is NOT compatible with the value of --ip-mask='{}'".format(hash_field, ip_mask), fg='red') + + if ((ip_mask is not None) and + (hash_field == 'INNER_IP_PROTOCOL' or + hash_field == 'INNER_L4_DST_PORT' or + hash_field == 'INNER_L4_SRC_PORT')): + exit_with_error("Error: the value of --hash-field='{}' is NOT compatible with the value of --ip-mask='{}'".format(hash_field, ip_mask), fg='red') if ((hash_field == 'INNER_DST_IPV4' or hash_field == 'INNER_SRC_IPV4') and - (not isinstance(ipaddress.ip_address(ip_mask), IPv4Address))): - exit_with_error("Error: --hash-field value '{}' not correspond to --ip-mask value '{}'".format(hash_field, ip_mask)) + (not isinstance(ipaddress.ip_address(ip_mask), IPv4Address))): + exit_with_error("Error: the value of --hash-field='{}' is NOT compatible with the value of --ip-mask='{}'".format(hash_field, ip_mask), fg='red') if ((hash_field == 'INNER_DST_IPV6' or hash_field == 'INNER_SRC_IPV6') and (not isinstance(ipaddress.ip_address(ip_mask), IPv6Address))): - exit_with_error("Error: --hash-field value '{}' not correspond to --ip-mask value '{}'".format(hash_field, ip_mask)) + exit_with_error("Error: the value of --hash-field='{}' is NOT compatible with the value of --ip-mask='{}'".format(hash_field, ip_mask), fg='red') + +def update_ip_mask_hash_field(db, hash_field_name, ip_mask, hash_field): + + if (ip_mask is None) and (hash_field is None): + return + + table = db.cfgdb.get_table('PBH_HASH_FIELD') + hash_field_obj = table[hash_field_name] + + if (ip_mask is None) and (hash_field is not None): + + try: + ip_mask = hash_field_obj['ip_mask'] + except Exception as e: + ip_mask = None + + ip_mask_hash_field_correspondence(ip_mask, hash_field) + + if (ip_mask is not None) and (hash_field is None): + + try: + hash_field = hash_field_obj['hash_field'] + except Exception as e: + hash_field = None + + ip_mask_hash_field_correspondence(ip_mask, hash_field_obj['hash_field']) @click.group(name='pbh', @@ -236,6 +271,8 @@ def PBH_HASH_FIELD_add(db, hash_field_name, hash_field, ip_mask, sequence_id): def PBH_HASH_FIELD_update(db, hash_field_name, hash_field, ip_mask, sequence_id): """ Update object in PBH_HASH_FIELD table """ + update_ip_mask_hash_field(db, hash_field_name, ip_mask, hash_field) + table = "PBH_HASH_FIELD" key = hash_field_name data = {} diff --git a/tests/pbh_test.py b/tests/pbh_test.py index 3a4c9021d2..0af6eb8189 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -10,7 +10,6 @@ logger = logging.getLogger(__name__) -test_path = os.path.dirname(os.path.abspath(__file__)) SUCCESS = 0 ERROR = 1 @@ -24,15 +23,23 @@ def setup_class(cls): ########## HASH-FIELD ########## - def test_hash_field_add_no_ip_mask(self): + def test_hash_field_add_delete_no_ip_mask(self): db = Db() - obj = { 'db': db.cfgdb } runner = CliRunner() result = runner.invoke(config.config.commands["pbh"]. commands["hash-field"].commands["add"], ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", - "--sequence-id", "1"], obj=obj) + "--sequence-id", "1"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + + assert result.exit_code == SUCCESS + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["delete"], + ["inner_ip_proto"], obj=db) logger.debug(result.output) logger.debug(result.exit_code) @@ -41,14 +48,13 @@ def test_hash_field_add_no_ip_mask(self): def test_hash_field_add_ip4_mask(self): db = Db() - obj = { 'db': db.cfgdb } runner = CliRunner() result = runner.invoke(config.config.commands["pbh"]. commands["hash-field"].commands["add"], ["inner_dst_ipv4", "--hash-field", "INNER_DST_IPV4", "--ip-mask", "255.0.0.0", - "--sequence-id", "3"], obj=obj) + "--sequence-id", "3"], obj=db) logger.debug(result.output) logger.debug(result.exit_code) @@ -57,14 +63,13 @@ def test_hash_field_add_ip4_mask(self): def test_hash_field_add_ip6_mask(self): db = Db() - obj = { 'db': db.cfgdb } runner = CliRunner() result = runner.invoke(config.config.commands["pbh"]. commands["hash-field"].commands["add"], ["inner_dst_ipv6", "--hash-field", "INNER_DST_IPV6", "--ip-mask", "ffff::", - "--sequence-id", "4"], obj=obj) + "--sequence-id", "4"], obj=db) logger.debug(result.output) logger.debug(result.exit_code) @@ -74,14 +79,13 @@ def test_hash_field_add_ip6_mask(self): # negative add: --hash-field & --ip-mask mismatch def test_hash_field_add_hash_field_with_ip(self): db = Db() - obj = { 'db': db.cfgdb } runner = CliRunner() result = runner.invoke(config.config.commands["pbh"]. commands["hash-field"].commands["add"], ["inner_ip_protocol", "--hash-field", "INNER_IP_PROTOCOL", "--ip-mask", "255.0.0.0", - "--sequence-id", "1"], obj=obj) + "--sequence-id", "1"], obj=db) logger.debug(result.output) logger.debug(result.exit_code) @@ -91,14 +95,13 @@ def test_hash_field_add_hash_field_with_ip(self): # negative add: --hash-field v6 & --ip-mask v4 mismatch def test_hash_field_add_ipv4_mismatch(self): db = Db() - obj = { 'db': db.cfgdb } runner = CliRunner() result = runner.invoke(config.config.commands["pbh"]. commands["hash-field"].commands["add"], ["inner_src_ipv6", "--hash-field", "INNER_SRC_IPV6", "--ip-mask", "255.0.0.0", - "--sequence-id", "4"], obj=obj) + "--sequence-id", "4"], obj=db) logger.debug(result.output) logger.debug(result.exit_code) @@ -108,14 +111,13 @@ def test_hash_field_add_ipv4_mismatch(self): # negative add: --hash-field v4 & --ip-mask v6 mismatch def test_hash_field_add_ipv6_mismatch(self): db = Db() - obj = { 'db': db.cfgdb } runner = CliRunner() result = runner.invoke(config.config.commands["pbh"]. commands["hash-field"].commands["add"], ["inner_src_ipv4", "--hash-field", "INNER_SRC_IPV4", "--ip-mask", "ffff::", - "--sequence-id", "2"], obj=obj) + "--sequence-id", "2"], obj=db) logger.debug(result.output) logger.debug(result.exit_code) @@ -125,14 +127,13 @@ def test_hash_field_add_ipv6_mismatch(self): # negative add: invalid --ip-mask def test_hash_field_add_invalid_ip(self): db = Db() - obj = { 'db': db.cfgdb } runner = CliRunner() result = runner.invoke(config.config.commands["pbh"]. commands["hash-field"].commands["add"], ["inner_src_ipv4", "--hash-field", "INNER_SRC_IPV4", "--ip-mask", "WRONG", - "--sequence-id", "2"], obj=obj) + "--sequence-id", "2"], obj=db) logger.debug(result.output) logger.debug(result.exit_code) @@ -142,13 +143,12 @@ def test_hash_field_add_invalid_ip(self): # negative add: None --ip-mask def test_hash_field_add_none_ipv4(self): db = Db() - obj = { 'db': db.cfgdb } runner = CliRunner() result = runner.invoke(config.config.commands["pbh"]. commands["hash-field"].commands["add"], ["inner_src_ipv4", "--hash-field", "INNER_SRC_IPV4", - "--sequence-id", "2"], obj=obj) + "--sequence-id", "2"], obj=db) logger.debug(result.output) logger.debug(result.exit_code) @@ -158,19 +158,187 @@ def test_hash_field_add_none_ipv4(self): # negative add: None --ip-mask def test_hash_field_add_none_ipv6(self): db = Db() - obj = { 'db': db.cfgdb } runner = CliRunner() result = runner.invoke(config.config.commands["pbh"]. commands["hash-field"].commands["add"], ["inner_src_ipv6", "--hash-field", "INNER_SRC_IPV6", - "--sequence-id", "2"], obj=obj) + "--sequence-id", "2"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + + assert result.exit_code == ERROR + + def test_hash_field_update_sequence_id(self): + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["add"], + ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", + "--sequence-id", "1"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + + assert result.exit_code == SUCCESS + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["update"], + ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", + "--sequence-id", "2"], obj=db) + + assert result.exit_code == SUCCESS + + result = runner.invoke(show.cli.commands["pbh"].commands["hash-field"], [], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + + def test_hash_field_update_hash_field(self): + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["add"], + ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", + "--sequence-id", "1"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + + assert result.exit_code == SUCCESS + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["update"], + ["inner_ip_proto", "--hash-field", "INNER_L4_DST_PORT", + "--sequence-id", "2"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + + assert result.exit_code == SUCCESS + + def test_hash_field_update_hash_field_ip_mask(self): + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["add"], + ["inner_dst_ipv4", "--hash-field", "INNER_DST_IPV4", + "--ip-mask", "255.0.0.0", "--sequence-id", "1"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + + assert result.exit_code == SUCCESS + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["update"], + ["inner_dst_ipv4", "--hash-field", "INNER_SRC_IPV4", + "--ip-mask", "0.0.0.255", "--sequence-id", "2"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + + assert result.exit_code == SUCCESS + + def test_hash_field_update_wrong_hash_field(self): + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["add"], + ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", + "--sequence-id", "1"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + + assert result.exit_code == SUCCESS + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["update"], + ["inner_ip_proto", "--hash-field", "INNER_DST_IPV4", + "--sequence-id", "2"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + + assert result.exit_code == ERROR + + def test_hash_field_update_wrong_ipv4_mask1(self): + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["add"], + ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", + "--sequence-id", "1"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + + assert result.exit_code == SUCCESS + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["update"], + ["inner_ip_proto", "--ip-mask", "0.0.0.255"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + + assert result.exit_code == ERROR + + def test_hash_field_update_wrong_ipv6_mask(self): + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["add"], + ["inner_dst_ipv6", "--hash-field", "INNER_DST_IPV6", + "--ip-mask", "ffff::", "--sequence-id", "3"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + + assert result.exit_code == SUCCESS + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["update"], + ["inner_dst_ipv6", "--ip-mask", "255.0.0.0", "--sequence-id", "2"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + + assert result.exit_code == ERROR + + + def test_hash_field_update_wrong_ipv4_mask2(self): + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["add"], + ["inner_dst_ipv4", "--hash-field", "INNER_DST_IPV4", + "--ip-mask", "255.0.0.0", "--sequence-id", "3"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + + assert result.exit_code == SUCCESS + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash-field"].commands["update"], + ["inner_dst_ipv4", "--ip-mask", "ffff::", "--sequence-id", "2"], obj=db) logger.debug(result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR + ########## HASH-FIELD ########## @classmethod From 1648760bb26eb050c79491a39a737c12c6cd9801 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Thu, 17 Jun 2021 11:53:05 +0000 Subject: [PATCH 33/79] Added hash UT, used DB migrator Signed-off-by: Vadym Hlushko --- tests/pbh_input/hash_fields.json | 34 +++++++++++++++++++++++++++++++ tests/pbh_test.py | 35 ++++++++++++++++++++++++++------ 2 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 tests/pbh_input/hash_fields.json diff --git a/tests/pbh_input/hash_fields.json b/tests/pbh_input/hash_fields.json new file mode 100644 index 0000000000..63e46fb86d --- /dev/null +++ b/tests/pbh_input/hash_fields.json @@ -0,0 +1,34 @@ +{ + "PBH_HASH_FIELD|inner_dst_ipv4": { + "hash_field": "INNER_DST_IPV4", + "ip_mask": "255.0.0.0", + "sequence_id": "3" + }, + "PBH_HASH_FIELD|inner_dst_ipv6": { + "hash_field": "INNER_DST_IPV6", + "ip_mask": "ffff::", + "sequence_id": "4" + }, + "PBH_HASH_FIELD|inner_ip_proto": { + "hash_field": "INNER_IP_PROTOCOL", + "sequence_id": "1" + }, + "PBH_HASH_FIELD|inner_l4_dst_port": { + "hash_field": "INNER_L4_DST_PORT", + "sequence_id": "2" + }, + "PBH_HASH_FIELD|inner_l4_src_port": { + "hash_field": "INNER_L4_SRC_PORT", + "sequence_id": "2" + }, + "PBH_HASH_FIELD|inner_src_ipv4": { + "hash_field": "INNER_SRC_IPV4", + "ip_mask": "0.0.0.255", + "sequence_id": "3" + }, + "PBH_HASH_FIELD|inner_src_ipv6": { + "hash_field": "INNER_SRC_IPV6", + "ip_mask": "::ffff", + "sequence_id": "4" + } +} diff --git a/tests/pbh_test.py b/tests/pbh_test.py index 0af6eb8189..3b25ad6276 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -7,9 +7,11 @@ from utilities_common.db import Db from click.testing import CliRunner - +from .mock_tables import dbconnector logger = logging.getLogger(__name__) +test_path = os.path.dirname(os.path.abspath(__file__)) +mock_db_path = os.path.join(test_path, "pbh_input") SUCCESS = 0 ERROR = 1 @@ -21,6 +23,11 @@ def setup_class(cls): logger.info("SETUP") os.environ['UTILITIES_UNIT_TESTING'] = "1" + @classmethod + def teardown_class(cls): + logger.info("TEARDOWN") + os.environ['UTILITIES_UNIT_TESTING'] = "0" + ########## HASH-FIELD ########## def test_hash_field_add_delete_no_ip_mask(self): @@ -338,11 +345,27 @@ def test_hash_field_update_wrong_ipv4_mask2(self): assert result.exit_code == ERROR + ########## HASH ########## - ########## HASH-FIELD ########## + def test_hash_add(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'hash_fields') + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash"].commands["add"], + ["inner_v4_hash", "--hash-field-list", + "inner_ip_proto,inner_l4_dst_port,inner_l4_src_port,inner_dst_ipv4,inner_dst_ipv4"], + obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + + result = runner.invoke(show.cli.commands["pbh"]. + commands["hash"], [], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) - @classmethod - def teardown_class(cls): - logger.info("TEARDOWN") - os.environ['UTILITIES_UNIT_TESTING'] = "0" From b0c603e0f14585b1f233ce3f913d437d2362a2b8 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Fri, 18 Jun 2021 08:25:03 +0000 Subject: [PATCH 34/79] Added UT for 'pbh table', added UT for 'pbh hash' need to add update flow Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 5 +- tests/pbh_input/table.json | 17 +++++ tests/pbh_test.py | 116 ++++++++++++++++++++++++++++++- 3 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 tests/pbh_input/table.json diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index 14dee411b4..3e750f1b8f 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -130,7 +130,7 @@ def is_exist_in_db(db, _list, conf_db_key, option_name): for elem in splited_list: if elem not in correct_list: - exit_with_error("Error: invalid value for '{}', please use {}".format(option_name, correct_list), fg="red") + exit_with_error("Error: invalid value '{}' for '{}', please use {}".format(elem, option_name, correct_list), fg="red") def ip_mask_hash_field_correspondence(ip_mask, hash_field): @@ -633,6 +633,9 @@ def PBH_TABLE(): pass def interfaces_list_validator(db, interface_list): + if interface_list is None: + exit_with_error("Error: invaliad value '{}', for '--interface-list' option".format(interface_list), fg="red") + error = False interfaces = interface_list.split(',') diff --git a/tests/pbh_input/table.json b/tests/pbh_input/table.json new file mode 100644 index 0000000000..ff043da987 --- /dev/null +++ b/tests/pbh_input/table.json @@ -0,0 +1,17 @@ +{ + "PORT|Ethernet0": { + "NULL": "NULL" + }, + "PORT|Ethernet4": { + "NULL": "NULL" + }, + "PORT|Ethernet8": { + "NULL": "NULL" + }, + "PORTCHANNEL|PortChannel0001": { + "NULL": "NULL" + }, + "PORTCHANNEL|PortChannel0002": { + "NULL": "NULL" + } +} diff --git a/tests/pbh_test.py b/tests/pbh_test.py index 3b25ad6276..91dd8b18f0 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -347,7 +347,7 @@ def test_hash_field_update_wrong_ipv4_mask2(self): ########## HASH ########## - def test_hash_add(self): + def test_hash_add_delete_ipv4(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'hash_fields') db = Db() runner = CliRunner() @@ -362,10 +362,120 @@ def test_hash_add(self): logger.debug(result.exit_code) assert result.exit_code == SUCCESS - result = runner.invoke(show.cli.commands["pbh"]. - commands["hash"], [], obj=db) + result = runner.invoke(config.config.commands["pbh"]. + commands["hash"].commands["delete"], + ["inner_v4_hash"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + + + def test_hash_add_ipv6(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'hash_fields') + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash"].commands["add"], + ["inner_v6_hash", "--hash-field-list", + "inner_ip_proto,inner_l4_dst_port,inner_l4_src_port,inner_dst_ipv4,inner_dst_ipv4"], + obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + + + #check to NONE + def test_hash_add_invalid_hash_field_list(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'hash_fields') + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash"].commands["add"], + ["inner_v6_hash", "--hash-field-list", + "INVALID"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == ERROR + + + ########## TABLE ########## + + def test_table_add_delete_ports(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["table"].commands["add"], + ["pbh_table1", "--interface-list", "Ethernet0,Ethernet4", + "--description", "NVGRE"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + + result = runner.invoke(config.config.commands["pbh"]. + commands["table"].commands["delete"], ["pbh_table1"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + + def test_table_add_update_portchannels(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["table"].commands["add"], + ["pbh_table2", "--interface-list", "PortChannel0001", + "--description", "VxLAN"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + + result = runner.invoke(config.config.commands["pbh"]. + commands["table"].commands["update"], + ["pbh_table2", "--interface-list", "PortChannel0002", + "--description", "VxLAN TEST"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + + result = runner.invoke(config.config.commands["pbh"]. + commands["table"].commands["update"], + ["pbh_table2", "--interface-list", "PortChannel0001"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + + result = runner.invoke(config.config.commands["pbh"]. + commands["table"].commands["update"], + ["pbh_table2", "--description", "TEST"], obj=db) logger.debug(result.output) logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + + + def test_table_add_port_and_portchannel(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') + db = Db() + runner = CliRunner() + result = runner.invoke(config.config.commands["pbh"]. + commands["table"].commands["add"], + ["pbh_table3", "--interface-list", "PortChannel0002,Ethernet8", + "--description", "VxLAN adn NVGRE"], obj=db) + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS From d5475449a887c89b839ee1dbe095e2aa1dcd272d Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Fri, 18 Jun 2021 08:30:40 +0000 Subject: [PATCH 35/79] Added UT for 'pbh hash update' Signed-off-by: Vadym Hlushko --- tests/pbh_test.py | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/tests/pbh_test.py b/tests/pbh_test.py index 91dd8b18f0..dad77f0897 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -371,7 +371,7 @@ def test_hash_add_delete_ipv4(self): assert result.exit_code == SUCCESS - def test_hash_add_ipv6(self): + def test_hash_add_update_ipv6(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'hash_fields') db = Db() runner = CliRunner() @@ -379,7 +379,17 @@ def test_hash_add_ipv6(self): result = runner.invoke(config.config.commands["pbh"]. commands["hash"].commands["add"], ["inner_v6_hash", "--hash-field-list", - "inner_ip_proto,inner_l4_dst_port,inner_l4_src_port,inner_dst_ipv4,inner_dst_ipv4"], + "inner_ip_proto,inner_l4_dst_port,inner_l4_src_port,inner_dst_ipv6,inner_dst_ipv6"], + obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash"].commands["update"], + ["inner_v6_hash", "--hash-field-list", + "inner_l4_dst_port,inner_l4_src_port,inner_dst_ipv6,inner_dst_ipv6"], obj=db) logger.debug(result.output) @@ -387,7 +397,6 @@ def test_hash_add_ipv6(self): assert result.exit_code == SUCCESS - #check to NONE def test_hash_add_invalid_hash_field_list(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'hash_fields') db = Db() @@ -402,6 +411,20 @@ def test_hash_add_invalid_hash_field_list(self): logger.debug(result.exit_code) assert result.exit_code == ERROR + def test_hash_add_empty_hash_field_list(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'hash_fields') + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["hash"].commands["add"], + ["inner_v6_hash", "--hash-field-list", + ""], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == ERROR + ########## TABLE ########## From b2e8c3fb8f24f1972181b494b3b02eaa1569a308 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Fri, 18 Jun 2021 09:46:44 +0000 Subject: [PATCH 36/79] Added UT for 'pbh rule' Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 6 +- tests/pbh_input/rule.json | 65 +++++++++++ tests/pbh_test.py | 186 ++++++++++++++++++++++++++++++- 3 files changed, 251 insertions(+), 6 deletions(-) create mode 100644 tests/pbh_input/rule.json diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index 3e750f1b8f..d6b2cac2d4 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -92,7 +92,7 @@ def ip_address_validator(ctx, param, value): try: ip = ipaddress.ip_address(value) except Exception as e: - exit_with_error("Error: invalid value for '{}'\n{}".format(param.name, e), fg="red") + exit_with_error("Error: invalid value for '{}' option\n{}".format(param.name, e), fg="red") return str(ip) @@ -102,7 +102,7 @@ def pbh_match(ctx, param, value): if value is not None: if re.match(pbh_pattern, str(value)) is None: - exit_with_error("Error: invalid value for '{}'".format(param.name), fg="red") + exit_with_error("Error: invalid value for '{}' option".format(param.name), fg="red") return value @@ -130,7 +130,7 @@ def is_exist_in_db(db, _list, conf_db_key, option_name): for elem in splited_list: if elem not in correct_list: - exit_with_error("Error: invalid value '{}' for '{}', please use {}".format(elem, option_name, correct_list), fg="red") + exit_with_error("Error: invalid value '{}' for '{}' option, please use {}".format(elem, option_name, correct_list), fg="red") def ip_mask_hash_field_correspondence(ip_mask, hash_field): diff --git a/tests/pbh_input/rule.json b/tests/pbh_input/rule.json new file mode 100644 index 0000000000..986ed33cb0 --- /dev/null +++ b/tests/pbh_input/rule.json @@ -0,0 +1,65 @@ +{ + "PORT|Ethernet0": { + "NULL": "NULL" + }, + "PORT|Ethernet4": { + "NULL": "NULL" + }, + "PBH_HASH_FIELD|inner_dst_ipv4": { + "hash_field": "INNER_DST_IPV4", + "ip_mask": "255.0.0.0", + "sequence_id": "3" + }, + "PBH_HASH_FIELD|inner_dst_ipv6": { + "hash_field": "INNER_DST_IPV6", + "ip_mask": "ffff::", + "sequence_id": "4" + }, + "PBH_HASH_FIELD|inner_ip_proto": { + "hash_field": "INNER_IP_PROTOCOL", + "sequence_id": "1" + }, + "PBH_HASH_FIELD|inner_l4_dst_port": { + "hash_field": "INNER_L4_DST_PORT", + "sequence_id": "2" + }, + "PBH_HASH_FIELD|inner_l4_src_port": { + "hash_field": "INNER_L4_SRC_PORT", + "sequence_id": "2" + }, + "PBH_HASH_FIELD|inner_src_ipv4": { + "hash_field": "INNER_SRC_IPV4", + "ip_mask": "0.0.0.255", + "sequence_id": "3" + }, + "PBH_HASH_FIELD|inner_src_ipv6": { + "hash_field": "INNER_SRC_IPV6", + "ip_mask": "::ffff", + "sequence_id": "4" + }, + "PBH_HASH|inner_v4_hash": { + "hash_field_list": [ + "inner_ip_proto", + "inner_l4_dst_port", + "inner_l4_src_port", + "inner_dst_ipv4", + "inner_src_ipv4" + ] + }, + "PBH_HASH|inner_v6_hash": { + "hash_field_list": [ + "inner_ip_proto", + "inner_l4_dst_port", + "inner_l4_src_port", + "inner_dst_ipv6", + "inner_src_ipv6" + ] + }, + "PBH_TABLE|pbh_table1": { + "description": "NVGRE", + "interface_list": [ + "Ethernet0", + "Ethernet4" + ] + } +} diff --git a/tests/pbh_test.py b/tests/pbh_test.py index dad77f0897..dedc2375d3 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -15,6 +15,7 @@ SUCCESS = 0 ERROR = 1 +ERROR2 = 2 class TestPBH: @@ -28,7 +29,7 @@ def teardown_class(cls): logger.info("TEARDOWN") os.environ['UTILITIES_UNIT_TESTING'] = "0" - ########## HASH-FIELD ########## + ########## PBH HASH-FIELD ########## def test_hash_field_add_delete_no_ip_mask(self): db = Db() @@ -345,7 +346,7 @@ def test_hash_field_update_wrong_ipv4_mask2(self): assert result.exit_code == ERROR - ########## HASH ########## + ########## PBH HASH ########## def test_hash_add_delete_ipv4(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'hash_fields') @@ -426,7 +427,7 @@ def test_hash_add_empty_hash_field_list(self): assert result.exit_code == ERROR - ########## TABLE ########## + ########## PBH TABLE ########## def test_table_add_delete_ports(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') @@ -502,3 +503,182 @@ def test_table_add_port_and_portchannel(self): logger.debug(result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS + + + def test_table_add_invalid_port(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["table"].commands["add"], + ["pbh_table3", "--interface-list", "INVALID", + "--description", "VxLAN adn NVGRE"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == ERROR + + + ########## PBH RULE ########## + + + def test_rule_add_delete_nvgre(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["rule"].commands["add"], + ["pbh_table1", "nvgre", "--priority", "1", "--gre-key", + "0x2500/0xffffff00", "--inner-ether-type", "0x86dd/0xffff", + "--hash", "inner_v6_hash", "--packet-action", "SET_ECMP_HASH", + "--flow-counter", "DISABLED"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + + result = runner.invoke(config.config.commands["pbh"]. + commands["rule"].commands["delete"], ["pbh_table1", "nvgre"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + + + def test_rule_add_update_vxlan(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["rule"].commands["add"], + ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", + "0x11/0xff", "--inner-ether-type", "0x0800/0xfff", + "--l4-dst-port", "0x12b5/0xffff", "--hash", "inner_v6_hash", + "--packet-action", "SET_ECMP_HASH", "--flow-counter", "ENABLED"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + + result = runner.invoke(config.config.commands["pbh"]. + commands["rule"].commands["update"], + ["pbh_table1", "vxlan ", "--priority", "3", "--inner-ether-type", "0x086dd/0xfff", + "--packet-action", "SET_LAG_HASH", "--flow-counter", "DISABLED"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + + + def test_rule_update_invalid(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["rule"].commands["add"], + ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", + "0x11/0xff", "--inner-ether-type", "0x0800/0xfff", + "--l4-dst-port", "0x12b5/0xffff", "--hash", "inner_v6_hash", + "--packet-action", "SET_ECMP_HASH", "--flow-counter", "ENABLED"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + + result = runner.invoke(config.config.commands["pbh"]. + commands["rule"].commands["update"], + ["pbh_table1", "vxlan ", "--flow-counter", "INVALID"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == ERROR2 + + + def test_rule_add_invalid_ip_priotiry(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["rule"].commands["add"], + ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", + "INVALID", "--inner-ether-type", "0x0800/0xfff", + "--l4-dst-port", "0x12b5/0xffff", "--hash", "inner_v6_hash", + "--packet-action", "SET_ECMP_HASH", "--flow-counter", "ENABLED"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == ERROR + + + def test_rule_add_invalid_inner_ether_type(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["rule"].commands["add"], + ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", + "0x11/0xff", "--inner-ether-type", "INVALID", + "--l4-dst-port", "0x12b5/0xffff", "--hash", "inner_v6_hash", + "--packet-action", "SET_ECMP_HASH", "--flow-counter", "ENABLED"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == ERROR + + + def test_rule_add_invalid_hash(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["rule"].commands["add"], + ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", + "0x11/0xff", "--inner-ether-type", "0x0800/0xfff", + "--l4-dst-port", "0x12b5/0xffff", "--hash", "INVALID", + "--packet-action", "SET_ECMP_HASH", "--flow-counter", "ENABLED"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == ERROR + + + def test_rule_add_invalid_packet_action(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["rule"].commands["add"], + ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", + "0x11/0xff", "--inner-ether-type", "0x0800/0xfff", + "--l4-dst-port", "0x12b5/0xffff", "--hash", "inner_v6_hash", + "--packet-action", "INVALID", "--flow-counter", "ENABLED"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == ERROR2 + + + def test_rule_add_invalid_flow_counter(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["rule"].commands["add"], + ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", + "0x11/0xff", "--inner-ether-type", "0x0800/0xfff", + "--l4-dst-port", "0x12b5/0xffff", "--hash", "inner_v6_hash", + "--packet-action", "SET_ECMP_HASH", "--flow-counter", "INVALID"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == ERROR2 + From 299f64d2a6186e27c8f719fefff4a905a002c780 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 22 Jun 2021 16:01:15 +0000 Subject: [PATCH 37/79] Fixed name of the colums for show, added update UT for pbh table, fixed interfaces_list_validator() Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 10 +++++--- show/plugins/sonic-pbh_yang.py | 42 ++++++++++++++++---------------- tests/pbh_test.py | 26 +++++++++++++++++++- 3 files changed, 52 insertions(+), 26 deletions(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index d6b2cac2d4..6ce0e5f26a 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -632,9 +632,9 @@ def PBH_TABLE(): pass -def interfaces_list_validator(db, interface_list): - if interface_list is None: - exit_with_error("Error: invaliad value '{}', for '--interface-list' option".format(interface_list), fg="red") +def interfaces_list_validator(db, interface_list, is_update: bool): + if is_update and (interface_list is None): + return error = False interfaces = interface_list.split(',') @@ -673,7 +673,7 @@ def interfaces_list_validator(db, interface_list): def PBH_TABLE_add(db, table_name, description, interface_list): """ Add object to PBH_TABLE table """ - interfaces_list_validator(db, interface_list) + interfaces_list_validator(db, interface_list, is_update=False) table = "PBH_TABLE" key = table_name @@ -707,6 +707,8 @@ def PBH_TABLE_add(db, table_name, description, interface_list): def PBH_TABLE_update(db, table_name, description, interface_list): """ Update object in PBH_TABLE table """ + interfaces_list_validator(db, interface_list, is_update=True) + table = "PBH_TABLE" key = table_name data = {} diff --git a/show/plugins/sonic-pbh_yang.py b/show/plugins/sonic-pbh_yang.py index 37fbf697e2..79325ce9a2 100644 --- a/show/plugins/sonic-pbh_yang.py +++ b/show/plugins/sonic-pbh_yang.py @@ -66,11 +66,11 @@ def PBH_HASH_FIELD(db): """ Show the PBH hash field configuration """ header = [ - "Name", - "Field", - "Mask", - "Sequence", - "Symmetric", + "NAME", + "FIELD", + "MASK", + "SEQUENCE", + "SYMMETRIC", ] body = [] @@ -143,8 +143,8 @@ def PBH_HASH(db): """ Show the PBH hash configuration """ header = [ - "Name", - "Hash field", + "NAME", + "HASH FIELD", ] body = [] @@ -181,13 +181,13 @@ def PBH_RULE(db): """ Show the PBH rules configuration """ header = [ - "Table", - "Rule", - "Priority", - "Match", - "Hash", - "Action", - "Counter", + "TABLE", + "RULE", + "PRIORITY", + "MATCH", + "HASH", + "ACTION", + "COUNTER", ] body = [] @@ -295,9 +295,9 @@ def PBH_TABLE(db): """ Show the PBH table configuration """ header = [ - "Name", - "Interface", - "Description", + "NAME", + "INTERFACE", + "DESCRIPTION", ] body = [] @@ -343,10 +343,10 @@ def PBH_STATISTICS(db): """ Show the PBH counters """ header = [ - "Table", - "Rule", - "Packets count", - "Bytes count", + "TABLE", + "RULE", + "PACKETS COUNT", + "BYTES COUNT", ] body = [] diff --git a/tests/pbh_test.py b/tests/pbh_test.py index dedc2375d3..337de95068 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -429,6 +429,7 @@ def test_hash_add_empty_hash_field_list(self): ########## PBH TABLE ########## + def test_table_add_delete_ports(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') db = Db() @@ -450,6 +451,7 @@ def test_table_add_delete_ports(self): logger.debug(result.exit_code) assert result.exit_code == SUCCESS + def test_table_add_update_portchannels(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') db = Db() @@ -520,6 +522,29 @@ def test_table_add_invalid_port(self): assert result.exit_code == ERROR + def test_table_add_update_wrong_interface(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') + db = Db() + runner = CliRunner() + + result = runner.invoke(config.config.commands["pbh"]. + commands["table"].commands["add"], + ["pbh_table2", "--interface-list", "PortChannel0001", + "--description", "VxLAN"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + + result = runner.invoke(config.config.commands["pbh"]. + commands["table"].commands["update"], + ["pbh_table2", "--interface-list", "INVALID"], obj=db) + + logger.debug(result.output) + logger.debug(result.exit_code) + assert result.exit_code == ERROR + + ########## PBH RULE ########## @@ -681,4 +706,3 @@ def test_rule_add_invalid_flow_counter(self): logger.debug(result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR2 - From c3c802db591e2c9f877f9faa495777518ac7d648 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Wed, 23 Jun 2021 12:25:57 +0000 Subject: [PATCH 38/79] Added UT for show, fixed codestyle and errors Signed-off-by: Vadym Hlushko --- tests/pbh_input/assert_show_output.py | 56 +++++++++ tests/pbh_input/full_pbh_config.json | 81 +++++++++++++ tests/pbh_input/hash.json | 40 ++++++ tests/pbh_input/rule.json | 21 +--- tests/pbh_test.py | 167 +++++++++++++++++++------- 5 files changed, 304 insertions(+), 61 deletions(-) create mode 100644 tests/pbh_input/assert_show_output.py create mode 100644 tests/pbh_input/full_pbh_config.json create mode 100644 tests/pbh_input/hash.json diff --git a/tests/pbh_input/assert_show_output.py b/tests/pbh_input/assert_show_output.py new file mode 100644 index 0000000000..943bde967d --- /dev/null +++ b/tests/pbh_input/assert_show_output.py @@ -0,0 +1,56 @@ +""" +Module holding correct show CLI command outputs for the pbh_test.py +""" + +show_pbh_hash_fields="""\ +NAME FIELD MASK SEQUENCE SYMMETRIC +----------------- ----------------- --------- ---------- ----------- +inner_ip_proto INNER_IP_PROTOCOL N/A 1 No +inner_l4_dst_port INNER_L4_DST_PORT N/A 2 Yes +inner_l4_src_port INNER_L4_SRC_PORT N/A 2 Yes +inner_dst_ipv4 INNER_DST_IPV4 255.0.0.0 3 Yes +inner_src_ipv4 INNER_SRC_IPV4 0.0.0.255 3 Yes +inner_dst_ipv6 INNER_DST_IPV6 ffff:: 4 Yes +inner_src_ipv6 INNER_SRC_IPV6 ::ffff 4 Yes +""" + + +show_pbh_hash="""\ +NAME HASH FIELD +------------- ----------------- +inner_v4_hash inner_ip_proto + inner_l4_dst_port + inner_l4_src_port + inner_dst_ipv4 + inner_src_ipv4 +inner_v6_hash inner_ip_proto + inner_l4_dst_port + inner_l4_src_port + inner_dst_ipv6 + inner_src_ipv6 +""" + + +show_pbh_table="""\ +NAME INTERFACE DESCRIPTION +---------- --------------- --------------- +pbh_table1 Ethernet0 NVGRE + Ethernet4 +pbh_table2 PortChannel0001 VxLAN + PortChannel0002 +pbh_table3 Ethernet0 NVGRE and VxLAN + Ethernet4 + PortChannel0001 + PortChannel0002 +""" + + +show_pbh_rule="""\ +TABLE RULE PRIORITY MATCH HASH ACTION COUNTER +---------- ------ ---------- ------------------------------------ ------------- ------------- --------- +pbh_table1 nvgre 1 gre_key: 0x2500/0xffffff00 inner_v6_hash SET_ECMP_HASH DISABLED + inner_ether_type: 0x86dd/0xffff +pbh_table2 vxlan 2 ip_protocol: 0x11/0xff inner_v4_hash SET_LAG_HASH ENABLED + l4_dst_port: 0x12b5/0xffff + inner_ether_type: 0x0800/0xfff +""" \ No newline at end of file diff --git a/tests/pbh_input/full_pbh_config.json b/tests/pbh_input/full_pbh_config.json new file mode 100644 index 0000000000..8a098727ba --- /dev/null +++ b/tests/pbh_input/full_pbh_config.json @@ -0,0 +1,81 @@ +{ + "PBH_HASH_FIELD|inner_dst_ipv4": { + "hash_field": "INNER_DST_IPV4", + "ip_mask": "255.0.0.0", + "sequence_id": "3" + }, + "PBH_HASH_FIELD|inner_dst_ipv6": { + "hash_field": "INNER_DST_IPV6", + "ip_mask": "ffff::", + "sequence_id": "4" + }, + "PBH_HASH_FIELD|inner_ip_proto": { + "hash_field": "INNER_IP_PROTOCOL", + "sequence_id": "1" + }, + "PBH_HASH_FIELD|inner_l4_dst_port": { + "hash_field": "INNER_L4_DST_PORT", + "sequence_id": "2" + }, + "PBH_HASH_FIELD|inner_l4_src_port": { + "hash_field": "INNER_L4_SRC_PORT", + "sequence_id": "2" + }, + "PBH_HASH_FIELD|inner_src_ipv4": { + "hash_field": "INNER_SRC_IPV4", + "ip_mask": "0.0.0.255", + "sequence_id": "3" + }, + "PBH_HASH_FIELD|inner_src_ipv6": { + "hash_field": "INNER_SRC_IPV6", + "ip_mask": "::ffff", + "sequence_id": "4" + }, + "PBH_HASH|inner_v4_hash": { + "hash_field_list@": "inner_ip_proto,inner_l4_dst_port,inner_l4_src_port,inner_dst_ipv4,inner_src_ipv4" + }, + "PBH_HASH|inner_v6_hash": { + "hash_field_list@": "inner_ip_proto,inner_l4_dst_port,inner_l4_src_port,inner_dst_ipv6,inner_src_ipv6" + }, + "PORT|Ethernet0": { + "NULL": "NULL" + }, + "PORT|Ethernet4": { + "NULL": "NULL" + }, + "PORTCHANNEL|PortChannel0001": { + "NULL": "NULL" + }, + "PORTCHANNEL|PortChannel0002": { + "NULL": "NULL" + }, + "PBH_TABLE|pbh_table1": { + "description": "NVGRE", + "interface_list@": "Ethernet0,Ethernet4" + }, + "PBH_TABLE|pbh_table2": { + "description": "VxLAN", + "interface_list@": "PortChannel0001,PortChannel0002" + }, + "PBH_TABLE|pbh_table3": { + "description": "NVGRE and VxLAN", + "interface_list@": "Ethernet0,Ethernet4,PortChannel0001,PortChannel0002" + }, + "PBH_RULE|pbh_table1|nvgre": { + "priority": "1", + "gre_key": "0x2500/0xffffff00", + "inner_ether_type": "0x86dd/0xffff", + "hash": "inner_v6_hash", + "packet_action": "SET_ECMP_HASH", + "flow_counter": "DISABLED" + }, + "PBH_RULE|pbh_table2|vxlan": { + "priority": "2", + "ip_protocol": "0x11/0xff", + "inner_ether_type": "0x0800/0xfff", + "l4_dst_port": "0x12b5/0xffff", + "hash": "inner_v4_hash", + "packet_action": "SET_LAG_HASH", + "flow_counter": "ENABLED" + } +} diff --git a/tests/pbh_input/hash.json b/tests/pbh_input/hash.json new file mode 100644 index 0000000000..d22096dab0 --- /dev/null +++ b/tests/pbh_input/hash.json @@ -0,0 +1,40 @@ +{ + "PBH_HASH_FIELD|inner_dst_ipv4": { + "hash_field": "INNER_DST_IPV4", + "ip_mask": "255.0.0.0", + "sequence_id": "3" + }, + "PBH_HASH_FIELD|inner_dst_ipv6": { + "hash_field": "INNER_DST_IPV6", + "ip_mask": "ffff::", + "sequence_id": "4" + }, + "PBH_HASH_FIELD|inner_ip_proto": { + "hash_field": "INNER_IP_PROTOCOL", + "sequence_id": "1" + }, + "PBH_HASH_FIELD|inner_l4_dst_port": { + "hash_field": "INNER_L4_DST_PORT", + "sequence_id": "2" + }, + "PBH_HASH_FIELD|inner_l4_src_port": { + "hash_field": "INNER_L4_SRC_PORT", + "sequence_id": "2" + }, + "PBH_HASH_FIELD|inner_src_ipv4": { + "hash_field": "INNER_SRC_IPV4", + "ip_mask": "0.0.0.255", + "sequence_id": "3" + }, + "PBH_HASH_FIELD|inner_src_ipv6": { + "hash_field": "INNER_SRC_IPV6", + "ip_mask": "::ffff", + "sequence_id": "4" + }, + "PBH_HASH|inner_v4_hash": { + "hash_field_list@": "inner_ip_proto,inner_l4_dst_port,inner_l4_src_port,inner_dst_ipv4,inner_src_ipv4" + }, + "PBH_HASH|inner_v6_hash": { + "hash_field_list@": "inner_ip_proto,inner_l4_dst_port,inner_l4_src_port,inner_dst_ipv6,inner_src_ipv6" + } +} diff --git a/tests/pbh_input/rule.json b/tests/pbh_input/rule.json index 986ed33cb0..50ecaddd4e 100644 --- a/tests/pbh_input/rule.json +++ b/tests/pbh_input/rule.json @@ -38,28 +38,13 @@ "sequence_id": "4" }, "PBH_HASH|inner_v4_hash": { - "hash_field_list": [ - "inner_ip_proto", - "inner_l4_dst_port", - "inner_l4_src_port", - "inner_dst_ipv4", - "inner_src_ipv4" - ] + "hash_field_list@": "inner_ip_proto,inner_l4_dst_port,inner_l4_src_port,inner_dst_ipv4,inner_src_ipv4" }, "PBH_HASH|inner_v6_hash": { - "hash_field_list": [ - "inner_ip_proto", - "inner_l4_dst_port", - "inner_l4_src_port", - "inner_dst_ipv6", - "inner_src_ipv6" - ] + "hash_field_list@": "inner_ip_proto,inner_l4_dst_port,inner_l4_src_port,inner_dst_ipv6,inner_src_ipv6" }, "PBH_TABLE|pbh_table1": { "description": "NVGRE", - "interface_list": [ - "Ethernet0", - "Ethernet4" - ] + "interface_list@": "Ethernet0,Ethernet4" } } diff --git a/tests/pbh_test.py b/tests/pbh_test.py index 337de95068..77038b8029 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -5,6 +5,7 @@ import show.main as show import config.main as config +from .pbh_input import assert_show_output from utilities_common.db import Db from click.testing import CliRunner from .mock_tables import dbconnector @@ -29,9 +30,11 @@ def teardown_class(cls): logger.info("TEARDOWN") os.environ['UTILITIES_UNIT_TESTING'] = "0" - ########## PBH HASH-FIELD ########## - def test_hash_field_add_delete_no_ip_mask(self): + ########## CONFIG PBH HASH-FIELD ########## + + + def test_config_pbh_hash_field_add_delete_no_ip_mask(self): db = Db() runner = CliRunner() @@ -54,7 +57,8 @@ def test_hash_field_add_delete_no_ip_mask(self): assert result.exit_code == SUCCESS - def test_hash_field_add_ip4_mask(self): + + def test_config_pbh_hash_field_add_ip4_mask(self): db = Db() runner = CliRunner() @@ -69,7 +73,8 @@ def test_hash_field_add_ip4_mask(self): assert result.exit_code == SUCCESS - def test_hash_field_add_ip6_mask(self): + + def test_config_pbh_hash_field_add_ip6_mask(self): db = Db() runner = CliRunner() @@ -84,8 +89,9 @@ def test_hash_field_add_ip6_mask(self): assert result.exit_code == SUCCESS + # negative add: --hash-field & --ip-mask mismatch - def test_hash_field_add_hash_field_with_ip(self): + def test_config_pbh_hash_field_add_hash_field_with_ip(self): db = Db() runner = CliRunner() @@ -100,8 +106,9 @@ def test_hash_field_add_hash_field_with_ip(self): assert result.exit_code == ERROR + # negative add: --hash-field v6 & --ip-mask v4 mismatch - def test_hash_field_add_ipv4_mismatch(self): + def test_config_pbh_hash_field_add_ipv4_mismatch(self): db = Db() runner = CliRunner() @@ -116,8 +123,9 @@ def test_hash_field_add_ipv4_mismatch(self): assert result.exit_code == ERROR + # negative add: --hash-field v4 & --ip-mask v6 mismatch - def test_hash_field_add_ipv6_mismatch(self): + def test_config_pbh_hash_field_add_ipv6_mismatch(self): db = Db() runner = CliRunner() @@ -133,7 +141,7 @@ def test_hash_field_add_ipv6_mismatch(self): assert result.exit_code == ERROR # negative add: invalid --ip-mask - def test_hash_field_add_invalid_ip(self): + def test_config_pbh_hash_field_add_invalid_ip(self): db = Db() runner = CliRunner() @@ -148,8 +156,9 @@ def test_hash_field_add_invalid_ip(self): assert result.exit_code == ERROR + # negative add: None --ip-mask - def test_hash_field_add_none_ipv4(self): + def test_config_pbh_hash_field_add_none_ipv4(self): db = Db() runner = CliRunner() @@ -163,8 +172,9 @@ def test_hash_field_add_none_ipv4(self): assert result.exit_code == ERROR + # negative add: None --ip-mask - def test_hash_field_add_none_ipv6(self): + def test_config_pbh_hash_field_add_none_ipv6(self): db = Db() runner = CliRunner() @@ -178,7 +188,8 @@ def test_hash_field_add_none_ipv6(self): assert result.exit_code == ERROR - def test_hash_field_update_sequence_id(self): + + def test_config_pbh_hash_field_update_sequence_id(self): db = Db() runner = CliRunner() @@ -199,12 +210,8 @@ def test_hash_field_update_sequence_id(self): assert result.exit_code == SUCCESS - result = runner.invoke(show.cli.commands["pbh"].commands["hash-field"], [], obj=db) - - logger.debug(result.output) - logger.debug(result.exit_code) - def test_hash_field_update_hash_field(self): + def test_config_pbh_hash_field_update_hash_field(self): db = Db() runner = CliRunner() @@ -228,7 +235,8 @@ def test_hash_field_update_hash_field(self): assert result.exit_code == SUCCESS - def test_hash_field_update_hash_field_ip_mask(self): + + def test_config_pbh_hash_field_update_hash_field_ip_mask(self): db = Db() runner = CliRunner() @@ -252,7 +260,8 @@ def test_hash_field_update_hash_field_ip_mask(self): assert result.exit_code == SUCCESS - def test_hash_field_update_wrong_hash_field(self): + + def test_config_pbh_hash_field_update_wrong_hash_field(self): db = Db() runner = CliRunner() @@ -276,7 +285,8 @@ def test_hash_field_update_wrong_hash_field(self): assert result.exit_code == ERROR - def test_hash_field_update_wrong_ipv4_mask1(self): + + def test_config_pbh_hash_field_update_wrong_ipv4_mask1(self): db = Db() runner = CliRunner() @@ -299,7 +309,8 @@ def test_hash_field_update_wrong_ipv4_mask1(self): assert result.exit_code == ERROR - def test_hash_field_update_wrong_ipv6_mask(self): + + def test_config_pbh_hash_field_update_wrong_ipv6_mask(self): db = Db() runner = CliRunner() @@ -323,7 +334,7 @@ def test_hash_field_update_wrong_ipv6_mask(self): assert result.exit_code == ERROR - def test_hash_field_update_wrong_ipv4_mask2(self): + def test_config_pbh_hash_field_update_wrong_ipv4_mask2(self): db = Db() runner = CliRunner() @@ -346,9 +357,11 @@ def test_hash_field_update_wrong_ipv4_mask2(self): assert result.exit_code == ERROR - ########## PBH HASH ########## - def test_hash_add_delete_ipv4(self): + ########## CONFIG PBH HASH ########## + + + def test_config_pbh_hash_add_delete_ipv4(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'hash_fields') db = Db() runner = CliRunner() @@ -372,7 +385,7 @@ def test_hash_add_delete_ipv4(self): assert result.exit_code == SUCCESS - def test_hash_add_update_ipv6(self): + def test_config_pbh_hash_add_update_ipv6(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'hash_fields') db = Db() runner = CliRunner() @@ -398,7 +411,7 @@ def test_hash_add_update_ipv6(self): assert result.exit_code == SUCCESS - def test_hash_add_invalid_hash_field_list(self): + def test_config_pbh_hash_add_invalid_hash_field_list(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'hash_fields') db = Db() runner = CliRunner() @@ -412,7 +425,8 @@ def test_hash_add_invalid_hash_field_list(self): logger.debug(result.exit_code) assert result.exit_code == ERROR - def test_hash_add_empty_hash_field_list(self): + + def test_config_pbh_hash_add_empty_hash_field_list(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'hash_fields') db = Db() runner = CliRunner() @@ -427,10 +441,10 @@ def test_hash_add_empty_hash_field_list(self): assert result.exit_code == ERROR - ########## PBH TABLE ########## + ########## CONFIG PBH TABLE ########## - def test_table_add_delete_ports(self): + def test_config_pbh_table_add_delete_ports(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') db = Db() runner = CliRunner() @@ -452,7 +466,7 @@ def test_table_add_delete_ports(self): assert result.exit_code == SUCCESS - def test_table_add_update_portchannels(self): + def test_config_pbh_table_add_update_portchannels(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') db = Db() runner = CliRunner() @@ -492,7 +506,7 @@ def test_table_add_update_portchannels(self): assert result.exit_code == SUCCESS - def test_table_add_port_and_portchannel(self): + def test_config_pbh_table_add_port_and_portchannel(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') db = Db() runner = CliRunner() @@ -507,7 +521,7 @@ def test_table_add_port_and_portchannel(self): assert result.exit_code == SUCCESS - def test_table_add_invalid_port(self): + def test_config_pbh_table_add_invalid_port(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') db = Db() runner = CliRunner() @@ -522,7 +536,7 @@ def test_table_add_invalid_port(self): assert result.exit_code == ERROR - def test_table_add_update_wrong_interface(self): + def test_config_pbh_table_add_update_wrong_interface(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') db = Db() runner = CliRunner() @@ -545,10 +559,10 @@ def test_table_add_update_wrong_interface(self): assert result.exit_code == ERROR - ########## PBH RULE ########## + ########## CONFIG PBH RULE ########## - def test_rule_add_delete_nvgre(self): + def test_config_pbh_rule_add_delete_nvgre(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') db = Db() runner = CliRunner() @@ -572,7 +586,7 @@ def test_rule_add_delete_nvgre(self): assert result.exit_code == SUCCESS - def test_rule_add_update_vxlan(self): + def test_config_pbh_rule_add_update_vxlan(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') db = Db() runner = CliRunner() @@ -581,8 +595,8 @@ def test_rule_add_update_vxlan(self): commands["rule"].commands["add"], ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", "0x11/0xff", "--inner-ether-type", "0x0800/0xfff", - "--l4-dst-port", "0x12b5/0xffff", "--hash", "inner_v6_hash", - "--packet-action", "SET_ECMP_HASH", "--flow-counter", "ENABLED"], obj=db) + "--l4-dst-port", "0x12b5/0xffff", "--hash", "inner_v4_hash", + "--packet-action", "SET_LAG_HASH", "--flow-counter", "ENABLED"], obj=db) logger.debug(result.output) logger.debug(result.exit_code) @@ -598,7 +612,7 @@ def test_rule_add_update_vxlan(self): assert result.exit_code == SUCCESS - def test_rule_update_invalid(self): + def test_config_pbh_rule_update_invalid(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') db = Db() runner = CliRunner() @@ -623,7 +637,7 @@ def test_rule_update_invalid(self): assert result.exit_code == ERROR2 - def test_rule_add_invalid_ip_priotiry(self): + def test_config_pbh_rule_add_invalid_ip_priotiry(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') db = Db() runner = CliRunner() @@ -640,7 +654,7 @@ def test_rule_add_invalid_ip_priotiry(self): assert result.exit_code == ERROR - def test_rule_add_invalid_inner_ether_type(self): + def test_config_pbh_rule_add_invalid_inner_ether_type(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') db = Db() runner = CliRunner() @@ -657,7 +671,7 @@ def test_rule_add_invalid_inner_ether_type(self): assert result.exit_code == ERROR - def test_rule_add_invalid_hash(self): + def test_config_pbh_rule_add_invalid_hash(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') db = Db() runner = CliRunner() @@ -674,7 +688,7 @@ def test_rule_add_invalid_hash(self): assert result.exit_code == ERROR - def test_rule_add_invalid_packet_action(self): + def test_config_pbh_rule_add_invalid_packet_action(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') db = Db() runner = CliRunner() @@ -691,7 +705,7 @@ def test_rule_add_invalid_packet_action(self): assert result.exit_code == ERROR2 - def test_rule_add_invalid_flow_counter(self): + def test_config_pbh_rule_add_invalid_flow_counter(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') db = Db() runner = CliRunner() @@ -706,3 +720,70 @@ def test_rule_add_invalid_flow_counter(self): logger.debug(result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR2 + + ########## SHOW PBH HASH-FIELD ########## + + def test_show_pbh_hash_field(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'full_pbh_config') + db = Db() + runner = CliRunner() + + result = runner.invoke(show.cli.commands["pbh"]. + commands["hash-field"], [], obj=db) + + logger.debug("\n" + result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + assert result.output == assert_show_output.show_pbh_hash_fields + + + ########## SHOW PBH HASH ########## + + + def test_show_pbh_hash(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'full_pbh_config') + db = Db() + runner = CliRunner() + + result = runner.invoke(show.cli.commands["pbh"]. + commands["hash"], [], obj=db) + + logger.debug("\n" + result.stdout) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + assert result.output == assert_show_output.show_pbh_hash + + + ########## SHOW PBH TABLE ########## + + + def test_show_pbh_table(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'full_pbh_config') + db = Db() + runner = CliRunner() + + result = runner.invoke(show.cli.commands["pbh"]. + commands["table"], [], obj=db) + + logger.debug("\n" + result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + assert result.output == assert_show_output.show_pbh_table + + + ########## SHOW PBH RULE ########## + + + def test_show_pbh_rule(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'full_pbh_config') + db = Db() + runner = CliRunner() + + result = runner.invoke(show.cli.commands["pbh"]. + commands["rule"], [], obj=db) + + logger.debug("\n" + result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + assert result.output == assert_show_output.show_pbh_rule + From b8b06f2bc76abbb334d731491a53ff6f88f45e82 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Wed, 23 Jun 2021 12:39:09 +0000 Subject: [PATCH 39/79] Added UT for 'show pbh statistics' Signed-off-by: Vadym Hlushko --- tests/pbh_input/assert_show_output.py | 12 ++++++++++-- tests/pbh_input/counters_db.json | 10 ++++++++++ tests/pbh_test.py | 17 +++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 tests/pbh_input/counters_db.json diff --git a/tests/pbh_input/assert_show_output.py b/tests/pbh_input/assert_show_output.py index 943bde967d..915dd86b34 100644 --- a/tests/pbh_input/assert_show_output.py +++ b/tests/pbh_input/assert_show_output.py @@ -1,5 +1,5 @@ """ -Module holding correct show CLI command outputs for the pbh_test.py +Module holding the correct values for show CLI command outputs for the pbh_test.py """ show_pbh_hash_fields="""\ @@ -53,4 +53,12 @@ pbh_table2 vxlan 2 ip_protocol: 0x11/0xff inner_v4_hash SET_LAG_HASH ENABLED l4_dst_port: 0x12b5/0xffff inner_ether_type: 0x0800/0xfff -""" \ No newline at end of file +""" + + +show_pbh_statistics="""\ +TABLE RULE PACKETS COUNT BYTES COUNT +---------- ------ --------------- ------------- +pbh_table1 nvgre 111 222 +pbh_table2 vxlan 333 444 +""" diff --git a/tests/pbh_input/counters_db.json b/tests/pbh_input/counters_db.json new file mode 100644 index 0000000000..fab6c9a4cc --- /dev/null +++ b/tests/pbh_input/counters_db.json @@ -0,0 +1,10 @@ +{ + "COUNTERS:pbh_table1:nvgre": { + "Packets": "111", + "Bytes": "222" + }, + "COUNTERS:pbh_table2:vxlan": { + "Packets": "333", + "Bytes": "444" + } +} \ No newline at end of file diff --git a/tests/pbh_test.py b/tests/pbh_test.py index 77038b8029..aeffaa8717 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -787,3 +787,20 @@ def test_show_pbh_rule(self): assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_rule + + ########## SHOW PBH STATISTICS ########## + + def test_show_pbh_statistics(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'full_pbh_config') + dbconnector.dedicated_dbs['COUNTERS_DB'] = os.path.join(mock_db_path, 'counters_db') + db = Db() + runner = CliRunner() + + result = runner.invoke(show.cli.commands["pbh"]. + commands["statistics"], [], obj=db) + + logger.debug("\n" + result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + assert result.output == assert_show_output.show_pbh_statistics + From cb04ffaaed67bd0169f1899a2d79e5c8234552e5 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Wed, 23 Jun 2021 13:57:18 +0000 Subject: [PATCH 40/79] Fixed empty lines in 'show pbh statistics' Signed-off-by: Vadym Hlushko --- show/plugins/sonic-pbh_yang.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/show/plugins/sonic-pbh_yang.py b/show/plugins/sonic-pbh_yang.py index 79325ce9a2..27971cd270 100644 --- a/show/plugins/sonic-pbh_yang.py +++ b/show/plugins/sonic-pbh_yang.py @@ -353,13 +353,11 @@ def PBH_STATISTICS(db): db_connector = SonicV2Connector(use_unix_socket_path=False) db_connector.connect(db_connector.COUNTERS_DB) - - pbh_counters = {} + pbh_rules = db.cfgdb.get_table("PBH_RULE") for table, rule in natsort.natsorted(pbh_rules): counter_props = lowercase_keys(db_connector.get_all(db_connector.COUNTERS_DB, "COUNTERS:%s:%s" % (table, rule))) - row = [] if counter_props is not None: row = [ table, @@ -367,8 +365,7 @@ def PBH_STATISTICS(db): counter_props['packets'], counter_props['bytes'] ] - - body.append(row) + body.append(row) click.echo(tabulate.tabulate(body, header)) From fdb0f6e116fa9cf4c69835ad68b36e362a1c562c Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Wed, 23 Jun 2021 14:05:34 +0000 Subject: [PATCH 41/79] Added descending sort by Priority for 'show pbh rule' Signed-off-by: Vadym Hlushko --- show/plugins/sonic-pbh_yang.py | 2 +- tests/pbh_input/assert_show_output.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/show/plugins/sonic-pbh_yang.py b/show/plugins/sonic-pbh_yang.py index 27971cd270..9307752d02 100644 --- a/show/plugins/sonic-pbh_yang.py +++ b/show/plugins/sonic-pbh_yang.py @@ -283,7 +283,7 @@ def PBH_RULE(db): body.append(row) # sorted by 'Priority' - body_sorted = sorted(body, key=lambda e: int(e[2])) + body_sorted = sorted(body, key=lambda e: int(e[2]), reverse=True) click.echo(tabulate.tabulate(body_sorted, header)) diff --git a/tests/pbh_input/assert_show_output.py b/tests/pbh_input/assert_show_output.py index 915dd86b34..e1c30b6fbf 100644 --- a/tests/pbh_input/assert_show_output.py +++ b/tests/pbh_input/assert_show_output.py @@ -48,11 +48,11 @@ show_pbh_rule="""\ TABLE RULE PRIORITY MATCH HASH ACTION COUNTER ---------- ------ ---------- ------------------------------------ ------------- ------------- --------- -pbh_table1 nvgre 1 gre_key: 0x2500/0xffffff00 inner_v6_hash SET_ECMP_HASH DISABLED - inner_ether_type: 0x86dd/0xffff pbh_table2 vxlan 2 ip_protocol: 0x11/0xff inner_v4_hash SET_LAG_HASH ENABLED l4_dst_port: 0x12b5/0xffff inner_ether_type: 0x0800/0xfff +pbh_table1 nvgre 1 gre_key: 0x2500/0xffffff00 inner_v6_hash SET_ECMP_HASH DISABLED + inner_ether_type: 0x86dd/0xffff """ From 9ecfd8f85232a6f30ddde731c6172c4b85a5efbc Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Thu, 24 Jun 2021 09:07:04 +0000 Subject: [PATCH 42/79] Reworked ip_mask_hash_field_correspondence() Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index 6ce0e5f26a..add9a1e65a 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -138,24 +138,25 @@ def ip_mask_hash_field_correspondence(ip_mask, hash_field): # --ip_mask value can be None or VALID IP # --hash_field always valid - if ((ip_mask is None) and - (hash_field == 'INNER_DST_IPV4' or hash_field == 'INNER_SRC_IPV4' or - hash_field == 'INNER_DST_IPV6' or hash_field == 'INNER_SRC_IPV6')): - exit_with_error("Error: the value of --hash-field='{}' is NOT compatible with the value of --ip-mask='{}'".format(hash_field, ip_mask), fg='red') + hf_v4_and_v6 = ['INNER_DST_IPV4', 'INNER_SRC_IPV4', 'INNER_DST_IPV6', 'INNER_SRC_IPV6'] + hf_no_ip = ['INNER_IP_PROTOCOL', 'INNER_L4_DST_PORT', 'INNER_L4_SRC_PORT'] + hf_v4 = ['INNER_DST_IPV4', 'INNER_SRC_IPV4'] + hf_v6 = ['INNER_DST_IPV6', 'INNER_SRC_IPV6'] - if ((ip_mask is not None) and - (hash_field == 'INNER_IP_PROTOCOL' or - hash_field == 'INNER_L4_DST_PORT' or - hash_field == 'INNER_L4_SRC_PORT')): + if (ip_mask is None) and (hash_field in hf_v4_and_v6): exit_with_error("Error: the value of --hash-field='{}' is NOT compatible with the value of --ip-mask='{}'".format(hash_field, ip_mask), fg='red') - if ((hash_field == 'INNER_DST_IPV4' or hash_field == 'INNER_SRC_IPV4') and - (not isinstance(ipaddress.ip_address(ip_mask), IPv4Address))): + if (ip_mask is not None) and (hash_field in hf_no_ip): exit_with_error("Error: the value of --hash-field='{}' is NOT compatible with the value of --ip-mask='{}'".format(hash_field, ip_mask), fg='red') - if ((hash_field == 'INNER_DST_IPV6' or hash_field == 'INNER_SRC_IPV6') and - (not isinstance(ipaddress.ip_address(ip_mask), IPv6Address))): - exit_with_error("Error: the value of --hash-field='{}' is NOT compatible with the value of --ip-mask='{}'".format(hash_field, ip_mask), fg='red') + if ip_mask is not None: + ip_addr_version = ipaddress.ip_address(ip_mask).version + + if (hash_field in hf_v4) and (ip_addr_version != 4): + exit_with_error("Error: the value of --hash-field='{}' is NOT compatible with the value of --ip-mask='{}'".format(hash_field, ip_mask), fg='red') + + if (hash_field in hf_v6) and (ip_addr_version != 6): + exit_with_error("Error: the value of --hash-field='{}' is NOT compatible with the value of --ip-mask='{}'".format(hash_field, ip_mask), fg='red') def update_ip_mask_hash_field(db, hash_field_name, ip_mask, hash_field): From 7dd8a294ac7cae9f1f58ffd2eb2cd4a89da719dd Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Thu, 24 Jun 2021 10:25:26 +0000 Subject: [PATCH 43/79] Reworked pbh_re_match() Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 53 ++++++++++++++++++++------------ tests/pbh_test.py | 2 +- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index add9a1e65a..e2c3059109 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -11,8 +11,6 @@ import re import utilities_common.cli as clicommon import utilities_common.general as general -from ipaddress import IPv4Address, IPv6Address - hash_field_types = ['INNER_IP_PROTOCOL', 'INNER_L4_DST_PORT', @@ -21,12 +19,14 @@ 'INNER_SRC_IPV4', 'INNER_DST_IPV6', 'INNER_SRC_IPV6'] - packet_action_types = ['SET_ECMP_HASH', 'SET_LAG_HASH'] - flow_counter_state = ['DISABLED', 'ENABLED'] -pbh_pattern = r"(0x){1}[a-fA-F0-9]+/(0x){1}[a-fA-F0-9]+" +gre_key_re = r"(0x){1}[a-fA-F0-9]{1,8}/(0x){1}[a-fA-F0-9]{1,8}" +ip_protocol_re = r"(0x){1}[a-fA-F0-9]{1,2}" +ipv6_next_header_re = ip_protocol_re +l4_dst_port_re = r"(0x){1}[a-fA-F0-9]{1,4}" +inner_ether_type_re = l4_dst_port_re def exit_with_error(*args, **kwargs): @@ -97,14 +97,27 @@ def ip_address_validator(ctx, param, value): return str(ip) -def pbh_match(ctx, param, value): +def re_match(value, param_name, regexp): + if re.match(regexp, str(value)) is None: + exit_with_error("Error: invalid value for '{}' option".format(param_name), fg="red") + + return value + + +def pbh_re_match(ctx, param, value): """ Check if PBH rule options is valid """ if value is not None: - if re.match(pbh_pattern, str(value)) is None: - exit_with_error("Error: invalid value for '{}' option".format(param.name), fg="red") - - return value + if param.name == 'gre_key': + return re_match(value, param.name, gre_key_re) + elif param.name == 'ip_protocol': + return re_match(value, param.name, ip_protocol_re) + elif param.name == 'ipv6_next_header': + return re_match(value, param.name, ipv6_next_header_re) + elif param.name == 'l4_dst_port': + return re_match(value, param.name, l4_dst_port_re) + elif param.name == 'inner_ether_type': + return re_match(value, param.name, inner_ether_type_re) def is_exist_in_db(db, _list, conf_db_key, option_name): @@ -419,27 +432,27 @@ def PBH_RULE(): @click.option( "--gre-key", help="Configures packet match: GRE key (value/mask)", - callback=pbh_match, + callback=pbh_re_match, ) @click.option( "--ip-protocol", help="Configures packet match: IP protocol (value/mask)", - callback=pbh_match, + callback=pbh_re_match, ) @click.option( "--ipv6-next-header", help="Configures packet match: IPv6 Next header (value/mask)", - callback=pbh_match, + callback=pbh_re_match, ) @click.option( "--l4-dst-port", help="Configures packet match: L4 destination port (value/mask)", - callback=pbh_match, + callback=pbh_re_match, ) @click.option( "--inner-ether-type", help="Configures packet match: inner EtherType (value/mask)", - callback=pbh_match, + callback=pbh_re_match, ) @click.option( "--hash", @@ -521,27 +534,27 @@ def PBH_RULE_add(db, @click.option( "--gre-key", help="Configures packet match: GRE key (value/mask)", - callback=pbh_match, + callback=pbh_re_match, ) @click.option( "--ip-protocol", help="Configures packet match: IP protocol (value/mask)", - callback=pbh_match, + callback=pbh_re_match, ) @click.option( "--ipv6-next-header", help="Configures packet match: IPv6 Next header (value/mask)", - callback=pbh_match, + callback=pbh_re_match, ) @click.option( "--l4-dst-port", help="Configures packet match: L4 destination port (value/mask)", - callback=pbh_match, + callback=pbh_re_match, ) @click.option( "--inner-ether-type", help="Configures packet match: inner EtherType (value/mask)", - callback=pbh_match, + callback=pbh_re_match, ) @click.option( "--hash", diff --git a/tests/pbh_test.py b/tests/pbh_test.py index aeffaa8717..a818430161 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -637,7 +637,7 @@ def test_config_pbh_rule_update_invalid(self): assert result.exit_code == ERROR2 - def test_config_pbh_rule_add_invalid_ip_priotiry(self): + def test_config_pbh_rule_add_invalid_ip_protocol(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') db = Db() runner = CliRunner() From c8ae867aeceb7e771f0aee8d008d85a02ad92c3d Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Thu, 24 Jun 2021 10:27:17 +0000 Subject: [PATCH 44/79] Corrected row names for 'show pbh statistics' Signed-off-by: Vadym Hlushko --- show/plugins/sonic-pbh_yang.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/show/plugins/sonic-pbh_yang.py b/show/plugins/sonic-pbh_yang.py index 9307752d02..10385dc292 100644 --- a/show/plugins/sonic-pbh_yang.py +++ b/show/plugins/sonic-pbh_yang.py @@ -345,8 +345,8 @@ def PBH_STATISTICS(db): header = [ "TABLE", "RULE", - "PACKETS COUNT", - "BYTES COUNT", + "RX PACKETS COUNT", + "RX BYTES COUNT", ] body = [] From cf1d1fcdfb0dfa8a2011724adc0ae75902e0f397 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Thu, 24 Jun 2021 10:58:36 +0000 Subject: [PATCH 45/79] Fixed codestyle Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 27 ++++-- tests/pbh_input/assert_show_output.py | 8 +- tests/pbh_test.py | 123 +++++++++++--------------- 3 files changed, 73 insertions(+), 85 deletions(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index e2c3059109..3aa562efd7 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -98,6 +98,8 @@ def ip_address_validator(ctx, param, value): def re_match(value, param_name, regexp): + """ Regexp validation of given parameter """ + if re.match(regexp, str(value)) is None: exit_with_error("Error: invalid value for '{}' option".format(param_name), fg="red") @@ -105,7 +107,7 @@ def re_match(value, param_name, regexp): def pbh_re_match(ctx, param, value): - """ Check if PBH rule options is valid """ + """ Check if PBH rule options are valid """ if value is not None: if param.name == 'gre_key': @@ -147,29 +149,38 @@ def is_exist_in_db(db, _list, conf_db_key, option_name): def ip_mask_hash_field_correspondence(ip_mask, hash_field): - # at this point - # --ip_mask value can be None or VALID IP - # --hash_field always valid + """ Check if the --ip-mask option are correspond to + the --hash-field option + Args: + ip_mask: ip address, + hash_field: hash field value, which was configured before + """ + + is_error = False hf_v4_and_v6 = ['INNER_DST_IPV4', 'INNER_SRC_IPV4', 'INNER_DST_IPV6', 'INNER_SRC_IPV6'] hf_no_ip = ['INNER_IP_PROTOCOL', 'INNER_L4_DST_PORT', 'INNER_L4_SRC_PORT'] hf_v4 = ['INNER_DST_IPV4', 'INNER_SRC_IPV4'] hf_v6 = ['INNER_DST_IPV6', 'INNER_SRC_IPV6'] if (ip_mask is None) and (hash_field in hf_v4_and_v6): - exit_with_error("Error: the value of --hash-field='{}' is NOT compatible with the value of --ip-mask='{}'".format(hash_field, ip_mask), fg='red') + is_error = True if (ip_mask is not None) and (hash_field in hf_no_ip): - exit_with_error("Error: the value of --hash-field='{}' is NOT compatible with the value of --ip-mask='{}'".format(hash_field, ip_mask), fg='red') + is_error = True if ip_mask is not None: ip_addr_version = ipaddress.ip_address(ip_mask).version if (hash_field in hf_v4) and (ip_addr_version != 4): - exit_with_error("Error: the value of --hash-field='{}' is NOT compatible with the value of --ip-mask='{}'".format(hash_field, ip_mask), fg='red') + is_error = True if (hash_field in hf_v6) and (ip_addr_version != 6): - exit_with_error("Error: the value of --hash-field='{}' is NOT compatible with the value of --ip-mask='{}'".format(hash_field, ip_mask), fg='red') + is_error = True + + if is_error: + exit_with_error("Error: the value of --hash-field='{}' is NOT compatible with the value of --ip-mask='{}'".format(hash_field, ip_mask), fg='red') + def update_ip_mask_hash_field(db, hash_field_name, ip_mask, hash_field): diff --git a/tests/pbh_input/assert_show_output.py b/tests/pbh_input/assert_show_output.py index e1c30b6fbf..e9da2aadea 100644 --- a/tests/pbh_input/assert_show_output.py +++ b/tests/pbh_input/assert_show_output.py @@ -57,8 +57,8 @@ show_pbh_statistics="""\ -TABLE RULE PACKETS COUNT BYTES COUNT ----------- ------ --------------- ------------- -pbh_table1 nvgre 111 222 -pbh_table2 vxlan 333 444 +TABLE RULE RX PACKETS COUNT RX BYTES COUNT +---------- ------ ------------------ ---------------- +pbh_table1 nvgre 111 222 +pbh_table2 vxlan 333 444 """ diff --git a/tests/pbh_test.py b/tests/pbh_test.py index a818430161..82b4b71a0a 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -43,18 +43,16 @@ def test_config_pbh_hash_field_add_delete_no_ip_mask(self): ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", "--sequence-id", "1"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == SUCCESS result = runner.invoke(config.config.commands["pbh"]. commands["hash-field"].commands["delete"], ["inner_ip_proto"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == SUCCESS @@ -68,7 +66,7 @@ def test_config_pbh_hash_field_add_ip4_mask(self): "--ip-mask", "255.0.0.0", "--sequence-id", "3"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS @@ -84,9 +82,8 @@ def test_config_pbh_hash_field_add_ip6_mask(self): "--ip-mask", "ffff::", "--sequence-id", "4"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == SUCCESS @@ -101,9 +98,8 @@ def test_config_pbh_hash_field_add_hash_field_with_ip(self): "--ip-mask", "255.0.0.0", "--sequence-id", "1"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == ERROR @@ -118,9 +114,8 @@ def test_config_pbh_hash_field_add_ipv4_mismatch(self): "--ip-mask", "255.0.0.0", "--sequence-id", "4"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == ERROR @@ -135,9 +130,8 @@ def test_config_pbh_hash_field_add_ipv6_mismatch(self): "--ip-mask", "ffff::", "--sequence-id", "2"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == ERROR # negative add: invalid --ip-mask @@ -151,9 +145,8 @@ def test_config_pbh_hash_field_add_invalid_ip(self): "--ip-mask", "WRONG", "--sequence-id", "2"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == ERROR @@ -167,9 +160,8 @@ def test_config_pbh_hash_field_add_none_ipv4(self): ["inner_src_ipv4", "--hash-field", "INNER_SRC_IPV4", "--sequence-id", "2"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == ERROR @@ -183,9 +175,8 @@ def test_config_pbh_hash_field_add_none_ipv6(self): ["inner_src_ipv6", "--hash-field", "INNER_SRC_IPV6", "--sequence-id", "2"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == ERROR @@ -198,16 +189,14 @@ def test_config_pbh_hash_field_update_sequence_id(self): ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", "--sequence-id", "1"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == SUCCESS result = runner.invoke(config.config.commands["pbh"]. commands["hash-field"].commands["update"], ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", "--sequence-id", "2"], obj=db) - assert result.exit_code == SUCCESS @@ -220,9 +209,8 @@ def test_config_pbh_hash_field_update_hash_field(self): ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", "--sequence-id", "1"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == SUCCESS result = runner.invoke(config.config.commands["pbh"]. @@ -230,9 +218,8 @@ def test_config_pbh_hash_field_update_hash_field(self): ["inner_ip_proto", "--hash-field", "INNER_L4_DST_PORT", "--sequence-id", "2"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == SUCCESS @@ -245,9 +232,8 @@ def test_config_pbh_hash_field_update_hash_field_ip_mask(self): ["inner_dst_ipv4", "--hash-field", "INNER_DST_IPV4", "--ip-mask", "255.0.0.0", "--sequence-id", "1"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == SUCCESS result = runner.invoke(config.config.commands["pbh"]. @@ -255,9 +241,8 @@ def test_config_pbh_hash_field_update_hash_field_ip_mask(self): ["inner_dst_ipv4", "--hash-field", "INNER_SRC_IPV4", "--ip-mask", "0.0.0.255", "--sequence-id", "2"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == SUCCESS @@ -270,9 +255,8 @@ def test_config_pbh_hash_field_update_wrong_hash_field(self): ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", "--sequence-id", "1"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == SUCCESS result = runner.invoke(config.config.commands["pbh"]. @@ -280,9 +264,8 @@ def test_config_pbh_hash_field_update_wrong_hash_field(self): ["inner_ip_proto", "--hash-field", "INNER_DST_IPV4", "--sequence-id", "2"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == ERROR @@ -295,18 +278,16 @@ def test_config_pbh_hash_field_update_wrong_ipv4_mask1(self): ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", "--sequence-id", "1"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == SUCCESS result = runner.invoke(config.config.commands["pbh"]. commands["hash-field"].commands["update"], ["inner_ip_proto", "--ip-mask", "0.0.0.255"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == ERROR @@ -319,18 +300,16 @@ def test_config_pbh_hash_field_update_wrong_ipv6_mask(self): ["inner_dst_ipv6", "--hash-field", "INNER_DST_IPV6", "--ip-mask", "ffff::", "--sequence-id", "3"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == SUCCESS result = runner.invoke(config.config.commands["pbh"]. commands["hash-field"].commands["update"], ["inner_dst_ipv6", "--ip-mask", "255.0.0.0", "--sequence-id", "2"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == ERROR @@ -343,18 +322,16 @@ def test_config_pbh_hash_field_update_wrong_ipv4_mask2(self): ["inner_dst_ipv4", "--hash-field", "INNER_DST_IPV4", "--ip-mask", "255.0.0.0", "--sequence-id", "3"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == SUCCESS result = runner.invoke(config.config.commands["pbh"]. commands["hash-field"].commands["update"], ["inner_dst_ipv4", "--ip-mask", "ffff::", "--sequence-id", "2"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == ERROR @@ -372,7 +349,7 @@ def test_config_pbh_hash_add_delete_ipv4(self): "inner_ip_proto,inner_l4_dst_port,inner_l4_src_port,inner_dst_ipv4,inner_dst_ipv4"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS @@ -380,7 +357,7 @@ def test_config_pbh_hash_add_delete_ipv4(self): commands["hash"].commands["delete"], ["inner_v4_hash"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS @@ -396,7 +373,7 @@ def test_config_pbh_hash_add_update_ipv6(self): "inner_ip_proto,inner_l4_dst_port,inner_l4_src_port,inner_dst_ipv6,inner_dst_ipv6"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS @@ -406,7 +383,7 @@ def test_config_pbh_hash_add_update_ipv6(self): "inner_l4_dst_port,inner_l4_src_port,inner_dst_ipv6,inner_dst_ipv6"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS @@ -421,7 +398,7 @@ def test_config_pbh_hash_add_invalid_hash_field_list(self): ["inner_v6_hash", "--hash-field-list", "INVALID"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR @@ -436,7 +413,7 @@ def test_config_pbh_hash_add_empty_hash_field_list(self): ["inner_v6_hash", "--hash-field-list", ""], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR @@ -454,14 +431,14 @@ def test_config_pbh_table_add_delete_ports(self): ["pbh_table1", "--interface-list", "Ethernet0,Ethernet4", "--description", "NVGRE"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS result = runner.invoke(config.config.commands["pbh"]. commands["table"].commands["delete"], ["pbh_table1"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS @@ -476,7 +453,7 @@ def test_config_pbh_table_add_update_portchannels(self): ["pbh_table2", "--interface-list", "PortChannel0001", "--description", "VxLAN"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS @@ -485,7 +462,7 @@ def test_config_pbh_table_add_update_portchannels(self): ["pbh_table2", "--interface-list", "PortChannel0002", "--description", "VxLAN TEST"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS @@ -493,7 +470,7 @@ def test_config_pbh_table_add_update_portchannels(self): commands["table"].commands["update"], ["pbh_table2", "--interface-list", "PortChannel0001"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS @@ -501,7 +478,7 @@ def test_config_pbh_table_add_update_portchannels(self): commands["table"].commands["update"], ["pbh_table2", "--description", "TEST"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS @@ -516,7 +493,7 @@ def test_config_pbh_table_add_port_and_portchannel(self): ["pbh_table3", "--interface-list", "PortChannel0002,Ethernet8", "--description", "VxLAN adn NVGRE"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS @@ -531,7 +508,7 @@ def test_config_pbh_table_add_invalid_port(self): ["pbh_table3", "--interface-list", "INVALID", "--description", "VxLAN adn NVGRE"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR @@ -546,7 +523,7 @@ def test_config_pbh_table_add_update_wrong_interface(self): ["pbh_table2", "--interface-list", "PortChannel0001", "--description", "VxLAN"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS @@ -554,7 +531,7 @@ def test_config_pbh_table_add_update_wrong_interface(self): commands["table"].commands["update"], ["pbh_table2", "--interface-list", "INVALID"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR @@ -574,14 +551,14 @@ def test_config_pbh_rule_add_delete_nvgre(self): "--hash", "inner_v6_hash", "--packet-action", "SET_ECMP_HASH", "--flow-counter", "DISABLED"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS result = runner.invoke(config.config.commands["pbh"]. commands["rule"].commands["delete"], ["pbh_table1", "nvgre"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS @@ -598,7 +575,7 @@ def test_config_pbh_rule_add_update_vxlan(self): "--l4-dst-port", "0x12b5/0xffff", "--hash", "inner_v4_hash", "--packet-action", "SET_LAG_HASH", "--flow-counter", "ENABLED"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS @@ -607,7 +584,7 @@ def test_config_pbh_rule_add_update_vxlan(self): ["pbh_table1", "vxlan ", "--priority", "3", "--inner-ether-type", "0x086dd/0xfff", "--packet-action", "SET_LAG_HASH", "--flow-counter", "DISABLED"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS @@ -624,7 +601,7 @@ def test_config_pbh_rule_update_invalid(self): "--l4-dst-port", "0x12b5/0xffff", "--hash", "inner_v6_hash", "--packet-action", "SET_ECMP_HASH", "--flow-counter", "ENABLED"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS @@ -632,7 +609,7 @@ def test_config_pbh_rule_update_invalid(self): commands["rule"].commands["update"], ["pbh_table1", "vxlan ", "--flow-counter", "INVALID"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR2 @@ -649,7 +626,7 @@ def test_config_pbh_rule_add_invalid_ip_protocol(self): "--l4-dst-port", "0x12b5/0xffff", "--hash", "inner_v6_hash", "--packet-action", "SET_ECMP_HASH", "--flow-counter", "ENABLED"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR @@ -666,7 +643,7 @@ def test_config_pbh_rule_add_invalid_inner_ether_type(self): "--l4-dst-port", "0x12b5/0xffff", "--hash", "inner_v6_hash", "--packet-action", "SET_ECMP_HASH", "--flow-counter", "ENABLED"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR @@ -683,7 +660,7 @@ def test_config_pbh_rule_add_invalid_hash(self): "--l4-dst-port", "0x12b5/0xffff", "--hash", "INVALID", "--packet-action", "SET_ECMP_HASH", "--flow-counter", "ENABLED"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR @@ -700,7 +677,7 @@ def test_config_pbh_rule_add_invalid_packet_action(self): "--l4-dst-port", "0x12b5/0xffff", "--hash", "inner_v6_hash", "--packet-action", "INVALID", "--flow-counter", "ENABLED"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR2 @@ -717,7 +694,7 @@ def test_config_pbh_rule_add_invalid_flow_counter(self): "--l4-dst-port", "0x12b5/0xffff", "--hash", "inner_v6_hash", "--packet-action", "SET_ECMP_HASH", "--flow-counter", "INVALID"], obj=db) - logger.debug(result.output) + logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR2 From a1488c0092ce4a37e128cc8d599582f04677c823 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Thu, 24 Jun 2021 11:02:57 +0000 Subject: [PATCH 46/79] Added function description Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 33 +++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index 3aa562efd7..dff7fd5f9c 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -86,7 +86,16 @@ def del_entry(db, table, key): def ip_address_validator(ctx, param, value): - """ Check if the given ip address is valid """ + """ Check if the given ip address is valid + + Args: + ctx: click context, + param: click parameter context, + value: value of parameter + + Returns: + str: ip address + """ if value is not None: try: @@ -98,7 +107,16 @@ def ip_address_validator(ctx, param, value): def re_match(value, param_name, regexp): - """ Regexp validation of given parameter """ + """ Regexp validation of given parameter + + Args: + value: value to validate, + param_name: parameter name, + regexp: regular expression + + Return: + str: validated value + """ if re.match(regexp, str(value)) is None: exit_with_error("Error: invalid value for '{}' option".format(param_name), fg="red") @@ -107,7 +125,16 @@ def re_match(value, param_name, regexp): def pbh_re_match(ctx, param, value): - """ Check if PBH rule options are valid """ + """ Check if PBH rule options are valid + + Args: + ctx: click context, + param: click parameter context, + value: value of parameter + + Returns: + str: validated parameter + """ if value is not None: if param.name == 'gre_key': From cfd04d0822a7ce9635eedc43e6d579d2654ec393 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Thu, 24 Jun 2021 11:06:22 +0000 Subject: [PATCH 47/79] Added function description Signed-off-by: Vadym Hlushko --- config/plugins/sonic-pbh_yang.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/sonic-pbh_yang.py index dff7fd5f9c..748eaa9246 100644 --- a/config/plugins/sonic-pbh_yang.py +++ b/config/plugins/sonic-pbh_yang.py @@ -210,6 +210,15 @@ def ip_mask_hash_field_correspondence(ip_mask, hash_field): def update_ip_mask_hash_field(db, hash_field_name, ip_mask, hash_field): + """ Function to validate --ip-mask and --hash-field + correspondence, during update flow + + Args: + db: reference to CONFIG DB, + hash_field_name: name of the hash-field, + ip_mask: ip address, + hash_field: native hash field value + """ if (ip_mask is None) and (hash_field is None): return From eeb6052ea5a61c75c8d854594c5a458c3680c096 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Thu, 24 Jun 2021 13:28:59 +0000 Subject: [PATCH 48/79] Changed name of CLI plugins Signed-off-by: Vadym Hlushko --- config/plugins/{sonic-pbh_yang.py => pbh.py} | 0 show/plugins/{sonic-pbh_yang.py => pbh.py} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename config/plugins/{sonic-pbh_yang.py => pbh.py} (100%) rename show/plugins/{sonic-pbh_yang.py => pbh.py} (100%) diff --git a/config/plugins/sonic-pbh_yang.py b/config/plugins/pbh.py similarity index 100% rename from config/plugins/sonic-pbh_yang.py rename to config/plugins/pbh.py diff --git a/show/plugins/sonic-pbh_yang.py b/show/plugins/pbh.py similarity index 100% rename from show/plugins/sonic-pbh_yang.py rename to show/plugins/pbh.py From 7a69c880683388d039724cc88f392a8aab15833c Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Fri, 25 Jun 2021 11:39:27 +0000 Subject: [PATCH 49/79] Added left alignment for numbers in show CLI group Signed-off-by: Vadym Hlushko --- show/plugins/pbh.py | 12 ++++++------ tests/pbh_input/assert_show_output.py | 28 +++++++++++++-------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/show/plugins/pbh.py b/show/plugins/pbh.py index 10385dc292..094ae2e96c 100644 --- a/show/plugins/pbh.py +++ b/show/plugins/pbh.py @@ -47,7 +47,7 @@ def format_group_value(entry, attrs): if entry.get(attr["name"]): data.append((attr["name"] + ":", format_attr_value(entry, attr))) - return tabulate.tabulate(data, tablefmt="plain") + return tabulate.tabulate(data, tablefmt="plain", numalign="left") @click.group(name='pbh', @@ -132,7 +132,7 @@ def PBH_HASH_FIELD(db): # sorted by 'sequence_id' body_sorted = sorted(body, key=lambda e: int(e[3])) - click.echo(tabulate.tabulate(body_sorted, header)) + click.echo(tabulate.tabulate(body_sorted, header, numalign="left")) @PBH.group(name="hash", @@ -170,7 +170,7 @@ def PBH_HASH(db): body.append(row) - click.echo(tabulate.tabulate(body, header)) + click.echo(tabulate.tabulate(body, header, numalign="left")) @PBH.group(name="rule", @@ -284,7 +284,7 @@ def PBH_RULE(db): # sorted by 'Priority' body_sorted = sorted(body, key=lambda e: int(e[2]), reverse=True) - click.echo(tabulate.tabulate(body_sorted, header)) + click.echo(tabulate.tabulate(body_sorted, header, numalign="left")) @PBH.group(name="table", @@ -333,7 +333,7 @@ def PBH_TABLE(db): body.append(row) - click.echo(tabulate.tabulate(body, header)) + click.echo(tabulate.tabulate(body, header, numalign="left")) @PBH.group(name="statistics", cls=clicommon.AliasedGroup, @@ -367,7 +367,7 @@ def PBH_STATISTICS(db): ] body.append(row) - click.echo(tabulate.tabulate(body, header)) + click.echo(tabulate.tabulate(body, header, numalign="left")) def register(cli): diff --git a/tests/pbh_input/assert_show_output.py b/tests/pbh_input/assert_show_output.py index e9da2aadea..715eff11e9 100644 --- a/tests/pbh_input/assert_show_output.py +++ b/tests/pbh_input/assert_show_output.py @@ -3,15 +3,15 @@ """ show_pbh_hash_fields="""\ -NAME FIELD MASK SEQUENCE SYMMETRIC +NAME FIELD MASK SEQUENCE SYMMETRIC ----------------- ----------------- --------- ---------- ----------- -inner_ip_proto INNER_IP_PROTOCOL N/A 1 No -inner_l4_dst_port INNER_L4_DST_PORT N/A 2 Yes -inner_l4_src_port INNER_L4_SRC_PORT N/A 2 Yes -inner_dst_ipv4 INNER_DST_IPV4 255.0.0.0 3 Yes -inner_src_ipv4 INNER_SRC_IPV4 0.0.0.255 3 Yes -inner_dst_ipv6 INNER_DST_IPV6 ffff:: 4 Yes -inner_src_ipv6 INNER_SRC_IPV6 ::ffff 4 Yes +inner_ip_proto INNER_IP_PROTOCOL N/A 1 No +inner_l4_dst_port INNER_L4_DST_PORT N/A 2 Yes +inner_l4_src_port INNER_L4_SRC_PORT N/A 2 Yes +inner_dst_ipv4 INNER_DST_IPV4 255.0.0.0 3 Yes +inner_src_ipv4 INNER_SRC_IPV4 0.0.0.255 3 Yes +inner_dst_ipv6 INNER_DST_IPV6 ffff:: 4 Yes +inner_src_ipv6 INNER_SRC_IPV6 ::ffff 4 Yes """ @@ -46,19 +46,19 @@ show_pbh_rule="""\ -TABLE RULE PRIORITY MATCH HASH ACTION COUNTER +TABLE RULE PRIORITY MATCH HASH ACTION COUNTER ---------- ------ ---------- ------------------------------------ ------------- ------------- --------- -pbh_table2 vxlan 2 ip_protocol: 0x11/0xff inner_v4_hash SET_LAG_HASH ENABLED +pbh_table2 vxlan 2 ip_protocol: 0x11/0xff inner_v4_hash SET_LAG_HASH ENABLED l4_dst_port: 0x12b5/0xffff inner_ether_type: 0x0800/0xfff -pbh_table1 nvgre 1 gre_key: 0x2500/0xffffff00 inner_v6_hash SET_ECMP_HASH DISABLED +pbh_table1 nvgre 1 gre_key: 0x2500/0xffffff00 inner_v6_hash SET_ECMP_HASH DISABLED inner_ether_type: 0x86dd/0xffff """ show_pbh_statistics="""\ -TABLE RULE RX PACKETS COUNT RX BYTES COUNT +TABLE RULE RX PACKETS COUNT RX BYTES COUNT ---------- ------ ------------------ ---------------- -pbh_table1 nvgre 111 222 -pbh_table2 vxlan 333 444 +pbh_table1 nvgre 111 222 +pbh_table2 vxlan 333 444 """ From f448353bd0960debb98ef4b13b070fee5a9a93d8 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 29 Jun 2021 09:25:59 +0000 Subject: [PATCH 50/79] Fixed LGTM errors Signed-off-by: Vadym Hlushko --- config/plugins/pbh.py | 3 +-- show/plugins/pbh.py | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/config/plugins/pbh.py b/config/plugins/pbh.py index 748eaa9246..cefba3a395 100644 --- a/config/plugins/pbh.py +++ b/config/plugins/pbh.py @@ -10,7 +10,6 @@ import ipaddress import re import utilities_common.cli as clicommon -import utilities_common.general as general hash_field_types = ['INNER_IP_PROTOCOL', 'INNER_L4_DST_PORT', @@ -242,7 +241,7 @@ def update_ip_mask_hash_field(db, hash_field_name, ip_mask, hash_field): except Exception as e: hash_field = None - ip_mask_hash_field_correspondence(ip_mask, hash_field_obj['hash_field']) + ip_mask_hash_field_correspondence(ip_mask, hash_field) @click.group(name='pbh', diff --git a/show/plugins/pbh.py b/show/plugins/pbh.py index 094ae2e96c..44357a0fb1 100644 --- a/show/plugins/pbh.py +++ b/show/plugins/pbh.py @@ -10,8 +10,7 @@ import tabulate import natsort import utilities_common.cli as clicommon -from operator import itemgetter -from swsscommon.swsscommon import SonicV2Connector, ConfigDBConnector +from swsscommon.swsscommon import SonicV2Connector def format_attr_value(entry, attr): From 071c01c8d4f39574c28e8960ba154f445026b9b0 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 29 Jun 2021 14:52:51 +0000 Subject: [PATCH 51/79] New version for 'show pbh statistics', UT passed Signed-off-by: Vadym Hlushko --- show/plugins/pbh.py | 68 ++++++++++++++++++++++++++++++++++++++------- tests/pbh_test.py | 15 ++++++++++ 2 files changed, 73 insertions(+), 10 deletions(-) diff --git a/show/plugins/pbh.py b/show/plugins/pbh.py index 44357a0fb1..c0c3df12f6 100644 --- a/show/plugins/pbh.py +++ b/show/plugins/pbh.py @@ -6,12 +6,16 @@ CLI Auto-generation tool HLD - https://github.com/Azure/SONiC/pull/78 """ +import os import click import tabulate import natsort +import json import utilities_common.cli as clicommon from swsscommon.swsscommon import SonicV2Connector +PBH_COUNTERS_LOCATION = '/tmp/.pbh_counters.txt' + def format_attr_value(entry, attr): """ Helper that formats attribute to be presented in the table output. @@ -350,25 +354,69 @@ def PBH_STATISTICS(db): body = [] - db_connector = SonicV2Connector(use_unix_socket_path=False) - db_connector.connect(db_connector.COUNTERS_DB) - pbh_rules = db.cfgdb.get_table("PBH_RULE") + pbh_counters = read_pbh_counters(pbh_rules) + saved_pbh_counters = read_saved_pbh_counters() - for table, rule in natsort.natsorted(pbh_rules): - counter_props = lowercase_keys(db_connector.get_all(db_connector.COUNTERS_DB, "COUNTERS:%s:%s" % (table, rule))) - if counter_props is not None: + if pbh_counters is not None: + for table_rule in pbh_rules: row = [ - table, - rule, - counter_props['packets'], - counter_props['bytes'] + table_rule[0], + table_rule[1], + get_counter_value(pbh_counters, saved_pbh_counters, table_rule, 'packets'), + get_counter_value(pbh_counters, saved_pbh_counters, table_rule, 'bytes'), ] body.append(row) click.echo(tabulate.tabulate(body, header, numalign="left")) +def get_counter_value(pbh_counters, saved_pbh_counters, key, type): + if not pbh_counters[key]: + return 'N/A' + + if saved_pbh_counters is not None: + if key in saved_pbh_counters: + new_value = int(pbh_counters[key][type]) - int(saved_pbh_counters[key][type]) + if new_value >= 0: + return str(new_value) + + return str(pbh_counters[key][type]) + + +def remap_keys(_list): + res = {} + for e in _list: + res[e['key'][0], e['key'][1]] = e['value'] + return res + + +def read_saved_pbh_counters(): + if os.path.isfile(PBH_COUNTERS_LOCATION): + # change approach maybe add if + try: + with open(PBH_COUNTERS_LOCATION) as fp: + saved_pbh_counters = remap_keys(json.load(fp)) + return saved_pbh_counters + except Exception: + click.echo('DEBUG: previous counter DOES NOT exist') + return None + + +def read_pbh_counters(pbh_rules) -> dict: + pbh_counters = {} + + db_connector = SonicV2Connector(use_unix_socket_path=False) + db_connector.connect(db_connector.COUNTERS_DB) + + # add some check + for table, rule in natsort.natsorted(pbh_rules): + counter_props = lowercase_keys(db_connector.get_all(db_connector.COUNTERS_DB, "COUNTERS:%s:%s" % (table, rule))) + pbh_counters[table, rule] = counter_props + + return pbh_counters + + def register(cli): cli_node = PBH if cli_node.name in cli.commands: diff --git a/tests/pbh_test.py b/tests/pbh_test.py index 82b4b71a0a..5786b4c2ce 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -766,6 +766,7 @@ def test_show_pbh_rule(self): ########## SHOW PBH STATISTICS ########## + # add empty counter DB test def test_show_pbh_statistics(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'full_pbh_config') @@ -781,3 +782,17 @@ def test_show_pbh_statistics(self): assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_statistics + #def test_show_pbh_empty_statistics(self): + # dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'full_pbh_config') + # dbconnector.dedicated_dbs['COUNTERS_DB'] = os.path.join(mock_db_path, 'empty_counters_db') + # db = Db() + # runner = CliRunner() + + # result = runner.invoke(show.cli.commands["pbh"]. + # commands["statistics"], [], obj=db) + + # logger.debug("\n" + result.output) + # logger.debug(result.exit_code) + # #assert result.exit_code == SUCCESS + # #assert result.output == assert_show_output.show_pbh_statistics + From 010cf6779e1f39e4ee8013a8222dae07ec65018f Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Wed, 30 Jun 2021 13:48:54 +0000 Subject: [PATCH 52/79] Added 'sonic-clear pbh' Signed-off-by: Vadym Hlushko --- clear/main.py | 25 +++++++++++++++++++++++-- tests/pbh_test.py | 23 ++++++++++++++++++++++- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/clear/main.py b/clear/main.py index 4302ae00aa..eb03410590 100755 --- a/clear/main.py +++ b/clear/main.py @@ -2,11 +2,13 @@ import os import subprocess import sys - import click +import utilities_common.cli as clicommon +import json +from swsscommon.swsscommon import SonicV2Connector from utilities_common import util_base - +from show.plugins.pbh import read_pbh_counters from . import plugins @@ -449,6 +451,25 @@ def translations(): cmd = "natclear -t" run_command(cmd) +# +# pbh +# +def remap_keys(dict): + return [{'key': k, 'value': v} for k, v in dict.items()] + +@cli.command() +@clicommon.pass_db +def pbh(db): + """ Clear PBH counters + clear counters -- write current counters to file in /tmp + """ + + pbh_rules = db.cfgdb.get_table("PBH_RULE") + pbh_counters = read_pbh_counters(pbh_rules) + + with open('/tmp/.pbh_counters.txt', 'w') as fp: + json.dump(remap_keys(pbh_counters), fp) + # Load plugins and register them helper = util_base.UtilHelper() diff --git a/tests/pbh_test.py b/tests/pbh_test.py index 5786b4c2ce..6d594397e4 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -4,6 +4,7 @@ import logging import show.main as show import config.main as config +import clear.main as clear from .pbh_input import assert_show_output from utilities_common.db import Db @@ -766,7 +767,6 @@ def test_show_pbh_rule(self): ########## SHOW PBH STATISTICS ########## - # add empty counter DB test def test_show_pbh_statistics(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'full_pbh_config') @@ -782,6 +782,27 @@ def test_show_pbh_statistics(self): assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_statistics + def test_clear_pbh_statistics(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'full_pbh_config') + dbconnector.dedicated_dbs['COUNTERS_DB'] = os.path.join(mock_db_path, 'counters_db') + db = Db() + runner = CliRunner() + + result = runner.invoke(clear.cli.commands["pbh"], [], obj=db) + + logger.debug("\n" + result.output) + logger.debug(result.exit_code) + + result = runner.invoke(show.cli.commands["pbh"]. + commands["statistics"], [], obj=db) + + logger.debug("\n" + result.output) + logger.debug(result.exit_code) + + #assert result.exit_code == SUCCESS + #assert result.output == assert_show_output.show_pbh_statistics + + # add empty counter DB test #def test_show_pbh_empty_statistics(self): # dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'full_pbh_config') # dbconnector.dedicated_dbs['COUNTERS_DB'] = os.path.join(mock_db_path, 'empty_counters_db') From 3733f0b7ad045269530d8e41206f76b5e90d6a88 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Wed, 30 Jun 2021 14:36:23 +0000 Subject: [PATCH 53/79] Added UT for 'show pbh statistics' & 'sonic-clear pbh' Signed-off-by: Vadym Hlushko --- show/plugins/pbh.py | 39 +++++------ tests/pbh_input/assert_show_output.py | 18 ++++- tests/pbh_input/counters_db.json | 10 +-- tests/pbh_input/counters_db_updated.json | 10 +++ tests/pbh_test.py | 87 ++++++++++++++++++------ 5 files changed, 118 insertions(+), 46 deletions(-) create mode 100644 tests/pbh_input/counters_db_updated.json diff --git a/show/plugins/pbh.py b/show/plugins/pbh.py index c0c3df12f6..2033f0e245 100644 --- a/show/plugins/pbh.py +++ b/show/plugins/pbh.py @@ -358,28 +358,29 @@ def PBH_STATISTICS(db): pbh_counters = read_pbh_counters(pbh_rules) saved_pbh_counters = read_saved_pbh_counters() - if pbh_counters is not None: - for table_rule in pbh_rules: - row = [ - table_rule[0], - table_rule[1], - get_counter_value(pbh_counters, saved_pbh_counters, table_rule, 'packets'), - get_counter_value(pbh_counters, saved_pbh_counters, table_rule, 'bytes'), - ] - body.append(row) + for key in pbh_rules: + # if counters value 0 or not exists should we display it? + if get_counter_value(pbh_counters, saved_pbh_counters, key, 'packets') == '0': + continue + row = [ + key[0], + key[1], + get_counter_value(pbh_counters, saved_pbh_counters, key, 'packets'), + get_counter_value(pbh_counters, saved_pbh_counters, key, 'bytes'), + ] + body.append(row) click.echo(tabulate.tabulate(body, header, numalign="left")) def get_counter_value(pbh_counters, saved_pbh_counters, key, type): if not pbh_counters[key]: - return 'N/A' + return '0' - if saved_pbh_counters is not None: - if key in saved_pbh_counters: - new_value = int(pbh_counters[key][type]) - int(saved_pbh_counters[key][type]) - if new_value >= 0: - return str(new_value) + if key in saved_pbh_counters: + new_value = int(pbh_counters[key][type]) - int(saved_pbh_counters[key][type]) + if new_value >= 0: + return str(new_value) return str(pbh_counters[key][type]) @@ -396,11 +397,11 @@ def read_saved_pbh_counters(): # change approach maybe add if try: with open(PBH_COUNTERS_LOCATION) as fp: - saved_pbh_counters = remap_keys(json.load(fp)) - return saved_pbh_counters + return remap_keys(json.load(fp)) except Exception: - click.echo('DEBUG: previous counter DOES NOT exist') - return None + return {} + + return {} def read_pbh_counters(pbh_rules) -> dict: diff --git a/tests/pbh_input/assert_show_output.py b/tests/pbh_input/assert_show_output.py index 715eff11e9..fb71a9d09b 100644 --- a/tests/pbh_input/assert_show_output.py +++ b/tests/pbh_input/assert_show_output.py @@ -56,9 +56,23 @@ """ +show_pbh_statistics_empty="""\ +TABLE RULE RX PACKETS COUNT RX BYTES COUNT +------- ------ ------------------ ---------------- +""" + + show_pbh_statistics="""\ TABLE RULE RX PACKETS COUNT RX BYTES COUNT ---------- ------ ------------------ ---------------- -pbh_table1 nvgre 111 222 -pbh_table2 vxlan 333 444 +pbh_table1 nvgre 100 200 +pbh_table2 vxlan 300 400 +""" + +show_pbh_statistics_updated="""\ +TABLE RULE RX PACKETS COUNT RX BYTES COUNT +---------- ------ ------------------ ---------------- +pbh_table1 nvgre 400 400 +pbh_table2 vxlan 400 400 """ + diff --git a/tests/pbh_input/counters_db.json b/tests/pbh_input/counters_db.json index fab6c9a4cc..1f764f32db 100644 --- a/tests/pbh_input/counters_db.json +++ b/tests/pbh_input/counters_db.json @@ -1,10 +1,10 @@ { "COUNTERS:pbh_table1:nvgre": { - "Packets": "111", - "Bytes": "222" + "Packets": "100", + "Bytes": "200" }, "COUNTERS:pbh_table2:vxlan": { - "Packets": "333", - "Bytes": "444" + "Packets": "300", + "Bytes": "400" } -} \ No newline at end of file +} diff --git a/tests/pbh_input/counters_db_updated.json b/tests/pbh_input/counters_db_updated.json new file mode 100644 index 0000000000..c1771ba3ff --- /dev/null +++ b/tests/pbh_input/counters_db_updated.json @@ -0,0 +1,10 @@ +{ + "COUNTERS:pbh_table1:nvgre": { + "Packets": "500", + "Bytes": "600" + }, + "COUNTERS:pbh_table2:vxlan": { + "Packets": "700", + "Bytes": "800" + } +} diff --git a/tests/pbh_test.py b/tests/pbh_test.py index 6d594397e4..001fb4e790 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -768,52 +768,99 @@ def test_show_pbh_rule(self): ########## SHOW PBH STATISTICS ########## + def test_show_pbh_statistics_on_empty_config(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = None + dbconnector.dedicated_dbs['COUNTERS_DB'] = None + + SAVED_PBH_COUNTERS_FILE = '/tmp/.pbh_counters.txt' + if os.path.isfile(SAVED_PBH_COUNTERS_FILE): + os.remove(SAVED_PBH_COUNTERS_FILE) + + db = Db() + runner = CliRunner() + + result = runner.invoke(show.cli.commands["pbh"]. + commands["statistics"], [], obj=db) + + logger.debug("\n" + result.output) + logger.debug(result.exit_code) + assert result.exit_code == SUCCESS + assert result.output == assert_show_output.show_pbh_statistics_empty + + def test_show_pbh_statistics(self): - dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'full_pbh_config') dbconnector.dedicated_dbs['COUNTERS_DB'] = os.path.join(mock_db_path, 'counters_db') + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'full_pbh_config') + + SAVED_PBH_COUNTERS_FILE = '/tmp/.pbh_counters.txt' + if os.path.isfile(SAVED_PBH_COUNTERS_FILE): + os.remove(SAVED_PBH_COUNTERS_FILE) + db = Db() runner = CliRunner() result = runner.invoke(show.cli.commands["pbh"]. commands["statistics"], [], obj=db) - logger.debug("\n" + result.output) logger.debug(result.exit_code) + assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_statistics - def test_clear_pbh_statistics(self): - dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'full_pbh_config') + def test_show_pbh_statistics_after_clear(self): dbconnector.dedicated_dbs['COUNTERS_DB'] = os.path.join(mock_db_path, 'counters_db') + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'full_pbh_config') + + SAVED_PBH_COUNTERS_FILE = '/tmp/.pbh_counters.txt' + if os.path.isfile(SAVED_PBH_COUNTERS_FILE): + os.remove(SAVED_PBH_COUNTERS_FILE) + db = Db() runner = CliRunner() - result = runner.invoke(clear.cli.commands["pbh"], [], obj=db) + result = runner.invoke(show.cli.commands["pbh"]. + commands["statistics"], [], obj=db) + logger.debug("\n" + result.output) + logger.debug(result.exit_code) + result = runner.invoke(clear.cli.commands["pbh"], [], obj=db) logger.debug("\n" + result.output) logger.debug(result.exit_code) result = runner.invoke(show.cli.commands["pbh"]. commands["statistics"], [], obj=db) - logger.debug("\n" + result.output) logger.debug(result.exit_code) - #assert result.exit_code == SUCCESS - #assert result.output == assert_show_output.show_pbh_statistics + assert result.exit_code == SUCCESS + assert result.output == assert_show_output.show_pbh_statistics_empty - # add empty counter DB test - #def test_show_pbh_empty_statistics(self): - # dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'full_pbh_config') - # dbconnector.dedicated_dbs['COUNTERS_DB'] = os.path.join(mock_db_path, 'empty_counters_db') - # db = Db() - # runner = CliRunner() + def test_show_pbh_statistics_after_clear_and_counters_updated(self): + dbconnector.dedicated_dbs['COUNTERS_DB'] = os.path.join(mock_db_path, 'counters_db') + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'full_pbh_config') - # result = runner.invoke(show.cli.commands["pbh"]. - # commands["statistics"], [], obj=db) + SAVED_PBH_COUNTERS_FILE = '/tmp/.pbh_counters.txt' + if os.path.isfile(SAVED_PBH_COUNTERS_FILE): + os.remove(SAVED_PBH_COUNTERS_FILE) - # logger.debug("\n" + result.output) - # logger.debug(result.exit_code) - # #assert result.exit_code == SUCCESS - # #assert result.output == assert_show_output.show_pbh_statistics + db = Db() + runner = CliRunner() + result = runner.invoke(show.cli.commands["pbh"]. + commands["statistics"], [], obj=db) + logger.debug("\n" + result.output) + logger.debug(result.exit_code) + + result = runner.invoke(clear.cli.commands["pbh"], [], obj=db) + logger.debug("\n" + result.output) + logger.debug(result.exit_code) + + dbconnector.dedicated_dbs['COUNTERS_DB'] = os.path.join(mock_db_path, 'counters_db_updated') + + result = runner.invoke(show.cli.commands["pbh"]. + commands["statistics"], [], obj=db) + logger.debug("\n" + result.output) + logger.debug(result.exit_code) + + assert result.exit_code == SUCCESS + assert result.output == assert_show_output.show_pbh_statistics_updated From af3f25e40c7001c408a844fa0f38fb587e46e536 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Wed, 30 Jun 2021 14:41:10 +0000 Subject: [PATCH 54/79] Codestyle improvement Signed-off-by: Vadym Hlushko --- clear/main.py | 6 +++--- show/plugins/pbh.py | 15 ++++++++------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/clear/main.py b/clear/main.py index eb03410590..5228804024 100755 --- a/clear/main.py +++ b/clear/main.py @@ -451,12 +451,12 @@ def translations(): cmd = "natclear -t" run_command(cmd) -# -# pbh -# def remap_keys(dict): return [{'key': k, 'value': v} for k, v in dict.items()] +# +# 'pbh' subcommand +# @cli.command() @clicommon.pass_db def pbh(db): diff --git a/show/plugins/pbh.py b/show/plugins/pbh.py index 2033f0e245..98336f6926 100644 --- a/show/plugins/pbh.py +++ b/show/plugins/pbh.py @@ -338,6 +338,7 @@ def PBH_TABLE(db): click.echo(tabulate.tabulate(body, header, numalign="left")) + @PBH.group(name="statistics", cls=clicommon.AliasedGroup, invoke_without_command=True) @@ -418,13 +419,6 @@ def read_pbh_counters(pbh_rules) -> dict: return pbh_counters -def register(cli): - cli_node = PBH - if cli_node.name in cli.commands: - raise Exception(f"{cli_node.name} already exists in CLI") - cli.add_command(PBH) - - def is_pbh_hash_field_symmetric(table: dict, key_to_check: str): """ The 'Symmetric' parameter will have 'Yes' value if there are 2 'pbh hash fields' with identical 'sequence_id' value @@ -451,3 +445,10 @@ def is_pbh_hash_field_symmetric(table: dict, key_to_check: str): def lowercase_keys(dictionary): return dict((k.lower(), v) for k, v in dictionary.items()) if dictionary else None + +def register(cli): + cli_node = PBH + if cli_node.name in cli.commands: + raise Exception(f"{cli_node.name} already exists in CLI") + cli.add_command(PBH) + From 3d3d18f05d532e76118e200e7cd32399905df14d Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Wed, 30 Jun 2021 14:58:33 +0000 Subject: [PATCH 55/79] fixed LGTM warnings Signed-off-by: Vadym Hlushko --- clear/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/clear/main.py b/clear/main.py index 5228804024..a827ceb805 100755 --- a/clear/main.py +++ b/clear/main.py @@ -6,7 +6,6 @@ import utilities_common.cli as clicommon import json -from swsscommon.swsscommon import SonicV2Connector from utilities_common import util_base from show.plugins.pbh import read_pbh_counters from . import plugins From a03c0029f4e6af29644c54dddb77fbeb4440e1ed Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Fri, 2 Jul 2021 11:02:59 +0000 Subject: [PATCH 56/79] Added unified format for exit_with_error() Signed-off-by: Vadym Hlushko --- config/plugins/pbh.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/config/plugins/pbh.py b/config/plugins/pbh.py index cefba3a395..1de7bfc187 100644 --- a/config/plugins/pbh.py +++ b/config/plugins/pbh.py @@ -41,7 +41,7 @@ def add_entry(db, table, key, data): cfg = db.get_config() cfg.setdefault(table, {}) if key in cfg[table]: - raise Exception(f"{key} already exists") + raise Exception("{} already exists".format(key)) cfg[table][key] = data @@ -60,7 +60,7 @@ def update_entry(db, table, key, data, create_if_not_exists=False): cfg[table].setdefault(key, {}) if key not in cfg[table]: - raise Exception(f"{key} does not exist") + raise Exception("{} does not exist".format(key)) for attr, value in data.items(): if value is None and attr in cfg[table][key]: @@ -77,7 +77,7 @@ def del_entry(db, table, key): cfg = db.get_config() cfg.setdefault(table, {}) if key not in cfg[table]: - raise Exception(f"{key} does not exist") + raise Exception("{} does not exist".format(key)) cfg[table].pop(key) @@ -303,7 +303,7 @@ def PBH_HASH_FIELD_add(db, hash_field_name, hash_field, ip_mask, sequence_id): try: add_entry(db.cfgdb, table, key, data) except Exception as err: - exit_with_error(f"Error: {err}", fg="red") + exit_with_error("Error: {}".format(err), fg="red") @PBH_HASH_FIELD.command(name="update") @@ -346,7 +346,7 @@ def PBH_HASH_FIELD_update(db, hash_field_name, hash_field, ip_mask, sequence_id) try: update_entry(db.cfgdb, table, key, data) except Exception as err: - exit_with_error(f"Error: {err}", fg="red") + exit_with_error("Error: {}".format(err), fg="red") @PBH_HASH_FIELD.command(name="delete") @@ -364,7 +364,7 @@ def PBH_HASH_FIELD_delete(db, hash_field_name): try: del_entry(db.cfgdb, table, key) except Exception as err: - exit_with_error(f"Error: {err}", fg="red") + exit_with_error("Error: {}".format(err), fg="red") @PBH.group(name="hash", @@ -401,7 +401,7 @@ def PBH_HASH_add(db, hash_name, hash_field_list): try: add_entry(db.cfgdb, table, key, data) except Exception as err: - exit_with_error(f"Error: {err}", fg="red") + exit_with_error("Error: {}".format(err), fg="red") @PBH_HASH.command(name="update") @@ -429,7 +429,7 @@ def PBH_HASH_update(db, hash_name, hash_field_list): try: update_entry(db.cfgdb, table, key, data) except Exception as err: - exit_with_error(f"Error: {err}", fg="red") + exit_with_error("Error: {}".format(err), fg="red") @PBH_HASH.command(name="delete") @@ -447,7 +447,7 @@ def PBH_HASH_delete(db, hash_name): try: del_entry(db.cfgdb, table, key) except Exception as err: - exit_with_error(f"Error: {err}", fg="red") + exit_with_error("Error: {}".format(err), fg="red") @PBH.group(name="rule", @@ -558,7 +558,7 @@ def PBH_RULE_add(db, try: add_entry(db.cfgdb, table, key, data) except Exception as err: - exit_with_error(f"Error: {err}", fg="red") + exit_with_error("Error: {}".format(err), fg="red") @PBH_RULE.command(name="update") @@ -659,7 +659,7 @@ def PBH_RULE_update(db, try: update_entry(db.cfgdb, table, key, data) except Exception as err: - exit_with_error(f"Error: {err}", fg="red") + exit_with_error("Error: {}".format(err), fg="red") @PBH_RULE.command(name="delete") @@ -682,7 +682,7 @@ def PBH_RULE_delete(db, table_name, rule_name): try: del_entry(db.cfgdb, table, key) except Exception as err: - exit_with_error(f"Error: {err}", fg="red") + exit_with_error("Error: {}".format(err), fg="red") @PBH.group(name="table", @@ -746,7 +746,7 @@ def PBH_TABLE_add(db, table_name, description, interface_list): try: add_entry(db.cfgdb, table, key, data) except Exception as err: - exit_with_error(f"Error: {err}", fg="red") + exit_with_error("Error: {}".format(err), fg="red") @PBH_TABLE.command(name="update") @@ -780,7 +780,7 @@ def PBH_TABLE_update(db, table_name, description, interface_list): try: update_entry(db.cfgdb, table, key, data) except Exception as err: - exit_with_error(f"Error: {err}", fg="red") + exit_with_error("Error: {}".format(err), fg="red") @PBH_TABLE.command(name="delete") @@ -798,12 +798,12 @@ def PBH_TABLE_delete(db, table_name): try: del_entry(db.cfgdb, table, key) except Exception as err: - exit_with_error(f"Error: {err}", fg="red") + exit_with_error("Error: {}".format(err), fg="red") def register(cli): cli_node = PBH if cli_node.name in cli.commands: - raise Exception(f"{cli_node.name} already exists in CLI") + raise Exception("{} already exists in CLI".format(cli_node.name)) cli.add_command(PBH) From 008eec38c1256adb151e559b0314027a3df7fd43 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Mon, 12 Jul 2021 11:09:31 +0000 Subject: [PATCH 57/79] Added exception handling for 'clear' subcommand Signed-off-by: Vadym Hlushko --- clear/main.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/clear/main.py b/clear/main.py index a827ceb805..25991678d0 100755 --- a/clear/main.py +++ b/clear/main.py @@ -450,9 +450,11 @@ def translations(): cmd = "natclear -t" run_command(cmd) + def remap_keys(dict): return [{'key': k, 'value': v} for k, v in dict.items()] + # # 'pbh' subcommand # @@ -466,8 +468,11 @@ def pbh(db): pbh_rules = db.cfgdb.get_table("PBH_RULE") pbh_counters = read_pbh_counters(pbh_rules) - with open('/tmp/.pbh_counters.txt', 'w') as fp: - json.dump(remap_keys(pbh_counters), fp) + try: + with open('/tmp/.pbh_counters.txt', 'w') as fp: + json.dump(remap_keys(pbh_counters), fp) + except IOError as err: + pass # Load plugins and register them From 56bb517a9b5a5e34b20b368d52f9e4fd25066953 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Mon, 12 Jul 2021 14:16:41 +0000 Subject: [PATCH 58/79] Unified click error msg format Signed-off-by: Vadym Hlushko --- config/plugins/pbh.py | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/config/plugins/pbh.py b/config/plugins/pbh.py index 1de7bfc187..19bee08179 100644 --- a/config/plugins/pbh.py +++ b/config/plugins/pbh.py @@ -100,7 +100,7 @@ def ip_address_validator(ctx, param, value): try: ip = ipaddress.ip_address(value) except Exception as e: - exit_with_error("Error: invalid value for '{}' option\n{}".format(param.name, e), fg="red") + exit_with_error("Error: invalid value '{}' for '{}' option\n{}".format(value, param.name, e), fg="red") return str(ip) @@ -118,7 +118,7 @@ def re_match(value, param_name, regexp): """ if re.match(regexp, str(value)) is None: - exit_with_error("Error: invalid value for '{}' option".format(param_name), fg="red") + exit_with_error("Error: invalid value '{}' for '{}' option".format(str(value), param_name), fg="red") return value @@ -148,7 +148,7 @@ def pbh_re_match(ctx, param, value): return re_match(value, param.name, inner_ether_type_re) -def is_exist_in_db(db, _list, conf_db_key, option_name): +def is_exist_in_db(db, obj_list, conf_db_key): """ Check if provided CLI option already exist in Config DB, i.g in case of --hash-field-list option it will check if 'hash-field' was previously added by @@ -156,22 +156,23 @@ def is_exist_in_db(db, _list, conf_db_key, option_name): Args: db: reference to Config DB, - _list: value of 'click' option + obj_list: value of 'click' option conf_db_key: key to search in Config DB - option_name: name of 'click' option """ - if _list is None: - return + if obj_list is None: + return True table = db.cfgdb.get_table(conf_db_key) correct_list = list(table.keys()) - splited_list = _list.split(',') + splited_list = obj_list.split(',') for elem in splited_list: if elem not in correct_list: - exit_with_error("Error: invalid value '{}' for '{}' option, please use {}".format(elem, option_name, correct_list), fg="red") + return False + + return True def ip_mask_hash_field_correspondence(ip_mask, hash_field): @@ -205,7 +206,7 @@ def ip_mask_hash_field_correspondence(ip_mask, hash_field): is_error = True if is_error: - exit_with_error("Error: the value of --hash-field='{}' is NOT compatible with the value of --ip-mask='{}'".format(hash_field, ip_mask), fg='red') + exit_with_error("Error: the value of '--hash-field'='{}' is NOT compatible with the value of '--ip-mask'='{}'".format(hash_field, ip_mask), fg='red') def update_ip_mask_hash_field(db, hash_field_name, ip_mask, hash_field): @@ -390,7 +391,8 @@ def PBH_HASH(): def PBH_HASH_add(db, hash_name, hash_field_list): """ Add object to PBH_HASH table """ - is_exist_in_db(db, hash_field_list, "PBH_HASH_FIELD", "--hash-field-list") + if not is_exist_in_db(db, hash_field_list, "PBH_HASH_FIELD"): + exit_with_error("Error: invalid value '{}' for '--hash-field-list' option".format(hash_field_list), fg="red") table = "PBH_HASH" key = hash_name @@ -418,7 +420,8 @@ def PBH_HASH_add(db, hash_name, hash_field_list): def PBH_HASH_update(db, hash_name, hash_field_list): """ Update object in PBH_HASH table """ - is_exist_in_db(db, hash_field_list, "PBH_HASH_FIELD", "--hash-field-list") + if not is_exist_in_db(db, hash_field_list, "PBH_HASH_FIELD"): + exit_with_error("Error: invalid value '{}' for '--hash-field-list' option".format(hash_field_list), fg="red") table = "PBH_HASH" key = hash_name @@ -530,8 +533,10 @@ def PBH_RULE_add(db, flow_counter): """ Add object to PBH_RULE table """ - is_exist_in_db(db, table_name, "PBH_TABLE", "--table-name") - is_exist_in_db(db, hash, "PBH_HASH", "--hash") + if not is_exist_in_db(db, table_name, "PBH_TABLE"): + exit_with_error("Error: invalid value '{}' for 'table-name' argument".format(table_name), fg="red") + if not is_exist_in_db(db, hash, "PBH_HASH"): + exit_with_error("Error: invalid value '{}' for '--hash' option".format(hash), fg="red") table = "PBH_RULE" key = table_name, rule_name @@ -631,8 +636,10 @@ def PBH_RULE_update(db, flow_counter): """ Update object in PBH_RULE table """ - is_exist_in_db(db, table_name, "PBH_TABLE", "--table-name") - is_exist_in_db(db, hash, "PBH_HASH", "--hash") + if not is_exist_in_db(db, table_name, "PBH_TABLE"): + exit_with_error("Error: invalid value '{}' for 'table-name' argument".format(table_name, table.name), fg="red") + if not is_exist_in_db(db, hash, "PBH_HASH"): + exit_with_error("Error: invalid value '{}' for '--hash' option".format(hash), fg="red") table = "PBH_RULE" key = table_name, rule_name @@ -710,7 +717,7 @@ def interfaces_list_validator(db, interface_list, is_update: bool): error = True if error: - exit_with_error("Error: invaliad value {}, for --interface-list option".format(interface_list), fg="red") + exit_with_error("Error: invalid value '{}', for '--interface-list' option".format(interface_list), fg="red") @PBH_TABLE.command(name="add") From c0e423a0f17cd2869ca92262963bff1d96f3a280 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 13 Jul 2021 08:50:21 +0000 Subject: [PATCH 59/79] Fixed teardown for pbh_test.py Signed-off-by: Vadym Hlushko --- tests/pbh_test.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/pbh_test.py b/tests/pbh_test.py index 001fb4e790..3a9387834d 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -5,11 +5,13 @@ import show.main as show import config.main as config import clear.main as clear +import importlib from .pbh_input import assert_show_output from utilities_common.db import Db from click.testing import CliRunner from .mock_tables import dbconnector +from .mock_tables import mock_single_asic logger = logging.getLogger(__name__) test_path = os.path.dirname(os.path.abspath(__file__)) @@ -30,6 +32,9 @@ def setup_class(cls): def teardown_class(cls): logger.info("TEARDOWN") os.environ['UTILITIES_UNIT_TESTING'] = "0" + os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "" + importlib.reload(mock_single_asic) + dbconnector.load_namespace_config() ########## CONFIG PBH HASH-FIELD ########## From f51982ebfd69f58fe30d2b2ed3b7e27d32810c25 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 13 Jul 2021 09:58:36 +0000 Subject: [PATCH 60/79] Fixed LGTM error Signed-off-by: Vadym Hlushko --- config/plugins/pbh.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/plugins/pbh.py b/config/plugins/pbh.py index 19bee08179..a0b7fa7fa6 100644 --- a/config/plugins/pbh.py +++ b/config/plugins/pbh.py @@ -637,7 +637,7 @@ def PBH_RULE_update(db, """ Update object in PBH_RULE table """ if not is_exist_in_db(db, table_name, "PBH_TABLE"): - exit_with_error("Error: invalid value '{}' for 'table-name' argument".format(table_name, table.name), fg="red") + exit_with_error("Error: invalid value '{}' for 'table-name' argument".format(table_name), fg="red") if not is_exist_in_db(db, hash, "PBH_HASH"): exit_with_error("Error: invalid value '{}' for '--hash' option".format(hash), fg="red") From fad30a73296e780cd9b2c384879a4af87eb04504 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 13 Jul 2021 12:04:13 +0000 Subject: [PATCH 61/79] Rework of ip_mask_hash_field_correspondence() Signed-off-by: Vadym Hlushko --- config/plugins/pbh.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/config/plugins/pbh.py b/config/plugins/pbh.py index a0b7fa7fa6..b0acb6b35c 100644 --- a/config/plugins/pbh.py +++ b/config/plugins/pbh.py @@ -180,33 +180,29 @@ def ip_mask_hash_field_correspondence(ip_mask, hash_field): the --hash-field option Args: - ip_mask: ip address, + ip_mask: ip address or None, hash_field: hash field value, which was configured before """ - is_error = False - hf_v4_and_v6 = ['INNER_DST_IPV4', 'INNER_SRC_IPV4', 'INNER_DST_IPV6', 'INNER_SRC_IPV6'] - hf_no_ip = ['INNER_IP_PROTOCOL', 'INNER_L4_DST_PORT', 'INNER_L4_SRC_PORT'] hf_v4 = ['INNER_DST_IPV4', 'INNER_SRC_IPV4'] hf_v6 = ['INNER_DST_IPV6', 'INNER_SRC_IPV6'] + hf_v4_and_v6 = hf_v4 + hf_v6 + hf_no_ip = ['INNER_IP_PROTOCOL', 'INNER_L4_DST_PORT', 'INNER_L4_SRC_PORT'] - if (ip_mask is None) and (hash_field in hf_v4_and_v6): - is_error = True + if (hash_field in hf_no_ip) and (ip_mask): + exit_with_error("Error: the value of '--hash-field'='{}' is NOT compatible with the value of '--ip-mask'='{}'".format(hash_field, ip_mask), fg='red') - if (ip_mask is not None) and (hash_field in hf_no_ip): - is_error = True + if (hash_field in hf_v4_and_v6) and (ip_mask is None): + exit_with_error("Error: the value of '--hash-field'='{}' is NOT compatible with the value of '--ip-mask'='{}'".format(hash_field, ip_mask), fg='red') - if ip_mask is not None: + if (ip_mask is not None): ip_addr_version = ipaddress.ip_address(ip_mask).version if (hash_field in hf_v4) and (ip_addr_version != 4): - is_error = True + exit_with_error("Error: the value of '--hash-field'='{}' is NOT compatible with the value of '--ip-mask'='{}'".format(hash_field, ip_mask), fg='red') if (hash_field in hf_v6) and (ip_addr_version != 6): - is_error = True - - if is_error: - exit_with_error("Error: the value of '--hash-field'='{}' is NOT compatible with the value of '--ip-mask'='{}'".format(hash_field, ip_mask), fg='red') + exit_with_error("Error: the value of '--hash-field'='{}' is NOT compatible with the value of '--ip-mask'='{}'".format(hash_field, ip_mask), fg='red') def update_ip_mask_hash_field(db, hash_field_name, ip_mask, hash_field): From 6682adde9e2a8479b0347b0fe12d58137ed2d6af Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 13 Jul 2021 12:23:50 +0000 Subject: [PATCH 62/79] Fixed functions name Signed-off-by: Vadym Hlushko --- config/plugins/pbh.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/config/plugins/pbh.py b/config/plugins/pbh.py index b0acb6b35c..9fb9b5a950 100644 --- a/config/plugins/pbh.py +++ b/config/plugins/pbh.py @@ -175,7 +175,7 @@ def is_exist_in_db(db, obj_list, conf_db_key): return True -def ip_mask_hash_field_correspondence(ip_mask, hash_field): +def ip_mask_hash_field_correspondence_validator(ip_mask, hash_field): """ Check if the --ip-mask option are correspond to the --hash-field option @@ -205,7 +205,7 @@ def ip_mask_hash_field_correspondence(ip_mask, hash_field): exit_with_error("Error: the value of '--hash-field'='{}' is NOT compatible with the value of '--ip-mask'='{}'".format(hash_field, ip_mask), fg='red') -def update_ip_mask_hash_field(db, hash_field_name, ip_mask, hash_field): +def ip_mask_hash_field_update_validator(db, hash_field_name, ip_mask, hash_field): """ Function to validate --ip-mask and --hash-field correspondence, during update flow @@ -229,7 +229,7 @@ def update_ip_mask_hash_field(db, hash_field_name, ip_mask, hash_field): except Exception as e: ip_mask = None - ip_mask_hash_field_correspondence(ip_mask, hash_field) + ip_mask_hash_field_correspondence_validator(ip_mask, hash_field) if (ip_mask is not None) and (hash_field is None): @@ -238,7 +238,7 @@ def update_ip_mask_hash_field(db, hash_field_name, ip_mask, hash_field): except Exception as e: hash_field = None - ip_mask_hash_field_correspondence(ip_mask, hash_field) + ip_mask_hash_field_correspondence_validator(ip_mask, hash_field) @click.group(name='pbh', @@ -285,7 +285,7 @@ def PBH_HASH_FIELD(): def PBH_HASH_FIELD_add(db, hash_field_name, hash_field, ip_mask, sequence_id): """ Add object to PBH_HASH_FIELD table """ - ip_mask_hash_field_correspondence(ip_mask, hash_field) + ip_mask_hash_field_correspondence_validator(ip_mask, hash_field) table = "PBH_HASH_FIELD" key = hash_field_name @@ -328,7 +328,7 @@ def PBH_HASH_FIELD_add(db, hash_field_name, hash_field, ip_mask, sequence_id): def PBH_HASH_FIELD_update(db, hash_field_name, hash_field, ip_mask, sequence_id): """ Update object in PBH_HASH_FIELD table """ - update_ip_mask_hash_field(db, hash_field_name, ip_mask, hash_field) + ip_mask_hash_field_update_validator(db, hash_field_name, ip_mask, hash_field) table = "PBH_HASH_FIELD" key = hash_field_name From 6bb079a01ee7f6bf3dac9fc578868cc43b410d1a Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 13 Jul 2021 12:29:45 +0000 Subject: [PATCH 63/79] Codestyle Signed-off-by: Vadym Hlushko --- config/plugins/pbh.py | 98 +++++++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 41 deletions(-) diff --git a/config/plugins/pbh.py b/config/plugins/pbh.py index 9fb9b5a950..58213e6dfb 100644 --- a/config/plugins/pbh.py +++ b/config/plugins/pbh.py @@ -11,13 +11,15 @@ import re import utilities_common.cli as clicommon -hash_field_types = ['INNER_IP_PROTOCOL', - 'INNER_L4_DST_PORT', - 'INNER_L4_SRC_PORT', - 'INNER_DST_IPV4', - 'INNER_SRC_IPV4', - 'INNER_DST_IPV6', - 'INNER_SRC_IPV6'] +hash_field_types = [ + 'INNER_IP_PROTOCOL', + 'INNER_L4_DST_PORT', + 'INNER_L4_SRC_PORT', + 'INNER_DST_IPV4', + 'INNER_SRC_IPV4', + 'INNER_DST_IPV6', + 'INNER_SRC_IPV6' +] packet_action_types = ['SET_ECMP_HASH', 'SET_LAG_HASH'] flow_counter_state = ['DISABLED', 'ENABLED'] @@ -241,16 +243,20 @@ def ip_mask_hash_field_update_validator(db, hash_field_name, ip_mask, hash_field ip_mask_hash_field_correspondence_validator(ip_mask, hash_field) -@click.group(name='pbh', - cls=clicommon.AliasedGroup) +@click.group( + name='pbh', + cls=clicommon.AliasedGroup +) def PBH(): """ Configure PBH (Policy based hashing) feature """ pass -@PBH.group(name="hash-field", - cls=clicommon.AliasedGroup) +@PBH.group( + name="hash-field", + cls=clicommon.AliasedGroup +) def PBH_HASH_FIELD(): """ Configure PBH hash field """ @@ -364,8 +370,10 @@ def PBH_HASH_FIELD_delete(db, hash_field_name): exit_with_error("Error: {}".format(err), fg="red") -@PBH.group(name="hash", - cls=clicommon.AliasedGroup) +@PBH.group( + name="hash", + cls=clicommon.AliasedGroup +) def PBH_HASH(): """ Configure PBH hash """ @@ -449,8 +457,10 @@ def PBH_HASH_delete(db, hash_name): exit_with_error("Error: {}".format(err), fg="red") -@PBH.group(name="rule", - cls=clicommon.AliasedGroup) +@PBH.group( + name="rule", + cls=clicommon.AliasedGroup +) def PBH_RULE(): """ Configure PBH rule """ @@ -515,18 +525,20 @@ def PBH_RULE(): type=click.Choice(flow_counter_state) ) @clicommon.pass_db -def PBH_RULE_add(db, - table_name, - rule_name, - priority, - gre_key, - ip_protocol, - ipv6_next_header, - l4_dst_port, - inner_ether_type, - hash, - packet_action, - flow_counter): +def PBH_RULE_add( + db, + table_name, + rule_name, + priority, + gre_key, + ip_protocol, + ipv6_next_header, + l4_dst_port, + inner_ether_type, + hash, + packet_action, + flow_counter +): """ Add object to PBH_RULE table """ if not is_exist_in_db(db, table_name, "PBH_TABLE"): @@ -618,18 +630,20 @@ def PBH_RULE_add(db, type=click.Choice(flow_counter_state) ) @clicommon.pass_db -def PBH_RULE_update(db, - table_name, - rule_name, - priority, - gre_key, - ip_protocol, - ipv6_next_header, - l4_dst_port, - inner_ether_type, - hash, - packet_action, - flow_counter): +def PBH_RULE_update( + db, + table_name, + rule_name, + priority, + gre_key, + ip_protocol, + ipv6_next_header, + l4_dst_port, + inner_ether_type, + hash, + packet_action, + flow_counter +): """ Update object in PBH_RULE table """ if not is_exist_in_db(db, table_name, "PBH_TABLE"): @@ -688,8 +702,10 @@ def PBH_RULE_delete(db, table_name, rule_name): exit_with_error("Error: {}".format(err), fg="red") -@PBH.group(name="table", - cls=clicommon.AliasedGroup) +@PBH.group( + name="table", + cls=clicommon.AliasedGroup +) def PBH_TABLE(): """ Configure PBH table""" From fd930ecb785fc849fa05e2121c1ae498a641061a Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 13 Jul 2021 12:40:34 +0000 Subject: [PATCH 64/79] Added defines for config module Signed-off-by: Vadym Hlushko --- config/plugins/pbh.py | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/config/plugins/pbh.py b/config/plugins/pbh.py index 58213e6dfb..11d8328c7e 100644 --- a/config/plugins/pbh.py +++ b/config/plugins/pbh.py @@ -29,6 +29,10 @@ l4_dst_port_re = r"(0x){1}[a-fA-F0-9]{1,4}" inner_ether_type_re = l4_dst_port_re +pbh_hash_field_tbl_name = 'PBH_HASH_FIELD' +pbh_hash_tbl_name = 'PBH_HASH' +pbh_table_tbl_name = 'PBH_TABLE' + def exit_with_error(*args, **kwargs): """ Print a message and abort CLI. """ @@ -221,7 +225,7 @@ def ip_mask_hash_field_update_validator(db, hash_field_name, ip_mask, hash_field if (ip_mask is None) and (hash_field is None): return - table = db.cfgdb.get_table('PBH_HASH_FIELD') + table = db.cfgdb.get_table(pbh_hash_field_tbl_name) hash_field_obj = table[hash_field_name] if (ip_mask is None) and (hash_field is not None): @@ -293,7 +297,7 @@ def PBH_HASH_FIELD_add(db, hash_field_name, hash_field, ip_mask, sequence_id): ip_mask_hash_field_correspondence_validator(ip_mask, hash_field) - table = "PBH_HASH_FIELD" + table = pbh_hash_field_tbl_name key = hash_field_name data = {} if hash_field is not None: @@ -336,7 +340,7 @@ def PBH_HASH_FIELD_update(db, hash_field_name, hash_field, ip_mask, sequence_id) ip_mask_hash_field_update_validator(db, hash_field_name, ip_mask, hash_field) - table = "PBH_HASH_FIELD" + table = pbh_hash_field_tbl_name key = hash_field_name data = {} if hash_field is not None: @@ -362,7 +366,7 @@ def PBH_HASH_FIELD_update(db, hash_field_name, hash_field, ip_mask, sequence_id) def PBH_HASH_FIELD_delete(db, hash_field_name): """ Delete object from PBH_HASH_FIELD table """ - table = "PBH_HASH_FIELD" + table = pbh_hash_field_tbl_name key = hash_field_name try: del_entry(db.cfgdb, table, key) @@ -395,10 +399,10 @@ def PBH_HASH(): def PBH_HASH_add(db, hash_name, hash_field_list): """ Add object to PBH_HASH table """ - if not is_exist_in_db(db, hash_field_list, "PBH_HASH_FIELD"): + if not is_exist_in_db(db, hash_field_list, pbh_hash_field_tbl_name): exit_with_error("Error: invalid value '{}' for '--hash-field-list' option".format(hash_field_list), fg="red") - table = "PBH_HASH" + table = pbh_hash_tbl_name key = hash_name data = {} if hash_field_list is not None: @@ -424,10 +428,10 @@ def PBH_HASH_add(db, hash_name, hash_field_list): def PBH_HASH_update(db, hash_name, hash_field_list): """ Update object in PBH_HASH table """ - if not is_exist_in_db(db, hash_field_list, "PBH_HASH_FIELD"): + if not is_exist_in_db(db, hash_field_list, pbh_hash_field_tbl_name): exit_with_error("Error: invalid value '{}' for '--hash-field-list' option".format(hash_field_list), fg="red") - table = "PBH_HASH" + table = pbh_hash_tbl_name key = hash_name data = {} if hash_field_list is not None: @@ -449,7 +453,7 @@ def PBH_HASH_update(db, hash_name, hash_field_list): def PBH_HASH_delete(db, hash_name): """ Delete object from PBH_HASH table """ - table = "PBH_HASH" + table = pbh_hash_tbl_name key = hash_name try: del_entry(db.cfgdb, table, key) @@ -541,9 +545,9 @@ def PBH_RULE_add( ): """ Add object to PBH_RULE table """ - if not is_exist_in_db(db, table_name, "PBH_TABLE"): + if not is_exist_in_db(db, table_name, pbh_table_tbl_name): exit_with_error("Error: invalid value '{}' for 'table-name' argument".format(table_name), fg="red") - if not is_exist_in_db(db, hash, "PBH_HASH"): + if not is_exist_in_db(db, hash, pbh_hash_tbl_name): exit_with_error("Error: invalid value '{}' for '--hash' option".format(hash), fg="red") table = "PBH_RULE" @@ -646,9 +650,9 @@ def PBH_RULE_update( ): """ Update object in PBH_RULE table """ - if not is_exist_in_db(db, table_name, "PBH_TABLE"): + if not is_exist_in_db(db, table_name, pbh_table_tbl_name): exit_with_error("Error: invalid value '{}' for 'table-name' argument".format(table_name), fg="red") - if not is_exist_in_db(db, hash, "PBH_HASH"): + if not is_exist_in_db(db, hash, pbh_hash_tbl_name): exit_with_error("Error: invalid value '{}' for '--hash' option".format(hash), fg="red") table = "PBH_RULE" From 01c3cca7520214b79b42e9dde766a97993fbd611 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Tue, 13 Jul 2021 15:17:37 +0000 Subject: [PATCH 65/79] Added cleanup of mocked db in UT Signed-off-by: Vadym Hlushko --- tests/pbh_test.py | 56 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/tests/pbh_test.py b/tests/pbh_test.py index 3a9387834d..c873854088 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -36,6 +36,10 @@ def teardown_class(cls): importlib.reload(mock_single_asic) dbconnector.load_namespace_config() + def clear_dedicated_mock_dbs(self): + dbconnector.dedicated_dbs['CONFIG_DB'] = None + dbconnector.dedicated_dbs['COUNTERS_DB'] = None + ########## CONFIG PBH HASH-FIELD ########## @@ -367,6 +371,8 @@ def test_config_pbh_hash_add_delete_ipv4(self): logger.debug(result.exit_code) assert result.exit_code == SUCCESS + self.clear_dedicated_mock_dbs() + def test_config_pbh_hash_add_update_ipv6(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'hash_fields') @@ -393,6 +399,8 @@ def test_config_pbh_hash_add_update_ipv6(self): logger.debug(result.exit_code) assert result.exit_code == SUCCESS + self.clear_dedicated_mock_dbs() + def test_config_pbh_hash_add_invalid_hash_field_list(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'hash_fields') @@ -408,6 +416,8 @@ def test_config_pbh_hash_add_invalid_hash_field_list(self): logger.debug(result.exit_code) assert result.exit_code == ERROR + self.clear_dedicated_mock_dbs() + def test_config_pbh_hash_add_empty_hash_field_list(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'hash_fields') @@ -423,6 +433,8 @@ def test_config_pbh_hash_add_empty_hash_field_list(self): logger.debug(result.exit_code) assert result.exit_code == ERROR + self.clear_dedicated_mock_dbs() + ########## CONFIG PBH TABLE ########## @@ -448,6 +460,8 @@ def test_config_pbh_table_add_delete_ports(self): logger.debug(result.exit_code) assert result.exit_code == SUCCESS + self.clear_dedicated_mock_dbs() + def test_config_pbh_table_add_update_portchannels(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') @@ -488,6 +502,8 @@ def test_config_pbh_table_add_update_portchannels(self): logger.debug(result.exit_code) assert result.exit_code == SUCCESS + self.clear_dedicated_mock_dbs() + def test_config_pbh_table_add_port_and_portchannel(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') @@ -503,6 +519,8 @@ def test_config_pbh_table_add_port_and_portchannel(self): logger.debug(result.exit_code) assert result.exit_code == SUCCESS + self.clear_dedicated_mock_dbs() + def test_config_pbh_table_add_invalid_port(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') @@ -518,6 +536,8 @@ def test_config_pbh_table_add_invalid_port(self): logger.debug(result.exit_code) assert result.exit_code == ERROR + self.clear_dedicated_mock_dbs() + def test_config_pbh_table_add_update_wrong_interface(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') @@ -541,6 +561,8 @@ def test_config_pbh_table_add_update_wrong_interface(self): logger.debug(result.exit_code) assert result.exit_code == ERROR + self.clear_dedicated_mock_dbs() + ########## CONFIG PBH RULE ########## @@ -568,6 +590,8 @@ def test_config_pbh_rule_add_delete_nvgre(self): logger.debug(result.exit_code) assert result.exit_code == SUCCESS + self.clear_dedicated_mock_dbs() + def test_config_pbh_rule_add_update_vxlan(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') @@ -594,6 +618,8 @@ def test_config_pbh_rule_add_update_vxlan(self): logger.debug(result.exit_code) assert result.exit_code == SUCCESS + self.clear_dedicated_mock_dbs() + def test_config_pbh_rule_update_invalid(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') @@ -619,6 +645,8 @@ def test_config_pbh_rule_update_invalid(self): logger.debug(result.exit_code) assert result.exit_code == ERROR2 + self.clear_dedicated_mock_dbs() + def test_config_pbh_rule_add_invalid_ip_protocol(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') @@ -636,6 +664,8 @@ def test_config_pbh_rule_add_invalid_ip_protocol(self): logger.debug(result.exit_code) assert result.exit_code == ERROR + self.clear_dedicated_mock_dbs() + def test_config_pbh_rule_add_invalid_inner_ether_type(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') @@ -653,6 +683,8 @@ def test_config_pbh_rule_add_invalid_inner_ether_type(self): logger.debug(result.exit_code) assert result.exit_code == ERROR + self.clear_dedicated_mock_dbs() + def test_config_pbh_rule_add_invalid_hash(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') @@ -670,6 +702,8 @@ def test_config_pbh_rule_add_invalid_hash(self): logger.debug(result.exit_code) assert result.exit_code == ERROR + self.clear_dedicated_mock_dbs() + def test_config_pbh_rule_add_invalid_packet_action(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') @@ -687,6 +721,8 @@ def test_config_pbh_rule_add_invalid_packet_action(self): logger.debug(result.exit_code) assert result.exit_code == ERROR2 + self.clear_dedicated_mock_dbs() + def test_config_pbh_rule_add_invalid_flow_counter(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') @@ -704,6 +740,8 @@ def test_config_pbh_rule_add_invalid_flow_counter(self): logger.debug(result.exit_code) assert result.exit_code == ERROR2 + self.clear_dedicated_mock_dbs() + ########## SHOW PBH HASH-FIELD ########## def test_show_pbh_hash_field(self): @@ -719,6 +757,8 @@ def test_show_pbh_hash_field(self): assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_hash_fields + self.clear_dedicated_mock_dbs() + ########## SHOW PBH HASH ########## @@ -736,6 +776,8 @@ def test_show_pbh_hash(self): assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_hash + self.clear_dedicated_mock_dbs() + ########## SHOW PBH TABLE ########## @@ -753,6 +795,8 @@ def test_show_pbh_table(self): assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_table + self.clear_dedicated_mock_dbs() + ########## SHOW PBH RULE ########## @@ -770,6 +814,8 @@ def test_show_pbh_rule(self): assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_rule + self.clear_dedicated_mock_dbs() + ########## SHOW PBH STATISTICS ########## @@ -792,6 +838,8 @@ def test_show_pbh_statistics_on_empty_config(self): assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_statistics_empty + self.clear_dedicated_mock_dbs() + def test_show_pbh_statistics(self): dbconnector.dedicated_dbs['COUNTERS_DB'] = os.path.join(mock_db_path, 'counters_db') @@ -812,6 +860,9 @@ def test_show_pbh_statistics(self): assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_statistics + self.clear_dedicated_mock_dbs() + + def test_show_pbh_statistics_after_clear(self): dbconnector.dedicated_dbs['COUNTERS_DB'] = os.path.join(mock_db_path, 'counters_db') dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'full_pbh_config') @@ -840,6 +891,9 @@ def test_show_pbh_statistics_after_clear(self): assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_statistics_empty + self.clear_dedicated_mock_dbs() + + def test_show_pbh_statistics_after_clear_and_counters_updated(self): dbconnector.dedicated_dbs['COUNTERS_DB'] = os.path.join(mock_db_path, 'counters_db') dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'full_pbh_config') @@ -869,3 +923,5 @@ def test_show_pbh_statistics_after_clear_and_counters_updated(self): assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_statistics_updated + + self.clear_dedicated_mock_dbs() From c22ce2a2886bcaccb6754a3f0b8a697d10b49ec4 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Wed, 14 Jul 2021 09:27:19 +0000 Subject: [PATCH 66/79] Codestyle and other improvement Signed-off-by: Vadym Hlushko --- config/plugins/pbh.py | 71 ++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/config/plugins/pbh.py b/config/plugins/pbh.py index 11d8328c7e..03ce4ceb5a 100644 --- a/config/plugins/pbh.py +++ b/config/plugins/pbh.py @@ -129,7 +129,7 @@ def re_match(value, param_name, regexp): return value -def pbh_re_match(ctx, param, value): +def pbh_re_match_validator(ctx, param, value): """ Check if PBH rule options are valid Args: @@ -239,14 +239,35 @@ def ip_mask_hash_field_update_validator(db, hash_field_name, ip_mask, hash_field if (ip_mask is not None) and (hash_field is None): - try: - hash_field = hash_field_obj['hash_field'] - except Exception as e: - hash_field = None + hash_field = hash_field_obj['hash_field'] ip_mask_hash_field_correspondence_validator(ip_mask, hash_field) +def interfaces_list_validator(db, interface_list, is_update): + if is_update and (interface_list is None): + return + + is_error = False + interfaces_splited = interface_list.split(',') + + for intf in interfaces_splited: + if intf.startswith('Ethernet'): + if not clicommon.is_valid_port(db.cfgdb, intf): + is_error = True + break + elif intf.startswith('PortChannel'): + if not clicommon.is_valid_portchannel(db.cfgdb, intf): + is_error = True + break + else: + is_error = True + break + + if is_error: + exit_with_error("Error: invalid value '{}', for '--interface-list' option".format(interface_list), fg="red") + + @click.group( name='pbh', cls=clicommon.AliasedGroup @@ -491,27 +512,27 @@ def PBH_RULE(): @click.option( "--gre-key", help="Configures packet match: GRE key (value/mask)", - callback=pbh_re_match, + callback=pbh_re_match_validator, ) @click.option( "--ip-protocol", help="Configures packet match: IP protocol (value/mask)", - callback=pbh_re_match, + callback=pbh_re_match_validator, ) @click.option( "--ipv6-next-header", help="Configures packet match: IPv6 Next header (value/mask)", - callback=pbh_re_match, + callback=pbh_re_match_validator, ) @click.option( "--l4-dst-port", help="Configures packet match: L4 destination port (value/mask)", - callback=pbh_re_match, + callback=pbh_re_match_validator, ) @click.option( "--inner-ether-type", help="Configures packet match: inner EtherType (value/mask)", - callback=pbh_re_match, + callback=pbh_re_match_validator, ) @click.option( "--hash", @@ -597,27 +618,27 @@ def PBH_RULE_add( @click.option( "--gre-key", help="Configures packet match: GRE key (value/mask)", - callback=pbh_re_match, + callback=pbh_re_match_validator, ) @click.option( "--ip-protocol", help="Configures packet match: IP protocol (value/mask)", - callback=pbh_re_match, + callback=pbh_re_match_validator, ) @click.option( "--ipv6-next-header", help="Configures packet match: IPv6 Next header (value/mask)", - callback=pbh_re_match, + callback=pbh_re_match_validator, ) @click.option( "--l4-dst-port", help="Configures packet match: L4 destination port (value/mask)", - callback=pbh_re_match, + callback=pbh_re_match_validator, ) @click.option( "--inner-ether-type", help="Configures packet match: inner EtherType (value/mask)", - callback=pbh_re_match, + callback=pbh_re_match_validator, ) @click.option( "--hash", @@ -715,26 +736,6 @@ def PBH_TABLE(): pass -def interfaces_list_validator(db, interface_list, is_update: bool): - if is_update and (interface_list is None): - return - - error = False - interfaces = interface_list.split(',') - - for intf in interfaces: - if intf.startswith('Ethernet'): - if not clicommon.is_valid_port(db.cfgdb, intf): - error = True - elif intf.startswith('PortChannel'): - if not clicommon.is_valid_portchannel(db.cfgdb, intf): - error = True - else: - error = True - - if error: - exit_with_error("Error: invalid value '{}', for '--interface-list' option".format(interface_list), fg="red") - @PBH_TABLE.command(name="add") @click.argument( From 048774a4dbee8a6b6cfd710d629c4a1efdeaa412 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Wed, 14 Jul 2021 10:40:02 +0000 Subject: [PATCH 67/79] improvements for show plugin Signed-off-by: Vadym Hlushko --- show/plugins/pbh.py | 65 ++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/show/plugins/pbh.py b/show/plugins/pbh.py index 98336f6926..6ee36e5408 100644 --- a/show/plugins/pbh.py +++ b/show/plugins/pbh.py @@ -16,6 +16,11 @@ PBH_COUNTERS_LOCATION = '/tmp/.pbh_counters.txt' +pbh_hash_field_tbl_name = 'PBH_HASH_FIELD' +pbh_hash_tbl_name = 'PBH_HASH' +pbh_table_tbl_name = 'PBH_TABLE' +pbh_rule_tbl_name = 'PBH_RULE' + def format_attr_value(entry, attr): """ Helper that formats attribute to be presented in the table output. @@ -53,17 +58,21 @@ def format_group_value(entry, attrs): return tabulate.tabulate(data, tablefmt="plain", numalign="left") -@click.group(name='pbh', - cls=clicommon.AliasedGroup) +@click.group( + name='pbh', + cls=clicommon.AliasedGroup +) def PBH(): """ Show PBH (Policy based hashing) feature configuration """ pass -@PBH.group(name="hash-field", - cls=clicommon.AliasedGroup, - invoke_without_command=True) +@PBH.group( + name="hash-field", + cls=clicommon.AliasedGroup, + invoke_without_command=True +) @clicommon.pass_db def PBH_HASH_FIELD(db): """ Show the PBH hash field configuration """ @@ -78,7 +87,7 @@ def PBH_HASH_FIELD(db): body = [] - table = db.cfgdb.get_table("PBH_HASH_FIELD") + table = db.cfgdb.get_table(pbh_hash_field_tbl_name) for key in natsort.natsorted(table): is_pbh_hash_field_symmetric(table, key) @@ -138,9 +147,11 @@ def PBH_HASH_FIELD(db): click.echo(tabulate.tabulate(body_sorted, header, numalign="left")) -@PBH.group(name="hash", - cls=clicommon.AliasedGroup, - invoke_without_command=True) +@PBH.group( + name="hash", + cls=clicommon.AliasedGroup, + invoke_without_command=True +) @clicommon.pass_db def PBH_HASH(db): """ Show the PBH hash configuration """ @@ -152,7 +163,7 @@ def PBH_HASH(db): body = [] - table = db.cfgdb.get_table("PBH_HASH") + table = db.cfgdb.get_table(pbh_hash_tbl_name) for key in natsort.natsorted(table): entry = table[key] if not isinstance(key, tuple): @@ -176,9 +187,11 @@ def PBH_HASH(db): click.echo(tabulate.tabulate(body, header, numalign="left")) -@PBH.group(name="rule", - cls=clicommon.AliasedGroup, - invoke_without_command=True) +@PBH.group( + name="rule", + cls=clicommon.AliasedGroup, + invoke_without_command=True +) @clicommon.pass_db def PBH_RULE(db): """ Show the PBH rules configuration """ @@ -195,7 +208,7 @@ def PBH_RULE(db): body = [] - table = db.cfgdb.get_table("PBH_RULE") + table = db.cfgdb.get_table(pbh_rule_tbl_name) for key in natsort.natsorted(table): entry = table[key] if not isinstance(key, tuple): @@ -290,9 +303,11 @@ def PBH_RULE(db): click.echo(tabulate.tabulate(body_sorted, header, numalign="left")) -@PBH.group(name="table", - cls=clicommon.AliasedGroup, - invoke_without_command=True) +@PBH.group( + name="table", + cls=clicommon.AliasedGroup, + invoke_without_command=True +) @clicommon.pass_db def PBH_TABLE(db): """ Show the PBH table configuration """ @@ -305,7 +320,7 @@ def PBH_TABLE(db): body = [] - table = db.cfgdb.get_table("PBH_TABLE") + table = db.cfgdb.get_table(pbh_table_tbl_name) for key in natsort.natsorted(table): entry = table[key] if not isinstance(key, tuple): @@ -339,9 +354,11 @@ def PBH_TABLE(db): click.echo(tabulate.tabulate(body, header, numalign="left")) -@PBH.group(name="statistics", - cls=clicommon.AliasedGroup, - invoke_without_command=True) +@PBH.group( + name="statistics", + cls=clicommon.AliasedGroup, + invoke_without_command=True +) @clicommon.pass_db def PBH_STATISTICS(db): """ Show the PBH counters """ @@ -355,7 +372,7 @@ def PBH_STATISTICS(db): body = [] - pbh_rules = db.cfgdb.get_table("PBH_RULE") + pbh_rules = db.cfgdb.get_table(pbh_rule_tbl_name) pbh_counters = read_pbh_counters(pbh_rules) saved_pbh_counters = read_saved_pbh_counters() @@ -386,9 +403,9 @@ def get_counter_value(pbh_counters, saved_pbh_counters, key, type): return str(pbh_counters[key][type]) -def remap_keys(_list): +def remap_keys(obj_list): res = {} - for e in _list: + for e in obj_list: res[e['key'][0], e['key'][1]] = e['value'] return res From 88992c65b53e06949335557f0c809ad1d5a094ba Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Wed, 14 Jul 2021 12:09:46 +0000 Subject: [PATCH 68/79] Fix for regexp & added --ether-type -> need to fix UT Signed-off-by: Vadym Hlushko --- config/plugins/pbh.py | 25 ++++++++++++++++++++++--- show/plugins/pbh.py | 7 +++++++ tests/pbh_test.py | 2 +- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/config/plugins/pbh.py b/config/plugins/pbh.py index 03ce4ceb5a..eb61550071 100644 --- a/config/plugins/pbh.py +++ b/config/plugins/pbh.py @@ -23,11 +23,12 @@ packet_action_types = ['SET_ECMP_HASH', 'SET_LAG_HASH'] flow_counter_state = ['DISABLED', 'ENABLED'] -gre_key_re = r"(0x){1}[a-fA-F0-9]{1,8}/(0x){1}[a-fA-F0-9]{1,8}" -ip_protocol_re = r"(0x){1}[a-fA-F0-9]{1,2}" +gre_key_re = r"^(0x){1}[a-fA-F0-9]{1,8}/(0x){1}[a-fA-F0-9]{1,8}$" +ip_protocol_re = r"^(0x){1}[a-fA-F0-9]{1,2}$" ipv6_next_header_re = ip_protocol_re -l4_dst_port_re = r"(0x){1}[a-fA-F0-9]{1,4}" +l4_dst_port_re = r"^(0x){1}[a-fA-F0-9]{1,4}$" inner_ether_type_re = l4_dst_port_re +ether_type_re = l4_dst_port_re pbh_hash_field_tbl_name = 'PBH_HASH_FIELD' pbh_hash_tbl_name = 'PBH_HASH' @@ -152,6 +153,8 @@ def pbh_re_match_validator(ctx, param, value): return re_match(value, param.name, l4_dst_port_re) elif param.name == 'inner_ether_type': return re_match(value, param.name, inner_ether_type_re) + elif param.name == 'ether_type': + return re_match(value, param.name, ether_type_re) def is_exist_in_db(db, obj_list, conf_db_key): @@ -514,6 +517,11 @@ def PBH_RULE(): help="Configures packet match: GRE key (value/mask)", callback=pbh_re_match_validator, ) +@click.option( + "--ether-type", + help="Configures packet match for this rule: EtherType (IANA Ethertypes)", + callback=pbh_re_match_validator, +) @click.option( "--ip-protocol", help="Configures packet match: IP protocol (value/mask)", @@ -556,6 +564,7 @@ def PBH_RULE_add( rule_name, priority, gre_key, + ether_type, ip_protocol, ipv6_next_header, l4_dst_port, @@ -578,6 +587,8 @@ def PBH_RULE_add( data["priority"] = priority if gre_key is not None: data["gre_key"] = gre_key + if ether_type is not None: + data["ether_type"] = ether_type if ip_protocol is not None: data["ip_protocol"] = ip_protocol if ipv6_next_header is not None: @@ -620,6 +631,11 @@ def PBH_RULE_add( help="Configures packet match: GRE key (value/mask)", callback=pbh_re_match_validator, ) +@click.option( + "--ether-type", + help="Configures packet match for this rule: EtherType (IANA Ethertypes)", + callback=pbh_re_match_validator, +) @click.option( "--ip-protocol", help="Configures packet match: IP protocol (value/mask)", @@ -661,6 +677,7 @@ def PBH_RULE_update( rule_name, priority, gre_key, + ether_type, ip_protocol, ipv6_next_header, l4_dst_port, @@ -683,6 +700,8 @@ def PBH_RULE_update( data["priority"] = priority if gre_key is not None: data["gre_key"] = gre_key + if ether_type is not None: + data["ether_type"] = ether_type if ip_protocol is not None: data["ip_protocol"] = ip_protocol if ipv6_next_header is not None: diff --git a/show/plugins/pbh.py b/show/plugins/pbh.py index 6ee36e5408..40fda27495 100644 --- a/show/plugins/pbh.py +++ b/show/plugins/pbh.py @@ -235,6 +235,13 @@ def PBH_RULE(db): 'is-mandatory': False, 'group': 'Match' }, + { + 'name': 'ether_type', + 'description': 'Configures packet match for this rule: EtherType (IANA Ethertypes)', + 'is-leaf-list': False, + 'is-mandatory': False, + 'group': 'Match' + }, { 'name': 'ip_protocol', 'description': 'Configures packet match for this rule: IP protocol (value/mask)', diff --git a/tests/pbh_test.py b/tests/pbh_test.py index c873854088..b93dee1097 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -575,7 +575,7 @@ def test_config_pbh_rule_add_delete_nvgre(self): result = runner.invoke(config.config.commands["pbh"]. commands["rule"].commands["add"], ["pbh_table1", "nvgre", "--priority", "1", "--gre-key", - "0x2500/0xffffff00", "--inner-ether-type", "0x86dd/0xffff", + "0x2500/0xffffff00", "--inner-ether-type", "0x86dd", "--hash", "inner_v6_hash", "--packet-action", "SET_ECMP_HASH", "--flow-counter", "DISABLED"], obj=db) From b2bad71217c1a4a8baed15d25dbf8b35e19c5857 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Wed, 14 Jul 2021 12:16:02 +0000 Subject: [PATCH 69/79] Fixed value for pbh regexp in UT Signed-off-by: Vadym Hlushko --- tests/pbh_test.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/pbh_test.py b/tests/pbh_test.py index b93dee1097..7feb1e6a7d 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -601,8 +601,8 @@ def test_config_pbh_rule_add_update_vxlan(self): result = runner.invoke(config.config.commands["pbh"]. commands["rule"].commands["add"], ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", - "0x11/0xff", "--inner-ether-type", "0x0800/0xfff", - "--l4-dst-port", "0x12b5/0xffff", "--hash", "inner_v4_hash", + "0x11", "--inner-ether-type", "0x0800", + "--l4-dst-port", "0x12b5", "--hash", "inner_v4_hash", "--packet-action", "SET_LAG_HASH", "--flow-counter", "ENABLED"], obj=db) logger.debug("\n" + result.output) @@ -611,7 +611,7 @@ def test_config_pbh_rule_add_update_vxlan(self): result = runner.invoke(config.config.commands["pbh"]. commands["rule"].commands["update"], - ["pbh_table1", "vxlan ", "--priority", "3", "--inner-ether-type", "0x086dd/0xfff", + ["pbh_table1", "vxlan ", "--priority", "3", "--inner-ether-type", "0x086d", "--packet-action", "SET_LAG_HASH", "--flow-counter", "DISABLED"], obj=db) logger.debug("\n" + result.output) @@ -629,8 +629,8 @@ def test_config_pbh_rule_update_invalid(self): result = runner.invoke(config.config.commands["pbh"]. commands["rule"].commands["add"], ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", - "0x11/0xff", "--inner-ether-type", "0x0800/0xfff", - "--l4-dst-port", "0x12b5/0xffff", "--hash", "inner_v6_hash", + "0x11", "--inner-ether-type", "0x0800", + "--l4-dst-port", "0x12b5", "--hash", "inner_v6_hash", "--packet-action", "SET_ECMP_HASH", "--flow-counter", "ENABLED"], obj=db) logger.debug("\n" + result.output) @@ -656,8 +656,8 @@ def test_config_pbh_rule_add_invalid_ip_protocol(self): result = runner.invoke(config.config.commands["pbh"]. commands["rule"].commands["add"], ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", - "INVALID", "--inner-ether-type", "0x0800/0xfff", - "--l4-dst-port", "0x12b5/0xffff", "--hash", "inner_v6_hash", + "INVALID", "--inner-ether-type", "0x0800", + "--l4-dst-port", "0x12b5", "--hash", "inner_v6_hash", "--packet-action", "SET_ECMP_HASH", "--flow-counter", "ENABLED"], obj=db) logger.debug("\n" + result.output) @@ -675,8 +675,8 @@ def test_config_pbh_rule_add_invalid_inner_ether_type(self): result = runner.invoke(config.config.commands["pbh"]. commands["rule"].commands["add"], ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", - "0x11/0xff", "--inner-ether-type", "INVALID", - "--l4-dst-port", "0x12b5/0xffff", "--hash", "inner_v6_hash", + "0x11", "--inner-ether-type", "INVALID", + "--l4-dst-port", "0x12b5", "--hash", "inner_v6_hash", "--packet-action", "SET_ECMP_HASH", "--flow-counter", "ENABLED"], obj=db) logger.debug("\n" + result.output) @@ -694,8 +694,8 @@ def test_config_pbh_rule_add_invalid_hash(self): result = runner.invoke(config.config.commands["pbh"]. commands["rule"].commands["add"], ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", - "0x11/0xff", "--inner-ether-type", "0x0800/0xfff", - "--l4-dst-port", "0x12b5/0xffff", "--hash", "INVALID", + "0x11", "--inner-ether-type", "0x0800", + "--l4-dst-port", "0x12b5", "--hash", "INVALID", "--packet-action", "SET_ECMP_HASH", "--flow-counter", "ENABLED"], obj=db) logger.debug("\n" + result.output) @@ -713,8 +713,8 @@ def test_config_pbh_rule_add_invalid_packet_action(self): result = runner.invoke(config.config.commands["pbh"]. commands["rule"].commands["add"], ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", - "0x11/0xff", "--inner-ether-type", "0x0800/0xfff", - "--l4-dst-port", "0x12b5/0xffff", "--hash", "inner_v6_hash", + "0x11", "--inner-ether-type", "0x0800", + "--l4-dst-port", "0x12b5", "--hash", "inner_v6_hash", "--packet-action", "INVALID", "--flow-counter", "ENABLED"], obj=db) logger.debug("\n" + result.output) @@ -732,8 +732,8 @@ def test_config_pbh_rule_add_invalid_flow_counter(self): result = runner.invoke(config.config.commands["pbh"]. commands["rule"].commands["add"], ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", - "0x11/0xff", "--inner-ether-type", "0x0800/0xfff", - "--l4-dst-port", "0x12b5/0xffff", "--hash", "inner_v6_hash", + "0x11", "--inner-ether-type", "0x0800", + "--l4-dst-port", "0x12b5", "--hash", "inner_v6_hash", "--packet-action", "SET_ECMP_HASH", "--flow-counter", "INVALID"], obj=db) logger.debug("\n" + result.output) From c227a73f88f346e948ce3e52c8af843b0e699ef0 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Wed, 14 Jul 2021 12:22:01 +0000 Subject: [PATCH 70/79] Fixed mock db & UT for show cli Signed-off-by: Vadym Hlushko --- tests/pbh_input/assert_show_output.py | 8 ++++---- tests/pbh_input/full_pbh_config.json | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/pbh_input/assert_show_output.py b/tests/pbh_input/assert_show_output.py index fb71a9d09b..73e13b3c8c 100644 --- a/tests/pbh_input/assert_show_output.py +++ b/tests/pbh_input/assert_show_output.py @@ -48,11 +48,11 @@ show_pbh_rule="""\ TABLE RULE PRIORITY MATCH HASH ACTION COUNTER ---------- ------ ---------- ------------------------------------ ------------- ------------- --------- -pbh_table2 vxlan 2 ip_protocol: 0x11/0xff inner_v4_hash SET_LAG_HASH ENABLED - l4_dst_port: 0x12b5/0xffff - inner_ether_type: 0x0800/0xfff +pbh_table2 vxlan 2 ip_protocol: 0x11 inner_v4_hash SET_LAG_HASH ENABLED + l4_dst_port: 0x12b5 + inner_ether_type: 0x0800 pbh_table1 nvgre 1 gre_key: 0x2500/0xffffff00 inner_v6_hash SET_ECMP_HASH DISABLED - inner_ether_type: 0x86dd/0xffff + inner_ether_type: 0x86dd """ diff --git a/tests/pbh_input/full_pbh_config.json b/tests/pbh_input/full_pbh_config.json index 8a098727ba..e9de879c8c 100644 --- a/tests/pbh_input/full_pbh_config.json +++ b/tests/pbh_input/full_pbh_config.json @@ -64,16 +64,16 @@ "PBH_RULE|pbh_table1|nvgre": { "priority": "1", "gre_key": "0x2500/0xffffff00", - "inner_ether_type": "0x86dd/0xffff", + "inner_ether_type": "0x86dd", "hash": "inner_v6_hash", "packet_action": "SET_ECMP_HASH", "flow_counter": "DISABLED" }, "PBH_RULE|pbh_table2|vxlan": { "priority": "2", - "ip_protocol": "0x11/0xff", - "inner_ether_type": "0x0800/0xfff", - "l4_dst_port": "0x12b5/0xffff", + "ip_protocol": "0x11", + "inner_ether_type": "0x0800", + "l4_dst_port": "0x12b5", "hash": "inner_v4_hash", "packet_action": "SET_LAG_HASH", "flow_counter": "ENABLED" From e7970a817cd633a3788fd328a94d43bc376196df Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Wed, 14 Jul 2021 16:39:04 +0000 Subject: [PATCH 71/79] Rework of inject_symmetric_field() Signed-off-by: Vadym Hlushko --- show/plugins/pbh.py | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/show/plugins/pbh.py b/show/plugins/pbh.py index 40fda27495..7b6427440f 100644 --- a/show/plugins/pbh.py +++ b/show/plugins/pbh.py @@ -90,8 +90,6 @@ def PBH_HASH_FIELD(db): table = db.cfgdb.get_table(pbh_hash_field_tbl_name) for key in natsort.natsorted(table): - is_pbh_hash_field_symmetric(table, key) - entry = table[key] if not isinstance(key, tuple): @@ -128,22 +126,13 @@ def PBH_HASH_FIELD(db): 'group': '' } ), - format_attr_value( - entry, - { - 'name': 'symmetric', - 'description': 'symmetric', - 'is-leaf-list': False, - 'is-mandatory': False, - 'group': '' - } - ), ] body.append(row) # sorted by 'sequence_id' body_sorted = sorted(body, key=lambda e: int(e[3])) + inject_symmetric_field(body_sorted) click.echo(tabulate.tabulate(body_sorted, header, numalign="left")) @@ -443,27 +432,32 @@ def read_pbh_counters(pbh_rules) -> dict: return pbh_counters -def is_pbh_hash_field_symmetric(table: dict, key_to_check: str): +def inject_symmetric_field(obj_list): """ The 'Symmetric' parameter will have 'Yes' value if there are 2 'pbh hash fields' with identical 'sequence_id' value Args: - table: 'PBH_HASH_FIELD' table from CONFIG DB. - key_to_check: key from the table above to check + obj_list: a row of pbh hash fields that will be + displayed to the user """ - if table[key_to_check].get('symmetric') is None: - counter = 0 + sequence_id = 3 + counter = 0 - for key in table: - if key_to_check != key: - if table[key_to_check].get('sequence_id') == table[key].get('sequence_id'): - counter += 1 + for i in range(0, len(obj_list)): + for j in range(0, len(obj_list)): + if i == j: + continue + + if obj_list[i][sequence_id] == obj_list[j][sequence_id]: + counter += 1 if counter >= 1: - table[key_to_check]['symmetric'] = 'Yes' + obj_list[i].append('Yes') else: - table[key_to_check]['symmetric'] = 'No' + obj_list[i].append('No') + + counter = 0 def lowercase_keys(dictionary): From 7f208b2f4dfa369ff73bc409ee1cfd53cbbcaf53 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Thu, 15 Jul 2021 05:18:19 +0000 Subject: [PATCH 72/79] Added check for --flow-counter when displaing pbh statistics Signed-off-by: Vadym Hlushko --- show/plugins/pbh.py | 18 ++++++++---------- tests/pbh_input/assert_show_output.py | 10 +++++++++- tests/pbh_input/full_pbh_config.json | 2 +- tests/pbh_test.py | 2 +- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/show/plugins/pbh.py b/show/plugins/pbh.py index 7b6427440f..0a1807cc73 100644 --- a/show/plugins/pbh.py +++ b/show/plugins/pbh.py @@ -373,16 +373,14 @@ def PBH_STATISTICS(db): saved_pbh_counters = read_saved_pbh_counters() for key in pbh_rules: - # if counters value 0 or not exists should we display it? - if get_counter_value(pbh_counters, saved_pbh_counters, key, 'packets') == '0': - continue - row = [ - key[0], - key[1], - get_counter_value(pbh_counters, saved_pbh_counters, key, 'packets'), - get_counter_value(pbh_counters, saved_pbh_counters, key, 'bytes'), - ] - body.append(row) + if pbh_rules[key]['flow_counter'] == 'ENABLED': + row = [ + key[0], + key[1], + get_counter_value(pbh_counters, saved_pbh_counters, key, 'packets'), + get_counter_value(pbh_counters, saved_pbh_counters, key, 'bytes'), + ] + body.append(row) click.echo(tabulate.tabulate(body, header, numalign="left")) diff --git a/tests/pbh_input/assert_show_output.py b/tests/pbh_input/assert_show_output.py index 73e13b3c8c..09bb2bfecc 100644 --- a/tests/pbh_input/assert_show_output.py +++ b/tests/pbh_input/assert_show_output.py @@ -51,7 +51,7 @@ pbh_table2 vxlan 2 ip_protocol: 0x11 inner_v4_hash SET_LAG_HASH ENABLED l4_dst_port: 0x12b5 inner_ether_type: 0x0800 -pbh_table1 nvgre 1 gre_key: 0x2500/0xffffff00 inner_v6_hash SET_ECMP_HASH DISABLED +pbh_table1 nvgre 1 gre_key: 0x2500/0xffffff00 inner_v6_hash SET_ECMP_HASH ENABLED inner_ether_type: 0x86dd """ @@ -62,6 +62,14 @@ """ +show_pbh_statistics_zero="""\ +TABLE RULE RX PACKETS COUNT RX BYTES COUNT +---------- ------ ------------------ ---------------- +pbh_table1 nvgre 0 0 +pbh_table2 vxlan 0 0 +""" + + show_pbh_statistics="""\ TABLE RULE RX PACKETS COUNT RX BYTES COUNT ---------- ------ ------------------ ---------------- diff --git a/tests/pbh_input/full_pbh_config.json b/tests/pbh_input/full_pbh_config.json index e9de879c8c..0052ad1854 100644 --- a/tests/pbh_input/full_pbh_config.json +++ b/tests/pbh_input/full_pbh_config.json @@ -67,7 +67,7 @@ "inner_ether_type": "0x86dd", "hash": "inner_v6_hash", "packet_action": "SET_ECMP_HASH", - "flow_counter": "DISABLED" + "flow_counter": "ENABLED" }, "PBH_RULE|pbh_table2|vxlan": { "priority": "2", diff --git a/tests/pbh_test.py b/tests/pbh_test.py index 7feb1e6a7d..4c2e75223d 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -889,7 +889,7 @@ def test_show_pbh_statistics_after_clear(self): logger.debug(result.exit_code) assert result.exit_code == SUCCESS - assert result.output == assert_show_output.show_pbh_statistics_empty + assert result.output == assert_show_output.show_pbh_statistics_zero self.clear_dedicated_mock_dbs() From dd35eec123f49c1cbe13a2e2467ace3c341d4b7b Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Thu, 15 Jul 2021 06:55:06 +0000 Subject: [PATCH 73/79] Added new UT for pbh statistics Signed-off-by: Vadym Hlushko --- show/plugins/pbh.py | 1 - tests/pbh_input/assert_show_output.py | 6 +++++ tests/pbh_test.py | 36 +++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/show/plugins/pbh.py b/show/plugins/pbh.py index 0a1807cc73..a8957482d5 100644 --- a/show/plugins/pbh.py +++ b/show/plugins/pbh.py @@ -406,7 +406,6 @@ def remap_keys(obj_list): def read_saved_pbh_counters(): if os.path.isfile(PBH_COUNTERS_LOCATION): - # change approach maybe add if try: with open(PBH_COUNTERS_LOCATION) as fp: return remap_keys(json.load(fp)) diff --git a/tests/pbh_input/assert_show_output.py b/tests/pbh_input/assert_show_output.py index 09bb2bfecc..5b67403a17 100644 --- a/tests/pbh_input/assert_show_output.py +++ b/tests/pbh_input/assert_show_output.py @@ -84,3 +84,9 @@ pbh_table2 vxlan 400 400 """ +show_pbh_statistics_after_disabling_rule="""\ +TABLE RULE RX PACKETS COUNT RX BYTES COUNT +---------- ------ ------------------ ---------------- +pbh_table1 nvgre 0 0 +""" + diff --git a/tests/pbh_test.py b/tests/pbh_test.py index 4c2e75223d..0b1bb94078 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -925,3 +925,39 @@ def test_show_pbh_statistics_after_clear_and_counters_updated(self): assert result.output == assert_show_output.show_pbh_statistics_updated self.clear_dedicated_mock_dbs() + + + def test_show_pbh_statistics_after_disabling_rule(self): + dbconnector.dedicated_dbs['COUNTERS_DB'] = os.path.join(mock_db_path, 'counters_db') + dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'full_pbh_config') + + SAVED_PBH_COUNTERS_FILE = '/tmp/.pbh_counters.txt' + if os.path.isfile(SAVED_PBH_COUNTERS_FILE): + os.remove(SAVED_PBH_COUNTERS_FILE) + + db = Db() + runner = CliRunner() + + result = runner.invoke(show.cli.commands["pbh"]. + commands["statistics"], [], obj=db) + logger.debug("\n" + result.output) + logger.debug(result.exit_code) + + result = runner.invoke(clear.cli.commands["pbh"], [], obj=db) + logger.debug("\n" + result.output) + logger.debug(result.exit_code) + + result = runner.invoke(config.config.commands["pbh"]. + commands["rule"].commands["update"], ["pbh_table2", "vxlan", "--flow-counter", "DISABLED"], obj=db) + logger.debug("\n" + result.output) + logger.debug(result.exit_code) + + result = runner.invoke(show.cli.commands["pbh"]. + commands["statistics"], [], obj=db) + logger.debug("\n" + result.output) + logger.debug(result.exit_code) + + assert result.exit_code == SUCCESS + assert result.output == assert_show_output.show_pbh_statistics_after_disabling_rule + + self.clear_dedicated_mock_dbs() From 438cea69f807e5f61efe5211b36421690f88022a Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Thu, 15 Jul 2021 07:05:58 +0000 Subject: [PATCH 74/79] Added check for read pbh counters Signed-off-by: Vadym Hlushko --- show/plugins/pbh.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/show/plugins/pbh.py b/show/plugins/pbh.py index a8957482d5..d7cd929e02 100644 --- a/show/plugins/pbh.py +++ b/show/plugins/pbh.py @@ -421,10 +421,10 @@ def read_pbh_counters(pbh_rules) -> dict: db_connector = SonicV2Connector(use_unix_socket_path=False) db_connector.connect(db_connector.COUNTERS_DB) - # add some check for table, rule in natsort.natsorted(pbh_rules): counter_props = lowercase_keys(db_connector.get_all(db_connector.COUNTERS_DB, "COUNTERS:%s:%s" % (table, rule))) - pbh_counters[table, rule] = counter_props + if counter_props: + pbh_counters[table, rule] = counter_props return pbh_counters From ef680de2aba527e572bc74e49851c5c7dd38844f Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Thu, 15 Jul 2021 07:14:48 +0000 Subject: [PATCH 75/79] Reworked sonic-clear cli group for pbh Signed-off-by: Vadym Hlushko --- clear/main.py | 19 ++++++++++--------- tests/pbh_test.py | 6 +++--- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/clear/main.py b/clear/main.py index 25991678d0..8f93597b68 100755 --- a/clear/main.py +++ b/clear/main.py @@ -450,17 +450,16 @@ def translations(): cmd = "natclear -t" run_command(cmd) +# 'pbh' group ("clear pbh ...") +@cli.group(cls=AliasedGroup) +def pbh(): + """ Clear the PBH info """ + pass -def remap_keys(dict): - return [{'key': k, 'value': v} for k, v in dict.items()] - - -# -# 'pbh' subcommand -# -@cli.command() +# 'statistics' subcommand ("clear pbh statistics") +@pbh.command() @clicommon.pass_db -def pbh(db): +def statistics(db): """ Clear PBH counters clear counters -- write current counters to file in /tmp """ @@ -474,6 +473,8 @@ def pbh(db): except IOError as err: pass +def remap_keys(dict): + return [{'key': k, 'value': v} for k, v in dict.items()] # Load plugins and register them helper = util_base.UtilHelper() diff --git a/tests/pbh_test.py b/tests/pbh_test.py index 0b1bb94078..4e7d2b37c5 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -879,7 +879,7 @@ def test_show_pbh_statistics_after_clear(self): logger.debug("\n" + result.output) logger.debug(result.exit_code) - result = runner.invoke(clear.cli.commands["pbh"], [], obj=db) + result = runner.invoke(clear.cli.commands["pbh"].commands["statistics"], [], obj=db) logger.debug("\n" + result.output) logger.debug(result.exit_code) @@ -910,7 +910,7 @@ def test_show_pbh_statistics_after_clear_and_counters_updated(self): logger.debug("\n" + result.output) logger.debug(result.exit_code) - result = runner.invoke(clear.cli.commands["pbh"], [], obj=db) + result = runner.invoke(clear.cli.commands["pbh"].commands["statistics"], [], obj=db) logger.debug("\n" + result.output) logger.debug(result.exit_code) @@ -943,7 +943,7 @@ def test_show_pbh_statistics_after_disabling_rule(self): logger.debug("\n" + result.output) logger.debug(result.exit_code) - result = runner.invoke(clear.cli.commands["pbh"], [], obj=db) + result = runner.invoke(clear.cli.commands["pbh"].commands["statistics"], [], obj=db) logger.debug("\n" + result.output) logger.debug(result.exit_code) From 9471b11e853a2c23fa4ae2c25e6b2f249143ce3c Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Thu, 15 Jul 2021 07:33:14 +0000 Subject: [PATCH 76/79] Fixed help messages for config cli according to the new YANG model Signed-off-by: Vadym Hlushko --- config/plugins/pbh.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/config/plugins/pbh.py b/config/plugins/pbh.py index eb61550071..3f6dd100a0 100644 --- a/config/plugins/pbh.py +++ b/config/plugins/pbh.py @@ -305,7 +305,7 @@ def PBH_HASH_FIELD(): ) @click.option( "--ip-mask", - help="""Configures IPv4/IPv6 address mask for this hash field required when the value of --hash-field are - INNER_DST_IPV4 or + help="""Configures IPv4/IPv6 address mask for this hash field, required when the value of --hash-field are - INNER_DST_IPV4 or INNER_SRC_IPV4 or INNER_SRC_IPV4 or INNER_SRC_IPV4 """, callback=ip_address_validator, ) @@ -524,22 +524,22 @@ def PBH_RULE(): ) @click.option( "--ip-protocol", - help="Configures packet match: IP protocol (value/mask)", + help="Configures packet match for this rule: IP protocol (IANA Protocol Numbers)", callback=pbh_re_match_validator, ) @click.option( "--ipv6-next-header", - help="Configures packet match: IPv6 Next header (value/mask)", + help="Configures packet match for this rule: IPv6 Next header (IANA Protocol Numbers)", callback=pbh_re_match_validator, ) @click.option( "--l4-dst-port", - help="Configures packet match: L4 destination port (value/mask)", + help="Configures packet match for this rule: L4 destination port", callback=pbh_re_match_validator, ) @click.option( "--inner-ether-type", - help="Configures packet match: inner EtherType (value/mask)", + help="Configures packet match for this rule: inner EtherType (IANA Ethertypes)", callback=pbh_re_match_validator, ) @click.option( @@ -638,22 +638,22 @@ def PBH_RULE_add( ) @click.option( "--ip-protocol", - help="Configures packet match: IP protocol (value/mask)", + help="Configures packet match for this rule: IP protocol (IANA Protocol Numbers)", callback=pbh_re_match_validator, ) @click.option( "--ipv6-next-header", - help="Configures packet match: IPv6 Next header (value/mask)", + help="Configures packet match for this rule: IPv6 Next header (IANA Protocol Numbers)", callback=pbh_re_match_validator, ) @click.option( "--l4-dst-port", - help="Configures packet match: L4 destination port (value/mask)", + help="Configures packet match for this rule: L4 destination port", callback=pbh_re_match_validator, ) @click.option( "--inner-ether-type", - help="Configures packet match: inner EtherType (value/mask)", + help="Configures packet match for this rule: inner EtherType (IANA Ethertypes)", callback=pbh_re_match_validator, ) @click.option( From 0d286901b42ee6ea9345ab6d4db312014a3eec13 Mon Sep 17 00:00:00 2001 From: Nazarii Hnydyn Date: Mon, 5 Jul 2021 16:44:33 +0000 Subject: [PATCH 77/79] [pbh]: Add CLI UM. Signed-off-by: Nazarii Hnydyn --- doc/Command-Reference.md | 300 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 300 insertions(+) diff --git a/doc/Command-Reference.md b/doc/Command-Reference.md index 6615413255..c944039827 100644 --- a/doc/Command-Reference.md +++ b/doc/Command-Reference.md @@ -97,6 +97,9 @@ * [NTP](#ntp) * [NTP show commands](#ntp-show-commands) * [NTP config commands](#ntp-config-commands) +* [PBH](#pbh) + * [PBH show commands](#pbh-show-commands) + * [PBH config commands](#pbh-config-commands) * [PFC Watchdog Commands](#pfc-watchdog-commands) * [Platform Component Firmware](#platform-component-firmware) * [Platform Component Firmware show commands](#platform-component-firmware-show-commands) @@ -5945,6 +5948,303 @@ This command adds or deletes a member port to/from the already created portchann Go Back To [Beginning of the document](#) or [Beginning of this section](#portchannels) +## PBH + +This section explains the various show commands and configuration commands available for users. + +### PBH show commands + +This subsection explains how to display PBH configuration and statistics. + +**show pbh table** + +This command displays PBH table configuration. + +- Usage: +```bash +show pbh table +``` + +- Example: +```bash +admin@sonic:~$ show pbh table +NAME INTERFACE DESCRIPTION +--------- --------------- --------------- +pbh_table Ethernet0 NVGRE and VxLAN + Ethernet4 + PortChannel0001 + PortChannel0002 +``` + +**show pbh rule** + +This command displays PBH rule configuration. + +- Usage: +```bash +show pbh rule +``` + +- Example: +```bash +admin@sonic:~$ show pbh rule +TABLE RULE PRIORITY MATCH HASH ACTION COUNTER +--------- ------ ---------- ------------------------------------ ------------- ------------- --------- +pbh_table nvgre 2 ether_type: 0x0800 inner_v6_hash SET_ECMP_HASH DISABLED + ip_protocol: 0x2f + gre_key: 0x2500/0xffffff00 + inner_ether_type: 0x86dd +pbh_table vxlan 1 ether_type: 0x0800 inner_v4_hash SET_LAG_HASH ENABLED + ip_protocol: 0x11 + l4_dst_port: 0x12b5 + inner_ether_type: 0x0800 +``` + +**show pbh hash** + +This command displays PBH hash configuration. + +- Usage: +```bash +show pbh hash +``` + +- Example: +```bash +admin@sonic:~$ show pbh hash +NAME HASH FIELD +------------- ----------------- +inner_v4_hash inner_ip_proto + inner_l4_dst_port + inner_l4_src_port + inner_dst_ipv4 + inner_src_ipv4 +inner_v6_hash inner_ip_proto + inner_l4_dst_port + inner_l4_src_port + inner_dst_ipv6 + inner_src_ipv6 +``` + +**show pbh hash-field** + +This command displays PBH hash field configuration. + +- Usage: +```bash +show pbh hash-field +``` + +- Example: +```bash +admin@sonic:~$ show pbh hash-field +NAME FIELD MASK SEQUENCE SYMMETRIC +----------------- ----------------- --------- ---------- ----------- +inner_ip_proto INNER_IP_PROTOCOL N/A 1 No +inner_l4_dst_port INNER_L4_DST_PORT N/A 2 Yes +inner_l4_src_port INNER_L4_SRC_PORT N/A 2 Yes +inner_dst_ipv4 INNER_DST_IPV4 255.0.0.0 3 Yes +inner_src_ipv4 INNER_SRC_IPV4 0.0.0.255 3 Yes +inner_dst_ipv6 INNER_DST_IPV6 ffff:: 4 Yes +inner_src_ipv6 INNER_SRC_IPV6 ::ffff 4 Yes +``` + +- Note: + - _SYMMETRIC_ is an artificial column and is only used to indicate fields symmetry + +**show pbh statistics** + +This command displays PBH statistics. + +- Usage: +```bash +show pbh statistics +``` + +- Example: +```bash +admin@sonic:~$ show pbh statistics +TABLE RULE RX PACKETS COUNT RX BYTES COUNT +--------- ------ ------------------ ---------------- +pbh_table nvgre 0 0 +pbh_table vxlan 0 0 +``` + +- Note: + - _RX PACKETS COUNT_ and _RX BYTES COUNT_ can be cleared by user: + ```bash + admin@sonic:~$ sonic-clear pbh statistics + ``` + +### PBH config commands + +This subsection explains how to configure PBH. + +**config pbh table** + +This command is used to manage PBH table objects. +It supports add/update/remove operations. + +- Usage: +```bash +config pbh table add --interface-list --description +config pbh table update [ --interface-list ] [ --description ] +config pbh table delete +``` + +- Parameters: + - _table_name_: the name of the PBH table + - _interface_list_: interfaces to which PBH table is applied + - _description_: the description of the PBH table + +- Examples: +```bash +config pbh table add 'pbh_table' \ +--interface-list 'Ethernet0,Ethernet4,PortChannel0001,PortChannel0002' \ +--description 'NVGRE and VxLAN' +config pbh table update 'pbh_table' \ +--interface-list 'Ethernet0' +config pbh table delete 'pbh_table' +``` + +**config pbh rule** + +This command is used to manage PBH rule objects. +It supports add/update/remove operations. + +- Usage: +```bash +config pbh rule add --priority \ +[ --gre-key ] [ --ether-type ] [ --ip-protocol ] \ +[ --ipv6-next-header ] [ --l4-dst-port ] [ --inner-ether-type ] \ +--hash [ --packet-action ] [ --flow-counter ] +config pbh rule update [ --priority ] \ +[ --gre-key ] [ --ether-type ] [ --ip-protocol ] \ +[ --ipv6-next-header ] [ --l4-dst-port ] [ --inner-ether-type ] \ +[ --hash ] [ --packet-action ] [ --flow-counter ] +config pbh rule delete +``` + +- Parameters: + - _table_name_: the name of the PBH table + - _rule_name_: the name of the PBH rule + - _priority_: the priority of the PBH rule + - _gre_key_: packet match for the PBH rule: GRE key (value/mask) + - _ether_type_: packet match for the PBH rule: EtherType (IANA Ethertypes) + - _ip_protocol_: packet match for the PBH rule: IP protocol (IANA Protocol Numbers) + - _ipv6_next_header_: packet match for the PBH rule: IPv6 Next header (IANA Protocol Numbers) + - _l4_dst_port_: packet match for the PBH rule: L4 destination port + - _inner_ether_type_: packet match for the PBH rule: inner EtherType (IANA Ethertypes) + - _hash_: _hash_ object to apply with the PBH rule + - _packet_action_: packet action for the PBH rule + + Valid values: + - SET_ECMP_HASH + - SET_LAG_HASH + + Default: + - SET_ECMP_HASH + + - _flow_counter_: packet/byte counter for the PBH rule + + Valid values: + - DISABLED + - ENABLED + + Default: + - DISABLED + +- Examples: +```bash +config pbh rule add 'pbh_table' 'nvgre' \ +--priority '2' \ +--ether-type '0x0800' \ +--ip-protocol '0x2f' \ +--gre-key '0x2500/0xffffff00' \ +--inner-ether-type '0x86dd' \ +--hash 'inner_v6_hash' \ +--packet-action 'SET_ECMP_HASH' \ +--flow-counter 'DISABLED' +config pbh rule update 'pbh_table' 'nvgre' \ +--flow-counter 'ENABLED' +config pbh rule delete 'pbh_table' 'nvgre' +``` + +**config pbh hash** + +This command is used to manage PBH hash objects. +It supports add/update/remove operations. + +- Usage: +```bash +config pbh hash add --hash-field-list +config pbh hash update [ --hash-field-list ] +config pbh hash delete +``` + +- Parameters: + - _hash_name_: the name of the PBH hash + - _hash_field_list_: list of _hash-field_ objects to apply with the PBH hash + +- Examples: +```bash +config pbh hash add 'inner_v6_hash' \ +--hash-field-list 'inner_ip_proto,inner_l4_dst_port,inner_l4_src_port,inner_dst_ipv6,inner_src_ipv6' +config pbh hash update 'inner_v6_hash' \ +--hash-field-list 'inner_ip_proto' +config pbh hash delete 'inner_v6_hash' +``` + +**config pbh hash-field** + +This command is used to manage PBH hash field objects. +It supports add/update/remove operations. + +- Usage: +```bash +config pbh hash-field add \ +--hash-field [ --ip-mask ] --sequence-id +config pbh hash-field update \ +[ --hash-field ] [ --ip-mask ] [ --sequence-id ] +config pbh hash-field delete +``` + +- Parameters: + - _hash_field_name_: the name of the PBH hash field + - _hash_field_: native hash field for the PBH hash field + + Valid values: + - INNER_IP_PROTOCOL + - INNER_L4_DST_PORT + - INNER_L4_SRC_PORT + - INNER_DST_IPV4 + - INNER_SRC_IPV4 + - INNER_DST_IPV6 + - INNER_SRC_IPV6 + + - _ip_mask_: IPv4/IPv6 address mask for the PBH hash field + + Valid only: _hash_field_ is: + - INNER_DST_IPV4 + - INNER_SRC_IPV4 + - INNER_DST_IPV6 + - INNER_SRC_IPV6 + + - _sequence_id_: the order in which fields are hashed + +- Examples: +```bash +config pbh hash-field add 'inner_dst_ipv6' \ +--hash-field 'INNER_DST_IPV6' \ +--ip-mask 'ffff::' \ +--sequence-id '4' +config pbh hash-field update 'inner_dst_ipv6' \ +--ip-mask 'ffff:ffff::' +config pbh hash-field delete 'inner_dst_ipv6' +``` + +Go Back To [Beginning of the document](#) or [Beginning of this section](#pbh) + ## QoS ### QoS Show commands From a4709f8341659c7ed7aed20b6b4991127946db1e Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Thu, 15 Jul 2021 15:47:59 +0000 Subject: [PATCH 78/79] Reworked clear after of mocked DB for UT, codestyle, changes some UT to parametrized Signed-off-by: Vadym Hlushko --- tests/pbh_test.py | 780 ++++++++++++++++++++++------------------------ 1 file changed, 378 insertions(+), 402 deletions(-) diff --git a/tests/pbh_test.py b/tests/pbh_test.py index 4e7d2b37c5..bc4c74db73 100644 --- a/tests/pbh_test.py +++ b/tests/pbh_test.py @@ -1,5 +1,6 @@ #!/usr/bin/env python +import pytest import os import logging import show.main as show @@ -21,6 +22,8 @@ ERROR = 1 ERROR2 = 2 +INVALID_VALUE = 'INVALID' + class TestPBH: @classmethod @@ -33,10 +36,6 @@ def teardown_class(cls): logger.info("TEARDOWN") os.environ['UTILITIES_UNIT_TESTING'] = "0" os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "" - importlib.reload(mock_single_asic) - dbconnector.load_namespace_config() - - def clear_dedicated_mock_dbs(self): dbconnector.dedicated_dbs['CONFIG_DB'] = None dbconnector.dedicated_dbs['COUNTERS_DB'] = None @@ -48,33 +47,45 @@ def test_config_pbh_hash_field_add_delete_no_ip_mask(self): db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["add"], - ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", - "--sequence-id", "1"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["hash-field"]. + commands["add"], ["inner_ip_proto", "--hash-field", + "INNER_IP_PROTOCOL", "--sequence-id", "1"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["delete"], - ["inner_ip_proto"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["hash-field"]. + commands["delete"], ["inner_ip_proto"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - def test_config_pbh_hash_field_add_ip4_mask(self): + @pytest.mark.parametrize("hash_field_name,hash_field,ip_mask", [ + ("inner_dst_ipv6", "INNER_DST_IPV6", "ffff::"), + ("inner_dst_ipv4", "INNER_DST_IPV4", "255.0.0.0") + ]) + def test_config_pbh_hash_field_add_ip_mask( + self, + hash_field_name, + hash_field, + ip_mask, + ): db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["add"], - ["inner_dst_ipv4", "--hash-field", "INNER_DST_IPV4", - "--ip-mask", "255.0.0.0", - "--sequence-id", "3"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["hash-field"]. + commands["add"], [hash_field_name, "--hash-field", + hash_field, "--ip-mask", ip_mask, + "--sequence-id", "3"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) @@ -82,263 +93,223 @@ def test_config_pbh_hash_field_add_ip4_mask(self): assert result.exit_code == SUCCESS - def test_config_pbh_hash_field_add_ip6_mask(self): + @pytest.mark.parametrize("hash_field_name,hash_field,ip_mask", [ + ("inner_ip_protocol", "INNER_IP_PROTOCOL", "255.0.0.0"), + ("inner_src_ipv6", "INNER_SRC_IPV6", "255.0.0.0"), + ("inner_src_ipv4", "INNER_SRC_IPV4", "ffff::") + ]) + def test_config_pbh_hash_field_add_mismatch_hash_field_ip_mask( + self, + hash_field_name, + hash_field, + ip_mask, + ): db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["add"], - ["inner_dst_ipv6", "--hash-field", "INNER_DST_IPV6", - "--ip-mask", "ffff::", - "--sequence-id", "4"], obj=db) - - logger.debug("\n" + result.output) - logger.debug(result.exit_code) - assert result.exit_code == SUCCESS - - - # negative add: --hash-field & --ip-mask mismatch - def test_config_pbh_hash_field_add_hash_field_with_ip(self): - db = Db() - runner = CliRunner() - - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["add"], - ["inner_ip_protocol", "--hash-field", "INNER_IP_PROTOCOL", - "--ip-mask", "255.0.0.0", - "--sequence-id", "1"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["hash-field"]. + commands["add"], [hash_field_name, "--hash-field", + hash_field, "--ip-mask", ip_mask, + "--sequence-id", "1"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR - # negative add: --hash-field v6 & --ip-mask v4 mismatch - def test_config_pbh_hash_field_add_ipv4_mismatch(self): - db = Db() - runner = CliRunner() - - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["add"], - ["inner_src_ipv6", "--hash-field", "INNER_SRC_IPV6", - "--ip-mask", "255.0.0.0", - "--sequence-id", "4"], obj=db) - - logger.debug("\n" + result.output) - logger.debug(result.exit_code) - assert result.exit_code == ERROR - - - # negative add: --hash-field v4 & --ip-mask v6 mismatch - def test_config_pbh_hash_field_add_ipv6_mismatch(self): - db = Db() - runner = CliRunner() - - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["add"], - ["inner_src_ipv4", "--hash-field", "INNER_SRC_IPV4", - "--ip-mask", "ffff::", - "--sequence-id", "2"], obj=db) - - logger.debug("\n" + result.output) - logger.debug(result.exit_code) - assert result.exit_code == ERROR - - # negative add: invalid --ip-mask def test_config_pbh_hash_field_add_invalid_ip(self): db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["add"], - ["inner_src_ipv4", "--hash-field", "INNER_SRC_IPV4", - "--ip-mask", "WRONG", - "--sequence-id", "2"], obj=db) - - logger.debug("\n" + result.output) - logger.debug(result.exit_code) - assert result.exit_code == ERROR - - - # negative add: None --ip-mask - def test_config_pbh_hash_field_add_none_ipv4(self): - db = Db() - runner = CliRunner() - - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["add"], - ["inner_src_ipv4", "--hash-field", "INNER_SRC_IPV4", - "--sequence-id", "2"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["hash-field"]. + commands["add"], ["inner_src_ipv4", "--hash-field", + "INNER_SRC_IPV4", "--ip-mask", INVALID_VALUE, + "--sequence-id", "2"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR - # negative add: None --ip-mask - def test_config_pbh_hash_field_add_none_ipv6(self): + @pytest.mark.parametrize("hash_field_name,hash_field", [ + ("inner_src_ipv6", "INNER_SRC_IPV6"), + ("inner_src_ipv4", "INNER_SRC_IPV4") + ]) + def test_config_pbh_hash_field_add_none_ip_mask( + self, + hash_field_name, + hash_field, + ): db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["add"], - ["inner_src_ipv6", "--hash-field", "INNER_SRC_IPV6", - "--sequence-id", "2"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["hash-field"]. + commands["add"], [hash_field_name, "--hash-field", + hash_field, "--sequence-id", "2"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR - def test_config_pbh_hash_field_update_sequence_id(self): + @pytest.mark.parametrize("hash_field_name,hash_field,updated_hash_field,sequence_id", [ + ("inner_ip_proto", "INNER_IP_PROTOCOL", "INNER_L4_DST_PORT", "1"), + ("inner_l4_src_port", "INNER_L4_SRC_PORT", "INNER_L4_DST_PORT", "2") + ]) + def test_config_pbh_hash_field_update_hash_field_sequence_id_no_ip( + self, + hash_field_name, + hash_field, + updated_hash_field, + sequence_id + ): db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["add"], - ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", - "--sequence-id", "1"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["hash-field"]. + commands["add"],[hash_field_name, "--hash-field", + hash_field, "--sequence-id", "1"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["update"], - ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", - "--sequence-id", "2"], obj=db) - assert result.exit_code == SUCCESS - - - def test_config_pbh_hash_field_update_hash_field(self): - db = Db() - runner = CliRunner() - - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["add"], - ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", - "--sequence-id", "1"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["hash-field"]. + commands["update"],[hash_field_name, "--hash-field", + updated_hash_field, "--sequence-id", sequence_id], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["update"], - ["inner_ip_proto", "--hash-field", "INNER_L4_DST_PORT", - "--sequence-id", "2"], obj=db) - logger.debug("\n" + result.output) - logger.debug(result.exit_code) - assert result.exit_code == SUCCESS - - - def test_config_pbh_hash_field_update_hash_field_ip_mask(self): + @pytest.mark.parametrize("hash_field_name,hash_field,updated_hash_field,ip_mask,updated_ip_mask", [ + ("inner_dst_ipv4", "INNER_DST_IPV4", "INNER_SRC_IPV4", "255.0.0.0", "0.0.0.255"), + ("inner_dst_ipv6", "INNER_DST_IPV6", "INNER_SRC_IPV6", "ffff::", "::ffff"), + ]) + def test_config_pbh_hash_field_update_hash_field_ip_mask( + self, + hash_field_name, + hash_field, + updated_hash_field, + ip_mask, + updated_ip_mask + ): db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["add"], - ["inner_dst_ipv4", "--hash-field", "INNER_DST_IPV4", - "--ip-mask", "255.0.0.0", "--sequence-id", "1"], obj=db) - - logger.debug("\n" + result.output) - logger.debug(result.exit_code) - assert result.exit_code == SUCCESS - - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["update"], - ["inner_dst_ipv4", "--hash-field", "INNER_SRC_IPV4", - "--ip-mask", "0.0.0.255", "--sequence-id", "2"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["hash-field"]. + commands["add"], [hash_field_name, "--hash-field", + hash_field, "--ip-mask", ip_mask, + "--sequence-id", "1"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - - def test_config_pbh_hash_field_update_wrong_hash_field(self): - db = Db() - runner = CliRunner() - - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["add"], - ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", - "--sequence-id", "1"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["hash-field"]. + commands["update"], [hash_field_name, "--hash-field", + updated_hash_field, "--ip-mask", updated_ip_mask], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["update"], - ["inner_ip_proto", "--hash-field", "INNER_DST_IPV4", - "--sequence-id", "2"], obj=db) - - logger.debug("\n" + result.output) - logger.debug(result.exit_code) - assert result.exit_code == ERROR - - def test_config_pbh_hash_field_update_wrong_ipv4_mask1(self): + def test_config_pbh_hash_field_update_invalid_hash_field(self): db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["add"], - ["inner_ip_proto", "--hash-field", "INNER_IP_PROTOCOL", - "--sequence-id", "1"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["hash-field"]. + commands["add"], ["inner_ip_proto", "--hash-field", + "INNER_IP_PROTOCOL", "--sequence-id", "1"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["update"], - ["inner_ip_proto", "--ip-mask", "0.0.0.255"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["hash-field"]. + commands["update"], ["inner_ip_proto", "--hash-field", + "INNER_DST_IPV4", "--sequence-id", "2"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR - def test_config_pbh_hash_field_update_wrong_ipv6_mask(self): + def test_config_pbh_hash_field_update_invalid_ipv4_mask(self): db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["add"], - ["inner_dst_ipv6", "--hash-field", "INNER_DST_IPV6", - "--ip-mask", "ffff::", "--sequence-id", "3"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["hash-field"]. + commands["add"],["inner_ip_proto", "--hash-field", + "INNER_IP_PROTOCOL", "--sequence-id", "1"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["update"], - ["inner_dst_ipv6", "--ip-mask", "255.0.0.0", "--sequence-id", "2"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["hash-field"]. + commands["update"], ["inner_ip_proto", "--ip-mask", + "0.0.0.255"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR - def test_config_pbh_hash_field_update_wrong_ipv4_mask2(self): + @pytest.mark.parametrize("hash_field_name,hash_field,ip_mask,updated_ip_mask", [ + ("inner_dst_ipv6", "INNER_DST_IPV6", "ffff::", "255.0.0.0"), + ("inner_dst_ipv4", "INNER_DST_IPV4", "255.0.0.0", "ffff::") + ]) + def test_config_pbh_hash_field_update_invalid_ip_mask( + self, + hash_field_name, + hash_field, + ip_mask, + updated_ip_mask + ): db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["add"], - ["inner_dst_ipv4", "--hash-field", "INNER_DST_IPV4", - "--ip-mask", "255.0.0.0", "--sequence-id", "3"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["hash-field"]. + commands["add"], [hash_field_name, "--hash-field", + hash_field, "--ip-mask", ip_mask, "--sequence-id", + "3"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - result = runner.invoke(config.config.commands["pbh"]. - commands["hash-field"].commands["update"], - ["inner_dst_ipv4", "--ip-mask", "ffff::", "--sequence-id", "2"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["hash-field"]. + commands["update"], [hash_field_name, "--ip-mask", + updated_ip_mask], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) @@ -353,87 +324,78 @@ def test_config_pbh_hash_add_delete_ipv4(self): db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["hash"].commands["add"], - ["inner_v4_hash", "--hash-field-list", + result = runner.invoke( + config.config.commands["pbh"].commands["hash"]. + commands["add"], ["inner_v4_hash", "--hash-field-list", "inner_ip_proto,inner_l4_dst_port,inner_l4_src_port,inner_dst_ipv4,inner_dst_ipv4"], - obj=db) + obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - result = runner.invoke(config.config.commands["pbh"]. - commands["hash"].commands["delete"], - ["inner_v4_hash"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["hash"]. + commands["delete"],["inner_v4_hash"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - self.clear_dedicated_mock_dbs() - def test_config_pbh_hash_add_update_ipv6(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'hash_fields') db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["hash"].commands["add"], - ["inner_v6_hash", "--hash-field-list", + result = runner.invoke( + config.config.commands["pbh"].commands["hash"]. + commands["add"], ["inner_v6_hash", "--hash-field-list", "inner_ip_proto,inner_l4_dst_port,inner_l4_src_port,inner_dst_ipv6,inner_dst_ipv6"], - obj=db) + obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - result = runner.invoke(config.config.commands["pbh"]. - commands["hash"].commands["update"], - ["inner_v6_hash", "--hash-field-list", + result = runner.invoke( + config.config.commands["pbh"].commands["hash"]. + commands["update"], ["inner_v6_hash", "--hash-field-list", "inner_l4_dst_port,inner_l4_src_port,inner_dst_ipv6,inner_dst_ipv6"], - obj=db) + obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - self.clear_dedicated_mock_dbs() - - - def test_config_pbh_hash_add_invalid_hash_field_list(self): + @pytest.mark.parametrize("hash_name,hash_field_list,exit_code", [ + ("inner_v6_hash", INVALID_VALUE, ERROR), + ("inner_v6_hash", "", ERROR), + ("inner_v6_hash", None, ERROR2) + ]) + def test_config_pbh_hash_add_invalid_hash_field_list( + self, + hash_name, + hash_field_list, + exit_code + ): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'hash_fields') db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["hash"].commands["add"], - ["inner_v6_hash", "--hash-field-list", - "INVALID"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["hash"]. + commands["add"], [hash_name, "--hash-field-list", + hash_field_list], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == ERROR - - self.clear_dedicated_mock_dbs() - - - def test_config_pbh_hash_add_empty_hash_field_list(self): - dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'hash_fields') - db = Db() - runner = CliRunner() - - result = runner.invoke(config.config.commands["pbh"]. - commands["hash"].commands["add"], - ["inner_v6_hash", "--hash-field-list", - ""], obj=db) - - logger.debug("\n" + result.output) - logger.debug(result.exit_code) - assert result.exit_code == ERROR - - self.clear_dedicated_mock_dbs() + assert result.exit_code == exit_code ########## CONFIG PBH TABLE ########## @@ -444,125 +406,130 @@ def test_config_pbh_table_add_delete_ports(self): db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["table"].commands["add"], - ["pbh_table1", "--interface-list", "Ethernet0,Ethernet4", - "--description", "NVGRE"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["table"]. + commands["add"],["pbh_table1", "--interface-list", + "Ethernet0,Ethernet4", "--description", "NVGRE"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - result = runner.invoke(config.config.commands["pbh"]. - commands["table"].commands["delete"], ["pbh_table1"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["table"]. + commands["delete"], ["pbh_table1"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - self.clear_dedicated_mock_dbs() - def test_config_pbh_table_add_update_portchannels(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["table"].commands["add"], - ["pbh_table2", "--interface-list", "PortChannel0001", - "--description", "VxLAN"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["table"]. + commands["add"], ["pbh_table2", "--interface-list", + "PortChannel0001", "--description", "VxLAN"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - result = runner.invoke(config.config.commands["pbh"]. - commands["table"].commands["update"], - ["pbh_table2", "--interface-list", "PortChannel0002", - "--description", "VxLAN TEST"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["table"]. + commands["update"],["pbh_table2", "--interface-list", + "PortChannel0002", "--description", "VxLAN TEST"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - result = runner.invoke(config.config.commands["pbh"]. - commands["table"].commands["update"], - ["pbh_table2", "--interface-list", "PortChannel0001"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["table"]. + commands["update"],["pbh_table2", "--interface-list", + "PortChannel0001"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - result = runner.invoke(config.config.commands["pbh"]. - commands["table"].commands["update"], - ["pbh_table2", "--description", "TEST"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["table"]. + commands["update"], ["pbh_table2", "--description", + "TEST"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - self.clear_dedicated_mock_dbs() - def test_config_pbh_table_add_port_and_portchannel(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["table"].commands["add"], - ["pbh_table3", "--interface-list", "PortChannel0002,Ethernet8", - "--description", "VxLAN adn NVGRE"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["table"]. + commands["add"], ["pbh_table3", "--interface-list", + "PortChannel0002,Ethernet8", "--description", + "VxLAN adn NVGRE"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - self.clear_dedicated_mock_dbs() - def test_config_pbh_table_add_invalid_port(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["table"].commands["add"], - ["pbh_table3", "--interface-list", "INVALID", - "--description", "VxLAN adn NVGRE"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["table"]. + commands["add"], ["pbh_table3", "--interface-list", + INVALID_VALUE, "--description", "VxLAN adn NVGRE"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR - self.clear_dedicated_mock_dbs() - - def test_config_pbh_table_add_update_wrong_interface(self): + def test_config_pbh_table_add_update_invalid_interface(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'table') db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["table"].commands["add"], - ["pbh_table2", "--interface-list", "PortChannel0001", - "--description", "VxLAN"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["table"]. + commands["add"], ["pbh_table2", "--interface-list", + "PortChannel0001", "--description", "VxLAN"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - result = runner.invoke(config.config.commands["pbh"]. - commands["table"].commands["update"], - ["pbh_table2", "--interface-list", "INVALID"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["table"]. + commands["update"], ["pbh_table2", "--interface-list", + INVALID_VALUE], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR - self.clear_dedicated_mock_dbs() - ########## CONFIG PBH RULE ########## @@ -572,176 +539,182 @@ def test_config_pbh_rule_add_delete_nvgre(self): db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["rule"].commands["add"], - ["pbh_table1", "nvgre", "--priority", "1", "--gre-key", - "0x2500/0xffffff00", "--inner-ether-type", "0x86dd", - "--hash", "inner_v6_hash", "--packet-action", "SET_ECMP_HASH", - "--flow-counter", "DISABLED"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["rule"]. + commands["add"],["pbh_table1", "nvgre", "--priority", + "1", "--gre-key", "0x2500/0xffffff00", "--inner-ether-type", + "0x86dd", "--hash", "inner_v6_hash", "--packet-action", + "SET_ECMP_HASH", "--flow-counter", "DISABLED"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - result = runner.invoke(config.config.commands["pbh"]. - commands["rule"].commands["delete"], ["pbh_table1", "nvgre"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["rule"]. + commands["delete"], ["pbh_table1", "nvgre"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - self.clear_dedicated_mock_dbs() - def test_config_pbh_rule_add_update_vxlan(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["rule"].commands["add"], - ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", - "0x11", "--inner-ether-type", "0x0800", - "--l4-dst-port", "0x12b5", "--hash", "inner_v4_hash", - "--packet-action", "SET_LAG_HASH", "--flow-counter", "ENABLED"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["rule"]. + commands["add"], ["pbh_table1", "vxlan ", + "--priority", "2", "--ip-protocol", "0x11", + "--inner-ether-type", "0x0800","--l4-dst-port", + "0x12b5", "--hash", "inner_v4_hash", "--packet-action", + "SET_LAG_HASH", "--flow-counter", "ENABLED"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - result = runner.invoke(config.config.commands["pbh"]. - commands["rule"].commands["update"], - ["pbh_table1", "vxlan ", "--priority", "3", "--inner-ether-type", "0x086d", - "--packet-action", "SET_LAG_HASH", "--flow-counter", "DISABLED"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["rule"]. + commands["update"], ["pbh_table1", "vxlan ", + "--priority", "3", "--inner-ether-type", "0x086d", + "--packet-action", "SET_LAG_HASH", "--flow-counter", + "DISABLED"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - self.clear_dedicated_mock_dbs() - def test_config_pbh_rule_update_invalid(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["rule"].commands["add"], - ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", - "0x11", "--inner-ether-type", "0x0800", - "--l4-dst-port", "0x12b5", "--hash", "inner_v6_hash", - "--packet-action", "SET_ECMP_HASH", "--flow-counter", "ENABLED"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["rule"]. + commands["add"], ["pbh_table1", "vxlan ", "--priority", + "2", "--ip-protocol", "0x11", "--inner-ether-type", + "0x0800", "--l4-dst-port", "0x12b5", "--hash", + "inner_v6_hash", "--packet-action", "SET_ECMP_HASH", + "--flow-counter", "ENABLED"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS - result = runner.invoke(config.config.commands["pbh"]. - commands["rule"].commands["update"], - ["pbh_table1", "vxlan ", "--flow-counter", "INVALID"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["rule"]. + commands["update"], ["pbh_table1", "vxlan ", + "--flow-counter", INVALID_VALUE], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR2 - self.clear_dedicated_mock_dbs() - def test_config_pbh_rule_add_invalid_ip_protocol(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["rule"].commands["add"], - ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", - "INVALID", "--inner-ether-type", "0x0800", - "--l4-dst-port", "0x12b5", "--hash", "inner_v6_hash", - "--packet-action", "SET_ECMP_HASH", "--flow-counter", "ENABLED"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["rule"]. + commands["add"], ["pbh_table1", "vxlan ", "--priority", + "2", "--ip-protocol", INVALID_VALUE, "--inner-ether-type", + "0x0800", "--l4-dst-port", "0x12b5", "--hash", "inner_v6_hash", + "--packet-action", "SET_ECMP_HASH", "--flow-counter", + "ENABLED"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR - self.clear_dedicated_mock_dbs() - def test_config_pbh_rule_add_invalid_inner_ether_type(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["rule"].commands["add"], - ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", - "0x11", "--inner-ether-type", "INVALID", - "--l4-dst-port", "0x12b5", "--hash", "inner_v6_hash", - "--packet-action", "SET_ECMP_HASH", "--flow-counter", "ENABLED"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["rule"]. + commands["add"], ["pbh_table1", "vxlan ", "--priority", + "2", "--ip-protocol", "0x11", "--inner-ether-type", + INVALID_VALUE, "--l4-dst-port", "0x12b5", "--hash", + "inner_v6_hash", "--packet-action", "SET_ECMP_HASH", + "--flow-counter", "ENABLED"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR - self.clear_dedicated_mock_dbs() - def test_config_pbh_rule_add_invalid_hash(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["rule"].commands["add"], - ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", - "0x11", "--inner-ether-type", "0x0800", - "--l4-dst-port", "0x12b5", "--hash", "INVALID", - "--packet-action", "SET_ECMP_HASH", "--flow-counter", "ENABLED"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["rule"]. + commands["add"], ["pbh_table1", "vxlan ", "--priority", + "2", "--ip-protocol", "0x11", "--inner-ether-type", "0x0800", + "--l4-dst-port", "0x12b5", "--hash", INVALID_VALUE, + "--packet-action", "SET_ECMP_HASH", "--flow-counter", + "ENABLED"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR - self.clear_dedicated_mock_dbs() - def test_config_pbh_rule_add_invalid_packet_action(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["rule"].commands["add"], - ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", - "0x11", "--inner-ether-type", "0x0800", - "--l4-dst-port", "0x12b5", "--hash", "inner_v6_hash", - "--packet-action", "INVALID", "--flow-counter", "ENABLED"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["rule"]. + commands["add"], ["pbh_table1", "vxlan ", "--priority", + "2", "--ip-protocol", "0x11", "--inner-ether-type", + "0x0800", "--l4-dst-port", "0x12b5", "--hash", + "inner_v6_hash", "--packet-action", INVALID_VALUE, + "--flow-counter", "ENABLED"], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR2 - self.clear_dedicated_mock_dbs() - def test_config_pbh_rule_add_invalid_flow_counter(self): dbconnector.dedicated_dbs['CONFIG_DB'] = os.path.join(mock_db_path, 'rule') db = Db() runner = CliRunner() - result = runner.invoke(config.config.commands["pbh"]. - commands["rule"].commands["add"], - ["pbh_table1", "vxlan ", "--priority", "2", "--ip-protocol", - "0x11", "--inner-ether-type", "0x0800", - "--l4-dst-port", "0x12b5", "--hash", "inner_v6_hash", - "--packet-action", "SET_ECMP_HASH", "--flow-counter", "INVALID"], obj=db) + result = runner.invoke( + config.config.commands["pbh"].commands["rule"]. + commands["add"], ["pbh_table1", "vxlan ", "--priority", + "2", "--ip-protocol", "0x11", "--inner-ether-type", + "0x0800", "--l4-dst-port", "0x12b5", "--hash", + "inner_v6_hash", "--packet-action", "SET_ECMP_HASH", + "--flow-counter", INVALID_VALUE], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == ERROR2 - self.clear_dedicated_mock_dbs() - ########## SHOW PBH HASH-FIELD ########## def test_show_pbh_hash_field(self): @@ -749,16 +722,16 @@ def test_show_pbh_hash_field(self): db = Db() runner = CliRunner() - result = runner.invoke(show.cli.commands["pbh"]. - commands["hash-field"], [], obj=db) + result = runner.invoke( + show.cli.commands["pbh"]. + commands["hash-field"], [], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_hash_fields - self.clear_dedicated_mock_dbs() - ########## SHOW PBH HASH ########## @@ -768,16 +741,16 @@ def test_show_pbh_hash(self): db = Db() runner = CliRunner() - result = runner.invoke(show.cli.commands["pbh"]. - commands["hash"], [], obj=db) + result = runner.invoke( + show.cli.commands["pbh"]. + commands["hash"], [], obj=db + ) logger.debug("\n" + result.stdout) logger.debug(result.exit_code) assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_hash - self.clear_dedicated_mock_dbs() - ########## SHOW PBH TABLE ########## @@ -787,16 +760,16 @@ def test_show_pbh_table(self): db = Db() runner = CliRunner() - result = runner.invoke(show.cli.commands["pbh"]. - commands["table"], [], obj=db) + result = runner.invoke( + show.cli.commands["pbh"]. + commands["table"], [], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_table - self.clear_dedicated_mock_dbs() - ########## SHOW PBH RULE ########## @@ -806,16 +779,16 @@ def test_show_pbh_rule(self): db = Db() runner = CliRunner() - result = runner.invoke(show.cli.commands["pbh"]. - commands["rule"], [], obj=db) + result = runner.invoke( + show.cli.commands["pbh"]. + commands["rule"], [], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_rule - self.clear_dedicated_mock_dbs() - ########## SHOW PBH STATISTICS ########## @@ -830,16 +803,16 @@ def test_show_pbh_statistics_on_empty_config(self): db = Db() runner = CliRunner() - result = runner.invoke(show.cli.commands["pbh"]. - commands["statistics"], [], obj=db) + result = runner.invoke( + show.cli.commands["pbh"]. + commands["statistics"], [], obj=db + ) logger.debug("\n" + result.output) logger.debug(result.exit_code) assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_statistics_empty - self.clear_dedicated_mock_dbs() - def test_show_pbh_statistics(self): dbconnector.dedicated_dbs['COUNTERS_DB'] = os.path.join(mock_db_path, 'counters_db') @@ -852,16 +825,16 @@ def test_show_pbh_statistics(self): db = Db() runner = CliRunner() - result = runner.invoke(show.cli.commands["pbh"]. - commands["statistics"], [], obj=db) + result = runner.invoke( + show.cli.commands["pbh"]. + commands["statistics"], [], obj=db + ) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_statistics - self.clear_dedicated_mock_dbs() - def test_show_pbh_statistics_after_clear(self): dbconnector.dedicated_dbs['COUNTERS_DB'] = os.path.join(mock_db_path, 'counters_db') @@ -874,25 +847,24 @@ def test_show_pbh_statistics_after_clear(self): db = Db() runner = CliRunner() - result = runner.invoke(show.cli.commands["pbh"]. - commands["statistics"], [], obj=db) - logger.debug("\n" + result.output) - logger.debug(result.exit_code) + result = runner.invoke( + clear.cli.commands["pbh"]. + commands["statistics"], [], obj=db + ) - result = runner.invoke(clear.cli.commands["pbh"].commands["statistics"], [], obj=db) logger.debug("\n" + result.output) logger.debug(result.exit_code) - result = runner.invoke(show.cli.commands["pbh"]. - commands["statistics"], [], obj=db) + result = runner.invoke( + show.cli.commands["pbh"]. + commands["statistics"], [], obj=db + ) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_statistics_zero - self.clear_dedicated_mock_dbs() - def test_show_pbh_statistics_after_clear_and_counters_updated(self): dbconnector.dedicated_dbs['COUNTERS_DB'] = os.path.join(mock_db_path, 'counters_db') @@ -905,27 +877,26 @@ def test_show_pbh_statistics_after_clear_and_counters_updated(self): db = Db() runner = CliRunner() - result = runner.invoke(show.cli.commands["pbh"]. - commands["statistics"], [], obj=db) - logger.debug("\n" + result.output) - logger.debug(result.exit_code) + result = runner.invoke( + clear.cli.commands["pbh"]. + commands["statistics"], [], obj=db + ) - result = runner.invoke(clear.cli.commands["pbh"].commands["statistics"], [], obj=db) logger.debug("\n" + result.output) logger.debug(result.exit_code) dbconnector.dedicated_dbs['COUNTERS_DB'] = os.path.join(mock_db_path, 'counters_db_updated') - result = runner.invoke(show.cli.commands["pbh"]. - commands["statistics"], [], obj=db) + result = runner.invoke( + show.cli.commands["pbh"]. + commands["statistics"], [], obj=db + ) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_statistics_updated - self.clear_dedicated_mock_dbs() - def test_show_pbh_statistics_after_disabling_rule(self): dbconnector.dedicated_dbs['COUNTERS_DB'] = os.path.join(mock_db_path, 'counters_db') @@ -938,26 +909,31 @@ def test_show_pbh_statistics_after_disabling_rule(self): db = Db() runner = CliRunner() - result = runner.invoke(show.cli.commands["pbh"]. - commands["statistics"], [], obj=db) - logger.debug("\n" + result.output) - logger.debug(result.exit_code) + result = runner.invoke( + clear.cli.commands["pbh"]. + commands["statistics"], [], obj=db + ) - result = runner.invoke(clear.cli.commands["pbh"].commands["statistics"], [], obj=db) logger.debug("\n" + result.output) logger.debug(result.exit_code) - result = runner.invoke(config.config.commands["pbh"]. - commands["rule"].commands["update"], ["pbh_table2", "vxlan", "--flow-counter", "DISABLED"], obj=db) + result = runner.invoke( + config.config.commands["pbh"]. + commands["rule"].commands["update"], + ["pbh_table2", "vxlan", "--flow-counter", + "DISABLED"], obj=db + ) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - result = runner.invoke(show.cli.commands["pbh"]. - commands["statistics"], [], obj=db) + result = runner.invoke( + show.cli.commands["pbh"]. + commands["statistics"], [], obj=db + ) + logger.debug("\n" + result.output) logger.debug(result.exit_code) - assert result.exit_code == SUCCESS assert result.output == assert_show_output.show_pbh_statistics_after_disabling_rule - self.clear_dedicated_mock_dbs() From 6a1936846d983f01b4f5369cb304794cc7d80910 Mon Sep 17 00:00:00 2001 From: Vadym Hlushko Date: Thu, 22 Jul 2021 13:17:07 +0000 Subject: [PATCH 79/79] Fixed description Signed-off-by: Vadym Hlushko --- config/plugins/pbh.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/config/plugins/pbh.py b/config/plugins/pbh.py index 3f6dd100a0..e5e5f0fdde 100644 --- a/config/plugins/pbh.py +++ b/config/plugins/pbh.py @@ -299,14 +299,13 @@ def PBH_HASH_FIELD(): ) @click.option( "--hash-field", - help="Configure native hash field for this hash field", + help="Configures native hash field for this hash field", required=True, type=click.Choice(hash_field_types) ) @click.option( "--ip-mask", - help="""Configures IPv4/IPv6 address mask for this hash field, required when the value of --hash-field are - INNER_DST_IPV4 or - INNER_SRC_IPV4 or INNER_SRC_IPV4 or INNER_SRC_IPV4 """, + help="""Configures IPv4/IPv6 address mask for this hash field, required when the value of --hash-field is - INNER_DST_IPV4 or INNER_SRC_IPV4 or INNER_SRC_IPV6 or INNER_SRC_IPV6""", callback=ip_address_validator, ) @click.option( @@ -350,7 +349,7 @@ def PBH_HASH_FIELD_add(db, hash_field_name, hash_field, ip_mask, sequence_id): ) @click.option( "--ip-mask", - help="Configures IPv4/IPv6 address mask for this hash field", + help="""Configures IPv4/IPv6 address mask for this hash field, required when the value of --hash-field is - INNER_DST_IPV4 or INNER_SRC_IPV4 or INNER_SRC_IPV6 or INNER_SRC_IPV6 """, callback=ip_address_validator, ) @click.option( @@ -508,7 +507,7 @@ def PBH_RULE(): ) @click.option( "--priority", - help="Configures priority", + help="Configures priority for this rule", required=True, type=click.INT, ) @@ -545,11 +544,11 @@ def PBH_RULE(): @click.option( "--hash", required=True, - help="Configures the hash to apply", + help="The hash to apply with this rule", ) @click.option( "--packet-action", - help="Configures packet action", + help="Configures packet action for this rule", type=click.Choice(packet_action_types) ) @click.option( @@ -623,7 +622,7 @@ def PBH_RULE_add( ) @click.option( "--priority", - help="Configures priority", + help="Configures priority for this rule", type=click.INT, ) @click.option( @@ -662,7 +661,7 @@ def PBH_RULE_add( ) @click.option( "--packet-action", - help="Configures packet action", + help="Configures packet action for this rule", type=click.Choice(packet_action_types) ) @click.option(