func (m *Map) Clone() (*Map, error) {
	if m == nil {
		return nil, nil
	}
	dup, err := m.fd.Dup()
	if err != nil {
		return nil, fmt.Errorf("can't clone map: %w", err)
	}
	return &Map{
		m.name,
		dup,
		m.typ,
		m.keySize,
		m.valueSize,
		m.maxEntries,
		m.flags,
		"",
		m.fullValueSize,
	}, nil
}
Clone creates a duplicate of the Map.

Closing the duplicate does not affect the original, and vice versa.
Changes made to the map are reflected by both instances however.
If the original map was pinned, the cloned map will not be pinned by default.

Cloning a nil Map returns nil.
package ebpf
import (
	"errors"
	"fmt"
	"io"
	"path/filepath"
	"reflect"
	"strings"
	"github.com/cilium/ebpf/internal"
	"github.com/cilium/ebpf/internal/btf"
	"github.com/cilium/ebpf/internal/unix"
)
var (
	ErrKeyNotExist      = errors.New("key does not exist")
	ErrKeyExist         = errors.New("key already exists")
	ErrIterationAborted = errors.New("iteration aborted")
	ErrMapIncompatible  = errors.New("map's spec is incompatible with pinned map")
)
type MapOptions struct {
	PinPath        string
	LoadPinOptions LoadPinOptions
}
type MapID uint32
type MapSpec struct {
	Name       string
	Type       MapType
	KeySize    uint32
	ValueSize  uint32
	MaxEntries uint32
	Flags uint32
	Pinning PinType
	NumaNode uint32
	Contents []MapKV
	Freeze bool
	InnerMap *MapSpec
	BTF *btf.Map
}
func (ms *MapSpec) String() string {
	return fmt.Sprintf("%s(keySize=%d, valueSize=%d, maxEntries=%d, flags=%d)", ms.Type, ms.KeySize, ms.ValueSize, ms.MaxEntries, ms.Flags)
}
func (ms *MapSpec) Copy() *MapSpec {
	if ms == nil {
		return nil
	}
	cpy := *ms
	cpy.Contents = make([]MapKV, len(ms.Contents))
	copy(cpy.Contents, ms.Contents)
	cpy.InnerMap = ms.InnerMap.Copy()
	return &cpy
}
func (ms *MapSpec) clampPerfEventArraySize() error {
	if ms.Type != PerfEventArray {
		return nil
	}
	n, err := internal.PossibleCPUs()
	if err != nil {
		return fmt.Errorf("perf event array: %w", err)
	}
	if n := uint32(n); ms.MaxEntries > n {
		ms.MaxEntries = n
	}
	return nil
}
type MapKV struct {
	Key   interface{}
	Value interface{}
}
func (ms *MapSpec) checkCompatibility(m *Map) error {
	switch {
	case m.typ != ms.Type:
		return fmt.Errorf("expected type %v, got %v: %w", ms.Type, m.typ, ErrMapIncompatible)
	case m.keySize != ms.KeySize:
		return fmt.Errorf("expected key size %v, got %v: %w", ms.KeySize, m.keySize, ErrMapIncompatible)
	case m.valueSize != ms.ValueSize:
		return fmt.Errorf("expected value size %v, got %v: %w", ms.ValueSize, m.valueSize, ErrMapIncompatible)
	case m.maxEntries != ms.MaxEntries:
		return fmt.Errorf("expected max entries %v, got %v: %w", ms.MaxEntries, m.maxEntries, ErrMapIncompatible)
	case m.flags != ms.Flags:
		return fmt.Errorf("expected flags %v, got %v: %w", ms.Flags, m.flags, ErrMapIncompatible)
	}
	return nil
}
type Map struct {
	name       string
	fd         *internal.FD
	typ        MapType
	keySize    uint32
	valueSize  uint32
	maxEntries uint32
	flags      uint32
	pinnedPath string
	fullValueSize int
}
func NewMapFromFD(fd int) (*Map, error) {
	if fd < 0 {
		return nil, errors.New("invalid fd")
	}
	return newMapFromFD(internal.NewFD(uint32(fd)))
}
func newMapFromFD(fd *internal.FD) (*Map, error) {
	info, err := newMapInfoFromFd(fd)
	if err != nil {
		fd.Close()
		return nil, fmt.Errorf("get map info: %s", err)
	}
	return newMap(fd, info.Name, info.Type, info.KeySize, info.ValueSize, info.MaxEntries, info.Flags)
}
func NewMap(spec *MapSpec) (*Map, error) {
	return NewMapWithOptions(spec, MapOptions{})
}
func NewMapWithOptions(spec *MapSpec, opts MapOptions) (*Map, error) {
	handles := newHandleCache()
	defer handles.close()
	return newMapWithOptions(spec, opts, handles)
}
func newMapWithOptions(spec *MapSpec, opts MapOptions, handles *handleCache) (_ *Map, err error) {
	closeOnError := func(c io.Closer) {
		if err != nil {
			c.Close()
		}
	}
	switch spec.Pinning {
	case PinByName:
		if spec.Name == "" || opts.PinPath == "" {
			return nil, fmt.Errorf("pin by name: missing Name or PinPath")
		}
		path := filepath.Join(opts.PinPath, spec.Name)
		m, err := LoadPinnedMap(path, &opts.LoadPinOptions)
		if errors.Is(err, unix.ENOENT) {
			break
		}
		if err != nil {
			return nil, fmt.Errorf("load pinned map: %w", err)
		}
		defer closeOnError(m)
		if err := spec.checkCompatibility(m); err != nil {
			return nil, fmt.Errorf("use pinned map %s: %w", spec.Name, err)
		}
		return m, nil
	case PinNone:
	default:
		return nil, fmt.Errorf("pin type %d: %w", int(spec.Pinning), ErrNotSupported)
	}
	var innerFd *internal.FD
	if spec.Type == ArrayOfMaps || spec.Type == HashOfMaps {
		if spec.InnerMap == nil {
			return nil, fmt.Errorf("%s requires InnerMap", spec.Type)
		}
		if spec.InnerMap.Pinning != PinNone {
			return nil, errors.New("inner maps cannot be pinned")
		}
		template, err := createMap(spec.InnerMap, nil, opts, handles)
		if err != nil {
			return nil, err
		}
		defer template.Close()
		innerFd = template.fd
	}
	m, err := createMap(spec, innerFd, opts, handles)
	if err != nil {
		return nil, err
	}
	defer closeOnError(m)
	if spec.Pinning == PinByName {
		path := filepath.Join(opts.PinPath, spec.Name)
		if err := m.Pin(path); err != nil {
			return nil, fmt.Errorf("pin map: %s", err)
		}
	}
	return m, nil
}
func createMap(spec *MapSpec, inner *internal.FD, opts MapOptions, handles *handleCache) (_ *Map, err error) {
	closeOnError := func(closer io.Closer) {
		if err != nil {
			closer.Close()
		}
	}
	spec = spec.Copy()
	switch spec.Type {
	case ArrayOfMaps:
		fallthrough
	case HashOfMaps:
		if err := haveNestedMaps(); err != nil {
			return nil, err
		}
		if spec.ValueSize != 0 && spec.ValueSize != 4 {
			return nil, errors.New("ValueSize must be zero or four for map of map")
		}
		spec.ValueSize = 4
	case PerfEventArray:
		if spec.KeySize != 0 && spec.KeySize != 4 {
			return nil, errors.New("KeySize must be zero or four for perf event array")
		}
		spec.KeySize = 4
		if spec.ValueSize != 0 && spec.ValueSize != 4 {
			return nil, errors.New("ValueSize must be zero or four for perf event array")
		}
		spec.ValueSize = 4
		if spec.MaxEntries == 0 {
			n, err := internal.PossibleCPUs()
			if err != nil {
				return nil, fmt.Errorf("perf event array: %w", err)
			}
			spec.MaxEntries = uint32(n)
		}
	}
	if spec.Flags&(unix.BPF_F_RDONLY_PROG|unix.BPF_F_WRONLY_PROG) > 0 || spec.Freeze {
		if err := haveMapMutabilityModifiers(); err != nil {
			return nil, fmt.Errorf("map create: %w", err)
		}
	}
	if spec.Flags&unix.BPF_F_MMAPABLE > 0 {
		if err := haveMmapableMaps(); err != nil {
			return nil, fmt.Errorf("map create: %w", err)
		}
	}
	if spec.Flags&unix.BPF_F_INNER_MAP > 0 {
		if err := haveInnerMaps(); err != nil {
			return nil, fmt.Errorf("map create: %w", err)
		}
	}
	attr := internal.BPFMapCreateAttr{
		MapType:    uint32(spec.Type),
		KeySize:    spec.KeySize,
		ValueSize:  spec.ValueSize,
		MaxEntries: spec.MaxEntries,
		Flags:      spec.Flags,
		NumaNode:   spec.NumaNode,
	}
	if inner != nil {
		var err error
		attr.InnerMapFd, err = inner.Value()
		if err != nil {
			return nil, fmt.Errorf("map create: %w", err)
		}
	}
	if haveObjName() == nil {
		attr.MapName = internal.NewBPFObjName(spec.Name)
	}
	var btfDisabled bool
	if spec.BTF != nil {
		handle, err := handles.btfHandle(btf.MapSpec(spec.BTF))
		btfDisabled = errors.Is(err, btf.ErrNotSupported)
		if err != nil && !btfDisabled {
			return nil, fmt.Errorf("load BTF: %w", err)
		}
		if handle != nil {
			attr.BTFFd = uint32(handle.FD())
			attr.BTFKeyTypeID = uint32(btf.MapKey(spec.BTF).ID())
			attr.BTFValueTypeID = uint32(btf.MapValue(spec.BTF).ID())
		}
	}
	fd, err := internal.BPFMapCreate(&attr)
	if err != nil {
		if errors.Is(err, unix.EPERM) {
			return nil, fmt.Errorf("map create: RLIMIT_MEMLOCK may be too low: %w", err)
		}
		if btfDisabled {
			return nil, fmt.Errorf("map create without BTF: %w", err)
		}
		return nil, fmt.Errorf("map create: %w", err)
	}
	defer closeOnError(fd)
	m, err := newMap(fd, spec.Name, spec.Type, spec.KeySize, spec.ValueSize, spec.MaxEntries, spec.Flags)
	if err != nil {
		return nil, fmt.Errorf("map create: %w", err)
	}
	if err := m.populate(spec.Contents); err != nil {
		return nil, fmt.Errorf("map create: can't set initial contents: %w", err)
	}
	if spec.Freeze {
		if err := m.Freeze(); err != nil {
			return nil, fmt.Errorf("can't freeze map: %w", err)
		}
	}
	return m, nil
}
func newMap(fd *internal.FD, name string, typ MapType, keySize, valueSize, maxEntries, flags uint32) (*Map, error) {
	m := &Map{
		name,
		fd,
		typ,
		keySize,
		valueSize,
		maxEntries,
		flags,
		"",
		int(valueSize),
	}
	if !typ.hasPerCPUValue() {
		return m, nil
	}
	possibleCPUs, err := internal.PossibleCPUs()
	if err != nil {
		return nil, err
	}
	m.fullValueSize = align(int(valueSize), 8) * possibleCPUs
	return m, nil
}
func (m *Map) String() string {
	if m.name != "" {
		return fmt.Sprintf("%s(%s)#%v", m.typ, m.name, m.fd)
	}
	return fmt.Sprintf("%s#%v", m.typ, m.fd)
}
func (m *Map) Type() MapType {
	return m.typ
}
func (m *Map) KeySize() uint32 {
	return m.keySize
}
func (m *Map) ValueSize() uint32 {
	return m.valueSize
}
func (m *Map) MaxEntries() uint32 {
	return m.maxEntries
}
func (m *Map) Flags() uint32 {
	return m.flags
}
func (m *Map) Info() (*MapInfo, error) {
	return newMapInfoFromFd(m.fd)
}
func (m *Map) Lookup(key, valueOut interface{}) error {
	valuePtr, valueBytes := makeBuffer(valueOut, m.fullValueSize)
	if err := m.lookup(key, valuePtr); err != nil {
		return err
	}
	return m.unmarshalValue(valueOut, valueBytes)
}
func (m *Map) LookupAndDelete(key, valueOut interface{}) error {
	valuePtr, valueBytes := makeBuffer(valueOut, m.fullValueSize)
	keyPtr, err := m.marshalKey(key)
	if err != nil {
		return fmt.Errorf("can't marshal key: %w", err)
	}
	if err := bpfMapLookupAndDelete(m.fd, keyPtr, valuePtr); err != nil {
		return fmt.Errorf("lookup and delete failed: %w", err)
	}
	return m.unmarshalValue(valueOut, valueBytes)
}
func (m *Map) LookupBytes(key interface{}) ([]byte, error) {
	valueBytes := make([]byte, m.fullValueSize)
	valuePtr := internal.NewSlicePointer(valueBytes)
	err := m.lookup(key, valuePtr)
	if errors.Is(err, ErrKeyNotExist) {
		return nil, nil
	}
	return valueBytes, err
}
func (m *Map) lookup(key interface{}, valueOut internal.Pointer) error {
	keyPtr, err := m.marshalKey(key)
	if err != nil {
		return fmt.Errorf("can't marshal key: %w", err)
	}
	if err = bpfMapLookupElem(m.fd, keyPtr, valueOut); err != nil {
		return fmt.Errorf("lookup failed: %w", err)
	}
	return nil
}
type MapUpdateFlags uint64
const (
	UpdateAny MapUpdateFlags = iota
	UpdateNoExist MapUpdateFlags = 1 << (iota - 1)
	UpdateExist
)
func (m *Map) Put(key, value interface{}) error {
	return m.Update(key, value, UpdateAny)
}
func (m *Map) Update(key, value interface{}, flags MapUpdateFlags) error {
	keyPtr, err := m.marshalKey(key)
	if err != nil {
		return fmt.Errorf("can't marshal key: %w", err)
	}
	valuePtr, err := m.marshalValue(value)
	if err != nil {
		return fmt.Errorf("can't marshal value: %w", err)
	}
	if err = bpfMapUpdateElem(m.fd, keyPtr, valuePtr, uint64(flags)); err != nil {
		return fmt.Errorf("update failed: %w", err)
	}
	return nil
}
func (m *Map) Delete(key interface{}) error {
	keyPtr, err := m.marshalKey(key)
	if err != nil {
		return fmt.Errorf("can't marshal key: %w", err)
	}
	if err = bpfMapDeleteElem(m.fd, keyPtr); err != nil {
		return fmt.Errorf("delete failed: %w", err)
	}
	return nil
}
func (m *Map) NextKey(key, nextKeyOut interface{}) error {
	nextKeyPtr, nextKeyBytes := makeBuffer(nextKeyOut, int(m.keySize))
	if err := m.nextKey(key, nextKeyPtr); err != nil {
		return err
	}
	if err := m.unmarshalKey(nextKeyOut, nextKeyBytes); err != nil {
		return fmt.Errorf("can't unmarshal next key: %w", err)
	}
	return nil
}
func (m *Map) NextKeyBytes(key interface{}) ([]byte, error) {
	nextKey := make([]byte, m.keySize)
	nextKeyPtr := internal.NewSlicePointer(nextKey)
	err := m.nextKey(key, nextKeyPtr)
	if errors.Is(err, ErrKeyNotExist) {
		return nil, nil
	}
	return nextKey, err
}
func (m *Map) nextKey(key interface{}, nextKeyOut internal.Pointer) error {
	var (
		keyPtr internal.Pointer
		err    error
	)
	if key != nil {
		keyPtr, err = m.marshalKey(key)
		if err != nil {
			return fmt.Errorf("can't marshal key: %w", err)
		}
	}
	if err = bpfMapGetNextKey(m.fd, keyPtr, nextKeyOut); err != nil {
		return fmt.Errorf("next key failed: %w", err)
	}
	return nil
}
func (m *Map) BatchLookup(prevKey, nextKeyOut, keysOut, valuesOut interface{}, opts *BatchOptions) (int, error) {
	return m.batchLookup(internal.BPF_MAP_LOOKUP_BATCH, prevKey, nextKeyOut, keysOut, valuesOut, opts)
}
func (m *Map) BatchLookupAndDelete(prevKey, nextKeyOut, keysOut, valuesOut interface{}, opts *BatchOptions) (int, error) {
	return m.batchLookup(internal.BPF_MAP_LOOKUP_AND_DELETE_BATCH, prevKey, nextKeyOut, keysOut, valuesOut, opts)
}
func (m *Map) batchLookup(cmd internal.BPFCmd, startKey, nextKeyOut, keysOut, valuesOut interface{}, opts *BatchOptions) (int, error) {
	if err := haveBatchAPI(); err != nil {
		return 0, err
	}
	if m.typ.hasPerCPUValue() {
		return 0, ErrNotSupported
	}
	keysValue := reflect.ValueOf(keysOut)
	if keysValue.Kind() != reflect.Slice {
		return 0, fmt.Errorf("keys must be a slice")
	}
	valuesValue := reflect.ValueOf(valuesOut)
	if valuesValue.Kind() != reflect.Slice {
		return 0, fmt.Errorf("valuesOut must be a slice")
	}
	count := keysValue.Len()
	if count != valuesValue.Len() {
		return 0, fmt.Errorf("keysOut and valuesOut must be the same length")
	}
	keyBuf := make([]byte, count*int(m.keySize))
	keyPtr := internal.NewSlicePointer(keyBuf)
	valueBuf := make([]byte, count*int(m.fullValueSize))
	valuePtr := internal.NewSlicePointer(valueBuf)
	var (
		startPtr internal.Pointer
		err      error
		retErr   error
	)
	if startKey != nil {
		startPtr, err = marshalPtr(startKey, int(m.keySize))
		if err != nil {
			return 0, err
		}
	}
	nextPtr, nextBuf := makeBuffer(nextKeyOut, int(m.keySize))
	ct, err := bpfMapBatch(cmd, m.fd, startPtr, nextPtr, keyPtr, valuePtr, uint32(count), opts)
	if err != nil {
		if !errors.Is(err, ErrKeyNotExist) {
			return 0, err
		}
		retErr = ErrKeyNotExist
	}
	err = m.unmarshalKey(nextKeyOut, nextBuf)
	if err != nil {
		return 0, err
	}
	err = unmarshalBytes(keysOut, keyBuf)
	if err != nil {
		return 0, err
	}
	err = unmarshalBytes(valuesOut, valueBuf)
	if err != nil {
		retErr = err
	}
	return int(ct), retErr
}
func (m *Map) BatchUpdate(keys, values interface{}, opts *BatchOptions) (int, error) {
	if err := haveBatchAPI(); err != nil {
		return 0, err
	}
	if m.typ.hasPerCPUValue() {
		return 0, ErrNotSupported
	}
	keysValue := reflect.ValueOf(keys)
	if keysValue.Kind() != reflect.Slice {
		return 0, fmt.Errorf("keys must be a slice")
	}
	valuesValue := reflect.ValueOf(values)
	if valuesValue.Kind() != reflect.Slice {
		return 0, fmt.Errorf("values must be a slice")
	}
	var (
		count    = keysValue.Len()
		valuePtr internal.Pointer
		err      error
	)
	if count != valuesValue.Len() {
		return 0, fmt.Errorf("keys and values must be the same length")
	}
	keyPtr, err := marshalPtr(keys, count*int(m.keySize))
	if err != nil {
		return 0, err
	}
	valuePtr, err = marshalPtr(values, count*int(m.valueSize))
	if err != nil {
		return 0, err
	}
	var nilPtr internal.Pointer
	ct, err := bpfMapBatch(internal.BPF_MAP_UPDATE_BATCH, m.fd, nilPtr, nilPtr, keyPtr, valuePtr, uint32(count), opts)
	return int(ct), err
}
func (m *Map) BatchDelete(keys interface{}, opts *BatchOptions) (int, error) {
	if err := haveBatchAPI(); err != nil {
		return 0, err
	}
	if m.typ.hasPerCPUValue() {
		return 0, ErrNotSupported
	}
	keysValue := reflect.ValueOf(keys)
	if keysValue.Kind() != reflect.Slice {
		return 0, fmt.Errorf("keys must be a slice")
	}
	count := keysValue.Len()
	keyPtr, err := marshalPtr(keys, count*int(m.keySize))
	if err != nil {
		return 0, fmt.Errorf("cannot marshal keys: %v", err)
	}
	var nilPtr internal.Pointer
	ct, err := bpfMapBatch(internal.BPF_MAP_DELETE_BATCH, m.fd, nilPtr, nilPtr, keyPtr, nilPtr, uint32(count), opts)
	return int(ct), err
}
func (m *Map) Iterate() *MapIterator {
	return newMapIterator(m)
}
func (m *Map) Close() error {
	if m == nil {
		return nil
	}
	return m.fd.Close()
}
func (m *Map) FD() int {
	fd, err := m.fd.Value()
	if err != nil {
		return -1
	}
	return int(fd)
}