Skip to content

Commit 1f48f9b

Browse files
committed
map: add ability to pin maps in different paths
1 parent c089de5 commit 1f48f9b

File tree

3 files changed

+172
-2
lines changed

3 files changed

+172
-2
lines changed

map.go

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,12 @@ type MapOptions struct {
4141
// The base path to pin maps in if requested via PinByName.
4242
// Existing maps will be re-used if they are compatible, otherwise an
4343
// error is returned.
44-
PinPath string
44+
PinPath string
45+
// The full path to use for each map with PinByPath
46+
// Existing maps will be re-used if they are compatible, otherwise an
47+
// error is returned.
48+
PinPathMapping map[string]string
49+
4550
LoadPinOptions LoadPinOptions
4651
}
4752

@@ -380,6 +385,28 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions) (_ *Map, err error) {
380385

381386
return m, nil
382387

388+
case PinByPath:
389+
if spec.Name == "" {
390+
return nil, fmt.Errorf("pin by path: missing Name")
391+
}
392+
path, ok := opts.PinPathMapping[spec.Name]
393+
if !ok {
394+
return nil, fmt.Errorf("pin by path: no path found for map %v", spec.Name)
395+
}
396+
m, err := LoadPinnedMap(path, &opts.LoadPinOptions)
397+
if errors.Is(err, unix.ENOENT) {
398+
break
399+
}
400+
if err != nil {
401+
return nil, fmt.Errorf("load pinned map: %w", err)
402+
}
403+
defer closeOnError(m)
404+
405+
if err := spec.Compatible(m); err != nil {
406+
return nil, fmt.Errorf("use pinned map %s: %w", spec.Name, err)
407+
}
408+
409+
return m, nil
383410
case PinNone:
384411
// Nothing to do here
385412

@@ -422,6 +449,16 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions) (_ *Map, err error) {
422449
}
423450
}
424451

452+
if spec.Pinning == PinByPath {
453+
path, ok := opts.PinPathMapping[spec.Name]
454+
if !ok {
455+
return nil, fmt.Errorf("pin by path: no path found for map %v", spec.Name)
456+
}
457+
if err := m.Pin(path); err != nil {
458+
return nil, fmt.Errorf("pin map to %s: %w", path, err)
459+
}
460+
}
461+
425462
return m, nil
426463
}
427464

map_test.go

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1602,7 +1602,7 @@ func TestNewMapFromID(t *testing.T) {
16021602
}
16031603
}
16041604

1605-
func TestMapPinning(t *testing.T) {
1605+
func TestMapPinningPinPath(t *testing.T) {
16061606
tmp := testutils.TempBPFFS(t)
16071607

16081608
spec := &MapSpec{
@@ -1659,6 +1659,137 @@ func TestMapPinning(t *testing.T) {
16591659
qt.Assert(t, qt.StringContains(err.Error(), "ValueSize"))
16601660
}
16611661

1662+
func TestMapPinningPinPathMapping(t *testing.T) {
1663+
tmp := testutils.TempBPFFS(t)
1664+
1665+
spec := &MapSpec{
1666+
Name: "test",
1667+
Type: Hash,
1668+
KeySize: 4,
1669+
ValueSize: 4,
1670+
MaxEntries: 1,
1671+
Pinning: PinByPath,
1672+
}
1673+
1674+
m1 := mustNewMap(t, spec, &MapOptions{
1675+
PinPathMapping: map[string]string{spec.Name: filepath.Join(tmp, "foo")},
1676+
})
1677+
pinned := m1.IsPinned()
1678+
qt.Assert(t, qt.IsTrue(pinned))
1679+
1680+
m1Info, err := m1.Info()
1681+
qt.Assert(t, qt.IsNil(err))
1682+
1683+
if err := m1.Put(uint32(0), uint32(42)); err != nil {
1684+
t.Fatal("Can't write value:", err)
1685+
}
1686+
1687+
m2 := mustNewMap(t, spec, &MapOptions{
1688+
PinPathMapping: map[string]string{spec.Name: filepath.Join(tmp, "foo")},
1689+
})
1690+
1691+
m2Info, err := m2.Info()
1692+
qt.Assert(t, qt.IsNil(err))
1693+
1694+
if m1ID, ok := m1Info.ID(); ok {
1695+
m2ID, _ := m2Info.ID()
1696+
qt.Assert(t, qt.Equals(m2ID, m1ID))
1697+
}
1698+
1699+
var value uint32
1700+
if err := m2.Lookup(uint32(0), &value); err != nil {
1701+
t.Fatal("Can't read from map:", err)
1702+
}
1703+
1704+
if value != 42 {
1705+
t.Fatal("Pinning doesn't use pinned maps")
1706+
}
1707+
1708+
spec.KeySize = 8
1709+
spec.ValueSize = 8
1710+
_, err = newMap(t, spec, &MapOptions{
1711+
PinPathMapping: map[string]string{spec.Name: filepath.Join(tmp, "foo")},
1712+
})
1713+
if err == nil {
1714+
t.Fatalf("Opening a pinned map with a mismatching spec did not fail")
1715+
}
1716+
if !errors.Is(err, ErrMapIncompatible) {
1717+
t.Fatalf("Opening a pinned map with a mismatching spec failed with the wrong error")
1718+
}
1719+
1720+
// Check if error string mentions both KeySize and ValueSize.
1721+
qt.Assert(t, qt.StringContains(err.Error(), "KeySize"))
1722+
qt.Assert(t, qt.StringContains(err.Error(), "ValueSize"))
1723+
}
1724+
1725+
func TestPinMapMappingMultiplePaths(t *testing.T) {
1726+
tmp1 := testutils.TempBPFFS(t)
1727+
tmp2 := testutils.TempBPFFS(t)
1728+
1729+
spec1 := &MapSpec{
1730+
Name: "test1",
1731+
Type: Hash,
1732+
KeySize: 4,
1733+
ValueSize: 4,
1734+
MaxEntries: 1,
1735+
Pinning: PinByPath,
1736+
}
1737+
1738+
spec2 := &MapSpec{
1739+
Name: "test2",
1740+
Type: Hash,
1741+
KeySize: 8,
1742+
ValueSize: 8,
1743+
MaxEntries: 1,
1744+
Pinning: PinByPath,
1745+
}
1746+
1747+
pathMapping := map[string]string{
1748+
spec1.Name: filepath.Join(tmp1, "test1_target"),
1749+
spec2.Name: filepath.Join(tmp2, "test2_target"),
1750+
}
1751+
1752+
m1 := mustNewMap(t, spec1, &MapOptions{
1753+
PinPathMapping: pathMapping,
1754+
})
1755+
pinned := m1.IsPinned()
1756+
qt.Assert(t, qt.IsTrue(pinned))
1757+
1758+
if err := m1.Put(uint32(0), uint32(42)); err != nil {
1759+
t.Fatal("Can't write value in m1:", err)
1760+
}
1761+
1762+
m2 := mustNewMap(t, spec2, &MapOptions{
1763+
PinPathMapping: pathMapping,
1764+
})
1765+
pinned = m2.IsPinned()
1766+
qt.Assert(t, qt.IsTrue(pinned))
1767+
1768+
if err := m2.Put(uint64(0), uint64(42)); err != nil {
1769+
t.Fatal("Can't write value in m2:", err)
1770+
}
1771+
1772+
m1Loaded, err := LoadPinnedMap(filepath.Join(tmp1, "test1_target"), nil)
1773+
testutils.SkipIfNotSupported(t, err)
1774+
if err != nil {
1775+
t.Fatal(err)
1776+
}
1777+
1778+
if err := m1Loaded.Close(); err != nil {
1779+
t.Fatalf("close loaded map: %v", err)
1780+
}
1781+
1782+
m2Loaded, err := LoadPinnedMap(filepath.Join(tmp2, "test2_target"), nil)
1783+
testutils.SkipIfNotSupported(t, err)
1784+
if err != nil {
1785+
t.Fatal(err)
1786+
}
1787+
if err := m2Loaded.Close(); err != nil {
1788+
t.Fatalf("close loaded map: %v", err)
1789+
}
1790+
1791+
}
1792+
16621793
func TestMapHandle(t *testing.T) {
16631794
kv := &btf.Int{Size: 4}
16641795
m := mustNewMap(t, &MapSpec{

types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,8 @@ const (
353353
PinNone PinType = iota
354354
// Pin an object by using its name as the filename.
355355
PinByName
356+
// Pin an object using its path as the full path.
357+
PinByPath
356358
)
357359

358360
// LoadPinOptions control how a pinned object is loaded.

0 commit comments

Comments
 (0)