빠른 패킷 처리를 위해 (e)BPF를 통해 Linux 커널의 XDP Hook에 연결하고 기본 Layer 3/4 전달을 수행하는 프로그램입니다. 이 프로그램은 연결 처리를 위해 IPTable 및 NTFable과 유사한 소스 포트 매핑을 수행합니다. 기존 연결은 나노초당 연결 패킷을 기준으로 우선순위가 지정됩니다. 이는 포트가 소진되면 나노초당 최소 패킷의 연결이 대체된다는 의미입니다. 나노초당 더 높은 패킷을 사용하는 연결이 더 민감하기 때문에 이것이 가장 좋다고 생각합니다.
또한 호스트의 네트워크 구성 또는 네트워크 인터페이스 카드(NIC)가 XDP DRV 후크(AKA 기본, SKB 생성 이전에 발생)를 지원하지 않는 경우 프로그램은 XDP SKB 후크(AKA 일반, SKB 이후에 발생)에 연결을 시도합니다. IPTable과 NTFable이 netfilter
커널 모듈을 통해 처리되는 생성) 명령줄을 통해 재정의를 사용하여 SKB 또는 오프로드 모드를 강제 실행할 수 있습니다.
그렇다면 호스트의 네트워크 구성이 XDP의 DRV 후크를 지원하지 않는 이유는 다음과 같습니다.
이 프로젝트가 XDP 활용에 관심이 있는 기존 네트워크 엔지니어/프로그래머 또는 해당 분야에 관심이 있는 모든 사람에게 도움이 되기를 바랍니다! 고성능 라우터/패킷 전달 및 (D)DoS 완화/예방은 사이버 보안의 매우 중요한 부분이며 낮은 수준에서 네트워킹 및 패킷 흐름의 개념을 이해하는 것은 해당 분야에서 경력을 추구하는 사람들에게 확실히 도움이 될 것입니다.
경고 - 이 프로젝트에는 아직 수행해야 할 작업이 많이 있으며 현재로서는 IPv4만 지원합니다. IPv6 지원은 공식 출시 전에 추가될 예정입니다. 현재로서는 프로그램에 버그가 있을 수 있으며 전달 기능을 아직 사용할 수 없습니다.
바인드 주소당 사용할 수 있는 기본 최대 소스 포트는 21개 이며 여기에서 설정됩니다(원하는 경우 이를 조정할 수 있음). 기본적으로 포트 범위 500 - 520 을 사용하지만 이를 구성할 수 있습니다.
처음에는 사용 가능한 대부분의 포트(1 - 65534)를 사용하려고 했습니다. 그러나 BPF 검증기 제한으로 인해 Linux 커널 내부에서 몇 가지 상수를 발생시키고 커널을 다시 컴파일해야 했습니다. 나는 이에 대한 패치를 만들었고 여기에 모든 것을 문서화했습니다. 내가 만든 패치를 사용하여 구축한 사용자 정의 커널에 문제 없이 바인드 주소당 최대 65534개의 포트로 프로그램을 실행할 수 있습니다. 하지만 사용 가능한 소스 포트가 많을수록 사용 가능한 포트를 확인할 때 XDP 프로그램이 수행해야 하는 처리량이 많아집니다.
이것을 프로덕션에 사용할 계획이라면 위에서 제기한 상수를 사용하여 자신만의 커널을 컴파일하는 것이 좋습니다. 바인드 주소당 최대 소스 포트 21개는 많지 않지만 불행하게도 기본 BPF 검증기 제한으로 인해 현재 더 이상 진행할 수 없습니다.
이러한 제한을 일으키는 주요 코드는 여기에 있으며 새 연결에 사용할 최상의 소스 포트를 찾으려고 할 때 발생합니다. 모든 소스 포트를 반복하고 나노초당 패킷 값(BPF 맵은 키로 검색)을 확인해야 하기 때문에 우리가 이해하는 유연성으로 사용 가능한 최상의 소스 포트를 확인할 수 있는 다른 방법은 없습니다.
프로젝트를 빌드하는 데 이러한 패키지를 사용하므로 make
, clang
, libelf
및 llvm
필요합니다. 또한 구성 파일을 구문 분석하려면 libconfig
( libconfig-dev
는 Ubuntu/Debian 시스템의 패키지임)도 필요합니다.
Ubuntu/Debian의 경우 다음이 작동합니다.
apt install build-essential make clang libelf-dev llvm libconfig-dev
패키지 이름은 다른 Linux 배포판에서도 비슷하다고 가정합니다.
xdpfwd-add
및 xdpfwd-del
사용하려면 XDP 프로그램이 BPF 맵을 /sys/fs/bpf/xdpfwd
에 고정하므로 BPF 파일 시스템을 마운트해야 합니다. iproute2
또는 이와 유사한 것을 통해 이미 이 작업이 수행되었을 가능성이 높지만 그렇지 않은 경우 다음 명령을 사용할 수 있습니다.
mount -t bpf bpf /sys/fs/bpf/
기본 명령줄 사용법에는 다음이 포함됩니다.
-o --offload => Attempt to load XDP program with HW/offload mode. If fails, will try DRV and SKB mode in that order.
-s --skb => Force program to load in SKB/generic mode.
-t --time => The amount of time in seconds to run the program for. Unset or 0 = infinite.
-c --config => Location to XDP Forward config (default is /etc/xdpfwd/xdpfwd.conf).
-l --list => List all forwarding rules.
-h --help => Print out command line usage.
XDP/BPF 프로그램을 시스템의 NIC로 오프로드하면 NIC가 하드웨어를 사용하여 패킷을 처리/전달하므로 달성할 수 있는 가장 빠른 패킷 처리가 가능합니다. 그러나 이 기능을 지원하는 NIC 제조업체는 많지 않으며 NIC의 메모리/처리가 제한 됩니다(예: BPF 맵 크기가 극도로 제한됩니다). 또한 일반적으로 오프로드된 BPF 프로그램에는 더 엄격한 BPF 검증 프로그램 제한이 있지만 NIC 제조업체에 연락하여 이러한 제한을 높이는 특수 버전의 NIC 드라이버를 제공하는지 확인할 수 있습니다(이것은 제가 한 제조업체에서 수행한 작업입니다). 나는)를 사용했다.
현재로서는 BPF 복잡성과 루프 요구 사항으로 인해 이 도구를 NIC에 완전히 오프로드할 수 있는 NIC 제조업체를 알지 못합니다. 솔직히 말해서 현재 네트워킹 시대에는 오프로드된 프로그램을 BPF 맵 조회 및 최소한의 패킷 검사에 맡기는 것이 가장 좋다고 생각합니다. 예를 들어 간단한 BPF 계층 2 경로 테이블 맵 조회를 수행한 다음 NIC에서 패킷을 다시 전송합니다 . 그러나 XDP는 여전히 매우 새로운 기능이므로 앞으로 몇 년 안에 이러한 제한이 완화되거나 해제될 것으로 예상됩니다. 이것이 제가 이 프로그램에 오프로드 모드에 대한 지원을 추가한 이유입니다.
설치 시 /usr/bin
통해 $PATH
에 추가되는 xdpfwd-add
실행 파일은 다음 인수를 허용합니다.
-b --baddr => The address to bind/look for.
-B --bport => The port to bind/look for.
-d --daddr => The destination address.
-D --dport => The destination port.
-p --protocol => The protocol (either "tcp", "udp", "icmp", or unset for all).
-a --save => Save rule to config file.
그러면 XDP 프로그램이 실행되는 동안 전달 규칙이 추가됩니다.
설치 시 /usr/bin
통해 $PATH
에 추가되는 xdpfwd-del
실행 파일은 다음 인수를 허용합니다.
-b --baddr => The address to bind/look for.
-B --bport => The port to bind/look for.
-p --protocol => The protocol (either "tcp", "udp", "icmp", or unset for all).
-a --save => Remove rule from config file.
XDP 프로그램이 실행되는 동안 전달 규칙이 삭제됩니다.
기본 구성 파일은 /etc/xdpfwd/xdpfwd.conf
에 있으며 libconfig
구문을 사용합니다. 다음은 현재 기능을 모두 사용하는 구성 예입니다.
interface = "ens18"; // The interface the XDP program attaches to.
// Forwarding rules array.
forwarding = (
{
bind = "10.50.0.3", // The bind address which incoming packets must match.
bindport = 80, // The bind port which incoming packets must match.
protocol = "tcp", // The protocol (as of right now "udp", "tcp", and "icmp" are supported). Right now, you must specify a protocol. However, in the future I will be implementing functionality so you don't have to and it'll do full layer-3 forwarding.
dest = "10.50.0.4", // The address we're forwarding to.
destport = 8080 // The port we're forwarding to (if not set, will use the bind port).
},
...
);
필요한 패키지를 모두 다운로드했다고 가정하면 이 프로젝트를 빌드하는 것은 간단할 것입니다. 다음 쉘 및 Bash 명령을 사용할 수 있습니다!
# Clone respository and its sub-modules such as LibBPF.
git clone --recursive https://github.com/gamemann/XDP-Forwarding
# Change directory.
cd XDP-Forwarding
# Make project using all cores.
make -j $( nproc )
# Install binaries to PATH as root so you may use 'xdpfwd', 'xdpfwd-add', 'xdpfwd-del'.
sudo make install