Use topology/links and anynetlinks filters with eq/in operators so store WAN follow-ups return real peer tunnels instead of unscoped dumps. Co-authored-by: Cursor <cursoragent@cursor.com>
3.2 KiB
Prisma Phase 2 — Voice Path Attribution Discovery
Time-boxed discovery notes for "voice is on this tunnel" / per-handset
attribution. Phase 1 (runtime waninterface status, overlay tunnels,
app DPI by path_type) ships without these.
Confirmed Phase 1 surfaces (pan.dev + code)
| Need | Endpoint | Notes |
|---|---|---|
| Circuit runtime status | GET /sdwan/v2.1/api/sites/{siteId}/waninterfaces/{wiId}/status |
Wired in getWanInterfaceStatus |
| Overlay tunnels | POST /sdwan/v2.0/api/topology/links/query with query_params.{source|target}_site_id.{in|eq} |
Preferred — includes status, peer names, vpnlinks[] |
| Anynet fallback | POST /sdwan/v4.0/api/anynetlinks/query with query_params.ep{1|2}_site_id.{eq|in} |
Config rows; no runtime status |
| Voice DPI by path_type | getAppMetric with filter.path_type=[VPN] etc. |
AppPerf* only; AppAudioMos omits path_type |
| Alarm → tunnel id | info.vpn_reasons[].vpn_link_id |
extractVpnLinkIdsFromAlarmInfo |
Live-tenant corrections (2026-07-28 / store 1005)
| Issue | Fix |
|---|---|
limit: { count: N } → 400 "expected int" |
Topology/anynet limit is a bare int |
query: { site_id: [...] } silently ignored |
Use query_params: { field: { eq|in: … } } (array under query_params → 400) |
100 tunnels all peer — unknown |
Site-scoped topology query; resolve peer opposite local site; renderer collapses all-unknown |
vpnlinks have no site fields |
Prefer topology links; anynet via ep1/ep2; never unscoped vpnlinks dump |
| Pairing down volume | Prefer public-anynet; rank down/unknown first; cap ≤12; renderer shows ≤6 |
| Cascading 429s | Path-type breakout gated by PRISMA_VOICE_PATH_TYPE_BREAKOUT; status GETs capped |
Probe recipes:
node scripts/prismaProbe.js wi-status <siteId> <wanInterfaceId>
node scripts/prismaProbe.js tunnels <siteId>
node scripts/prismaProbe.js app-by-path-type <siteId> <appId> --metric loss
node scripts/prismaProbe.js try-shapes app-by-path <siteId> <appId> <wiId>
Phase 2a candidates (probe before implementing further)
-
App metrics +
filter.path(waninterface id) — already supported ingetAppMetric({ pathIds })behindPRISMA_VOICE_PATH_ATTRIBUTION=1. Confirm live tenant accepts the filter (SCHEMA_CHECK_FAIL risk). -
Flow / session / app-path details — SCM UI "Application Path Details" HAR may reveal monitor endpoints that bind RTP to a specific path. Candidates: topology query v3.6, object_stats, app/wan contexts.
-
Join keys to Webex — need client IP, subnet, or device id in Prisma flow records to map to Meraki/Webex handset inventory. Not confirmed.
Phase 2c status
attributeVoicePathToEndpoint() in
services/callReport/voicePathAttribution.js returns null until a
join key is confirmed. Path-level / path_type-level annotation is live
via annotateWanWithPath().
Confidence language
| Level | Meaning |
|---|---|
site |
Site-wide DPI only (siteLevelApprox: true) |
path_type |
One path_type uniquely worse in window |
path |
One waninterface uniquely worse (byPath) |
endpoint |
Per-handset — not available without flow join keys |