github.com/elfadel/cilium@v1.6.12/pkg/bpf/map_linux.go (about)

     1  // Copyright 2016-2019 Authors of Cilium
     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  // +build linux
    16  
    17  package bpf
    18  
    19  import (
    20  	"bufio"
    21  	"context"
    22  	"fmt"
    23  	"os"
    24  	"path"
    25  	"reflect"
    26  	"sync"
    27  	"syscall"
    28  	"time"
    29  	"unsafe"
    30  
    31  	"github.com/cilium/cilium/api/v1/models"
    32  	"github.com/cilium/cilium/pkg/bpf/binary"
    33  	"github.com/cilium/cilium/pkg/byteorder"
    34  	"github.com/cilium/cilium/pkg/controller"
    35  	"github.com/cilium/cilium/pkg/lock"
    36  	"github.com/cilium/cilium/pkg/logging/logfields"
    37  	"github.com/cilium/cilium/pkg/metrics"
    38  	"github.com/cilium/cilium/pkg/option"
    39  
    40  	"github.com/sirupsen/logrus"
    41  	"golang.org/x/sys/unix"
    42  )
    43  
    44  type MapKey interface {
    45  	fmt.Stringer
    46  
    47  	// Returns pointer to start of key
    48  	GetKeyPtr() unsafe.Pointer
    49  
    50  	// Allocates a new value matching the key type
    51  	NewValue() MapValue
    52  
    53  	// DeepCopyMapKey returns a deep copy of the map key
    54  	DeepCopyMapKey() MapKey
    55  }
    56  
    57  type MapValue interface {
    58  	fmt.Stringer
    59  
    60  	// Returns pointer to start of value
    61  	GetValuePtr() unsafe.Pointer
    62  
    63  	// DeepCopyMapValue returns a deep copy of the map value
    64  	DeepCopyMapValue() MapValue
    65  }
    66  
    67  type MapInfo struct {
    68  	MapType  MapType
    69  	MapKey   MapKey
    70  	KeySize  uint32
    71  	MapValue MapValue
    72  	// ReadValueSize is the value size that is used to read from the BPF maps
    73  	// this value an the ValueSize values can be different for BPF_MAP_TYPE_PERCPU_HASH
    74  	// for example.
    75  	ReadValueSize uint32
    76  	ValueSize     uint32
    77  	MaxEntries    uint32
    78  	Flags         uint32
    79  	InnerID       uint32
    80  	OwnerProgType ProgType
    81  }
    82  
    83  type cacheEntry struct {
    84  	Key   MapKey
    85  	Value MapValue
    86  
    87  	DesiredAction DesiredAction
    88  	LastError     error
    89  }
    90  
    91  type Map struct {
    92  	MapInfo
    93  	fd   int
    94  	name string
    95  	path string
    96  	once sync.Once
    97  	lock lock.RWMutex
    98  
    99  	// inParallelMode is true when the Map is currently being run in
   100  	// parallel and all modifications are performed on both maps until
   101  	// EndParallelMode() is called.
   102  	inParallelMode bool
   103  
   104  	// cachedCommonName is the common portion of the name excluding any
   105  	// endpoint ID
   106  	cachedCommonName string
   107  
   108  	// enableSync is true when synchronization retries have been enabled.
   109  	enableSync bool
   110  
   111  	// openLock serializes calls to Map.Open()
   112  	openLock lock.Mutex
   113  
   114  	// NonPersistent is true if the map does not contain persistent data
   115  	// and should be removed on startup.
   116  	NonPersistent bool
   117  
   118  	// DumpParser is a function for parsing keys and values from BPF maps
   119  	dumpParser DumpParser
   120  
   121  	cache map[string]*cacheEntry
   122  
   123  	// errorResolverLastScheduled is the timestamp when the error resolver
   124  	// was last scheduled
   125  	errorResolverLastScheduled time.Time
   126  
   127  	// outstandingErrors is the number of outsanding errors syncing with
   128  	// the kernel
   129  	outstandingErrors int
   130  }
   131  
   132  // NewMap creates a new Map instance - object representing a BPF map
   133  func NewMap(name string, mapType MapType, mapKey MapKey, keySize int, mapValue MapValue, valueSize, maxEntries int, flags uint32, innerID uint32, dumpParser DumpParser) *Map {
   134  	m := &Map{
   135  		MapInfo: MapInfo{
   136  			MapType:       mapType,
   137  			MapKey:        mapKey,
   138  			KeySize:       uint32(keySize),
   139  			MapValue:      mapValue,
   140  			ReadValueSize: uint32(valueSize),
   141  			ValueSize:     uint32(valueSize),
   142  			MaxEntries:    uint32(maxEntries),
   143  			Flags:         flags,
   144  			InnerID:       innerID,
   145  			OwnerProgType: ProgTypeUnspec,
   146  		},
   147  		name:       path.Base(name),
   148  		dumpParser: dumpParser,
   149  	}
   150  	return m
   151  }
   152  
   153  // NewPerCPUHashMap creates a new Map type of "per CPU hash" - object representing a BPF map
   154  // The number of cpus is used to have the size representation of a value when
   155  // a lookup is made on this map types.
   156  func NewPerCPUHashMap(name string, mapKey MapKey, keySize int, mapValue MapValue, valueSize, cpus, maxEntries int, flags uint32, innerID uint32, dumpParser DumpParser) *Map {
   157  	m := &Map{
   158  		MapInfo: MapInfo{
   159  			MapType:       BPF_MAP_TYPE_PERCPU_HASH,
   160  			MapKey:        mapKey,
   161  			KeySize:       uint32(keySize),
   162  			MapValue:      mapValue,
   163  			ReadValueSize: uint32(valueSize * cpus),
   164  			ValueSize:     uint32(valueSize),
   165  			MaxEntries:    uint32(maxEntries),
   166  			Flags:         flags,
   167  			InnerID:       innerID,
   168  			OwnerProgType: ProgTypeUnspec,
   169  		},
   170  		name:       path.Base(name),
   171  		dumpParser: dumpParser,
   172  	}
   173  	return m
   174  }
   175  
   176  // WithNonPersistent turns the map non-persistent and returns the map
   177  func (m *Map) WithNonPersistent() *Map {
   178  	m.NonPersistent = true
   179  	return m
   180  }
   181  
   182  func (m *Map) commonName() string {
   183  	if m.cachedCommonName != "" {
   184  		return m.cachedCommonName
   185  	}
   186  
   187  	m.cachedCommonName = extractCommonName(m.name)
   188  	return m.cachedCommonName
   189  }
   190  
   191  // scheduleErrorResolver schedules a periodic resolver controller that scans
   192  // all BPF map caches for unresolved errors and attempts to resolve them. On
   193  // error of resolution, the controller is-rescheduled in an expedited manner
   194  // with an exponential back-off.
   195  //
   196  // m.lock must be held for writing
   197  func (m *Map) scheduleErrorResolver() {
   198  	m.outstandingErrors++
   199  
   200  	if time.Since(m.errorResolverLastScheduled) <= errorResolverSchedulerMinInterval {
   201  		return
   202  	}
   203  
   204  	m.errorResolverLastScheduled = time.Now()
   205  
   206  	go func() {
   207  		time.Sleep(errorResolverSchedulerDelay)
   208  		mapControllers.UpdateController(m.controllerName(),
   209  			controller.ControllerParams{
   210  				DoFunc:      m.resolveErrors,
   211  				RunInterval: errorResolverSchedulerMinInterval,
   212  			},
   213  		)
   214  	}()
   215  
   216  }
   217  
   218  // WithCache enables use of a cache. This will store all entries inserted from
   219  // user space in a local cache (map) and will indicate the status of each
   220  // individual entry.
   221  func (m *Map) WithCache() *Map {
   222  	m.cache = map[string]*cacheEntry{}
   223  	m.enableSync = true
   224  	return m
   225  }
   226  
   227  func (m *Map) GetFd() int {
   228  	return m.fd
   229  }
   230  
   231  // Name returns the basename of this map.
   232  func (m *Map) Name() string {
   233  	return m.name
   234  }
   235  
   236  // Path returns the path to this map on the filesystem.
   237  func (m *Map) Path() (string, error) {
   238  	if err := m.setPathIfUnset(); err != nil {
   239  		return "", err
   240  	}
   241  
   242  	return m.path, nil
   243  }
   244  
   245  // Unpin attempts to unpin (remove) the map from the filesystem.
   246  func (m *Map) Unpin() error {
   247  	path, err := m.Path()
   248  	if err != nil {
   249  		return err
   250  	}
   251  
   252  	return os.RemoveAll(path)
   253  }
   254  
   255  // UnpinIfExists tries to unpin (remove) the map only if it exists.
   256  func (m *Map) UnpinIfExists() error {
   257  	found, err := m.exist()
   258  	if err != nil {
   259  		return err
   260  	}
   261  
   262  	if !found {
   263  		return nil
   264  	}
   265  
   266  	return m.Unpin()
   267  }
   268  
   269  // DeepEquals compares the current map against another map to see that the
   270  // attributes of the two maps are the same.
   271  func (m *Map) DeepEquals(other *Map) bool {
   272  	return m.name == other.name &&
   273  		m.path == other.path &&
   274  		m.NonPersistent == other.NonPersistent &&
   275  		reflect.DeepEqual(m.MapInfo, other.MapInfo)
   276  }
   277  
   278  func (m *Map) controllerName() string {
   279  	return fmt.Sprintf("bpf-map-sync-%s", m.name)
   280  }
   281  
   282  func GetMapInfo(pid int, fd int) (*MapInfo, error) {
   283  
   284  	fdinfoFile := fmt.Sprintf("/proc/%d/fdinfo/%d", pid, fd)
   285  
   286  	file, err := os.Open(fdinfoFile)
   287  	if err != nil {
   288  		return nil, err
   289  	}
   290  	defer file.Close()
   291  
   292  	info := &MapInfo{}
   293  
   294  	scanner := bufio.NewScanner(file)
   295  	scanner.Split(bufio.ScanLines)
   296  	for scanner.Scan() {
   297  		var value int
   298  
   299  		line := scanner.Text()
   300  		if n, err := fmt.Sscanf(line, "map_type:\t%d", &value); n == 1 && err == nil {
   301  			info.MapType = MapType(value)
   302  		} else if n, err := fmt.Sscanf(line, "key_size:\t%d", &value); n == 1 && err == nil {
   303  			info.KeySize = uint32(value)
   304  		} else if n, err := fmt.Sscanf(line, "value_size:\t%d", &value); n == 1 && err == nil {
   305  			info.ValueSize = uint32(value)
   306  			info.ReadValueSize = uint32(value)
   307  		} else if n, err := fmt.Sscanf(line, "max_entries:\t%d", &value); n == 1 && err == nil {
   308  			info.MaxEntries = uint32(value)
   309  		} else if n, err := fmt.Sscanf(line, "map_flags:\t0x%x", &value); n == 1 && err == nil {
   310  			info.Flags = uint32(value)
   311  		} else if n, err := fmt.Sscanf(line, "owner_prog_type:\t%d", &value); n == 1 && err == nil {
   312  			info.OwnerProgType = ProgType(value)
   313  		}
   314  	}
   315  
   316  	if scanner.Err() != nil {
   317  		return nil, scanner.Err()
   318  	}
   319  
   320  	return info, nil
   321  }
   322  
   323  // OpenMap opens the given bpf map and generates the Map info based in the
   324  // information stored in the bpf map.
   325  // *Warning*: Calling this function requires the caller to properly setup
   326  // the MapInfo.MapKey and MapInfo.MapValues fields as those structures are not
   327  // stored in the bpf map.
   328  func OpenMap(name string) (*Map, error) {
   329  	// Expand path if needed
   330  	if !path.IsAbs(name) {
   331  		name = MapPath(name)
   332  	}
   333  
   334  	fd, err := ObjGet(name)
   335  	if err != nil {
   336  		return nil, err
   337  	}
   338  
   339  	info, err := GetMapInfo(os.Getpid(), fd)
   340  	if err != nil {
   341  		return nil, err
   342  	}
   343  
   344  	if info.MapType == 0 {
   345  		return nil, fmt.Errorf("Unable to determine map type")
   346  	}
   347  
   348  	if info.KeySize == 0 {
   349  		return nil, fmt.Errorf("Unable to determine map key size")
   350  	}
   351  
   352  	m := &Map{
   353  		MapInfo: *info,
   354  		fd:      fd,
   355  		name:    path.Base(name),
   356  		path:    name,
   357  	}
   358  
   359  	registerMap(name, m)
   360  
   361  	return m, nil
   362  }
   363  
   364  func (m *Map) setPathIfUnset() error {
   365  	if m.path == "" {
   366  		if m.name == "" {
   367  			return fmt.Errorf("either path or name must be set")
   368  		}
   369  
   370  		m.path = MapPath(m.name)
   371  	}
   372  
   373  	return nil
   374  }
   375  
   376  // EndParallelMode ends the parallel mode of a map
   377  func (m *Map) EndParallelMode() {
   378  	m.lock.Lock()
   379  	defer m.lock.Unlock()
   380  
   381  	if m.inParallelMode {
   382  		m.inParallelMode = false
   383  		m.scopedLogger().Debug("End of parallel mode")
   384  	}
   385  }
   386  
   387  // OpenParallel is similar to OpenOrCreate() but prepares the existing map to
   388  // be faded out while a new map is taking over. This can be used if a map is
   389  // shared between multiple consumers and the context of the shared map is
   390  // changing. Any update to the shared map would impact all consumers and
   391  // consumers can only be updated one by one. Parallel mode allows for consumers
   392  // to continue using the old version of the map until the consumer is updated
   393  // to use the new version.
   394  func (m *Map) OpenParallel() (bool, error) {
   395  	m.lock.Lock()
   396  	defer m.lock.Unlock()
   397  
   398  	if m.fd != 0 {
   399  		return false, fmt.Errorf("OpenParallel() called on already open map")
   400  	}
   401  
   402  	if err := m.setPathIfUnset(); err != nil {
   403  		return false, err
   404  	}
   405  
   406  	if _, err := os.Stat(m.path); err == nil {
   407  		err := os.Remove(m.path)
   408  		if err != nil {
   409  			log.WithError(err).Warning("Unable to remove BPF map for parallel operation")
   410  			// Fall back to non-parallel mode
   411  		} else {
   412  			m.scopedLogger().Debug("Opening map in parallel mode")
   413  			m.inParallelMode = true
   414  		}
   415  	}
   416  
   417  	return m.openOrCreate(true)
   418  }
   419  
   420  // OpenOrCreate attempts to open the Map, or if it does not yet exist, create
   421  // the Map. If the existing map's attributes such as map type, key/value size,
   422  // capacity, etc. do not match the Map's attributes, then the map will be
   423  // deleted and reopened without any attempt to retain its previous contents.
   424  // If the map is marked as non-persistent, it will always be recreated.
   425  //
   426  // If the map type is MapTypeLRUHash or MapTypeLPMTrie and the kernel lacks
   427  // support for this map type, then the map will be opened as MapTypeHash
   428  // instead. Note that the BPF code that interacts with this map *MUST* be
   429  // structured in such a way that the map is declared as the same type based on
   430  // the same probe logic (eg HAVE_LRU_MAP_TYPE, HAVE_LPM_MAP_TYPE).
   431  //
   432  // For code that uses an LPMTrie, the BPF code must also use macros to retain
   433  // the "longest prefix match" behaviour on top of the hash maps, for example
   434  // via LPM_LOOKUP_FN() (see bpf/lib/maps.h).
   435  //
   436  // To detect map type support properly, this function must be called after
   437  // a call to ReadFeatureProbes(); failure to do so will result in LPM or LRU
   438  // map types being unconditionally opened as hash maps.
   439  //
   440  // Returns whether the map was deleted and recreated, or an optional error.
   441  func (m *Map) OpenOrCreate() (bool, error) {
   442  	m.lock.Lock()
   443  	defer m.lock.Unlock()
   444  
   445  	return m.openOrCreate(true)
   446  }
   447  
   448  // OpenOrCreateUnpinned is similar to OpenOrCreate (see above) but without
   449  // pinning the map to the file system if it had to be created.
   450  func (m *Map) OpenOrCreateUnpinned() (bool, error) {
   451  	m.lock.Lock()
   452  	defer m.lock.Unlock()
   453  
   454  	return m.openOrCreate(false)
   455  }
   456  
   457  func (m *Map) openOrCreate(pin bool) (bool, error) {
   458  	if m.fd != 0 {
   459  		return false, nil
   460  	}
   461  
   462  	if err := m.setPathIfUnset(); err != nil {
   463  		return false, err
   464  	}
   465  
   466  	// If the map represents non-persistent data, always remove the map
   467  	// before opening or creating.
   468  	if m.NonPersistent {
   469  		os.Remove(m.path)
   470  	}
   471  
   472  	mapType := GetMapType(m.MapType)
   473  	flags := m.Flags | GetPreAllocateMapFlags(mapType)
   474  	fd, isNew, err := OpenOrCreateMap(m.path, int(mapType), m.KeySize, m.ValueSize, m.MaxEntries, flags, m.InnerID, pin)
   475  	if err != nil {
   476  		return false, err
   477  	}
   478  
   479  	registerMap(m.path, m)
   480  
   481  	m.fd = fd
   482  	m.MapType = mapType
   483  	m.Flags = flags
   484  	return isNew, nil
   485  }
   486  
   487  func (m *Map) Open() error {
   488  	m.openLock.Lock()
   489  	defer m.openLock.Unlock()
   490  
   491  	if m.fd != 0 {
   492  		return nil
   493  	}
   494  
   495  	if err := m.setPathIfUnset(); err != nil {
   496  		return err
   497  	}
   498  
   499  	fd, err := ObjGet(m.path)
   500  	if err != nil {
   501  		return err
   502  	}
   503  
   504  	registerMap(m.path, m)
   505  
   506  	m.fd = fd
   507  	m.MapType = GetMapType(m.MapType)
   508  	return nil
   509  }
   510  
   511  func (m *Map) Close() error {
   512  	m.lock.Lock()
   513  	defer m.lock.Unlock()
   514  
   515  	if m.enableSync {
   516  		mapControllers.RemoveController(m.controllerName())
   517  	}
   518  
   519  	if m.fd != 0 {
   520  		unix.Close(m.fd)
   521  		m.fd = 0
   522  	}
   523  
   524  	unregisterMap(m.path, m)
   525  
   526  	return nil
   527  }
   528  
   529  // Reopen attempts to close and re-open the received map.
   530  func (m *Map) Reopen() error {
   531  	m.Close()
   532  	return m.Open()
   533  }
   534  
   535  type DumpParser func(key []byte, value []byte, mapKey MapKey, mapValue MapValue) (MapKey, MapValue, error)
   536  type DumpCallback func(key MapKey, value MapValue)
   537  type MapValidator func(path string) (bool, error)
   538  
   539  // DumpWithCallback iterates over the Map and calls the given callback
   540  // function on each iteration. That callback function is receiving the
   541  // actual key and value. The callback function should consider creating a
   542  // deepcopy of the key and value on between each iterations to avoid memory
   543  // corruption.
   544  func (m *Map) DumpWithCallback(cb DumpCallback) error {
   545  	m.lock.RLock()
   546  	defer m.lock.RUnlock()
   547  
   548  	key := make([]byte, m.KeySize)
   549  	nextKey := make([]byte, m.KeySize)
   550  	value := make([]byte, m.ReadValueSize)
   551  
   552  	if err := m.Open(); err != nil {
   553  		return err
   554  	}
   555  
   556  	if err := GetFirstKey(m.fd, unsafe.Pointer(&nextKey[0])); err != nil {
   557  		return nil
   558  	}
   559  
   560  	mk := m.MapKey.DeepCopyMapKey()
   561  	mv := m.MapValue.DeepCopyMapValue()
   562  
   563  	bpfCurrentKey := bpfAttrMapOpElem{
   564  		mapFd: uint32(m.fd),
   565  		key:   uint64(uintptr(unsafe.Pointer(&key[0]))),
   566  		value: uint64(uintptr(unsafe.Pointer(&nextKey[0]))),
   567  	}
   568  	bpfCurrentKeyPtr := unsafe.Pointer(&bpfCurrentKey)
   569  	bpfCurrentKeySize := unsafe.Sizeof(bpfCurrentKey)
   570  
   571  	bpfNextKey := bpfAttrMapOpElem{
   572  		mapFd: uint32(m.fd),
   573  		key:   uint64(uintptr(unsafe.Pointer(&nextKey[0]))),
   574  		value: uint64(uintptr(unsafe.Pointer(&value[0]))),
   575  	}
   576  
   577  	bpfNextKeyPtr := unsafe.Pointer(&bpfNextKey)
   578  	bpfNextKeySize := unsafe.Sizeof(bpfNextKey)
   579  
   580  	for {
   581  		err := LookupElementFromPointers(m.fd, bpfNextKeyPtr, bpfNextKeySize)
   582  		if err != nil {
   583  			return err
   584  		}
   585  
   586  		mk, mv, err = m.dumpParser(nextKey, value, mk, mv)
   587  		if err != nil {
   588  			return err
   589  		}
   590  
   591  		if cb != nil {
   592  			cb(mk, mv)
   593  		}
   594  
   595  		copy(key, nextKey)
   596  
   597  		err = GetNextKeyFromPointers(m.fd, bpfCurrentKeyPtr, bpfCurrentKeySize)
   598  		if err != nil {
   599  			break
   600  		}
   601  	}
   602  	return nil
   603  }
   604  
   605  // DumpWithCallbackIfExists is similar to DumpWithCallback, but returns earlier
   606  // if the given map does not exist.
   607  func (m *Map) DumpWithCallbackIfExists(cb DumpCallback) error {
   608  	found, err := m.exist()
   609  	if err != nil {
   610  		return err
   611  	}
   612  
   613  	if found {
   614  		return m.DumpWithCallback(cb)
   615  	}
   616  
   617  	return nil
   618  }
   619  
   620  // DumpReliablyWithCallback is similar to DumpWithCallback, but performs
   621  // additional tracking of the current and recently seen keys, so that if an
   622  // element is removed from the underlying kernel map during the dump, the dump
   623  // can continue from a recently seen key rather than restarting from scratch.
   624  // In addition, it caps the maximum number of map entry iterations by the
   625  // maximum size of the map.
   626  //
   627  // The caller must provide a callback for handling each entry, and a stats
   628  // object initialized via a call to NewDumpStats().
   629  func (m *Map) DumpReliablyWithCallback(cb DumpCallback, stats *DumpStats) error {
   630  	var (
   631  		prevKey    = make([]byte, m.KeySize)
   632  		currentKey = make([]byte, m.KeySize)
   633  		nextKey    = make([]byte, m.KeySize)
   634  		value      = make([]byte, m.ReadValueSize)
   635  
   636  		prevKeyValid = false
   637  	)
   638  	stats.start()
   639  	defer stats.finish()
   640  
   641  	if err := m.Open(); err != nil {
   642  		return err
   643  	}
   644  
   645  	err := GetFirstKey(m.fd, unsafe.Pointer(&currentKey[0]))
   646  	if err != nil {
   647  		// Map is empty, nothing to clean up.
   648  		stats.Lookup = 1
   649  		stats.Completed = true
   650  		return nil
   651  	}
   652  
   653  	mk := m.MapKey.DeepCopyMapKey()
   654  	mv := m.MapValue.DeepCopyMapValue()
   655  
   656  	bpfCurrentKey := bpfAttrMapOpElem{
   657  		mapFd: uint32(m.fd),
   658  		key:   uint64(uintptr(unsafe.Pointer(&currentKey[0]))),
   659  		value: uint64(uintptr(unsafe.Pointer(&value[0]))),
   660  	}
   661  	bpfCurrentKeyPtr := unsafe.Pointer(&bpfCurrentKey)
   662  	bpfCurrentKeySize := unsafe.Sizeof(bpfCurrentKey)
   663  
   664  	bpfNextKey := bpfAttrMapOpElem{
   665  		mapFd: uint32(m.fd),
   666  		key:   uint64(uintptr(unsafe.Pointer(&currentKey[0]))),
   667  		value: uint64(uintptr(unsafe.Pointer(&nextKey[0]))),
   668  	}
   669  
   670  	bpfNextKeyPtr := unsafe.Pointer(&bpfNextKey)
   671  	bpfNextKeySize := unsafe.Sizeof(bpfNextKey)
   672  
   673  	for stats.Lookup = 1; stats.Lookup <= stats.MaxEntries; stats.Lookup++ {
   674  		// currentKey was returned by GetNextKey() so we know it existed in the map, but it may have been
   675  		// deleted by a concurrent map operation. If currentKey is no longer in the map, nextKey will be
   676  		// the first key in the map again. Use the nextKey only if we still find currentKey in the Lookup()
   677  		// after the GetNextKey() call, this way we know nextKey is NOT the first key in the map.
   678  		nextKeyValid := GetNextKeyFromPointers(m.fd, bpfNextKeyPtr, bpfNextKeySize)
   679  		err := LookupElementFromPointers(m.fd, bpfCurrentKeyPtr, bpfCurrentKeySize)
   680  		if err != nil {
   681  			stats.LookupFailed++
   682  
   683  			// Restarting from a invalid key starts the iteration again from the beginning.
   684  			// If we have a previously found key, try to restart from there instead
   685  			if prevKeyValid {
   686  				copy(currentKey, prevKey)
   687  				// Restart from a given previous key only once, otherwise if the prevKey is
   688  				// concurrently deleted we might loop forever trying to look it up.
   689  				prevKeyValid = false
   690  				stats.KeyFallback++
   691  			} else {
   692  				// Depending on exactly when currentKey was deleted from the map, nextKey may be the actual
   693  				// keyelement after the deleted one, or the first element in the map.
   694  				copy(currentKey, nextKey)
   695  				stats.Interrupted++
   696  			}
   697  			continue
   698  		}
   699  
   700  		mk, mv, err = m.dumpParser(currentKey, value, mk, mv)
   701  		if err != nil {
   702  			stats.Interrupted++
   703  			return err
   704  		}
   705  
   706  		if cb != nil {
   707  			cb(mk, mv)
   708  		}
   709  
   710  		if nextKeyValid != nil {
   711  			stats.Completed = true
   712  			break
   713  		}
   714  		// remember the last found key
   715  		copy(prevKey, currentKey)
   716  		prevKeyValid = true
   717  		// continue from the next key
   718  		copy(currentKey, nextKey)
   719  	}
   720  
   721  	return nil
   722  }
   723  
   724  // Dump returns the map (type map[string][]string) which contains all
   725  // data stored in BPF map.
   726  func (m *Map) Dump(hash map[string][]string) error {
   727  	callback := func(key MapKey, value MapValue) {
   728  		// No need to deep copy since we are creating strings.
   729  		hash[key.String()] = append(hash[key.String()], value.String())
   730  	}
   731  
   732  	if err := m.DumpWithCallback(callback); err != nil {
   733  		return err
   734  	}
   735  
   736  	return nil
   737  }
   738  
   739  // DumpIfExists dumps the contents of the map into hash via Dump() if the map
   740  // file exists
   741  func (m *Map) DumpIfExists(hash map[string][]string) error {
   742  	found, err := m.exist()
   743  	if err != nil {
   744  		return err
   745  	}
   746  
   747  	if found {
   748  		return m.Dump(hash)
   749  	}
   750  
   751  	return nil
   752  }
   753  
   754  func (m *Map) Lookup(key MapKey) (MapValue, error) {
   755  	m.lock.RLock()
   756  	defer m.lock.RUnlock()
   757  
   758  	value := key.NewValue()
   759  
   760  	if err := m.Open(); err != nil {
   761  		return nil, err
   762  	}
   763  
   764  	err := LookupElement(m.fd, key.GetKeyPtr(), value.GetValuePtr())
   765  	if err != nil {
   766  		return nil, err
   767  	}
   768  	return value, nil
   769  }
   770  
   771  func (m *Map) Update(key MapKey, value MapValue) error {
   772  	var err error
   773  
   774  	m.lock.Lock()
   775  	defer m.lock.Unlock()
   776  
   777  	defer func() {
   778  		if m.cache == nil {
   779  			return
   780  		}
   781  
   782  		desiredAction := OK
   783  		if err != nil {
   784  			desiredAction = Insert
   785  			m.scheduleErrorResolver()
   786  		}
   787  
   788  		m.cache[key.String()] = &cacheEntry{
   789  			Key:           key,
   790  			Value:         value,
   791  			DesiredAction: desiredAction,
   792  			LastError:     err,
   793  		}
   794  	}()
   795  
   796  	if err = m.Open(); err != nil {
   797  		return err
   798  	}
   799  
   800  	err = UpdateElement(m.fd, key.GetKeyPtr(), value.GetValuePtr(), 0)
   801  	if option.Config.MetricsConfig.BPFMapOps {
   802  		metrics.BPFMapOps.WithLabelValues(m.commonName(), metricOpUpdate, metrics.Error2Outcome(err)).Inc()
   803  	}
   804  	return err
   805  }
   806  
   807  // deleteCacheEntry evaluates the specified error, if nil the map key is
   808  // removed from the cache to indicate successful deletion. If non-nil, the map
   809  // key entry in the cache is updated to indicate deletion failure with the
   810  // specified error.
   811  //
   812  // Caller must hold m.lock for writing
   813  func (m *Map) deleteCacheEntry(key MapKey, err error) {
   814  	if m.cache == nil {
   815  		return
   816  	}
   817  
   818  	k := key.String()
   819  	if err == nil {
   820  		delete(m.cache, k)
   821  	} else {
   822  		entry, ok := m.cache[k]
   823  		if !ok {
   824  			m.cache[k] = &cacheEntry{
   825  				Key: key,
   826  			}
   827  			entry = m.cache[k]
   828  		}
   829  
   830  		entry.DesiredAction = Delete
   831  		entry.LastError = err
   832  		m.scheduleErrorResolver()
   833  	}
   834  }
   835  
   836  func (m *Map) DeleteWithErrno(key MapKey) (error, syscall.Errno) {
   837  	var (
   838  		err   error
   839  		errno syscall.Errno
   840  	)
   841  
   842  	m.lock.Lock()
   843  	defer m.lock.Unlock()
   844  
   845  	defer m.deleteCacheEntry(key, err)
   846  
   847  	if err = m.Open(); err != nil {
   848  		return err, 0
   849  	}
   850  
   851  	_, errno = deleteElement(m.fd, key.GetKeyPtr())
   852  	if option.Config.MetricsConfig.BPFMapOps {
   853  		metrics.BPFMapOps.WithLabelValues(m.commonName(), metricOpDelete, metrics.Errno2Outcome(errno)).Inc()
   854  	}
   855  	if errno != 0 {
   856  		err = fmt.Errorf("Unable to delete element from map %s: %s", m.name, errno.Error())
   857  	}
   858  
   859  	return err, errno
   860  }
   861  
   862  func (m *Map) Delete(key MapKey) error {
   863  	err, _ := m.DeleteWithErrno(key)
   864  	return err
   865  }
   866  
   867  // scopedLogger returns a logger scoped for the map. m.lock must be held.
   868  func (m *Map) scopedLogger() *logrus.Entry {
   869  	return log.WithFields(logrus.Fields{logfields.Path: m.path, "name": m.name})
   870  }
   871  
   872  // DeleteAll deletes all entries of a map by traversing the map and deleting individual
   873  // entries. Note that if entries are added while the taversal is in progress,
   874  // such entries may survive the deletion process.
   875  func (m *Map) DeleteAll() error {
   876  	m.lock.Lock()
   877  	defer m.lock.Unlock()
   878  
   879  	scopedLog := m.scopedLogger()
   880  	scopedLog.Debug("deleting all entries in map")
   881  
   882  	nextKey := make([]byte, m.KeySize)
   883  
   884  	if m.cache != nil {
   885  		// Mark all entries for deletion, upon successful deletion,
   886  		// entries will be removed or the LastError will be updated
   887  		for _, entry := range m.cache {
   888  			entry.DesiredAction = Delete
   889  			entry.LastError = fmt.Errorf("deletion pending")
   890  		}
   891  	}
   892  
   893  	if err := m.Open(); err != nil {
   894  		return err
   895  	}
   896  
   897  	mk := m.MapKey.DeepCopyMapKey()
   898  	mv := m.MapValue.DeepCopyMapValue()
   899  
   900  	for {
   901  		if err := GetFirstKey(m.fd, unsafe.Pointer(&nextKey[0])); err != nil {
   902  			break
   903  		}
   904  
   905  		err := DeleteElement(m.fd, unsafe.Pointer(&nextKey[0]))
   906  
   907  		mk, _, err2 := m.dumpParser(nextKey, []byte{}, mk, mv)
   908  		if err2 == nil {
   909  			m.deleteCacheEntry(mk, err)
   910  		} else {
   911  			log.WithError(err2).Warningf("Unable to correlate iteration key %v with cache entry. Inconsistent cache.", nextKey)
   912  		}
   913  
   914  		if err != nil {
   915  			return err
   916  		}
   917  	}
   918  
   919  	return nil
   920  }
   921  
   922  // GetNextKey returns the next key in the Map after key.
   923  func (m *Map) GetNextKey(key MapKey, nextKey MapKey) error {
   924  	if err := m.Open(); err != nil {
   925  		return err
   926  	}
   927  
   928  	err := GetNextKey(m.fd, key.GetKeyPtr(), nextKey.GetKeyPtr())
   929  	if option.Config.MetricsConfig.BPFMapOps {
   930  		metrics.BPFMapOps.WithLabelValues(m.commonName(), metricOpGetNextKey, metrics.Error2Outcome(err)).Inc()
   931  	}
   932  	return err
   933  }
   934  
   935  // ConvertKeyValue converts key and value from bytes to given Golang struct pointers.
   936  func ConvertKeyValue(bKey []byte, bValue []byte, key MapKey, value MapValue) (MapKey, MapValue, error) {
   937  
   938  	if len(bKey) > 0 {
   939  		if err := binary.Read(bKey, byteorder.Native, key); err != nil {
   940  			return nil, nil, fmt.Errorf("Unable to convert key: %s", err)
   941  		}
   942  	}
   943  
   944  	if len(bValue) > 0 {
   945  		if err := binary.Read(bValue, byteorder.Native, value); err != nil {
   946  			return nil, nil, fmt.Errorf("Unable to convert value: %s", err)
   947  		}
   948  	}
   949  
   950  	return key, value, nil
   951  }
   952  
   953  // GetModel returns a BPF map in the representation served via the API
   954  func (m *Map) GetModel() *models.BPFMap {
   955  	m.lock.RLock()
   956  	defer m.lock.RUnlock()
   957  
   958  	mapModel := &models.BPFMap{
   959  		Path: m.path,
   960  	}
   961  
   962  	if m.cache != nil {
   963  		mapModel.Cache = make([]*models.BPFMapEntry, len(m.cache))
   964  		i := 0
   965  		for k, entry := range m.cache {
   966  			model := &models.BPFMapEntry{
   967  				Key:           k,
   968  				DesiredAction: entry.DesiredAction.String(),
   969  			}
   970  
   971  			if entry.LastError != nil {
   972  				model.LastError = entry.LastError.Error()
   973  			}
   974  
   975  			if entry.Value != nil {
   976  				model.Value = entry.Value.String()
   977  			}
   978  			mapModel.Cache[i] = model
   979  			i++
   980  		}
   981  	}
   982  
   983  	return mapModel
   984  }
   985  
   986  // resolveErrors is schedule by scheduleErrorResolver() and runs periodically.
   987  // It resolves up to maxSyncErrors discrepancies between cache and BPF map in
   988  // the kernel.
   989  func (m *Map) resolveErrors(ctx context.Context) error {
   990  	started := time.Now()
   991  
   992  	m.lock.Lock()
   993  	defer m.lock.Unlock()
   994  
   995  	if m.cache == nil {
   996  		return nil
   997  	}
   998  
   999  	if m.outstandingErrors == 0 {
  1000  		return nil
  1001  	}
  1002  
  1003  	scopedLogger := m.scopedLogger()
  1004  	scopedLogger.WithField("remaining", m.outstandingErrors).
  1005  		Debug("Starting periodic BPF map error resolver")
  1006  
  1007  	resolved := 0
  1008  	scanned := 0
  1009  	errors := 0
  1010  	for k, e := range m.cache {
  1011  		scanned++
  1012  
  1013  		switch e.DesiredAction {
  1014  		case OK:
  1015  		case Insert:
  1016  			err := UpdateElement(m.fd, e.Key.GetKeyPtr(), e.Value.GetValuePtr(), 0)
  1017  			if option.Config.MetricsConfig.BPFMapOps {
  1018  				metrics.BPFMapOps.WithLabelValues(m.commonName(), metricOpUpdate, metrics.Error2Outcome(err)).Inc()
  1019  			}
  1020  			if err == nil {
  1021  				e.DesiredAction = OK
  1022  				e.LastError = nil
  1023  				resolved++
  1024  				m.outstandingErrors--
  1025  			} else {
  1026  				e.LastError = err
  1027  				errors++
  1028  			}
  1029  
  1030  		case Delete:
  1031  			_, err := deleteElement(m.fd, e.Key.GetKeyPtr())
  1032  			if option.Config.MetricsConfig.BPFMapOps {
  1033  				metrics.BPFMapOps.WithLabelValues(m.commonName(), metricOpDelete, metrics.Error2Outcome(err)).Inc()
  1034  			}
  1035  			if err == 0 || err == unix.ENOENT {
  1036  				delete(m.cache, k)
  1037  				resolved++
  1038  				m.outstandingErrors--
  1039  			} else {
  1040  				e.LastError = err
  1041  				errors++
  1042  			}
  1043  		}
  1044  
  1045  		m.cache[k] = e
  1046  
  1047  		// bail out if maximum errors are reached to relax the map lock
  1048  		if errors > maxSyncErrors {
  1049  			break
  1050  		}
  1051  	}
  1052  
  1053  	scopedLogger.WithFields(logrus.Fields{
  1054  		"remaining": m.outstandingErrors,
  1055  		"resolved":  resolved,
  1056  		"scanned":   scanned,
  1057  		"duration":  time.Since(started),
  1058  	}).Debug("BPF map error resolver completed")
  1059  
  1060  	if m.outstandingErrors > 0 {
  1061  		return fmt.Errorf("%d map sync errors", m.outstandingErrors)
  1062  	}
  1063  
  1064  	return nil
  1065  }
  1066  
  1067  // CheckAndUpgrade checks the received map's properties (for the map currently
  1068  // loaded into the kernel) against the desired properties, and if they do not
  1069  // match, deletes the map.
  1070  //
  1071  // Returns true if the map was upgraded.
  1072  func (m *Map) CheckAndUpgrade(desired *MapInfo) bool {
  1073  	desiredMapType := GetMapType(desired.MapType)
  1074  	desired.Flags |= GetPreAllocateMapFlags(desired.MapType)
  1075  
  1076  	return objCheck(
  1077  		m.fd,
  1078  		m.path,
  1079  		int(desiredMapType),
  1080  		desired.KeySize,
  1081  		desired.ValueSize,
  1082  		desired.MaxEntries,
  1083  		desired.Flags,
  1084  	)
  1085  }
  1086  
  1087  func (m *Map) exist() (bool, error) {
  1088  	path, err := m.Path()
  1089  	if err != nil {
  1090  		return false, err
  1091  	}
  1092  
  1093  	if _, err := os.Stat(path); err == nil {
  1094  		return true, nil
  1095  	}
  1096  
  1097  	return false, nil
  1098  }