All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Documentation: Add HOWTO Korean translation into BPF and XDP Reference Guide.
@ 2018-09-21  4:22 Changan Song
  2018-09-24 17:15 ` Tejun Heo
  2018-09-24 18:20 ` [PATCH] " Jonathan Corbet
  0 siblings, 2 replies; 7+ messages in thread
From: Changan Song @ 2018-09-21  4:22 UTC (permalink / raw)
  To: netdev; +Cc: Changan Song

Signed-off-by: Changan Song <csongxdp@gmail.com>
---
 Documentation/translations/ko_KR/bpf-xdp.txt | 3511 ++++++++++++++++++
 1 file changed, 3511 insertions(+)
 create mode 100644 Documentation/translations/ko_KR/bpf-xdp.txt

diff --git a/Documentation/translations/ko_KR/bpf-xdp.txt b/Documentation/translations/ko_KR/bpf-xdp.txt
new file mode 100644
index 000000000000..c9472c437fdc
--- /dev/null
+++ b/Documentation/translations/ko_KR/bpf-xdp.txt
@@ -0,0 +1,3511 @@
+NOTE:
+
+This is a version of https://cilium.readthedocs.io/en/v1.0/bpf/ translated
+into Korean. The latest version of the English documentation can be found
+at https://cilium.readthedocs.io/en/latest/bpf/. This document is maintained
+by Changan Song <csongxdp@gmail.com>.
+
+If you find any difference between this document and the original file or
+a problem with the translation, please contact the maintainer of this file.
+
+Please also note that the purpose of this file is to be easier to read for
+non English (read: Korean) speakers and is not intended as a fork.  So if
+you have any comments or updates for this file please update the original
+English file first.  The English version is definitive, and readers should
+look there if they have any doubt.
+
+===================================
+이 문서는
+https://cilium.readthedocs.io/en/v1.0/bpf/#bpf-guide
+의 한글 번역입니다. 다소 이해를 돕기 위해서 의역도 이루어 졌음을 알려
+드립니다.
+역자: 송창안 <csongxdp@gmail.com>
+===================================
+
+참고:이 문서 과정은 기술적인 면에서 BPF와 XDP를 이해하고자 하는 개발자와
+사용자를 대상으로 만들어졌습니다. 현재의 참조안내서를 읽는 동안 Cilium에
+대한 이해하는데 있어서 도움이 될 수 있지만, Cilium을 사용하는 것에 있어서
+필수사항이 아닙니다. 더 높은 수준의 소개에 대해서는 시작 안내서
+(https://cilium.readthedocs.io/en/v1.0/gettingstarted/#gs-guide)
+및개념(https://cilium.readthedocs.io/en/v1.0/concepts/#arch-guide)을
+참조하십시오.
+
+BPF는 Linux 커널에서 매우 유연하고 효율적인 가상 시스템과 같은 구조 이며, 다양한 방식
+으로 바이트 코드를 안전하게 실행할 수 있습니다. 또한, 많은 리눅스 커널 서브 시스템에서
+사용되며 네트워킹, 추적 및 보안 (예 : 보호된 영역 내에서 프로그램을 동작시키는 것을 뜻하며,
+sandboxing 라고 합니다)이 가장 두드러집니다. BPF는 1992 년부터 존재 하였지만,
+현재의 문서는 커널 3.18에 처음으로 등장한 버클리 패킷 필터 (eBPF) 버전을 다루고 있으며,
+고전적인 BPF (cBPF)라고 불리는 의미에 대해서는 요즘은 거의 사용 되지 않습니다
+
+cBPF는 많은 사람들에게 tcpdump가 사용하는 패킷 필터 언어로 친숙히 알려져 있습니다.
+최신 Linux 커널은 eBPF만 실행하고 로드 된 cBPF 바이트 코드는 프로그램 실행 전에 커널에서
+eBPF 표현으로 편리하게 변환됩니다. 이 문서는 일반적으로 eBPF와 cBPF 간의 명시적인 차이점이
+따로 언급되지 않는 상태에서는 통상적으로 BPF라는 용어를 사용합니다.
+
+Berkeley Packet Filter라는 이름이 특정 목적을 필터링하는 패킷을 암시 하긴 하지만,
+명령어 세트는 요즘에는 앞서 설명한 의미와는 별도로 BPF에 대한 많은 사용 사례가 있으며
+일반적이며 유연합니다. BPF를 사용하는 프로젝트 목록은 추가 자료
+(https://cilium.readthedocs.io/en/v1.0/bpf/#bpf-users)를 참조하십시오.
+
+Cilium은 BPF를 데이터 경로에 많이 사용하며, 자세한 내용은 개념
+(https://cilium.readthedocs.io/en/v1.0/concepts/#arch-guide)
+을 참조하십시오. 이 장의 목표는 BPF에 대한 이해와 tc(트래픽 제어) 및 XDP(고속 데이터 경로)로
+BPF 프로그램을 로드하는 것을 포함한 네트워크 관련 용도 와 Cilium에서 BPF 템플릿을 개발
+하는데 도움이되는 BPF 참조 가이드를 제공하는 것입니다.
+
+* BPF 구조
+BPF는 명령 세트만 제공함에 있어서 다른 정의하지 않지만, 효율적인 키/값 저장소 역할을 하는 map이
+있으며, 커널 기능과 상호 작용하고 활용하는 도와주는 함수인 helper 함수, 다른 BPF 프로그램을
+호출하는 tail call, 보안 강화 기본 요소, 객체(map, 프로그램) 고정용 가상 파일 시스템,
+BPF를 네트워크 카드와 같은 오프로드 허용하는 기반을 언급하고 있습니다.
+
+LLVM은 BPF 백엔드를 제공하므로 clang과 같은 도구를 사용하여 C를 BPF 객체 파일로 컴파일
+한 다음에 커널에 로드 할 수 있습니다. BPF는 리눅스 커널에 많은 연관 관계가 있으며, 원래의
+커널 성능을 저해시키지 않으면서 완전한 프로그래밍이 가능합니다.
+
+마지막으로, 그렇지만 앞에서 설명한 것과 마찬가지로 중요한 것은 BPF를 사용하는 커널 서브 시스템은
+BPF의 기반의 일부라는 것입니다. 이 문서에서 다루는 두 가지 주요 하위 시스템은
+BPF 프로그램을 연결할 수 있는 tc 및 XDP 입니다.
+(첨언 : https://fosdem.org/2018/schedule/event/xdp/attachments/slides/
+2220/export/events/attachments/xdp/slides/2220/fosdem18_SdN_NFV_qmonnet_XDPoffload.pdf
+10 번 슬라이드를 참고 부탁드립니다) XDP BPF 프로그램은 초기 네트워킹 드라이버 단계에 연결되어
+패킷 수신시 BPF 프로그램 실행을 유발하게 합니다. 정의에 따르면 패킷이 소프트웨어보다 더 빠른 시점에서
+처리 될 수 없으므로 최상의 패킷 처리 성능을 얻을 수 있습니다. 그러나 이러한 처리는 네트워킹 스택의 초기에
+발생하기 때문에 스택은 패킷에서 아직 메타 데이터를 추출하지 못했습니다. 반면에 tc BPF 프로그램은 커널 스택에서
+나중에 실행 되므로 더 많은 메타 데이터와 코어 커널 기능에 접근 할 수 있습니다.
+tc 및 XDP 프로그램 외에도 추적 (kprobes, uprobes, tracepoints 등)와 같은
+BPF를 사용하는 다양한 다른 커널 하위 시스템이 있습니다.
+
+다음 하위 절에서는 앞에서 열거한 BPF 아키텍처의 개별적인 측면에 대해 자세히 설명합니다.
+
+# 명령어 집합
+BPF는 범용 RISC 명령어 집합이며 compiler 하위 단계에서 (예를 들어 LLVM)를 통해
+BPF 명령어로 컴파일 가능한 C언어로 프로그램을 작성하기 위해 설계 되었으며,
+이후 커널은 나중에 커널 내부의 최적의 실행 성능을 위해 커널 내 JIT 컴파일러를 통해 고유의
+연산자 코드(opcode)로 매핑 할 수 있습니다.
+
+이러한 명령어들을 커널에 적용 하게되면 다음과 같은 장점이 있습니다:
+
+* 커널/사용자 영역 간 경계를 넘지 않아도 커널 프로그래밍 할 수 있습니다. 예를 들어, Cilium의 경우에서는
+네트워킹과 관련된 BPF 프로그램은 유연한 컨테이너 정책, 로드 밸런싱 구현이 가능 하며, 다른 의미로써
+패킷을 사용자 영역으로 이동시키고 커널로 다시 보낼 필요가 없다는 것을 의미합니다.
+또한, BPF 프로그램과 커널/사용자 영역 사이의 상태는 필요할 때마다 맵을 통해 공유 할 수 있습니다.
+(역자 : https://suchakra.wordpress.com/tag/ebpf/의 그림에서
+제일 마지막 그림중에 bpf()시스템콜을 받으면서 read maps 부분을 참고 부탁드립니다.)
+(역자 참고 : 커널 v2.6 부터 v4.6 v4.9 까지의 BPF 프로파일링에 대한 변화를 확인하고 싶다면,
+http://www.brendangregg.com/blog/2016-10-21/linux-efficient-profiler.html
+을 참고 부탁드립니다)
+
+* 프로그램 가능한 데이터 경로의 유연성을 감안할 때, 프로그램은 사용 사례에는 요구하지 않는 기능에 대해
+컴파일 제외 하여 성능을 크게 향상시킬 수 있습니다. 예를 들어, 컨테이너에서 IPv4가 필요하지 않은 경우
+BPF 프로그램은 fast-path에서의 자원들을 절약 하기 위해 IPv6 만 처리하도록 구축 될 수 있습니다.
+
+* 네트워킹 (예 : tc 및 XDP)의 경우 BPF 프로그램은 커널, 시스템 서비스 또는 컨테이너를 다시 시작하지 않고
+트래픽 중단 없이 최소한으로 업데이트 할 수 있습니다. 또한 BPF 맵을 통해 모든 프로그램 상태를 업데이트 할 수 있습니다.
+
+* BPF는 사용자 영역에 대해 안정적인 ABI를 제공 하며 써드파티 커널 모듈을 따로 필요로 하지 않습니다.
+BPF는 모든 곳에서 포함되는 Linux 커널의 핵심 부분(LTM 버젼으로 최소 v4.4 이상으로 판단)이며
+기존 BPF 프로그램이 최신 커널버전으로 계속 실행 될수 있도록 보장합니다.
+앞서 설명한 보장은 사용자 공간 응용 프로그램과 관련하여 커널이 system 콜을 제공하는 것과 동일한 보장입니다.
+또한 BPF 프로그램은 다른 아키텍처(ARM32, ARM64, Power, NFR 등등)에서 이식 가능합니다.
+
+* BPF 프로그램은 커널과 함께 작동하며 커널이 제공하는 안전 보장 뿐만 아니라 기존 커널 기반(예 : 드라이버,
+net device, 터널, 프로토콜 스택, 소켓) 및 도구 (예 : iproute2)를 사용합니다.
+커널 모듈과는 달리 BPF 프로그램으로 커널을 crash가 발생 할수 없도록 하며, 항상 종료 되도록 보장하기 위해
+커널 내 verifier 를 통해 검증 됩니다.예를 들어, XDP 프로그램은 기존의  커널 내부 드라이버를 재사용하며,
+XDP 프로그램을 다른 모델처럼 사용자 또는 전체 드라이버를 사용자 공간에 공개하지 않고 xdp 패킷 프레임을
+포함하는 커널에서 제공된 DMA 버퍼에서 동작합니다. 또한 XDP 프로그램은 기존 프로토콜 스택을 bypass 하는
+대신에  다시 사용합니다. BPF는 특정 사용 사례를 해결하기 위한 프로그램을 만들기 위해 커널 기능에 대한
+일반적인 "Glue code" 로 고려되어 질수 있습니다.
+
+커널 내부의 BPF 프로그램 실행은 항상 이벤트 동작 입니다. 예를 들어, 들어오는 경로에 BPF 프로그램이 연결된
+네트워킹 장치는 패킷이  수신되면 프로그램의 실행을 트리거합니다. BPF 프로그램이 연결된 kprobes가 위치한
+커널 주소는 해당 주소의 코드가 도착하면 트랩 되며,  실행 한 다음 측정을 위해 kprobes 콜백 함수를 호출하며
+이후에  연결된 BPF 프로그램의 실행을 트리거 합니다.
+
+BPF는 11 개의 64 비트 레지스터와 32 비트 서브 레지스터로 구성 되며,
+프로그램 카운터 및 512 바이트의 큰 BPF 스택 공간이 있습니다. BPF 레지스터의 이름은 "r0 - r10"입니다.
+작동 방식는 기본적으로 64 비트이며 32 비트 하위 레지스터는 특수 ALU(산술 논리 장치) 작업을 통해서만
+액세스 할 수 있습니다. 32 비트 하위 하위 레지스터는 기록 될 때 64 비트로 zero-extend 됩니다.
+
+레지스터 r10은 읽기 전용이며 BPF 스택 공간에 액세스하기 위해 프레임 포인터 주소를 포함하는 유일한
+레지스터입니다.  나머지 r0 부터 r9 레지스터는 범용이며 읽기 / 쓰기 특성을 가지고 있습니다.
+BPF 프로그램은 핵심 커널에 의해 정의 된 사전 정의 된 Helper 함수를 콜 할 수 있습니다
+(모듈별로 사용하지 않습니다). BPF 콜 규칙은 다음과 같이 정의됩니다.
+
+* r0      레지스터리는 helper 함수 콜의 반환 값이 포함됩니다.
+* r1 - r5 레지스터리는 BPF 프로그램에서 커널 helper 기능에 대한 인수를 가지게 됩니다.
+* r6 - r9 레지스터리는 helper 함수 콜시 callee가 저장하는 레지스터 입니다.
+
+BPF 호출 규약은 x86_64, arm64 및 기타 ABI 를 직접 매핑 할만큼 충분히 일반적이며, 따라서
+모든 BPF 레지스터들은  HW CPU 레지스터들과 1:1 매핑 되며, JIT는 호출 명령어를 단지 전달하며,
+함수 인자들을 배치 하기 위한 추가적인 행동들은 없습니다.이 콜 규약은 성능 저하 없이 일반적인 호출
+상황은 포함하도록 모델링 되었습니다. 6 개 이상의 인자가 있는 콜은 현재 지원되지 않습니다.
+
+커널에서 BPF (BPF_call_0() 함수에서 BPF_call_5() 함수들)의 Helper 함수는 특별히 규칙을
+염두에 두고 고안되었습니다. (역자 : 위의서 설명한  BPF_call_0 에서 BPF_call_5() 함수는 아래의
+코드에서 확인 가능 합니다.)
+https://github.com/torvalds/linux/blob/master/kernel/bpf/helpers.c)
+
+레지스터 r0은 BPF 프로그램의 종료 값을 포함하는 레지스터 이기도합니다.
+종료 값의 의미는 프로그램 유형에 따라 정의됩니다. 커널에게 실행을 다시 전달 할때, 종료 값은 32비트
+값으로 전달됩니다.
+
+(역자 : https://github.com/iovisor/bpf-docs/blob/master/bpf-internals-2.md
+에서 구조 부분을 참조 )
+
+R0 – rax      return value from function
+R1 – rdi      1st argument
+R2 – rsi      2nd argument
+R3 – rdx      3rd argument
+R4 – rcx      4th argument
+R5 – r8       5th argument
+R6 – rbx      callee saved
+R7 - r13      callee saved
+R8 - r14      callee saved
+R9 - r15      callee saved
+R10 – rbp     frame pointer ( read only )
+
+
+레지스터 r1 - r5는 스크래치 레지스터 이며, BPF 프로그램은 BPF 스택에 이들을 spilling
+하거나 이러한 인수가 여러 helper 함수 콜에 걸쳐 재사용 될 경우  callee 저장 레지스터로 이동
+중 하나가 필요하게 됩니다. spilling은 레지스터의 변수가 BPF 스택으로 이동 하는 것을 뜻합니다.
+변수를 BPF 스택에서 레지스터로 이동하는 반대 작업을 채우기라고합니다.
+BPF 스택에서 레지스트로 변구를 이동하는 역동작을 가리켜  filling 이라고 합니다.
+제한된 레지스터 수로 인해 spilling/filling 이 동작이 있는 이유 입니다.
+
+BPF 프로그램 실행을 시작하면 레지스터 r1은 처음에 프로그램의 컨텍스트를 포함합니다.
+컨텍스트는 프로그램의 입력 인수 뜻하며, (일반적인 C 프로그램의 경우 argc/argv 쌍과
+유사하다고 이해하시면 됩니다). BPF는 단일 컨텍스트에서 작업하도록 제한됩니다.
+컨텍스트는 프로그램의 유형에 따라 달리지며, 예를 들어, 네트워킹 프로그램은
+네트워크 패킷 (skb)의  kernel representation을 입력 인수로 가질 수 있습니다.
+
+BPF의 일반적인 연산은 포인터 연산을 수행하기 위해 64 비트 아키텍처의 natural model
+을 따르는 64 비트이며,  포인터를 전달 할 뿐만 아니라 64 비트 값을 helper 함수에 전달하며,
+그리고 64bit atomic operation을 허용합니다.
+
+프로그램 당 최대 명령어은 4096 BPF 명령어 으로 제한이 되며 이는 설계적으로
+모든 BPF 프로그램은 빨리 종료  되는것을 의미 합니다. 명령어 세트가 순방향 및 역방향 점프를 포함하지만
+커널 내 BPF verifier는 루프를 금지 하므로 종료가 항상 보장됩니다. BPF 프로그램은 커널 내부에서
+실행되기 때문에 verifier의 job는 시스템의 안정성에 영향을 주지 않고 실행이 안전하다는 것을
+확인하는 것입니다. 즉, 명령어 세트 관점에서 루프를 구현할 수 있지만 verifier는 이를 제한 합니다.
+그러나 한 BPF 프로그램이 다른 BPF 프로그램으로 이동할 수 있도록 하는 tail 콜 개념도 있습니다.
+(역자 : https://elixir.bootlin.com/…/l…/source/kernel/bpf/verifier.c
+코드를 확인하면 좀더 자세히 verifier에 대한 내부 구조가 확인 가능합니다.)
+"eBPF verifier statically determines that the program
+terminates and safe to execute." :-)
+
+(오역의 가능성)
+This, too, comes with an upper nesting limit of 32 calls, and is usually used to
+decouple parts of the program logic, for example, into stages.
+이것 또한, 32개의 상위 nesting 제한이 있으며, 일반적으로 프로그램의 논리 부분을 분리 하는데 사용되며,
+예를 들어 다음 단계로 진입을 뜻합니다. (역자 : bpf syscall은 BPF_PROG_LOAD 가 되면서, JIT interpreter로
+진입을 뜻하는 것으로 판단해서 물론 로드된 byter code에 대해 verfier가 실행을 하기 위해 존재
+하며 따라서 위와 같은 번역을 하였습니다.)
+
+명령어 형식은 두 개의 피연산자 명령어들로 모델링 되며 JIT 단계에서 BPF 명령어를 기본 명령어에 매핑하는
+데 도움이 됩니다. 명령어 세트는 고정 크기이며 모든 명령어가 64 비트 인코딩을 가지는것을 의미합니다.
+현재 87 개의 명령어가 구현 되었으며 인코딩을 통해 필요할 때 further 명령어을 사용하여 세트를 확장
+할 수 있습니다. big-endian 머신에서 단일 64 비트 명령어의 명령어 인코딩은 아래로 구성이 되며,
+op:8, dst_reg:4, src_reg:4, off:16, imm:32, off  그리고 imm은 부호 타입 입니다.
+인코딩은 커널 헤더의 일부이며 linux/bpf_common.h를 포함하는 linux/bpf.h 헤더 파일에
+정의되어 있습니다.
+
+msb                                                        lsb
++------------------------+----------------+----+----+--------+
+|immediate               |offset          |src |dst |opcode  |
+:%s/\s\+$//e
++------------------------+----------------+----+----+--------+
+
+8 bit opcode
+4 bit destination register (dst)
+4 bit source register (src)
+16 bit offset
+32 bit immediate (imm)
+
+@/include/uapi/linux/bpf.h
+struct bpf_insn {
+__u8	code;		/* opcode */
+__u8	dst_reg:4;	/* dest register */
+__u8	src_reg:4;	/* source register */
+__s16	off;		/* signed offset */
+__s32	imm;		/* signed immediate constant */
+};
+
+https://github.com/iovisor/bpf-docs/blob/master/eBPF.md ( 참조)
+
+op는 수행 할 실제 작업을 정의합니다. op에 대한 대부분의 인코딩은 cBPF에서 다시 사용 되었습니다.
+동작은 레지스터 또는 즉각적인 피연산자를 기반으로 할 수 있습니다. op 자체의 인코딩은 사용할 방식
+(레지스터 기반 동작을 표현하기 위한 BPF_X 그리고 즉각적인 기반 각각 동작을 위한 BPF_K)에 대한
+정보를 제공합니다. (역자 : opcode는 약 8 bit 이며, operation code(4 bits), Source bit(1bit),
+instruction class(3bit)로 내부에 나누어 져 있습니다. operation code에는 BPF_MOV, BPF_JNE에
+해당하는 값이 포함되며, Source bit(1bit)에서는 BPF_X src_reg와 dst_reg 혹은 BPF_K dst_reg 와
+32bit imm 이 포함할수 있으며, instruction class(3bit)는 BPF_ALU, BPF_ALU64, BPF_JMP가 포함됩니다.
+https://open-nfp.org/s/pdfs/dxdd-europe-bpf-and-xdp-explained.pdf 참조)
+후자의 경우 대상 피연산자는 항상 레지스터 입니다.
+dst_reg 및 src_reg는 모두 동작을 위해 사용될 레지스터 피연산자 (예 : r0 - r9)에 대한 추가 정보를 제공합니다.
+off는 예를 들어 BPF에 이용 가능한 스택 또는 다른 버퍼 (예를 들어, 맵 값, 패킷 데이터 등)를 어드레싱하거나,
+Jump 명령어에서 타겟을 점프 와 같은 상대 오프셋을 제공 하기 위해 일부 명령어 에서 사용됩니다.
+imm은 상수 / 즉각적인 값을 포함합니다.
+
+(현재 아래의 두개의 그림은 현재의 번역하는 문서에는 없는 내용입니다. 하지만 이해를 돕기 위해서 아래의 페이지를
+참고하여 opcode 구조를 참조 하였습니다)
+https://github.com/iovisor/bpf-docs/blob/master/eBPF.md
+
+ALU/ALU64/JMP opcode 구조:
++----------------+--------+--------------------+
+|   4 bits       |  1 bit |   3 bits           |
+| operation code | source | instruction class  |
++----------------+--------+--------------------+
+(MSB)                                      (LSB)
+
+LD/LDX/ST/STX opcode 구조:
++------------+------------+--------------------+
+|   3 bit    |  2 bit     |   3 bits           |
+|    mode    |   size     | instruction class  |
++------------+------------+--------------------+
+(MSB)                                      (LSB)
+
+Least Significant Bit(LSB)
+Most Significant Bit(MSB)
+
+사용 가능한 op 명령어는 다양한 명령어 클래스로 분류 할 수 있습니다. 이러한 클래스는 op 필드에도 인코딩 됩니다.
+연산 필드는 최하위 비트(lsb) 부터 최상위 비트(msb)까지 이며, code:4 bits ,source:1 bits 그리고
+instruction class:3 bits 으로 나뉩니다. instruction class 필드는 일반적인 명령어 클래스이며,
+operation code는 해당 클래스의 특정 연산 코드를 나타내며, source 필드는 소스 피연산자가
+레지스터인지 즉각적인 값 인지를 알려 줍니다. 가능한 명령 클래스는 다음과 같습니다:
+
+BPF_LD, BPF_LDX : 두개 모두 load 동작을 위한 클래스 입니다.
+BPF_LD는 imm 필드의 32 bits 와 패킷 데이터의 byte/half-word/word 로드 하기 의한
+두개의 명령어를 포괄하는 특수 명령어 이며, double word를 로드 하는데 사용합니다.
+이후 에는 주로 최적화 된 JIT 코드를 가지고 있기 때문에 cBPF를 BPF 변환으로 유지하기 위해 주로
+cBPF에서 가져와서 적용 되었습니다. 현재의 BPF의 경우에는 이러한 패킷 로드 명령어는 관련성이 낮습니다.
+BPF_LDX 클래스는 메모리에서 byte/half-word/word/double-word 로드에 대한 명령어를 저장합니다.
+이 컨텍스트의 메모리는 일반적이며 스택 메모리, 맵 값 데이터, 패킷 데이터 등 일 수 있습니다.
+
+mode 필드에서는 다음과 같이 포함될 수 있습니다:
+BPF_IMM  0x00  /* used for 32-bit mov in classic BPF and 64-bit in eBPF */
+BPF_ABS  0x20
+BPF_IND  0x40
+BPF_MEM  0x60
+BPF_LEN  0x80  /* classic BPF only, reserved in eBPF */
+BPF_MSH  0xa0  /* classic BPF only, reserved in eBPF */
+BPF_XADD 0xc0  /* eBPF only, exclusive add */
+
+BPF_IND 와 BPF_ABS에 대한 데이터 크기는 word (BPF_W), half-word (BPF_H) 혹은 byte (BPF_B) 로 지정 됩니다.
+size 필드에서는 다음과 같이 포함될 수 있습니다:
+BPF_W   0x00    /*     word (4 byte)               */
+BPF_H   0x08    /*     half word (2 byte)          */
+BPF_B   0x10    /*     byte (1 byte)               */
+BPF_DW  0x18    /* eBPF only, double word (8 byte) */
+
+BPF_ST, BPF_STX: 두개 모두 저장 연산을 위한 클래스 입니다.
+BPF_LDX와 비슷하게 BPF_STX는 마찬가지로 저장하는 역활을 하며 레지스터의 데이터를 메모리에 저장하는 데 사용되며
+다시 스택 메모리, 맵 값, 패킷 데이터 등이 될 수 있습니다. BPF_STX는 또한 예를 들어, 카운터에 사용할 수있는 단어 및
+double-word 기반 atomic 추가 연산을 수행하기위한 특수 명령어를 가지게 됩니다.
+BPF_ST 클래스는 소스 피연산자가 즉각적인 값이라는 것을 메모리에 저장하기 위한 명령을 제공함으로써 BPF_STX와 유사합니다.
+
+BPF_ALU, BPF_ALU64: 두개의 모두 ALU 동작을 포함한 클래스 입니다.
+일반적으로, BPF_ALU 동작은 32bit 방식 이며, BPF_ALU64는 64bit 방식 입니다.
+두 ALU 클래스는 모두 레지스터 기반의 원본 피연산자와 즉각적인 기반의 피연산자로 기본 연산을 수행합니다.
+add(+), sub(-), and(&), or(|), left shift(<<),
+right shift (>>), xor(^), mul (*), div (/),
+mod (%), neg (~) 연산을 두개의 class가 지원합니다. 또한 mov(<X> := <Y>)는 두 피연산자 방식에서
+두 클래스의 특수한 ALU 연산으로 추가되었습니다. BPF_ALU64에는 signed right shift도 포함됩니다.
+BPF_ALU는 주어진 source 레지스터에 대한 half-word word/double-word 에 대한 엔디안 변환 명령을 추가로 포함합니다.
+
+만약 BPF_CLASS(code) == BPF_ALU 혹은 BPF_ALU64 [ eBPF에서 ], BPF_OP(code)에는 다음 중 하나 입니다:
+
+BPF_ADD   0x00
+BPF_SUB   0x10
+BPF_MUL   0x20
+BPF_DIV   0x30
+BPF_OR    0x40
+BPF_AND   0x50
+BPF_LSH   0x60
+BPF_RSH   0x70
+BPF_NEG   0x80
+BPF_MOD   0x90
+BPF_XOR   0xa0
+BPF_MOV   0xb0  /* eBPF only: mov reg to reg */
+BPF_ARSH  0xc0  /* eBPF only: sign extending shift right */
+BPF_END   0xd0  /* eBPF only: endianness conversion */
+
+BPF_JMP: 점프 동작 전용 클래스 입니다. 점프는 무조건 그리고 조건부 일 수 있습니다.
+무조건 점프는 단순히 프로그램 카운터를 앞으로 이동시켜 현재 명령과 관련하여 실행될 다음 명령이 off + 1이
+되도록 하며, 여기서 off는 명령에 인코딩 된 상수 오프셋 입니다.
+off가 signed 때문에 점프는 루프를 생성하지 않고 프로그램 범위 내에있는 한 다시 실행할 수 있습니다.
+조건부 점프는 레지스터 기반 및 즉각적인 기반 소스 피연산자 모두에서 작동합니다.
+점프 작업의 조건이 참일 경우 오프 + 1로 상대 점프가 수행되고, 그렇지 않으면 다음 명령 (0 + 1)이 수행됩니다.
+이 fall-through jump 로직은 cBPF와 비교하여 다르므로 보다 자연스럽게 CPU 분기 예측 로직에 적합하므로
+더 나은 분기 예측이 가능하게 됩니다. 사용 가능한 조건은 jeq (==),  jne (!=), jgt(>), jge (>=),
+jsgt (signed >), jsge (signed >=), jlt (<), jle (<=), jslt (signed <),
+jsle (signed <=) and jset (만약 DST & SRC 점프).
+그 외에도 이 클래스에는 세 가지 특별한 점프 작업들이 있으며: 다시말해서, BPF 프로그램을 종료하고
+r0의 현재 값을 반환 코드로 반환하는 종료 명령, 사용 가능한 BPF helper function 중 하나로 함수 콜을 발행하는
+콜 명령어 및 다른 BPF 프로그램으로 점프하는 tail 콜 명령어가 있습니다.
+
+만약 BPF_CLASS(code) == BPF_JMP 인 경우에 BPF_OP(code)에는 다음 중 하나 입니다:
+BPF_JA    0x00
+BPF_JEQ   0x10
+BPF_JGT   0x20
+BPF_JGE   0x30
+BPF_JSET  0x40
+BPF_JNE   0x50  /* eBPF only: jump != */
+BPF_JSGT  0x60  /* eBPF only: signed '>' */
+BPF_JSGE  0x70  /* eBPF only: signed '>=' */
+BPF_CALL  0x80  /* eBPF only: function call */
+BPF_EXIT  0x90  /* eBPF only: function return */
+BPF_JLT   0xa0  /* eBPF only: unsigned '<' */
+BPF_JLE   0xb0  /* eBPF only: unsigned '<=' */
+BPF_JSLT  0xc0  /* eBPF only: signed '<' */
+BPF_JSLE  0xd0  /* eBPF only: signed '<=' */
+
+만약 BPF_CLASS(code) == BPF_ALU 또는 BPF_JMP 일 때, 4 번째 비트는 소스 피연산자를 인코딩 하게 됩니다.
+BPF_K     0x00
+BPF_X     0x08
+
+예를 들어서
+BPF_IND | BPF_W | BPF_LD 의미는:
+
+R0 = ntohl(*(u32 *) (((struct sk_buff *) R6)->data + src_reg + imm32))
+그리고 R1 - R5 스크래치 됬었습니다.
+
+기본 BPF 명령어 세트와 달리, eBPF는 일반적인 로드/저장 연산을 가지고 있습니다 :
+
+BPF_MEM | <size> | BPF_STX:  *(size *) (dst_reg + off) = src_reg
+BPF_MEM | <size> | BPF_ST:   *(size *) (dst_reg + off) = imm32
+BPF_MEM | <size> | BPF_LDX:  dst_reg = *(size *) (src_reg + off)
+BPF_XADD | BPF_W  | BPF_STX: lock xadd *(u32 *)(dst_reg + off16) += src_reg
+BPF_XADD | BPF_DW | BPF_STX: lock xadd *(u64 *)(dst_reg + off16) += src_reg
+
+Linux 커널은 BPF 명령어로 어셈블된 프로그램을 실행하는 BPF 인터프리터와 함께 제공됩니다.
+아직 cBPF JIT와 함께 제공되고 아직 eBPF JIT로 마이그레이션되지 않은 아키텍처를 제외하고는 cBPF
+프로그램도 커널에서 투명하게 eBPF 프로그램으로 변환됩니다. 현재 x86_64, arm64, ppc64, s390x, mips64,
+sparc64 및 arm 아키텍처에는 커널 내 eBPF JIT 컴파일러가 제공됩니다.
+
+프로그램을 커널에 로드하거나 BPF 맵을 작성하는 것와 같은 모든 BPF 처리는 중앙 bpf() 시스템 콜을 통해 관리됩니다.
+또한 맵 엔트리 (lookup/update/delete)를 관리하고, 프로그램뿐만 아니라 고정 된 맵을
+BPF 파일 시스템에 고정시키는 데에도 사용됩니다.
+
+#Helper 함수
+
+Helper 함수는 BPF 프로그램이 코어 커널에 정의된 함수 콜 참조하여 커널에서 데이터를
+검색/푸시 할수있게 해주는 개념입니다. 사용 가능한 Helper 기능은 각 BPF 프로그램 유형 마다 다를 수 있으며,
+예를 들어, 소켓에 연결된 BPF 프로그램은 TC 계층에 연결된 BPF 프로그램과 비교하여 Helper 하위 집합 만 콜 할 수 있습니다.
+경량 터널링을 위한 캡슐화 및 캡슐해제 Helper는 tc 레이어 아래쪽에서 사용할 수 있는 기능의 예를 구성하는
+반면 사용자 공간에 알림을 푸시 하기위한 event output Helper는 tc 및 XDP 프로그램에서 사용 할 수 있습니다.
+
+각 helper 함수는 시스템 콜과 유사한 공통적으로 공유되는 함수 대표로 구현됩니다. 대표는 다음과 같이 정의됩니다:
+u64 fn(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
+
+이전 섹션에서 설명한대로 콜 규칙은 모든 BPF helper 함수에 적용됩니다.
+커널은 helper 함수를 매크로 "BPF_call_0 ()에서 BPF_call_5 ()까지 시스템 콜과 유사하게 규격화 하였습니다.
+다음 예제는 map 구현에 해당하는 콜백을 콜하여 맵 요소를 업데이트 하는 helper 함수를 발췌하였습니다.
+
+BPF_call_4(bpf_map_update_elem, struct bpf_map *, map, void *, key,
+void *, value, u64, flags)
+{
+WARN_ON_ONCE(!rcu_read_lock_held());
+return map->ops->map_update_elem(map, key, value, flags);
+}
+
+const struct bpf_func_proto bpf_map_update_elem_proto = {
+.func           = bpf_map_update_elem,
+.gpl_only       = false,
+.ret_type       = RET_INTEGER,
+.arg1_type      = ARG_CONST_MAP_PTR,
+.arg2_type      = ARG_PTR_TO_MAP_KEY,
+.arg3_type      = ARG_PTR_TO_MAP_VALUE,
+.arg4_type      = ARG_ANYTHING,
+};
+
+이러한 접근에는 여러 가지 장점이 있습니다: 기존의 cBPF는 보조 helper 함수를 호출
+하기 위해 무리한 패킷 오프셋에서 데이터를 가져 오기 위해 로드 명령어를 오버로드 했으며,
+각 cBPF JIT는 이러한 cBPF 확장에 대한 지원을 구현해야했습니다.  하지만 eBPF의 경우, 새로 추가된
+각 helper함수는 JIT 가 투명하고 효율적인 컴파일된 컴파일이 되며, 이러한 의미는 JIT 컴파일러는
+레지스터 매핑과 같은 방식으로 이루어지기 때문에 단지 호출 명령을 내보내며 되며,
+레지스터 매핑과 같은 방식은 BPF 레지스터 할당은 이미 기본 아키텍처의 호출 개념과 일치합니다.
+이렇게 하면 새로운 helper 기능으로 core 커널을 쉽게 확장 할 수 있습니다.
+하지만 모든 BPF helper 함수는 core 커널의 일부이며 커널 모듈을 통해 확장하거나 추가 할 수 없습니다.
+
+앞서 언급한 함수 시그니처는 또한 verifier가 유형 검사를 수행 하도록 허용합니다.
+구조체 bpf_func_proto는 helper에 대해 알 필요가 있는 모든 필요한 정보를 verifier에게
+넘겨주기 위해 사용되며, 따라서 verifier는 helper가 BPF 프로그램의 분석 된 레지스터의
+현재 내용과 일치에서 예상되는 유형을 확인할 수 있습니다.
+
+인수 유형은 모든 종류의 값 전달에서 BPF 스택 버퍼에 대한 포인터/크기 쌍
+(예를 들어서, helper에서 읽거나 쓸 내용)까지 다양합니다. 후자의 경우, verifier는 예를 들어 버퍼가
+이전에 초기화되었는지 여부와 같은 추가 검사를 수행 할 수도 있습니다. 사용 가능한 BPF helper
+함수 목록은 다소 길며 지속적으로 증가하고 있으며, 예를 들어 글을 쓰는 시점에서,  BPF 프로그램은 38 개의
+BPF helper 중에서 선택할 수 있습니다. (역자 주 : 커널 코드 내 에서 helper 함수에 대해서는
+git grep 'FN(' include/uapi/linux/bpf.h 명령을 토대로
+helper 함수 리스트를 확인 할 수 있습니다. 4.17.0-rc7 기준으로 80개의  helper 함수를 확인 할 수
+있었습니다. 자세한 내용은
+https://github.com/iovisor/bcc/blob/master/docs/kernel-versions.md#helpers
+를 참조 하였습니다.)  커널 구조체 인 bpf_verifier_ops는 제공된 BPF 프로그램 타입을 위한 사용
+가능 한 helper 중 하나에  특정 enum 키워드인 bpf_func_id를 매핑을 제공하는
+get_func_proto 콜백 함수가 있습니다.
+
+@include/linux/bpf.h
+....
+229 struct bpf_verifier_ops {
+230         /* return eBPF function prototype for verification */
+231         const struct bpf_func_proto *
+232         (*get_func_proto)(enum bpf_func_id func_id,
+233                           const struct bpf_prog *prog);
+....
+
+#Maps
+map은 커널 공간에 있는 효율적인 키/값 저장소입니다. 여러 BPF 프로그램 콜간에 상태를 유지하기 위해
+BPF 프로그램에서 액세스 할 수 있습니다. 또한 사용자 공간의 파일 설명자를 통해 액세스 할 수 있으며 다른
+BPF 프로그램이나 사용자 공간 응용 프로그램과 마음대로 공유 할 수 있습니다. 서로 map을 공유하는 BPF 프로그램은
+동일한 프로그램 유형이 아니어야 하며, 예를 들어, trace 프로그램은 네트워크 프로그램과 map을 공유 할 수 있습니다.
+단일 BPF 프로그램은 현재 최대 64 개의 다른 map에 직접 액세스 할 수 있습니다.
+map 구현은 코어 커널에 의해 제공됩니다. 마음대로 데이터를 읽고 쓸 수있는 각 CPU 마다 일반적인 map 및 각 CPU 마다
+아닌 일반적인 map들 있지만 helper 함수와 함께 사용 되는 일부 일반적 이지 않는 map도 있습니다.
+(역자 주 : 커널 코드내 에서 map에 관련된 내용에 대해서는
+git grep -W 'bpf_map_type {' include/uapi/linux/bpf.h 명령을 토대로 리스트가 확인이 가능합니다.)
+
+지금 사용 가능한 일반적인 map은 BPF_MAP_TYPE_HASH, BPF_MAP_TYPE_ARRAY, BPF_MAP_TYPE_PERCPU_HASH,
+BPF_MAP_TYPE_PERCPU_ARRAY, BPF_MAP_TYPE_LRU_HASH, BPF_MAP_TYPE_LRU_PERCPU_HASH and
+BPF_MAP_TYPE_LPM_TRIE 가 있습니다. 그들은 서로 다른 의미와 성능 특성을 지닌 다른 백엔드를 구현되었지만
+조회, 업데이트 또는 삭제 작업을 수행하기 위해 BPF herlper 함수들의 동일한 공통 세트를 사용합니다.
+일반적이지 않는 map은 현재 커널에서  BPF_MAP_TYPE_PROG_ARRAY, BPF_MAP_TYPE_PERF_EVENT_ARRAY,
+BPF_MAP_TYPE_CGROUP_ARRAY, BPF_MAP_TYPE_STACK_TRACE, BPF_MAP_TYPE_ARRAY_OF_MAPS,
+BPF_MAP_TYPE_HASH_OF_MAPS 가 있습니다. 예를 들어, BPF_MAP_TYPE_PROG_ARRAY는 다른 BPF 프로그램을
+저장하는 배열 map이며, BPF_MAP_TYPE_ARRAY_OF_MAPS 및 BPF_MAP_TYPE_HASH_OF_MAPS는 런타임시
+전체 BPF 맵을 원자적 으로 대체 할 수 있도록  다른 맵에 대한 포인터를 보유합니다.
+이러한 유형의 map은 BPF 프로그램 콜을 통해 추가(비-데이터) 상태가 유지되어야 하기 때문에
+BPF helper 함수를 통해 구현 하기에는 부적합한 문제를 해결 합니다.
+
+#객체 고정
+
+BPF 맵과 프로그램은 커널 리소스 역할을 하며 커널의 익명 inode가 지원하는 파일 디스크립터를 통해서만
+액세스 할 수 있으며, 장점 인것 뿐만 아니라 여러 가지 단점이 있습니다:
+사용자 공간 응용 프로그램은 대부분의 파일 디스크립터 관련 API, Unix 도메인 소켓을 통과하는
+파일 디스크립터 등을 투명하게  사용할 수 있지만 동시에 파일 디스크립터는 프로세스의 수명에만 제한되기
+때문에 map 공유와 같은 옵션이 동작하는 것은 어려워집니다. 따라서 iproute2 에서는 tc 또는 XDP는
+커널에 프로그램을 로드하고 결국 종료되는 것 같은 특정 사용 사례에서는  여러가지 복잡한 문제가 발생합니다.
+앞의 문제를 포함하여, 또한 데이터 경로의 ingress 및 engress 위치 사이에서 맵을 공유하는 경우 와
+같이 사용자 공간 측면에서도 map에 액세스 할 수 없습니다. 또한 사용자 공간 측면에서 map에 대한
+액세스를 사용할 수 없습니다.  또한 타사 응용 프로그램은 BPF 프로그램 런타임 중에 map
+내용에 대해 모니터링 하거나 업데이트 하려고 할수 있습니다. 이러한 한계를 극복 하기 위해서
+BPF map 과 프로그램은 객체 고정 이라고 불리는 고정이 될수 있는  최소한의 커널 공간 BPF 파일 시스템
+(/sys/fs/bpf)이 구현 되었습니다. 따라서 BPF 시스템 콜은 이전에 고정 된
+객체를 고정(BPF_OBJ_PIN)하거나 검색(BPF_OBJ_GET) 할 수있는 두 개의 새로운 명령으로 확장 되었습니다.
+
+kernel/bpf/syscall.c
+...
+static int bpf_obj_pin(const union bpf_attr *attr)
+{
+if (CHECK_ATTR(BPF_OBJ) || attr->file_flags != 0)
+return -EINVAL;
+
+return bpf_obj_pin_user(attr->bpf_fd, u64_to_user_ptr(attr->pathname));
+}
+
+static int bpf_obj_get(const union bpf_attr *attr)
+{
+if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0 ||
+attr->file_flags & ~BPF_OBJ_FLAG_MASK)
+return -EINVAL;
+
+return bpf_obj_get_user(u64_to_user_ptr(attr->pathname),
+attr->file_flags);
+}
+...
+
+예를 들어 tc와 같은 도구는 진입 및 이탈에서 map를 공유하기 위해 이러한 구조를 사용합니다.
+BPF 관련 파일 시스템은 싱글톤 패턴이 아니며 다중 마운트 인스턴스, 하드 및 소프트 링크 등을 지원합니다.
+
+* Tail 콜
+
+BPF와 함께 사용할 수있는 또 다른 개념을 tail 콜이라고합니다.
+Tail 콜은 하나의 BPF 프로그램이 이전 프로그램으로 돌아 가지 않고 다른 프로그램을 콜 할수 있게 해주는
+메커니즘으로 보여질수 있습니다. 이러한 콜은 함수 콜과 달리 최소한의 오버 헤드를 가지며 동일한
+스택 프레임을 재사용하여 긴 점프로 구현됩니다. 이러한 프로그램은 서로 관계없이 확인되므로 CPU 마다 맵을
+스크래치 버퍼로 전송하거나 tc 프로그램의 경우 cb[] 영역과 같은 skb 필드를 사용해야합니다.
+동일한 유형의 프로그램만 tail 콜 할 수 있으며, 또한 JIT 컴파일과 관련하여 일치해야하므로
+JIT 컴파일되거나 해석 된  프로그램 만 콜 할 수 있지만 함께 혼재되서 구동 할 수는 없습니다.
+tail 콜을 수행하는 데는 두 가지 구성 요소가 필요하며:  첫 번째 요소은 사용자 공간에서
+키/값으로 덧붙일수 있는  프로그램 배열(BPF_MAP_TYPE_PROG_ARRAY)이라는 특수한 맵을 설정해야 하며,
+여기서 값은 tail 콜 된 BPF 프로그램이라는 파일 디스크립터 이며, 두 번째 요소는 컨텍스트
+다시 말해 프로그램 배열에 대한 참조 및  조회 키가 전달되는 bpf_tail_call() helper입니다.
+(역자 주: https://lwn.net/Articles/645169/ "bpf: introduce
+bpf_tail_call() helper" 참조 부탁 드립니다.
+또한  tail 콜 에 대한 예제는
+https://github.com/torvalds/linux/blob/master/samples/bpf/sockex3_kern.c 이며
+BPF_MAP_TYPE_PROG_ARRAY의 BPF map을 제공 한 후, bpf_tail_call () helper를 사용하면
+구성이 가능합니다. http://yunazuno.hatenablog.com/entry/2017/05/09/102154
+참조 하였습니다.)
+
+그런 다음 커널은 이 helper 콜을 특수화 된 BPF 명령어로 직접 인라인 합니다.
+이러한 프로그램 배열은 현재 사용자 공간 측면에서 쓰기 전용입니다.
+커널은 전달 된 파일 디스크립터에서 관련 BPF 프로그램을 찾고 지정된 map 슬롯에서 프로그램 포인터를
+원자적으로 대체합니다. 제공된 키에서 map 항목을 찾지 못한다면, 커널은 "fall-through" 및
+bpf_taill_call()다음에 오는 명령으로 이전 프로그램의  실행을 계속합니다. taill 콜은 강력한 유틸리티 이며,
+예를 들어 파싱 네트워크 헤더는 taill 콜을 통해 구조화 될 수 있습니다.
+런타임 중에는 기능을 원자적으로 추가하거나 대체 할 수 있으므로 BPF 프로그램의 실행 동작이 변경됩니다.
+(역자 주 : https://lwn.net/Articles/741773/ )
+
+#BPF 호출에서 BPF 호출
+BPF helper 콜과 BPF tail 콜 외에도 BPF 핵심 구조에 추가 된 최신 기능은 BPF 호출에서 BPF 호출 입니다.
+이 기능이 커널에 도입되기 전에, 일반적인 BPF C 프로그램은 다음과 같은 재사용 가능한 코드를 선언 해야 했으며,
+예를 들어, 헤더에 always_inline으로 존재하며 LLVM이 컴파일 하고 BPF 객체 모든 함수들이 인라인이 되며,
+그리하여 생성된 오프젝트 파일에 여러번 복제되어 인위적으로 코드 크기가 늘어나게됩니다.
+
+#include <linux/bpf.h>
+
+#ifndef __section
+# define __section(NAME)                  \
+__attribute__((section(NAME), used))
+#endif
+
+#ifndef __inline
+# define __inline                         \
+inline __attribute__((always_inline))
+#endif
+
+static __inline int foo(void)
+{
+return XDP_DROP;
+}
+
+__section("prog")
+int xdp_drop(struct xdp_md *ctx)
+{
+return foo();
+}
+
+char __license[] __section("license") = "GPL";
+
+이것이 필요했던 주된 이유는 BPF 프로그램 로더뿐만 아니라 verifier, 인터프리터 및 JIT에서 함수 콜 지원이 부족했기 때문입니다.
+Linux 커널 4.16 및 LLVM 6.0부터이 제한이 해제 되었으며 BPF 프로그램은 더 이상 always_inline을 사용할 필요가 없습니다.
+따라서 이전에 표시된 BPF 예제 코드는 다음과 같이 자연스럽게 다시 작성 될 수 있습니다:
+
+#include <linux/bpf.h>
+
+#ifndef __section
+# define __section(NAME)                  \
+__attribute__((section(NAME), used))
+#endif
+
+static int foo(void)
+{
+return XDP_DROP;
+}
+
+__section("prog")
+int xdp_drop(struct xdp_md *ctx)
+{
+return foo();
+}
+
+char __license[] __section("license") = "GPL";
+x86_64 및 arm64와 같은 메인스트림 BPF JIT 컴파일러는 BPF 에서 BPF 콜을 지원합니다.
+BPF에서 BPF 콜은 생성 된 BPF 코드 크기를 많이 줄여 CPU의 명령어 캐시에 더 우호적이기 때문에 중요한 성능 최적화입니다.
+BPF helper 함수에서 알려진 콜 규칙은 BPF에서 BPF 콜에도 적용되며, 이 의미는 r1 ~ r5는 콜 수신자에게 인수를 전달하기위한 것이며
+결과는 r0에 리턴됩니다. r1 ~ r5는 스크래치 레지스터이며 r6 ~ r9는 일반적인 콜을 통해 유지됩니다. 각각 허용 된 콜
+프레임의 최대 중첩 콜 수는 8입니다. 콜 송신자는 콜 송신자의 포인터 (예를 들어서, 콜 송신자의 스택 프레임에 대한 포인터)를 콜
+수신자에게 전달할 수 있지만 역방향으로는 동작하지 않습니다. BPF에서 BPF 콜은 현재 BPF tail 콜과 호환되지 않으며,
+후자는 현상태의 스택 설정을 그대로 재사용 할 것을 요구하기 때문에, 전자는 추가 스택 프레임을 추가하므로 tail 콜의
+예상된 레이아웃을 변경이됩니다. BPF JIT 컴파일러는 각 함수 본체에 대해 별도의 이미지를 내보내고 나중에
+최종 JIT 경로에서 이미지의 함수 콜 주소를 수정합니다. BPF 에 BPF 콜은 일반적인 BPF helper 콜로 처리 할 수 있다는 점에서
+JIT에 대한 최소한의 변경이 필요하다는 것이 입증되었습니다.
+
+#JIT
+64 비트 x86_64, arm64, ppc64, s390x, mips64, sparc64 및 32 비트 arm 아키텍처는 모두 커널 내 eBPF
+JIT 컴파일러와 함께 제공되며 모든 기능이 동일하며 다음을 통해 활성화 할 수 있습니다:
+
+# echo 1 > /proc/sys/net/core/bpf_jit_enable
+
+32 비트 mips, ppc 및 sparc 아키텍처에는 현재 cBPF JIT 컴파일러가 있습니다.
+cBPF JIT와 BPF JIT 컴파일러가 없는 Linux 커널이 지원하는 나머지 아키텍처는
+모두 커널 내 인터프리터를 통해  eBPF 프로그램을 실행할 필요가 있습니다. 커널의 소스 트리에서
+eBPF JIT 지원은 HAVE_EBPF_JIT에 대한 grep을 통해 쉽게 확인할 수 있습니다:
+
+# git grep HAVE_EBPF_JIT arch/
+arch/arm/Kconfig:       select HAVE_EBPF_JIT   if !CPU_ENDIAN_BE32
+arch/arm64/Kconfig:     select HAVE_EBPF_JIT
+arch/powerpc/Kconfig:   select HAVE_EBPF_JIT   if PPC64
+arch/mips/Kconfig:      select HAVE_EBPF_JIT   if (64BIT && !CPU_MICROMIPS)
+arch/s390/Kconfig:      select HAVE_EBPF_JIT   if PACK_STACK && HAVE_MARCH_Z196_FEATURES
+arch/sparc/Kconfig:     select HAVE_EBPF_JIT   if SPARC64
+arch/x86/Kconfig:       select HAVE_EBPF_JIT   if X86_64
+
+(역자주 : 4.17.0-rc7 기준으로 아래와 같습니다.
+# git grep HAVE_EBPF_JIT arch/
+arch/arm/Kconfig:       select HAVE_EBPF_JIT if !CPU_ENDIAN_BE32
+arch/arm64/Kconfig:     select HAVE_EBPF_JIT
+arch/mips/Kconfig:      select HAVE_EBPF_JIT if (64BIT && !CPU_MICROMIPS)
+arch/mips/Kconfig:      depends on BPF_JIT && HAVE_EBPF_JIT
+arch/powerpc/Kconfig:   select HAVE_EBPF_JIT                    if PPC64
+arch/s390/Kconfig:      select HAVE_EBPF_JIT if PACK_STACK && HAVE_MARCH_Z196_FEATURES
+arch/sparc/Kconfig:     select HAVE_EBPF_JIT if SPARC64
+arch/x86/Kconfig:       select HAVE_EBPF_JIT
+)
+
+JIT 컴파일러는 BPF 프로그램의 실행 속도를 인터프리터와 비교하여 명령 마다 비용을 크게 줄여주므로
+속도를 크게 높입니다. 명령어는 종종 기본 아키텍처의 기본 명령어로 1:1로 매핑 될 수 있습니다.
+이렇게 하면 실행 가능 이미지 크기가 줄어들며, CPU에 우호적인 더 많은 명령어 캐시가 됩니다.
+특히 x86과 같은 CISC 명령어 세트의 경우 JITs는 주어진 명령어에 대해 가능한 가장
+짧은 opcode를 변환하여 프로그램 변환에 필요한 총 크기를 줄이기 위해 최적화됩니다.
+
+#Hardening
+BPF는 코드 잠재적 손상을 방지하기 위해 프로그램의 실행 동안 커널에서 읽기 전용으로 JIT 컴파일 된 이미지 (
+struct bpf_binary_header)뿐만 아니라 BPF 인터프리터 이미지(struct bpf_prog)를 잠급니다.
+이러한 시점에서 일어난 corruption, 예를 들어, 일부 커널 버그로 인해 general protection fault가 발생하고
+따라서 corruption이 자동으로 일어나는 것을 허용하지 않고 커널을 crash 시킵니다.
+이미지 메모리를 읽기 전용으로 설정하는 것을 지원하는 아키텍처는 다음을 통해 결정될 수 있습니다:
+$ git grep ARCH_HAS_SET_MEMORY | grep select
+arch/arm/Kconfig:    select ARCH_HAS_SET_MEMORY
+arch/arm64/Kconfig:  select ARCH_HAS_SET_MEMORY
+arch/s390/Kconfig:   select ARCH_HAS_SET_MEMORY
+arch/x86/Kconfig:    select ARCH_HAS_SET_MEMORY
+
+CONFIG_ARCH_HAS_SET_MEMORY 옵션은 설정 가능 하지 않으며, 보호 기능이 항상 내장되어 있습니다.
+다른 아키텍처들은 향후 동일 할 수 있습니다.x86_64 JIT 컴파일러의 경우, tail 콜을 사용하여,
+간접 점프의 JiTing은 CONFIG_RETPOLINE이 설정 되었을 때,
+가장 최신의 리눅스 배포판에서 retpoline 을 통해 실행됩니다.
+
+/proc/sys/net/core/bpf_jit_harden 의 값이 1로 설정된 경우 JIT 컴파일에 대한 추가적인 hardening 단계로
+권한이 없는 사용자들에게 적용됩니다.
+
+(역자 주: 추가적으로 옵션은 아래와 같은 설정이 가능합니다 )
+
+bpf_jit_harden
+--------------
+BPF JIT 컴파일러을 위한 hardening을 활성화 합니다. 현재 지원되는 것은 eBPF JIT 백엔드입니다.
+hardening 기능을 사용하면 성능이 저하 되지만 JIT spraying를 완화 할 수 있습니다.
+
+Values :
+0 - JIT hardening 비활성화 (기본값)
+1 - 권한이 없는 사용자들에 대한 JIT hardening 활성화
+2 - 모든 사용자들에 대한 JIT hardening 활성화
+
+이것은 시스템에서 동작하는 신뢰할 수없는 사용자에 대해서 (잠재적인)공격 지점을 줄임으로써 성능을 실제적으로 약간 저하 됩니다.
+이러한 프로그램 실행의 축소는 여전히 인터프리터로 전환하는 것 보다 더 나은 성능을 나타냅니다.
+현재 hardening 기능을 사용하면 원시 opcode를 직접적인 값으로 주입하는 JIT spraying 공격을 방지하기 위해
+JIT 컴파일시 BPF 프로그램의 모든 32 비트 및 64 비트 상수를 제공받지 못하게됩니다.
+이러한 직접적인 값은 실행 가능한 커널 메모리에 있기 때문에 문제가 되며, 따라서 일부 커널 버그로 인해 발생할 수있는 점프는
+직접적인 값의 시작으로 이동 한 다음 기본 명령어로 실행합니다.
+
+JIT 상수 블라인드는 실제 명령어를 무작위로 지정하여 방지 하며, 이것은 직접적인 기반을 둔 소스 피연산자에서
+레지스터 기반을 둔 실제 피연산자로 값의 실제 로드를 두 단계로 나누어 명령을 다시 작성하는 방식으로 변환됩니다:
+
+1) 블라인드 된 직접 값 rnd ^ imm을 레지스터에 로드 하며, 2) 본래의 imm immediatie가 레지스터에 상주하고 실제 작업에
+사용될 수 있도록 rnd로 등록하는 xoring을 합니다.
+이 예제는 로드 동작을 위해 제공 되었지만, 실제로 모든 일반 동작은 블라인드입니다.
+
+hardening이 비활성화 된 프로그램의 JITing 예제 :
+# echo 0 > /proc/sys/net/core/bpf_jit_harden
+
+ffffffffa034f5e9 + <x>:
+[...]
+39:   mov    $0xa8909090,%eax
+3e:   mov    $0xa8909090,%eax
+43:   mov    $0xa8ff3148,%eax
+48:   mov    $0xa89081b4,%eax
+4d:   mov    $0xa8900bb0,%eax
+52:   mov    $0xa810e0c1,%eax
+57:   mov    $0xa8908eb4,%eax
+5c:   mov    $0xa89020b0,%eax
+[...]
+
+같은 프로그램이 경우 hardening이 활성화 된 권한이 없는 사용자를 BPF를 통해 로드 될 때 상수가 블라인드가됩니다:
+# echo 1 > /proc/sys/net/core/bpf_jit_harden
+
+ffffffffa034f1e5 + <x>:
+[...]
+39:   mov    $0xe1192563,%r10d
+3f:   xor    $0x4989b5f3,%r10d
+46:   mov    %r10d,%eax
+49:   mov    $0xb8296d93,%r10d
+4f:   xor    $0x10b9fd03,%r10d
+56:   mov    %r10d,%eax
+59:   mov    $0x8c381146,%r10d
+5f:   xor    $0x24c7200e,%r10d
+66:   mov    %r10d,%eax
+69:   mov    $0xeb2a830e,%r10d
+6f:   xor    $0x43ba02ba,%r10d
+76:   mov    %r10d,%eax
+79:   mov    $0xd9730af,%r10d
+7f:   xor    $0xa5073b1f,%r10d
+86:   mov    %r10d,%eax
+89:   mov    $0x9a45662b,%r10d
+8f:   xor    $0x325586ea,%r10d
+96:   mov    %r10d,%eax
+[...]
+
+두 프로그램 모두 의미 상 동일 하며, 단지 두 번째 프로그램의 디스어셈블리에서 더 이상 원래의 직접 값이 보이지 않습니다.
+동시에 hardening는 JIT 이미지 주소가 /proc/kallsyms에 더 이상 노출되지 않도록 권한있는 사용자에 대한 JIT
+kallsyms 노출에 대해 비활성화합니다.
+
+(역자주 : 해당 옵션에 대해서 세부 적인 내용을 확인 하였습니다.)
+bpf_jit_kallsyms
+----------------
+BPF JIT 컴파일러가 활성화 되면, 컴파일된 이미지는 커널에 알려지지 않는 주소 이며, 이것은 추적이나 /proc/kallsyms에
+나타나지 않는 것을 의미합니다. 이 파라메터를 활성화 하면, 디버깅 및 추적에 사용 할수 있는 주소를 내보낼수 있습니다.
+만약 bpf_jit_harden 파라메터가 활성화 되었다면, 이 기능은 비 활성화 됩니다.
+Values :
+0 - disable JIT kallsyms 내보내기 비 활성화 (기본값)
+1 - 허가된 유저들만 JIT kallsyms 내보내기 활성화
+
+또한 Linux 커널은 전체 BPF 인터프리터를 커널에서 제거하고 JIT 컴파일러를 영구적으로 활성화하는
+CONFIG_BPF_JIT_ALWAYS_ON 옵션을 제공합니다. 이것은 Spectre v2의 상황에서 VM 기반 설정에서
+사용될 때 게스트 커널이 공격이 증가 할때 호스트 커널의 BPF 인터프리터를 재사용하지 않기 위해 개발되었습니다.
+컨테이너 기반 환경의 경우 CONFIG_BPF_JIT_ALWAYS_ON
+구성 옵션은 선택 사항이지만, JIT가 활성화되어있는 경우 인터프리터는 커널의 복잡성을 줄이기 위해 컴파일에서
+제외 될 수 있습니다. 따라서 x86_64 및 arm64와 같은 메인 스트림 아키텍처의 경우 널리 사용되는 JITs를
+일반적으로 권장됩니다.
+
+마지막으로, 커널은 /proc/sys/kernel/unprivileged_bpf_disabled sysctl 설정를 통해 권한이없는
+사용자에게 bpf(2)시스템콜을 사용하지 못하게 하는 옵션을 제공합니다. 일회성 kill 스위치 이며, 한번 1로 설정이되면,
+새로운 커널을 부팅 할때까지 다시 0으로 재 설정하는 옵션은 없습니다.
+초기 네임스페이스에서 CAP_SYS_ADAMIN 권한이 설정된 프로세서만 설정하면, 그 시점 이후 bpf(2)
+시스템콜을 사용 할수 있습니다. cilium은 이 설정에 대해서 1로 설정합니다.
+# echo 1 > /proc/sys/kernel/unprivileged_bpf_disabled
+
+(역자 주 : https://lwn.net/Articles/660331/ Unprivileged bpf()를 참조 부탁드리며,
+패치된 내용은 아래에 있습니다. https://git.kernel.org/pub/scm/linux/kernel
+/git/stable/linux.git/commit/?h=v4.17.8&id=c1bf5fe03184f782f2a6827cf314ae58834865da)
+
+#Offloads
+
+BPF의 네트워킹 프로그램, 특히 tc와 XDP의 경우 NIC에서 직접 BPF 코드를 실행하기 위해 커널의 하드웨어에
+대한 오프로드 인터페이스가 있습니다. 현재 Netronome의 nfp 드라이버는 BPF 명령어를 NIC에 대해
+구현된 명령어 세트로 변환하여  JIT 컴파일러를 통해 BPF를 오프로드 할 수 있도록 지원합니다. 여기에는 NIC에
+대한 BPF 맵의 offloading 포함되므로  offload된 BPF 프로그램은 맵 조회, 업데이트 및 삭제를 수행 할 수 있습니다.
+(역자 주 : 관심이 있으신 분은 "eBPF Offload Getting Started Guide - Netronome" 라는 키워드를 통해
+구글을 통해서 설정 및 간단한 예제가 포함된 문서를 찾으실 수 있습니다.)
+
+#툴체인
+
+현재 사용자 공간에서의 도구, BPF 관련 자가 검사 방법 및 BPF 관련의 커널 설정 제어는
+이 섹션에서 논의됩니다. BPF 관련된 도구 및 구조는 여전히 빠르게 발전하고 있으므로, 사용 가능한
+모든 도구에 대한 전체 그림을 제공하지 못할 수도 있습니다.
+
+개발환경
+Fedora와 Ubuntu 모두에서 BPF 개발 환경을 설정하는 단계별 가이드는 아래에 나와 있습니다.
+이것은 iproute2 빌드 및 설치는 물론 개발 커널의 빌드, 설치 및 테스트를 안내합니다.
+iproute2 및 Linux 커널을 수동으로 빌드하는 단계는 일반적으로 주요 배포판이 이미 최신 커널을 기본적으로 제공하기
+때문에 필요하지 않지만
+리스크가 있는 가장 최신의 버전을 테스트하거나 BPF 패치에 기여하는 iproute2 및 리눅스 커널에 필요합니다.
+마찬가지로, 디버깅 및 자가 검사를 위해 bpftool을 빌드하는 것은 선택 사항이지만 권장됩니다.
+
+페도라
+페도라 25 이상의 버젼에 적용됩니다:
+
+$ sudo dnf install -y git gcc ncurses-de음el elfutils-libelf-devel bc \
+openssl-devel libcap-devel clang llvm graphviz bison flex glibc-static
+
+노트 : 다른 페도라 파생 버젼을 사용하는 경우, dnf 명령어가 없는 경우 yum을 사용해 보세요.
+
+우분트
+우분투 17.04 이상의 버젼에 적용 됩니다:
+
+$ sudo apt-get install -y make gcc libssl-dev bc libelf-dev libcap-dev \
+clang gcc-multilib llvm libncurses5-dev git pkg-config libmnl bison flex \
+graphviz
+
+커널 컴파일
+리눅스 커널을 위한 새로운 BPF 기능의 개발은 net-next git 트리 안에서 이루어지며, 최신 BPF는 net
+트리에서 fix됩니다.다음 명령은 git을 통해 net-next 트리의 커널 소스를 얻습니다:
+
+$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git
+
+자식 커밋 기록에 대해 관심이 없다면 "--depth 1"은 자식 커밋 기록을 가장 최근의 커밋으로 제외함으로써 훨씬
+빠르게 트리를 복제합니다.
+
+net 트리에 관심이 있는 경우에는 다음 URL에서 복제 할수 있습니다:
+$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git
+
+인터넷에 리눅스 커널을 만드는 방법에 대한 수십 가지 튜토리얼이 있으며, 하나의 좋은 자료는 Kernel Newbies
+웹 사이트 (https://kernelnewbies.org/KernelBuild) 이며, 위에서 언급 한 두 가지 자식 트리 중
+하나를 따라 리눅스 커널을 구성 합니다.
+
+생성 된 .config 파일에 BPF를 실행하기 위한 다음 CONFIG_ * 항목이 포함되어 있는지 확인하십시오.
+이 항목은 Cilium에도 필요합니다.
+CONFIG_CGROUP_BPF=y
+CONFIG_BPF=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_CLS_BPF=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_BPF_JIT=y
+CONFIG_LWTUNNEL_BPF=y
+CONFIG_HAVE_EBPF_JIT=y
+CONFIG_BPF_EVENTS=y
+CONFIG_TEST_BPF=m
+
+일부 항목은 make menuconfig를 통해 조정할 수 없습니다. 예를 들어 CONFIG_HAVE_EBPF_JIT는 지정된 아키텍처에
+eBPF JIT가 있는 경우 자동으로 선택됩니다. 이 경우 CONFIG_HAVE_EBPF_JIT는 선택 사항이지만 적극 권장됩니다.
+eBPF JIT 컴파일러가 없는 아키텍처는 커널 내 인터프리터로 대체하여 BPF 명령어를 실행되며 효율적이지 않습니다.
+
+설정확인
+새로 컴파일 된 커널로 부팅 한 후, BPF 기능을 테스트하기 위해 BPF 셀프 테스트 그룹으로 이동합니다 (현재 작업 디렉토리가
+복제 된 git 트리의 루트를 가리킵니다).
+
+$ cd tools/testing/selftests/bpf/
+$ make
+$ sudo ./test_verifier
+
+verifier 프로그램 테스트는 수행중인 모든 현재 검사를 출력합니다:
+Summary: 847 PASSED, 0 SKIPPED, 0 FAILED
+
+노트:
+커널 릴리즈 4.16 이상 버젼에서 BPF 셀프 테스트는 더 이상 인라인 될 필요가 없는 BPF 함수 호출로 인해 LLVM 6.0 이상
+버젼에 의존됩니다.자세한 정보는 BPF에서 BPF 호출에 대한 항목을 참조하거나 커널 패치 (https://lwn.net/Articles/741773/)
+에서 커버 레터 메일을 참조하십시오. 이 새로운 기능을 사용하지 않으면 모든 BPF 프로그램이 LLVM 6.0 이상에 의존적이지 않습니다.
+배포판에서 LLVM 6.0 이상을 제공하지 않으면 LLVM 섹션의 지침에 따라 컴파일 할 수 있습니다.
+
+모든 BPF 셀프 테스트를 실행하려면 다음 명령이 필요합니다:
+$ sudo make run_tests
+
+iproute2 컴파일
+
+net(fixes 전용)과 net-next(새로운 기능) 커널 트리와 비슷하게 iproute2 git 트리에는 master와 net-next라는
+두 가지 분기가 있습니다. 마스터 분기는 net 트리를 기반으로 하며 net-next 분기는 net-next 커널 트리를 기반으로 합니다.
+헤더 파일의 변경 사항을 iproute2 트리에서 동기화 할 수 있도록 하려면이 작업이 필요합니다.
+iproute2 마스터 분기를 복제 하려면 다음 명령을 사용할 수 있습니다:
+$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/iproute2/iproute2.git
+
+마찬가지로 iproute2의 언급 된 net-next 분기에 복제 하려면 다음을 실행하십시오.
+$ git clone -b net-next git://git.kernel.org/pub/scm/linux/kernel/git/iproute2/iproute2.git
+
+그런 다음 빌드 및 설치를 진행하십시오:
+
+$ cd iproute2/
+$ ./configure --prefix=/usr
+TC schedulers
+ATM    no
+
+libc has setns: yes
+SELinux support: yes
+ELF support: yes
+libmnl support: no
+Berkeley DB: no
+
+docs: latex: no
+WARNING: no docs can be built from LaTeX files
+sgml2html: no
+WARNING: no HTML docs can be built from SGML
+$ make
+[...]
+$ sudo make install
+
+iproute2가 LLVM의 BPF 백엔드에서 ELF 파일을 처리 할 수 있도록 configure 스크립트에
+"ELF support : yes"가 표시거 되는지 확인하십시오.libelf는 이전에 Fedora와 Ubuntu의 경우 의존성
+설치 지침에 나열되었습니다.
+
+bpftool 컴파일
+bpftool은 BPF 프로그램 및 맵의 디버깅 및 내부 검사에 필수적인 도구입니다. 커널 트리의 일부이며
+tools/bpf/bpftool/ 아래에 위치해 있습니다.앞에서 설명한 것처럼 net 또는 net-next 커널 트리를 복제
+되었는지 확인하십시오.
+
+bpftool을 빌드하고 설치하려면 다음 단계가 필요합니다:
+$ cd <kernel-tree>/tools/bpf/bpftool/
+$ make
+Auto-detecting system features:
+...                        libbfd: [ on  ]
+...        disassembler-four-args: [ OFF ]
+
+CC       xlated_dumper.o
+CC       prog.o
+CC       common.o
+CC       cgroup.o
+CC       main.o
+CC       json_writer.o
+CC       cfg.o
+CC       map.o
+CC       jit_disasm.o
+CC       disasm.o
+make[1]: Entering directory '/home/foo/trees/net/tools/lib/bpf'
+
+Auto-detecting system features:
+...                        libelf: [ on  ]
+...                           bpf: [ on  ]
+
+CC       libbpf.o
+CC       bpf.o
+CC       nlattr.o
+LD       libbpf-in.o
+LINK     libbpf.a
+make[1]: Leaving directory '/home/foo/trees/bpf/tools/lib/bpf'
+LINK     bpftool
+$ sudo make install
+
+LLVM
+
+LLVM은 현재 BPF 백엔드를 제공하는 유일한 컴파일러 모음입니다. 현재 gcc는 BPF를 지원하지 않습니다.
+BPF 백엔드는 LLVM의 3.7 릴리즈로 병합되었습니다.
+주요 배포판은 LLVM을 패키징 할 때 기본적으로 BPF 백엔드를 사용 가능하게하므로
+가장 최근의 배포판에서 clang 및 llvm을 설치하면 C를 BPF 오브젝트 파일로 컴파일 하기에 충분합니다.
+일반적인 워크 플로우는 BPF 프로그램이 C로 작성되고 LLVM에 의해 object/ELF 파일로 컴파일되며
+사용자 공간 BPF ELF 로더(예 : iproute2 또는 기타)로 구문 분석되고 커널 BPF 시스템 호출을 통해 커널에 푸시됩니다.
+커널은 BPF 명령어 와 JIT를 검증하고, 프로그램을 위한 새로운 파일 디스크립터를 리턴하고, 서브 시스템
+(예 : 네트워킹)에 소속 할 수 있습니다.
+만약 지원된다면, 서브 시스템은 BPF 프로그램을 하드웨어 (예컨대, NIC)로 더 오프로드 할 수 있습니다.
+
+LLVM의 경우 BPF 대상 지원은 다음을 통해 확인할 수 있습니다:
+$ llc --version
+LLVM (http://llvm.org/):
+LLVM version 3.8.1
+Optimized build.
+Default target: x86_64-unknown-linux-gnu
+Host CPU: skylake
+
+Registered Targets:
+[...]
+bpf        - BPF (host endian)
+bpfeb      - BPF (big endian)
+bpfel      - BPF (little endian)
+[...]
+
+기본적으로 bpf 타겟은 컴파일되는 CPU의 엔디안을 사용하며, 즉, CPU의 엔디안이 리틀 엔디안인 경우 프로그램은
+리틀 엔디안 형식으로 표시되며 CPU의 엔디안이 빅 엔디안 인 경우 프로그램 빅 엔디안 형식으로 표현됩니다.
+이것은 BPF의 런타임 동작과도 일치 하며, BPF는 일반적인 형식이며, 어떤 형식의 아키텍처에도 불리하지 않도록하기 위해
+실행되는 CPU의 엔디안을 사용합니다.
+
+크로스 컴파일의 경우, 두개의 타겟 bpfeb 와 bpfel이 도입 덕분에, BPF 프로그램은 x86에서의 리틀 엔디안에서 실행되는 노드에서
+컴파일 할수 있으며,arm에서의 빅 엔디안 형식의 노드에서 실행 할 수 있습니다. 프런트 엔드(clang)는 타겟 엔디안 에서도 실행 해야 합니다.
+타겟으로 bpf사용하는 것은 엔디안이 혼재되지 않는 상황에서 선호 되는 방법입니다.
+
+예를 들어, x86_64에서의 컴파일은 little endian이기 때문에 타겟 bpf 및 bpfel에 대해 동일한 결과물 로써, 컴파일을
+트리거하는 스크립트에서는 endian을 인식 할 필요가 없습니다.
+최소한의 독립실행형 XDP drop 프로그램은 다음 예제 (xdp-example.c)와 같습니다.
+
+#include <linux/bpf.h>
+
+#ifndef __section
+# define __section(NAME)                  \
+__attribute__((section(NAME), used))
+#endif
+
+__section("prog")
+int xdp_drop(struct xdp_md *ctx)
+{
+return XDP_DROP;
+}
+
+char __license[] __section("license") = "GPL";
+
+그런 다음 다음과 같이 컴파일하고 커널에 로드 할 수 있습니다.
+$ clang -O2 -Wall -target bpf -c xdp-example.c -o xdp-example.o
+# ip link set dev em1 xdp obj xdp-example.o
+
+NOTE: 위와 같이 네트워크 장치에 XDP BPF 프로그램을 연결하려면 XDP를 지원하는 장치가있는 Linux 4.11 혹은 Linux 4.12 이 요구됩니다.
+생성 된 오브젝트 파일의 경우 LLVM (> = 3.9)은 공식적인 BPF 시스템 값, 즉 EM_BPF (10진수:247/16진수:0xf7)를 사용합니다.
+이 예제에서 프로그램은 x86_64에서 bpf 타겟으로 컴파일 되었으므로 LSB(MSB와 반대)가 endian와 관련하여 표시됩니다.
+
+$ file xdp-example.o
+xdp-example.o: ELF 64-bit LSB relocatable, *unknown arch 0xf7* version 1 (SYSV), not stripped
+
+readelf -a xdp-example.o 은 ELF 파일에 대한 추가 정보를 덤프 하며, 생성 된 섹션 헤더, 재배치 항목 및
+기호 테이블을 자가검사 할 때 유용 할 수 있습니다.
+Clang 및 LLVM을 처음부터 컴파일 해야하는 경우에는 다음 명령을 사용할 수 있습니다:
+
+$ git clone http://llvm.org/git/llvm.git
+$ cd llvm/tools
+$ git clone --depth 1 http://llvm.org/git/clang.git
+$ cd ..; mkdir build; cd build
+$ cmake .. -DLLVM_TARGETS_TO_BUILD="BPF;X86" -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release -DLLVM_BUILD_RUNTIME=OFF
+$ make -j $(getconf _NPROCESSORS_ONLN)
+
+$ ./bin/llc --version
+LLVM (http://llvm.org/):
+LLVM version x.y.zsvn
+Optimized build.
+Default target: x86_64-unknown-linux-gnu
+Host CPU: skylake
+
+Registered Targets:
+bpf    - BPF (host endian)
+bpfeb  - BPF (big endian)
+bpfel  - BPF (little endian)
+x86    - 32-bit X86: Pentium-Pro and above
+x86-64 - 64-bit X86: EM64T and AMD64
+
+$ export PATH=$PWD/bin:$PATH   # add to ~/.bashrc
+
+--version 정보에 Optimized build가 포함되어 있는지 확인해야 하며, 그렇지 않으면 디버깅 방식에서 LLVM을 사용하는
+프로그램의 컴파일 시간이 크게 늘어납니다 (예:10 배 이상).
+
+디버깅을 위해 clang에서는 다음과 같이 어셈블러 출력을 생성 할 수 있습니다.
+
+$ clang -O2 -S -Wall -target bpf -c xdp-example.c -o xdp-example.S
+$ cat xdp-example.S
+.text
+.section    prog,"ax",@progbits
+.globl      xdp_drop
+.p2align    3
+xdp_drop:                             # @xdp_drop
+# BB#0:
+r0 = 1
+exit
+
+.section    license,"aw",@progbits
+.globl    __license               # @__license
+__license:
+.asciz    "GPL"
+
+또한 최신 LLVM 버전 (>= 4.0)은 디버그 정보를 dwarf 형식으로 객체 파일에 저장할 수 있습니다.
+이것은 컴파일 -g 파라메터를 추가하여 일반적인 워크플로우를 통해 수행 할 수 있습니다.
+
+$ clang -O2 -g -Wall -target bpf -c xdp-example.c -o xdp-example.o
+$ llvm-objdump -S -no-show-raw-insn xdp-example.o
+
+xdp-example.o:        file format ELF64-BPF
+
+Disassembly of section prog:
+xdp_drop:
+; {
+0:        r0 = 1
+; return XDP_DROP;
+1:        exit
+
+llvm-objdump 도구는 컴파일러에서 사용 된 원본 C 코드로 어셈블러 출력에 주석을 추가 할 수 있습니다.
+이 경우 간단한 예제는 C 코드를 많이 포함하지 않지만 0 : 및 1: 로 표시된 줄 번호는 커널의 verifier 로그에 직접 해당합니다.
+
+즉, BPF 프로그램이 verifier에 의해 거부되는 경우 llvm-objdump는 명령을 원래의
+C코드와 연관시키는 데 도움을 줄 수 있으며 이는 분석하는데 있어서 매우 유용합니다.
+
+# ip link set dev em1 xdp obj xdp-example.o verb
+
+Prog section 'prog' loaded (5)!
+- Type:         6
+- Instructions: 2 (0 over limit)
+- License:      GPL
+
+Verifier analysis:
+
+0: (b7) r0 = 1
+1: (95) exit
+processed 2 insns
+
+verifier 분석에서 볼 수 있듯이, llvm-objdump 출력 값은 커널과 동일한 BPF 어셈블러 코드를 덤프 합니다.
+-no-show-raw-insn 옵션을 제외하면 raw struct bpf_insn을 어셈블리 앞에 16 지수로 덤프 합니다:
+
+$ llvm-objdump -S xdp-example.o
+
+xdp-example.o:        file format ELF64-BPF
+
+Disassembly of section prog:
+xdp_drop:
+; {
+0:       b7 00 00 00 01 00 00 00     r0 = 1
+; return foo();
+1:       95 00 00 00 00 00 00 00     exit
+
+
+LLVM IR(중간 표현) 디버깅인 경우, BPF 컴파일 프로세스를 두 단계로 나뉠 수 있으며, 나중에 llc에 전달 될수 있는
+바이너리 LLVM IR(중간 표현) 중간 파일인 xdp-example.bc 생성 합니다.
+$ clang -O2 -Wall -target bpf -emit-llvm -c xdp-example.c -o xdp-example.bc
+$ llc xdp-example.bc -march=bpf -filetype=obj -o xdp-example.o
+
+생성 된 LLVM IR(중간 표현)은 또한 다음을 통해 사람이 읽을 수있는 형식으로 덤프 될 수 있습니다:
+$ clang -O2 -Wall -emit-llvm -S -c xdp-example.c -o -
+
+LLVM의 BPF 백 엔드는 현재 BPF의 32비트 하위 레지스터를 사용하는 코드 생성을 지원하지 않습니다.
+현재 BPF 용 인라인 어셈블리도 지원되지 않습니다.
+또한 BPF 어셈블리 파서가 없기 때문에 현재 BPF 어셈블리
+(예를 들어, llvm-mc xdp-example.S -arch bpf -filetype = obj -o xdp-example.o)
+에서 컴파일이 지원되지 않습니다.
+
+LLVM은 기본적으로 코드를 생성하기 위해 BPF 기본 명령어 세트를 사용하여 생성 된 오브젝트 파일이
+long-term stable kernel(예 : 4.9 이상)과 같은 이전의 커널로 로드 될 수 있는지 확인합니다.
+그러나 LLVM에는 BPF 명령어 세트의 다른 버전을 선택하기 위해 BPF 백엔드에 대한 -mcpu 선택 옵션이 있어서,
+보다 효율적이고 작은 코드를 생성하기 위해 BPF 기본 명령어 세트의 맨 위에 있는 명령어 세트 확장을 사용합니다.
+
+사용 가능한 -mcpu 옵션은 다음을 통해 쿼리 할 수 있습니다:
+$ llc -march bpf -mcpu=help
+Available CPUs for this target:
+
+generic - Select the generic processor.
+probe   - Select the probe processor.
+v1      - Select the v1 processor.
+v2      - Select the v2 processor.
+[...]
+
+일반 프로세서는 기본 프로세서이며 BPF의 기본 명령어 세트 v1 입니다.
+옵션 v1과 v2는 일반적으로 BPF 프로그램이 크로스 컴파일 되는 환경에서 유용하며, 프로그램이 로드 되는
+대상 호스트와 컴파일 된 대상 호스트가 다릅니다(따라서 사용 가능한 BPF 커널 기능도 다를 수 있음).
+
+Cilium에서 내부적으로 사용하는 -mcpu 권장 옵션은 -mcpu=probe 입니다!
+여기서 LLVM BPF 백엔드는 BPF 명령어 세트 확장의 가용성을 커널에 쿼리하며, 커널에서 사용 가능한 것으로 확인되면
+LLVM은 필요할 때마다 BPF 프로그램을 컴파일 하기 위해 옵션을 사용합니다.
+
+llc의 -mcpu = probe를 사용한 전체 명령 행 예제:
+$ clang -O2 -Wall -target bpf -emit-llvm -c xdp-example.c -o xdp-example.bc
+$ llc xdp-example.bc -march=bpf -mcpu=probe -filetype=obj -o xdp-example.o
+
+일반적으로 LLVM IR 생성은 아키텍처 독립적입니다.
+그러나 clang -target bpf를 -target bpf를 제외하고 사용하면 몇 가지 차이점이 있으며,
+기본 아키텍처에 따라 x86_64, arm64 또는 기타 등의 clang의 기본 대상을 사용할 수 있습니다.
+
+커널의 Documentation/bpf/bpf_devel_QA.txt에서 인용:
+
+그러나 clang -target bpf를 사용하는 경우 와 -target bpf 를 사용하지 않을 때
+clang의 기본 대상을 사용하는 경우에는 기본 아키텍처에 따라 x86_64, arm64 또는 기타와 같은 몇 가지 차이점이 있습니다.
+
+* BPF 프로그램은 파일 범위 인라인 어셈블리 코드가 있는 헤더 파일을 재귀적으로 포함 할 수 있습니다.
+기본 타켓은 잘 처리 할 수 있지만, bpf 백엔드 어셈블러가 이러한 어셈블리 코드를 이해하지 못하면
+대부분의 경우에 bpf 타겟이 실패 할 수 있습니다.
+
+* -g 옵션 없이 컴파일하면 예를 들어 .eh_frame 및 .rela.eh_frame 과 같은 추가 elf 섹션이
+기본 타겟을 가지는 오프젝트 파일에 존재 할 수 있으며, bpf 타겟과는 다릅니다.
+
+* 기본 타겟은 C언어 switch 문을 switch table lookup 및 Jump 동작으로 변환 할 수 있습니다.
+switch table이 전역 읽기 전용 섹션에 있으므로 bpf 프로그램이 로드 되지 않습니다.
+bpf 타겟은 switch table 최적화를 지원하지 않습니다. clang 옵션 -fno-jump-tables를 사용하여 switch table 생성을 비 활성화 할 수 있습니다.
+
+* clang -target bpf 의 경우, 포인터 또는 long/unsigned long 타입은
+기본 clang 바이너리 또는 기본 타겟(또는 커널)이 32 비트인지 여부에 관계없이 항상 64 비트의 크기를 가집니다.
+그러나 네이티브 clang 타겟이 사용될 때 기본 아키텍처의 규칙에 따라 이러한 유형을 컴파일 하며,
+32 비트 아키텍처의 경우 포인터 또는 long/unsigned long 타입을 의미 하며,
+BPF 컨텍스트 구조는 32 비트의 너비를 가지며, BPF LLVM 백엔드는 여전히 64 비트로 작동합니다.
+
+* 네이티브 타겟은 CPU 레지스터 또는 CPU의 레지스터 너비가 중요한 다른 커널 구조를 매핑하는 커널의 구조체
+pt_regs 이동 하는 경우 추적에 주로 필요합니다.
+네트워킹과 같은 다른 모든 경우에는 clang -target bpf를 사용하는 것이 좋습니다.
+
+BPF를 위한 C 프로그램을 작성 할때, C를 사용하여 일반적인 어플리케이션 개발과 비교 되며, 알고 있어야 할 몇 가지
+저지르기 쉬운 실수가 있습니다.다음 항목에서는 BPF 모델의 몇 가지 차이점에 대해 설명합니다:
+
+1. 모든 것이 인라인 될 필요가 있으며, 함수 콜 (구 LLVM 버전에서)이나 공유 라이브러리 호출이 없습니다.
+공유 라이브러리 등은 BPF와 함께 사용할 수 없습니다.
+그러나 BPF 프로그램에서 사용되는 공통 라이브러리 코드는 헤더 파일에 배치되고 주 프로그램에 포함될 수 있습니다.
+예를 들어, Cilium은 이것을 많이 사용합니다 (bpf/lib/ 참조). 그러나 이것은 여전히 헤더 파일을 포함 할 수 있으며,
+예를 들어 커널이나 다른 라이브러리에서 가져 와서 정적 인라인 함수 나 매크로/정의를 재사용 할 수 있습니다.
+BPF에서 BPF 함수 콜이 지원되는 최신 커널 (4.16+)과 LLVM (6.0+)이 사용하지 않는 경우에
+LLVM은 전체 코드를 컴파일하고 주어진 프로그램 섹션에 대한 BPF 명령어의 flat sequence로 인라인 해야합니다.
+
+이 경우 아래에 표시된 것처럼 모든 라이브러리 함수에 대해 __inline과 같은 주석을 사용하는 것이 가장 좋습니다.
+always_inline을 사용하는 것이 추천하며, 컴파일러는 여전히 inline 으로 주석 처리 된 큰 함수의 uninline 할 수 있기 때문입니다.
+후자가 발생하면 LLVM은 ELF 파일로 재배치 엔트리를 생성하며, 이 엔트리는 iproute2와 같은 BPF ELF 로더가 해석 할 수 없으며
+따라서 BPF 맵만이 로더가 처리 할 수있는 유효한 재배치 엔트리이기 때문에 오류가 발생합니다.
+
+#include <linux/bpf.h>
+
+#ifndef __section
+# define __section(NAME)                  \
+__attribute__((section(NAME), used))
+#endif
+
+#ifndef __inline
+# define __inline                         \
+inline __attribute__((always_inline))
+#endif
+
+static __inline int foo(void)
+{
+return XDP_DROP;
+}
+
+__section("prog")
+int xdp_drop(struct xdp_md *ctx)
+{
+return foo();
+}
+
+char __license[] __section("license") = "GPL";
+
+2.여러 프로그램은 서로 다른 섹션의 단일 C 파일 내에 상주 할 수 있습니다.
+BPF 용 C 프로그램은 섹션 주석을 많이 사용합니다. C 파일은 일반적으로 3 개 이상의 섹션으로
+구성됩니다.BPF ELF 로더는 이 이름들을 사용하여 bpf 시스템 콜을 통해 프로그램 과 맵을
+로드하기 위해 관련 정보를 추출하고 준비합니다.
+예를 들어, iproute2는 맵과 라이센스를 기본 섹션 이름으로 사용하여 맵 작성에 필요한
+메타 데이터와 BPF 프로그램에 대한 라이센스를 각각 찾습니다.프로그램 생성시 마지막에
+커널에 푸시가 되며, 프로그램이 GPL호환 라이센스를 보유한 경우에만 GPL로 노출되는 일부 Helper 기능
+들이 활성화 되며,예를 들어 bpf_ktime_get_ns(), bfp_probe_read() 및 기타가 해당이 됩니다.
+나머지 섹션 이름은 BPF 프로그램 코드이며, 예를 들어 아래 코드는 두 개의 프로그램 섹션 인
+ingress 와 egress 를 포함하도록 수정되었습니다.toy 예제 코드는 둘 다 map 와 account_data () 함수와
+같은 일반적인 정적 인라인  helper를 공유 할 수 있음을 보여 줍니다.
+xdp-example.c 예제는 tc로 로드되고 netdevice의 ingress 및
+egress hook에 연결될 수 있는 tc-example.c 예제로 수정되었습니다.
+전송 된 바이트를 두 개의 map 슬롯을 가지고 있으며, 하나는 ingress hook에 있는 트래픽 용이고 다른 하나는
+egress hook에 있는 acc_map이라는 맵에 기록 됩니다.
+
+#include <linux/bpf.h>
+#include <linux/pkt_cls.h>
+#include <stdint.h>
+#include <iproute2/bpf_elf.h>
+
+#ifndef __section
+# define __section(NAME)                  \
+__attribute__((section(NAME), used))
+#endif
+
+#ifndef __inline
+# define __inline                         \
+inline __attribute__((always_inline))
+#endif
+
+#ifndef lock_xadd
+# define lock_xadd(ptr, val)              \
+((void)__sync_fetch_and_add(ptr, val))
+#endif
+
+#ifndef BPF_FUNC
+# define BPF_FUNC(NAME, ...)              \
+(*NAME)(__VA_ARGS__) = (void *)BPF_FUNC_##NAME
+#endif
+
+static void *BPF_FUNC(map_lookup_elem, void *map, const void *key);
+
+struct bpf_elf_map acc_map __section("maps") = {
+.type           = BPF_MAP_TYPE_ARRAY,
+.size_key       = sizeof(uint32_t),
+.size_value     = sizeof(uint32_t),
+.pinning        = PIN_GLOBAL_NS,
+.max_elem       = 2,
+};
+
+static __inline int account_data(struct __sk_buff *skb, uint32_t dir)
+{
+uint32_t *bytes;
+
+bytes = map_lookup_elem(&acc_map, &dir);
+if (bytes)
+lock_xadd(bytes, skb->len);
+
+return TC_ACT_OK;
+}
+
+__section("ingress")
+int tc_ingress(struct __sk_buff *skb)
+{
+return account_data(skb, 0);
+}
+
+__section("egress")
+int tc_egress(struct __sk_buff *skb)
+{
+return account_data(skb, 1);
+}
+
+char __license[] __section("license") = "GPL";
+
+이 예제는 또한 프로그램을 개발할 때 알아두면 유용한 몇 가지 다른 것들을 보여줍니다.
+이 코드에는 커널 헤더, 표준 C 헤더 및 struct bpf_elf_map의 정의가 포함 된 iproute2 특정 헤더가 포함됩니다.
+iproute2는 일반적인 BPF ELF 로더를 가지고 있으며 그리고 그러한 구조체 bpf_elf_map의 정의는 XDP 및 tc
+타입 프로그램에 대해 매우 동일합니다.struct bpf_elf_map 항목은 프로그램에서 map을 정의하며
+두 BPF 프로그램에서 사용되는 map을 생성하는 데 필요한 모든 관련 정보 (예를 들어 키/값 크기 등)를 포함합니다.
+구조체는 로더가 찾을 수 있도록 map 섹션에 배치해야 합니다.
+다른 변수 이름을 가진이 타입의 map 선언이 여러 개있을 수 있지만, 모두 __section( "maps")으로 주석을 추가해야 합니다.
+
+구조체 bpf_elf_map은 iproute2에만 적용됩니다.
+다른 BPF ELF 로더는 다른 형식을 가질 수 있으며, 예를 들어, perf에 의해 주로 사용되는 커널 소스 트리의
+libbpf는 다른 사양을 갖습니다. iproute2는 struct bpf_elf_map에 대한 하위 호환성을 보장합니다.
+Cilium은 iproute2 모델을 따릅니다. 이 예제는 또한 BPF helper 함수가 C 코드로 매핑되고 사용되는 방법을 보여줍니다.
+
+여기에서 map_lookup_elem() 함수는 uapi/linux/bpf.h 에서 helper로 표시되는
+BPF_FUNC_map_lookup_elem 열거 형 값에 매핑하여 정의합니다.프로그램이 나중에 커널에 로드 될 때,
+verifier는 전달 된 인수가 예상되는 유형인지 확인하고 helper 호출을 실제 함수 호출로 재 지정합니다.
+또한 map_lookup_elem() 함수는 map를 BPF helper 함수에 전달하는 방법을 보여줍니다.
+여기서 maps 섹션의 &acc_map은 map_lookup_elem() 함수의 첫 번째 인수로 전달됩니다.
+정의 된 배열 map이 전역 이므로, 어카운팅은 lock_xadd()로 정의되는 atomic operation을 사용해야합니다.
+
+LLVM은 __sync_fetch_and_add()를 내장 함수로 매핑하여 word 크기에 대해
+BPF atomic add 명령어 즉  BPF_STX | BPF_XADD | BPF_W를 매핑합니다.
+마지막으로, bpf_elf_map 구조체는 map이 PIN_GLOBAL_NS로 고정 되도록 나타냅니다.
+즉, tc는 map을 BPF pseudo file system 에 노드 로 고정 합니다.
+기본적으로 주어진 예제에서는 /sys/fs/bpf/tc/globalals/acc_map에 고정됩니다.
+PIN_GLOBAL_NS로 인해 map은 /sys/fs/bpf/tc/globals/에 위치 하게 됩니다.
+전역은 개체 파일에 걸쳐있는 전역 네임 스페이스 역할을합니다. 예제에서 PIN_OBJECT_NS를 사용하면
+tc는 오브젝트 파일에 대한 로컬 디렉토리를 작성합니다.
+
+예를 들어, BPF 코드가있는 다른 C 파일은 위의 PIN_GLOBAL_NS 고정과 동일한 acc_map
+정의를 가질 수 있습니다.이 경우 map은 다양한 오브젝트 파일에서 비롯된 BPF 프로그램 간에
+공유됩니다. PIN_NONE은 map가 BPF 파일 시스템에 노드로 배치 되지 않으며, 결과적으로 tc가 종료 된 후
+사용자 공간에서 액세스 할 수 없음을 의미합니다.또한 tc가 각 프로그램에 대해 두 개의 개별 맵 인스턴스를 생성
+한다는 것은 해당 이름으로 이전에 고정 된 맵을 검색 할 수 없기 때문입니다. 언급 된 경로의 acc_map 부분은 소스
+코드에 지정된 map의 이름입니다.
+
+따라서, ingress 프로그램을 로딩 할 때, tc는 BPF 파일 시스템에 그러한 맵이 존재하지 않으며
+새로운 맵을 생성한다는 것을 알게 될 것입니다.성공하면 map가 고정되어 egress 프로그램이 tc를 통해 로드 될 때,
+해당 map이 BPF 파일 시스템에 이미 있음 을 알게되고 egress 프로그램에 재사용 하게 됩니다.
+또한 로더는 맵의 속성 (키/값 크기 등)이 일치하는 동일한 이름의 map이 있는 경우에도 확인합니다.
+
+tc가 같은 map을 검색 할 수있는 것처럼, 타사 응용 프로그램은 bpf 시스템 콜에서 BPF_OBJ_GET 명령을 사용하여
+동일한 맵 인스턴스를 가리키는 새 파일 디스크립터를 생성 할 수 있으며,이 디스크립터는 맵 요소를 검색/갱신/삭제
+하는데 사용 될수 있습니다.
+
+다음과 같이 코드를 컴파일하고 iproute2를 통해 로드 할 수 있습니다:
+$ clang -O2 -Wall -target bpf -c tc-example.c -o tc-example.o
+
+# tc qdisc add dev em1 clsact
+# tc filter add dev em1 ingress bpf da obj tc-example.o sec ingress
+# tc filter add dev em1 egress bpf da obj tc-example.o sec egress
+
+# tc filter show dev em1 ingress
+filter protocol all pref 49152 bpf
+filter protocol all pref 49152 bpf handle 0x1 tc-example.o:[ingress] direct-action id 1 tag c5f7825e5dac396f
+
+# tc filter show dev em1 egress
+filter protocol all pref 49152 bpf
+filter protocol all pref 49152 bpf handle 0x1 tc-example.o:[egress] direct-action id 2 tag b2fd5adc0f262714
+
+# mount | grep bpf
+sysfs on /sys/fs/bpf type sysfs (rw,nosuid,nodev,noexec,relatime,seclabel)
+bpf on /sys/fs/bpf type bpf (rw,relatime,mode=0700)
+
+# tree /sys/fs/bpf/
+/sys/fs/bpf/
++-- ip -> /sys/fs/bpf/tc/
++-- tc
+|   +-- globals
+|       +-- acc_map
++-- xdp -> /sys/fs/bpf/tc/
+
+4 directories, 1 file
+
+패킷이 em1 장치를 통과 하자마자 BPF map의 카운터가 증가합니다.
+
+3. 허용되는 전역 변수가 없습니다.
+1 에서 언급 한 이유로 BPF는 일반적인 C 프로그램에서 자주 사용되는 전역 변수를 가질 수 없습니다.
+그러나 프로그램에서 단순히 BPF_MAP_TYPE_PERCPU_ARRAY 타입의 BPF 맵을 임의의 값 크기의
+단일 슬롯과 함께 사용할 수 있다는 해결 방법이 있습니다.이것은 실행 중에 BPF 프로그램이 결코 커널에 의해 선점되지
+않도록 보장되므로 단일 맵 항목을 임시 데이터를 위한 스크래치 버퍼로 사용할 수 있으며,  예를 들어서, 스택 제한 범위를
+넘어서는 확장 입니다. 이것은 또한 선점과 관련하여 동일한 보장이 있기 때문에,  tail call에 건너서 동작 합니다.
+그렇지 않으면 여러 BPF 프로그램 실행에서 상태를 유지하기 위해 정상적인 BPF 맵을 사용할 수 있습니다.
+
+4. const 문자열이나 배열이 허용되지 않습니다.
+BPF C 프로그램에서 const 문자열 이나 다른 배열을 정의하는 것은 섹션 1과 3에서 지적한 내용과 같이
+즉, 로더쪽으로 ABI의 일부가 아니기 때문에 로더가 거부하는 ELF 파일에 재배치 항목이 생성 되는 이유로 동작 하지 않습니다
+(로더는 이미 컴파일 된 BPF 순서를 다시 작성 해야하므로 이러한 항목을 수정할 수 없습니다).
+앞으로 LLVM은 이러한 발생을 감지하고 사용자에게 오류를 일찍 알수 있습니다.
+
+trace_printk()과 같은 helper 함수는 다음과 같이 처리 할 수 있습니다:
+
+static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);
+
+#ifndef printk
+# define printk(fmt, ...)                                      \
+({                                                         \
+char ____fmt[] = fmt;                                  \
+trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \
+})
+#endif
+
+그런 다음 프로그램은 printk("skb len:%u\n", skb->len); 와 같이 자연스럽게 매크로를 사용할 수 있습니다.
+그러면 출력이 추적 파이프에 기록됩니다. tc exec bpf dbg를 사용하여 거기에서 메시지를 검색 할 수 있습니다.
+trace_printk() helper 함수의 사용에는 몇 가지 단점이 있으므로 프로덕션 용도로 권장되지 않습니다.
+helper 함수가 호출 될 때마다 "skb len:%u\n"과 같은 상수 문자열을 BPF 스택에 로드 해야 하지만
+BPF helper 함수는 최대 5 개의 인수로 제한됩니다.이것은 dumping을 위해 전달 될 수 있는 추가 변수
+3 개만 남겨 둡니다.
+
+따라서 빠른 디버깅에 도움이 되지만 네트워킹 프로그램에서 skb_event_output() 또는
+xdp_event_output() helper 함수를 사용하는 것이 좋습니다.
+BPF 프로그램의 사용자 지정 구조체를 선택적 패킷 샘플과 함께 perf 이벤트 링 버퍼로 전달할 수 있습니다.
+예를 들어, Cilium의 모니터는 디버깅 프레임 워크, 네트워크 정책 위반에 대한 알림 등을 구현하기
+위해 이 helper 함수 를 사용합니다.이러한 helper 함수들은 잠금없는 메모리 매핑 된 CPU 당 성능 링 버퍼를 통해
+데이터를 전달 하므로 trace_printk()보다 훨씬 빠릅니다.
+
+5. memset()/memcpy()/memmove()/memcmp()에 LLVM 내장 함수를 사용합니다.
+BPF 프로그램은 BPF helper 가 아닌 다른 함수 호출을 수행 할 수 없기 때문에 공용 라이브러리 코드를 인라인 함수로 구현해야합니다.
+또한 LLVM은 프로그램이 일정한 크기(여기서는 n)로 사용할 수있는 내장 함수를 제공 라며, 이 함수는 항상 인라인 됩니다:
+
+#ifndef memset
+# define memset(dest, chr, n)   __builtin_memset((dest), (chr), (n))
+#endif
+
+#ifndef memcpy
+# define memcpy(dest, src, n)   __builtin_memcpy((dest), (src), (n))
+#endif
+
+#ifndef memmove
+# define memmove(dest, src, n)  __builtin_memmove((dest), (src), (n))
+#endif
+
+memcmp() 빌트인은 백엔드에서 LLVM 문제로 인해 인라인이 발생하지 않는 일부 corner case가 있으므로 문제가 해결 될 때까지는
+사용하지 않는 것이 좋습니다.
+
+6.사용할 수 있는 루프가 없습니다(미완성).
+커널의 BPF verifier는 BPF 프로그램이 다른 제어 흐름 그래프 검증 외에 가능한 모든 프로그램 경로의 깊이 우선 검색을 수행하여
+루프를 포함하고 있지 않은지 확인합니다.목적은 프로그램이 항상 종료되도록 보장하는 것입니다.
+#pragma unroll 지시문을 사용하여 상한 루프 경계에서 매우 제한된 루핑 형식을 사용할 수 있습니다.
+BPF로 컴파일 된 예제 코드:
+#pragma unroll
+for (i = 0; i < IPV6_MAX_HEADERS; i++) {
+switch (nh) {
+case NEXTHDR_NONE:
+return DROP_INVALID_EXTHDR;
+case NEXTHDR_FRAGMENT:
+return DROP_FRAG_NOSUPPORT;
+case NEXTHDR_HOP:
+case NEXTHDR_ROUTING:
+case NEXTHDR_AUTH:
+case NEXTHDR_DEST:
+if (skb_load_bytes(skb, l3_off + len, &opthdr, sizeof(opthdr)) < 0)
+return DROP_INVALID;
+
+nh = opthdr.nexthdr;
+if (nh == NEXTHDR_AUTH)
+len += ipv6_authlen(&opthdr);
+else
+len += ipv6_optlen(&opthdr);
+break;
+default:
+*nexthdr = nh;
+return len;
+}
+}
+또 다른 가능성은 같은 프로그램에 다시 호출하고 로컬 스크래치 공간을 갖는 BPF_MAP_TYPE_PERCPU_ARRAY 맵을
+사용하여 tail call을 사용하는 것입니다.동적 인 반면,이 루핑 형식은 최대 32 회 반복으로 제한됩니다. 앞으로 BPF는
+네이티브이지만 제한된 형태의 구현 루프를 가질 수 있습니다.
+
+7. tail call로 프로그램 분할.
+tail call은 하나의 BPF 프로그램에서 다른 BPF 프로그램으로 점프하여 런타임 중에 프로그램 동작을
+atomically으로 변경할 수있는 유연성을 제공합니다. 다음 프로그램을 선택하기 위해 tail call은 프로그램 배열 map
+(BPF_MAP_TYPE_PROG_ARRAY)을 사용하고 map뿐만 아니라 다음 프로그램에게 인덱스를
+다음 프로그램으로 점프 되도록 인덱스를 전달 합니다. 점프가 수행 된 이후에는 이전 프로그램으로 리턴되지 않으며 주어진
+map 인덱스에 프로그램이 없는 경우 처음 수행한 프로그램에서 실행을 계속됩니다. 예를 들어, 이것은 파서의 다양한 단계를
+구현하는 데 사용할 수 있으며, 이러한 단계는 런타임 중에 새로운 구문 분석 기능으로 업데이트 될 수 있습니다. 또 다른 사용
+사례는 이벤트 알림 이며, 예를 들어, Cilium은 런타임 중에 패킷 드랍 알림을 선택 할 수 있으며,
+skb_event_output() 함수 콜은 tail called 프로그램 안에 위치합니다. 따라서 일반적인 동작에서는 프로그램이 관련
+map 인덱스에 추가되지 않으면 fall-through 경로가 항상 실행 되며, 여기에서 프로그램은 메타 데이터를 준비하고
+사용자 공간에 있는 데몬에 이벤트 통지를 트리거 합니다. 프로그램 배열 map은 매우 유연하므로 각 map 인덱스에 있는
+프로그램에 대해 개별 액션을 구현할 수 있습니다.
+
+예를 들어서, XDP 혹은 tc에 연결된 최상위 프로그램은 프로그램 배열 맵의 인덱스 0에서 초기
+tail call을 수행하여, 트래픽 샘플링을 수행 한 다음 프로그램 배열 맵의 인덱스 1로 이동하며,
+여기서 방화벽 정책을 적용하며, 프로그램 맵 배열 인덱스 2에서 패킷에 대해 drop 또는 추후 처리중 하나를 선택하며,
+여기서 패킷이 mangled 되고, 인터페이스에서 다시 전동 됩니다.
+
+물론 프로그램 배열 맵의 점프는 임의적 일 수 있습니다. 최대 taill call 제한에 도달하면 커널은 결국
+fall-through path 를 실행합니다. tail call 을 사용하는 최소 예제 발쵀는 아래와 같습니다:
+
+[...]
+
+#ifndef __stringify
+# define __stringify(X)   #X
+#endif
+
+#ifndef __section
+# define __section(NAME)                  \
+__attribute__((section(NAME), used))
+#endif
+
+#ifndef __section_tail
+# define __section_tail(ID, KEY)          \
+__section(__stringify(ID) "/" __stringify(KEY))
+#endif
+
+#ifndef BPF_FUNC
+# define BPF_FUNC(NAME, ...)              \
+(*NAME)(__VA_ARGS__) = (void *)BPF_FUNC_##NAME
+#endif
+
+#define BPF_JMP_MAP_ID   1
+
+static void BPF_FUNC(tail_call, struct __sk_buff *skb, void *map,
+uint32_t index);
+
+struct bpf_elf_map jmp_map __section("maps") = {
+.type           = BPF_MAP_TYPE_PROG_ARRAY,
+.id             = BPF_JMP_MAP_ID,
+.size_key       = sizeof(uint32_t),
+.size_value     = sizeof(uint32_t),
+.pinning        = PIN_GLOBAL_NS,
+.max_elem       = 1,
+};
+
+__section_tail(JMP_MAP_ID, 0)
+int looper(struct __sk_buff *skb)
+{
+printk("skb cb: %u\n", skb->cb[0]++);
+tail_call(skb, &jmp_map, 0);
+return TC_ACT_OK;
+}
+
+__section("prog")
+int entry(struct __sk_buff *skb)
+{
+skb->cb[0] = 0;
+tail_call(skb, &jmp_map, 0);
+return TC_ACT_OK;
+}
+
+char __license[] __section("license") = "GPL";
+
+이 toy 프로그램을 로드 할 때, tc는 프로그램 배열을 생성하고 jmp_map 아래의 전역 네임 스페이스의 BPF 파일 시스템에 고정 시킵니다.
+또한 iproute2의 BPF ELF 로더는 __section_tail()으로 표시 된 섹션을 인식합니다.
+struct bpf_elf_map의 제공된 ID는 __section_tail()의 ID 마커, 즉 JMP_MAP_ID와 일치하므로
+프로그램은 사용자 지정 프로그램 배열 map 인덱스 (이 예제에서는 0)에서 로드 됩니다.
+결과적으로 제공된 모든 tail call 섹션은 iproute2 로더에 의해 해당 맵에 채워 집니다.
+이 메커니즘은 tc에만 해당되는 것이 아니라 iproute2가 지원하는 다른 BPF 프로그램 유형(예 :XDP, lwt)에도 적용 할 수 있습니다.
+
+생성 된 elf에는 map ID와 해당 map 내의 항목을 설명하는 섹션 헤더가 있습니다:
+$ llvm-objdump -S --no-show-raw-insn prog_array.o | less
+prog_array.o:   file format ELF64-BPF
+
+Disassembly of section 1/0:
+looper:
+0:       r6 = r1
+1:       r2 = *(u32 *)(r6 + 48)
+2:       r1 = r2
+3:       r1 += 1
+4:       *(u32 *)(r6 + 48) = r1
+5:       r1 = 0 ll
+7:       call -1
+8:       r1 = r6
+9:       r2 = 0 ll
+11:       r3 = 0
+12:       call 12
+13:       r0 = 0
+14:       exit
+Disassembly of section prog:
+entry:
+0:       r2 = 0
+1:       *(u32 *)(r1 + 48) = r2
+2:       r2 = 0 ll
+4:       r3 = 0
+5:       call 12
+6:       r0 = 0
+7:       exi
+
+이 경우 section 1/0 은 looper()함수 가 0 위치의 map ID 1 에 상주 함을 나타냅니다.
+고정 된 map은 새로운 프로그램으로 맵을 업데이트하기 위해 사용자 공간 애플리케이션(예 : Cilium 데몬)에
+의해 검색 될뿐만 아니라 tc 자체에 의해 검색 될 수 있습니다.
+업데이트는 atomically 으로 발생하며, 다양한 하위 시스템에서 처음 트리거되는
+초기 엔트리 프로그램도 자동 업데이트 됩니다.
+
+tail call map 업데이트를 수행하는 tc의 예:
+# tc exec bpf graft m:globals/jmp_map key 0 obj new.o sec foo
+
+iproute2가 고정 된 프로그램 배열을 갱신 할 경우, graft 명령을 사용할 수 있습니다.
+globals/jmp_map을 가리키면 tc는 인덱스/키 0의 맵을 foo 섹션 아래 new.o 오브젝트 파일에 있는
+새 프로그램으로 갱신합니다.
+
+8. 최대 512 바이트의 제한된 스택 공간
+BPF 프로그램의 스택 공간은 512 바이트로 제한되어 있으므로 C로 BPF 프로그램을 구현할 때는
+신중하게 고려해야합니다. 그러나 앞의 3 번 항목에서 설명한 것처럼 스크래치 버퍼 공간을 확장하기 위해
+단일 항목이있는 BPF_MAP_TYPE_PERCPU_ARRAY 맵을 사용할 수 있습니다.
+
+9.BPF 인라인 어셈블리를 사용할 수 있습니다.
+또한 LLVM은 필요할 수있는 드문 경우를 위해 BPF 용 인라인 어셈블리를 사용할 수 있습니다.
+다음 (말도 안되는) toy 예제는 64 비트 atomic 추가를 보여 줍니다.
+문서가 없기 때문에 lib/Target/BPF/BPFInstrInfo.td 및 test/CodeGen/BPF/ 에있는
+LLVM 소스 코드가 몇 가지 추가 예제를 제공하는 데 도움이 될 수 있습니다.
+
+테스트 코드:
+#include <linux/bpf.h>
+
+#ifndef __section
+# define __section(NAME)                  \
+__attribute__((section(NAME), used))
+#endif
+
+__section("prog")
+int xdp_test(struct xdp_md *ctx)
+{
+__u64 a = 2, b = 3, *c = &a;
+/* just a toy xadd example to show the syntax */
+asm volatile("lock *(u64 *)(%0+0) += %1" : "=r"(c) : "r"(b), "0"(c));
+return a;
+}
+
+char __license[] __section("license") = "GPL";
+
+위의 프로그램은 다음과 같은 BPF 명령어 순서로 컴파일 됩니다:
+Verifier analysis:
+
+0: (b7) r1 = 2
+1: (7b) *(u64 *)(r10 -8) = r1
+2: (b7) r1 = 3
+3: (bf) r2 = r10
+4: (07) r2 += -8
+5: (db) lock *(u64 *)(r2 +0) += r1
+6: (79) r0 = *(u64 *)(r10 -8)
+7: (95) exit
+processed 8 insns (limit 131072), stack depth 8
+
+iproute2
+bcc, perf, iproute2 및 기타와 같은 BPF 프로그램을 커널에 로드 하기위한 다양한 프런트 엔드가 있습니다.
+Linux 커널 소스 트리는 tools/lib/bpf/ 디렉토리 아래에 사용자 공간 라이브러리를 제공하는데, 이는 주로
+BPF 추적 프로그램을 커널에 로드하기 위해 perf에 의해 사용됩니다. 그러나 라이브러리 자체는
+범용이며 perf에만 제한되지 않습니다. bcc는 BPF C 코드가 내장 된 Python 인터페이스를 통해
+ad-hoc으로 로드 되는 많은 유용한 BPF 프로그램을 주로 제공하는 툴킷 입니다.
+BPF 프로그램을 구현하기위한 구문 및 의미는 일반적으로 프론트 엔드간에 약간 다릅니다.
+게다가, 생성된 오브젝트 파일을 구문 분석 하고 코드를 시스템 콜 인터페이스에 직접 로드 하는
+BPF 샘플 코드들이 커널 소스 트리 samples/bpf/ 아래에 있습니다. Cilium 프로그램은 주로 BPF 로더에 대해 구현 되므로,
+현재 세션 및 이전 섹션은 주로 XDP, tc 또는 lwt 유형의 네트워킹 프로그램을 로드 하기 위한
+iproute2 제품군의 BPF 프런트 엔드에 중점을 둡니다. 앞으로 Cilium에는 기본 BPF 로더가 갖추어져 있지만,
+개발 및 디버깅을 용이하게 하기 위해 프로그램은 iproute2 제품군을 통해 로드 될 수 있도록 여전히 호환됩니다.
+iproute2가 지원하는 모든 BPF 프로그램 타입은 공통 로더 백엔드를 라이브러리
+(iproute2 소스 트리의 lib/bpf.c)로 구현 하므로 동일한 BPF 로더 로직을 공유 합니다.
+LLVM의 이전 섹션에서는 BPF C 프로그램 작성과 관련된 일부 iproute2 부분을 다루었으며,
+이 문서의 뒷부분은 프로그램 작성시 tc 및 XDP 특정 측면과 관련이 있습니다. 따라서 현재 섹션에서는 로더의 일반
+메커니즘 뿐만 아니라 iproute2로 객체 파일을 로드하는 데 사용 예제에 초점을 맞춥니다.
+모든 세부 사항을 완벽하게 다루지는 않지만 시작하기에 충분합니다.
+
+1. XDP BPF 오브젝트 파일 로드.
+BPF 객체 파일 prog.o가 XDP 용으로 컴파일 된 경우, 다음 명령을 사용하여 em1이라는 XDP 지원 netdevice에
+ip 명령어를 통해 로드 할 수 있습니다:
+# ip link set dev em1 xdp obj prog.o
+
+위의 명령은 프로그램 코드가 XDP의 경우 prog 라고하는 기본 섹션에 있다고 가정합니다.
+이런 경우가 아니고 섹션의 이름이 다르게 지정되면 (예 : foobar) 프로그램을 다음과 같이 로드 해야 합니다:
+
+# ip link set dev em1 xdp obj prog.o sec foobar
+
+네트워크 인터페이스에 XDP 프로그램이 이미 연결되어 있어 실수로 덮어 쓰지 않도록 기본적으로 ip 명령어는
+오류를 발생 시킵니다.
+현재 실행중인 XDP 프로그램을 새 프로그램으로 바꾸려면 -force 옵션을 사용해야합니다:
+
+# ip -force link set dev em1 xdp obj prog.o
+
+오늘날 대부분의 XDP 지원 드라이버는 트래픽 중단 없이 기존 프로그램을 새로운 것으로 대체합니다.
+여기에는 성능상의 이유로 XDP 지원 드라이버에 연결된 단일 프로그램 만 있으므로 프로그램 체인이
+지원되지 않습니다. 그러나 이전 섹션에서 설명한 것처럼 필요한 경우 유사한 사례를 얻기 위해 tail call
+을 통해 프로그램을 나뉠 수 있습니다. 인터페이스에 XDP 프로그램이 연결되어 있으면
+ip link 명령에 xdp 플래그가 표시됩니다. 따라서 "ip link | grep xdp"를 사용하여 XDP가 실행되는
+모든 인터페이스를 찾을 수 있습니다. ip link 덤프에 표시된 BPF 프로그램 ID를 기반으로
+연결된 프로그램에 대한 정보를 검색하는 데 ip -d 링크가있는 자세히 보기를 통해
+추가 자가 검사 기능이 제공 되며 bpftool을 사용하여 이 정보를 검색 할 수 있습니다.
+
+인터페이스에서 기존 XDP 프로그램을 제거하려면 다음 명령을 실행해야합니다:
+# ip link set dev em1 xdp off
+
+드라이버의 동작 방식을 non-XDP에서 네이티브 XDP로 또는 그 반대로 전환하는 경우,
+일반적으로 드라이버는 수신 된 패킷이 BPF가 읽고 쓸 수있는 단일 페이지 내에서 선형적으로
+설정되도록 수신(및 전송) 링을 재구성해야합니다.
+그러나, 일단 완료되면, 대부분의 드라이버는 BPF 프로그램을 스왑 하도록 요청할 때
+프로그램 자체의 atomic 교체를 수행하면 됩니다.
+
+전체적으로 XDP는 iproute2가 구현하는 세 가지 작동 방식을 지원 합니다 : xdpdrv, xdpoffload, xdpgeneric.
+xdpdrv는 네이티브 XDP를 의미하며,  즉, BPF 프로그램은 소프트웨어의 가능한 가장 빠른 시점에
+드라이버의 수신 경로에서 직접 실행됩니다.이것은 일반/일반 XDP 방식이며, XDP 지원을 구현 하는 데 드라이버가 필요하며,
+업스트림 리눅스 커널의 모든 주요 10G/40G/+ 네트워킹 드라이버가 이미 제공합니다.
+
+xdpgeneric은 일반 XDP를 나타내며 아직 네이티브 XDP를 지원하지 않는 드라이버를 위한 실험용 테스트 베드로 사용됩니다.
+진입 경로의 일반적인 XDP hook이 패킷이 이미 스택의 메인 수신 경로인 skb로 들어 가는 훨씬 늦은 시점에 제공되며,
+xdpdrv 방식에서 처리하는 것보다 성능이 훨씬 낮습니다.그러므로 xdpgeneric은 대부분 실험적인 측면에서만 흥미롭고
+실제 운영 환경 에서는 적습니다.
+
+마지막으로, xdpoffload 모드는 Netronome의 nfp 드라이버가 지원하는 SmartNIC에서 구현되며 전체 BPF/XDP 프로그램을
+하드웨어로 오프로드 할 수 있으므로 프로그램은 카드의 각 패킷 수신시 직접 실행됩니다.네이티브 XDP 와 비교하여 모든 BPF map 유형
+또는 BPF helper 함수를 사용할 수 있는 것은 아니지만 네이티브 XDP에서 실행하는 것보다 훨씬 높은 성능을 제공합니다.
+이 경우 BPF verifier는 프로그램을 거부하고 그리고 지원되지 않는 것을 사용자에게 보고합니다.
+지원되는 BPF 기능 및 도우미 기능의 영역에 머무르는 것 외에 BPF C 프로그램을 작성할 때는 특별한 주의를 기울이 지 않아도됩니다
+
+ip link set dev em1 xdp obj [...] 와 같은 명령이 사용되면 커널은 먼저 프로그램을 기본 XDP로 로드 하려고 시도하고
+그리고 드라이버가 네이티브 XDP를 지원하지 않으면 자동으로 일반 XDP로 되돌아갑니다.따라서 예를 들어 xdp 대신 명시적으로 xdpdrv를
+사용하면 커널은 프로그램을 raw XDP로 로드 하려고 시도하고 드라이버가 지원하지 않는 경우 실패 하여 일반 XDP가 모두 회피 되는 보장을 제공 합니다.
+
+네이티브 XDP 방식에서 로드 할 BPF/XDP 프로그램 실행, 링크 세부 정보 덤프 및 프로그램 언로드 예:
+
+# ip -force link set dev em1 xdpdrv obj prog.o
+# ip link show
+[...]
+6: em1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 xdp qdisc mq state UP mode DORMANT group default qlen 1000
+link/ether be:08:4d:b6:85:65 brd ff:ff:ff:ff:ff:ff
+prog/xdp id 1 tag 57cd311f2e27366b
+[...]
+# ip link set dev em1 xdpdrv off
+
+드라이버가 기본 XDP를 지원하고 bpftool을 통해 삽입된 더미 프로그램의 BPF 명령어를 추가로 덤프하는 경우에도 일반
+XDP를 강제 실행하는 것과 같은 예제가 있습니다:
+
+# ip -force link set dev em1 xdpgeneric obj prog.o
+# ip link show
+[...]
+6: em1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 xdpgeneric qdisc mq state UP mode DORMANT group default qlen 1000
+link/ether be:08:4d:b6:85:65 brd ff:ff:ff:ff:ff:ff
+prog/xdp id 4 tag 57cd311f2e27366b                <-- BPF 프로그램 ID 4
+[...]
+# bpftool prog dump xlated id 4                       <-- em1에서 실행중인 명령어 덤프
+0: (b7) r0 = 1
+1: (95) exit
+# ip link set dev em1 xdpgeneric off
+
+마지막이긴 하나 중요한 오프로드 된 XDP는 일반 메타 데이터 검색을 위해 bpftool을 통해 프로그램 정보를 추가로 덤프합니다:
+
+# ip -force link set dev em1 xdpoffload obj prog.o
+# ip link show
+[...]
+6: em1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 xdpoffload qdisc mq state UP mode DORMANT group default qlen 1000
+link/ether be:08:4d:b6:85:65 brd ff:ff:ff:ff:ff:ff
+prog/xdp id 8 tag 57cd311f2e27366b
+[...]
+# bpftool prog show id 8
+8: xdp  tag 57cd311f2e27366b dev em1                  <-- 또한 em1에 오프로드 된 BPF 프로그램을 나타냅니다.
+loaded_at Apr 11/20:38  uid 0
+xlated 16B  not jited  memlock 4096B
+# ip link set dev em1 xdpoffload off
+
+xdpdrv와 xdpgeneric 또는 다른 방식를 동시에 사용할 수는 없으며, 이는 XDP 동작 방식 중 하나만 선택해야 함을 의미합니다.
+다른 XDP 모드 간의 전환은 예를 들어 generic에서 native로 또는 그 반대로도 atomically으로 가능하지 않습니다:
+
+# ip -force link set dev em1 xdpgeneric obj prog.o
+# ip -force link set dev em1 xdpoffload obj prog.o
+RTNETLINK answers: File exists
+# ip -force link set dev em1 xdpdrv obj prog.o
+RTNETLINK answers: File exists
+# ip -force link set dev em1 xdpgeneric obj prog.o    <-- xdpgeneric로 인해 성공.
+#
+
+방식을 전환하려면 먼저 현재 작동 모드를 종료 한 후 새로운 방식으로 전환해야합니다:
+# ip -force link set dev em1 xdpgeneric obj prog.o
+# ip -force link set dev em1 xdpgeneric off
+# ip -force link set dev em1 xdpoffload obj prog.o
+# ip l
+[...]
+6: em1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 xdpoffload qdisc mq state UP mode DORMANT group default qlen 1000
+link/ether be:08:4d:b6:85:65 brd ff:ff:ff:ff:ff:ff
+prog/xdp id 17 tag 57cd311f2e27366b
+[...]
+# ip -force link set dev em1 xdpoffload off
+
+2. tc BPF 오브젝트 파일의 로딩.
+prog.o가 tc 용으로 컴파일 된 BPF 오브젝트 파일이 고려될때, tc 명령을 통해 netdevice에 로드 할 수 있습니다.
+XDP와 달리 장치에 BPF 프로그램을 연결하는 데 필요한 드라이버 의존성이 없습니다.
+여기서 netdevice는 em1이라고하며 다음 명령을 사용하여 프로그램을 em1의 네트워킹 ingress 경로에 연결할 수 있습니다:
+
+# tc qdisc add dev em1 clsact
+# tc filter add dev em1 ingress bpf da obj prog.o
+
+첫 번째 단계는 clsact qdisc (리눅스 대기 행렬의 규칙)를 설정하는 것입니다.
+clsact는 ingress qdisc와 비슷한 더미 qdisc이며, classifier 및 action 만 보유 할 수 있지만
+실제 대기열을 작동 하지는 않습니다. bpf verifier를 연결하기 위해 필요합니다. clsact qdisc는
+ingress 및 egress 라고 하는 두 개의  특수 hook를 제공 하며, 이 hook는 classifier를 연결할 수 있습니다.
+ingress 및 egress hook은 장치의 모든 패킷이 통과하는 네트워킹 데이터 경로의 중심 수신 및 전송 위치에 있습니다.
+
+ingress hook은 커널의 함수의 __netif_receive_skb_core () -> sch_handle_ingress () 호출되며,
+egress hook은 __dev_queue_xmit () -> sch_handle_egress () 에서 호출됩니다.
+
+net/core/dev.c(ingress hook 커널 함수 호출 흐름이며, 4.17.0-rc7 기반에서 확인한 내용입니다.)
+...
+static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc)
+{
+...
+if (pfmemalloc)
+goto skip_taps;
+...
+skip_taps:
+#ifdef CONFIG_NET_INGRESS
+if (static_branch_unlikely(&ingress_needed_key)) {
+skb = sch_handle_ingress(skb, &pt_prev, &ret, orig_dev);
+if (!skb)
+goto out;
+
+if (nf_ingress(skb, &pt_prev, &ret, orig_dev) < 0)
+goto out;
+}
+#endif
+....
+}
+
+static inline struct sk_buff *
+sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret,
+struct net_device *orig_dev)
+{
+....
+switch (tcf_classify(skb, miniq->filter_list, &cl_res, false)) {
+case TC_ACT_OK:
+case TC_ACT_RECLASSIFY:
+skb->tc_index = TC_H_MIN(cl_res.classid);
+break;
+case TC_ACT_SHOT:
+mini_qdisc_qstats_cpu_drop(miniq);
+kfree_skb(skb);
+return NULL;
+case TC_ACT_STOLEN:
+case TC_ACT_QUEUED:
+case TC_ACT_TRAP:
+consume_skb(skb);
+return NULL;
+case TC_ACT_REDIRECT:
+/* skb_mac_header check was done by cls/act_bpf, so
+* we can safely push the L2 header back before
+* redirecting to another netdev
+*/
+__skb_push(skb, skb->mac_len);
+skb_do_redirect(skb);
+return NULL;
+default:
+break;
+}
+....
+}
+
+net/core/dev.c(egress hook 커널 함수 호출 흐름이며, 4.17.0-rc7 기반에서 확인한 내용입니다.)
+static int __dev_queue_xmit(struct sk_buff *skb, void *accel_priv)
+{
+...
+# ifdef CONFIG_NET_EGRESS
+if (static_branch_unlikely(&egress_needed_key)) {
+skb = sch_handle_egress(skb, &rc, dev);
+if (!skb)
+goto out;
+}
+...
+}
+
+...
+
+static struct sk_buff *
+sch_handle_egress(struct sk_buff *skb, int *ret, struct net_device *dev)
+{
+...
+switch (tcf_classify(skb, miniq->filter_list, &cl_res, false)) {
+case TC_ACT_OK:
+case TC_ACT_RECLASSIFY:
+skb->tc_index = TC_H_MIN(cl_res.classid);
+break;
+case TC_ACT_SHOT:
+mini_qdisc_qstats_cpu_drop(miniq);
+*ret = NET_XMIT_DROP;
+kfree_skb(skb);
+return NULL;
+case TC_ACT_STOLEN:
+case TC_ACT_QUEUED:
+case TC_ACT_TRAP:
+*ret = NET_XMIT_SUCCESS;
+consume_skb(skb);
+return NULL;
+case TC_ACT_REDIRECT:
+/* No need to push/pop skb's mac_header here on egress! */
+skb_do_redirect(skb);
+*ret = NET_XMIT_SUCCESS;
+return NULL;
+default:
+break;
+}
+
+egress hook에 프로그램을 연결하는 것에 해당하는 것은 다음과 같습니다 :
+# tc filter add dev em1 egress bpf da obj prog.o
+
+clsact qdisc는 ingress 및 egress 방향에서 lockless로 처리 되며, 컨테이너를 연결하는 veth 장치와 같은 가상,
+대기열없는 장치 에도 연결할 수 있습니다. hook 다음에, tc filter 명령은 da(직접 실행, direct-action mode)
+방식에서 사용 할 bpf를 선택합니다. da mode가 권장이 되며 그리고 항상 명시 해야 합니다.
+그것은 기본적으로 모든 작업 패킷 mangling, forwarding 또는 다른 종류의 이미 있는 하나의
+BPF 프로그램 내부에서 수행 할 수 있기 때문에 BPF 분류는,어쨌든 BPF 필요하지 않은 외부 TC 액션 모듈로 호출 할 필요가
+없음을 의미 따라서 연결이 상당히 빨라집니다.
+
+기본적으로 bpf classifier는 모든 패킷 mangling 및 포워딩 또는 다른 동작이 이미
+single bpf 프로그램 내부에서 수행 될 수 있기 때문에 외부 tc action 모듈을 호출 할 필요가 없다는 것을 의미
+하며, 연결이 될때 상당히 빨라 집니다. 이 시점에서 프로그램이 연결되어 패킷이 장치를 통과하면 프로그램이 실행됩니다.
+XDP처럼, 기본 섹션 이름을 사용하지 않으면 로드 중에 foobar 섹션과 같이 지정할 수 있습니다:
+# tc filter add dev em1 egress bpf da obj prog.o sec foobar
+
+iproute2의 BPF 로더는 프로그램 타입에 따라 동일한 명령 행 구문을 사용할 수 있으므로 obj prog.o sec foobar는
+앞에서 언급 한 XDP와 같은 구문입니다. 연결 된 프로그램은 다음 명령을 통해 나열 될 수 있습니다:
+
+# tc filter show dev em1 ingress
+filter protocol all pref 49152 bpf
+filter protocol all pref 49152 bpf handle 0x1 prog.o:[ingress] direct-action id 1 tag c5f7825e5dac396f
+
+# tc filter show dev em1 egress
+filter protocol all pref 49152 bpf
+filter protocol all pref 49152 bpf handle 0x1 prog.o:[egress] direct-action id 2 tag b2fd5adc0f262714
+
+prog.o : [ingress] 의 출력은 프로그램 섹션 ingress가 prog.o 파일에서 로드 되었으며,
+bpf가 직접-실행(direct-action mode) 방식에서 동작 하는 것을 나타냅니다.프로그램 id 및 tag 는 각각 값이며, 마지막 명령어 스트림에 대한
+hash 나타내며, 오브젝트 파일 혹은 stack trace가 있는 perf reports 등과 같은 관련을 될수 있습니다. 마지막이긴 하나 중요한 id는
+bpftool과 함께 사용하여 첨부 된 BPF 프로그램을 추가로 검사하거나 덤프 할 수있는 시스템 전체의 고유 한 BPF 프로그램 식별자를 나타냅니다.
+
+tc는 단 하나의 BPF 프로그램 이상을 연결 할 수 있으며, tc는 함께 chained 할 수 있는 다양한 다른
+classifier들을 제공합니다.하지만, BPF 프로그램 자체가 이미 TC_ACT_OK, TC_ACT_SHOT 및 기타와
+같은 tc 작업 결정을 반환한다는 것을 의미하는 da(직접-실행, direct-action)방식 덕분에
+모든 패킷 조작이 프로그램 자체에 포함될 수 있기 때문에 단일 BPF 프로그램을 연결 만으로 충분합니다.
+최적의 성능과 유연성을 위해 권장되는 사용법 입니다.
+
+위의 show 명령에서 tc는 BPF 관련 출력 옆에 pref 49152 및 handle 0x1도 표시합니다.
+둘 다 명령 줄을 통해 명시적으로 제공되지 않는 경우 자동 생성됩니다.
+pref는 우선 순위 번호를 나타내며, 이는 다중 classifier들이 연결 된 경우 오름차순 우선 순위에 따라 실행되는 것을 의미하며,
+handle은 같은 classifier의 다중 인스턴스가 동일한 pref 아래 로드 된 경우 식별자를 나타냅니다.
+BPF의 경우 하나의 프로그램으로 충분하기 때문에 일반적으로 pref와 handle을 무시할 수 있습니다.
+연결된 BPF 프로그램들을 atomically하게 교체할 계획이 있는 경우 에만, 초기 로드시 연역적으로
+pref 및 handle을 명시적으로 지정하는 것을 추천하며, 따라서 나중에 교체 작업을 위해 따로 쿼리할 필요는 없습니다.
+따라서 창작물은 다음과 같이 됩니다:
+
+# tc filter add dev em1 ingress pref 1 handle 1 bpf da obj prog.o sec foobar
+
+# tc filter show dev em1 ingress
+filter protocol all pref 1 bpf
+filter protocol all pref 1 bpf handle 0x1 prog.o:[foobar] direct-action id 1 tag c5f7825e5dac396f
+
+그리고 atomic 교체을 위해 foobar 섹션의 prog.o 파일에서 새로운 BPF 프로그램으로 ingress hook에서
+기존 프로그램을 업데이트하기 위해 다음을 발행 할 수 있습니다:
+# tc filter replace dev em1 ingress pref 1 handle 1 bpf da obj prog.o sec foobar
+
+마지막으로 중요한 것은 첨부 된 각 프로그램을 ingress 및 egress hook에서 모두 제거하려면 다음을 사용할 수 있습니다:
+# tc filter del dev em1 ingress
+# tc filter del dev em1 egress
+
+netdevice에서 clsact qdisc 전체 즉 암시적으로 ingress 및 egress hook에 모든 연결된 프로그램을
+제거하려면 다음과 같은 명령이 제공 됩니다 :
+# tc qdisc del dev em1 clsact
+
+tc BPF 프로그램은 만약 NIC 및 드라이버가 XDP BPF 프로그램과 유사하게 지원 되는 경우 오프로드 할 수 있습니다.
+Netronome의 nfp 지원 NIC는 두 가지 유형의 BPF 오프로드를 제공합니다.
+# tc qdisc add dev em1 clsact
+# tc filter replace dev em1 ingress pref 1 handle 1 bpf skip_sw da obj prog.o
+Error: TC offload is disabled on net device.
+We have an error talking to the kernel
+
+위의 오류가 표시되면 ethtool의 hw-tc-offload 설정을 통해 장치의 tc 하드웨어 오프로드를 먼저 활성화 해야 합니다.
+# ethtool -K em1 hw-tc-offload on
+# tc qdisc add dev em1 clsact
+# tc filter replace dev em1 ingress pref 1 handle 1 bpf skip_sw da obj prog.o
+# tc filter show dev em1 ingress
+filter protocol all pref 1 bpf
+filter protocol all pref 1 bpf handle 0x1 prog.o:[classifier] direct-action skip_sw in_hw id 19 tag 57cd311f2e27366b
+
+in_hw 플래그는 프로그램이 NIC로 오프로드 되었음을 확인합니다.
+tc와 XDP의 BPF 오프로드를 동시에 로드 할 수 없으므로 tc 또는 XDP 오프로드 옵션을 선택해야합니다.
+
+3. netdevsim 드라이버를 통해 BPF 오프로드 인터페이스를 테스트합니다.
+Linux 커널의 일부인 netdevsim 드라이버는 XDP BPF 및 tc BPF 프로그램 용 오프로드 인터페이스를
+구현하는 더미 드라이버를 제공하며 커널의 UAPI에 대해 직접 control plane을 구현하는 커널 변경 또는
+low-level 사용자 공간 프로그램 테스트를 가능 하게합니다.
+
+netdevsim 장치는 다음과 같이 생성 될 수 있습니다 :
+# ip link add dev sim0 type netdevsim
+# ip link set dev sim0 up
+# ethtool -K sim0 hw-tc-offload on
+# ip l
+[...]
+7: sim0: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
+link/ether a2:24:4c:1c:c2:b3 brd ff:ff:ff:ff:ff:ff
+
+** 역자주 : 커널 컴파일시 , 만약 hw 오프로드 관련 테스트 하고자 한다면, 아래 옵션에 대해서 활성화를 해야 합니다.
+미 활성화 인 경우, 인터페이스는 생성되지 않습니다.
+CONFIG_NETDEVSIM:
+│
+│ This driver is a developer testing tool and software model that can
+│ be used to test various control path networking APIs, especially
+│ HW-offload related.
+│
+│ To compile this driver as a module, choose M here: the module
+│ will be called netdevsim.
+│
+│ Symbol: NETDEVSIM [=n]
+│ Type  : tristate
+│ Prompt: Simulated networking device
+│   Location:
+│     -> Device Drivers
+│       -> Network device support (NETDEVICES [=y])
+│   Defined at drivers/net/Kconfig:502
+│   Depends on: NETDEVICES [=y] && DEBUG_FS [=y] && MAY_USE_DEVLINK [=y]
+
+
+이 단계가 끝난 후 XDP BPF 또는 tc BPF 프로그램은 앞서 다양한 예제에 표시된대로 로드 할 수 있습니다.
+# ip -force link set dev sim0 xdpoffload obj prog.o
+# ip l
+[...]
+7: sim0: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 xdpoffload qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
+link/ether a2:24:4c:1c:c2:b3 brd ff:ff:ff:ff:ff:ff
+prog/xdp id 20 tag 57cd311f2e27366b
+
+.....
+
+이 두 워크 플로는 iproute2를 사용하여 XDP BPF 및 tc BPF 프로그램을 로드하는 기본 작업입니다.
+BPF 로더에는 XDP와 tc에 모두 적용되는 여러 가지 고급 옵션이 있으며 그 중 일부는 여기에 나열되어 있습니다.
+예제에서 XDP는 단순화를 위해 제시된 것입니다.
+
+1. 성공시에도 자세한 로그 출력.
+오류가 발생하지 않은 경우에도 Verifier 로그를 덤프하기 위해 verb 옵션을 추가하여 프로그램을 로드 할 수 있습니다.
+
+# ip link set dev em1 xdp obj xdp-example.o verb
+
+Prog section 'prog' loaded (5)!
+- Type:         6
+- Instructions: 2 (0 over limit)
+- License:      GPL
+
+Verifier analysis:
+
+0: (b7) r0 = 1
+1: (95) exit
+processed 2 insns
+
+2. BPF 파일 시스템에 이미 고정되어 있는 프로그램을 로드 하십시오.
+
+오브젝트 파일에서 프로그램을 로드하는 대신에, iproute2는 BPF 파일 시스템에서 프로그램을 검색 할 수 있으며, 외부 엔티티가 거기에
+고정시키고 장치에 연결하는 경우입니다:
+# ip link set dev em1 xdp pinned /sys/fs/bpf/prog
+
+iproute2는 감지 된 BPF 파일 시스템의 마운트 지점과 관련된 짧은 형식을 사용할 수도 있습니다:
+# ip link set dev em1 xdp pinned m:prog
+
+BPF 프로그램을 로드 할 때, iproute2는 노드의 고정을 수행하기 위해 마운트 된 파일 시스템 인스턴스를 자동으로 감지합니다.
+마운트 된 BPF 파일 시스템 인스턴스가 없는 경우, tc는 이를 자동으로 /sys/fs/bpf/ 아래의 기본 위치에 마운트 합니다.
+
+인스턴스가 이미 발견 된 경우, 인스턴스가 사용되며 추가 마운트가 수행되지 않습니다.
+# mkdir /var/run/bpf
+# mount --bind /var/run/bpf /var/run/bpf
+# mount -t bpf bpf /var/run/bpf
+# tc filter add dev em1 ingress bpf da obj tc-example.o sec prog
+# tree /var/run/bpf
+/var/run/bpf
++-- ip -> /run/bpf/tc/
++-- tc
+|   +-- globals
+|       +-- jmp_map
++-- xdp -> /run/bpf/tc/
+
+4 directories, 1 file
+
+기본적으로 tc는 위와 같이 모든 서브 시스템 사용자는 전역 이름 공간에 대한 기호 링크를 통해 동일한 위치를 가리키는 초기 디렉토리 구조를 생성하며,
+고정 된 BPF 맵을 iproute2의 다양한 BPF 프로그램 유형간에 재사용 할 수 있습니다.
+파일 시스템 인스턴스가 이미 마운트 되었고 기존 구조가 이미 존재하는 경우, tc는 파일 시스템 인스턴스를 오버라이드 하지 않습니다.
+
+이는 전역 파일을 공유하지 않기 위해 lwt, tc 및 xdp map을 분리하는 경우가 발생 할 수 있습니다.
+이전 LLVM 섹션에서 간단히 설명 했듯이, iproute2는 설치 시 BPF 프로그램에 의해 표준 include 경로를 통해 포함될 수있는 헤더 파일을 설치합니다.
+#include <iproute2/bpf_elf.h>
+
+이 헤더 파일의 목적은 프로그램에 사용되는 map과 기본 섹션 이름에 대한 API를 제공하는 것입니다. 그것은 iproute2와 BPF 프로그램 사이의 안정적인 계약입니다.
+iproute2에 대한 map 정의는 bpf_elf_map 구조체 입니다. 그것의 구성은 이 문서의 LLVM 부분에서 더 일찍 다루어졌습니다.
+BPF 객체 파일을 구문 분석 할 때 iproute2 로더는 모든 ELF 섹션을 처리합니다. 처음에는 map 및 라이센스 와 같은 보조 섹션을 가져옵니다.
+map의 경우 struct bpf_elf_map 배열의 유효성을 검사하고 필요할 때마다 호환성 우회 방법이 수행 됩니다.
+결과적으로 모든 map은 사용자가 제공 한 정보로 생성되며, 고정 된 객체로 검색되거나 새로 생성 된 다음 BPF 파일 시스템에 고정됩니다.
+다음으로 로더는 map에 대한 ELF 재배치 엔트리가 포함된 프로그램 세션을 처리 하며, 이 의미는 map 파일 디스크립터를 레지스터리에
+로드하는 BPF 명령어로 다시 작성되어, 해당 map 파일 디스크립터가 immediate 값으로 인코딩이 되고, 이는 커널이 나중에 커널 포인터로
+변환 할 수 있도록 하기 위해서 입니다. 이후 모든 프로그램 자체가 BPF 시스템 호출을 통해 생성되고 tail 호출된 map이 있는 경우,
+이 프로그램의 파일 디스크립터로 업데이트 됩니다.
+
+bpftool
+bpftool은 BPF 주변의 주요 자가 검사 및 디버깅 도구이며 tools/bpf/bpftool/ 아래의 Linux 커널 트리와 함께 개발 및 제공됩니다.
+이 도구는 현재 시스템에 로드 된 모든 BPF 프로그램과 맵을 덤프하거나, 특정 프로그램에서 사용하는 모든 BPF 맵을 나열하고 연관시킬 수 있습니다.
+
+또한 전체 맵의 키/값 쌍을 덤프하거나 개별 맵을 조회, 업데이트, 삭제할 수있을 뿐만 아니라 맵에서 키의 인접 키를 검색 할 수 있습니다.
+이러한 작업은 BPF 프로그램 또는 맵 ID를 기반으로 수행하거나, BPF 파일 시스템 고정 프로그램 또는 맵의 위치를 지정하여 수행 할 수 있습니다.
+또한 이 도구는 map을 고정하는 옵션 또는 프로그램을 BPF 파일 시스템에 제공합니다.
+
+현재 호스트에 로드 된 모든 BPF 프로그램의 개요 내용을 확인하려면 다음 명령을 호출하십시오:
+# bpftool prog
+398: sched_cls  tag 56207908be8ad877
+loaded_at Apr 09/16:24  uid 0
+xlated 8800B  jited 6184B  memlock 12288B  map_ids 18,5,17,14
+399: sched_cls  tag abc95fb4835a6ec9
+loaded_at Apr 09/16:24  uid 0
+xlated 344B  jited 223B  memlock 4096B  map_ids 18
+400: sched_cls  tag afd2e542b30ff3ec
+loaded_at Apr 09/16:24  uid 0
+xlated 1720B  jited 1001B  memlock 4096B  map_ids 17
+401: sched_cls  tag 2dbbd74ee5d51cc8
+loaded_at Apr 09/16:24  uid 0
+xlated 3728B  jited 2099B  memlock 4096B  map_ids 17
+[...]
+
+마찬가지로 모든 활성 map의 개요를 보려면 다음을 수행하십시오:
+# bpftool map
+5: hash  flags 0x0
+key 20B  value 112B  max_entries 65535  memlock 13111296B
+6: hash  flags 0x0
+key 20B  value 20B  max_entries 65536  memlock 7344128B
+7: hash  flags 0x0
+key 10B  value 16B  max_entries 8192  memlock 790528B
+8: hash  flags 0x0
+key 22B  value 28B  max_entries 8192  memlock 987136B
+9: hash  flags 0x0
+key 20B  value 8B  max_entries 512000  memlock 49352704B
+[...]
+
+각 명령에 대해 bpftool은 명령 줄 끝에 --json을 추가하여 json 기반 출력을 지원합니다. 추가적인 --pretty 는
+사람이 읽을 수 있는 출력을 향상 시킵니다.
+# bpftool prog --json --pretty
+
+특정 BPF 프로그램의 verifier 후 BPF 명령어 이미지를 덤프 하는 경우, 예를 들어 tc ingress hook에 연결된 특정 프로그램을 검사 할 수 있습니다.
+# tc filter show dev cilium_host egress
+filter protocol all pref 1 bpf chain 0
+filter protocol all pref 1 bpf chain 0 handle 0x1 bpf_host.o:[from-netdev] \
+direct-action not_in_hw id 406 tag e0362f5bd9163a0a jited
+
+객체 파일 bpf_host.o 프로그램은 from-netdev 섹션에서 id 406에 표시 된대로, 프로그램 ID 406을 가지고 있습니다.
+이 정보를 바탕으로 bpftool은 프로그램과 관련된 몇 가지 상위 레벨 메타 데이터를 제공 할 수 있습니다:
+
+# bpftool prog show id 406
+406: sched_cls  tag e0362f5bd9163a0a
+loaded_at Apr 09/16:24  uid 0
+xlated 11144B  jited 7721B  memlock 12288B  map_ids 18,20,8,5,6,14
+
+ID 406의 프로그램은 sched_cls(BPF_PROG_TYPE_SCHED_CLS) 타입이며, e0362f5bd9163a0a(명령 시퀀스에 대한 sha 합계)
+tag를 가지고 있으며, Apr 09/16:24 에 root uid 0에 의해 로드 되었습니다. BPF 명령 시퀀스는 11,144 바이트 이며, 주입된 이미지는 7,721 바이트입니다.
+프로그램 자체 (map 제외)는 사용자 uid 0에 대해 계산된/소비된 accounted/charged 12,288 바이트를 사용합니다.
+그리고 BPF 프로그램은 ID가 18, 20, 8, 5, 6 및 14 인 BPF 맵을 사용 합니다. 이후의 ID는 정보를 얻거나 맵을 덤프 하는 데 더 사용될 수 있습니다.
+또한 bpftool은 프로그램이 실행하는 BPF 명령의 덤프 요청을 실행 할 수 있습니다.
+# bpftool prog dump xlated id 406
+0: (b7) r7 = 0
+1: (63) *(u32 *)(r1 +60) = r7
+2: (63) *(u32 *)(r1 +56) = r7
+3: (63) *(u32 *)(r1 +52) = r7
+[...]
+47: (bf) r4 = r10
+48: (07) r4 += -40
+49: (79) r6 = *(u64 *)(r10 -104)
+50: (bf) r1 = r6
+51: (18) r2 = map[id:18]                    <-- BPF map id 18
+53: (b7) r5 = 32
+54: (85) call bpf_skb_event_output#5656112  <-- BPF helper 호출
+55: (69) r1 = *(u16 *)(r6 +192)
+[...]
+
+bpftool은 BPF helper 또는 다른 BPF 프로그램에 대한 호출 뿐만 아니라 위의 그림과 같이 BPF map ID를 명령 스트림에 상관 관계가 있습니다.
+명령 덤프는 커널의 BPF verifier와 동일한 'pretty-printer'를 다시 사용 합니다.
+위의 xlated 명령에서 생성된 프로그램이 주입 되어 실제 JIT 이미지가 실행 되므로 bpftool을 통해서 덤프 될 수 있습니다.
+
+# bpftool prog dump jited id 406
+0:        push   %rbp
+1:        mov    %rsp,%rbp
+4:        sub    $0x228,%rsp
+b:        sub    $0x28,%rbp
+f:        mov    %rbx,0x0(%rbp)
+13:        mov    %r13,0x8(%rbp)
+17:        mov    %r14,0x10(%rbp)
+1b:        mov    %r15,0x18(%rbp)
+1f:        xor    %eax,%eax
+21:        mov    %rax,0x20(%rbp)
+25:        mov    0x80(%rdi),%r9d
+[...]
+
+BPF JIT 개발자를 중심으로, 실제 네이티브 opcode로 디스 어셈블리를 interleave하는 옵션도 있습니다:
+# bpftool prog dump jited id 406 opcodes
+0:        push   %rbp
+55
+1:        mov    %rsp,%rbp
+48 89 e5
+4:        sub    $0x228,%rsp
+48 81 ec 28 02 00 00
+b:        sub    $0x28,%rbp
+48 83 ed 28
+f:        mov    %rbx,0x0(%rbp)
+48 89 5d 00
+13:        mov    %r13,0x8(%rbp)
+4c 89 6d 08
+17:        mov    %r14,0x10(%rbp)
+4c 89 75 10
+1b:        mov    %r15,0x18(%rbp)
+4c 89 7d 18
+[...]
+
+커널에서 디버깅 할 때 유용 할 수있는 일반적인 BPF 명령어에 대해 동일한 interleave을 수행 할 수 있습니다:
+# bpftool prog dump xlated id 406 opcodes
+0: (b7) r7 = 0
+b7 07 00 00 00 00 00 00
+1: (63) *(u32 *)(r1 +60) = r7
+63 71 3c 00 00 00 00 00
+2: (63) *(u32 *)(r1 +56) = r7
+63 71 38 00 00 00 00 00
+3: (63) *(u32 *)(r1 +52) = r7
+63 71 34 00 00 00 00 00
+4: (63) *(u32 *)(r1 +48) = r7
+63 71 30 00 00 00 00 00
+5: (63) *(u32 *)(r1 +64) = r7
+63 71 40 00 00 00 00 00
+[...]
+
+graphviz의 도움을 받아 프로그램의 기본 블록을 시각화 할 수도 있습니다.
+이 목적을 위해 bpftool은 나중에 png 파일로 변환 할 수 있는 일반 BPF xlated  명령 덤프 대신 도트 파일을 생성하는
+시각적 덤프 모드를 가지고 있습니다:
+
+# bpftool prog dump xlated id 406 visual &> output.dot
+$ dot -Tpng output.dot -o output.png
+
+또 다른 옵션은 dot 파일을 뷰어인 dotty로 전달 하는 것이며, 즉 dotty output.dot 하는 경우 ,
+bpg_host.o 프로그램의 결과는 다음과 같습니다(작은 발췌). xlated 명령어 덤프는 만약 BPF 인터프리터를 통해
+실행될 경우와 같은 명령어를 덤프한다는 의미의 verifier후 BPF 명령어 이미지를 제공합니다.
+커널에서 verifier는 BPF 로더가 제공 한 본래 명령어의 다양한 다시 쓰기을 수행합니다.
+
+다시 쓰기의 한가지 예는 런타임 성능을 향상 시키기 위해, helper 함수의 인라이닝(inline) 이며,
+여기 hash 테이블에 대한 map 조회 경우 입니다:
+# bpftool prog dump xlated id 3
+0: (b7) r1 = 2
+1: (63) *(u32 *)(r10 -4) = r1
+2: (bf) r2 = r10
+3: (07) r2 += -4
+4: (18) r1 = map[id:2]                      <-- BPF map id 2
+6: (85) call __htab_map_lookup_elem#77408   <-+ BPF helper inlined rewrite
+7: (15) if r0 == 0x0 goto pc+2                |
+8: (07) r0 += 56                              |
+9: (79) r0 = *(u64 *)(r0 +0)                <-+
+10: (15) if r0 == 0x0 goto pc+24
+11: (bf) r2 = r10
+12: (07) r2 += -4
+[...]
+
+bpftool은 모듈이 참조할 수 있는 커널 내부의 함수나 변수의 심볼 정보인 kallsyms를 통해, helper 함수
+또는 BPF 호출에서 BPF 호출에 연결 합니다. 따라서 주입되어 BPF 프로그램이 kallsyms(bpf_jit_kallsyms 파라메터를 통해)에
+노출 되어 있고, kallsyms주소가 난독화되지 않는지 확인하십시오 호출은 call bpf_unspec#0 로 표시됩니다):
+
+# echo 0 > /proc/sys/kernel/kptr_restrict
+(역자주 : kptr_restrict 파라메터 설명
+이 토글은 /proc 및 다른 인터페이스를 통해 커널 주소를 노출하는 데 제한이 있는지 여부를 나타냅니다.
+kptr_restrict가 0(기본값)으로 설정되면 출력하기 전에 주소가 hash됩니다. (이것은 % p와 동일합니다.)
+kptr_restrict를 (1)로 설정하면 커널 포인터는 %pK를 사용하여 사용자가
+CAP_SYSLOG 권한을 가지고 있지 않으면 형식 지정자는 "0" 으로 바뀝니다. 유효 사용자 및 그룹 ID는 실제 ID와 같습니다.
+이것은 %pK 확인은 open() 시간 보다는 read () 시간에 완료 되었기 때문 이며, 따라서 open()과 read() 사이에서 권한이
+상승하면(예 :setuid 바이너리) 그런 다음 %pK는 권한이 없는 사용자에게 커널 포인터를 누설하지 않습니다
+이것은 일시적인 해결책 일뿐입니다. 올바른 장기적인 해결책은 open() 시간에 권한 검사를 수행하는 것입니다.
+권한이없는 사용자에 대한 커널 포인터 누설 값이 문제가되는 경우 dmesg_restrict를 사용하여
+dmesg(8)에서 %pK 사용을 방지하려면 %pK를 사용하는 파일에서 전역 읽기 사용 권한을 제거하는 것이 좋습니다.
+kptr_restrict가 (2)로 설정되면 %pK를 사용하여 출력된 커널 포인터는 권한에 관계없이 "0"으로 바뀝니다.
+)
+
+# echo 1 > /proc/sys/net/core/bpf_jit_kallsyms
+(역자주 : bpf_jit_kallsyms 파라메터 설명
+bpf: make jited programs visible in traces commit 메세지 참조
+https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=74451e66d516c55e3
+
+Berkeley Packet Filter Just in Time 컴파일러가 활성화 되면 컴파일된 이미지는 커널에 알려지지 않는 주소이며,
+이것은 추적 이나 /proc/kallsyms에 나타나지 않는 것을 의미 합니다.
+
+이것을 활성화 하면 디버깅/추적에 사용할 수 있는 이러한 주소를 내보낼수 있습니다.
+bpf_jit_harden 파라메터 값이 활성화 된 경우에는 이 기능은 비활성화 됩니다.
+설정값 :
+0 -  JIT kallsyms 내보내기 비활성화(기본값)
+1 -  인가받은 사용자들에 대해서 JIT kallsyms 내보내기 활성화
+)
+
+BPF 호출에서 BPF 호출은 JIT 경우뿐만 아니라 인터프리터와 상관 관계가 있습니다.
+뒤에서는 서브 프로그램의 태그가 호출 대상으로 표시됩니다.
+각각의 경우, pc+2는 호출 대상의 pc-상대 오프셋이며, 서브 프로그램을 나타냅니다.
+# bpftool prog dump xlated id 1
+0: (85) call pc+2#__bpf_prog_run_args32
+1: (b7) r0 = 1
+2: (95) exit
+3: (b7) r0 = 2
+4: (95) exit
+
+덤프의 주입된 변형:
+# bpftool prog dump xlated id 1
+0: (85) call pc+2#bpf_prog_3b185187f1855c4c_F
+1: (b7) r0 = 1
+2: (95) exit
+3: (b7) r0 = 2
+4: (95) exit
+
+tail 호출의 경우, 커널은 내부적으로 하나의 명령어로 매핑을 하며, bpftool은 디버깅을 쉽게하기 위해
+helper 호출과 연관 시킵니다:
+
+# bpftool prog dump xlated id 2
+[...]
+10: (b7) r2 = 8
+11: (85) call bpf_trace_printk#-41312
+12: (bf) r1 = r6
+13: (18) r2 = map[id:1]
+15: (b7) r3 = 0
+16: (85) call bpf_tail_call#12
+17: (b7) r1 = 42
+18: (6b) *(u16 *)(r6 +46) = r1
+19: (b7) r0 = 0
+20: (95) exit
+
+# bpftool map show id 1
+1: prog_array  flags 0x0
+key 4B  value 4B  max_entries 1  memlock 4096B
+
+map dump 서브 명령을 사용하여, 현재의 모든 맵 요소를 반복하고 키/값 쌍으로 16진 수로 덤프하는
+전체 맵을 덤프할 수 있습니다. 곧 나오는 BTF(BPF 타입 포멧), 맵은 키/값 구조로 디버깅 정보를 가지고 있으며,
+bpftool은 16 진수 덤프 외에도 내용을 'pretty-print' 할수 있습니다:
+# bpftool map dump id 5
+key:
+f0 0d 00 00 00 00 00 00  0a 66 00 00 00 00 8a d6
+02 00 00 00
+value:
+00 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
+key:
+0a 66 1c ee 00 00 00 00  00 00 00 00 00 00 00 00
+01 00 00 00
+value:
+00 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
+[...]
+Found 6 elements
+
+특정 키에 대한 map에서 조회, 업데이트, 삭제 및 다음 키 얻기 작업은 bpftool을 통해서도 수행 할 수 있습니다.
+
+BPF sysctls
+리눅스 커널에서는 몇가지 BPF와 관련된 sysctl에 대한 제공을 하며, 이 장에서는 이 내용을 다룹니다.
+
+* /proc/sys/net/core/bpf_jit_enable: BPF JIT 컴파일러를 활성화 혹은 비활성화 하도록 설정합니다.
+설정값:
+0 - JIT를 비활성화 하며, 인터프리터만 사용합니다 (커널 기본값)
+1 - JIT 컴파일러를 활성화 합니다.
+2 - JIT를 활성화 하며,  커널 로그에 emit 디버깅 추적을 남깁니다.
+
+다음 절에서 설명하는 것 처럼, bpf_jit_disasm 도구는 JIT 컴파일러가 디버깅 모드(옵션 2)로
+설정된 경우 디버깅 추적을 처리하는 데 사용 할 수 있습니다.
+
+* /proc/sys/net/core/bpf_jit_harden: BPF JIT 하드닝를 활성화 혹은 비활성화 하도록 설정합니다.
+하드닝 기능을 사용하면 성능이 저하되지만, BPF 프로그램의 즉각적인 값을 무시함으로써
+JIT 스프레이 공격에 대해 완화 할 수 있습니다. 인터프리터를 통해 처리되는 프로그램의 경우
+즉시 값의 블라인드가 필요하지 않거나 수행되지 않습니다.
+
+설정값:
+0 - JIT 하드닝 비활성화 (커널의 기본값)
+1 - 허가받은 사용자들에 대해서 JIT 하드닝 활성화
+2 - 모든 사용자들에 대해서 JIT 하드닝 활성화
+
+* /proc/sys/net/core/bpf_jit_kallsyms: 주입된 프로그램을 /proc/kallsyms에 대한 커널
+심볼로 내보내기를 활성화하거나 비활성화 하도록 설정하며, perf 도구와 함께 사용할 수 있으며 이러한 주소가
+스택 해제를 위해 커널에 인식 되며, 예를 들어 스택 추적을 덤프라는 데 사용됩니다.
+심볼 이름에는 BPF 프로그램 태그 (bpf_prog_<tag>)가 포함됩니다.
+만약 bpf_jit_harden 파라메터 값이 활성화 되어 있다면, 이 기능은 비활성화 됩니다.
+
+설정값:
+0 - JIT kallsyms 내보내기 비활성화(커널 기본값)
+1 - 인가받은 사용자들에 대해서 JIT kallsyms 내보내기 활성화
+
+* /proc/sys/kernel/unprivileged_bpf_disabled:
+bpf(2) 시스템 호출의 권한없는 사용을 활성화하거나 비활성화 하도록 설정합니다.
+Linux 커널은 기본적으로 bpf(2)를 사용하는 권한 없는 사용에 대해서 활성화 되어 있으며,
+이 옵션이 바뀌면, 다음 재부팅 때까지 권한이 없는 사용이 영구적으로 비 활성화됩니다.
+이 sysctl 설정은 일회성 스위치 이며, 즉 일단 설정되면, 응용프로그램이나 관리자가 더 이상
+값을 재설정 할수 없습니다. 이 설정은 프로그램을 커널에 로드하기 위해 bpf(2) 시스템 호출을 사용하지 않는
+seccomp 또는 기존 소켓 필터와 같은 cBPF 프로그램에는 영향을 주지 않습니다.
+설정값:
+0 - 권한없는 bpf 시스템 호출 사용 활성화 (커널 기본값)
+1 - 권한없는 bpf 시스템 호출 사용 비활성화
+
+Kernel Testing
+Linux 커널은 커널 소스 트리에서 tools/testing/selftest/bpf 아래에 BPF
+자가 테스트 모음을 제공 합니다.
+
+$ cd tools/testing/selftests/bpf/
+$ make
+# make run_tests
+
+테스트 모음는 BPF verifier에 대한 테스트 케이스, 프로그램 태그, BPF map 인터페이스 및
+map 유형에 대한 다양한 테스트를 포함합니다. LLVM 백엔드 확인을위한 C 코드와 인터프리터 및 JIT 테스트를 위해
+커널에서 실행되는 cBPF asm 코드 뿐만 아니라 eBPF의 다양한 런타임 테스트가 포함되어 있습니다.
+
+JIT 디버깅
+
+감사를 수행 하거나 확장 기능을 수행하는 JIT 개발자의 경우, 각 컴파일러 실행은 생성된 JIT 이미지를 다음을 통해 커널 로그에 출력 할수 있습니다:
+# echo 2 > /proc/sys/net/core/bpf_jit_enable
+
+새 BPF 프로그램이 로드 될 때마다 JIT 컴파일러는 출력을 덤프하고 dmesg를 통해 점검 할 수 있으며, 예를 들면 다음과 같습니다:
+[ 3389.935842] flen=6 proglen=70 pass=3 image=ffffffffa0069c8f from=tcpdump pid=20583
+[ 3389.935847] JIT code: 00000000: 55 48 89 e5 48 83 ec 60 48 89 5d f8 44 8b 4f 68
+[ 3389.935849] JIT code: 00000010: 44 2b 4f 6c 4c 8b 87 d8 00 00 00 be 0c 00 00 00
+[ 3389.935850] JIT code: 00000020: e8 1d 94 ff e0 3d 00 08 00 00 75 16 be 17 00 00
+[ 3389.935851] JIT code: 00000030: 00 e8 28 94 ff e0 83 f8 01 75 07 b8 ff ff 00 00
+[ 3389.935852] JIT code: 00000040: eb 02 31 c0 c9 c3
+
+flen는 BPF 프로그램 여기서는 6개 BPF 명령어이며, proglen는 opcode 이미지에 대해 JIT에서 생성된 70 byte
+를 알려 줍니다. pass는 이미지가 3 단계 compiler passes 에서 생성 된 것을 의미 하며, 예를 들어 x86_64는 가능한 경우에
+이미지 크기를 줄이기 위해 다양한 최적화 단계를 가질수 있습니다. image는 생성 된 JIT 이미지의 주소를 포함하고 있으며,
+from및 pid는 컴파일 프로세스를 트리거 한 사용자 영역 응용 프로그램 이름과 PID입니다. eBPF 및 cBPF JIT의 덤프 출력은 동일한 형식입니다.
+
+tools/bpf/ 아래의 커널 트리에는 bpf_jit_disasm 불리는 도구가 있습니다. 최신 덤프를 읽고 추가 검사를 위해 디스 어셈블리를 출력합니다:
+# ./bpf_jit_disasm
+70 bytes emitted from JIT compiler (pass:3, flen:6)
+ffffffffa0069c8f + <x>:
+0:       push   %rbp
+1:       mov    %rsp,%rbp
+4:       sub    $0x60,%rsp
+8:       mov    %rbx,-0x8(%rbp)
+c:       mov    0x68(%rdi),%r9d
+10:       sub    0x6c(%rdi),%r9d
+14:       mov    0xd8(%rdi),%r8
+1b:       mov    $0xc,%esi
+20:       callq  0xffffffffe0ff9442
+25:       cmp    $0x800,%eax
+2a:       jne    0x0000000000000042
+2c:       mov    $0x17,%esi
+31:       callq  0xffffffffe0ff945e
+36:       cmp    $0x1,%eax
+39:       jne    0x0000000000000042
+3b:       mov    $0xffff,%eax
+40:       jmp    0x0000000000000044
+42:       xor    %eax,%eax
+44:       leaveq
+45:       retq
+
+또는 이 도구는 디스어셈블 와 함께 관련 opcode를 덤프 할 수도 있습니다.
+# ./bpf_jit_disasm -o
+70 bytes emitted from JIT compiler (pass:3, flen:6)
+ffffffffa0069c8f + <x>:
+0:       push   %rbp
+55
+1:       mov    %rsp,%rbp
+48 89 e5
+4:       sub    $0x60,%rsp
+48 83 ec 60
+8:       mov    %rbx,-0x8(%rbp)
+48 89 5d f8
+c:       mov    0x68(%rdi),%r9d
+44 8b 4f 68
+10:       sub    0x6c(%rdi),%r9d
+44 2b 4f 6c
+14:       mov    0xd8(%rdi),%r8
+4c 8b 87 d8 00 00 00
+1b:       mov    $0xc,%esi
+be 0c 00 00 00
+20:       callq  0xffffffffe0ff9442
+e8 1d 94 ff e0
+25:       cmp    $0x800,%eax
+3d 00 08 00 00
+2a:       jne    0x0000000000000042
+75 16
+2c:       mov    $0x17,%esi
+be 17 00 00 00
+31:       callq  0xffffffffe0ff945e
+e8 28 94 ff e0
+36:       cmp    $0x1,%eax
+83 f8 01
+39:       jne    0x0000000000000042
+75 07
+3b:       mov    $0xffff,%eax
+b8 ff ff 00 00
+40:       jmp    0x0000000000000044
+eb 02
+42:       xor    %eax,%eax
+31 c0
+44:       leaveq
+c9
+45:       retq
+c3
+
+
+보다 최근에 bpftool은 이미 시스템에 로드 된 BPF 프로그램 ID를 기반으로 BPF JIT 이미지를 덤프하는 것과 동일한 기능을
+채택했습니다 (bpftool 섹션 참조 부탁드립니다). 주입된 BPF 프로그램의 성능 분석을 위해 일반적으로 perf를 사용할 수 있습니다.
+전제 조건으로, 주입된 프로그램은 kallsyms 인프라를 통해 export 되어야 합니다.
+
+# echo 1 > /proc/sys/net/core/bpf_jit_enable
+# echo 1 > /proc/sys/net/core/bpf_jit_kallsyms
+
+bpf_jit_kallsyms 파라메터를 활성화 또는 비 활성화에는 관련 BPF 프로그램을 다시 로드 할 필요가 없습니다.
+다음으로 BPF 프로그램을 프로파일링하기 위한 작은 작업 흐름 예제가 제공됩니다. 만들어진 tc BPF 프로그램은
+bpf_clone_redirect() helper 함수에서 perf가 실패한 할당을 기록하는 데 사용됩니다. 직접 쓰기를 사용하기 때문에,
+bpf_try_make_head_writable() 함수에 실패하여 복제 된 skb를 다시 해제하고 오류 메시지와 함께 리턴합니다.
+perf는 모든 kfree_skb 이벤트를 기록합니다.
+# tc qdisc add dev em1 clsact
+# tc filter add dev em1 ingress bpf da obj prog.o sec main
+# tc filter show dev em1 ingress
+filter protocol all pref 49152 bpf
+filter protocol all pref 49152 bpf handle 0x1 prog.o:[main] direct-action id 1 tag 8227addf251b7543
+
+# cat /proc/kallsyms
+[...]
+ffffffffc00349e0 t fjes_hw_init_command_registers    [fjes]
+ffffffffc003e2e0 d __tracepoint_fjes_hw_stop_debug_err    [fjes]
+ffffffffc0036190 t fjes_hw_epbuf_tx_pkt_send    [fjes]
+ffffffffc004b000 t bpf_prog_8227addf251b7543
+
+# perf record -a -g -e skb:kfree_skb sleep 60
+# perf script --kallsyms=/proc/kallsyms
+[...]
+ksoftirqd/0     6 [000]  1004.578402:    skb:kfree_skb: skbaddr=0xffff9d4161f20a00 protocol=2048 location=0xffffffffc004b52c
+7fffb8745961 bpf_clone_redirect (/lib/modules/4.10.0+/build/vmlinux)
+7fffc004e52c bpf_prog_8227addf251b7543 (/lib/modules/4.10.0+/build/vmlinux)
+7fffc05b6283 cls_bpf_classify (/lib/modules/4.10.0+/build/vmlinux)
+7fffb875957a tc_classify (/lib/modules/4.10.0+/build/vmlinux)
+7fffb8729840 __netif_receive_skb_core (/lib/modules/4.10.0+/build/vmlinux)
+7fffb8729e38 __netif_receive_skb (/lib/modules/4.10.0+/build/vmlinux)
+7fffb872ae05 process_backlog (/lib/modules/4.10.0+/build/vmlinux)
+7fffb872a43e net_rx_action (/lib/modules/4.10.0+/build/vmlinux)
+7fffb886176c __do_softirq (/lib/modules/4.10.0+/build/vmlinux)
+7fffb80ac5b9 run_ksoftirqd (/lib/modules/4.10.0+/build/vmlinux)
+7fffb80ca7fa smpboot_thread_fn (/lib/modules/4.10.0+/build/vmlinux)
+7fffb80c6831 kthread (/lib/modules/4.10.0+/build/vmlinux)
+7fffb885e09c ret_from_fork (/lib/modules/4.10.0+/build/vmlinux)
+
+perf로 기록 된 스택 추적은 함수 호출 추적의 일부로 bpf_prog_8227addf251b7543() 심볼을 표시하며.
+태그 8227addf251b7543을 가진 BPF 프로그램이 kfree_skb 이벤트와 관련이 있다는 것을 의미하며,
+앞서 말한 프로그램은 tc에 표시된 것처럼 ingress hook의 netdevice em1에 연결되었습니다.
+
+Introspection(자가 검사)
+리눅스 커널은 BPF 와 XDP 주변의 다양한 tracepoint들을 제공하는데, 이는 추가적인 introspection를 뜻하며,
+예를 들어 사용자 영역 프로그램과 bpf 시스템 콜의 대화를 추적 할 수 있습니다.
+
+BPF를 위한 tracepoint:
+# perf list | grep bpf:
+bpf:bpf_map_create                                 [Tracepoint event]
+bpf:bpf_map_delete_elem                            [Tracepoint event]
+bpf:bpf_map_lookup_elem                            [Tracepoint event]
+bpf:bpf_map_next_key                               [Tracepoint event]
+bpf:bpf_map_update_elem                            [Tracepoint event]
+bpf:bpf_obj_get_map                                [Tracepoint event]
+bpf:bpf_obj_get_prog                               [Tracepoint event]
+bpf:bpf_obj_pin_map                                [Tracepoint event]
+bpf:bpf_obj_pin_prog                               [Tracepoint event]
+bpf:bpf_prog_get_type                              [Tracepoint event]
+bpf:bpf_prog_load                                  [Tracepoint event]
+bpf:bpf_prog_put_rcu                               [Tracepoint event]
+
+perf를 사용한 예제 사용법(여기에 사용 된 sleep 예제 대신 tc 와 같은 특정 응용 프로그램을 사용할 수 있습니다):
+# perf record -a -e bpf:* sleep 10
+# perf script
+sock_example  6197 [005]   283.980322:      bpf:bpf_map_create: map type=ARRAY ufd=4 key=4 val=8 max=256 flags=0
+sock_example  6197 [005]   283.980721:       bpf:bpf_prog_load: prog=a5ea8fa30ea6849c type=SOCKET_FILTER ufd=5
+sock_example  6197 [005]   283.988423:   bpf:bpf_prog_get_type: prog=a5ea8fa30ea6849c type=SOCKET_FILTER
+sock_example  6197 [005]   283.988443: bpf:bpf_map_lookup_elem: map type=ARRAY ufd=4 key=[06 00 00 00] val=[00 00 00 00 00 00 00 00]
+[...]
+sock_example  6197 [005]   288.990868: bpf:bpf_map_lookup_elem: map type=ARRAY ufd=4 key=[01 00 00 00] val=[14 00 00 00 00 00 00 00]
+swapper     0 [005]   289.338243:    bpf:bpf_prog_put_rcu: prog=a5ea8fa30ea6849c type=SOCKET_FILTER
+
+BPF 프로그램의 경우, 개별 프로그램 태그가 표시됩니다.
+디버깅을 위해 XDP에는 예외가 발생할 때 트리거되는 tracepoint도 있습니다:
+# perf list | grep xdp:
+xdp:xdp_exception                                  [Tracepoint event]
+
+예외는 다음 시나리오에서 트리거 됩니다:
+* BPF 프로그램은 유효하지 않은/알 수없는 XDP 액션 코드를 반환 했습니다.
+* BPF 프로그램은 비정상 종료를 나타내는 XDP_ABORTED를 반환 했습니다.
+* BPF 프로그램은 XDP_TX와 함께 반환 되었지만, 예를 들어 포트가 작동하지 않거나,
+transmit ring이 가득 차거나, 할당 실패 로 인해, 전송 시 오류가 발생했습니다.
+
+두개의 tracepoint class는 BPF 프로그램 자체가 하나 이상의 tracepoint에 연결되어 검사될 수 있으며,
+예를 들어, bpf_perf_event_output() helper 함수를 통해 map에 추가 정보를 수집하거나
+사용자 영역 수집기에 이러한 이벤트를 punting 할수 있습니다.
+
+Miscellaneous
+
+BPF 프로그램과 map는 RLIMIT_MEMLOCK/* 최대 잠긴 기억 장소 주소 공간 */을 기준으로 한 메모리 이며, perf 와 비슷합니다.
+메모리에 잠길 수 있는 시스템 페이지 단위의 현재 사용 가능한 크기는 ulimit -l을 통해 검사 할 수 있습니다.
+setrlimit 시스템 콜 man 페이지는 자세한 내용을 제공합니다.
+
+BPF 시스템 콜이 EPERM의 errno와 함께 반환 될 수 있으며, 보통은 더 복잡한 프로그램이나 큰 BPF 맵을 로드하는 데는
+기본 한계가 충분하지 않습니다.더 복잡한 프로그램이나 큰 BPF map을 로드하는 데에는 기본 한계값은 충분하지 않으며,
+그래서 BPF 시스템 콜은 EPERM 의 에러 번호(errno)를 반환활 것 입니다.
+이런 상황에서는 ulimit -l ulimited 혹은 충분히 큰 제한 값을 수행이 될수 있습니다.
+RLMIT_MEMLOCK는 주로 권한이 없는 사용자에게 제한이 적용됩니다.
+설정에 따라, 권한있는 사용자에 대해 더 높은 제한을 설정하는 것이 종종 허용 됩니다.
+
+프로그램 유형
+이 글을 쓸 당시, 사용 가능한 18 가지의 다른 BPF 프로그램의 유형이 있으며, 네트워킹을 위한 주요 유형 중 두가지는
+XDP BPF 프로그램 과 tc BPF 프로그램에 대해 하위 세션에서 자세히 설명합니다.
+LLVM, iproute2 또는 기타 도구에 대한 두 가지 프로그램 유형에 대한 광범위한 사용 예는 툴체인 섹션에 전달되어 있으며
+여기서는 다루지 않습니다. 대신이 이 섹션에서는 아키텍처, 개념 및 사용 사례에 중점을 둡니다.
+
+XDP
+XDP는 eXpress Data Path의 약자이며 리눅스 커널에서 고성능 프로그램 가능한 패킷 처리를
+가능하게 하는 BPF를 위한 프레임 워크를 제공합니다.XDP는 BPF 프로그램을 소프트웨어의 가장 빠른 시점,
+즉 네트워크 드라이버가 패킷을 받는 순간 실행합니다. 고속 경로의 이시점에서, 드라이버는 패킷등을
+GRO(generic receive offload)로 푸시 하지 않고, 패킷을 네트워킹 스택 보다 더 위로 올리기 위한
+skb 할당과 같은 비용이 많이 드는 작업을 수행하지 않고,
+수신링에서 패킷을 수신합니다. 따라서, XDP BPF 프로그램은 처리를 위해 CPU에서 사용 할수 있는 가장 빠른 시점에 실행됩니다.
+XDP는 리눅스 커널 및 인프라와 함께 동작 하므로, 사용자 영역에서만 작동하는 다양한 네트워크 프레임 워크
+(dpdk, netmap,등등)처럼 커널을 우회하는 동작을 하지 않습니다. 패킷을 커널 공간에 유지하면 다음과 같은 몇 가지 주요 이점이 있습니다:
+
+* XDP는 BPF helper 호출 자체에서 라우팅 테이블, 소켓등과 같이 업스트립에서 개발된 모든 커널 드라이버,
+사용자 영역 툴 또는 다른 사용 가능한 커널 내부 구조를 재사용 할수 있습니다.
+* 커널 공간에 존재하는 XDP는 하드웨어에 접근을 위한 커널의 나머지 부분과 동일한 보안 모델을 가지고 있습니다.
+* 처리 된 패킷이 이미 커널에 있기 때문에 컨테이너 혹은 커널의 네트워킹 스택 자체에서 사용되는 네임 스페이스와
+같은 다른 커널 내부 엔터티로 패킷을 유연하게 전달할 수 있으므로 커널/사용자 영역 경계를 넘을 필요가 없습니다.
+이것은 멜트다운과 스펙터의 시기와 관련이 있습니다.
+* XDP에서 커널의 robust로 패킷을 퍼팅(punting)하여 광범위하게 사용되는 TCP/IP 스택을 쉽게 사용할 수 있으며,
+완전히 재사용 할 수 있으며 사용자 공간 프레임 워크와 별도로 TCP/IP 스택을 유지 관리 할 필요가 없습니다.
+* BPF를 이용하여 커널의 시스템 call ABI 호출하는 것과 동일한 naver-break-user-space 보장을 통해
+안정적인 ABI를 유지하며, 모듈과 비교하여 커널 동작의 안정성을 보장하는 BPF verifier 덕분에
+안정 장치를 제공하는 완전한 프로그래밍 기능을 사용 할수 있습니다.
+* XDP를 사용하면 네트워크 트래픽 중단이나 커널/시스템 재부팅 없이 런타임에 프로그램을 atomically하게
+스왑할 수 있습니다.
+* XDP를 사용하면 커널에 통합된 워크로드를 유연한 구조화 할 수 있습니다. 예를 들어, "busy polling"또는
+"interrupt driven"모드에서 작동 할 수 있습니다. 명시 적으로 CPU를 XDP 전용으로 지정할 필요는 없습니다.
+특별한 하드웨어 요구 사항은 없으며, hugepages에 의존하지 않습니다.
+* XDP에는 타사 커널 모듈이나 라이센스가 필요하지 않습니다. 이것은 장기적인 아키텍처 솔루션으로 리눅스 커널의
+핵심 부분이며 커널 커뮤니티에 의해 개발되었습니다.
+* XDP는 4.8 이상에 해당하는 커널을 실행하는 주요 배포판을 통해 모든 곳에서 이미 활성화되고 제공되며 대부분의 주요
+10G 이상의 네트워킹 드라이버를 지원합니다(XDP native mode).
+
+드라이버에서 BPF를 실행하기 위한 프레임워크로서, XDP는 패킷이 선형적으로 배치되어 BPF 프로그램이 읽고 쓸 수
+있는 단일 DMA의 페이지에 맞도록 보장합니다. 또한 XDP는 bpf_xdp_adjust_head() BPF helper 함수를 사용하여,
+사용자 정의 캡슐화 헤더를 구현하거나 bpf_xdp_adjust_meta()를 통해 패킷 앞에 사용자 정의 메타 데이터를 추가하는
+프로그램에서 256 바이트의 추가 헤드룸을 사용할 수 있도록합니다.
+
+프레임워크에서 BPF 프로그램이 드라이버에게 패킷 진행 방법을 지시하기 위해 반환 할 수 있는 XDP 액션 코드가
+아래의 절에 자세히 설명되어 있으며, XDP 계층에서 실행되는 BPF 프로그램을 atomically 하게 바꿀 수 있습니다.
+XDP는 고성능을 위해 디자인 되었습니다. BPF는 '직접 패킷 액세스(direct packet access)'를 통해 패킷
+데이터에 액세스 할 수 있으며,  이는 프로그램이 레지스터에서 직접 데이터 포인터를 보유하고,
+내용을 레지스터에 로드하고, 레지스터로 부터 패킷으로 씁니다.
+
+BPF 컨텍스트로 BPF 프로그램에 전달 된 XDP의 패킷 표현은 다음과 같습니다:
+struct xdp_buff {
+void *data;
+void *data_end;
+void *data_meta;
+void *data_hard_start;
+struct xdp_rxq_info *rxq;
+};
+
+data는 페이지의 패킷 데이터의 시작을 가르키며, 이름에서 알 수 있듯이 data_end는 패킷
+데이터의 끝을 가르킵니다. XDP는 헤드 룸을 허용하기 때문에 data_hard_start는 페이지에서
+가능한 최대 헤드 룸 시작을 가리 키며, 즉, 패킷을 캡슐화 해야 할 때
+데이터가 bpf_xdp_adjust_head()를 통해 data_hard_start쪽으로 더 가까이 이동합니다.
+같은 BPF 도우미 함수는 데이터를 data_hard_start에서 더 멀리 이동시키는 경우 역캡슐화를 허용합니다.
+data_meta는 처음에는 data와 같은 위치를 가리키고 bpf_xdp_adjust_meta()는 일반적인 커널 네트워킹
+스택에서는 볼 수 없는 사용자 정의 메타 데이터 공간을 제공하기 위해 포인터를 data_hard_start방향으로
+이동할 수 있지만, tc BPF 프로그램은 XDP에서 skb로 전송되기 때문에 읽을 수 있습니다. 그 반대의 경우에는
+data_hard_start에서 data_meta를 다시 이동하여, 동일한 BPF helper 함수를 통해,
+사용자 정의 메타 데이터의 크기를 제거하거나 줄일 수 있습니다. data_meta는 tc BPF 프로그램에서 액세스 할 수있는
+skb->cb[] 제어 블럭의 경우와 유사하게 tail 호출 간에 상태를 전달하는 용도로만 사용할 수도 있습니다.
+이것은 구조체 xdp_buff 패킷포인터에 대해 각가 다음과 같은 관계를 갖습니다:
+data_hard_start <= data_meta <= data < data_end
+
+(역자주: 유태희님, 송태웅 님의 공유 하신 XDP 패킷 구조에 대해서
+분석된 내용을 바탕으로 아래의 구조를 설명 하였습니다.
+
+HEADROOM                      MAC HEADER     IP HEADER                                        TAIL/TAILROOM         END
+|                     |       |              |                                                |                     |
+|                     |       |              |                                                |                     |
+|---------------------|-------|--------------|------------------------------------------------|---------------------|
+|                     |       |              |                                                |                     |
+|                     |       |              |                                                |                     |
+|                     |       |              |                                                |                     |
+xdp->data_hard_start  |       xdp->data
+xdp_frame             |       skb->data
+|       xdp->data_meta(이전 위치)
+|
+|xdp->data_meta(현재 위치): bpf_xdp_adjust_head() 함수를 통해, xdp->data_meta의 위치를 이동합니다.
+
+
+@net/core/filter.c (4.17-rc7 기준)
+커널에 선언된 bpf_xdp_adjust_head 함수 입니다.
+....
+BPF_CALL_2(bpf_xdp_adjust_head, struct xdp_buff *, xdp, int, offset)
+{
+void *xdp_frame_end = xdp->data_hard_start + sizeof(struct xdp_frame);
+unsigned long metalen = xdp_get_metalen(xdp);
+void *data_start = xdp_frame_end + metalen;
+void *data = xdp->data + offset;
+
+if (unlikely(data < data_start ||
+data > xdp->data_end - ETH_HLEN))
+return -EINVAL;
+
+if (metalen)
+memmove(xdp->data_meta + offset,
+xdp->data_meta, metalen);
+xdp->data_meta += offset;
+xdp->data = data;
+
+return 0;
+}
+....
+
+rxq 필드는 링 설정 시간(XDP 런타임이 아님)에 채워지는 수신 큐 메타 데이터 당 몇 가지 추가 정보를 가리 킵니다:
+struct xdp_rxq_info {
+struct net_device *dev;
+u32 queue_index;
+u32 reg_state;
+} ____cacheline_aligned;
+BPF 프로그램은 ifindex와 같은 netdevice 자체에서 추가 데이터 뿐만 아니라, queue_index를 검색 할 수 있습니다.
+
+BPF program return codes
+XDP BPF 프로그램을 실행 한 후 드라이버에게 다음 패킷 처리 방법을 알리기 위해 프로그램에서 결정이 반환됩니다.
+linux/bpf.h 시스템 헤더 파일에서 사용 가능한 모든 반환 결과가 나열됩니다:
+
+enum xdp_action {
+XDP_ABORTED = 0,
+XDP_DROP,
+XDP_PASS,
+XDP_TX,
+XDP_REDIRECT,
+};
+
+이름에서 알 수 있듯이 XDP_DROP은 추가 리소스를 낭비하지 않고 드라이버 수준에서 바로 패킷을 삭제합니다.
+이것은 특히 DDoS 완화 메커니즘 또는 방화벽을 일반적으로 구현하는 BPF 프로그램에 유용합니다.
+XDP_PASS 리턴 코드는 패킷이 커널의 네트워킹 스택에 전달 될 수 있음을 의미합니다.
+이 의미는 이 패킷을 처리하고 있던 현재 CPU는 이제 skb를 할당하고 채우고 GRO 엔진으로 전달합니다.
+이것은 XDP가 없는 기본 패킷 처리 동작과 동일합니다. XDP_TX를 사용하면 BPF 프로그램은 방금 도착한 동일한 NIC에서
+네트워크 패킷을 전송할 수 있는 효율적인 옵션을 제공합니다.
+이는 일반적으로 클러스터에서 후속 로드 밸런싱을 사용하는 방화벽과 같이, XDP BFP에서 재작성 후 들어오는 패킷을 다시 스위치로
+밀어 넣는 헤어핀(loopback) 로드 밸런서의 역활을 하는 몇 개의 노드가 구현되는 경우에 유용합니다.
+XDP_REDIRECT는 XDP 패킷을 전송할 수 있지만 다른 NIC를 통해 전송할 수 있다는 점에서 XDP_TX와 유사합니다.
+XDP_REDIRECT의 또 다른 옵션은 BPF cpumap으로 리디렉션하는 것이며, 이 의미는, NIC의 수신 대기열에서 XDP를 제공하는
+CPU는 계속해서 상위 커널 스택을 처리하기 위해 패킷을 원격 CPU로 푸시 할 수 있습니다.
+이는 XDP_PASS와 유사하지만 XDP BPF 프로그램이 상위 계층으로 푸시하기 위해, 일시적으로 현재 패킷에 대한 작업을 수행하는
+것과 달리 들어오는 높은 부하를 계속 서비스 할 수있는 기능을 갖추고 있습니다.
+마지막으로 프로그램에서 상태와 같은 예외를 표시하는 역할을 하는 XDP_ABORTED가 있으며, XDP_DROP와 동일한 동작을하며,
+XDP_ABORTED는 추가로 잘못 감지 된 trace_xdp_exception tracepoint 을 전달합니다.
+
+XDP 사용 사례
+XDP의 주요 사용 사례 중 일부 이 하위 섹션에 나와 있습니다.
+이 목록은 포괄적인 것은 아니며 XDP 및 BPF가 프로그래밍 할 수있는 효율성과 효율성을 고려할 때 매우 구체적인 사용 사례를 해결하기
+위해 쉽게 적용 할 수 있습니다.
+
+DDoS 완화, 방화벽 기능
+기본적인 XDP BPF 기능 중 하나이며 드라이버가 초기 단계에서 XDP_DROP를 사용하여 패킷을 drop하도록 지시하는 것으로
+패킷 당 비용이 매우 낮아 모든 종류의 효율적인 네트워크 정책 시행을 허용합니다.
+이것은 모든 종류의 DDoS 공격애 대처할 필요가 있을 때 이상적이며, BPF에서 오버레드가 거의 없는 모든 종류의 방화벽 정책을 구현 할 수 있으며,
+예를 들어 독립형 어플라이언스 (예를 들어, XDP_TX를 통한 'clean' 트래픽 제거) 또는 마지막 호스트 자체를 보호하는 노드
+(XDP_PASS 또는 cpumap XDP_REDIRECT를 통한 양호한 트래픽)에 널리 배치 됩니다.
+오프로드 된 XDP는 라인 속도로 처리하면서, 이미 패킷 당 비용을 전체적으로 NIC로 완전히 옮김으로써 한 단계 더 나아갑니다.
+
+포워딩 및 로드밸런싱
+XDP의 또 다른 주요 사용 사례는 XDP_TX 또는 XDP_REDIRECT 동작을 통한 패킷 전달 및 로드 밸런싱 입니다.
+패킷은 XDP 계층에서 실행되는 BPF 프로그램에 의해 중간에 mangle 될수 있으며, BPF 도우미 함수 기능은 패킷을 캡슐화 해제하고
+다시 캡슐화 하기 전에 캡슐화하기 위해패킷의 headroom을 늘리거나 줄일 수 있습니다. 원래 도착한 동일한 네트워크 장치에서 패킷을
+푸시 하는 XDP_TX hairpinned(혹은 loopback) 로드 밸런서를 사용하거나 XDP_REDIRECT 동작을 통해 전송을 위해 다른
+NIC로 전달할 수 있습니다. 이후의 리턴 코드는 BPF의 cpumap과 함께  로컬 스택을 통과 하기위한 패킷을 로드 밸런싱하기 위해 사용될 수 있지만
+원격의 non-XDP 프로세싱 CPU에서는 사용할 수 없습니다.
+
+사전 스택 필터링 / 처리
+정책 적용 외에도 XDP는 XDP_DROP의 경우, 커널의 네트워크 스택을 강화하는 데 사용 할 수 있으며,
+이 의미는 네트워크 스택이 알기 전에 로컬 노트에 대해 관련성 없는 패킷을 가능한 빨리 삭제 할 수 있으며,
+예를 들어 노드가 TCP 트래픽 만 처리하는 것을 알면, 모든 UDP, SCTP 또는 기타 L4 트래픽을 버릴 수 있습니다. 이것은 패킷이 GRO 엔진 과 같은 커널의
+흐름 분석기 및 다른 것들을 가로지를  필요가 없이  패킷을 버릴수 있기 때문에 커널의 공격 영역을 줄일 수 있다는 이점이 있습니다.
+XDP의 조기 처리 단계 덕분에, 이것은 효과적으로 커널의 네트워킹 스택을 가장하며, 이러한 패킷은 네트워킹 장치에서 확인된적은 없습니다.
+또한 스택의 수신 경로에 잠재적 인 버그가 발견되어 'ping of death'같은 시나리오가 발생하면 XDP를 사용하여 커널을
+재부팅하거나 서비스를 다시 시작하지 않고도 해당 패킷을 즉시 삭제할 수 있습니다. 이러한 프로그램을 atomically으로 스왑하여
+불량 패킷을 버리는 기능으로 인해 호스트에서 네트워크 트래픽이 중단되지 않습니다.사전 스택 처리를 위한 또 다른 사용 사례는 커널이 아직 패킷에
+대한 skb를 할당하지 않은 경우, BPF 프로그램은 패킷을 수정 할 수 있으며, 이 방법으로 네트워크 장비로 부터 스택에 수신된 패킷 인척 합니다.
+이렇게하면 GRO 는 사용자 정의 프로토콜를 인식 못하기 때문에 어떠한 종료의 통계도 수행
+할수 없으며, GRO aggregation을 들어가기 전에 패킷을 캡슐화 해제할 수있는 사용자 정의  패킷 맹 글링 및 캡슐화 프로토콜이 있는 경우가 허용됩니다.
+이는 일반적인 커널 스택에 '보이지'않으며, GRO(메타 데이터 매칭을 위해)를 집계하고, 나중에 예를 들어 사용할 수있는 다양한 skb 필드를 설정 하여,
+skb 컨텍스트를 갖는 tc ingress BPF 프로그램과 함께 처리 할 수 있습니다.
+
+flow 샘플링, 모니터링
+또한 XDP는 패킷 모니터링, 샘플링 또는 기타 네트워크 분석과 같은 경우에 사용할 수 있으며, 예를 들어 경로의 중간 노드
+또는 끝 호스트에서 앞서 언급 한 사용 사례와 함께 사용할 수 있습니다.복잡한 패킷 분석을 위해 XDP는 네트워크 패킷
+(생략된 또는 전체 페이로드 포함) 및 사용자 지정 메타 데이터를  Linux perf 인프라에서 사용자 공간 응용 프로그램으로 제공되는 CPU 메모리
+매핑 링 버퍼 당 빠른 lock없이 신속하게 푸시 할 수있는 기능을 제공합니다. 이는 또한 흐름의 초기 데이터 만 분석하고 모니터링을 우회하는 양호한
+트래픽으로 판단되는 경우도 허용합니다. BPF가 제공하는 유연성으로 인해 사용자 정의 모니터링이나 샘플링을 구현할 수 있습니다. XDP BPF
+프로덕션 사용의 한 예로 L4로드 균형 조정 및 DDoS 대응을 구현하는 Facebook SHIV및 Droplet infrastructure 가 있습니다.
+
+프로덕션 인프라를 Netfilter의 IPVS (IP Virtual Server)에서 XDP BPF로 마이그레이션하면 이전 IPVS 설정에 비해 속도가 10 배 빨라졌습니다.
+이것은 netdev 2.1 컨퍼런스에서 처음 발표되었습니다:
+
+Slides: https://www.netdevconf.org/2.1/slides/apr6/zhou-netdev-xdp-2017.pdf
+Video: https://youtu.be/YEU2ClcGqts
+
+iptables의 사용으로 인해 이것은 사용자 영역 우회 솔루션이 필요하다고 생각되는 공격 하에서 심각한 성능 문제를 일으켰지 만 NIC를 바쁘게 폴링하고 커널
+스택에 비용이 많이 드는 패킷을 다시 주입해야하는 등의 단점이있었습니다.eBPF와 XDP 로의 이전은 고성능 프로그래머블 패킷 처리를 커널 내부에서
+직접 수행함으로써 두 영역의 장점을 결합했습니다:
+
+Slides: https://www.netdevconf.org/2.1/slides/apr6/bertin_Netdev-XDP.pdf
+Video: https://youtu.be/7OuOukmuivg
+
+XDP 동작 모드
+XDP에는 세 가지 작동 모드가 있습니다. '네이티브'XDP가 기본 모드입니다. XDP에 관해 이야기 할 때 일반적으로 이 모드가 암시됩니다.
+
+네이티브 XDP
+이 모드는 XDP BPF 프로그램이 네트워킹 드라이버의 초기 수신 경로에서 직접 실행되는 기본 모드입니다. 10G 이상을 위해 널리 사용되는 NIC는 이미 네이티브 XDP를 지원합니다.
+
+오프로드 XDP
+오프로드 XDP 모드에서 XDP BPF 프로그램은 호스트 CPU에서 실행되는 대신에 NIC로 직접 오프로드됩니다.
+따라서 패킷 당 비용이 매우 낮아 호스트 CPU에서 완전히 푸시되고 NIC에서 실행되므로 네이티브 XDP에서 실행하는 것보다 훨씬 높은 성능을 제공합니다.
+이 오프로드는 일반적으로 커널 내 JIT 컴파일러가 BPF를 후자의 기본 명령어로 변환하는 멀티 스레드, 멀티 코어 플로우 프로세서를 포함하는 SmartNIC에 의해 구현됩니다.
+또한 오프로드 XDP를 지원하는 드라이버는 일부 BPF helper가 아직 또는 기본 모드에서만 사용할 수없는 경우에 대비해 네이티브 XDP를 지원합니다.
+
+일반 XDP
+
+네이티브 또는 오프로드 XDP를 아직 구현되지 않는 드라이버의 경우, 커널은 네트워킹 스택에서 많이 늦는 시점에서 실행되는 드라이버 변경이 필요없는 일반 XDP 옵션을 제공합니다.
+이 설정은 주로 커널의 XDP API에 대해 프로그램을 작성 및 테스트하고 원시 또는 오프로드 모드의 성능 속도로 동작하지 않는 개발자를 대상으로합니다.
+프로덕션 환경에서의 XDP 사용의 경우 네이티브 또는 오프로드 모드가 더 적합하며 XDP를 실행하는 데 권장되는 방법입니다.
+
+드라이버 지원
+
+BPF와 XDP는 기능 및 드라이버 지원 측면에서 빠르게 진화하고 있기 때문에 다음은 커널 4.17에서의 네이티브 및 오프로드 된 XDP 드라이버 목록입니다.
+
+네이티브 XDP를 지원하는 드라이버
+
+Drivers supporting native XDP
+
+* Broadcom
+- bnxt
+
+* Cavium
+- thunderx
+
+* Intel
+- ixgbe
+- ixgbevf
+- i40e
+
+* Mellanox
+- mlx4
+- mlx5
+
+* Netronome
+- nfp
+
+* Others
+- tun
+- virtio_net
+
+* Qlogic
+- qede
+
+* Solarflare
+- sfc [1]
+
+Drivers supporting offloaded XDP
+
+* Netronome
+- nfp [2]
+
+XDP 프로그램 작성 및 로드 예제는 해당 도구 아래의 도구 모음 섹션에 포함되어 있습니다.
+[1] sfc에 대한 XDP는 커널 4.17에서 트리 드라이버를 통해 사용할 수 있지만 곧 업스트림에 반영 예정에 있습니다.
+[2] (1, 2) 현재 CPU 번호 검색과 같은 일부 BPF helper 기능은 오프로드 된 설정에서 사용할 수 없습니다.
+
+tc (트래픽 제어)
+XDP와 같은 다른 프로그램 유형 과는 별도로 BPF는 네트워킹 데이터 경로의 커널 tc(트래픽 제어) 계층에서도 사용할 수 있습니다.
+상위 수준에서 XDP BPF 프로그램과 tc BPF 프로그램을 비교할 때 세 가지 주요 차이점이 있습니다:
+
+*BPF 입력 컨텍스트는 xdp_buff가 아닌 sk_buff입니다. 커널의 네트워킹 스택이 패킷을 받으면 XDP 계층 다음에 버퍼를 할당하고
+패킷을 구문 분석하여 패킷에 대한 메타 데이터를 저장합니다. 이 표현을 sk_buff라고합니다.이후 이 구조는 BPF 입력 컨텍스트에서 노출되므로
+tc ingress 레이어의 BPF 프로그램이 스택에서 패킷에서 추출한 메타 데이터를 사용할 수 있습니다.이것은 유용 할 수 있지만,이러한  할당 및 메타 데이터
+추출을 수행하는 스택의 관련 비용과 함께 tc hook에 도달 할 때까지 패킷을 처리합니다. 정의에 따르면 xdp_buff는이 작업이 완료되기 전에,
+XDP hook가 호출되기 때문에 이 메타 데이터에 액세스 할 수 없습니다. 이는 XDP와 tc hook 간의 성능 차이에 크게 관여됩니다.
+
+따라서 tc BPF hook에 연결 된 BPF 프로그램은 예를 들어, 읽기 혹은 쓰기 skb의 mark, pkt_type, protocol, priority, queue_mapping,
+napi_id, cb[] array, hash, tc_classid or tc_index, vlan 메타데이터, XDP로 전송 된 사용자 정의 메타 데이터 및 다양한 다른 정보를 제
+공 할 수 있습니다. tc BPF에서 사용되는 struct __sk_buff BPF 컨텍스트의 모든 멤버는 linux/bpf.h 시스템 헤더에 정의되어 있습니다.
+일반적으로 sk_buff는 장점과 단점이 모두 있는 xdp_buff 와 완전히 다릅니다. 예를 들어 sk_buff의 경우에는 연관된 메타 데이터를 mangle하는 것이
+훨씬 간단하지만, 많은 프로토콜 관련 정보 (예 : GSO 관련 상태) 를 가진 sk_buff가 단순히 패킷 데이터를 다시 작성하여 프로토콜을 간단하게 전환하는 되는
+것은 어렵습니다. 이것은 매번 패킷 내용에 액세스하는 비용이 들지 않고 메타 데이터를 기반으로 패킷을 처리하는 스택 때문입니다. 따라서 sk_buff 내부가
+올바르게 변환되도록 주의하면서, BPF helper 함수에서 추가 변환이 필요합니다. 그러나 xdp_buff의 경우 커널이 아직 sk_buff를 할당하지 않은 처음
+단계에 있기 때문에 이러한 문제는 발생하지 않으므로 모든 종류의 패킷 재 작성을 쉽게 실현할 수 있습니다. 그러나 xdp_buff의 경우에는이 단계에서
+mangling에 sk_buff 메타 데이터를 사용할 수 없다는 단점이 있습니다.후자는 XDP BPF에서 tc BPF로 사용자 지정 메타 데이터를 전달함으로써
+해결이 됩니다. 이러한 방식으로, 각 프로그램 유형의 한계는 사용 사례를 요구하는 두 유형의 보완 프로그램을 동작하는 것으로 해결 될 수 있습니다.
+
+* XDP와 비교하여 네트워킹 데이터 경로의 ingress 및 egress 지점에서 tc BPF 프로그램이 트리거 될 수 있으며, XDP의 경우는 반대로 ingress 만 가능합니다.
+커널에서 sch_handle_ingress() 및 sch_handle_egress()라는 두 개의 hook 지점은 각각 __netif_receive_skb_core() 및 __dev_queue_xmit()에서
+트리거 됩니다. 후자의 두 가지는 데이터 경로의 주요 수신 및 전송 기능으로, XDP를 별도로 설정하면 노드에서 들어오고 나가는 모든 네트워크 패킷에 대해 트리거되어
+이러한 hook 지점에서 tc BPF 프로그램을 완벽하게 볼 수 있습니다.
+
+* tc BPF 프로그램은 네트워킹 스택의 일반 레이어에서 연결 지점에서 실행 되므로 드라이버 변경이 필요하지 않습니다. 따라서 모든 유형의
+네트워킹 장치에 연결할 수 있습니다. 이는 유연성을 제공하지만 네이티브 XDP 계층에서 실행하는 것과 비교하여 성능을 저하 시킵니다.
+그러나 tc BPF 프로그램은 GRO이 실행 된 후 모든 프로토콜 처리, 기존 iptables 방화벽이 실행되기 전에 일반 커널의 네트워킹 데이터 경로의 가장 초기 단계에
+있으며, 예를 들어, iptables PREROUTING 또는 nftables ingress hooks 또는 다른 패킷 처리 와 같은 항목이 발생합니다.
+마찬가지로 egress에서 tc BPF 프로그램은 전송을 위해 패킷을 드라이버에 전달 하기전 마지막 부분에서 실행이 되며 이 의미는 iptables POSTROUTING과
+같은 전통적인 iptables firewall hook 이후 패킷을 커널의 GSO 엔진에게 넘겨주기 전 부분을 설명하는내용입니다. 그러나 드라이버 변결을 요구하는 예외
+사항 중 하나는 tc BPF 프로그램을 오프로드 하는 것이며, 일반적으로 BPF 입력 컨텍스트, helper 기능 및 결정 코드의 차이로 인해 기능이 다르기 때문에
+오프로드된 XDP와 유사한 방식으로 SmartNIC에서 제공합니다.
+
+tc 계층에서 실행되는 BPF 프로그램은 cls_bpf classifier에서 실행됩니다. tc 용어는 BPF 연결 지점을 "classifier"로 설명하지만 cls_bpf가 수행
+할 수 있는 것을 충분하지 않는 표현을 하기 때문에 다소 오해의 소지가 있습니다. 즉, 완전히 프로그래밍 가능한 패킷 프로세서는 skb 메타 데이터 및 패킷 데이터를
+읽을 수있을뿐만 아니라 임의로 mangle하고 동작 판정으로 tc 처리를 종료 할 수 있습니다. 따라서 cls_bpf는 tc BPF 프로그램을 관리하고 실행하는 독립적인 엔티티로
+간주 될 수 있습니다. cls_bpf는 하나 이상의 tc BPF 프로그램을 보유 할 수 있습니다. Cilium이 cls_bpf 프로그램을 배포하는 경우 직접 실행 모드에서 지정된 hook에
+대해 단일 프로그램 만 연결합니다. 일반적으로 전통적인 TC 체계에는 classfier와 일치하는 하나 이상의 동작이 연결 된 classfier 와 동작 모듈간에 구분이 있으며,
+classfier 에게는 일치가 있는 경우 트리거됩니다. 소프트웨어 데이터 경로에서 tc를 사용하는 현대 세계에서 이 모델은 복잡한 패킷 처리에 대해서는 확장 되지 않습니다.
+cls_bpf에 연결 된 tc BPF 프로그램이 완전히 독립적 인 경우, 파싱 및 액션 프로세스를 효과적으로 단일 단위로 통합 합니다. cls_bpf의 직접 행동 모드(direct-action mode)
+덕분에, 그것은 tc 액션 결정을 반환하고, 처리 파이프 라인을 즉시 종료합니다. 이를 통해 작업의 선형 반복을 피함으로써 네트워킹 데이터 경로에서 확장 가능한 프로그래밍
+가능한 패킷 처리를 구현할 수 있습니다. cls_bpf는 이러한 고속 경로가 가능한 tc 계층의 유일한 "classifier" 모듈 입니다. XDP BPF 프로그램과 마찬가지로
+tc BPF 프로그램은 네트워크 트래픽을 방해하거나 서비스를 다시 시작하지 않고 cls_bpf를 통해 런타임에 atomically하게 업데이트 될 수 있습니다.
+
+cls_bpf 자체가 연결 될 수 있는 tc ingress 와 egress 훅은 sch_clsact 라는 preseudo qdisc에 의해 관리됩니다. 이는 ingress 및 egress tc hook를
+모두 관리 할 수 있으므로, ingress qdisc의 drop-in 대체 및 적절한 상위 집합 입니다. __dev_queue_xmit()에서 tc의 egress hook의 경우 커널의 q
+disc root lock 아래에서 실행되지 않는다고 강조하는 것이 중요합니다. 따라서, tc ingress 및 egress hook은 고속 경로에서 잠금없는 방식으로 실행됩니다.
+두 경우 모두 선점이 비활성화되고 RCU 읽기 측에서 실행이 발생합니다.
+
+일반적으로 egress에는 넷디바이스에 연결된 qdisc가 있으며,예를 들어 sch_mq, sch_fq, sch_fq_codel 또는 sch_htb와 같이 하위클래스 를 포함하는
+classical qdisc 인 패킷을 역다중화 판정을 결정하는 패킷 분류 메커니즘이 필요합니다.
+
+이것은 tc classier를 호출하는 tcf_classify() 호출에 의해 처리 됩니다.이러한 경우 cls_bpf를 연결하여 사용할 수도 있습니다.
+이러한 작업은 대부분 qdisc root lock 아래에서 수행 되며 lock 경합의 영향을 받을 수 있습니다. sch_clsact qdisc의 egress hook는 훨씬 빠르지 만,
+기존의 egress qdisc와는 완전히 독립적으로 작동합니다. 따라서 sch_htb와 같은 경우 sch_clsact qdisc는 qdisc root lock 외부의 tc BPF를 통해
+과도한 패킷 분류를 수행 할 수 있습니다. skb-> mark 또는 skb-> priority를 설정하면 sch_htb는 root lock 아래 비용이 많이 발생하는 패킷 분류 없이
+평면 매핑 만 필요 하므로 경합이 줄어 듭니다. 오프로드 된 tc BPF 프로그램은 이전 로드 된 BPF 프로그램이 SmartNIC 드라이버에서 주입되어 NIC에서
+기본적으로 실행되는 cls_bpf와 함께 sch_clsact의 경우에 지원됩니다. 직접 실행 모드에서 작동하는 cls_bpf 프로그램 만이 오프로드 되도록 지원됩니다.
+cls_bpf는 단일 프로그램의 오프로딩 만 지원하며 여러 프로그램을 오프로드 할 수 없습니다. 또한 ingress hook만으로 BPF 프로그램을 오프로드 할 수 있습니다.
+하나의 cls_bpf 인스턴스는 여러 tc BPF 프로그램을 내부적으로 가질수 있습니다. 이 경우 TC_ACT_UNSPEC 프로그램 리턴 코드는 해당 목록의 다음
+tc BPF 프로그램으로 계속 실행됩니다. 그러나 이는 여러 프로그램이 패킷을 반복해서 구문 분석해야 성능이 저하된다는 단점이 있습니다.
+
+BPF program return codes
+tc ingress 및 egress hook는 tc BPF 프로그램이 사용할 수있는 동일한 작업 결정 반환 공유합니다.
+이 내용에 대해서는 linux/pkt_cls.h 시스템 헤더에 정의되어 있습니다 :
+
+#define TC_ACT_UNSPEC         (-1)
+#define TC_ACT_OK               0
+#define TC_ACT_SHOT             2
+#define TC_ACT_STOLEN           4
+#define TC_ACT_REDIRECT         7
+
+두개의 hook에서도 사용되는 시스템 헤더 파일에서 사용 할수 있는 몇가지 액션 TC_ACT_* 결정이 더 있습니다. 그러나
+언급한 몇가지 행동은 위의 것과 동일한 의미를 공유합니다.(역자 주: 몇가지 더 있는 액션에 대해서 찾아 보았습니다.)
+@include/uapi/linux/pkt_cls.h
+#define TC_ACT_UNSPEC   (-1)
+#define TC_ACT_OK               0
+#define TC_ACT_RECLASSIFY       1
+#define TC_ACT_SHOT             2
+#define TC_ACT_PIPE             3
+#define TC_ACT_STOLEN           4
+#define TC_ACT_QUEUED           5
+#define TC_ACT_REPEAT           6
+#define TC_ACT_REDIRECT         7
+#define TC_ACT_TRAP             8 /* 하드웨어 경로의 경우 이는 "trap to cpu"를 의미하며
+* 하드웨어에서 프레임을 더 이상 처리하지 않습니다.
+* 소프트웨어 경로의 경우 이값은 TC_ACT_STOLEN
+* 와 같은 것을 의미 하며, skb를 버리고,
+* 모든것이 정상적인 것 처럼 행동 합니다.
+*/
+#define TC_ACT_VALUE_MAX        TC_ACT_TRAP
+
+tc BPF 관점에서 의미는 TC_ACT_OK 와 TC_ACT_RECLASSIFY는
+세 가지 TC_ACT_STOLEN, TC_ACT_QUEUED 및 TC_ACT_TRAP opcode와 동일한 의미를 가집니다.
+따라서 이 경우 두 그룹에 대한 TC_ACT_OK 및 TC_ACT_STOLEN 연산 코드만 설명합니다.
+
+결정 코드에 대해서 TC_ACT_UNSPEC으로 시작합니다. 이것은 "지정되지 않은 동작"의 의미를 가지며 다음과 같은
+세 가지 경우에 사용됩니다.
+i) 오프로드 된 tc BPF 프로그램이 연결되고 오프로드 된 프로그램에 대한 cls_bpf 표현이
+TC_ACT_UNSPEC을 반환하는 tc ingress hook이 실행되는 경우,
+ii) 다중 프로그램의 경우 cls_bpf에있는 다음 tc BPF 프로그램을 계속 진행되는 경우,
+후자는 오프로드 된 경우에만 실행되는 다음
+tc BPF 프로그램에서 TC_ACT_UNSPEC이 계속되는 시점인 i)에서 오프로드 된 tc
+BPF 프로그램과 함께 작동합니다.
+
+마지막으로 중요한 것은, iii) TC_ACT_UNSPEC은 단일 프로그램의 경우에도 커널에 부가적인 부작용없이 skb
+계속 진행 하도록 알려 주는 용도로 사용됩니다. TC_ACT_UNSPEC은 TC_ACT_OK 결정 코드 와 매우 유사 하며,
+즉, ingress 에서 스택의 상위 레이어로 skb를 전달하거나, egress에서 전송하기 위해 네트워킹
+디바이스 드라이버로 내리는 행동을 합니다.
+
+TC_ACT_OK의 유일한 차이점은 TC_ACT_OK 가 tc BPF 프로그램 세트의 classid를 기반으로 skb->tc_index 를 설정한다는 것입니다.
+후자는 BPF 컨텍스트에서 skb->tc_classid를 통해 tc BPF 프로그램 자체에서 설정됩니다. TC_ACT_SHOT 명령은 커널에게
+패킷을 버리게 하며, 즉 네트워킹 스택의 상위 레이어는 진입시skb를 전혀 볼 수 없으며 유사하게 패킷은 egress에서 전송을 위해
+제출되지 않습니다.
+
+TC_ACT_SHOT 및 TC_ACT_STOLEN은 근본적으로 유사하지만 몇 가지 차이점이 있습니다:
+TC_ACT_SHOT는 kfree_skb()를 통해 skb가 해제 되었고, 즉각적인 피드백을 위해 발신자에게 NET_XMIT_DROP를 반환하지만
+TC_ACT_STOLEN은 consume_skb()를 통해 skb를 해제하고 NET_XMIT_SUCCESS를 통해 전송이 성공했다고 상위 계층처럼 가장합니다.
+
+따라서 kfree_skb()의 흔적을 기록하는 perf 모니터는 TC_ACT_STOLEN의 버리는 표시를 보지 않으며, 이 의미는 skb가 "
+사용"되거나 대기하지만 확실히 "삭제"되지 않았기 때문에 입니다.
+
+마지막으로 tc BPF 프로그램에서 사용할 수있는 TC_ACT_REDIRECT 동작도 있습니다. 이렇게 하면 skb를 bpf_redirect() helper와 함께
+동일한 또는 다른 장치의 ingress 또는 egress 경로로 리디렉션 할 수 있습니다. 패킷을 다른 장치의 ingress 또는 egress 방향으로 주입
+할 수 있기 때문에 BPF를 사용한 패킷 전달에서 완전한 유연성을 얻을 수 있습니다.
+네트워킹 장치 자체가 아닌 대상 네트워킹 장치에 대한 요구 사항이 없으므로, 대상 장치에서 cls_bpf의 다른 인스턴스 또는 다른 제한 사항을
+실행할 필요가 없습니다.
+
+tc BPF FAQ
+이 절에는 자주 질문하는 tc BPF 프로그램과 관련된 몇 가지 질문과 대답이 있습니다.
+
+질문 : 액션 모듈로 "act_bpf"는 무엇입니까? 여전히 관련이 있습니까?
+답변 : 그렇지 않습니다. cls_bpf와 act_bpf는 tc BPF 프로그램에 대해 동일한 기능을 공유하지만
+cls_bpf는 act_bpf의 적절한 수퍼 세트 이며, 더 유연합니다. tc가 작동하는 방식은 tc 액션을 tc 분류 자에 연결되어야 한다는 것입니다.
+cls_bpf와 동일한 유연성을 얻으려면 act_bpf를 cls_matchall 분류 자에 연결 해야합니다. 이름에서 알 수 있듯이, 이것은 연결 된
+tc 작업 처리를 위해 모든 패킷에서 일치합니다. act_bpf의 경우 직접 실행 모드에서 cls_bpf를 직접 사용하는 것보다 패킷 처리가 덜 효율적 입니다.
+act_bpf가 cls_bpf 또는 cls_matchall이 아닌 다른 분류 자의 설정에서 사용 되면, tc 분류 자의 동작 특성으로 인해 더 나쁜 성능을 보입니다.
+분류자 A가 불일치 하는 경우, 패킷은 분류자 B로 전달되며, 패킷등을 다시 패싱 되므로, 일반적인 경우에 패킷은 이러한 일치를 찾아 act_bpf를
+실행하기 위해 최악의 경우 N개의 분류기를 통과해야 하는 선형 처리가 있게 됩니다. 따라서 act_bpf는 그다지 중요하지 않습니다.
+또한 act_bpf는 cls_bpf와 비교하여 tc 오프 로딩 인터페이스를 제공하지 않습니다.
+
+질문 : 직접 행동 모드(direct-action mode)가 아닌 cls_bpf를 사용하는 것이 좋습니다?
+답변 : 아니요. 답변은 복잡한 처리를 위해 확장 할 수 없다는 점에서 위의 것과 비슷합니다.
+tc BPF는 이미 효율적으로 자체적으로 필요한 모든 것을 수행 할 수 있으므로 직접 실행 모드 이외의 다른 기능은 필요하지 않습니다.
+
+질문 : 오프로드 된 cls_bpf와 오프로드 된 XDP에서 성능 차이가 있습니까?
+답변 : 아니요. 둘 다 SmartNIC에 대한 오프로드를 처리하는 커널의 동일한 컴파일러를 통해 주입이 됩니다. 두 가지 모두의 로딩 메커니즘도 비슷합니다.
+따라서 BPF 프로그램은 NIC에서 기본적으로 실행될 수 있도록 동일한 대상 명령 세트로 변환됩니다.
+두 개의 tc BPF 및 XDP BPF 프로그램 유형은 서로 다른 기능 세트를 가지므로 사용 사례에 따라 다른 서비스 유형 (예 : 오프로드 경우)의 가용성으로 인해 다른 서비스 유형을 선택할 수 있습니다.
+
+tc BPF의 사용 사례
+
+tc BPF 프로그램의 주요 사용 사례 중 일부 내용이 하위 절에 나와 있습니다.
+또한 여기에서는 목록이 전체적이지는 않지만, 프로그래밍 가능성 과 효율성을 감안할 때 매우 특정한 사용자 사례를 해결하기 위해
+오케스트레이션 시스템에 맞춤화되고 통합될 수 있습니다. XDP 사용 사례가 일부 겹칠 수 있지만 tc BPF와 XDP BPF는 상호 보완적이며 동시에 해결할 주어진 문제에
+가장 적합한 두 가지 방법을 주어진 문제를 풀기에 가장 적합하게 동시에 또는 한 번에 사용할 수 있습니다.
+
+* 컨테이너에 대한 정책 시행
+tc BPF 프로그램이 적합한 한 응용 프로그램은 정책 집행, 사용자 정의 방화벽 또는 컨테이너 또는 포드에 대한 유사한 보안 대책을 각각 구현하는 것입니다.
+이전의 경우, 컨테이너 격리는 호스트의 초기 네임 스페이스와 전용 컨테이너의 네임 스페이스를 연결하는 네트워크 장치가 있는 네트워크 네임 스페이스를 통해 구현됩니다.
+veth 인터페이스 쌍의 한쪽 끝은 컨테이너의 네임 스페이스로 이동 되었지만 다른 쪽 끝은 호스트의 초기 네임 스페이스에 남아 있기 때문에, 컨테이너로부터의 모든 네트워크 트래픽은
+호스트 측면의 tc ingress 및 egress hook에 연결 가능한 veth 디바이스를 통과 해야 합니다. 컨테이너로 들어오는 네트워크 트래픽은 호스트를 향한 경로로 전달되지만,
+컨테이너에서 들어오는 네트워크 트래픽은 호스트를 향한 경로로 전달됩니다. 컨테이너로 들어오는 네트워크 트래픽은 호스트 측면 veth의 egress hook을 통과하지만 컨테이너에서
+오는 네트워크 트래픽은 호스트 측면 veth의 ingress hook을 통과합니다.
+veth 장치와 같은 가상 장치의 경우, XDP는 커널이 여기의 skb에서만 작동하고 일반 XDP는 복제 된 skb와 함께 작동하지 않는 몇 가지 제한 사항이 있으므로 이 경우 적합하지 않습니다.
+후자는 generic XDP hook이 단순히 우회되는 재전송을 위한 데이터 세그먼트를 유지하기 위해 TCP/IP 스택에서 많이 사용됩니다. 또한 generic XDP는 전체 skb를 선형화 해야 성능이
+크게 저하됩니다. 반면에 tc BPF는 skb 입력 컨텍스트 케이스를 전문으로 하므로 더 유연하며, 따라서 generic XDP의 한계에 염두할 필요가 없습니다.
+
+* 포워딩 그리고 로드벨런싱
+포워딩 및로드 밸런싱 사용 사례는 서버와 클라이언트 간의 트래픽 보다는 컨테이너 와 컨테이너 사이의 워크로드를 타겟으로 하며,
+(두 기술이 어느 경우에도 사용될 수 있지만,) XDP 와 매우 유사합니다. XDP는 ingress 측에서만 사용할 수 있으므로 tc BPF 프로그램은 특히 egress에서 적용되는
+추가 사용 사례를 허용 하며, 예를 들어 컨테이너 기반 트래픽은 초기 네임 스페이스에서 BPF를 통해 송신 측에서 이미 NAT된 및 로드 밸런싱 될 수 있으며, 이것은
+컨테이너 자체에 투명하게 이루어 집니다. egress 트래픽은 커널의 네트워킹 스택의 특성 때문에 sk_buff 구조체를 기반으로 하므로 패킷 재작성 및 리디렉션는
+tc BPF에서 적합합니다. BPF는 bpf_redirect() helper 함수를 활용하여 포워딩 로직를 대신 받아 패킷을 다른 네트워킹 장치의 ingress 또는 egress 경로로
+푸시 할 수 있습니다. 따라서 모든 브리지 형 장치는 forwarding fabric으로 tc BPF 활용으로 불필요하게 됩니다
+
+* 흐름 샘플링, 모니터링
+XDP의 경우와 마찬가지로 플로우 샘플링 및 모니터링은 BPF 프로그램이 맞춤 데이터, 전체 또는 절단 된 패킷 내용, 또는 사용자 공간 응용 프로그램에 이르기까지 푸시
+할 수있는 고성능의 잠금없는 CPU 당 메모리 매핑 된 perf ring 버퍼를 통해 실현 될 수 있습니다. tc BPF 프로그램에서 이것은 bpf_xdp_event_output()과
+같은 대표 함수 와 의미를 가진 bpf_skb_event_output() BPF help 함수를 통해 실현됩니다. 주어진 tc BPF 프로그램은 XDP BPF 사용 사례에서 ingress 만
+아닌 ingress와 egress에 연결 될수 있으며, 두 개의 tc 후크는 (일반) 네트워킹 스택의 가장 낮은 계층에 있으며,이를 통해 특정 노드의 모든 네트워크 트래픽을 양방향
+모니터링 할 수 있습니다. 이것은 tcpdump와 wireshark가 skb를 복제할 필요 없으며, 프로그래밍 가능성 측면에서 보다 유연한 cBPF 사용 사례와 다소 관련될 수 있으며,
+예를 들어 BPF는 이미 링 버퍼에 푸시 된 패킷에 대해 사용자 공간 뿐만 아니라 사용자 annotations까지 모두를 푸시하는 대신에 커널 내 aggregation을 수행 할 수 있습니다.
+후자는 또한 Cilium에서 많이 사용되는데, 패킷 레이블에 컨테이너 레이블을 연관 시키려면 패킷 주석을 추가로 주석을 붙여야하며, 다양한 패킷을 처리해야하는
+이유(정책 위반 등) 때문에 다양한 context을 제공 해야합니다.
+
+* 패킷 스케줄러 사전 처리
+sch_clsact의 egress hook 인 sch_handle_egress()는 커널의 qdisc 루트 잠금을 취하기 바로 전에 실행 되며,
+따라서 tc BPF 프로그램은 패킷이 sch_htb와 같은 진짜 완전한 qdisc로 전송되기 전에 heavy lifting packet classification 및
+mangling을 동작하는 데 사용될 수 있습니다. 이러한 sch_clsact 와 sch_htb 와 같은 실제 qdisc와의 상호 작용은 나중에 sch_clsact의
+egress hook가 잠금을 사용하지 않고 실행되기 때문에 전송 단계에서 나중에 발생하는 lock contention을 줄일 수 있습니다.
+
+tc BPF뿐만 아니라 XDP BPF 프로그램의 한 구체적인 예는 Cilium입니다. Cilium은 Docker 및 Kubernetes와 같은 Linux 컨테이너 관리 플랫폼을
+사용하여 배포 된 응용 프로그램 서비스 간의 네트워크 연결을 투명하게 보호 하기위한 오픈 소스 소프트웨어이며 Layer 3 및 Layer 7에서 작동합니다.
+Cilium의 핵심은 BPF를 사용하여 정책 시행과 로드 밸런싱 및 모니터링을 구현합니다.
+
+Slides: https://www.slideshare.net/ThomasGraf5/dockercon-2017-cilium-network-and-application-security-with-bpf-and-xdp
+Video: https://youtu.be/ilKlmTDdFgk
+Github: https://github.com/cilium/cilium
+
+드라이버 지원
+
+tc BPF 프로그램은 커널의 네트워킹 스택에서 시작되고 드라이버에서 직접 시작되지 않으므로 추가 드라이버 수정이 필요하지 않으므로 모든 네트워킹 장치에서
+실행할 수 있습니다. 아래 나열된 유일한 예외는 tc BPF 프로그램을 NIC에 오프 로딩하는 것을 뜻합니다.
+
+오프로드 된 tc BPF를 지원하는 드라이버
+
+Netronome
+nfp[2]
+
+tc BPF 프로그램을 작성하고 로딩하는 예제는 각 도구 아래의 toolchain 섹션에 포함되어 있습니다.
+
+더 읽을 거리
+
+문서, 프로젝트, 대담, 논문 및 추가 자료의 언급 목록은 완전하지 않을 수 있습니다. 따라서, 목록을 완료하기 위해 pull 요청을 열어 주시기 바랍니다.
+
+커널 개발자 자주 묻는 질문
+Documentation/bpf/ 에서 Linux 커널은 주로 BPF 하위 시스템과 관련된 커널 개발자를 대상으로하는 두 개의 FAQ 파일을 제공합니다.
+
+
+BPF Devel 자주 묻는 질문 :이 문서는 주로 패치 제출 과정 주변 정보와 BPF 커널 트리, 안정 트리 및 버그보고 워크 플로우, LLVM 등을 통해 BPF의
+확장성 및 상호 작용의 주변에 관련된 질문을 제공합니다.
+https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/bpf/bpf_devel_QA.txt
+
+BPF Design 자주 묻는 질문 :이 문서는 명령어 세트, 검증에 관련된 BPF 설계 결정, 호출 규칙, JITs 등 주변 자주 묻는 질문에 대한 답변을 하려고 합니다.
+https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/bpf/bpf_design_QA.txt
+
+BPF를 사용하는 프로젝트
+
+다음 목록에는 BPF를 사용하는 오픈 소스 프로젝트 중 하나가 포함되어 있으며 각각 BPF에 대한 도구을 제공합니다. 이 문맥에서 eBPF 명령어 세트는 기존
+cBPF를 활용하는 프로젝트 대신 특별히 의미가 있습니다.
+
+Tracing
+
+* BCC
+BCC는 BPF Compiler Collection의 약자로, 핵심 기능은 kprobes, kretprobes, tracepoints, uprobes, uretprobes 및 사용자 레벨에서 정적으로
+정의 된 추적(USDT) probe를 기반으로하는 커널 인프라에 BPF 프로그램을 연결하여 사용하기 쉽고 효율적인 커널 추적 유틸리티 세트를 제공하는 것입니다.
+이 컬렉션은 응용 프로그램, 시스템 라이브러리, 다양한 커널 하위 시스템에 이르기까지 스택의 여러 계층을 대상으로하는 수백 가지 도구를 제공하여 시스템의 성능 특성
+또는 문제를 분석합니다. 또한 BCC는 다른 프로젝트의 라이브러리로 사용하기 위해 API를 제공합니다.
+
+https://github.com/iovisor/bcc
+
+* bpftrace
+
+bpftrace는 Linux 용 DTrace 스타일의 동적 추적 도구이며 LLVM을 백엔드로 사용하여 스크립트를 BPF 바이트 코드로 컴파일하고, BCC를 사용하여 커널의
+BPF 추적 인프라와 상호 작용합니다.원시 BCC와 비교하여 추적 스크립트를 구현하기 위한 고급 언어를 제공합니다.
+
+https://github.com/ajor/bpftrace
+
+* perf
+
+Linux 커널 커뮤니티에서 커널 소스 트리의 일부로 개발 한 perf 도구는 BPF의 수집된 된 데이터를 검색하고 처리 할 수있는 기존의 perf 레코드 하위 명령을 통해
+추적 BPF 프로그램을 로드하는 방법을 제공 하며, 예를 들어 perf 스크립트 및 다른 방법을 통해 perf.data에 저장됩니다.
+
+https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/perf
+
+* ply
+
+ply는 yore의 'Little Language'접근 방식을 따르는 추적 도구이며 커널의 kprobes 및 tracepoint에 연결된 Linux BPF 프로그램에
+ply 스크립트를 컴파일합니다. 스크립트는 DTrace와 확장 awk에 크게 영향을받은 C와 유사한 구문을 사용합니다. ply는 의존성을 매우 최소한으로 유지하고 빌드시
+flex 및 bison 만 필요하며 런타임에는 libc 만 필요합니다.
+
+https://github.com/wkz/ply
+
+* systemtap
+systemtap은 성능 또는 기능적 문제를 진단하고 분석하기 위해 데이터를 추출, 필터링 및 요약하기위한 스크립트 언어 및 도구입니다.
+stapbpf라는 BPF 백엔드는 추가 컴파일러가 필요없이 스크립트를 BPF로 직접 변환하고 프로브를 커널에 주입합니다. 따라서 stap의 커널 모듈과 달리
+외부 종속성이 없으며, 커널 모듈을 따로 로드 할 필요도 없습니다.
+
+https://sourceware.org/git/gitweb.cgi?p=systemtap.git;a=summary
+
+* PCP
+
+Performance Co-Pilot (PCP)은 수집 된 시스템의 성능 측정을 실시간으로 분석하거나 기록 데이터를 사용하여 다양한 에이전트를 통해
+측정을 수집 할 수있는 시스템 성능 및 분석 프레임 워크입니다.
+pmdabcc를 사용하면 PCP에는 BPF 및 BCC를 통해 커널에서 데이터를 추출하는 BCC 기반 성능 측정 도메인 에이전트가 있습니다.
+
+https://github.com/performancecopilot/pcp
+
+* Weave Scope
+
+Weave Scope는 kprobes와 함께 BPF를 사용하여 프로세스, 네트워킹 연결 또는 기타 시스템 데이터에
+대한 데이터를 수집하는 클라우드 모니터링 도구입니다. Weave Scope는 BPF ELF 파일을 커널에 로드하기 위해 gobpf 라이브러리의 맨 위에서 작동하며
+TCP 이벤트를 추적하기 위해 연결, 승인 및 닫기 호출을 모니터링하는 tcptracer-bpf 도구와 함께 제공됩니다.
+
+https://github.com/weaveworks/scope
+
+Networking
+
+* Cilium
+
+Cilium은 응용 프로그램 컨테이너 또는 프로세스와 같은 응용 프로그램 작업 부하간에
+네트워크 연결 및 로드 벨런스 조정을 제공하고 투명하게 보호합니다. Cilium은 레이어 3/4에서 작동하여 기존 네트워킹 및
+보안 서비스 뿐만 아니라 레이어 7을 제공하여 HTTP, gRPC 및 Kafka와 같은 최신 응용 프로그램 프로토콜의
+보호 및 보안을 유지합니다. Kubernetes 및 Mesos와 같은 오케스트레이션 프레임 워크에 통합되어 있으며,
+BPF는 커널의 네트워킹 데이터 경로에서 작동하는 Cilium의 기본 부분입니다.
+
+https://github.com/cilium/cilium
+
+* Suricata
+
+Suricata는 네트워크 IDS, IPS 및 NSM 엔진이며, BPF를 기반으로 하는 로드 밸런서로서 특정 패킷을 처리하거나, 우회하기 위해
+BPF 필터로서 프로그래밍 가능한 세 가지 영역에서 BPF와 XDP를 활용합니다. 로드 밸런싱 및 XDP가 높은 패킷 속도로 바이 패스 또는
+drop 메커니즘을 구현할 수 있습니다.
+
+http://suricata.readthedocs.io/ko/latest/capture-hardware/ebpf-xdp.html
+https://github.com/OISF/suricata
+
+* systemd
+systemd는 IPv4/v6 주소을 허용하고, BPF의 cgroup ingress 및 egress hook을 기반으로하는
+systemd 장치에 대한 네트워크 액세스 제어를 구현합니다. 주소는 패킷/바이트를 기반으로하며
+허용/거부 규칙에 대한 주소 접두어로 ACL을 지정할 수 있습니다. 자세한 정보는 다음에서 찾을 수 있습니다 :
+
+http : / /pointer.net/blog/ip-accounting-and-access-lists-with-systemd.html
+https://github.com/systemd/systemd
+
+* iproute2
+
+iproute2는 LLVM이 ELF 파일을 커널에 생성 할 때 BPF 프로그램을 로드하는 기능을 제공합니다.
+iproute2는 일반적인 BPF 로더 백엔드를 통해 tc BPF 프로그램뿐만 아니라 XDP BPF 프로그램도 지원합니다.
+tc 및 ip 명령 행 유틸리티는 사용자에게 로더 및 자가 검사 기능을 사용을 가능하게 합니다.
+
+https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/
+
+* p4c-xdp
+
+p4c-xdp는 BPF 및 XDP를 대상으로하는 P4 컴파일러 백엔드를 제공합니다. P4는 NIC, 어플라이언스 또는 스위치와 같은
+프로그램 가능한 네트워크 요소의 데이터 플레인에 의해 패킷이 처리되는 방법을 설명하고
+p4c-xdp의 도움으로 도메인 에 따른 언어입니다. P4 프로그램은 다음에 의해 컴파일 될 수 있는 BPF C 프로그램으로 변환 될 수 있습니다.
+clang/LLVM을 사용하고 고성능 패킷 처리를 위해 XDP 계층의 커널에 BPF 프로그램으로 로드됩니다.
+
+https://github.com/vmware/p4c-xdp
+
+기타
+
+* LLVM
+
+clang/LLVM은 C BPF 프로그램을 ELF 파일에 포함 된 BPF 명령어로 컴파일하기 위해 BPF 백엔드를 제공합니다.
+LLVM BPF 백엔드는 Linux 커널의 BPF 핵심 인프라와 함께 개발되며 동일한 커뮤니티에서 관리합니다.
+clang/LLVM은 BPF 프로그램 개발을 위한 툴체인의 핵심 부분입니다.
+
+https://llvm.org/
+
+* libbpf
+
+libbpf는 커널 소스 트리의 일부로 Linux 커널 커뮤니티에서 개발 한 일반 BPF 라이브러리이며, LLVM에서 생성 된 ELF 파일의 BPF 프로그램을 로드하여 커널에 연결 할 수 있습니다.
+라이브러리는 perf 및 bpftool과 같은 다른 커널 프로젝트에서 사용됩니다.
+
+https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/lib/bpf
+
+* bpftool
+
+bpftool은 BPF 프로그램과 BPF 맵을 자가 검사 하고 디버깅 하기위한 주요 도구이며, libbpf는 리눅스 커널 커뮤니티에 의해 개발되었습니다.
+시스템의 모든 활성 BPF 프로그램 및 맵을 덤프하고 프로그램에서 BPF 또는 주입된 BPF 명령어를 덤프 및 역어셈블 하고 시스템의 BPF 맵을 덤프 및 조작 할 수 있습니다.
+bpftool은 BPF 파일 시스템과의 상호 작용을 지원하며 객체 파일에서 커널에 다양한 프로그램 타입을 로드 합니다.
+
+https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/bpf/bpftool
+
+* gobpf
+
+gobpf는 ELF 파일에서 BPF 프로그램을 로드하고 사용하기 위해 저수준 루틴 뿐 아니라 bcc 프레임 워크에 대한 바인딩을 제공합니다.
+
+https://github.com/iovisor/gobpf
+
+
+* ebpf_asm
+
+ebpf_asm은 Intel 계열 어셈블리 구문으로 작성된 BPF 프로그램 용 어셈블러를 제공 하므로,
+clang/LLVM 도구 체인을 이용하지 않고, 프로그램이 작고 단순한 경우 어셈블리에서 BPF 프로그램을 직접 작성할 수있는 대안을 제공합니다.
+
+https://github.com/solarflarecom/ebpf_asm
+
+XDP Newbies
+
+David S. Miller가 xdp-newbies 메일 링리스트 (http://vger.kernel.org/vger-lists.html#xdp-newbies)에 대한 XDP 및 BPF 다양한 파트에 대해 자세히 설명한 게시물이 있습니다:
+
+4. May 2017,
+BPF Verifier Overview, David S. Miller, https://www.spinics.net/lists/xdp-newbies/msg00185.html
+
+3. May 2017,
+Contextually speaking…, David S. Miller, https://www.spinics.net/lists/xdp-newbies/msg00181.html
+
+2. May 2017,
+bpf.h and you…, David S. Miller, https://www.spinics.net/lists/xdp-newbies/msg00179.html
+
+1. Apr 2017,
+XDP example of the day, David S. Miller, https://www.spinics.net/lists/xdp-newbies/msg00009.html
+
+BPF 뉴스 레터
+Alexander Alemayhu는 주 마다 대략 한 번 BPF를 관련된 뉴스 레터를 작성하여 Linux 커널 영역 와 사용자 영역 의 주변 에코시스템에 대한 BPF 관련 최신 개발 내용을 다루었습니다.
+모든 BPF 업데이트 뉴스 레터 (01 - 12)는 다음에서 찾을 수 있습니다.
+https://cilium.io/blog/categories/BPF%20Newsletter
+
+팟케스트
+
+부분적으로 BPF를 다루는 많은 팟케스트가 있었습니다.
+불완전한 목록:
+
+5. Feb 2017,
+Linux Networking Update from Netdev Conference, Thomas Graf, Software Gone Wild, Show 71,
+http://blog.ipspace.net/2017/02/linux-networking-update-from-netdev.html http://media.blubrry.com/ipspace/stream.ipspace.net/nuggets/podcast/Show_71-NetDev_Update.mp3
+
+4. Jan 2017,
+The IO Visor Project, Brenden Blanco, OVS Orbit, Episode 23, https://ovsorbit.org/#e23 https://ovsorbit.org/episode-23.mp3
+
+3. Oct 2016,
+Fast Linux Packet Forwarding, Thomas Graf, Software Gone Wild, Show 64, http://blog.ipspace.net/2016/10/fast-linux-packet-forwarding-with.html http://media.blubrry.com/ipspace/stream.ipspace.net/nuggets/podcast/Show_64-Cilium_with_Thomas_Graf.mp3
+
+2. Aug 2016,
+P4 on the Edge, John Fastabend, OVS Orbit, Episode 11, https://ovsorbit.org/#e11 https://ovsorbit.org/episode-11.mp3
+
+1. May 2016,
+Cilium, Thomas Graf, OVS Orbit, Episode 4, https://ovsorbit.org/#e4 https://ovsorbit.benpfaff.org/episode-4.mp3
+
+블로그 게시물
+다음 (불완전한)목록에는 BPF, XDP 및 관련 프로젝트 관련 블로그 게시물이 포함됩니다:
+
+35. May 2017,
+An entertaining eBPF XDP adventure, Suchakra Sharma, https://suchakra.wordpress.com/2017/05/23/an-entertaining-ebpf-xdp-adventure/
+
+34. May 2017,
+eBPF, part 2: Syscall and Map Types, Ferris Ellis, https://ferrisellis.com/posts/ebpf_syscall_and_maps/
+
+33. May 2017,
+Monitoring the Control Plane, Gary Berger, http://firstclassfunc.com/2017/05/monitoring-the-control-plane/
+
+32. Apr 2017,
+USENIX/LISA 2016 Linux bcc/BPF Tools, Brendan Gregg, http://www.brendangregg.com/blog/2017-04-29/usenix-lisa-2016-bcc-bpf-tools.html
+
+31. Apr 2017,
+Liveblog: Cilium for Network and Application Security with BPF and XDP, Scott Lowe, http://blog.scottlowe.org//2017/04/18/black-belt-cilium/
+
+30. Apr 2017,
+eBPF, part 1: Past, Present, and Future, Ferris Ellis, https://ferrisellis.com/posts/ebpf_past_present_future/
+
+29. Mar 2017,
+Analyzing KVM Hypercalls with eBPF Tracing, Suchakra Sharma, https://suchakra.wordpress.com/2017/03/31/analyzing-kvm-hypercalls-with-ebpf-tracing/
+
+28. Jan 2017,
+Golang bcc/BPF Function Tracing, Brendan Gregg, http://www.brendangregg.com/blog/2017-01-31/golang-bcc-bpf-function-tracing.html
+
+27. Dec 2016,
+Give me 15 minutes and I’ll change your view of Linux tracing, Brendan Gregg, http://www.brendangregg.com/blog/2016-12-27/linux-tracing-in-15-minutes.html
+
+26. Nov 2016,
+Cilium: Networking and security for containers with BPF and XDP, Daniel Borkmann, https://opensource.googleblog.com/2016/11/cilium-networking-and-security.html
+
+25. Nov 2016,
+Linux bcc/BPF tcplife: TCP Lifespans, Brendan Gregg, http://www.brendangregg.com/blog/2016-11-30/linux-bcc-tcplife.html
+
+24. Oct 2016,
+DTrace for Linux 2016, Brendan Gregg, http://www.brendangregg.com/blog/2016-10-27/dtrace-for-linux-2016.html
+
+23. Oct 2016,
+Linux 4.9’s Efficient BPF-based Profiler, Brendan Gregg, http://www.brendangregg.com/blog/2016-10-21/linux-efficient-profiler.html
+
+22. Oct 2016,
+Linux bcc tcptop, Brendan Gregg, http://www.brendangregg.com/blog/2016-10-15/linux-bcc-tcptop.html
+
+21. Oct 2016,
+Linux bcc/BPF Node.js USDT Tracing, Brendan Gregg, http://www.brendangregg.com/blog/2016-10-12/linux-bcc-nodejs-usdt.html
+
+20. Oct 2016,
+Linux bcc/BPF Run Queue (Scheduler) Latency, Brendan Gregg, http://www.brendangregg.com/blog/2016-10-08/linux-bcc-runqlat.html
+
+19. Oct 2016,
+Linux bcc ext4 Latency Tracing, Brendan Gregg, http://www.brendangregg.com/blog/2016-10-06/linux-bcc-ext4dist-ext4slower.html
+
+18. Oct 2016,
+Linux MySQL Slow Query Tracing with bcc/BPF, Brendan Gregg, http://www.brendangregg.com/blog/2016-10-04/linux-bcc-mysqld-qslower.html
+
+17. Oct 2016,
+Linux bcc Tracing Security Capabilities, Brendan Gregg, http://www.brendangregg.com/blog/2016-10-01/linux-bcc-security-capabilities.html
+
+16. Sep 2016,
+Suricata bypass feature, Eric Leblond, https://www.stamus-networks.com/2016/09/28/suricata-bypass-feature/
+
+15. Aug 2016,
+Introducing the p0f BPF compiler, Gilberto Bertin, https://blog.cloudflare.com/introducing-the-p0f-bpf-compiler/
+
+14. Jun 2016,
+Ubuntu Xenial bcc/BPF, Brendan Gregg, http://www.brendangregg.com/blog/2016-06-14/ubuntu-xenial-bcc-bpf.html
+
+13. Mar 2016,
+Linux BPF/bcc Road Ahead, March 2016, Brendan Gregg, http://www.brendangregg.com/blog/2016-03-28/linux-bpf-bcc-road-ahead-2016.html
+
+12. Mar 2016,
+Linux BPF Superpowers, Brendan Gregg, http://www.brendangregg.com/blog/2016-03-05/linux-bpf-superpowers.html
+
+11. Feb 2016,
+Linux eBPF/bcc uprobes, Brendan Gregg, http://www.brendangregg.com/blog/2016-02-08/linux-ebpf-bcc-uprobes.html
+
+10. Feb 2016,
+Who is waking the waker? (Linux chain graph prototype), Brendan Gregg, http://www.brendangregg.com/blog/2016-02-05/ebpf-chaingraph-prototype.html
+
+9. Feb 2016,
+Linux Wakeup and Off-Wake Profiling, Brendan Gregg, http://www.brendangregg.com/blog/2016-02-01/linux-wakeup-offwake-profiling.html
+
+8. Jan 2016,
+Linux eBPF Off-CPU Flame Graph, Brendan Gregg, http://www.brendangregg.com/blog/2016-01-20/ebpf-offcpu-flame-graph.html
+
+7. Jan 2016,
+Linux eBPF Stack Trace Hack, Brendan Gregg, http://www.brendangregg.com/blog/2016-01-18/ebpf-stack-trace-hack.html
+
+6. Sep 2015,
+Linux Networking, Tracing and IO Visor, a New Systems Performance Tool for a Distributed World, Suchakra Sharma, https://thenewstack.io/comparing-dtrace-iovisor-new-systems-performance-platform-advance-linux-networking-virtualization/
+
+5. Aug 2015,
+BPF Internals - II, Suchakra Sharma, https://suchakra.wordpress.com/2015/08/12/bpf-internals-ii/
+
+4. May 2015,
+eBPF: One Small Step, Brendan Gregg, http://www.brendangregg.com/blog/2015-05-15/ebpf-one-small-step.html
+
+3. May 2015,
+BPF Internals - I, Suchakra Sharma, https://suchakra.wordpress.com/2015/05/18/bpf-internals-i/
+
+2. Jul 2014,
+Introducing the BPF Tools, Marek Majkowski, https://blog.cloudflare.com/introducing-the-bpf-tools/
+
+1. May 2014,
+BPF - the forgotten bytecode, Marek Majkowski, https://blog.cloudflare.com/bpf-the-forgotten-bytecode/
+
+대담
+
+다음 (불완전한) 목록에는 BPF 및 XDP와 관련된 대담 및 회의 논문이 포함됩니다:
+
+44. May 2017,
+PyCon 2017, Portland, Executing python functions in the linux kernel by transpiling to bpf, Alex Gartrell, https://www.youtube.com/watch?v=CpqMroMBGP4
+
+43. May 2017,
+gluecon 2017, Denver, Cilium + BPF: Least Privilege Security on API Call Level for Microservices, Dan Wendlandt, http://gluecon.com/#agenda
+
+42. May 2017,
+Lund Linux Con, Lund, XDP - eXpress Data Path, Jesper Dangaard Brouer, http://people.netfilter.org/hawk/presentations/LLC2017/XDP_DDoS_protecting_LLC2017.pdf
+
+41. May 2017,
+Polytechnique Montreal, Trace Aggregation and Collection with eBPF, Suchakra Sharma, http://step.polymtl.ca/~suchakra/eBPF-5May2017.pdf
+
+40. Apr 2017,
+DockerCon, Austin, Cilium - Network and Application Security with BPF and XDP, Thomas Graf, https://www.slideshare.net/ThomasGraf5/dockercon-2017-cilium-network-and-application-security-with-bpf-and-xdp
+
+39. Apr 2017,
+NetDev 2.1, Montreal, XDP Mythbusters, David S. Miller, https://www.netdevconf.org/2.1/slides/apr7/miller-XDP-MythBusters.pdf
+
+38. Apr 2017,
+NetDev 2.1, Montreal, Droplet: DDoS countermeasures powered by BPF + XDP, Huapeng Zhou, Doug Porter, Ryan Tierney, Nikita Shirokov, https://www.netdevconf.org/2.1/slides/apr6/zhou-netdev-xdp-2017.pdf
+
+37. Apr 2017,
+NetDev 2.1, Montreal, XDP in practice: integrating XDP in our DDoS mitigation pipeline, Gilberto Bertin, https://www.netdevconf.org/2.1/slides/apr6/bertin_Netdev-XDP.pdf
+
+36. Apr 2017,
+NetDev 2.1, Montreal, XDP for the Rest of Us, Andy Gospodarek, Jesper Dangaard Brouer, https://www.netdevconf.org/2.1/slides/apr7/gospodarek-Netdev2.1-XDP-for-the-Rest-of-Us_Final.pdf
+
+35. Mar 2017,
+SCALE15x, Pasadena, Linux 4.x Tracing: Performance Analysis with bcc/BPF, Brendan Gregg, https://www.slideshare.net/brendangregg/linux-4x-tracing-performance-analysis-with-bccbpf
+
+34. Mar 2017,
+XDP Inside and Out, David S. Miller, https://github.com/iovisor/bpf-docs/raw/master/XDP_Inside_and_Out.pdf
+
+33. Mar 2017,
+OpenSourceDays, Copenhagen, XDP - eXpress Data Path, Used for DDoS protection, Jesper Dangaard Brouer, https://github.com/iovisor/bpf-docs/raw/master/XDP_Inside_and_Out.pdf
+
+32. Mar 2017,
+source{d}, Infrastructure 2017, Madrid, High-performance Linux monitoring with eBPF, Alfonso Acosta, https://www.youtube.com/watch?v=k4jqTLtdrxQ
+
+31. Feb 2017,
+FOSDEM 2017, Brussels, Stateful packet processing with eBPF, an implementation of OpenState interface, Quentin Monnet, https://fosdem.org/2017/schedule/event/stateful_ebpf/
+
+30. Feb 2017,
+FOSDEM 2017, Brussels, eBPF and XDP walkthrough and recent updates, Daniel Borkmann, http://borkmann.ch/talks/2017_fosdem.pdf
+
+29. Feb 2017,
+FOSDEM 2017, Brussels, Cilium - BPF & XDP for containers, Thomas Graf, https://fosdem.org/2017/schedule/event/cilium/
+
+28. Jan 2017,
+linuxconf.au, Hobart, BPF: Tracing and more, Brendan Gregg, https://www.slideshare.net/brendangregg/bpf-tracing-and-more
+
+27. Dec 2016,
+USENIX LISA 2016, Boston, Linux 4.x Tracing Tools: Using BPF Superpowers, Brendan Gregg, https://www.slideshare.net/brendangregg/linux-4x-tracing-tools-using-bpf-superpowers
+
+26. Nov 2016,
+Linux Plumbers, Santa Fe, Cilium: Networking & Security for Containers with BPF & XDP, Thomas Graf, http://www.slideshare.net/ThomasGraf5/clium-container-networking-with-bpf-xdp
+
+25. Nov 2016,
+OVS Conference, Santa Clara, Offloading OVS Flow Processing using eBPF, William (Cheng-Chun) Tu, http://openvswitch.org/support/ovscon2016/7/1120-tu.pdf
+
+24. Oct 2016,
+One.com, Copenhagen, XDP - eXpress Data Path, Intro and future use-cases, Jesper Dangaard Brouer, http://people.netfilter.org/hawk/presentations/xdp2016/xdp_intro_and_use_cases_sep2016.pdf
+
+23. Oct 2016,
+Docker Distributed Systems Summit, Berlin, Cilium: Networking & Security for Containers with BPF & XDP, Thomas Graf, http://www.slideshare.net/Docker/cilium-bpf-xdp-for-containers-66969823
+
+22. Oct 2016,
+NetDev 1.2, Tokyo, Data center networking stack, Tom Herbert, http://netdevconf.org/1.2/session.html?tom-herbert
+
+21. Oct 2016,
+NetDev 1.2, Tokyo, Fast Programmable Networks & Encapsulated Protocols, David S. Miller, http://netdevconf.org/1.2/session.html?david-miller-keynote
+
+20. Oct 2016,
+NetDev 1.2, Tokyo, XDP workshop - Introduction, experience, and future development, Tom Herbert, http://netdevconf.org/1.2/session.html?herbert-xdp-workshop
+
+19. Oct 2016,
+NetDev1.2, Tokyo, The adventures of a Suricate in eBPF land, Eric Leblond, http://netdevconf.org/1.2/slides/oct6/10_suricata_ebpf.pdf
+
+18. Oct 2016,
+NetDev1.2, Tokyo, cls_bpf/eBPF updates since netdev 1.1, Daniel Borkmann, http://borkmann.ch/talks/2016_tcws.pdf
+
+17. Oct 2016,
+NetDev1.2, Tokyo, Advanced programmability and recent updates with tc’s cls_bpf, Daniel Borkmann, http://borkmann.ch/talks/2016_netdev2.pdf http://www.netdevconf.org/1.2/papers/borkmann.pdf
+
+16. Oct 2016,
+NetDev 1.2, Tokyo, eBPF/XDP hardware offload to SmartNICs, Jakub Kicinski, Nic Viljoen, http://netdevconf.org/1.2/papers/eBPF_HW_OFFLOAD.pdf
+
+15. Aug 2016,
+LinuxCon, Toronto, What Can BPF Do For You?, Brenden Blanco, https://events.linuxfoundation.org/sites/events/files/slides/iovisor-lc-bof-2016.pdf
+
+14. Aug 2016,
+LinuxCon, Toronto, Cilium - Fast IPv6 Container Networking with BPF and XDP, Thomas Graf, https://www.slideshare.net/ThomasGraf5/cilium-fast-ipv6-container-networking-with-bpf-and-xdp
+
+13 .Aug 2016,
+P4, EBPF and Linux TC Offload, Dinan Gunawardena, Jakub Kicinski, https://de.slideshare.net/Open-NFP/p4-epbf-and-linux-tc-offload
+
+12. Jul 2016,
+Linux Meetup, Santa Clara, eXpress Data Path, Brenden Blanco, http://www.slideshare.net/IOVisor/express-data-path-linux-meetup-santa-clara-july-2016
+
+11. Jul 2016,
+Linux Meetup, Santa Clara, CETH for XDP, Yan Chan, Yunsong Lu, http://www.slideshare.net/IOVisor/ceth-for-xdp-linux-meetup-santa-clara-july-2016
+
+10. May 2016,
+P4 workshop, Stanford, P4 on the Edge, John Fastabend, https://schd.ws/hosted_files/2016p4workshop/1d/Intel%20Fastabend-P4%20on%20the%20Edge.pdf
+
+9. Mar 2016,
+Performance @Scale 2016, Menlo Park, Linux BPF Superpowers, Brendan Gregg, https://www.slideshare.net/brendangregg/linux-bpf-superpowers
+
+8. Mar 2016,
+eXpress Data Path, Tom Herbert, Alexei Starovoitov, https://github.com/iovisor/bpf-docs/raw/master/Express_Data_Path.pdf
+
+7. Feb 2016,
+NetDev1.1, Seville, On getting tc classifier fully programmable with cls_bpf, Daniel Borkmann, http://borkmann.ch/talks/2016_netdev.pdf http://www.netdevconf.org/1.1/proceedings/papers/On-getting-tc-classifier-fully-programmable-with-cls-bpf.pdf
+
+6. Jan 2016,
+FOSDEM 2016, Brussels, Linux tc and eBPF, Daniel Borkmann, http://borkmann.ch/talks/2016_fosdem.pdf
+
+5. Oct 2015,
+LinuxCon Europe, Dublin, eBPF on the Mainframe, Michael Holzheu, https://events.linuxfoundation.org/sites/events/files/slides/ebpf_on_the_mainframe_lcon_2015.pdf
+
+4. Aug 2015,
+Tracing Summit, Seattle, LLTng’s Trace Filtering and beyond (with some eBPF goodness, of course!), Suchakra Sharma, https://github.com/iovisor/bpf-docs/raw/master/ebpf_excerpt_20Aug2015.pdf
+
+3. Jun 2015,
+LinuxCon Japan, Tokyo, Exciting Developments in Linux Tracing, Elena Zannoni, https://events.linuxfoundation.org/sites/events/files/slides/tracing-linux-ezannoni-linuxcon-ja-2015_0.pdf
+
+2. Feb 2015,
+Collaboration Summit, Santa Rosa, BPF: In-kernel Virtual Machine, Alexei Starovoitov, https://events.linuxfoundation.org/sites/events/files/slides/bpf_collabsummit_2015feb20.pdf
+
+1. Feb 2015,
+NetDev 0.1, Ottawa, BPF: In-kernel Virtual Machine, Alexei Starovoitov, http://netdevconf.org/0.1/sessions/15.html
+
+0. Feb 2014,
+DevConf.cz, Brno, tc and cls_bpf: lightweight packet classifying with BPF, Daniel Borkmann, http://borkmann.ch/talks/2014_devconf.pdf
+
+추가 문서
+
+Dive into BPF: a list of reading material, Quentin Monnet (https://qmonnet.github.io/whirl-offload/2016/09/01/dive-into-bpf/)
+XDP - eXpress Data Path, Jesper Dangaard Brouer (https://prototype-kernel.readthedocs.io/en/latest/networking/XDP/index.html)
-- 
2.17.1

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Documentation: Add HOWTO Korean translation into BPF and XDP Reference Guide.
  2018-09-21  4:22 [PATCH] Documentation: Add HOWTO Korean translation into BPF and XDP Reference Guide Changan Song
@ 2018-09-24 17:15 ` Tejun Heo
  2018-09-24 18:20 ` [PATCH] " Jonathan Corbet
  1 sibling, 0 replies; 7+ messages in thread
From: Tejun Heo @ 2018-09-24 17:15 UTC (permalink / raw)
  To: Changan Song; +Cc: netdev, Alexei Starovoitov, Song Liu

Hello,

First of all, thanks a lot for the contribution.  It'd be great to
have a korean translation.  I glanced over it and there often were
areas where it was a bit challenging to understand without going back
to the english version.

I think this would still be helpful and a step in the right direction;
however, I think it'd be helpful to explicitly note, in korean, that
the translation is still work-in-progress and the readers are
recommended to refer back to the english copy when there's any doubt.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] Documentation: Add HOWTO Korean translation into BPF and XDP Reference Guide.
  2018-09-21  4:22 [PATCH] Documentation: Add HOWTO Korean translation into BPF and XDP Reference Guide Changan Song
  2018-09-24 17:15 ` Tejun Heo
@ 2018-09-24 18:20 ` Jonathan Corbet
  2018-09-26  9:11   ` Chang-an Song
  1 sibling, 1 reply; 7+ messages in thread
From: Jonathan Corbet @ 2018-09-24 18:20 UTC (permalink / raw)
  To: Changan Song; +Cc: netdev

On Fri, 21 Sep 2018 13:22:38 +0900
Changan Song <csongxdp@gmail.com> wrote:

> Signed-off-by: Changan Song <csongxdp@gmail.com>
> ---
>  Documentation/translations/ko_KR/bpf-xdp.txt | 3511 ++++++++++++++++++
>  1 file changed, 3511 insertions(+)
>  create mode 100644 Documentation/translations/ko_KR/bpf-xdp.txt

I can't judge the quality of the translation, of course, but I do have a
couple of related questions:

 - Since you're adding a new document, could you please format it as RST
   and add it to index.rst with the other Korean translations?  The
   original will have been in RST, so this should be relatively easy to
   do.

 - The original document has a copyright assertion but no associated
   license.  Do we know what the license is?  I assume it's something
   that is free and GPL-compatible, but that would be good to know for
   sure.

Thanks for doing this work,

jon

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] Documentation: Add HOWTO Korean translation into BPF and XDP Reference Guide.
  2018-09-24 18:20 ` [PATCH] " Jonathan Corbet
@ 2018-09-26  9:11   ` Chang-an Song
  2018-09-26 19:44     ` Jonathan Corbet
  0 siblings, 1 reply; 7+ messages in thread
From: Chang-an Song @ 2018-09-26  9:11 UTC (permalink / raw)
  To: Jonathan Corbet, tj; +Cc: netdev, daniel, davem

Hello,

Thank you very much to Tejun and Jon for the review first.
I have summarized the my action items as below,

> I think this would still be helpful and a step in the right direction;
> however, I think it'd be helpful to explicitly note, in korean, that
> the translation is still work-in-progress and the readers are
> recommended to refer back to the english copy when there's any doubt.

1. I will add to comment in the NOTE explicitly that "the translation is still
work-in-progress and the readers are recommended to refer back to the
english copy when there's any doubt".
Thank you very much for your advice, Tejun.

>  - Since you're adding a new document, could you please format it as RST
>    and add it to index.rst with the other Korean translations?  The
>    original will have been in RST, so this should be relatively easy to
>    do.

2. I need to convert the document format to rst file and
add a list of my current documents to the index.rst file, again.

>  - The original document has a copyright assertion but no associated
>    license.  Do we know what the license is?  I assume it's something
>    that is free and GPL-compatible, but that would be good to know for
>    sure.

3. I asked to main author Daniel that apache 2.0 license for this document.
I will need to do additional work for 1 and 2, and need to regenerate the patch.
Thank you very much for your advice, Jon.

If I have something to fix, please feel free to tell me.

BR/Leo

2018-09-25 3:20 GMT+09:00 Jonathan Corbet <corbet@lwn.net>:
> On Fri, 21 Sep 2018 13:22:38 +0900
> Changan Song <csongxdp@gmail.com> wrote:
>
>> Signed-off-by: Changan Song <csongxdp@gmail.com>
>> ---
>>  Documentation/translations/ko_KR/bpf-xdp.txt | 3511 ++++++++++++++++++
>>  1 file changed, 3511 insertions(+)
>>  create mode 100644 Documentation/translations/ko_KR/bpf-xdp.txt
>
> I can't judge the quality of the translation, of course, but I do have a
> couple of related questions:
>
>  - Since you're adding a new document, could you please format it as RST
>    and add it to index.rst with the other Korean translations?  The
>    original will have been in RST, so this should be relatively easy to
>    do.
>
>  - The original document has a copyright assertion but no associated
>    license.  Do we know what the license is?  I assume it's something
>    that is free and GPL-compatible, but that would be good to know for
>    sure.
>
> Thanks for doing this work,
>
> jon

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] Documentation: Add HOWTO Korean translation into BPF and XDP Reference Guide.
  2018-09-26  9:11   ` Chang-an Song
@ 2018-09-26 19:44     ` Jonathan Corbet
  2018-09-26 21:19       ` Daniel Borkmann
  0 siblings, 1 reply; 7+ messages in thread
From: Jonathan Corbet @ 2018-09-26 19:44 UTC (permalink / raw)
  To: Chang-an Song; +Cc: tj, netdev, daniel, davem

On Wed, 26 Sep 2018 18:11:42 +0900
Chang-an Song <csongxdp@gmail.com> wrote:

> >  - The original document has a copyright assertion but no associated
> >    license.  Do we know what the license is?  I assume it's something
> >    that is free and GPL-compatible, but that would be good to know for
> >    sure.  
> 
> 3. I asked to main author Daniel that apache 2.0 license for this document.

That is a bit of a problem, since Apache v2 is not compatible with GPLv2.
If the license of the document cannot be changed, I don't think we can
accept it into the kernel tree.

Thanks,

jon

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] Documentation: Add HOWTO Korean translation into BPF and XDP Reference Guide.
  2018-09-26 19:44     ` Jonathan Corbet
@ 2018-09-26 21:19       ` Daniel Borkmann
  2018-09-30  2:12         ` Chang-an Song
  0 siblings, 1 reply; 7+ messages in thread
From: Daniel Borkmann @ 2018-09-26 21:19 UTC (permalink / raw)
  To: Jonathan Corbet, Chang-an Song; +Cc: tj, netdev, davem

On 09/26/2018 09:44 PM, Jonathan Corbet wrote:
> On Wed, 26 Sep 2018 18:11:42 +0900
> Chang-an Song <csongxdp@gmail.com> wrote:
> 
>>>  - The original document has a copyright assertion but no associated
>>>    license.  Do we know what the license is?  I assume it's something
>>>    that is free and GPL-compatible, but that would be good to know for
>>>    sure.  
>>
>> 3. I asked to main author Daniel that apache 2.0 license for this document.
> 
> That is a bit of a problem, since Apache v2 is not compatible with GPLv2.
> If the license of the document cannot be changed, I don't think we can
> accept it into the kernel tree.

Alternative option could also be to integrate it into Cilium's doc given the
original document is present there as well, so it could link to the Korean
version from there.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] Documentation: Add HOWTO Korean translation into BPF and XDP Reference Guide.
  2018-09-26 21:19       ` Daniel Borkmann
@ 2018-09-30  2:12         ` Chang-an Song
  0 siblings, 0 replies; 7+ messages in thread
From: Chang-an Song @ 2018-09-30  2:12 UTC (permalink / raw)
  To: daniel; +Cc: Jonathan Corbet, tj, netdev, davem

Hello Daniel, Jon
Thank you very much for review.

>That is a bit of a problem, since Apache v2 is not compatible with GPLv2.
>If the license of the document cannot be changed, I don't think we can
>accept it into the kernel tree.

Thank you for sharing information, Jon.  I will check the rst file format
and the license of the document when I submit document at next time.
If I miss something, Please let me know and I will check the checklist, first.

>Alternative option could also be to integrate it into Cilium's doc given the
>original document is present there as well, so it could link to the Korean
>version from there.

Thank you for sharing about other ways, Daniel.
I will check the information you have provided, and then I am investigating
how to put the Korean version page, and I will proceed as soon as it
is completed.

BR/Leo
2018년 9월 27일 (목) 오전 6:19, Daniel Borkmann <daniel@iogearbox.net>님이 작성:
>
> On 09/26/2018 09:44 PM, Jonathan Corbet wrote:
> > On Wed, 26 Sep 2018 18:11:42 +0900
> > Chang-an Song <csongxdp@gmail.com> wrote:
> >
> >>>  - The original document has a copyright assertion but no associated
> >>>    license.  Do we know what the license is?  I assume it's something
> >>>    that is free and GPL-compatible, but that would be good to know for
> >>>    sure.
> >>
> >> 3. I asked to main author Daniel that apache 2.0 license for this document.
> >
> > That is a bit of a problem, since Apache v2 is not compatible with GPLv2.
> > If the license of the document cannot be changed, I don't think we can
> > accept it into the kernel tree.
>
> Alternative option could also be to integrate it into Cilium's doc given the
> original document is present there as well, so it could link to the Korean
> version from there.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2018-09-30  8:43 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-21  4:22 [PATCH] Documentation: Add HOWTO Korean translation into BPF and XDP Reference Guide Changan Song
2018-09-24 17:15 ` Tejun Heo
2018-09-24 18:20 ` [PATCH] " Jonathan Corbet
2018-09-26  9:11   ` Chang-an Song
2018-09-26 19:44     ` Jonathan Corbet
2018-09-26 21:19       ` Daniel Borkmann
2018-09-30  2:12         ` Chang-an Song

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.