Skip to content

Instantly share code, notes, and snippets.

@teknoraver
Last active September 29, 2025 11:37
Show Gist options
  • Save teknoraver/1a1e58c07ce6c6a8f2a196a3c7bb7e4c to your computer and use it in GitHub Desktop.
Save teknoraver/1a1e58c07ce6c6a8f2a196a3c7bb7e4c to your computer and use it in GitHub Desktop.
calculate the minimum BPF features needed to run a program
#!/usr/bin/env python3
import subprocess
import sys
cmds = [
"BPFMapCreate", "BPFMapLookupElem", "BPFMapUpdateElem", "BPFMapDeleteElem",
"BPFMapGetNextKey", "BPFProgLoad", "BPFObjPin", "BPFObjGet",
"BPFProgAttach", "BPFProgDetach", "BPFProgTestRun", "BPFProgGetNextId",
"BPFMapGetNextId", "BPFProgGetFdById", "BPFMapGetFdById",
"BPFObjGetInfoByFd", "BPFProgQuery", "BPFRawTracepointOpen",
"BPFBtfLoad", "BPFBtfGetFdById", "BPFTaskFdQuery",
"BPFMapLookupAndDeleteElem", "BPFMapFreeze", "BPFBtfGetNextId",
"BPFMapLookupBatch", "BPFMapLookupAndDeleteBatch", "BPFMapUpdateBatch",
"BPFMapDeleteBatch", "BPFLinkCreate", "BPFLinkUpdate",
"BPFLinkGetFdById", "BPFLinkGetNextId", "BPFEnableStats",
"BPFIterCreate", "BPFLinkDetach", "BPFProgBindMap", "BPFTokenCreate",
"BPFProgStreamReadByFd"
]
maps = [
"BPFMapTypeUnspec", "BPFMapTypeHash", "BPFMapTypeArray",
"BPFMapTypeProgArray", "BPFMapTypePerfEventArray", "BPFMapTypePercpuHash",
"BPFMapTypePercpuArray", "BPFMapTypeStackTrace", "BPFMapTypeCgroupArray",
"BPFMapTypeLruHash", "BPFMapTypeLruPercpuHash", "BPFMapTypeLpmTrie",
"BPFMapTypeArrayOfMaps", "BPFMapTypeHashOfMaps", "BPFMapTypeDevmap",
"BPFMapTypeSockmap", "BPFMapTypeCpumap", "BPFMapTypeXskmap",
"BPFMapTypeSockhash", "BPFMapTypeCgroupStorageDeprecated",
"BPFMapTypeReuseportSockarray", "BPFMapTypePercpuCgroupStorageDeprecated",
"BPFMapTypeQueue", "BPFMapTypeStack", "BPFMapTypeSkStorage",
"BPFMapTypeDevmapHash", "BPFMapTypeStructOps", "BPFMapTypeRingbuf",
"BPFMapTypeInodeStorage", "BPFMapTypeTaskStorage", "BPFMapTypeBloomFilter",
"BPFMapTypeUserRingbuf", "BPFMapTypeCgrpStorage", "BPFMapTypeArena"
]
progs = [
"BPFProgTypeUnspec", "BPFProgTypeSocketFilter", "BPFProgTypeKprobe",
"BPFProgTypeSchedCls", "BPFProgTypeSchedAct", "BPFProgTypeTracepoint",
"BPFProgTypeXdp", "BPFProgTypePerfEvent", "BPFProgTypeCgroupSkb",
"BPFProgTypeCgroupSock", "BPFProgTypeLwtIn", "BPFProgTypeLwtOut",
"BPFProgTypeLwtXmit", "BPFProgTypeSockOps", "BPFProgTypeSkSkb",
"BPFProgTypeCgroupDevice", "BPFProgTypeSkMsg", "BPFProgTypeRawTracepoint",
"BPFProgTypeCgroupSockAddr", "BPFProgTypeLwtSeg6local",
"BPFProgTypeLircMode2", "BPFProgTypeSkReuseport", "BPFProgTypeFlowDissector",
"BPFProgTypeCgroupSysctl", "BPFProgTypeRawTracepointWritable",
"BPFProgTypeCgroupSockopt", "BPFProgTypeTracing", "BPFProgTypeStructOps",
"BPFProgTypeExt", "BPFProgTypeLsm", "BPFProgTypeSkLookup",
"BPFProgTypeNetfilter"
]
attachments = [
"BPFCgroupInetIngress", "BPFCgroupInetEgress", "BPFCgroupInetSockCreate",
"BPFCgroupSockOps", "BPFSkSkbStreamParser", "BPFSkSkbStreamVerdict",
"BPFCgroupDevice", "BPFSkMsgVerdict", "BPFCgroupInet4Bind",
"BPFCgroupInet6Bind", "BPFCgroupInet4Connect", "BPFCgroupInet6Connect",
"BPFCgroupInet4PostBind", "BPFCgroupInet6PostBind", "BPFCgroupUdp4Sendmsg",
"BPFCgroupUdp6Sendmsg", "BPFLircMode2", "BPFFlowDissector",
"BPFCgroupSysctl", "BPFCgroupUdp4Recvmsg", "BPFCgroupUdp6Recvmsg",
"BPFCgroupGetsockopt", "BPFCgroupSetsockopt", "BPFTraceRawTp",
"BPFTraceFentry", "BPFTraceFexit", "BPFModifyReturn", "BPFLsmMac",
"BPFTraceIter", "BPFCgroupInet4Getpeername", "BPFCgroupInet6Getpeername",
"BPFCgroupInet4Getsockname", "BPFCgroupInet6Getsockname", "BPFXdpDevmap",
"BPFCgroupInetSockRelease", "BPFXdpCpumap", "BPFSkLookup", "BPFXdp",
"BPFSkSkbVerdict", "BPFSkReuseportSelect", "BPFSkReuseportSelectOrMigrate",
"BPFPerfEvent", "BPFTraceKprobeMulti", "BPFLsmCgroup", "BPFStructOps",
"BPFNetfilter", "BPFTcxIngress", "BPFTcxEgress", "BPFTraceUprobeMulti",
"BPFCgroupUnixConnect", "BPFCgroupUnixSendmsg", "BPFCgroupUnixRecvmsg",
"BPFCgroupUnixGetpeername", "BPFCgroupUnixGetsockname", "BPFNetkitPrimary",
"BPFNetkitPeer", "BPFTraceKprobeSession", "BPFTraceUprobeSession"
]
command = sys.argv[1:]
def join(arr):
return ",".join(arr)
def run_command():
cmd = [
"sudo", "systemd-run", "-q", "--wait",
"-p", "PrivateUsers=yes",
"-p", "PrivateMounts=yes",
"-p", "DelegateNamespaces=mnt",
"-p", "PrivateBPF=yes",
"-p", f"BPFDelegateCommands={join(cmds)}",
"-p", f"BPFDelegateMaps={join(maps)}",
"-p", f"BPFDelegatePrograms={join(progs)}",
"-p", f"BPFDelegateAttachments={join(attachments)}",
"-p", "AmbientCapabilities=CAP_BPF",
"timeout", "1"
] + command
result = subprocess.run(cmd)
# 124 == timeout, hence success
return result.returncode == 0 or result.returncode == 124
def print_status(name, arr):
print(f"{name}: {len(arr)} ", end='\r', flush=True)
def ddmin(arr, name):
n = 2 # initial granularity
length = len(arr)
print_status(name, arr)
while length >= 1:
subset_size = max(1, length // n)
some_progress = False
for start in range(0, length, subset_size):
trial = arr[:start] + arr[start+subset_size:]
backup = arr[:]
arr[:] = trial
if run_command():
length = len(arr)
n = 2
some_progress = True
print_status(name, arr)
break
else:
arr[:] = backup
if not some_progress:
if n >= length:
break
n = min(length, n * 2)
return arr
cmds = ddmin(cmds, "BPFDelegateCommands")
print("BPFDelegateCommands="+join(cmds))
maps = ddmin(maps, "BPFDelegateMaps")
print("BPFDelegateMaps="+join(maps))
progs = ddmin(progs, "BPFDelegatePrograms")
print("BPFDelegatePrograms="+join(progs))
attachments = ddmin(attachments, "BPFDelegateAttachments")
print("BPFDelegateAttachments="+join(attachments))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment