func PktBufFree(buf *PktBuf) {
	buf.mempool.freeStack[buf.mempool.freeStackTop] = buf.mempoolIdx
	buf.mempool.freeStackTop++
}
PktBufFree frees PktBuf
package driver
import (
	"encoding/binary"
	"fmt"
	"log"
	"math/rand"
	"os"
	"syscall"
	"time"
	"unsafe"
)
const (
	hugePageBits       = 21
	hugePageSize       = 1 << hugePageBits
	sizePktBufHeadroom = 40
)
type PktBuf struct {
	Pkt        []byte
	PhyAddr    uint64
	mempool    *Mempool
	mempoolIdx uint32
	Size       uint32
}
type Mempool struct {
	buf                               []byte
	bufSize, numEntries, freeStackTop uint32
	freeStack                         []uint32
	packetBuf                         []*PktBuf
}
func virtToPhys(virt uintptr) uintptr {
	pagesize := syscall.Getpagesize()
	fd, err := os.OpenFile("/proc/self/pagemap", os.O_RDONLY, 0700)
	defer fd.Close()
	if err != nil {
		log.Fatalf("Error opening pagemap: %v", err)
	}
	rbuf := make([]byte, unsafe.Sizeof(uintptr(0)))
	_, err = fd.ReadAt(rbuf, int64(virt)/int64(pagesize)*int64(unsafe.Sizeof(uintptr(0))))
	if err != nil {
		log.Fatalf("Error translating address: %v", err)
	}
	var phy uintptr
	if isBig {
		phy = uintptr(binary.BigEndian.Uint64(rbuf))
	} else {
		phy = uintptr(binary.LittleEndian.Uint64(rbuf))
	}
	if phy == 0 {
		log.Fatalf("failed to translate virtual address %#v to physical address", virt)
	}
	return (phy&0x7fffffffffffff)*uintptr(pagesize) + virt%uintptr(pagesize)
}
func memoryAllocateDma(size uint32, requireContiguous bool) ([]byte, uintptr) {
	if size%hugePageSize != 0 {
		size = ((size >> hugePageBits) + 1) << hugePageBits
	}
	if requireContiguous && size > hugePageSize {
		log.Fatal("could not map physically contiguous memory\n")
	}
	rand.Seed(time.Now().UTC().UnixNano())
	id := rand.Uint32()
	path := fmt.Sprintf("/mnt/huge/ixy-%v-%v", os.Getpid(), id)
	fd, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, syscall.S_IRWXU)
	defer fd.Close()
	if err != nil {
		log.Fatalf("opening hugetlbfs file failed, check that /mnt/huge is mounted. Error: %v\n", err)
	}
	err = fd.Truncate(int64(size))
	if err != nil {
		log.Fatalf("allocating huge page memory failed, check hugetlbfs configuration. Error: %v\n", err)
	}
	var mmap []byte
	mmap, err = syscall.Mmap(int(fd.Fd()), 0, int(size), syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED|syscall.MAP_HUGETLB)
	if err != nil {
		log.Fatalf("mmaping hugepage failed. Error: %v\n", err)
	}
	err = syscall.Mlock(mmap)
	if err != nil {
		log.Fatalf("disabling swap for DMA memory failed. Error: %v\n", err)
	}
	syscall.Unlink(path)
	return mmap, virtToPhys(uintptr(unsafe.Pointer(&mmap[0])))
}
func MemoryAllocateMempool(numEntries, entrySize uint32) *Mempool {
	if entrySize == 0 {
		entrySize = 2048
	}
	if hugePageSize%entrySize != 0 {
		log.Fatalf("entry size must be a divisor of the huge page size (%v)", hugePageSize)
	}
	memvirt, _ := memoryAllocateDma(numEntries*entrySize, false)
	fStack := make([]uint32, numEntries)
	pBuf := make([]*PktBuf, numEntries)
	mempool := &Mempool{
		buf:          memvirt,
		bufSize:      entrySize,
		numEntries:   numEntries,
		freeStackTop: numEntries,
		freeStack:    fStack,
		packetBuf:    pBuf,
	}
	for i := uint32(0); i < numEntries; i++ {
		mempool.freeStack[i] = i
		mempool.packetBuf[i] = &PktBuf{
			Pkt:        mempool.buf[i*entrySize : (i+1)*entrySize],
			PhyAddr:    uint64(virtToPhys(uintptr(unsafe.Pointer(&mempool.buf[i*entrySize])))),
			mempool:    mempool,
			mempoolIdx: i,
			Size:       0,
		}
	}
	return mempool
}
func PktBufAllocBatch(mempool *Mempool, numBufs uint32) []*PktBuf {
	if mempool.freeStackTop < numBufs {
		fmt.Printf("memory pool %v only has %v free bufs, requested %v\n", mempool, mempool.freeStackTop, numBufs)
		numBufs = mempool.freeStackTop
	}
	bufs := make([]*PktBuf, numBufs)
	for i := uint32(0); i < numBufs; i++ {
		mempool.freeStackTop--
		id := mempool.freeStack[mempool.freeStackTop]
		bufs[i] = mempool.packetBuf[id]
	}
	return bufs
}
func PktBufAlloc(mempool *Mempool) *PktBuf {
	if mempool.freeStackTop < 1 {
		fmt.Printf("memory pool %v is currently full, cannot allocate packet\n", mempool)
		return nil
	}
	mempool.freeStackTop--
	id := mempool.freeStack[mempool.freeStackTop]
	return mempool.packetBuf[id]
}