-
bpf()
시스템 콜은 eBPF와 관련된 다양한 동작을 수행한다. 이 시스템 콜을 사용해 커널 내 eBPF 헬퍼 함수들을 호출할 수 있으며 eBPF Map 같은 공유 자료 구조에 접근할 수 있다. -
각 eBPF 프로그램은 완료 때까지 안전하게 실행할 수 있는 명령어들의 집합이다. 커널 내 검증기가 eBPF 프로그램이 안전한지 여부를 정적으로 판단한다. 검증하는 동안 커널에서 그 eBPF 프로그램이 쓰는 맵 각각에 참조 카운터를 올려서 프로그램이 내려갈 때까지 관련 맵들이 제거되지 않도록 한다.
cmd
-
bpf()
시스템 호출이 수행할 동작을 cmd 인자로 결정할 수 있다. 각 동작은 bpf_attr 타입 공용체(아래 참고) 포인터인 attr을 통해 추가 인자를 받는다. size 인자는 attr이 가리키는 공용체의 크기다. -
cmd로 주는 값은 다음 중 하나이다.
BPF_MAP_CREATE
: 맵을 생성하고 그 맵을 가리키는 파일 디스크립터를 반환한다. 새 파일 디스크립터에는 close-on-exec 플래그가 자동으로 켜진다.BPF_MAP_LOOKUP_ELEM
: 지정한 맵에서 키로 항목을 찾아서 그 값을 반환한다.BPF_MAP_UPDATE_ELEM
: 지정한 맵에서 항목(키/값 쌍)을 생성하거나 갱신한다.BPF_MAP_DELETE_ELEM
: 지정한 맵에서 키로 항목을 찾아서 삭제한다.BPF_MAP_GET_NEXT_KEY
: 지정한 맵에서 키로 항목을 찾아서 다음 항목의 키를 반환한다.BPF_PROG_LOAD
: eBPF 프로그램을 검증 및 적재하고 프로그램과 연계된 새 파일 디스크립터를 반환한다. 새 파일 디스크립터에는 close-on-exec 플래그가 자동으로 켜진다.
attr
-
attr는 명령어 실행 옵션을 넣기 위한 파라미터이다.
bpf_attr
union은 여러bpf()
명령에서 쓰는 다양한 익명 구조체들로 이뤄져 있다.
size
- size 파라미터에는 attr가 가리키는 union의 size 값을 넣으면 된다.
map 관련 시스템 콜
BPF_MAP_CREATE
-
BPF_MAP_CREATE 명령은 새로운 맵을 만들고 그 맵을 가리키는 새 파일 디스크립터를 반환한다.
-
map_type
으로 맵의 종류를 지정할 수 있다.map_type
으로 지원되는 값은 다음과 같은 것들이 있다.-
BPF_MAP_TYPE_PROG_ARRAY
-
eBPF 맵중에는 program array라는 특수한 맵이 있다. 이 맵은 다른 eBPF 프로그램을 가리키는 파일 디스크립터들을 저장한다.
- 이 맵에서 lookup을 수행하면 프로그램 흐름이 그대로 다른 eBPF 프로그램의 시작점으로 옮겨진다.
-
호출된 프로그램은 같은 스택을 재사용하게 된다. 새 프로그램으로 점프를 수행하고 나면 이전 프로그램으로는 더이상 돌아오지 않는다.
-
중첩 깊이 제한은 32단계이다. 맵에 저장된 프로그램 파일 디스크립터는 런타임에 변경할 수 있다.
-
프로그램 배열 맵에서 참조하는 모든 프로그램은
bpf()
를 통해 커널로 미리 적재해 둬야 한다. 맵 탐색이 실패하면 현재 프로그램이 실행을 계속한다. -
key_size
와value_size
모두 정확히 4바이트여야 한다. -
이 맵은
bpf_tail_call()
헬퍼와 함께 사용한다. -
프로그램 배열의 주어진 색인에서 eBPF 프로그램을 찾을 수 없으면 현재 eBPF 프로그램 실행을 계속한다.
-
-
BPF_MAP_LOOKUP_ELEM
-
BPF_MAP_LOOKUP_ELEM
명령은 파일 디스크립터 fd가 가리키는 맵에서 주어진 key로 항목을 찾는다. -
항목을 찾으면 동작이 0을 반환하며 항목의 값을 value에 저장한다. value는
value_size
바이트 크기의 버퍼를 가리켜야 한다.
BPF_MAP_UPDATE_ELEM
-
BPF_MAP_UPDATE_ELEM
명령은 파일 디스크립터 fd가 가리키는 맵에서 주어진 key/value로 항목을 생성하거나 갱신한다. -
flags 인자는 다음 중 하나로 지정해야 한다.
BPF_ANY
: 새 항목을 생성하거나 기존 항목을 갱신한다.BPF_NOEXIST
: 존재하지 않을 때 새 항목을 생성하기만 한다.BPF_EXIST
: 기존 항목을 갱신한다.
BPF_MAP_DELETE_ELEM
-
BPF_MAP_DELETE_ELEM
명령은 파일 디스크립터 fd가 가리키는 맵에서 키가 key인 항목을 삭제한다. -
성공 시 0을 반환한다. 항목을 찾지 못하면 -1을 반환하며 errno를 ENOENT로 설정한다.
BPF_MAP_GET_NEXT_KEY
-
BPF_MAP_GET_NEXT_KEY
명령은 파일 디스크립터 fd가 가리키는 맵에서 key로 항목을 찾아서 그 다음 항목의 키를next_key
포인터가 가리키게 설정한다. -
이 시스템 콜을 사용해서 맵의 항목 전체를 순회할 수 있다.
-
key를 찾으면 0을 반환하며 다음 항목의 키를
next_key
포인터가 가리키게 설정한다. -
key를 찾지 못하면 동작이 0을 반환하고 첫 번째 항목의 키를
next_key
포인터가 가리키게 설정한다. -
key가 마지막 항목이면 -1을 반환하며 errno를
ENOENT
로 설정한다.
close(map_fd)
- 파일 디스크립터 fd가 가리키는 맵을 삭제한다.
- 맵을 생성한 사용자 공간 프로그램이 종료할 때 모든 맵들이 자동으로 삭제된다. (하지만 NOTES를 보라.)
eBPF 프로그램 관련 시스템 콜
BPF_PROG_LOAD
-
BPF_PROG_LOAD
명령을 사용해 eBPF 프로그램을 커널로 적재할 수 있다. 이 명령의 반환 값은 eBPF 프로그램에 연결된 새 파일 디스크립터이다. -
BPF_PROG_LOAD
가 반환한 파일 디스크립터로close()
를 호출하면 eBPF 프로그램을 제거할 수 있다. -
bpf_attr의 각 필드는 아래와 같은 의미이다.
insns
는 struct bpf_insn 인스트럭션의 배열이다.insn_cnt
는 insns가 가리키는 프로그램 인스트럭션의 갯수이다.license
는 라이선스 문자열이며, gpl_only로 표시된 헬퍼 함수들을 호출하려면 GPL 호환이어야 한다. (라이선스 규칙이 커널 모듈과 같으므로 “Dual BSD/GPL” 같은 이중 라이선스를 쓸 수도 있다.)log_buf
는 호출자가 할당한 버퍼에 대한 포인터이며 커널 내 검증기가 여기에 검증 로그를 저장할 수 있다. 그 로그는 여러 행의 문자열이며 프로그램 작성자가 이를 확인하여 검증기가 어떻게 그 eBPF 프로그램이 안전하지 않다는 결론에 도달했는지 알 수 있다. 검증기가 발전함에 따라 출력 형식이 언제든 바뀔 수 있다.log_size
는log_buf
가 가리키는 버퍼의 크기다. 버퍼 크기가 검증기 메시지를 모두 담기에 충분하지 않으면 -1을 반환하고 errno를 ENOSPC로 설정한다.log_level
은 로그 단계를 뜻한다. 0 값은 검증기가 로그를 제공하지 않는다는 뜻이다. 이 경우log_buf
가 NULL 포인터인 동시에log_size
가 0이어야 한다.
-
prog_type은 사용 가능한 프로그램 종류들 중 하나이다.
참고