Skip to content

v2.11.0 Release Changes - #1367

Open
tvancott42 wants to merge 945 commits into
mainfrom
release/2.11
Open

tvancott42 wants to merge 945 commits into
mainfrom
release/2.11

Conversation

@tvancott42

Copy link
Copy Markdown
Collaborator

Release changes for v2.11.0, rebase-merged from release/2.11. Commits that main already has from the v2.10.x patches drop out of the rebase.

Change Control is the headline. Every configuration Change on a Site is recorded as it happens: who made it (an admin, Network Optimizer, or UniFi on its own), which fields moved, the Security Audit impact, and latency, throughput, and Wi-Fi Clients in the hour after. Site Health scores each Site hourly. Incidents list the Changes from the two hours before them, each with Roll Back. Snapshots + Templates compares Snapshots and applies Templates as a delta. Edit is a YAML editor for every config collection, with search, + Add, and masked secrets. Every apply is a Review Plan, with lockout checks, acknowledgements, and commit-confirmed revert on the management or WAN path. Migrate / Restore covers Restore a Snapshot, Replace Device, Set Up Zones, Translate Legacy Rules, and Re-address Networks.

Also new in v2.11.0:

Fixes:

Agent

The Agent's link closure changed since v2.10.7. Change Control's commit-confirmed rollback runs through the On-Site Agent, and Automatic Blocking is hooked in once on an On-Gateway Agent (#1351). LatestAgentVersion is 2.11.0-preview19: the closure has not changed since that preview (later commits touch only Core helpers the Agent never calls). RequiredAgentVersion is unchanged.

Release checks

  • dev fully merged forward: git log origin/release/2.11..origin/dev is empty.
  • Tour: wwwroot/data/tours/2.11.0.json, 8 steps.
  • Feature index: complete. The last two lines are in 1e7e6b1.

tvancott42 and others added 30 commits November 2, 2026 13:19
… folded object shows its edits

The marks along the scrollbar were placed over the scroller's whole
height by content height. The track runs between the scrollbar's arrow
buttons, and the bar maps the scroller's full scroll height, padding
included, so a mark near the top sat on the up arrow, above the thumb,
while its line was on screen. Marks now go on the scroll height scale
from the document's offset in the scroller, over the track between the
arrows (each as tall as the bar is wide; an overlay scrollbar has none).

An edit inside a folded object showed no gutter mark: folding hid the
line it was on. A fold whose hidden lines hold edits now marks its
first line, "added" when every hidden mark is, else "modified"
(foldedEditMarks), and the gutter redraws when a fold opens or closes.
…urity Audit Check

The check ran and returned, but CcZones never re-rendered: the rename comes through
InlineEditField's Save handler, and Blazor re-renders only the component whose handler
fired. Moves and toggles are CcZones handlers, so they re-rendered on their own.
RefreshAsync now renders when it finishes.
…sioning

On Snapshots, Edit, and Migrate / Restore (desktop), the right of the tab row reads
Gateway provisioning while any adopted gateway is not connected, Gateway provisioned
for 15 seconds once it settles, then Gateway ready. It polls every 5 seconds through a
Viewer-gated GetGatewayProvisioningAsync, which reuses the plan gates' stat/device check
with a 4-second cache so open tabs share one read. The plan gates keep a fresh read.
…eway is provisioning

The gateway indicator sits in Review Plan's sticky footer, beside Apply, which waits while the
gateway provisions. Desktop puts it before the buttons; a phone gives it its own line under
the state track. The tab-row indicator stays desktop-only (CcGatewayStatus Mobile parameter).
…ce policy a zone delete takes

The note came from the zone-wide copy path, so it named only the policy that path met
(Net. Opt. Public Lists (Outbound)) while the plan deleted all eight of the emptied zone's.
The note now lists every Threat Intelligence policy the copy skips or the zone delete takes,
in console order, and says Threat Intelligence writes its own for the zones left.
…s chosen

Changes reports its site filter to the tab row, which shows that site's gateway state.
The check goes through the fleet service (Viewer, site access checked), on the same
cached stat/device read as the other tabs.
…arsed rule

OperatorAllow matched raw policy JSON (action, enabled, predefined, zones). It now parses
through ZonePaths.Parse and takes the Audit's FirewallRule: enabled, an allow action,
AllowsNewConnections, not predefined, in the zone pair. Any scope still counts (#1332).
The Set Up Zones description marker stays a JSON read: it is config identity.

Characterization first (Board_ExceptionCoverage_ByRuleShape, 8 shapes): only a
RESPOND_ONLY allow changed verdict. It opens no new connections, so it no longer marks
an exception covered. The allows are parsed once per board and per plan, not per pair.
A search icon beside the Collections title opens a search field in its place,
focused. Enter counts the query in every collection (loading the ones not
opened yet), shows each collection's match count in the list, and goes to the
first match from the open collection on. Enter / Shift+Enter and the pager
step through matches across collections; Escape closes.

Matches are case-insensitive literal text over the YAML, so field names and
values both match; masked secret tokens are skipped. The editor highlights
them with CodeMirror's search-match classes, now themed in cc-editor.js so the
Ctrl+F panel and this search look the same. Discard, Start from, Upload, and a
switch of what is edited clear the results.
…names people use

A query that names a collection or list the way people say it also finds the
name the YAML gives it: VLAN finds networks, client devices finds clients,
UniFi devices finds devices, SSID / Wi-Fi / wireless find wlans, and similar
for firewall groups, port forwards, Local DNS, Dynamic DNS, traffic routes,
port overrides, link aggregation groups, private pre-shared keys, SAE (WPA3),
RADIUS servers, IP aliases, allow and block lists, regions, and the SIM.
Aliases are one way, and a plural query finds them and its own singular.

A space in the query also matches "_", "-", or nothing, so "port forward"
finds port_forwards and "user group" finds usergroup without an alias.

CcFind owns the alias table and hands the expanded terms to the editor, so
the server's counts and the editor's highlights match the same text.
The search runs 300 ms after typing pauses; Enter still searches at once, and
on results already current steps to the next match. A newer search supersedes
one still reading collections. The previous results and highlight stay up
until the new ones replace them, and "Searching..." shows only while
collections not opened yet are read, so typing does not flicker. A query with
no match anywhere clears the old highlight.
…rk Optimizer reaches the site from

Since the lockout checks moved to the Audit's engine, an IP source with Match Opposite is honored, but
the Audit's source match has no zone. A block into the Gateway zone from IoT, Cameras, or any zone that
holds none of Network Optimizer's networks, sourced "every address except a group", was flagged as a
Possible lockout with typed confirmation. Set Up Zones splits such a block into each new zone, and a
rename of one of those copies in Edit raised it too.

An address now counts only when its network sits in the policy's source zone; an address in no zoned
network counts only for a source zone that is not a LAN zone.
…names

Alias keys now match a query with "-" or "_" for a space, so
"policy-based route" finds its alias as "policy based route" did. Added
policy-based routing, selective routing, and device-based routing (all
traffic_routes), and load balancing / WAN load balancing (the
wan_load_balance_* keys and the radio loadbalance_enabled). "failover" needs
no alias: the keys and the failover-only value hold the word.
…aches the site from

Only a Set Up Zones plan used the routed source; every other plan judged every address the host owns. A
host with a leg on several VLANs then "reached the site" from each of them: renaming a gateway block
sourced from IoT, "every address except a group", raised a Possible lockout with typed confirmation
because the server has an IoT address the group does not list, though it never manages from it.

Every plan now uses the routed source, except one that moves a subnet (Re-address), where the route can
change and every host address still counts.
…ollection opens on its first match

With a search active, a collection picked from the Collections list opens on
its first match, opening any fold over it, as paging into it does. Before, it
opened where it was last left and the match stayed folded away.

Aliases: switches, APs / access points, gateways, and routers find the
devices collection and the lists only that kind of device has (port_overrides
and switch_vlan_enabled; radio_table and the AP group lists). The YAML carries
no device type: type and model are read-only and not exported. "DNS server"
finds the numbered server fields (dns1/dns2, wan_dns1, wan_ipv6_dns2,
dhcpd_dns_1..4, dhcpdv6_dns_1..4).

Plurals in -ches, -shes, and -xes now drop "es" ("switches" looks up
"switch"), and a singular under four letters is not added as a term ("APs"
would otherwise match "ap" inside half the field names).
Added aliases for names people use where UniFi's YAML name differs, each
checked against a full site export:

- DHCP: dhcp server (dhcpd_*), dhcp range / pool, PXE / network boot,
  DHCP snooping, rogue DHCP, reservation / DHCP reservation / static IP
  (fixed_ip, use_fixedip), inform URL
- IPv6: prefix delegation, router advertisement
- Wi-Fi: 2.4 / 5 / 6 GHz (UniFi's ng, na, 6e fields and radio values),
  channel width, transmit power, minimum RSSI, minimum data rate, 802.11r,
  802.11v, multicast enhancement, hidden SSID, captive / guest portal,
  client isolation, WPA2, encryption, PMF, MLO, Passpoint / Hotspot 2.0,
  lock to AP
- Switching: native / untagged VLAN, voice VLAN, trunk, 802.1X, spanning
  tree, storm control, PoE, EEE, autonegotiation, Etherlighting, LCD /
  screen, PTP
- Gateway and security: SQM, AQM, fq_codel, smart queues (wan_smartq),
  public IP, bandwidth / speed limit, MSS clamping, DPI, IPS / IDS / threat
  management, geoblocking, DNS over HTTPS / encrypted DNS, Bonjour /
  multicast DNS, data cap, auto / firmware update

A "-" or "_" in a query now works as a space does (matches any of the three
or nothing), so "NAT-PMP" finds upnp_nat_pmp_enabled. A query of only
separators finds nothing instead of matching everywhere.
Finds the rate limits (download_limit, upload_limit, qos_rate_max), the
Smart Queues rates, and Wi-Fi channel width (channel_width, ht_modes_*).
radio_table's ht field is left out: as a term it also matches "weight:".
…160 MHz

The YAML holds channel width as a number (channel_width: 160, radio_table's
ht: 160), so "bw160", "BW 160", "160 MHz", and "160mhz" search for that
width on both. A bare "bw" works as "bandwidth".
…vers

"local DNS", "local DNS server", "LAN DNS", and "LAN DNS server" find the
DNS servers a LAN hands its clients (dhcpd_dns_*, dhcpdv6_dns_*). "local DNS"
still finds Local DNS and the clients' local_dns_record too.
Where a letter meets a digit in a query, the YAML may have a "_" or "-"
between, so "dns1" finds dhcpd_dns_1 and dhcpdv6_dns_1 as well as dns1 and
wan_dns1. "dns_1" already found dns1 through the separator rule, so the two
now match both ways. Applied in CcFind and the editor's termPattern alike.

The local and LAN DNS aliases also find each device's own DNS servers on its
management IP (config_network dns1, dns2), and "device DNS" finds those with
dnssuffix.
…e's agent coverage (#1343)

* Path Localization: a resumed episode's server vantage follows the site's agent coverage

ExecutorFor ran any vantage without an agent id on the server's LocalProbeExecutor. On
restart, RebuildRun rebuilds each open episode target's vantage from its last stored trace.
A target with no trace yet falls back to the WAN context's agent id, which is null for most
contexts. A restart during the first rounds of an episode therefore traced and pinged that
target from the central server, even on a secondary site or on a default site its agent
covers, and stored the server's path as the site's evidence.

The no-agent vantage now resolves the way ProbeExecutorFactory.GetServer does, through
SiteAgentCoverage.AgentOwnsPathMeasurement. A named agent is unchanged, and so is an
uncovered default site.

* Path Localization: a resumed target adopts its live vantage, and the fallback binds like the agent push

A resumed target with no trace yet guesses its vantage from the WAN context. The guess now
binds the way AgentProbeResultSink pushes the context's agent (interface, else source IP),
so an on-gateway agent context resumes on its WAN interface instead of the default route.

The guess is also replaced by the target's first live observation after the restart. That
names the exact agent and bind, including for an unassigned target on a site with several
agents, where the unnamed executor would run on whichever agent connected first. Hop pings
hold their target's id and take its current vantage each round, so they follow the adoption.

SiteAgentCoverage is now a required constructor parameter. PathVantage.FromLabel replaces two
copies of the "agent-N" parse.
… and goes shows where it starts

The hop table took each hop's minimum RTT twice: within a trace (removes slow-path ICMP) and
across the episode's traces. The second kept only the best trace, so an intermittent rise
always read as no change: Speedtest ORD was slower in 6 of 10 traces, 43 to 70 ms against 32,
and the table said 32.8 to 32.3 ms. The hop decision read the same value, so no hop could be
elevated by a rise that came and went.

Each hop now keeps every trace's minimum. The table shows their median, normal to during,
over one bar per trace (amber when slower). A hop counts as slower in a trace when it rises
past the existing hop threshold over its recovery or control baseline, else over its own
fastest trace. A hop that slows in most of the traces the destination slowed in is elevated
(PathHopMinPairedRounds, 2 slow destination traces before pairing applies). The elevated-run
rule is unchanged, so a noisy hop the next hop does not follow stays ICMP-limited. Tooltips
say how each hop did against the destination; the PDF adds "slower in N of M traces".

An episode that has used its traces stays open until its targets clear. It no longer claims
"Tracing now": its badge is Ongoing, and its banner says how many times it traced and that one
more trace follows recovery.
… not read as a path problem

Replayed all 25 stored episodes on the test sites through the analyzer before and after the
per-trace change. On the Starlink WAN, a handover moves the first hop and every hop after it in
the same traces, so most hops paired with the destination and the onset landed wherever the
noisy middle hops let the run start: episode 12 read "starts inside Google", Confirmed.

- Pairing places the start only at a hop the trace decides (not monitored, not an access hop),
  right after a responding hop that stayed fast in every slow destination trace. With no such
  clean point the swing is upstream of everything, and pairing places nothing.
- A hop is slower against its own second-fastest trace in the episode, not the recovery or
  control trace: those are one moment, which on a jittery link sits above most traces and hides
  which ones moved, and one lucky trace no longer makes every other one slow.
- The steady-rise arm goes back to best trace against the baseline trace, like for like. The
  median sits above a one-trace minimum on any jittery link with nothing wrong.

Replay after: 2 of 25 change, both on the fiber WAN. Episode 15 gains a Confirmed start inside
the Linode ORD data center (its border router held 38 ms in all ten traces while everything past
it rose in six); episode 18 tags three noisy Linode hops ICMP-limited. No Starlink episode changes.

Also: a Custom target linked from an episode opens on the episode's WAN, which its trace went out
over, not every WAN. Fabric targets still ask for every WAN.
…iable, and names the return path

Pairing shows that the hops from a point on slowed in the same traces as the destination, not
which way. A hop's RTT includes its reply's way home, so the same pattern appears when the hops
from there send replies home over a congested return path the routers before them do not use.

A return trace from the Speedtest ORD box showed exactly that: the return path leaves Akamai at a
Chicago interconnect into the next network, and mtr there read best 1.1 ms, average 32.9 ms, with
the rise carried to the access ISP's edge. The forward hops inside the Linode fabric share that
return path, so episode 15's Confirmed start between the Akamai border and the first Linode hop was
the return path.

When the onset hop was elevated by pairing alone, the verdict is Unverifiable: "The problem first
shows at X, and every router after it shows it too. Their replies may come home a different way
than the routers before it, so it could be on the return path." The hop table is unchanged.
tvancott42 and others added 30 commits November 7, 2026 21:56
A site's tunnel that drops usually re-registers in 1-3s (seen on the
SaaS instance behind Cloudflare). A console call caught in that gap was
refused with "no agent online", failed TLS, and its single 0.5s retry
landed in the same gap, so the user saw "The SSL connection could not be
established". The proxy now waits up to 8s after a drop for the site's
tunnel to register again, then dials through it. A site that never had a
tunnel, or lost it longer ago, still fails at once.
…s button

Accept as Baseline, Return to Baseline, Roll Back, and the snapshot row
actions showed their error at the bottom of the tab, below Templates and
Console Backups. It now shows in the Drift from Baseline, Compare, or
Snapshots card that holds the button.
…ncelled wait closes its socket

A tunnel the watchdog drops after 45s+ of silence is an outage, so dials
after it keep failing at once instead of waiting 8s per page render. A
dial cancelled during the wait now disposes its local stream, as every
other refusal path does.
…ntrol

Take Snapshot and Compare errors show under the Snapshots header (under
the phone footer on a phone). A snapshot row's Pin, Set as Baseline,
Roll Back To, or YAML error shows under that row. A template's Apply,
Use as Baseline, Clear Baseline, or Delete error shows under its row,
and Save Template and Save show under their form. A UniFi Console
Backups download error shows under its row.

Compare, the YAML view, the YAML download, and Download Diff now catch
their errors; before, a failure went to Blazor's error bar. A failed
YAML view returns to Changes instead of spinning.
…er UniFi sends

An object of two scalars or fewer is written in flow style
({a: 1, b: 2}) in UniFi's JSON order. UniFi Network 11.1 sends
wan_provider_capabilities' download and upload keys in the other order,
so the YAML view showed an unchanged value as removed and re-added. Flow
style now uses the same order as block style: the collection's nested
field order, then alphabetical.
…t too

The 11.1 upgrade filled lte_lan_enabled_devices on five networks (seen in a
Compare across it). It is still the admin's Applies To list, so it stays
editable.
…t was not read

With the console unreachable (an On-Site Agent down), the live read came
back empty and was used as the real config: Compare against Now showed
every object deleted, Download Diff held only its header, the Now row's
YAML downloaded empty, and New Template from live would save no objects.
They now fail with "Could not read the live config.", as Accept as
Baseline does. The snapshot and plan builds use the same unread test.
… the live config

When the console could not be read (an On-Site Agent restarting), Take
Snapshot took no snapshot and showed nothing. It now shows "Could not
read the live config." under the Snapshots header, as Accept as
Baseline does.
… an unread one

Fix it for me, Re-address Networks (preview, plan, and Lower Lease
Times), Set Up Zones, Translate Legacy Rules, Restore a Snapshot, and
the Edit tab's base now read the live config through the unread check,
and fail with "Could not read the live config." With the console
unreachable they worked from an empty config: a misleading preview or
error, and the Edit tab cached the empty base for 30 seconds. Each page
already shows this error type.

Left on the plain read on purpose: Replace Device's device lookup (it
falls back to the latest snapshot) and the Agent revert arm (it runs
mid-apply). Plan builds keep their own check.
…the toolbar wraps

On a desktop width the toolbar wraps, and its YAML and Discard Edits
buttons started the second line at the left. They now sit at the right,
with Discard Edits above the editor's own header buttons.
… site

A plan's ID is a row in the old site's database, so switching sites on
/change-control/plans/{id} opened a different plan or none on the new
site. The switch now lands on Change Control there instead.
… left

The header switcher built its own target and dropped only ?wan= and
Client Performance's ?ip=, so the site-bound rules in SiteSwitchService
(device, client, AP, target, alert, and result IDs, and now a Review
Plan's ID) never applied to it. It now uses the same rules: switching
sites on a Review Plan opens Change Control on the new site.
…shows the run while it starts

The SSH launch for the Network and UniFi OS installs backgrounded the
whole "write && nohup" list. Under bash, the gateway's login shell, that
subshell keeps the session's stdout until the install ends, so every
SSH start hit its 60-second timeout and the rollout recorded the
Network update as refused while it installed. Only nohup is backgrounded
now, and a script that cannot be written fails instead of printing
"started".

A start stays Scheduled or Announced through the backup, the catalog
refresh, and the console's own update, so the page sat on Clear to
Deploy? for the whole of it. The plan now records StartingAt once the
start passes its checks (cleared if the start throws), and the page
shows Rollout Starting with the 2D map from Deploy Now or from that
mark. A mark older than 15 minutes is ignored, so a start the process
died inside does not hide the controls. Running is still set after the
console phase is commanded: a tick before that would read the
untriggered Network update as nothing to do.
…ng view

- The plan is marked starting, still Scheduled, and not yet triggered
  while the Network update is commanded; Running follows.
- A start that throws clears the mark; a start the health gate holds
  never sets it.
- The page's starting rule: a fresh mark or an in-flight Deploy Now on a
  waiting plan only, and a mark older than 15 minutes reads as waiting.
…e console through an agent (#1362)

* Monitoring: a repeated InfluxDB failure logs once an hour, not on every query

A site whose buckets were never provisioned (its admin never opened
Monitoring) still runs collection, so every read fails with "could not find
bucket" and every flush drops its points. One such site logged 4,700
warnings in ten hours, about one every 9 seconds, and each warning also
wrote the same health state to the database.

Each failure message now logs at its own level once an hour; repeats log at
Debug, and a repeated query failure skips the health write, since the stored
state already holds it. A passing health check clears the record, so the
next failure logs and stores again.

* AP Telemetry: create the site's InfluxDB buckets, or say they are missing

A site's buckets are created only by the Monitoring setup wizard, so a Site
Admin can turn on AP Telemetry without them. The AP Agent then runs, but
every per-client Wi-Fi point it writes is dropped, and nothing says so.

SiteInfluxBucketSetup does the wizard's silent step for the current site:
when the site's buckets do not answer and the shared token can already
create buckets (it resolves the org), it creates them through
ISiteInfluxProvisioningService, so the site-scoped gate and the audit event
are unchanged. It uses the site client's own bucket names. It never prompts,
never changes the shared token, leaves the main site to the wizard, and
never throws.

The AP Telemetry tab runs it when it loads with AP Telemetry on and when
AP Telemetry is turned on, off the load path, since an unreachable InfluxDB
can take the client's full timeout to answer. When the buckets still do not
answer, the tab and Wi-Fi Optimizer show a warning with a link to
Monitoring. Wi-Fi Optimizer only checks; it never creates buckets.

Site creation and the wizard are unchanged.

* Multi-Site: Add a site wizard can connect the console through an On-Site Agent

The Console step's secondary button is now Connect Through an Agent instead of
Skip for Now. It runs the Agent step first, with the SSH and UniFi Console proxy
checked and locked, then returns to the Console step. That step waits for the
agent's tunnel before Connect & Save and List Sites enable, because a login
through a tunnel that is not up fails and saves no credentials. The step bar
shows Name, Agent, Console, Done on this path. The reversed Console step keeps
a Skip button; the Agent step's Skip becomes Back to the direct Console step.
Shorter Console step sub-text names the agent path.

* Multi-Site: SiteSetupOptions seam to start the Add a site wizard agent-first

SiteSetupOptions.ConsoleThroughAgentByDefault starts every new site on the
Connect Through an Agent path. Upstream registers nothing, so IOptions yields
the default (off) and behavior is unchanged; a hosted deployment turns it on
with services.Configure<SiteSetupOptions>.

* Monitoring: concurrent InfluxDB query failures warn once, not once per caller

ShouldLogFailure read the last-logged time and then wrote it, so two queries
failing in the same moment both found no entry and both warned (seen as two
identical WRN lines in one millisecond on a site with no buckets). It now
records with TryAdd/TryUpdate, so exactly one caller wins the slot.

* Multi-Site: a removed site reports in the info style, not success green

* Multi-Site: action messages sit next to the action

The Add a site wizard's message renders right under the wizard box instead of
inside it, and the site-row messages (removed, enable/disable and no-console
errors) render right under the site list instead of at the bottom of the tab.
…p was taken

When our pre-flight backup fails, the plan notes that UniFi takes its
own backup before an update through its API. An SSH install (apt-get for
the Network app, ubnt-systool for UniFi OS) skips that backup, so the
note promised a backup that does not exist. When an SSH install is
accepted (first try, pinned build, retry, or UniFi OS), the note now
reads "No backup was taken: ours didn't run, and an SSH install skips
UniFi's own." The API path keeps the original note.
New ap-telemetry predicate: the site's ap_agent.enabled setting, the one the
AP Agent deployment reads, evaluated from the same per-site context as the
other database predicates. Without AP Telemetry the card does not render, so
the 2.11.0 Site Access Points step is filtered out before the driver navigates.
…agent-first is the default

StepOrder read only _agentFirst, which Create Site sets. With
SiteSetupOptions.ConsoleThroughAgentByDefault on, the Name step drew Name, Console, Agent,
Done, and the steps then ran Agent before Console. On step 1 it now reads the option too.
Later steps still follow _agentFirst.
* Re-address Networks: devices find the console at its new address

The dry run's "Point the Inform Host at ... first" warning is replaced by a
per-device verdict (ReaddressInform.Classify, no API calls): not affected,
follows automatically (gateway-hosted console, or the gateway's own LAN
address), follows by DNS (a name the gateway's Local DNS serves and the plan
moves, asked through the gateway), the plan re-points the console, or SSH
fallback. Console type is Firmware Rollout's IsStandaloneConsole.

- A UniFi OS Server in a moved subnet with the Inform Host override off gets
  the override written to its new IP, ordered just before the console-path
  networks (99). On with an IP, the existing rewrite moves it; on with a name,
  the name is kept. Roll Back takes the same order.
- When the re-address watch raises "Network devices offline after", each
  offline device gets set-inform over SSH (DeviceSshRouter), at its new static
  address and then its old one, once per device per plan, 10 s each. A name the
  gateway does not serve becomes its resolved address, mapped (10-27: the
  stranded switch could not resolve the name). DHCP devices with no known
  address and sites without Device SSH are listed with the command instead.
  Each attempt is audited as Network Optimizer. The pass runs off the tick,
  so the watch's timing, misses, severity, and plan status are unchanged, and
  it never writes to the console. Only re-address plans run it.

* Re-address Networks: the hand command adds a host route when the console is on the device's network

A device left on its old address has no route to the console's new one, but
on the same network a /32 route on its own interface reaches it. The alert's
hand command for such a device leads with ip route add <console>/32 dev <if>,
and the alert now says where to run it: SSH to the device at the address
shown, from a host already on the new subnets (the rewritten policies refuse
old-subnet sources). Network Optimizer itself still runs set-inform only.

* Re-address Networks inform: review fixes

- The SSH fallback skips a device whose inform host did not move, and a name
  is replaced by an IP only when it resolves into a moved subnet: set-inform
  would otherwise overwrite a working URL.
- A Console with no UniFi OS answer (a self-hosted Network Application, or
  unreadable) counts as needing re-pointing, not as following by itself.
- The dry run says when Device SSH is not configured instead of promising an
  SSH re-point.
- The gateway is checked against Gateway SSH, which carries its set-inform.
- At most four SSH sessions at once.
- The on-link check maps only the old address (a swap mapped the new one twice).
- A static device whose DNS is any gateway address follows by DNS.
- A DHCP device's hand line names its last address.
- A device reached at its old address on the Console's network still gets the
  hand command with the host route: set-inform runs there but cannot connect.
- The per-plan attempt record is dropped when the watch ends.

* Re-address Networks inform: a device at its old address gets the Console's IP

A device that never got its new config keeps its old DNS server, the old
gateway address, which is gone after the move, so it cannot resolve any name.
set-inform dialed at the new static keeps a name the gateway serves; dialed at
the old static it sends the Console's new IP, taken from the moved Local DNS
record. The hand command with the host route uses the IP too.

* Re-address Networks inform: every override write goes just before the console path; no override at a gateway address

- An Inform Host override already on with an IP was rewritten as the plan's
  first write (setting order 1). Its new address is dead until the console's
  host moves, so devices lost the console before their own writes landed. It
  now takes the same slot as the new override write (99), and so does its
  Roll Back.
- A console whose inform address is a gateway LAN address never gets an
  override write, even when its type did not read.

* Re-address Networks: the Default network shows VLAN 1, not Untagged

Untagged is a per-port setting; the network with no VLAN ID is UniFi's
Default network, VLAN 1, which is also what the pattern's {vlan} uses.

* Change Control: the Default network reads VLAN 1 in the Pattern tooltip and the Migrate name-match note

Untagged is a per-port setting, not a network's. The Pattern tooltip drops
its "(1 when untagged)" aside; the note for a network matched by name onto
another VLAN says VLAN 1 for the Default network.

* Re-address Networks: a Console on the Gateway moves with the Plan, and the copy says so

A Plan now records when the UniFi Console runs on the Gateway (or a
CloudKey). Review Plan's When to Apply line, its last Lockout item, and the
"Network devices offline after" alert then say Network Devices drop until the
Gateway provisions its new addresses, instead of "until the console moves too",
which only fits a UniFi OS Server. Plans built before this keep the old text.

The strings this branch added capitalize the app's terms (Plan, Device,
Network, Gateway, Console, Alert), FEATURES.md included.

* Re-address Networks inform: review follow-ups

- The "Network devices offline after" alert goes out at once, as on
  release/2.11. The set-inform outcome follows as its own alert
  ("Re-point over SSH after: <plan>") when the pass finishes.
- The background pass logs a failure to publish that outcome.
- A DHCP Device with no new static is dialed at its last address with the
  Console's IP; only one with no known address at all is listed instead.
- The Gateway-address checks read LAN networks only: a VPN server or WAN
  network's address no longer counts as the Gateway's.
- The per-Plan attempt record is dropped when the Plan is reverted or
  cancelled, not only when its watch ends.

* Re-address Networks: the host-moves warning offers keeping both addresses

"Network Optimizer's host moves" now also says it can keep both addresses
until every Device is back: Network Optimizer then reaches Devices at their
new and old addresses, so the SSH re-point can connect.

* Re-address Networks inform: set-inform over SSH calls mca-cli-op directly

set-inform is only an /etc/profile alias for mca-cli-op set-inform (read on
an AP and a UXG), and a non-interactive SSH command never loads it, so every
attempt would have failed with "not found". The SSH pass now sends the same
guarded form Firmware Rollout uses for upgrade. The hand commands in the
alert keep plain set-inform, which a person types in an interactive shell.

Checked on a main-site AP with the exact command: exit 0, "Adoption request
sent", the AP informed to the IP, and the Console answered with its Inform
Host override (a name), which the AP saved within a second.

* Change Control: re-address watch and Lockout copy capitalize the app's terms

The older UniFi OS Server and management-move sentences in Review Plan's
When to Apply line, its Lockout items, and the "Network devices offline
after" alert now read Network Devices, UniFi Console, Gateway, Network, Plan,
and Re-address, like the strings this branch added. The management-network
Lockout detail capitalizes Devices.

* Re-address Networks: a Console at a Gateway LAN address reads as on the Gateway

The Plan's on-the-Gateway flag now also holds when the Console's address is
a Gateway LAN address, the same test that already blocks the override write,
so a Gateway-hosted Console whose type did not read gets the Gateway wording.
Review Plan's commit-confirmed line says "every Network Device" and "the Plan".
* Netgear CM: Genie form login for CM1000 firmware V7.01.01

CM1000 firmware V7.01.01 gates DocsisStatus.asp behind the Netgear Genie
login: the page is a 200 that redirects to /GenieLogin.asp, which carries a
per-load, unquoted webToken. Credentials POST to /goform/GenieLogin, the
session is bound to the source IP (no cookie), and the login's 302 carries
non-header bytes after the header block. The provider only knew Basic and
the CM2050V's /goform/Login, so every attempt failed and the CM2050V POST's
connection reset was the error shown.

- Attempts now carry an auth style (Basic, FormLogin, GenieLogin) instead
  of a form-login flag. With credentials, the Genie login runs on the .asp
  page and the CM2050V login on the .htm page. The login for the configured
  extension goes last, so a total failure surfaces that model's error.
- The Genie flow is raw HTTP/1.0 via LenientHttp throughout. It reuses a
  live session (one GET when already signed in), reads webToken and the
  form action with HtmlAgilityPack, and reports a login that still does
  not open the status page as a 401 ("Authentication failed").
- A modem without a Genie form (404 or no webToken) returns the page it
  reached, so the matrix moves on. A 404 status page ends the attempt
  before any Genie request. An empty reply (reset/close before any byte)
  is a transport error.

Tests run the full matrix against stateful loopback fakes of the CM1000
V7.01.01 and the CM2050V, plus a Basic-auth modem: Genie sign-in, cached
combo with a live session, expired session with a fresh token, wrong
password, no credentials, and the CM2050V and Basic models resolving as
before without touching the Genie login.

* Self-review: rewrap a doc comment, generic test token, lock the fake server request log

* Review: keep a quoted webToken intact, name the POST path in a Genie login error, rewrap a doc comment
Updated Docker Pulls badge to reflect new count.
…Fi Cable Internet, Richerlink, MikroTik, more Realtek sticks, Nighthawk and GL.iNet models)
* ONT Stats: Peter-Pon GPON firmware provider

Adds an ONT provider for GPON SFP sticks running Peter-Pon, the
OpenWrt-based firmware for the Huawei MA5671A. The stick's uhttpd serves
ubus JSON-RPC at /ubus/. A poll signs in with session.login (username
root by default), then reads luci.gpon status and info in one batch:

- status: Rx/Tx power (the dBm half of "12.14uW -19.16dBm"), PLOAM
  state, and the laser temperature (kelvin to C). The laser temperature
  is the optic reading SFP DDM and the other sticks report; the SoC die
  temperature has no OntStats field.
- info: GPON SN, firmware build, OLT vendor ID (stored raw, "HWTC", and
  decoded for display), OLT version and equipment ID.

luci.gpon live_get adds laser bias, supply voltage (optic.vcc_mv), and
the stick's uptime for reboot detection. It is best effort: a firmware
without it still polls. live_get returns every 1 s sample after its
since sequence number, so each poll passes the previous reply's seq to
read only the samples taken since the last poll, not the whole ring. A
failed read, or a reply with no seq, starts over from 0.

The firmware serves no cumulative error counters, only per-second GTC
rates in that ring. The provider sums gtc.bip_ps, gtc.fec_uncorr_ps,
gtc.fec_corr_ps, gtc.hec_corr_ps, and gtc.hec_uncorr_ps into running
BIP, FEC, and HEC counters per configuration. Samples are counted by
their time (ms since the stick booted), so a reply that repeats the ring
never counts a sample twice, and a sample time that goes back means the
stick rebooted and the totals start over. The totals also restart with
Network Optimizer; the charts, alerts, and ISP Health already read a
counter that goes down as a reset. Samples the ring drops between two
polls are not counted.

The ubus session is reused across polls and replaced when the stick
answers Access denied (-32002, or ubus status 6), as rpcd expires it
after 300 s idle. A denial that survives a fresh sign-in reports that
the user has no access to luci.gpon. A stick without luci.gpon reports
that it does not look like Peter-Pon firmware. Requests carry a
Content-Length instead of a chunked body.

Implements ISfpSupplementalOntProvider, so the stick can attach to the
gateway's monitored SFP module: its PLOAM state, counters, firmware, and
OLT identity merge into the module's sfp series, and its optics fill
gaps the gateway's DDM read leaves.

Registered in DI and in the Settings - Monitoring ONT provider list,
with 192.168.1.10 as the default host and root as the username
placeholder. FEATURES.md lists the stick under Fiber ONTs.

* test: Peter-Pon provider parsing, sessions, and error counters

Fixtures are the luci.gpon status, info, and live_get replies from a web
UI capture of an MA5671A on Peter-Pon, with the GPON serial and service
VLANs replaced by generic values.

Covers the dBm and kelvin conversions, batch replies matched by id,
Access denied and missing-object replies, the newest live sample (bias
8.53 mA, 3.35 V, uptime), and the status and info mapping. The error
counter tests cover sums across polls, repeated samples counted once, a
stick reboot starting the totals over, a reply with no new samples still
reporting the totals, metric arrays aligned from the newest sample, and
a firmware without the rates leaving the counters null.

A loopback ubus stub serves the captured replies to cover sign-in,
session reuse, re-login after expiry, rejected and changed credentials,
a user without access to luci.gpon, a firmware without luci.gpon, and
since tracking across polls and after a failed live_get.

* ONT Stats: Peter-Pon Test button leaves the saved config's state alone

The Test button probes the edited form, which can point at a different
stick, but it polled with the saved configuration's Id. That advanced the
saved configuration's live_get since and replaced its ubus session, and
the other stick's samples were added to its error totals. Test now polls
with Id 0, like an unsaved configuration.

Also marks the provider [VendorSpecific]: it parses raw ubus JSON.

* ONT Stats: Peter-Pon hardware is the Lantiq PEB98035 sticks

The fixtures come from an FS.com GPON-SFP-ONT-MAC-I, not an MA5671A.
Both sticks use the Lantiq PEB98035 and run Peter-Pon. The provider
summary, the test fixture note, and FEATURES.md now name both.

* README: Peter-Pon firmware GPON sticks under Fiber ONT

* ONT Stats: Peter-Pon uptime on the sample clock

The stick's uptime came from live_get's uptime_s, while the error totals
reset on the sample times t, read as ms since boot. In the capture
uptime_s is 134143 but updated_s and the newest t are 134171: uptime_s
trails the boot clock, so it is likely omci_ngd's age (pid 1420), and a
daemon restart would read as a stick reboot.

Uptime now comes from updated_s, or from the newest t when updated_s is
absent, so reboot detection and the totals use one clock.

* README, FEATURES: Peter-Pon covers other Lantiq PEB98035 sticks
…ises no banner

An Acknowledgment keys on the degraded Targets plus the finding's reading,
and a tracing episode has no reading yet, so every new episode on an
Acknowledged Target showed the "Tracing now" banner until its trace ended.
The banner now treats a tracing episode on exactly an Acknowledged Target
set as Acknowledged, taken from the episodes on the page whose full key was
Acknowledged. Once the trace finishes, the full key decides again, so a
changed last clean router still shows. Path & Congestion Events keep
listing it as Tracing now.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant