Skip to content

Commit b17e712

Browse files
Merge branch 'master' into acl_actions
2 parents f4e65c9 + 0e233d1 commit b17e712

File tree

8 files changed

+475
-10
lines changed

8 files changed

+475
-10
lines changed

gearsyncd/gearboxparser.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,12 @@ bool GearboxParser::parse()
158158
attr = std::make_pair("macsec_ipg", std::to_string(val.get<int>()));
159159
attrs.push_back(attr);
160160
}
161+
if (phy.find("macsec_supported") != phy.end())
162+
{
163+
val = phy["macsec_supported"];
164+
attr = std::make_pair("macsec_supported", val.get<bool>() ? "true" : "false");
165+
attrs.push_back(attr);
166+
}
161167
if (phy.find("hwinfo") == phy.end())
162168
{
163169
SWSS_LOG_ERROR("missing 'hwinfo' field in 'phys' item %d in gearbox configuration", iter);

lib/gearboxutils.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ std::map<int, gearbox_phy_t> GearboxUtils::loadPhyMap(Table *gearboxTable)
137137
{
138138
gearbox_phy_t phy = {};
139139

140+
// default capability if absent
141+
phy.macsec_supported = true;
142+
140143
gearboxTable->get(k, ovalues);
141144
for (auto &val : ovalues)
142145
{
@@ -193,6 +196,10 @@ std::map<int, gearbox_phy_t> GearboxUtils::loadPhyMap(Table *gearboxTable)
193196
{
194197
phy.macsec_ipg = std::stoi(val.second);
195198
}
199+
else if (val.first == "macsec_supported")
200+
{
201+
phy.macsec_supported = (val.second == "true");
202+
}
196203
}
197204
gearboxPhyMap[phy.phy_id] = phy;
198205
}

lib/gearboxutils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ typedef struct
6464
uint32_t bus_id;
6565
uint32_t context_id;
6666
uint32_t macsec_ipg;
67+
bool macsec_supported;
6768
} gearbox_phy_t;
6869

6970
typedef struct

orchagent/macsecorch.cpp

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -355,12 +355,25 @@ class MACsecOrchContext
355355
{
356356
return nullptr;
357357
}
358-
if (port->m_line_side_id != SAI_NULL_OBJECT_ID)
358+
359+
const auto *phy = get_gearbox_phy();
360+
bool force_npu = true;
361+
if (phy)
362+
{
363+
force_npu = !phy->macsec_supported;
364+
}
365+
366+
if (!force_npu && port->m_line_side_id != SAI_NULL_OBJECT_ID)
359367
{
360368
m_port_id = std::make_unique<sai_object_id_t>(port->m_line_side_id);
361369
}
362370
else
363371
{
372+
if (force_npu && port->m_line_side_id != SAI_NULL_OBJECT_ID)
373+
{
374+
SWSS_LOG_NOTICE("MACsec: %s -> backend=NPU (phy marked unsupported), using NPU port",
375+
m_port_name ? m_port_name->c_str() : "");
376+
}
364377
m_port_id = std::make_unique<sai_object_id_t>(port->m_port_id);
365378
}
366379
}
@@ -381,12 +394,27 @@ class MACsecOrchContext
381394
{
382395
switchId = port->m_switch_id;
383396
}
397+
384398
if (switchId == SAI_NULL_OBJECT_ID)
385399
{
386400
SWSS_LOG_ERROR("Switch ID cannot be found");
387401
return nullptr;
388402
}
389403
m_switch_id = std::make_unique<sai_object_id_t>(switchId);
404+
405+
const auto *phy = port ? m_orch->m_port_orch->getGearboxPhy(*port) : nullptr;
406+
bool force_npu = true;
407+
if (phy)
408+
{
409+
force_npu = !phy->macsec_supported;
410+
}
411+
412+
if (force_npu && (*m_switch_id != gSwitchId))
413+
{
414+
SWSS_LOG_NOTICE("MACsec: %s -> backend=NPU (phy marked unsupported), override switch to global",
415+
m_port_name ? m_port_name->c_str() : "");
416+
*m_switch_id = gSwitchId;
417+
}
390418
}
391419
return m_switch_id.get();
392420
}
@@ -2507,28 +2535,32 @@ bool MACsecOrch::deleteMACsecSA(sai_object_id_t sa_id)
25072535

25082536
FlexCounterManager& MACsecOrch::MACsecSaStatManager(MACsecOrchContext &ctx)
25092537
{
2510-
if (ctx.get_gearbox_phy() != nullptr)
2538+
const auto *phy = ctx.get_gearbox_phy();
2539+
if (phy && phy->macsec_supported)
25112540
return m_gb_macsec_sa_stat_manager;
25122541
return m_macsec_sa_stat_manager;
25132542
}
25142543

25152544
FlexCounterManager& MACsecOrch::MACsecSaAttrStatManager(MACsecOrchContext &ctx)
25162545
{
2517-
if (ctx.get_gearbox_phy() != nullptr)
2546+
const auto *phy = ctx.get_gearbox_phy();
2547+
if (phy && phy->macsec_supported)
25182548
return m_gb_macsec_sa_attr_manager;
25192549
return m_macsec_sa_attr_manager;
25202550
}
25212551

25222552
FlexCounterManager& MACsecOrch::MACsecFlowStatManager(MACsecOrchContext &ctx)
25232553
{
2524-
if (ctx.get_gearbox_phy() != nullptr)
2554+
const auto *phy = ctx.get_gearbox_phy();
2555+
if (phy && phy->macsec_supported)
25252556
return m_gb_macsec_flow_stat_manager;
25262557
return m_macsec_flow_stat_manager;
25272558
}
25282559

25292560
Table& MACsecOrch::MACsecCountersMap(MACsecOrchContext &ctx)
25302561
{
2531-
if (ctx.get_gearbox_phy() != nullptr)
2562+
const auto *phy = ctx.get_gearbox_phy();
2563+
if (phy && phy->macsec_supported)
25322564
return m_gb_macsec_counters_map;
25332565
return m_macsec_counters_map;
25342566
}

orchagent/portsorch.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4795,11 +4795,6 @@ void PortsOrch::doPortTask(Consumer &consumer)
47954795
p.m_alias.c_str(), pCfg.speed.value
47964796
);
47974797
}
4798-
else
4799-
{
4800-
/* Always update Gearbox speed on Gearbox ports */
4801-
setGearboxPortsAttr(p, SAI_PORT_ATTR_SPEED, &pCfg.speed.value);
4802-
}
48034798
}
48044799

48054800
if (pCfg.adv_speeds.is_set)
@@ -5087,6 +5082,7 @@ void PortsOrch::doPortTask(Consumer &consumer)
50875082

50885083
p.m_fec_mode = pCfg.fec.value;
50895084
p.m_override_fec = pCfg.fec.override_fec;
5085+
p.m_fec_cfg = true;
50905086
m_portList[p.m_alias] = p;
50915087

50925088
SWSS_LOG_NOTICE(

tests/gearbox.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
"""
2+
Generic helper functions for gearbox testing.
3+
4+
This module provides reusable utility functions for gearbox-related tests,
5+
including port management and configuration setup.
6+
"""
7+
8+
import json
9+
10+
11+
class TestGearboxHelper:
12+
"""Helper class for gearbox-related test operations."""
13+
14+
@staticmethod
15+
def get_first_gearbox_port(gearbox):
16+
"""
17+
Get the first port from Gearbox object (reads from _GEARBOX_TABLE in APPL_DB).
18+
19+
Args:
20+
gearbox: Gearbox fixture
21+
22+
Returns:
23+
tuple: (port_name, phy_id) - First available gearbox port and its PHY ID
24+
"""
25+
assert len(gearbox.interfaces) > 0, "No interfaces found in gearbox"
26+
27+
# Get first interface
28+
first_idx = next(iter(gearbox.interfaces))
29+
first_intf = gearbox.interfaces[first_idx]
30+
31+
port_name = first_intf.get("name")
32+
phy_id = first_intf.get("phy_id")
33+
34+
assert port_name, "First interface has no 'name' field"
35+
assert phy_id is not None, "First interface has no 'phy_id' field"
36+
37+
return port_name, phy_id
38+
39+
@staticmethod
40+
def configure_gearbox_macsec_support(dvs, gearbox, phy_id=None, macsec_supported=None):
41+
"""
42+
Configure MACsec support on a gearbox PHY by modifying gearbox_config.json and restarting DVS.
43+
44+
This is necessary because:
45+
1. gearsyncd reads gearbox_config.json only at startup
46+
2. PortsOrch caches _GEARBOX_TABLE only at startup (initGearbox)
47+
3. MACsecOrch reads from PortsOrch's cache, not from _GEARBOX_TABLE
48+
4. Full DVS restart is the only reliable way to reload the configuration
49+
because partial service restarts cause inconsistent port state
50+
51+
Args:
52+
dvs: Docker Virtual Switch instance
53+
gearbox: Gearbox fixture
54+
phy_id: PHY ID (string, e.g., "1"). If None, uses the first PHY from Gearbox object.
55+
macsec_supported: None (remove field), True, or False
56+
"""
57+
# If phy_id not provided, use the first PHY from Gearbox object
58+
if phy_id is None:
59+
assert len(gearbox.phys) > 0, "No PHYs found in gearbox"
60+
phy_id = next(iter(gearbox.phys))
61+
print(f"No phy_id provided, using first PHY: {phy_id}")
62+
63+
# Resolve symlink to get actual config path
64+
config_path = "/usr/share/sonic/hwsku/gearbox_config.json"
65+
rc, actual_path = dvs.runcmd(f"readlink -f {config_path}")
66+
if rc == 0 and actual_path.strip():
67+
config_path = actual_path.strip()
68+
69+
# Read current config
70+
rc, config_json = dvs.runcmd(f"cat {config_path}")
71+
assert rc == 0, f"Failed to read gearbox_config.json from {config_path}"
72+
config = json.loads(config_json)
73+
74+
phy_id = int(phy_id)
75+
76+
# Find and modify the PHY configuration
77+
phy_found = False
78+
for phy in config.get("phys", []):
79+
if phy.get("phy_id") == phy_id:
80+
phy_found = True
81+
if macsec_supported is None:
82+
# Remove the field if it exists
83+
if "macsec_supported" in phy:
84+
del phy["macsec_supported"]
85+
else:
86+
# Set the field
87+
phy["macsec_supported"] = macsec_supported
88+
break
89+
90+
assert phy_found, f"PHY {phy_id} not found in gearbox_config.json"
91+
92+
# Write modified config back using heredoc
93+
config_str = json.dumps(config, indent=2)
94+
heredoc = "__GEARBOX_JSON__"
95+
rc, _ = dvs.runcmd(
96+
"bash -lc 'cat > {path} <<\"{tag}\"\n{payload}\n{tag}\n'".format(
97+
path=config_path,
98+
tag=heredoc,
99+
payload=config_str,
100+
)
101+
)
102+
assert rc == 0, f"Failed to write modified config to {config_path}"
103+
104+
# Restart DVS to reload configuration
105+
dvs.restart()

0 commit comments

Comments
 (0)