Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

YANG validation for ConfigDB Updates: MIRROR_SESSION use case #2430

Merged
merged 9 commits into from
Mar 7, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 47 additions & 21 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -952,7 +952,7 @@ def validate_mirror_session_config(config_db, session_name, dst_port, src_port,
""" Check if SPAN mirror-session config is valid """
ctx = click.get_current_context()
if len(config_db.get_entry('MIRROR_SESSION', session_name)) != 0:
click.echo("Error: {} already exists".format(session_name))
click.echo("Error: {} already exists".format(session_name)) # TODO: MISSING CONSTRAINT IN YANG MODEL
return False

vlan_member_table = config_db.get_table('VLAN_MEMBER')
Expand Down Expand Up @@ -2333,25 +2333,35 @@ def add_erspan(session_name, src_ip, dst_ip, dscp, ttl, gre_type, queue, policer
session_info['gre_type'] = gre_type

session_info = gather_session_info(session_info, policer, queue, src_port, direction)
ctx = click.get_current_context()

"""
For multi-npu platforms we need to program all front asic namespaces
"""
namespaces = multi_asic.get_all_namespaces()
if not namespaces['front_ns']:
config_db = ConfigDBConnector()
config_db = ValidatedConfigDBConnector(ConfigDBConnector())
config_db.connect()
if validate_mirror_session_config(config_db, session_name, None, src_port, direction) is False:
return
config_db.set_entry("MIRROR_SESSION", session_name, session_info)
if ADHOC_VALIDATION:
if validate_mirror_session_config(config_db, session_name, None, src_port, direction) is False:
return
try:
config_db.set_entry("MIRROR_SESSION", session_name, session_info)
except ValueError as e:
ctx.fail("Invalid mirror session config. Error: {}".format(e))

else:
per_npu_configdb = {}
for front_asic_namespaces in namespaces['front_ns']:
per_npu_configdb[front_asic_namespaces] = ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces)
per_npu_configdb[front_asic_namespaces] = ValidatedConfigDBConnector(ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces))
per_npu_configdb[front_asic_namespaces].connect()
if validate_mirror_session_config(per_npu_configdb[front_asic_namespaces], session_name, None, src_port, direction) is False:
return
per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, session_info)
if ADHOC_VALIDATION:
if validate_mirror_session_config(per_npu_configdb[front_asic_namespaces], session_name, None, src_port, direction) is False:
return
try:
per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, session_info)
except ValueError as e:
ctx.fail("Invalid mirror session config. Error: {}".format(e))

@mirror_session.group(cls=clicommon.AbbreviationGroup, name='span')
@click.pass_context
Expand Down Expand Up @@ -2383,25 +2393,34 @@ def add_span(session_name, dst_port, src_port, direction, queue, policer):
}

session_info = gather_session_info(session_info, policer, queue, src_port, direction)
ctx = click.get_current_context()

"""
For multi-npu platforms we need to program all front asic namespaces
"""
namespaces = multi_asic.get_all_namespaces()
if not namespaces['front_ns']:
config_db = ConfigDBConnector()
config_db = ValidatedConfigDBConnector(ConfigDBConnector())
config_db.connect()
if validate_mirror_session_config(config_db, session_name, dst_port, src_port, direction) is False:
return
config_db.set_entry("MIRROR_SESSION", session_name, session_info)
if ADHOC_VALIDATION:
if validate_mirror_session_config(config_db, session_name, dst_port, src_port, direction) is False:
return
try:
config_db.set_entry("MIRROR_SESSION", session_name, session_info)
except ValueError as e:
ctx.fail("Invalid mirror session config. Error: {}".format(e))
else:
per_npu_configdb = {}
for front_asic_namespaces in namespaces['front_ns']:
per_npu_configdb[front_asic_namespaces] = ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces)
per_npu_configdb[front_asic_namespaces] = ValidatedConfigDBConnector(ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces))
per_npu_configdb[front_asic_namespaces].connect()
if validate_mirror_session_config(per_npu_configdb[front_asic_namespaces], session_name, dst_port, src_port, direction) is False:
return
per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, session_info)
if ADHOC_VALIDATION:
if validate_mirror_session_config(per_npu_configdb[front_asic_namespaces], session_name, dst_port, src_port, direction) is False:
return
try:
per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, session_info)
except ValueError as e:
ctx.fail("Invalid mirror session config. Error: {}".format(e))


@mirror_session.command()
Expand All @@ -2413,16 +2432,23 @@ def remove(session_name):
For multi-npu platforms we need to program all front asic namespaces
"""
namespaces = multi_asic.get_all_namespaces()
ctx = click.get_current_context()
if not namespaces['front_ns']:
config_db = ConfigDBConnector()
config_db = ValidatedConfigDBConnector(ConfigDBConnector())
config_db.connect()
config_db.set_entry("MIRROR_SESSION", session_name, None)
try:
config_db.set_entry("MIRROR_SESSION", session_name, None)
except JsonPatchConflict:
ctx.fail("Failed to remove MIRROR_SESSION {}".format(session_name))
else:
per_npu_configdb = {}
for front_asic_namespaces in namespaces['front_ns']:
per_npu_configdb[front_asic_namespaces] = ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces)
per_npu_configdb[front_asic_namespaces] = ValidatedConfigDBConnector(ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces))
per_npu_configdb[front_asic_namespaces].connect()
per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, None)
try:
per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, None)
except JsonPatchConflict:
ctx.fail("Failed to remove MIRROR_SESSION {}".format(session_name))

#
# 'pfcwd' group ('config pfcwd ...')
Expand Down
17 changes: 17 additions & 0 deletions config/validated_config_db_connector.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import jsonpatch
import subprocess
from jsonpointer import JsonPointer

from sonic_py_common import device_info
Expand All @@ -12,6 +13,15 @@ def ValidatedConfigDBConnector(config_db_connector):
config_db_connector.delete_table = validated_delete_table
return config_db_connector

def is_table_present_config_db(table):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is_table_present_config_db

this implementation is not efficient.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made implementation more efficient in this PR- #2452

After PR 2452 is merged, I will rebase this MIRROR_SESSION PR to include those changes because this MIRROR_SESSION PR is blocked by YANG issue sonic-net/sonic-buildimage#12397 , and PR 2452 will likely be merged first

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2452 is merged. Could you rebase this one?

cmd = "sonic-cfggen -d --print-data"
result = subprocess.Popen(cmd, shell=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
text, err = result.communicate()
return_code = result.returncode
if return_code: # non-zero means failure
raise Exception(f"Failed to get running config, Return code: {return_code}, Error: {err}")
return table in text

def make_path_value_jsonpatch_compatible(table, key, value):
if type(key) == tuple:
path = JsonPointer.from_parts([table, '|'.join(key)]).path
Expand All @@ -22,6 +32,13 @@ def make_path_value_jsonpatch_compatible(table, key, value):
return path, value

def create_gcu_patch(op, table, key=None, value=None):
gcu_json_input = []
if op == "add" and not is_table_present_config_db(table):
Copy link
Contributor

@qiluo-msft qiluo-msft Oct 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is_table_present_config_db

Need to check key and table existence. #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also addressed this comment in PR #2452

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see it resolved in 2452.

gcu_json = {"op": "{}".format(op),
"path": "/{}".format(table),
"value": {}}
gcu_json_input.append(gcu_json)

if key:
path, value = make_path_value_jsonpatch_compatible(table, key, value)
else:
Expand Down