Repository: cilium/ebpf
Pull request #551 (2022-01-25 20:44:05)

coll,elf: use string references to inner maps/progs in MapSpec.Contents
Since the caller doesn't have access to programStub or mapStub, manually populating a MapSpec.Contents with inner maps or programs was not possible.

This patch eliminates the programStub and mapStub types in favor of normal strings so references to other progs/maps in the same CollectionSpec can be added (or changed) by the caller.


Patch:
diff --git a/collection.go b/collection.go
index 7ba15e1..fb32ada 100644
--- a/collection.go
+++ b/collection.go
@@ -483,24 +483,30 @@ func (cl *collectionLoader) populateMaps() error {
 
 		mapSpec = mapSpec.Copy()
 
-		// Replace any object stubs with loaded objects.
+		// MapSpecs that refer to inner maps or programs within the same
+		// CollectionSpec do so using strings. These strings are used as the key
+		// to look up the respective object in the Maps or Programs fields.
+		// Resolve those references to actual Map or Program resources that
+		// have been loaded into the kernel.
 		for i, kv := range mapSpec.Contents {
-			switch v := kv.Value.(type) {
-			case programStub:
-				// loadProgram is idempotent and could return an existing Program.
-				prog, err := cl.loadProgram(string(v))
-				if err != nil {
-					return fmt.Errorf("loading program %s, for map %s: %w", v, mapName, err)
+			if objName, ok := kv.Value.(string); ok {
+				switch mapSpec.Type {
+				case ProgramArray:
+					// loadProgram is idempotent and could return an existing Program.
+					prog, err := cl.loadProgram(objName)
+					if err != nil {
+						return fmt.Errorf("loading program %s, for map %s: %w", objName, mapName, err)
+					}
+					mapSpec.Contents[i] = MapKV{kv.Key, prog}
+
+				case ArrayOfMaps, HashOfMaps:
+					// loadMap is idempotent and could return an existing Map.
+					innerMap, err := cl.loadMap(objName)
+					if err != nil {
+						return fmt.Errorf("loading inner map %s, for map %s: %w", objName, mapName, err)
+					}
+					mapSpec.Contents[i] = MapKV{kv.Key, innerMap}
 				}
-				mapSpec.Contents[i] = MapKV{kv.Key, prog}
-
-			case mapStub:
-				// loadMap is idempotent and could return an existing Map.
-				innerMap, err := cl.loadMap(string(v))
-				if err != nil {
-					return fmt.Errorf("loading inner map %s, for map %s: %w", v, mapName, err)
-				}
-				mapSpec.Contents[i] = MapKV{kv.Key, innerMap}
 			}
 		}
 
diff --git a/elf_reader.go b/elf_reader.go
index 53c9758..bbc8831 100644
--- a/elf_reader.go
+++ b/elf_reader.go
@@ -728,14 +728,6 @@ func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec) error {
 	return nil
 }
 
-// A programStub is a placeholder for a Program to be inserted at a certain map key.
-// It needs to be resolved into a Program later on in the loader process.
-type programStub string
-
-// A mapStub is a placeholder for a Map to be inserted at a certain map key.
-// It needs to be resolved into a Map later on in the loader process.
-type mapStub string
-
 // mapSpecFromBTF produces a MapSpec based on a btf.Struct def representing
 // a BTF map definition. The name and spec arguments will be copied to the
 // resulting MapSpec, and inner must be true on any resursive invocations.
@@ -1009,9 +1001,9 @@ func resolveBTFValuesContents(es *elfSection, vs *btf.VarSecinfo, member btf.Mem
 		// skipped here.
 		switch t := elf.ST_TYPE(r.Info); t {
 		case elf.STT_FUNC:
-			contents = append(contents, MapKV{uint32(k), programStub(r.Name)})
+			contents = append(contents, MapKV{uint32(k), r.Name})
 		case elf.STT_OBJECT:
-			contents = append(contents, MapKV{uint32(k), mapStub(r.Name)})
+			contents = append(contents, MapKV{uint32(k), r.Name})
 		default:
 			return nil, fmt.Errorf("unknown relocation type %v", t)
 		}


Test patch:
diff --git a/elf_reader_test.go b/elf_reader_test.go
index a0d48c7..cbb24e9 100644
--- a/elf_reader_test.go
+++ b/elf_reader_test.go
@@ -363,8 +363,12 @@ func TestLoadInitializedBTFMap(t *testing.T) {
 				t.Errorf("expecting MapSpec entry Key to equal 1, got %v", p.Key)
 			}
 
-			if _, ok := p.Value.(programStub); !ok {
-				t.Errorf("expecting MapSpec entry Value to be of type programStub, got %T", p.Value)
+			if _, ok := p.Value.(string); !ok {
+				t.Errorf("expecting MapSpec entry Value to be a string, got %T", p.Value)
+			}
+
+			if p.Value != "tail_1" {
+				t.Errorf("expected MapSpec entry Value 'tail_1', got: %s", p.Value)
 			}
 		})
 
@@ -383,8 +387,12 @@ func TestLoadInitializedBTFMap(t *testing.T) {
 				t.Errorf("expecting MapSpec entry Key to equal 1, got %v", p.Key)
 			}
 
-			if _, ok := p.Value.(mapStub); !ok {
-				t.Errorf("expecting MapSpec entry Value to be of type mapStub, got %T", p.Value)
+			if _, ok := p.Value.(string); !ok {
+				t.Errorf("expecting MapSpec entry Value to be a string, got %T", p.Value)
+			}
+
+			if p.Value != "inner_map" {
+				t.Errorf("expected MapSpec entry Value 'inner_map', got: %s", p.Value)
 			}
 		})
 	})