github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/datasource/data.go (about)

     1  // Copyright 2024 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 datasource
    16  
    17  import (
    18  	"encoding/binary"
    19  	"errors"
    20  	"fmt"
    21  	"io"
    22  	"maps"
    23  	"reflect"
    24  	"slices"
    25  	"sort"
    26  	"strings"
    27  	"sync"
    28  
    29  	"github.com/inspektor-gadget/inspektor-gadget/pkg/gadget-service/api"
    30  )
    31  
    32  type (
    33  	data  api.GadgetData
    34  	field api.Field
    35  )
    36  
    37  func (*data) private() {}
    38  
    39  func (f *field) ReflectType() reflect.Type {
    40  	switch f.Kind {
    41  	default:
    42  		return nil
    43  	case api.Kind_Int8:
    44  		return reflect.TypeOf(int8(0))
    45  	case api.Kind_Int16:
    46  		return reflect.TypeOf(int16(0))
    47  	case api.Kind_Int32:
    48  		return reflect.TypeOf(int32(0))
    49  	case api.Kind_Int64:
    50  		return reflect.TypeOf(int64(0))
    51  	case api.Kind_Uint8:
    52  		return reflect.TypeOf(uint8(0))
    53  	case api.Kind_Uint16:
    54  		return reflect.TypeOf(uint16(0))
    55  	case api.Kind_Uint32:
    56  		return reflect.TypeOf(uint32(0))
    57  	case api.Kind_Uint64:
    58  		return reflect.TypeOf(uint64(0))
    59  	case api.Kind_Float32:
    60  		return reflect.TypeOf(float32(0))
    61  	case api.Kind_Float64:
    62  		return reflect.TypeOf(float64(0))
    63  	case api.Kind_Bool:
    64  		return reflect.TypeOf(false)
    65  	}
    66  }
    67  
    68  type dataSource struct {
    69  	name string
    70  	id   uint32
    71  
    72  	dType Type
    73  
    74  	// keeps information on registered fields
    75  	fields   []*field
    76  	fieldMap map[string]*field
    77  
    78  	tags        []string
    79  	annotations map[string]string
    80  
    81  	payloadCount uint32
    82  
    83  	requestedFields map[string]bool
    84  
    85  	subscriptions []*subscription
    86  
    87  	requested bool
    88  
    89  	byteOrder binary.ByteOrder
    90  	lock      sync.RWMutex
    91  }
    92  
    93  func newDataSource(t Type, name string) *dataSource {
    94  	return &dataSource{
    95  		name:            name,
    96  		dType:           t,
    97  		requestedFields: make(map[string]bool),
    98  		fieldMap:        make(map[string]*field),
    99  		byteOrder:       binary.NativeEndian,
   100  		tags:            make([]string, 0),
   101  		annotations:     map[string]string{},
   102  	}
   103  }
   104  
   105  func New(t Type, name string) DataSource {
   106  	return newDataSource(t, name)
   107  }
   108  
   109  func NewFromAPI(in *api.DataSource) (DataSource, error) {
   110  	ds := newDataSource(Type(in.Type), in.Name)
   111  	for _, f := range in.Fields {
   112  		ds.fields = append(ds.fields, (*field)(f))
   113  		if !FieldFlagUnreferenced.In(f.Flags) {
   114  			ds.fieldMap[f.Name] = (*field)(f)
   115  		}
   116  	}
   117  	if in.Flags&api.DataSourceFlagsBigEndian != 0 {
   118  		ds.byteOrder = binary.BigEndian
   119  	} else {
   120  		ds.byteOrder = binary.LittleEndian
   121  	}
   122  	// TODO: add more checks / validation
   123  	return ds, nil
   124  }
   125  
   126  func (ds *dataSource) Name() string {
   127  	return ds.name
   128  }
   129  
   130  func (ds *dataSource) Type() Type {
   131  	return ds.dType
   132  }
   133  
   134  func (ds *dataSource) NewData() Data {
   135  	d := &data{
   136  		Payload: make([][]byte, ds.payloadCount),
   137  	}
   138  	for i := range d.Payload {
   139  		d.Payload[i] = make([]byte, 0)
   140  	}
   141  	return d
   142  }
   143  
   144  func (ds *dataSource) ByteOrder() binary.ByteOrder {
   145  	return ds.byteOrder
   146  }
   147  
   148  func resolveNames(id uint32, fields []*field, parentOffset uint32) (string, error) {
   149  	if id >= uint32(len(fields)) {
   150  		return "", errors.New("invalid id")
   151  	}
   152  	out := ""
   153  	if FieldFlagHasParent.In(fields[id].Flags) {
   154  		p, err := resolveNames(fields[id].Parent-parentOffset, fields, parentOffset)
   155  		if err != nil {
   156  			return "", errors.New("parent not found")
   157  		}
   158  		out = p + "."
   159  	}
   160  	out += fields[id].Name
   161  	return out, nil
   162  }
   163  
   164  // AddStaticFields adds a statically sized container for fields to the payload and returns an accessor for the
   165  // container; if you want to access individual fields, get them from the DataSource directly
   166  func (ds *dataSource) AddStaticFields(size uint32, fields []StaticField) (FieldAccessor, error) {
   167  	ds.lock.Lock()
   168  	defer ds.lock.Unlock()
   169  
   170  	idx := ds.payloadCount
   171  
   172  	// temporary write to newFields to not write to ds.fields in case of errors
   173  	newFields := make([]*field, 0, len(fields))
   174  
   175  	parentOffset := len(ds.fields)
   176  	parentFields := make(map[int]struct{})
   177  	checkParents := make(map[*field]struct{})
   178  
   179  	for _, f := range fields {
   180  		fieldName := f.FieldName()
   181  		if _, ok := ds.fieldMap[fieldName]; ok {
   182  			return nil, fmt.Errorf("field %q already exists", fieldName)
   183  		}
   184  		nf := &field{
   185  			Name:         fieldName,
   186  			Index:        uint32(len(ds.fields) + len(newFields)),
   187  			PayloadIndex: idx,
   188  			Flags:        FieldFlagStaticMember.Uint32(),
   189  		}
   190  		nf.Size = f.FieldSize()
   191  		nf.Offs = f.FieldOffset()
   192  		if nf.Offs+nf.Size > size {
   193  			return nil, fmt.Errorf("field %q exceeds size of container (offs %d, size %d, container size %d)", nf.Name, nf.Offs, nf.Size, size)
   194  		}
   195  		if s, ok := f.(TypedField); ok {
   196  			nf.Kind = s.FieldType()
   197  		}
   198  		if tagger, ok := f.(TaggedField); ok {
   199  			nf.Tags = tagger.FieldTags()
   200  		}
   201  		if s, ok := f.(FlaggedField); ok {
   202  			nf.Flags |= uint32(s.FieldFlags())
   203  		}
   204  		if s, ok := f.(AnnotatedField); ok {
   205  			nf.Annotations = s.FieldAnnotations()
   206  		}
   207  		if s, ok := f.(ParentedField); ok {
   208  			parent := s.FieldParent()
   209  			if parent >= 0 {
   210  				nf.Parent = uint32(parent + parentOffset)
   211  				nf.Flags |= FieldFlagHasParent.Uint32()
   212  				parentFields[parent] = struct{}{}
   213  				checkParents[nf] = struct{}{}
   214  			}
   215  		}
   216  		newFields = append(newFields, nf)
   217  	}
   218  
   219  	// Unref parent fields
   220  	for p := range parentFields {
   221  		FieldFlagUnreferenced.AddTo(&newFields[p].Flags)
   222  	}
   223  
   224  	// Check whether parent id is valid
   225  	for f := range checkParents {
   226  		parentID := f.Parent - uint32(parentOffset) // adjust offset again to match offset in newFields for this check
   227  		if parentID >= uint32(len(newFields)) {
   228  			return nil, fmt.Errorf("invalid parent for field %q", f.Name)
   229  		}
   230  	}
   231  
   232  	var err error
   233  	for i, f := range newFields {
   234  		f.FullName, err = resolveNames(uint32(i), newFields, uint32(parentOffset))
   235  		if err != nil {
   236  			return nil, fmt.Errorf("resolving full fieldnames: %w", err)
   237  		}
   238  	}
   239  
   240  	ds.fields = append(ds.fields, newFields...)
   241  
   242  	for _, f := range newFields {
   243  		ds.fieldMap[f.Name] = f
   244  	}
   245  
   246  	ds.payloadCount++
   247  
   248  	return &fieldAccessor{ds: ds, f: &field{
   249  		PayloadIndex: idx,
   250  		Size:         size,
   251  		Flags:        FieldFlagContainer.Uint32(),
   252  	}}, nil
   253  }
   254  
   255  func (ds *dataSource) AddField(name string, opts ...FieldOption) (FieldAccessor, error) {
   256  	ds.lock.Lock()
   257  	defer ds.lock.Unlock()
   258  
   259  	if _, ok := ds.fieldMap[name]; ok {
   260  		return nil, fmt.Errorf("field %q already exists", name)
   261  	}
   262  
   263  	nf := &field{
   264  		Name:     name,
   265  		FullName: name,
   266  		Index:    uint32(len(ds.fields)),
   267  		Kind:     api.Kind_Invalid,
   268  	}
   269  	for _, opt := range opts {
   270  		opt(nf)
   271  	}
   272  
   273  	// Reserve new payload for non-empty fields
   274  	if !FieldFlagEmpty.In(nf.Flags) {
   275  		nf.PayloadIndex = ds.payloadCount
   276  		ds.payloadCount++
   277  	}
   278  
   279  	ds.fields = append(ds.fields, nf)
   280  	ds.fieldMap[nf.FullName] = nf
   281  	return &fieldAccessor{ds: ds, f: nf}, nil
   282  }
   283  
   284  func (ds *dataSource) GetField(name string) FieldAccessor {
   285  	ds.lock.RLock()
   286  	defer ds.lock.RUnlock()
   287  
   288  	f, ok := ds.fieldMap[name]
   289  	if !ok {
   290  		return nil
   291  	}
   292  	return &fieldAccessor{ds: ds, f: f}
   293  }
   294  
   295  func (ds *dataSource) GetFieldsWithTag(tag ...string) []FieldAccessor {
   296  	ds.lock.RLock()
   297  	defer ds.lock.RUnlock()
   298  
   299  	res := make([]FieldAccessor, 0)
   300  	for _, f := range ds.fields {
   301  		for _, t := range tag {
   302  			if slices.Contains(f.Tags, t) {
   303  				res = append(res, &fieldAccessor{ds: ds, f: f})
   304  				break
   305  			}
   306  		}
   307  	}
   308  	return res
   309  }
   310  
   311  func (ds *dataSource) Subscribe(fn DataFunc, priority int) {
   312  	if fn == nil {
   313  		return
   314  	}
   315  
   316  	ds.lock.Lock()
   317  	defer ds.lock.Unlock()
   318  
   319  	ds.subscriptions = append(ds.subscriptions, &subscription{
   320  		priority: priority,
   321  		fn:       fn,
   322  	})
   323  	sort.SliceStable(ds.subscriptions, func(i, j int) bool {
   324  		return ds.subscriptions[i].priority < ds.subscriptions[j].priority
   325  	})
   326  }
   327  
   328  func (ds *dataSource) EmitAndRelease(d Data) error {
   329  	for _, sub := range ds.subscriptions {
   330  		err := sub.fn(ds, d)
   331  		if err != nil {
   332  			return err
   333  		}
   334  	}
   335  	return nil
   336  }
   337  
   338  func (ds *dataSource) Release(d Data) {
   339  }
   340  
   341  func (ds *dataSource) ReportLostData(ctr uint64) {
   342  	// TODO
   343  }
   344  
   345  func (ds *dataSource) IsRequestedField(fieldName string) bool {
   346  	return true
   347  	ds.lock.RLock()
   348  	defer ds.lock.RUnlock()
   349  	return ds.requestedFields[fieldName]
   350  }
   351  
   352  func (ds *dataSource) Dump(xd Data, wr io.Writer) {
   353  	ds.lock.RLock()
   354  	defer ds.lock.RUnlock()
   355  
   356  	d := xd.(*data)
   357  	for _, f := range ds.fields {
   358  		if f.Offs+f.Size > uint32(len(d.Payload[f.PayloadIndex])) {
   359  			fmt.Fprintf(wr, "%s (%d): ! invalid size\n", f.Name, f.Size)
   360  			continue
   361  		}
   362  		fmt.Fprintf(wr, "%s (%d) [%s]: ", f.Name, f.Size, strings.Join(f.Tags, " "))
   363  		if f.Offs > 0 || f.Size > 0 {
   364  			fmt.Fprintf(wr, "%v\n", d.Payload[f.PayloadIndex][f.Offs:f.Offs+f.Size])
   365  		} else {
   366  			fmt.Fprintf(wr, "%v\n", d.Payload[f.PayloadIndex])
   367  		}
   368  	}
   369  }
   370  
   371  func (ds *dataSource) Fields() []*api.Field {
   372  	ds.lock.RLock()
   373  	defer ds.lock.RUnlock()
   374  
   375  	res := make([]*api.Field, 0, len(ds.fields))
   376  	for _, f := range ds.fields {
   377  		res = append(res, (*api.Field)(f))
   378  	}
   379  	return res
   380  }
   381  
   382  func (ds *dataSource) Accessors(rootOnly bool) []FieldAccessor {
   383  	ds.lock.RLock()
   384  	defer ds.lock.RUnlock()
   385  
   386  	res := make([]FieldAccessor, 0, len(ds.fields))
   387  	for _, f := range ds.fields {
   388  		if rootOnly && FieldFlagHasParent.In(f.Flags) {
   389  			continue
   390  		}
   391  		res = append(res, &fieldAccessor{
   392  			ds: ds,
   393  			f:  f,
   394  		})
   395  	}
   396  	return res
   397  }
   398  
   399  func (ds *dataSource) IsRequested() bool {
   400  	ds.lock.RLock()
   401  	defer ds.lock.RUnlock()
   402  	return ds.requested
   403  }
   404  
   405  func (ds *dataSource) AddAnnotation(key, value string) {
   406  	ds.lock.Lock()
   407  	defer ds.lock.Unlock()
   408  	ds.annotations[key] = value
   409  }
   410  
   411  func (ds *dataSource) AddTag(tag string) {
   412  	ds.lock.Lock()
   413  	defer ds.lock.Unlock()
   414  	ds.tags = append(ds.tags, tag)
   415  }
   416  
   417  func (ds *dataSource) Annotations() map[string]string {
   418  	ds.lock.RLock()
   419  	defer ds.lock.RUnlock()
   420  	return maps.Clone(ds.annotations)
   421  }
   422  
   423  func (ds *dataSource) Tags() []string {
   424  	ds.lock.RLock()
   425  	defer ds.lock.RUnlock()
   426  	return slices.Clone(ds.tags)
   427  }