From 430addcf2070c93c5084ca498fda9c8d46ff822e Mon Sep 17 00:00:00 2001 From: Rayhaan Jaufeerally Date: Wed, 7 Oct 2026 23:19:56 +0200 Subject: [PATCH] Status page: IPv6 first in a neighbour's pair of sessions Of -v6 and -v4, the IPv6 session is listed first and carries the name in full; IPv4 is under it. The same order in the lookup's list of peers. Co-Authored-By: Claude Fable 5.1 --- crates/web/static/statusz.html | 19 ++++++++++++++----- docs/content/docs/operations/monitoring.md | 4 ++-- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/crates/web/static/statusz.html b/crates/web/static/statusz.html index 5b53fd1..bc7f4dd 100644 --- a/crates/web/static/statusz.html +++ b/crates/web/static/statusz.html @@ -412,6 +412,17 @@ from return p.state === 'Established' && p.expected_routes > 0 && p.routes != null && p.routes < p.expected_routes / 2 && now() - p.established_at_unix > SETTLING_SECS; } + // Peers in name order, except that the IPv6 session of a neighbour + // (-v6) comes before its IPv4 one: IPv6 is the network's present, + // IPv4 what is still carried along. + const FAMILY_SUFFIX = /^(.*)-v([46])$/; + function nameOrder(a, c) { + const [sa, fa] = FAMILY_SUFFIX.exec(a)?.slice(1) || [a, '']; + const [sc, fc] = FAMILY_SUFFIX.exec(c)?.slice(1) || [c, '']; + return sa.localeCompare(sc) || fc.localeCompare(fa); + } + const byName = (a, c) => nameOrder(a.name || a.peer_addr, c.name || c.peer_addr); + // Where a peer stands, for the strip and for sorting: 0 failed, 1 // degraded, 2 normal, 3 inactive and expected. function peerRank(p) { @@ -524,9 +535,8 @@ from if (!peers.length) { setHTML(b, 'No peers configured and none connected.'); return; } const problemsOnly = $('peers-problems').checked; // The IPv4 and IPv6 sessions of one neighbour, named -v4 and - // -v6, are one neighbour to the reader: listed together, the - // name once in full and once quietly, joined down the side. - const FAMILY_SUFFIX = /^(.*)-v([46])$/; + // -v6, are one neighbour to the reader: listed together, IPv6 + // first, the name once in full and once quietly, joined down the side. const row = (p, pair) => { const up = p.state === 'Established'; const family = p.name && FAMILY_SUFFIX.exec(p.name); @@ -559,7 +569,6 @@ from if (sameStem(list[i - 1])) return row(p, 'pair-b'); return row(p); }).join(''); - const byName = (a, c) => (a.name || a.peer_addr).localeCompare(c.name || c.peer_addr); let html = ''; // What needs attention first, whoever it is; then everyone by what // they are to us. @@ -661,7 +670,7 @@ from function renderPeerChoices() { const chosen = lookup().peer; const names = [...new Set(state.peers.filter(p => p.state === 'Established') - .map(p => p.name || p.peer_addr.replace(/:\d+$/, '').replace(/^\[|\]$/g, '')))].sort(); + .map(p => p.name || p.peer_addr.replace(/:\d+$/, '').replace(/^\[|\]$/g, '')))].sort(nameOrder); if (chosen && !names.includes(chosen)) names.push(chosen); setHTML($('lookup-peer'), '' + names.map(n => ``).join('')); diff --git a/docs/content/docs/operations/monitoring.md b/docs/content/docs/operations/monitoring.md index 637ae78..662d1b6 100644 --- a/docs/content/docs/operations/monitoring.md +++ b/docs/content/docs/operations/monitoring.md @@ -40,8 +40,8 @@ Below the status line, the page displays the following information: session properties, number of accepted routes, rejected announcements, and held routes, and its last error. Neighbors that need attention are listed first; the others are grouped by role. The IPv4 and IPv6 sessions - of one neighbor, named `NAME-v4` and `NAME-v6`, are listed together and - joined by a bar. The **problems only** option hides the neighbors that + of one neighbor, named `NAME-v4` and `NAME-v6`, are listed together, + IPv6 first, and joined by a bar. The **problems only** option hides the neighbors that need no attention; the **compact** option removes the next hop and session columns, for a small or distant screen, and is remembered by the browser.