[ECMP][Multi-ASIC] Have different ECMP seed value on each ASIC (#5357)
* Calculate ECMP hash seed based on ASIC ID on multi ASIC platform. Each ASIC will have a unique ECMP hash seed value.
This commit is contained in:
parent
895f4e0bf7
commit
744612d269
@ -1,20 +1,25 @@
|
|||||||
{# the range of hash_seed is 0-15 #}
|
{# the range of hash_seed is 0-15 #}
|
||||||
{# set default hash seed to 0 #}
|
{# set default hash seed to 0 #}
|
||||||
{% set hash_seed = 0 %}
|
{% set hash_seed = 0 %}
|
||||||
|
{% set hash_seed_offset = 0 %}
|
||||||
{% if DEVICE_METADATA.localhost.type %}
|
{% if DEVICE_METADATA.localhost.type %}
|
||||||
{% if DEVICE_METADATA.localhost.type == "ToRRouter" %}
|
{% if DEVICE_METADATA.localhost.type == "ToRRouter" %}
|
||||||
{% set hash_seed = 0 %}
|
{% set hash_seed = 0 %}
|
||||||
{% elif DEVICE_METADATA.localhost.type == "LeafRouter" %}
|
{% elif DEVICE_METADATA.localhost.type == "LeafRouter" %}
|
||||||
{% set hash_seed = 10 %}
|
{% set hash_seed = 10 %}
|
||||||
{% elif DEVICE_METADATA.localhost.type == "SpineRouter" %}
|
{% elif DEVICE_METADATA.localhost.type == "SpineRouter" %}
|
||||||
{% set hash_seed = 15 %}
|
{% set hash_seed = 25 %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if DEVICE_METADATA.localhost.namespace_id %}
|
||||||
|
{% set hash_seed_offset = DEVICE_METADATA.localhost.namespace_id | int %}
|
||||||
|
{% endif %}
|
||||||
|
{% set hash_seed_value = hash_seed_offset + hash_seed %}
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"SWITCH_TABLE:switch": {
|
"SWITCH_TABLE:switch": {
|
||||||
"ecmp_hash_seed": "{{ hash_seed }}",
|
"ecmp_hash_seed": "{{ hash_seed_value }}",
|
||||||
"lag_hash_seed": "{{ hash_seed }}",
|
"lag_hash_seed": "{{ hash_seed_value }}",
|
||||||
"fdb_aging_time": "600"
|
"fdb_aging_time": "600"
|
||||||
},
|
},
|
||||||
"OP": "SET"
|
"OP": "SET"
|
||||||
|
@ -31,7 +31,7 @@ import contextlib
|
|||||||
import jinja2
|
import jinja2
|
||||||
import json
|
import json
|
||||||
import netaddr
|
import netaddr
|
||||||
import os.path
|
import os
|
||||||
import sys
|
import sys
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ def sort_by_port_index(value):
|
|||||||
if not value:
|
if not value:
|
||||||
return
|
return
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
# In multi-ASIC platforms backend ethernet ports are identified as
|
# In multi-ASIC platforms backend ethernet ports are identified as
|
||||||
# 'Ethernet-BPxy'. Add 1024 to sort backend ports to the end.
|
# 'Ethernet-BPxy'. Add 1024 to sort backend ports to the end.
|
||||||
value.sort(
|
value.sort(
|
||||||
key = lambda k: int(k[8:]) if "BP" not in k else int(k[11:]) + 1024
|
key = lambda k: int(k[8:]) if "BP" not in k else int(k[11:]) + 1024
|
||||||
@ -296,8 +296,14 @@ def main():
|
|||||||
asic_id = None
|
asic_id = None
|
||||||
if asic_name is not None:
|
if asic_name is not None:
|
||||||
asic_id = get_asic_id_from_name(asic_name)
|
asic_id = get_asic_id_from_name(asic_name)
|
||||||
|
# get the namespace ID
|
||||||
|
namespace_id = os.getenv("NAMESPACE_ID")
|
||||||
|
if namespace_id:
|
||||||
|
deep_update(data, {
|
||||||
|
'DEVICE_METADATA': {
|
||||||
|
'localhost': {'namespace_id': namespace_id}
|
||||||
|
}
|
||||||
|
})
|
||||||
# Load the database config for the namespace from global database json
|
# Load the database config for the namespace from global database json
|
||||||
if args.namespace is not None:
|
if args.namespace is not None:
|
||||||
SonicDBConfig.load_sonic_global_db_config(namespace=args.namespace)
|
SonicDBConfig.load_sonic_global_db_config(namespace=args.namespace)
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"SWITCH_TABLE:switch": {
|
||||||
|
"ecmp_hash_seed": "11",
|
||||||
|
"lag_hash_seed": "11",
|
||||||
|
"fdb_aging_time": "600"
|
||||||
|
},
|
||||||
|
"OP": "SET"
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,10 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"SWITCH_TABLE:switch": {
|
||||||
|
"ecmp_hash_seed": "13",
|
||||||
|
"lag_hash_seed": "13",
|
||||||
|
"fdb_aging_time": "600"
|
||||||
|
},
|
||||||
|
"OP": "SET"
|
||||||
|
}
|
||||||
|
]
|
10
src/sonic-config-engine/tests/sample_output/t0-switch.json
Normal file
10
src/sonic-config-engine/tests/sample_output/t0-switch.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"SWITCH_TABLE:switch": {
|
||||||
|
"ecmp_hash_seed": "0",
|
||||||
|
"lag_hash_seed": "0",
|
||||||
|
"fdb_aging_time": "600"
|
||||||
|
},
|
||||||
|
"OP": "SET"
|
||||||
|
}
|
||||||
|
]
|
10
src/sonic-config-engine/tests/sample_output/t1-switch.json
Normal file
10
src/sonic-config-engine/tests/sample_output/t1-switch.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"SWITCH_TABLE:switch": {
|
||||||
|
"ecmp_hash_seed": "10",
|
||||||
|
"lag_hash_seed": "10",
|
||||||
|
"fdb_aging_time": "600"
|
||||||
|
},
|
||||||
|
"OP": "SET"
|
||||||
|
}
|
||||||
|
]
|
@ -171,6 +171,68 @@ class TestJ2Files(TestCase):
|
|||||||
sample_output_file = os.path.join(self.test_dir, 'multi_npu_data', utils.PYvX_DIR, 'ipinip.json')
|
sample_output_file = os.path.join(self.test_dir, 'multi_npu_data', utils.PYvX_DIR, 'ipinip.json')
|
||||||
assert filecmp.cmp(sample_output_file, self.output_file)
|
assert filecmp.cmp(sample_output_file, self.output_file)
|
||||||
|
|
||||||
|
def test_swss_switch_render_template(self):
|
||||||
|
switch_template = os.path.join(
|
||||||
|
self.test_dir, '..', '..', '..', 'dockers', 'docker-orchagent',
|
||||||
|
'switch.json.j2'
|
||||||
|
)
|
||||||
|
constants_yml = os.path.join(
|
||||||
|
self.test_dir, '..', '..', '..', 'files', 'image_config',
|
||||||
|
'constants', 'constants.yml'
|
||||||
|
)
|
||||||
|
test_list = {
|
||||||
|
"t1": {
|
||||||
|
"graph": self.t1_mlnx_minigraph,
|
||||||
|
"output": "t1-switch.json"
|
||||||
|
},
|
||||||
|
"t0": {
|
||||||
|
"graph": self.t0_minigraph,
|
||||||
|
"output": "t0-switch.json"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, v in test_list.items():
|
||||||
|
argument = " -m {} -y {} -t {} > {}".format(
|
||||||
|
v["graph"], constants_yml, switch_template, self.output_file
|
||||||
|
)
|
||||||
|
sample_output_file = os.path.join(
|
||||||
|
self.test_dir, 'sample_output', v["output"]
|
||||||
|
)
|
||||||
|
self.run_script(argument)
|
||||||
|
assert filecmp.cmp(sample_output_file, self.output_file)
|
||||||
|
|
||||||
|
def test_swss_switch_render_template_multi_asic(self):
|
||||||
|
# verify the ECMP hash seed changes per namespace
|
||||||
|
switch_template = os.path.join(
|
||||||
|
self.test_dir, '..', '..', '..', 'dockers', 'docker-orchagent',
|
||||||
|
'switch.json.j2'
|
||||||
|
)
|
||||||
|
constants_yml = os.path.join(
|
||||||
|
self.test_dir, '..', '..', '..', 'files', 'image_config',
|
||||||
|
'constants', 'constants.yml'
|
||||||
|
)
|
||||||
|
test_list = {
|
||||||
|
"0": {
|
||||||
|
"namespace_id": "1",
|
||||||
|
"output": "t0-switch-masic1.json"
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"namespace_id": "3",
|
||||||
|
"output": "t0-switch-masic3.json"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, v in test_list.items():
|
||||||
|
os.environ["NAMESPACE_ID"] = v["namespace_id"]
|
||||||
|
argument = " -m {} -y {} -t {} > {}".format(
|
||||||
|
self.t1_mlnx_minigraph, constants_yml, switch_template,
|
||||||
|
self.output_file
|
||||||
|
)
|
||||||
|
sample_output_file = os.path.join(
|
||||||
|
self.test_dir, 'sample_output', v["output"]
|
||||||
|
)
|
||||||
|
self.run_script(argument)
|
||||||
|
assert filecmp.cmp(sample_output_file, self.output_file)
|
||||||
|
os.environ["NAMESPACE_ID"] = ""
|
||||||
|
|
||||||
def test_ndppd_conf(self):
|
def test_ndppd_conf(self):
|
||||||
conf_template = os.path.join(self.test_dir, "ndppd.conf.j2")
|
conf_template = os.path.join(self.test_dir, "ndppd.conf.j2")
|
||||||
vlan_interfaces_json = os.path.join(self.test_dir, "data", "ndppd", "vlan_interfaces.json")
|
vlan_interfaces_json = os.path.join(self.test_dir, "data", "ndppd", "vlan_interfaces.json")
|
||||||
@ -180,7 +242,6 @@ class TestJ2Files(TestCase):
|
|||||||
self.run_script(argument)
|
self.run_script(argument)
|
||||||
assert filecmp.cmp(expected, self.output_file), self.run_diff(expected, self.output_file)
|
assert filecmp.cmp(expected, self.output_file), self.run_diff(expected, self.output_file)
|
||||||
|
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
try:
|
try:
|
||||||
os.remove(self.output_file)
|
os.remove(self.output_file)
|
||||||
|
Loading…
Reference in New Issue
Block a user