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 }