github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/tracer-collection/tracer-collection.go (about) 1 // Copyright 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 tracercollection 16 17 import ( 18 "fmt" 19 "os" 20 21 "github.com/cilium/ebpf" 22 log "github.com/sirupsen/logrus" 23 24 containercollection "github.com/inspektor-gadget/inspektor-gadget/pkg/container-collection" 25 "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgettracermanager/stream" 26 ) 27 28 const ( 29 MaxContainersPerNode = 1024 30 MountMapPrefix = "mntnsset_" 31 ) 32 33 type TracerCollection struct { 34 tracers map[string]tracer 35 containerCollection *containercollection.ContainerCollection 36 testOnly bool 37 } 38 39 type tracer struct { 40 tracerID string 41 42 containerSelector containercollection.ContainerSelector 43 44 mntnsSetMap *ebpf.Map 45 46 gadgetStream *stream.GadgetStream 47 } 48 49 func NewTracerCollection(cc *containercollection.ContainerCollection) (*TracerCollection, error) { 50 return &TracerCollection{ 51 tracers: make(map[string]tracer), 52 containerCollection: cc, 53 }, nil 54 } 55 56 func NewTracerCollectionTest(cc *containercollection.ContainerCollection) (*TracerCollection, error) { 57 return &TracerCollection{ 58 tracers: make(map[string]tracer), 59 containerCollection: cc, 60 testOnly: true, 61 }, nil 62 } 63 64 func (tc *TracerCollection) TracerMapsUpdater() containercollection.FuncNotify { 65 if tc.testOnly { 66 return func(event containercollection.PubSubEvent) {} 67 } 68 69 return func(event containercollection.PubSubEvent) { 70 switch event.Type { 71 case containercollection.EventTypeAddContainer: 72 // Skip the pause container, only if it is not a standalone 73 // container (ig use-case) 74 if event.Container.K8s.ContainerName == "" && event.Container.Runtime.ContainerName == "" { 75 return 76 } 77 78 for _, t := range tc.tracers { 79 if containercollection.ContainerSelectorMatches(&t.containerSelector, event.Container) { 80 mntnsC := uint64(event.Container.Mntns) 81 one := uint32(1) 82 if mntnsC != 0 { 83 t.mntnsSetMap.Put(mntnsC, one) 84 } else { 85 log.Errorf("new container with mntns=0") 86 } 87 } 88 } 89 90 case containercollection.EventTypeRemoveContainer: 91 for _, t := range tc.tracers { 92 if containercollection.ContainerSelectorMatches(&t.containerSelector, event.Container) { 93 mntnsC := uint64(event.Container.Mntns) 94 t.mntnsSetMap.Delete(mntnsC) 95 } 96 } 97 } 98 } 99 } 100 101 func (tc *TracerCollection) AddTracer(id string, containerSelector containercollection.ContainerSelector) error { 102 if _, ok := tc.tracers[id]; ok { 103 return fmt.Errorf("tracer id %q: %w", id, os.ErrExist) 104 } 105 var mntnsSetMap *ebpf.Map 106 if !tc.testOnly { 107 mntnsSpec := &ebpf.MapSpec{ 108 Name: MountMapPrefix + id, 109 Type: ebpf.Hash, 110 KeySize: 8, 111 ValueSize: 4, 112 MaxEntries: MaxContainersPerNode, 113 } 114 var err error 115 mntnsSetMap, err = ebpf.NewMap(mntnsSpec) 116 if err != nil { 117 return fmt.Errorf("creating mntnsset map: %w", err) 118 } 119 120 tc.containerCollection.ContainerRangeWithSelector(&containerSelector, func(c *containercollection.Container) { 121 one := uint32(1) 122 mntnsC := uint64(c.Mntns) 123 if mntnsC != 0 { 124 mntnsSetMap.Put(mntnsC, one) 125 } 126 }) 127 } 128 tc.tracers[id] = tracer{ 129 tracerID: id, 130 containerSelector: containerSelector, 131 mntnsSetMap: mntnsSetMap, 132 gadgetStream: stream.NewGadgetStream(), 133 } 134 return nil 135 } 136 137 func (tc *TracerCollection) RemoveTracer(id string) error { 138 if id == "" { 139 return fmt.Errorf("container id not set") 140 } 141 142 t, ok := tc.tracers[id] 143 if !ok { 144 return fmt.Errorf("unknown tracer %q", id) 145 } 146 147 if t.mntnsSetMap != nil { 148 t.mntnsSetMap.Close() 149 } 150 151 t.gadgetStream.Close() 152 153 delete(tc.tracers, id) 154 return nil 155 } 156 157 func (tc *TracerCollection) Stream(id string) (*stream.GadgetStream, error) { 158 t, ok := tc.tracers[id] 159 if !ok { 160 return nil, fmt.Errorf("unknown tracer %q", id) 161 } 162 return t.gadgetStream, nil 163 } 164 165 func (tc *TracerCollection) TracerCount() int { 166 return len(tc.tracers) 167 } 168 169 func (tc *TracerCollection) TracerDump() (out string) { 170 for i, t := range tc.tracers { 171 out += fmt.Sprintf("%v -> %q/%q (%s) Labels: \n", 172 i, 173 t.containerSelector.K8s.Namespace, 174 t.containerSelector.K8s.PodName, 175 t.containerSelector.K8s.ContainerName) 176 for k, v := range t.containerSelector.K8s.PodLabels { 177 out += fmt.Sprintf(" %v: %v\n", k, v) 178 } 179 out += " Matches:\n" 180 tc.containerCollection.ContainerRangeWithSelector(&t.containerSelector, func(c *containercollection.Container) { 181 out += fmt.Sprintf(" - %s/%s [Mntns=%v CgroupID=%v]\n", c.K8s.Namespace, c.K8s.PodName, c.Mntns, c.CgroupID) 182 }) 183 } 184 return 185 } 186 187 func (tc *TracerCollection) TracerExists(id string) bool { 188 _, ok := tc.tracers[id] 189 return ok 190 } 191 192 func (tc *TracerCollection) Close() {} 193 194 func (tc *TracerCollection) TracerMountNsMap(id string) (*ebpf.Map, error) { 195 t, ok := tc.tracers[id] 196 if !ok { 197 return nil, fmt.Errorf("unknown tracer %q", id) 198 } 199 200 return t.mntnsSetMap, nil 201 }