Skip to content

LPM fixes - #188

Merged
joamaki merged 13 commits into
mainfrom
pr/joamaki/lpm-fixes
Aug 27, 2026
Merged

LPM fixes#188
joamaki merged 13 commits into
mainfrom
pr/joamaki/lpm-fixes

Conversation

@joamaki

@joamaki joamaki commented Aug 26, 2026

Copy link
Copy Markdown
Contributor
  • Preserve all objects sharing a key in non-unique LPM indexes instead of overwriting earlier entries.
  • Correct lookups for keys terminating within compressed trie paths.
  • Deduplicate objects indexed under multiple matching prefixes in non-unique LPM query results.
  • Canonicalize IPv4-mapped IPv6 to IPv4 while keeping ordinary IPv6 lookups isolated.
  • Reject LPM indexes as primary table indexes because the LPM indexer doesn't implement all required methods for primary index.
  • Prevent prefix-length arithmetic from overflowing for maximum-length LPM keys.

See commits for detailed descriptions.

joamaki added 12 commits August 26, 2026 13:40
Non-unique LPM entries keep objects after the head in a slice. Updating
one of those objects in a write transaction currently changes the object
visible through an older read snapshot before the write is committed.
Aborting the write does not restore the snapshot.

Add a regression test that holds an old read transaction while updating a
non-head object under the same LPM key and verifies that the old value
remains visible.

AIL:3
Signed-off-by: Jussi Maki <jussi@isovalent.com>
LookupExact returns an lpmEntry by value, but the tail slice still shares
its backing array with the entry in the committed trie. lpmEntry.upsert
updates that array in place when replacing a tail object and may also
reuse it while inserting or reordering objects. This violates StateDB
snapshot isolation and can expose uncommitted writes to readers.

Clone the tail before every path that mutates it. The updated entry then
owns its backing array before it is inserted into the transactional trie.

AIL:3
Signed-off-by: Jussi Maki <jussi@isovalent.com>
Lookup treats reaching the end of the query prefix as a match even when
the current compressed node is more specific than the query. It can
therefore return a prefix that does not contain the query. If the current
node is imaginary, the same early return also discards a valid less
specific ancestor.

Add regression cases for both outcomes: a query ending inside a real
compressed node and a query ending exactly at an imaginary node below a
default route. Update the script fixture so a /16 lookup expects its
containing /8 instead of a more-specific /32.

AIL:3
Signed-off-by: Jussi Maki <jussi@isovalent.com>
Ending the query inside a compressed node only proves that the query is a
prefix of that node; it does not make the more-specific node an LPM
candidate. Likewise, an exact imaginary node carries no value and must
not hide the closest real ancestor found during traversal.

Return the current node only when its prefix length equals the query
length and the node is real. Otherwise stop traversal and use the saved
closest ancestor.

AIL:3
Signed-off-by: Jussi Maki <jussi@isovalent.com>
An object may contribute multiple keys to a non-unique LPM index. Prefix
and lower-bound iteration currently visits each matching trie entry
independently, so an object whose broader and narrower keys both match is
returned more than once.

Add a regression test that indexes one object under an 8-bit and a
16-bit prefix and requires both Prefix and LowerBound to emit it once.

AIL:3
Signed-off-by: Jussi Maki <jussi@isovalent.com>
LPM iterator adaptation previously discarded the primary keys stored in
lpmEntry and yielded every object from every matching prefix. It
therefore had no way to recognize the same object reached through
multiple secondary keys.

Mark adapters for non-unique indexes as deduplicating and keep a visited
set keyed by primary key while iterating. Unique indexes retain the
allocation-free path.

AIL:3
Signed-off-by: Jussi Maki <jussi@isovalent.com>
NetIPPrefixIndex embeds IPv4 keys in the IPv4-mapped portion of the IPv6
key space. This preserves equivalence between native IPv4 and mapped IPv6
forms, but it also places every IPv4 key below broad IPv6 prefixes. An
IPv6 default prefix can therefore satisfy an unrelated IPv4 lookup.

Add a regression test with a mapped IPv4 subnet and an IPv6 default. Both
native and mapped queries for the subnet must find the canonical IPv4
entry, an ordinary IPv6 query must find the IPv6 default, and an unrelated
IPv4 query must not fall back to that IPv6 default.

AIL:3
Signed-off-by: Jussi Maki <jussi@isovalent.com>
Encoding both families as 16-byte addresses makes broad IPv6 prefixes match
IPv4 queries. Separating every mapped address as IPv6 would avoid that
cross-family match, but would also discard the existing and useful aliasing
between native IPv4 and IPv4-mapped IPv6 forms.

First canonicalize prefixes wholly contained in the IPv4-mapped IPv6 range
by unmapping their address and subtracting the 96-bit mapped prefix. Then
prefix each canonical key with an address-family discriminator and include
those bits in the LPM length. Address queries use the same encoder, so
native and mapped IPv4 forms share a key while ordinary IPv6 remains in a
separate trie namespace. IPv6 prefixes broader than the mapped range remain
IPv6 because they have no equivalent IPv4 prefix.

AIL:3
Signed-off-by: Jussi Maki <jussi@isovalent.com>
NetIPPrefixIndex and LPMIndex implement Indexer and are accepted by
NewTable as primary indexes when marked unique. Their primary mutation
methods are intentionally unsupported, so the first table insertion
panics instead of returning a construction-time error.

Add regression coverage requiring NewTable to reject both LPM index
implementations when supplied as the primary index.

AIL:3
Signed-off-by: Jussi Maki <jussi@isovalent.com>
LPM indexes only implement secondary-index reindexing; their primary
insert, modify, and delete operations panic. Allowing one through
NewTable defers a configuration error until the first write and crashes
the caller.

Mark the LPM index implementations as secondary-only and have NewTable
return ErrPrimaryIndexNotSupported when such an index is selected as the
primary index.

AIL:3
Signed-off-by: Jussi Maki <jussi@isovalent.com>
PrefixLen is uint16, but rounding a bit length to bytes currently adds
seven before widening the value. Lengths from 65529 through 65535
overflow that addition; encoding the maximum length consequently emits
only the two-byte length suffix, and decoding accepts that truncated key.

Add a regression test for the maximum PrefixLen that verifies the full
8192-byte payload, final-byte masking, and rejection of a truncated key.

AIL:3
Signed-off-by: Jussi Maki <jussi@isovalent.com>
The byte-length calculations in encoding, decoding, and trie validation
perform prefixLen + 7 as uint16. The addition wraps near the maximum
PrefixLen before the result is converted to int, producing malformed
keys and ineffective validation.

Centralize the calculation in lpmDataLen and convert prefixLen to int
before rounding. Use it consistently in EncodeLPMKey, DecodeLPMKey, and
the validation path.

AIL:3
Signed-off-by: Jussi Maki <jussi@isovalent.com>
@joamaki
joamaki requested a review from a team as a code owner August 26, 2026 12:03
@joamaki
joamaki requested review from derailed and removed request for a team August 26, 2026 12:03
@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown
$ make
go build ./...
go: downloading github.com/cilium/hive v1.0.4
go: downloading golang.org/x/time v0.15.0
go: downloading go.yaml.in/yaml/v3 v3.0.4
go: downloading github.com/spf13/cobra v1.10.2
go: downloading github.com/spf13/pflag v1.0.10
go: downloading github.com/cilium/stream v0.0.1
go: downloading github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de
go: downloading github.com/spf13/viper v1.18.2
go: downloading go.uber.org/dig v1.17.1
go: downloading golang.org/x/term v0.16.0
go: downloading github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
go: downloading github.com/mitchellh/mapstructure v1.5.0
go: downloading golang.org/x/sys v0.17.0
go: downloading golang.org/x/tools v0.17.0
go: downloading github.com/spf13/cast v1.6.0
go: downloading github.com/fsnotify/fsnotify v1.7.0
go: downloading github.com/sagikazarmark/slog-shim v0.1.0
go: downloading github.com/spf13/afero v1.11.0
go: downloading github.com/subosito/gotenv v1.6.0
go: downloading github.com/hashicorp/hcl v1.0.0
go: downloading gopkg.in/ini.v1 v1.67.0
go: downloading github.com/magiconair/properties v1.8.7
go: downloading github.com/pelletier/go-toml/v2 v2.1.0
go: downloading gopkg.in/yaml.v3 v3.0.1
go: downloading golang.org/x/text v0.14.0
STATEDB_VALIDATE=1 go test ./... -cover -vet=all -test.count 1
go: downloading github.com/stretchr/testify v1.11.1
go: downloading go.uber.org/goleak v1.3.0
go: downloading golang.org/x/exp v0.0.0-20240119083558-1b970713d09a
go: downloading github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2
ok  	github.com/cilium/statedb	298.449s	coverage: 79.5% of statements
ok  	github.com/cilium/statedb/index	0.005s	coverage: 33.7% of statements
ok  	github.com/cilium/statedb/internal	0.022s	coverage: 42.9% of statements
ok  	github.com/cilium/statedb/lpm	4.798s	coverage: 75.8% of statements
ok  	github.com/cilium/statedb/part	72.351s	coverage: 86.1% of statements
ok  	github.com/cilium/statedb/reconciler	0.322s	coverage: 93.1% of statements
	github.com/cilium/statedb/reconciler/benchmark		coverage: 0.0% of statements
	github.com/cilium/statedb/reconciler/example		coverage: 0.0% of statements
go test -race ./... -test.count 1
ok  	github.com/cilium/statedb	42.130s
ok  	github.com/cilium/statedb/index	1.015s
ok  	github.com/cilium/statedb/internal	1.025s
ok  	github.com/cilium/statedb/lpm	2.656s
ok  	github.com/cilium/statedb/part	38.002s
ok  	github.com/cilium/statedb/reconciler	1.380s
?   	github.com/cilium/statedb/reconciler/benchmark	[no test files]
?   	github.com/cilium/statedb/reconciler/example	[no test files]
go test ./... -bench . -benchmem -test.run xxx
goos: linux
goarch: amd64
pkg: github.com/cilium/statedb
cpu: AMD EPYC 7763 64-Core Processor                
BenchmarkDB_WriteTxn_1-4                      	  742989	      1532 ns/op	    652557 objects/sec	     704 B/op	      17 allocs/op
BenchmarkDB_WriteTxn_10-4                     	 1916426	       625.9 ns/op	   1597751 objects/sec	     386 B/op	       8 allocs/op
BenchmarkDB_WriteTxn_100-4                    	 2019092	       505.7 ns/op	   1977265 objects/sec	     349 B/op	       7 allocs/op
BenchmarkDB_WriteTxn_1000-4                   	 2170053	       556.9 ns/op	   1795757 objects/sec	     350 B/op	       7 allocs/op
BenchmarkDB_WriteTxn_100_SecondaryIndex-4     	 1438918	       831.7 ns/op	   1202326 objects/sec	     459 B/op	      10 allocs/op
BenchmarkDB_WriteTxn_CommitOnly_100Tables-4   	  881775	      1333 ns/op	    1128 B/op	       6 allocs/op
BenchmarkDB_WriteTxn_CommitOnly_1Table-4      	 1384680	       867.1 ns/op	     240 B/op	       6 allocs/op
BenchmarkDB_NewWriteTxn-4                     	 1557002	       771.3 ns/op	     216 B/op	       5 allocs/op
BenchmarkDB_WriteTxnCommit100-4               	  835922	      1328 ns/op	    1112 B/op	       6 allocs/op
BenchmarkDB_NewReadTxn-4                      	548019260	         2.186 ns/op	       0 B/op	       0 allocs/op
BenchmarkDB_Modify-4                          	    2008	    596258 ns/op	   1677126 objects/sec	  374572 B/op	    8080 allocs/op
BenchmarkDB_GetInsert-4                       	    1761	    680126 ns/op	   1470317 objects/sec	  358570 B/op	    8080 allocs/op
BenchmarkDB_RandomInsert-4                    	    2148	    560300 ns/op	   1784758 objects/sec	  350565 B/op	    7080 allocs/op
BenchmarkDB_RandomReplace-4                   	    1150	   1114550 ns/op	    897223 objects/sec	  472496 B/op	   11109 allocs/op
BenchmarkDB_SequentialInsert-4                	    2178	    553506 ns/op	   1806666 objects/sec	  350565 B/op	    7080 allocs/op
BenchmarkDB_SequentialInsert_Prefix-4         	     517	   2355966 ns/op	    424454 objects/sec	 2840379 B/op	   45536 allocs/op
BenchmarkDB_Changes_Baseline-4                	    1725	    699600 ns/op	   1429388 objects/sec	  444574 B/op	    9201 allocs/op
BenchmarkDB_Changes-4                         	     974	   1238938 ns/op	    807143 objects/sec	  660557 B/op	   12371 allocs/op
BenchmarkDB_RandomLookup-4                    	   23942	     50830 ns/op	  19673429 objects/sec	       0 B/op	       0 allocs/op
BenchmarkDB_SequentialLookup-4                	   29193	     41163 ns/op	  24293945 objects/sec	       0 B/op	       0 allocs/op
BenchmarkDB_Prefix_SecondaryIndex-4           	    6794	    166012 ns/op	   6023677 objects/sec	  124952 B/op	    1026 allocs/op
BenchmarkDB_FullIteration_All-4               	     760	   1572460 ns/op	  63594623 objects/sec	     104 B/op	       4 allocs/op
BenchmarkDB_FullIteration_Prefix-4            	     722	   1641631 ns/op	  60915039 objects/sec	     136 B/op	       5 allocs/op
BenchmarkDB_FullIteration_Get-4               	     220	   5472192 ns/op	  18274212 objects/sec	       0 B/op	       0 allocs/op
BenchmarkDB_FullIteration_Get_Secondary-4     	      92	  12731816 ns/op	   7854339 objects/sec	       0 B/op	       0 allocs/op
BenchmarkDB_FullIteration_ReadTxnGet-4        	     206	   5737002 ns/op	  17430706 objects/sec	       0 B/op	       0 allocs/op
BenchmarkDB_PropagationDelay-4                	  677792	      1576 ns/op	        13.00 50th_µs	        16.00 90th_µs	        48.00 99th_µs	     877 B/op	      20 allocs/op
BenchmarkDB_WriteTxn_100_LPMIndex-4           	  524931	      2360 ns/op	    423682 objects/sec	    1606 B/op	      37 allocs/op
BenchmarkDB_WriteTxn_1_LPMIndex-4             	  132462	     14920 ns/op	     67025 objects/sec	   13637 B/op	      82 allocs/op
BenchmarkDB_LPMIndex_Get-4                    	     241	   4539556 ns/op	   2202859 objects/sec	       0 B/op	       0 allocs/op
BenchmarkWatchSet_4-4                         	 2307360	       512.4 ns/op	     296 B/op	       4 allocs/op
BenchmarkWatchSet_16-4                        	  691058	      1583 ns/op	    1096 B/op	       5 allocs/op
BenchmarkWatchSet_128-4                       	   87295	     13682 ns/op	    8904 B/op	       5 allocs/op
BenchmarkWatchSet_1024-4                      	    8934	    137370 ns/op	   73743 B/op	       5 allocs/op
PASS
ok  	github.com/cilium/statedb	44.512s
PASS
ok  	github.com/cilium/statedb/index	0.004s
goos: linux
goarch: amd64
pkg: github.com/cilium/statedb/internal
cpu: AMD EPYC 7763 64-Core Processor                
Benchmark_SortableMutex-4   	 5721079	       209.6 ns/op	       0 B/op	       0 allocs/op
PASS
ok  	github.com/cilium/statedb/internal	1.203s
goos: linux
goarch: amd64
pkg: github.com/cilium/statedb/lpm
cpu: AMD EPYC 7763 64-Core Processor                
Benchmark_txn_insert/batchSize=1-4         	    1878	    633831 ns/op	   1577707 objects/sec	  822408 B/op	   13975 allocs/op
Benchmark_txn_insert/batchSize=10-4        	    3266	    378081 ns/op	   2644934 objects/sec	  369195 B/op	    6668 allocs/op
Benchmark_txn_insert/batchSize=100-4       	    3418	    347983 ns/op	   2873705 objects/sec	  329613 B/op	    6027 allocs/op
Benchmark_txn_delete/batchSize=1-4         	    1554	    766217 ns/op	   1305113 objects/sec	 1270473 B/op	   13976 allocs/op
Benchmark_txn_delete/batchSize=10-4        	    3183	    369532 ns/op	   2706124 objects/sec	  356419 B/op	    5769 allocs/op
Benchmark_txn_delete/batchSize=100-4       	    3667	    326896 ns/op	   3059081 objects/sec	  270754 B/op	    5038 allocs/op
Benchmark_LPM_Lookup-4                     	    9110	    131747 ns/op	   7590303 objects/sec	       0 B/op	       0 allocs/op
Benchmark_LPM_All-4                        	  142381	      9447 ns/op	 105853375 objects/sec	      32 B/op	       1 allocs/op
Benchmark_LPM_Prefix-4                     	  132806	      9013 ns/op	 110949261 objects/sec	      32 B/op	       1 allocs/op
Benchmark_LPM_LowerBound-4                 	  250894	      4719 ns/op	 105950771 objects/sec	     288 B/op	       2 allocs/op
PASS
ok  	github.com/cilium/statedb/lpm	12.120s
goos: linux
goarch: amd64
pkg: github.com/cilium/statedb/part
cpu: AMD EPYC 7763 64-Core Processor                
Benchmark_Set_Singleton_Create-4              	21939414	        54.46 ns/op	      24 B/op	       1 allocs/op
Benchmark_Set_Singleton_Has-4                 	100000000	        11.22 ns/op	       0 B/op	       0 allocs/op
Benchmark_StringMap_Txn_Insert-4              	    7806	    141011 ns/op	   7091641 items/sec	   98250 B/op	    1306 allocs/op
Benchmark_Uint64Map_Random-4                  	    1902	    641704 ns/op	   1558352 items/sec	 1323901 B/op	    6033 allocs/op
Benchmark_Uint64Map_Sequential-4              	    1894	    636898 ns/op	   1570109 items/sec	 1703089 B/op	    5753 allocs/op
Benchmark_Uint64Map_Sequential_Insert-4       	    2139	    605480 ns/op	   1651583 items/sec	 1695086 B/op	    4752 allocs/op
Benchmark_Uint64Map_Sequential_Txn_Insert-4   	   10000	    117959 ns/op	   8477555 items/sec	   90464 B/op	    2031 allocs/op
Benchmark_Uint64Map_Random_Insert-4           	    2035	    565745 ns/op	   1767580 items/sec	 1316209 B/op	    5060 allocs/op
Benchmark_Uint64Map_Random_Txn_Insert-4       	    6134	    186062 ns/op	   5374555 items/sec	  118445 B/op	    2418 allocs/op
Benchmark_Insert_RootOnlyWatch-4              	    9064	    117645 ns/op	   8500165 objects/sec	   75552 B/op	    2036 allocs/op
Benchmark_Insert-4                            	    7952	    142426 ns/op	   7021212 objects/sec	   84256 B/op	    3067 allocs/op
Benchmark_WatchReplace-4                      	    9531	    118683 ns/op	   8425781 objects/sec	   65346 B/op	    2011 allocs/op
Benchmark_Modify-4                            	   12910	     93006 ns/op	  10751955 objects/sec	   58056 B/op	    1007 allocs/op
Benchmark_GetInsert-4                         	    9460	    119048 ns/op	   8399939 objects/sec	   58056 B/op	    1007 allocs/op
Benchmark_Replace-4                           	33686826	        35.30 ns/op	  28326989 objects/sec	       0 B/op	       0 allocs/op
Benchmark_Replace_RootOnlyWatch-4             	33417079	        35.30 ns/op	  28331387 objects/sec	       0 B/op	       0 allocs/op
Benchmark_txn_1-4                             	 7830130	       151.5 ns/op	   6600090 objects/sec	      64 B/op	       3 allocs/op
Benchmark_txn_10-4                            	10741965	       111.8 ns/op	   8941598 objects/sec	      76 B/op	       2 allocs/op
Benchmark_txn_100-4                           	12071910	        98.93 ns/op	  10108307 objects/sec	      67 B/op	       2 allocs/op
Benchmark_txn_1000-4                          	10555526	       113.1 ns/op	   8845061 objects/sec	      65 B/op	       2 allocs/op
Benchmark_txn_delete_1-4                      	 5242926	       230.6 ns/op	   4337274 objects/sec	     632 B/op	       3 allocs/op
Benchmark_txn_delete_10-4                     	10951411	       108.8 ns/op	   9190654 objects/sec	     103 B/op	       1 allocs/op
Benchmark_txn_delete_100-4                    	13349554	        88.60 ns/op	  11286247 objects/sec	      35 B/op	       1 allocs/op
Benchmark_txn_delete_1000-4                   	13706319	        88.28 ns/op	  11327537 objects/sec	      28 B/op	       1 allocs/op
Benchmark_Get-4                               	   44149	     27168 ns/op	  36808223 objects/sec	       0 B/op	       0 allocs/op
Benchmark_GetWatch-4                          	   41386	     28939 ns/op	  34555909 objects/sec	       0 B/op	       0 allocs/op
Benchmark_All-4                               	  143827	      8333 ns/op	 120005618 objects/sec	       0 B/op	       0 allocs/op
Benchmark_Iterator_All-4                      	  157766	      7599 ns/op	 131591540 objects/sec	       0 B/op	       0 allocs/op
Benchmark_Iterator_Next-4                     	  148855	      7927 ns/op	 126158228 objects/sec	     896 B/op	       1 allocs/op
Benchmark_Hashmap_Insert-4                    	   14438	     82706 ns/op	  12090955 objects/sec	   74264 B/op	      20 allocs/op
Benchmark_Hashmap_Get_Uint64-4                	  135769	      8844 ns/op	 113072412 objects/sec	       0 B/op	       0 allocs/op
Benchmark_Hashmap_Get_Bytes-4                 	  109599	     10920 ns/op	  91579038 objects/sec	       0 B/op	       0 allocs/op
Benchmark_Delete_Random-4                     	      54	  20170354 ns/op	   4957771 objects/sec	 2539426 B/op	  102756 allocs/op
Benchmark_find16-4                            	213045061	         5.625 ns/op	       0 B/op	       0 allocs/op
Benchmark_findIndex16-4                       	88417388	        13.45 ns/op	       0 B/op	       0 allocs/op
Benchmark_find64-4                            	293975576	         4.071 ns/op	       0 B/op	       0 allocs/op
Benchmark_findIndex64_hit-4                   	295643762	         4.058 ns/op	       0 B/op	       0 allocs/op
Benchmark_findIndex64_miss-4                  	295401938	         4.059 ns/op	       0 B/op	       0 allocs/op
Benchmark_find4-4                             	416313019	         2.851 ns/op	       0 B/op	       0 allocs/op
Benchmark_findIndex4-4                        	320367915	         3.749 ns/op	       0 B/op	       0 allocs/op
BenchmarkSmallWriteTxn/updates_1-4            	  442948	      2564 ns/op	    3529 B/op	       4 allocs/op
BenchmarkSmallWriteTxn/updates_2-4            	  315964	      3649 ns/op	    4742 B/op	       6 allocs/op
BenchmarkSmallWriteTxn/updates_4-4            	  212784	      5709 ns/op	    7155 B/op	      11 allocs/op
BenchmarkSmallWriteTxn/updates_8-4            	  121786	      9768 ns/op	   11927 B/op	      20 allocs/op
BenchmarkSmallWriteTxn/updates_16-4           	   66139	     18073 ns/op	   21289 B/op	      38 allocs/op
PASS
ok  	github.com/cilium/statedb/part	54.862s
PASS
ok  	github.com/cilium/statedb/reconciler	0.005s
?   	github.com/cilium/statedb/reconciler/benchmark	[no test files]
?   	github.com/cilium/statedb/reconciler/example	[no test files]
go run ./reconciler/benchmark -quiet
1000000 objects reconciled in 1.79 seconds (batch size 1000)
Throughput 559986.07 objects per second
568MB total allocated, 6015186 in-use objects, 239MB bytes in use

@joamaki

joamaki commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

cc @immanuwell

@derailed derailed 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.

@joamaki Nice work!

Comment thread lpm/key.go Outdated
EncodeLPMKey accepts caller-provided byte slices and prefix lengths, but
currently panics when the data is too short. Generic LPM queries and string
parsers can receive malformed input and should be able to report it without
terminating the process.

Return an error from EncodeLPMKey and propagate it through generic query and
string conversion paths. Keep panic-on-error behavior in netip helpers and
object indexing callbacks, where address sizes or existing interfaces make
an encoding failure an internal invariant violation. Propagate the otherwise
impossible error while constructing compressed trie nodes through Insert's
existing error result.

AIL:3
Signed-off-by: Jussi Maki <jussi@isovalent.com>
@joamaki
joamaki merged commit 85c090c into main Aug 27, 2026
1 check passed
@joamaki
joamaki deleted the pr/joamaki/lpm-fixes branch August 27, 2026 08:09
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.

2 participants