feat(traffic): Report all pairs and add -tx/-length aliases

V0.4.0 -- report now lists ALL 108 pairs, PASS / FAIL / NA alike,
one line per port (two lines per pair). Missing counters render as
'-', so -a becomes the default (the flag is still accepted) and the
long "# NA (no counters): ..." summary line is dropped since every
NA pair is now a visible row. The table printer is generalised to a
column array with per-column alignment, keeping the pad-then-colour
order so ANSI codes do not break the column widths. This is the only
intentional difference from tools/bcm_mibpair_report_V1.1.0.py.

V0.3.3 -- accept -tx / -length as aliases for -c / -l so a tx burst
can be written the way the bcm command reads
("start -u 0 -tx 100 -length 512"); both are validated as positive
integers. Fix --dry-run printing nothing for init/start/stop/report
since V0.3.1, where the new bcm wrapper discarded the "[DRY ]" lines.
Offline report notes now go to stderr so the table on stdout stays
pipe/diff clean.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-17 21:20:36 +08:00
co-authored by Claude
parent 9d61b1aa43
commit 224ddbd21c
@@ -40,6 +40,27 @@
# to the plain text before colouring so the columns stay # to the plain text before colouring so the columns stay
# aligned. Auto-disabled when stdout is not a terminal or # aligned. Auto-disabled when stdout is not a terminal or
# with --tsv; --color / --no-color / TL_COLOR force it. # with --tsv; --color / --no-color / TL_COLOR force it.
# V0.3.3 2026-08-17 Add: -tx / -length aliases for -c / -l so the tx burst can
# be written the way the bcm command reads
# ("start -u 0 -tx 100 -length 512"). Values are validated
# as positive integers; omitted = defaults 100 / 512.
# Fix: --dry-run printed nothing for init/start/stop/report
# since V0.3.1 (the new wrapper discarded the "[DRY ]"
# lines); the commands are listed again.
# V0.4.0 2026-08-17 Change: report now lists ALL 108 pairs, PASS / FAIL / NA
# alike, keeping one line per port (two lines per pair):
# Port TX RX PASS/FAIL
# cd0 4 4 PASS
# cd32 4 4 PASS
# cd204 - - NA
# cd236 - - NA
# Missing counters show '-'. -a is therefore the default
# (the flag is still accepted), and the long
# "# NA (no counters): ..." summary line is dropped because
# every NA pair is now a visible row. This is the only
# intentional difference from
# tools/bcm_mibpair_report_V1.1.0.py, which hides NA pairs
# unless -a is given.
# ============================================================================= # =============================================================================
# #
# The VLAN/port table below is copied verbatim from # The VLAN/port table below is copied verbatim from
@@ -67,11 +88,14 @@
# Options (any order, after the subcommand): # Options (any order, after the subcommand):
# -u|--unit <0|1|all|0,1> bcmcmd unit(s). Default: $TL_UNITS ("0 1") # -u|--unit <0|1|all|0,1> bcmcmd unit(s). Default: $TL_UNITS ("0 1")
# -c|--count <n> tx packet count (default $TL_TX_COUNT) # -c|--count <n> tx packet count (default $TL_TX_COUNT)
# aliases: -tx | --tx
# -l|--length <n> tx packet length (default $TL_TX_LENGTH) # -l|--length <n> tx packet length (default $TL_TX_LENGTH)
# aliases: -length | --len
# -p|--ports <list|all> ps: port list ('all' = plain 'ps', every port) # -p|--ports <list|all> ps: port list ('all' = plain 'ps', every port)
# -T|--tolerance <n> report: allowed |delta| in packets (default 0; # -T|--tolerance <n> report: allowed |delta| in packets (default 0;
# -T 1 absorbs the normal snapshot skew) # -T 1 absorbs the normal snapshot skew)
# -a|--all report: also list pairs that have no counters # -a|--all report: accepted for compatibility -- every pair is
# listed by default, NA included
# -g|--grouped report: comma-group the values (1,234,567) # -g|--grouped report: comma-group the values (1,234,567)
# -P|--with-port report: render cd1(2) instead of cd1 # -P|--with-port report: render cd1(2) instead of cd1
# -q|--quiet report: drop the trailing summary comments # -q|--quiet report: drop the trailing summary comments
@@ -283,7 +307,8 @@ TL_BENIGN_REMOVE="${TL_BENIGN_REMOVE:-Entry not found|not found|does not exist|n
_tl_bcm_run() { _tl_bcm_run() {
local unit="$1" benign="$2"; shift 2 local unit="$1" benign="$2"; shift 2
local cmd="$*" out rc local cmd="$*" out rc
if [ "$TL_DRY_RUN" = "1" ]; then _tl_bcm "$unit" "$cmd" >/dev/null; return 0; fi # dry-run: let _tl_bcm print the "[DRY ] bcmcmd ..." line, run nothing
if [ "$TL_DRY_RUN" = "1" ]; then _tl_bcm "$unit" "$cmd"; return 0; fi
_tl_dbg "$BCMCMD_CMD -n $unit -c '$cmd'" _tl_dbg "$BCMCMD_CMD -n $unit -c '$cmd'"
out=$("$BCMCMD_CMD" -n "$unit" -c "$cmd" </dev/null 2>&1); rc=$? out=$("$BCMCMD_CMD" -n "$unit" -c "$cmd" </dev/null 2>&1); rc=$?
[ "$DEBUG_MODE" = "1" ] && [ -n "$out" ] && echo "$out" [ "$DEBUG_MODE" = "1" ] && [ -n "$out" ] && echo "$out"
@@ -319,6 +344,9 @@ _tl_units_check() {
_tl_pair_count() { echo "$TL_PAIRS" | grep -c . ; } _tl_pair_count() { echo "$TL_PAIRS" | grep -c . ; }
# positive integer? (tx count / length come straight from the command line)
_tl_is_uint() { case "$1" in ''|*[!0-9]*) return 1 ;; 0) return 1 ;; *) return 0 ;; esac; }
# === Step 1: VLAN loopback setup (traffic_loopback_vlan_setting.ttl) ========= # === Step 1: VLAN loopback setup (traffic_loopback_vlan_setting.ttl) =========
traffic_linespeed_init() { traffic_linespeed_init() {
_tl_units_check || return 1 _tl_units_check || return 1
@@ -369,6 +397,8 @@ traffic_linespeed_show() {
# === Step 4: start traffic (traffic_loopback_start.ttl) ===================== # === Step 4: start traffic (traffic_loopback_start.ttl) =====================
traffic_linespeed_start() { traffic_linespeed_start() {
_tl_units_check || return 1 _tl_units_check || return 1
_tl_is_uint "$TL_TX_COUNT" || { _tl_err "tx count '$TL_TX_COUNT' is not a positive integer (-tx|-c <n>)"; return 1; }
_tl_is_uint "$TL_TX_LENGTH" || { _tl_err "tx length '$TL_TX_LENGTH' is not a positive integer (-length|-l <n>)"; return 1; }
local unit vid pa pb n fail local unit vid pa pb n fail
for unit in $TL_UNITS; do for unit in $TL_UNITS; do
n=0; fail=0 n=0; fail=0
@@ -480,6 +510,12 @@ _tl_pair_report() {
NP = split(PAIRS, L, "\n") NP = split(PAIRS, L, "\n")
for (i = 1; i <= NP; i++) { split(L[i], f, " "); VID[i] = f[1]; A[i] = f[2]; B[i] = f[3] } for (i = 1; i <= NP; i++) { split(L[i], f, " "); VID[i] = f[1]; A[i] = f[2]; B[i] = f[3] }
MISSING = "-" MISSING = "-"
NC = 4
HDR[1] = "Port"; AL[1] = 0
HDR[2] = "TX"; AL[2] = 1
HDR[3] = "RX"; AL[3] = 1
HDR[4] = "PASS/FAIL"; AL[4] = 1
VCOL = NC # the verdict is always the last column
} }
{ {
idx = index($0, "MIB_") idx = index($0, "MIB_")
@@ -512,10 +548,9 @@ _tl_pair_report() {
oka = (a in HTX) && (a in HRX); okb = (b in HTX) && (b in HRX) oka = (a in HTX) && (a in HRX); okb = (b in HTX) && (b in HRX)
if (!(oka && okb)) { if (!(oka && okb)) {
v = "NA"; nna++ v = "NA"; nna++
miss = miss (miss == "" ? "" : " ") a "/" b # every pair is listed, NA included; absent counters show '-'
if (!ALL) continue ta = (a in HTX) ? grp(TX[a]) : MISSING; ra = (a in HRX) ? grp(RX[a]) : MISSING
ta = oka ? grp(TX[a]) : MISSING; ra = oka ? grp(RX[a]) : MISSING tb = (b in HTX) ? grp(TX[b]) : MISSING; rb = (b in HRX) ? grp(RX[b]) : MISSING
tb = okb ? grp(TX[b]) : MISSING; rb = okb ? grp(RX[b]) : MISSING
} else { } else {
dtx = TX[a] - RX[b]; drx = RX[a] - TX[b] dtx = TX[a] - RX[b]; drx = RX[a] - TX[b]
d = absd(dtx); if (absd(drx) > d) d = absd(drx) d = absd(dtx); if (absd(drx) > d) d = absd(drx)
@@ -528,28 +563,37 @@ _tl_pair_report() {
ta = grp(TX[a]); ra = grp(RX[a]); tb = grp(TX[b]); rb = grp(RX[b]) ta = grp(TX[a]); ra = grp(RX[a]); tb = grp(TX[b]); rb = grp(RX[b])
} }
nrep++ nrep++
nrow++; C0[nrow] = pname(a); C1[nrow] = ta; C2[nrow] = ra; C3[nrow] = v nrow++; CELL[nrow,1] = pname(a); CELL[nrow,2] = ta; CELL[nrow,3] = ra; CELL[nrow,4] = v
nrow++; C0[nrow] = pname(b); C1[nrow] = tb; C2[nrow] = rb; C3[nrow] = v nrow++; CELL[nrow,1] = pname(b); CELL[nrow,2] = tb; CELL[nrow,3] = rb; CELL[nrow,4] = v
} }
H0 = "Port"; H1 = "TX"; H2 = "RX"; H3 = "PASS/FAIL"
if (TSV) { if (TSV) {
print H0 "\t" H1 "\t" H2 "\t" H3 line = HDR[1]
for (r = 1; r <= nrow; r++) print C0[r] "\t" C1[r] "\t" C2[r] "\t" C3[r] for (c = 2; c <= NC; c++) line = line "\t" HDR[c]
} else { print line
w0 = length(H0); w1 = length(H1); w2 = length(H2); w3 = length(H3)
for (r = 1; r <= nrow; r++) { for (r = 1; r <= nrow; r++) {
if (length(C0[r]) > w0) w0 = length(C0[r]) line = CELL[r, 1]
if (length(C1[r]) > w1) w1 = length(C1[r]) for (c = 2; c <= NC; c++) line = line "\t" CELL[r, c]
if (length(C2[r]) > w2) w2 = length(C2[r]) print line
if (length(C3[r]) > w3) w3 = length(C3[r])
} }
w0 += 2; w1 += 2; w2 += 2; w3 += 2 } else {
printf "%-*s%*s%*s%*s\n", w0, H0, w1, H1, w2, H2, w3, H3 for (c = 1; c <= NC; c++) {
w[c] = length(HDR[c])
for (r = 1; r <= nrow; r++) if (length(CELL[r, c]) > w[c]) w[c] = length(CELL[r, c])
w[c] += 2
}
for (c = 1; c <= NC; c++) printf(AL[c] ? "%*s" : "%-*s", w[c], HDR[c])
printf "\n"
for (r = 1; r <= nrow; r++) { for (r = 1; r <= nrow; r++) {
# pad on the plain text, then colour, so the columns stay aligned for (c = 1; c <= NC; c++) {
printf "%-*s%*s%*s", w0, C0[r], w1, C1[r], w2, C2[r] if (c == VCOL) {
printf "%*s%s\n", w3 - length(C3[r]), "", vc(C3[r]) # pad on the plain text, then colour, so columns stay aligned
printf "%*s%s", w[c] - length(CELL[r, c]), "", vc(CELL[r, c])
} else {
printf(AL[c] ? "%*s" : "%-*s", w[c], CELL[r, c])
}
}
printf "\n"
} }
} }
@@ -559,7 +603,7 @@ _tl_pair_report() {
printf "# pairs reported : %d\n", nrep printf "# pairs reported : %d\n", nrep
printf "# %s %d %s %d %s %d (tolerance %d)\n", \ printf "# %s %d %s %d %s %d (tolerance %d)\n", \
vc("PASS"), npass, vc("FAIL"), nfail, vc("NA"), nna, TOL + 0 vc("PASS"), npass, vc("FAIL"), nfail, vc("NA"), nna, TOL + 0
if (miss != "") printf "# %s (no counters): %s\n", vc("NA"), miss # every NA pair is a visible row -> no long "no counters" list needed
for (i = 1; i <= nf; i++) print redl(FL[i]) for (i = 1; i <= nf; i++) print redl(FL[i])
} }
exit (nfail || nna) ? 2 : 0 exit (nfail || nna) ? 2 : 0
@@ -572,13 +616,14 @@ traffic_linespeed_report() {
# -f <log>: offline mode, no DUT access, no unit loop # -f <log>: offline mode, no DUT access, no unit loop
if [ -n "$TL_REPORT_FILE" ]; then if [ -n "$TL_REPORT_FILE" ]; then
[ -r "$TL_REPORT_FILE" ] || { _tl_err "cannot read log '$TL_REPORT_FILE'"; return 1; } [ -r "$TL_REPORT_FILE" ] || { _tl_err "cannot read log '$TL_REPORT_FILE'"; return 1; }
_tl_info "report from log: $TL_REPORT_FILE (tolerance $TL_TOLERANCE)" # note on stderr so the table on stdout stays pipe/diff clean
_tl_info "report from log: $TL_REPORT_FILE (tolerance $TL_TOLERANCE)" >&2
_tl_pair_report "$TL_REPORT_FILE"; return $? _tl_pair_report "$TL_REPORT_FILE"; return $?
fi fi
_tl_units_check || return 1 _tl_units_check || return 1
if [ "$TL_DRY_RUN" = "1" ]; then if [ "$TL_DRY_RUN" = "1" ]; then
for unit in $TL_UNITS; do _tl_bcm "$unit" "show c" >/dev/null; done for unit in $TL_UNITS; do _tl_bcm "$unit" "show c"; done
return 0 return 0
fi fi
@@ -627,17 +672,17 @@ blanton_traffic_linespeed_help() {
echo -e " \033[33mstart\033[0m step 4 tx <count> length=<len> VLantag=<vid> per VLAN" echo -e " \033[33mstart\033[0m step 4 tx <count> length=<len> VLantag=<vid> per VLAN"
echo -e " \033[33mstop\033[0m step 5 vlan remove <vid> pbm=<pair> [--destroy also destroys]" echo -e " \033[33mstop\033[0m step 5 vlan remove <vid> pbm=<pair> [--destroy also destroys]"
echo -e " \033[33mps\033[0m ps <portlist> port status (link/speed) of the cabled ports" echo -e " \033[33mps\033[0m ps <portlist> port status (link/speed) of the cabled ports"
echo -e " \033[33mreport\033[0m show c -> per-pair TX/RX table + PASS/FAIL cross-check" echo -e " \033[33mreport\033[0m show c -> per-port TX/RX per pair + PASS/FAIL/NA cross-check"
echo -e " \033[33mrun\033[0m ps -> init -> clear -> start -> report" echo -e " \033[33mrun\033[0m ps -> init -> clear -> start -> report"
echo -e " \033[33mhelp\033[0m" echo -e " \033[33mhelp\033[0m"
echo "" echo ""
echo -e "\033[1mOptions\033[0m" echo -e "\033[1mOptions\033[0m"
echo -e " \033[33m-u|--unit\033[0m <0|1|all> bcmcmd unit(s); 'all' = 0 1 (default: $TL_UNITS)" echo -e " \033[33m-u|--unit\033[0m <0|1|all> bcmcmd unit(s); 'all' = 0 1 (default: $TL_UNITS)"
echo -e " \033[33m-c|--count\033[0m <n> tx packet count (default $TL_TX_COUNT)" echo -e " \033[33m-c|--count|-tx\033[0m <n> tx packet count (default $TL_TX_COUNT)"
echo -e " \033[33m-l|--length\033[0m <n> tx packet length (default $TL_TX_LENGTH)" echo -e " \033[33m-l|--length|-length\033[0m <n> tx packet length (default $TL_TX_LENGTH)"
echo -e " \033[33m-p|--ports\033[0m <list> ps port list, or 'all' for every port" echo -e " \033[33m-p|--ports\033[0m <list> ps port list, or 'all' for every port"
echo -e " \033[33m-T|--tolerance\033[0m <n> report: allowed |delta| pkts (default $TL_TOLERANCE; -T 1 = snapshot skew)" echo -e " \033[33m-T|--tolerance\033[0m <n> report: allowed |delta| pkts (default $TL_TOLERANCE; -T 1 = snapshot skew)"
echo -e " \033[33m-a|--all\033[0m report: also list pairs with no counters" echo -e " \033[33m-a|--all\033[0m report: kept for compatibility (all pairs are listed)"
echo -e " \033[33m-g|--grouped\033[0m report: comma-group values" echo -e " \033[33m-g|--grouped\033[0m report: comma-group values"
echo -e " \033[33m-P|--with-port\033[0m report: render cd1(2) instead of cd1" echo -e " \033[33m-P|--with-port\033[0m report: render cd1(2) instead of cd1"
echo -e " \033[33m-q|--quiet\033[0m report: no trailing summary" echo -e " \033[33m-q|--quiet\033[0m report: no trailing summary"
@@ -658,7 +703,8 @@ blanton_traffic_linespeed_help() {
echo -e " blanton_traffic_linespeed report -u 1 -q | grep -v PASS" echo -e " blanton_traffic_linespeed report -u 1 -q | grep -v PASS"
echo -e " blanton_traffic_linespeed report -f /tmp/showc_unit1_*.log -a" echo -e " blanton_traffic_linespeed report -f /tmp/showc_unit1_*.log -a"
echo -e " blanton_traffic_linespeed show -u 1 | grep -iE 'error|discard|drop'" echo -e " blanton_traffic_linespeed show -u 1 | grep -iE 'error|discard|drop'"
echo -e " blanton_traffic_linespeed start -c 1000 -l 9216 -d" echo -e " blanton_traffic_linespeed start -u 0 -tx 100 -length 512"
echo -e " blanton_traffic_linespeed start -tx 100000 -length 9216 -d"
echo -e " blanton_traffic_linespeed stop --destroy" echo -e " blanton_traffic_linespeed stop --destroy"
echo "" echo ""
echo -e " report exit code: 0 = all pairs PASS, 2 = any FAIL/NA, 1 = parse error" echo -e " report exit code: 0 = all pairs PASS, 2 = any FAIL/NA, 1 = parse error"
@@ -679,8 +725,8 @@ blanton_traffic_linespeed() {
*) TL_UNITS="$2" ;; *) TL_UNITS="$2" ;;
esac esac
shift 2 ;; shift 2 ;;
-c|--count) TL_TX_COUNT="$2"; shift 2 ;; -c|--count|-tx|--tx) TL_TX_COUNT="$2"; shift 2 ;;
-l|--length) TL_TX_LENGTH="$2"; shift 2 ;; -l|-length|--length|--len) TL_TX_LENGTH="$2"; shift 2 ;;
-p|--ports) TL_PS_PORTS="$2"; shift 2 ;; -p|--ports) TL_PS_PORTS="$2"; shift 2 ;;
-T|--tolerance) TL_TOLERANCE="$2"; shift 2 ;; -T|--tolerance) TL_TOLERANCE="$2"; shift 2 ;;
-f|--file) TL_REPORT_FILE="$2"; shift 2 ;; -f|--file) TL_REPORT_FILE="$2"; shift 2 ;;