Skip to content

StateDB Get is a prefix match iff the key is variable length #29324

@bimmlerd

Description

@bimmlerd

The Get method on a statedb Table is documented as follows.

	// Get returns an iterator for all objects matching the given query
	// and a watch channel that is closed if the query results are
	// invalidated by a write to the table.
	Get(ReadTxn, Query[Obj]) (Iterator[Obj], <-chan struct{})

For queries which query variable (and only variable) length keys, 'matching' surprisingly means a prefix match, instead of an exact match. This can lead to surprising results for strings, but likely also for IP addresses. Imagine querying for an IPv4 and getting IPv6 addresses which just happens to be prefixed by said IPv4 😱

In the following example program, the issue manifests - it prints [{cilium} {cilium_host}] instead of just [{cilium}]. This also happens if the ByName index is secondary and non-unique.

package main

import (
	"context"
	"fmt"

	"github.com/cilium/cilium/pkg/statedb"
	"github.com/cilium/cilium/pkg/statedb/index"
)

type Device struct {
	name string
}

var (
	DeviceByNameIndex = statedb.Index[Device, string]{
		Name: "name",
		FromObject: func(a Device) index.KeySet {
			return index.NewKeySet(index.String(a.name))
		},
		FromKey: index.String,
		Unique:  true,
	}
)

func main() {
	table, err := statedb.NewTable[Device]("devices", DeviceByNameIndex)
	if err != nil {
		panic(err)
	}
	db, err := statedb.NewDB([]statedb.TableMeta{table}, statedb.NewMetrics())
	if err != nil {
		panic(err)
	}

	if err := db.Start(context.Background()); err != nil {
		panic(err)
	}

	txn := db.WriteTxn(table)
	table.Insert(txn, Device{
		name: "cilium",
	})
	table.Insert(txn, Device{
		name: "cilium_host",
	})
	txn.Commit()

	rtxn := db.ReadTxn()
	it, _ := table.Get(rtxn, DeviceByNameIndex.Query("cilium"))
	ciliumDevice := statedb.Collect[Device](it)
	fmt.Printf("%v\n", ciliumDevice)
}

Metadata

Metadata

Assignees

Labels

kind/bugThis is a bug in the Cilium logic.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions