Skip to content

fix(nrfcache): match filters reject profiles they should accept - #170

Merged
gab-arrobo merged 3 commits into
omec-project:mainfrom
bgrewell:fix/nrfcache-matcher-rejects-valid-profiles
Aug 7, 2026
Merged

fix(nrfcache): match filters reject profiles they should accept#170
gab-arrobo merged 3 commits into
omec-project:mainfrom
bgrewell:fix/nrfcache-matcher-rejects-valid-profiles

Conversation

@bgrewell

@bgrewell bgrewell commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Two related defects in nrfcache/match_filters.go. Both make cached NF discovery return empty for profiles that are valid, so the cache is structurally incapable of hitting and every lookup falls through to the NRF.

Both were found and measured against a live Aether SD-Core deployment under registration load, with a 5G SA gNB/UE simulator driving attaches.

1 — Profiles without SUPI ranges are treated as restricted

MatchUdmProfile / MatchPcfProfile / MatchAusfProfile require a cached profile to carry a non-empty SupiRanges whenever the discovery query includes a supi; a profile with no ranges is rejected.

SD-Core registers one UDM/PCF serving every subscriber, with no SUPI ranges — verified on the wire, the NRF returns udmInfo:{"groupId":""}. So the match can never succeed, and the AMF logs cache miss for nftype AUSF/UDM/PCF on every attach, preceded by match found = false (no SUPI ranges).

Per TS 29.510 supiRanges is an optional restriction on an NF profile: a range constrains, and an absent constraint admits everything. The matchers now treat "no SUPI ranges" as unrestricted.

2 — No match filter is registered for UDR

matchFilters has no NFTYPE_UDR entry, and nrfcache.go silently drops any profile whose NfType has no filter. Cached UDR discovery therefore always returns empty — a permanent miss — after which the EnableNrfCaching && empty fallback fires a second, direct NRF query. The UDM performs several UDR discoveries per registration, so this sits on the attach hot path.

Measured effect

Registering the UDR filter took the test deployment from 22 to ~185 registrations/s (stable across 5 runs, 173–189/s, 100% success), registration P50 400 ms → 256 ms, and MongoDB operations per attach 50 → 25 as NfProfile and urilist queries left the hot path. The SUPI-range fix removes the remaining per-attach AUSF/UDM/PCF misses (4 → 0 observed).

Testing

Regression tests added for both defects; each fails without its fix. go test ./nrfcache/ passes.

Validated live by building the consuming NFs (AMF, UDM) against this branch with a go mod edit -replace and re-measuring on the deployment.

The two changes share nrfcache_test.go and the second builds on the first, hence one PR; happy to split if preferred.

bgrewell added 2 commits July 30, 2026 22:35
A cached NF profile that declares no SUPI ranges was rejected whenever a
discovery query carried a SUPI, so UDM, PCF and AUSF lookups could never
be served from cache and every request fell through to the NRF.

The NRF's own discovery filter matches those profiles: its supi filter is
an $or over "a range contains the SUPI", "supiRanges is null" and
"supiRanges is absent". The cache therefore selected a different set of
profiles than the NRF it caches, so a cached lookup and a live discovery
disagreed for the same query.

Match the NRF semantics in MatchUdmProfile, MatchPcfProfile and
MatchAusfProfile, and cover both the unrestricted case and the
still-filtered case with regression tests.

Measured on an SD-Core deployment whose single UDM/PCF register without
SUPI ranges: AMF NRF cache misses per registration dropped from ~4 to 0,
NfProfile queries from 21 to 16 per registration, and NRF CPU from 77 ms
to 51 ms per registration.

Signed-off-by: Ben Grewell <bgrewell@gmail.com>
NrfCache.get drops any cached profile whose NfType has no entry in
matchFilters, and UDR had no entry. Cached UDR discovery therefore always
returned an empty result, so every UDM and PCF subscriber data access fell
through to a live NRF query.

That miss is expensive beyond the extra query: handleLookup holds the
cache write lock across the NRF round trip, so a permanently-missing NF
type serialises every concurrent discovery for it behind one network call.
UDR is resolved on every subscriber data access, which makes it the most
frequently discovered NF in the core.

Add MatchUdrProfile, mirroring the NRF's own UDR supi filter, and register
it. Cover the SUPI-range and unrestricted cases, and assert the filter is
registered so a future NF type is not silently dropped again.

Measured on SD-Core, registration throughput over the same load sweep rose
from 22 to ~185 attaches/s, and MongoDB operations per registration fell
from 50 to 25 as the NfProfile and urilist queries left the hot path.

Signed-off-by: Ben Grewell <bgrewell@gmail.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Comment thread nrfcache/nrfcache_test.go Outdated
Reorder struct to satisfy field alignment lint

Co-authored-by: Gabriel Arrobo <gabriel.arrobo@intel.com>
Signed-off-by: Ben Grewell <BGrewell@gmail.com>
Copilot AI review requested due to automatic review settings August 6, 2026 23:00

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (1)

nrfcache/match_filters.go:289

  • The inline reference to nrf producer/nf_discovery.go / [Query-18] appears to point to a file/query that does not exist in this repository, which makes the rationale hard to verify/maintain from this codebase. Consider rewording the comment to describe the behavior without referencing an external path/query label.
		// A profile declaring no SUPI ranges is unrestricted and serves every
		// SUPI. The NRF's own discovery filter encodes this as an $or over
		// "a range contains the SUPI" / "supiRanges is null" / "supiRanges is
		// absent" (nrf producer/nf_discovery.go, [Query-18] supi). Rationale:
		// the cache must select the same profiles as the NRF it caches,
		// otherwise a cached lookup and a live discovery disagree.

@gab-arrobo
gab-arrobo merged commit 80f6857 into omec-project:main Aug 7, 2026
9 checks passed
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.

3 participants