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  }