github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/gadgettracermanager/containers-map/tracer.go (about) 1 // Copyright 2019-2022 The Inspektor Gadget authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package containersmap 16 17 import ( 18 "errors" 19 "fmt" 20 "os" 21 "path/filepath" 22 23 "github.com/cilium/ebpf" 24 "golang.org/x/sys/unix" 25 26 containercollection "github.com/inspektor-gadget/inspektor-gadget/pkg/container-collection" 27 "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgettracermanager/common" 28 ) 29 30 //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target bpfel -cc clang -cflags ${CFLAGS} containersmap ./bpf/containers-map.c -- -I./bpf/ -I../../ 31 32 const ( 33 BPFMapName = "containers" 34 NameMaxLength = common.NameMaxLength 35 NameMaxCharacters = NameMaxLength - 1 36 ) 37 38 func copyToC(dest *[NameMaxLength]byte, source string) { 39 for i := 0; i < len(source) && i < NameMaxCharacters; i++ { 40 dest[i] = source[i] 41 } 42 } 43 44 // ContainersMap creates a global map /sys/fs/bpf/gadget/containers 45 // exposing container details for each mount namespace. 46 // 47 // This makes it possible for gadgets to access that information and 48 // display it directly from the BPF code. Example of such code: 49 // 50 // struct container *container_entry; 51 // container_entry = bpf_map_lookup_elem(&containers, &mntns_id); 52 // 53 // External tools such as tracee or bpftrace could also benefit from this just 54 // by using this "containers" map (other interaction with Inspektor Gadget is 55 // not necessary for this). 56 type ContainersMap struct { 57 // containersMap is the global map at /sys/fs/bpf/gadget/containers 58 // exposing container details for each mount namespace. 59 containersMap *ebpf.Map 60 61 coll *ebpf.Collection 62 63 pinPath string 64 } 65 66 func NewContainersMap(pinPath string) (*ContainersMap, error) { 67 if pinPath != "" { 68 if err := os.Mkdir(pinPath, 0o700); err != nil && !errors.Is(err, unix.EEXIST) { 69 return nil, fmt.Errorf("creating folder for pinning bpf maps: %w", err) 70 } 71 72 os.Remove(filepath.Join(pinPath, BPFMapName)) 73 } 74 75 spec, err := loadContainersmap() 76 if err != nil { 77 return nil, fmt.Errorf("loading asset: %w", err) 78 } 79 80 opts := ebpf.CollectionOptions{} 81 if pinPath != "" { 82 spec.Maps[BPFMapName].Pinning = ebpf.PinByName 83 opts.Maps.PinPath = pinPath 84 } 85 86 coll, err := ebpf.NewCollectionWithOptions(spec, opts) 87 if err != nil { 88 return nil, fmt.Errorf("creating BPF collection: %w", err) 89 } 90 91 m, ok := coll.Maps[BPFMapName] 92 if !ok { 93 return nil, fmt.Errorf("map %s not found", BPFMapName) 94 } 95 return &ContainersMap{ 96 containersMap: m, 97 pinPath: pinPath, 98 coll: coll, 99 }, nil 100 } 101 102 func (cm *ContainersMap) addContainerInMap(c *containercollection.Container) { 103 if cm.containersMap == nil || c.Mntns == 0 { 104 return 105 } 106 mntnsC := uint64(c.Mntns) 107 108 val := common.Container{} 109 110 copyToC(&val.ContainerID, c.Runtime.ContainerID) 111 copyToC(&val.Namespace, c.K8s.Namespace) 112 copyToC(&val.Pod, c.K8s.PodName) 113 copyToC(&val.Container, c.K8s.ContainerName) 114 115 cm.containersMap.Put(mntnsC, val) 116 } 117 118 func (cm *ContainersMap) deleteContainerFromMap(c *containercollection.Container) { 119 if cm.containersMap == nil || c.Mntns == 0 { 120 return 121 } 122 cm.containersMap.Delete(uint64(c.Mntns)) 123 } 124 125 func (cm *ContainersMap) ContainersMapUpdater() containercollection.FuncNotify { 126 return func(event containercollection.PubSubEvent) { 127 switch event.Type { 128 case containercollection.EventTypeAddContainer: 129 // Skip the pause container 130 if event.Container.K8s.ContainerName == "" { 131 return 132 } 133 134 cm.addContainerInMap(event.Container) 135 136 case containercollection.EventTypeRemoveContainer: 137 cm.deleteContainerFromMap(event.Container) 138 } 139 } 140 } 141 142 func (cm *ContainersMap) ContainersMap() *ebpf.Map { 143 return cm.containersMap 144 } 145 146 func (cm *ContainersMap) Close() { 147 if cm == nil { 148 return 149 } 150 os.Remove(filepath.Join(cm.pinPath, BPFMapName)) 151 cm.coll.Close() 152 }