DPDK 작업
이 페이지에서는 U4C Compute Engine 인스턴스에서 데이터 영역 개발 키트 (DPDK)를 사용하는 방법을 설명합니다.
AF_XDP를 통한 DPDK 정보
데이터 영역 개발 키트 (DPDK)는 빠른 패킷 처리, 낮은 지연 시간, 일관적인 성능이 필요한 성능 집약적인 애플리케이션을 위한 프레임워크입니다. DPDK는 Linux 커널 네트워크 스택을 우회하고 사용자 공간에서 직접 실행됩니다. AF_XDP 아키텍처를 사용하여 U4C 인스턴스에서 DPDK를 실행할 수 있습니다.
DPDK는 복사 모드 또는 제로 복사 모드에서 DPDK 애플리케이션이 AF_XDP 위에 실행되도록 하는 가상 기기 (vdev)인 AF_XDP 폴 모드 드라이버(PMD)를 제공합니다. 자세한 내용은
DPDK 문서의
AF_XDP 폴 모드 드라이버를 참조하세요. Compute Engine의
일반적인 배포와 달리,
U4C 인스턴스의 AF_XDP를 통한 DPDK는 VFIO, UIO 또는
dpdk-devbind.py를 구성할 필요가 없습니다.
ULL 솔루션과 함께 DPDK를 사용하면 흐름 조정이 지원됩니다. 특정 트래픽 흐름을 지정된 수신 대기열 (RX)로 직접 조정하여 기본 수신 측면 확장 (RSS) 해싱을 우회할 수 있습니다. ULL 솔루션은 ULL 유니캐스트 및 멀티캐스트 트래픽에 대해 3-튜플 흐름 조정 (프로토콜, 대상 IP 주소, 대상 포트)을 지원합니다.
시작하기 전에
U4C Compute Engine 인스턴스에서 DPDK를 사용하기 전에 다음 요구사항을 충족해야 합니다.
U4C 인스턴스 만들기
아직 만들지 않았다면 U4C 베어메탈 인스턴스를 만듭니다. ULL Compute Engine 인스턴스 만들기를 참조하세요.
SSH를 사용하여 인스턴스에 연결
아직 연결하지 않았다면 SSH를 사용하여 인스턴스에 연결합니다.
루트 사용자로 전환
다음 절차의 명령어와 스크립트는 시스템 수준 설정, 커널 매개변수, 네트워크 인터페이스를 수정합니다. 성공적으로 실행하려면 루트 사용자로 실행해야 합니다.
`sudo su`를 실행하여 루트 셸로 전환하거나 필요에 따라 명령어를 실행하기 전에 `sudo`를 추가할 수 있습니다.sudo susudo
U4C 인스턴스에 DPDK 설치
U4C 인스턴스에 DPDK를 설치하려면 다음 단계를 따르세요.
DPDK 설치의 종속 항목을 구성합니다.
apt-get update && apt-get upgrade -yq apt-get install -yq build-essential ninja-build python3-pip \ linux-headers-$(uname -r) pkg-config libnuma-dev pip install pyelftools mesonDPDK를 설치합니다.
wget https://fast.dpdk.org/rel/dpdk-VERSION.tar.xz tar xvf dpdk-VERSION.tar.xz cd dpdk-VERSION
VERSION을 설치하려는 DPDK 버전(예:26.07)으로 바꿉니다. 필요한 경우 DPDK 다운로드 페이지를 참조하세요.예시를 사용해서 DPDK를 빌드하려면 다음 안내를 따르세요.
meson setup -Dexamples=all build ninja -C build install; ldconfig
AF_XDP의 네트워크 인터페이스 구성
Google 가상 NIC (gVNIC)에서 AF_XDP를 사용하려면 기본 드라이버 기능을 조정하여 네트워크 인터페이스를 준비해야 합니다.
이러한 단계는 수동으로 수행하거나 자동 구성 스크립트를 사용하여 수행할 수 있습니다. 다음 탭 중 하나를 선택합니다.
수동
구성하려는 각 네트워크 인터페이스에 대해 다음 단계를 따르세요.
RX 및 TX 대기열 수 줄이기: gVNIC는 기본적으로 지원되는 최대 RX 및 TX 대기열 수를 사용하지만 일반 커널 트래픽에 충분한 TX 대기열이 있도록 이 수를 절반으로 줄여야 합니다.
ethtool -L NIC_NAME rx NUM_SOCKETS \ tx NUM_SOCKETS
다음을 바꿉니다.
NIC_NAME: 네트워크 인터페이스의 OS 이름(예:eth1)NUM_SOCKETS: 구성할 AF_XDP 소켓 수입니다. 이 값을 인터페이스의 최대 대기열 수의 절반 이하로 설정합니다. U4C 인스턴스의 경우 일반적으로8(기본 대기열 16개의 절반)입니다.ethtool -l NIC_NAME을 실행하여 최대 대기열을 확인할 수 있습니다.
하드웨어 GRO 및 LRO 사용 중지: gVNIC는 멀티 버퍼 XDP를 지원하지 않으므로 Large Receive Offload (LRO) 및 하드웨어 Generic Receive Offload (GRO)를 사용 중지해야 합니다.
ethtool -K NIC_NAME rx-gro-hw off ethtool -K NIC_NAME lro off
RX 버퍼 길이 줄이기: 기본적으로 최신 드라이버는 RX를 위해 4KB (4,096바이트) 버퍼를 네트워크 인터페이스에 게시하지만 XDP에는
2048의 버퍼 길이가 필요합니다.ethtool -G NIC_NAME rx-buf-len 2048
스크립트
또는 구성하려는 각 네트워크 인터페이스에 대해 다음 Bash 스크립트를 실행할 수 있습니다. 이 스크립트는 대기열 수를 줄이고, 오프로드를 사용 중지하고, RX 버퍼 길이를 조정하여 지정된 네트워크 인터페이스를 XDP용으로 자동으로 준비합니다.
#!/bin/bash # Usage example: NUM_SOCKETS=8 prep_xdp.sh eth0 DEV=$1 NUM_SOCKETS=${NUM_SOCKETS=1} # Reduce RX/TX queue counts to the number of AF_XDP sockets ethtool -L $DEV rx $NUM_SOCKETS tx $NUM_SOCKETS # Disable LRO/HW-gro OFFLOAD=$(ethtool -k $DEV | \ grep "rx-gro-hw\|large-receive-offload" | \ grep -v fixed | cut -d ":" -f 1) ethtool -K $DEV ${OFFLOAD} off # Reduce RX buffer length to 2048 ethtool -G $DEV rx-buf-len 2048
DPDK 애플리케이션 실행
AF_XDP PMD를 사용하려면 DPDK 애플리케이션의 환경 추상화 레이어 (EAL) 인수에 --vdev 플래그를 포함합니다.
다음 예시 명령어에는 몇 가지 주요 매개변수가 포함되어 있습니다. 설정 및 매개변수에 대한 자세한 내용은 DPDK 문서의 AF_XDP 폴 모드 드라이버 를 참조하세요.
DPDK_APPLICATION -a PCIE_BDF \ --vdev=net_af_xdp,iface=NIC_NAME,queue_count=NUM_SOCKETS,start_queue=START_QUEUE,xdp_prog=XDP_PROG \ -- APPLICATION_ARGS
다음을 바꿉니다.
DPDK_APPLICATION: 실행할 DPDK 애플리케이션 바이너리입니다.PCIE_BDF: 네트워크 인터페이스의 PCI 주소입니다.ethtool -i NIC_NAME을 실행하고bus-info값(예:0000:00:04.0)을 확인하여 이 값을 찾을 수 있습니다.NIC_NAME: 네트워크 인터페이스의 OS 이름(예:eth1)NUM_SOCKETS: 열 AF_XDP 소켓 수입니다. 각 소켓은 단일 대기열 쌍에 연결됩니다. 이 값은 인터페이스에서 구성한 대기열 수와 일치해야 합니다.START_QUEUE: AF_XDP 소켓의 시작 대기열 색인입니다.XDP_PROG: 수신된 패킷에서 실행할 커스텀 XDP 프로그램입니다. 생략하면 DPDK는libxdp에서 제공하는 기본 XDP 프로그램을 사용합니다.APPLICATION_ARGS: DPDK 애플리케이션에 특정한 인수입니다.
드라이버 기능 사용
이 섹션에서는 흐름 조정 및 RX 타임스탬프 지정에 대한 사용 정보를 제공합니다.
흐름 조정
XDP와 함께 흐름 조정을 사용하여 애플리케이션 패킷을 특정 대기열 하위 집합으로 조정하고 나머지 대기열은 커널 트래픽에 사용할 수 있습니다. 다음 섹션에서는 흐름 규칙 프로그래밍에 사용할 수 있는 두 가지 접근 방식을 설명합니다.
흐름 조정 사전 프로그래밍 (권장)
ioctl 호출을 사용하는 즉석 흐름 프로그래밍은 AF_XDP PMD에서 지원되지 않으며 DPDK 애플리케이션을 수정해야 하므로 애플리케이션을 시작하기 전에 ethtool을 사용하여 흐름 규칙을 사전 프로그래밍하는 것이 좋습니다.
예를 들어 IPv4 UDP 트래픽을 대기열 0으로 조정하는 흐름 규칙을 프로그래밍하려면 다음 안내를 따르세요.
ethtool -N NIC_NAME flow-type udp4 \ dst-ip DST_IP dst-port DST_PORT action 0 loc 0
다음을 바꿉니다.
NIC_NAME: 네트워크 인터페이스의 OS 이름(예:eth1)DST_IP: 조정할 트래픽의 대상 IP 주소입니다.DST_PORT: 조정할 트래픽의 대상 포트입니다.
즉석에서 흐름 규칙 프로그래밍
AF_XDP PMD는 즉석 흐름 프로그래밍을 지원하지 않습니다. 이 메서드를 사용하려면 DPDK 애플리케이션을 수정하여 ethtool ioctl 호출을 수동으로 보내야 합니다.
애플리케이션이 많은 임시 연결을 처리하지 않는 한 이 접근 방식을 피하는 것이 좋습니다. gVNIC는 최대 20,000개의 3-튜플 흐름 조정 규칙을 지원합니다. 더 적은 규칙이 필요하고 대상 IP 주소와 포트를 미리 알고 있는 경우 규칙을 사전 프로그래밍하세요.
규칙을 동적으로 프로그래밍해야 하는 경우 다음 C 코드 예시를 참조하세요.
펼쳐서 C 코드 예시 보기
struct flow_rule_info { uint32_t src_ip; uint32_t dst_ip; uint16_t src_port; uint16_t dst_port; uint32_t target_queue; uint32_t rule_id; } int add_flow_rule(const char *ifname, struct flow_rule_info *rule_info, bool is_5tuple) { struct ethtool_rxnfc cmd; struct ifreq ifr; int fd; fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { fprintf(stderr, "Failed to open socket: %s", strerror(fd)); return -1; } memset(&cmd, 0, sizeof(cmd)); memset(&ifr, 0, sizeof(ifr)); cmd.cmd = ETHTOOL_SRXCLSRLINS; cmd.fs.flow_type = UDP_V4_FLOW; cmd.fs.h_u.udp_ip4_spec.ip4dst = rule_info->dst_ip; cmd.fs.h_u.udp_ip4_spec.pdst = htons(rule_info->dst_port); cmd.fs.m_u.udp_ip4_spec.ip4dst = 0xFFFFFFFF; cmd.fs.m_u.udp_ip4_spec.pdst = 0xFFFF; if (is_5tuple) { cmd.fs.h_u.udp_ip4_spec.ip4src = rule_info->src_ip; cmd.fs.h_u.udp_ip4_spec.psrc = htons(rule_info->src_port); cmd.fs.m_u.udp_ip4_spec.ip4src = 0xFFFFFFFF; cmd.fs.m_u.udp_ip4_spec.psrc = 0xFFFF; } cmd.fs.ring_cookie = rule_info->target_queue; cmd.fs.location = rule_info->rule_id; strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); ifr.ifr_data = (void *)&cmd; int ret = ioctl(fd, SIOCETHTOOL, &ifr); if (ret) fprintf(stderr, "Failed to send ioctl: %s\n", strerror(errno)); close(fd); return ret; } int try_add_xdp_flow_rule(int port, struct flow_rule_info *rule_info) { char dev_name[RTE_ETH_NAME_MAX_LEN]; char *af_xdp_driver = "net_af_xdp"; struct rte_eth_dev_info dev_info; int err; if (!rte_eth_dev_is_valid_port(port)) return -1; err = rte_eth_dev_info_get(port, &dev_info); if (err) { fprintf(stderr, "Error getting info for port %d: %s\n", port, strerror(err)); return retval; } if (strncmp(dev_info.driver_name, af_xdp_driver, strlen(af_xdp_driver)) != 0) { fprintf(stderr, "Not an AF_XDP vdev!\n"); return -EINVAL; } err = rte_eth_dev_get_name_by_port(port, dev_name); if (retval) { fprintf(stderr, "Failed to get dev_name: %s\n", strerror(err)); return retval; } /* replace ens4 with correct ifname; must be passed in as application argument */ err = add_flow_rule("ens4", rule_info)); if (err) fprintf("Failed to add flow rule: %s\n", strerror(err)); return err; } /* From somewhere in the application: */ int application_func(...) { ... struct flow_rule_info *rule_info { .src_ip = 0x0a000001, .dst_ip = 0x0a000002, .src_port = 0x1110, .uint16_t dst_port = 0x1011, .uint32_t target_queue = 0, .uint32_t rule_id = 1, }; try_add_xdp_flow_rule(xdp_port_id, &rule_info, /*is_5tuple=*/false); ... }
RSS 프로그래밍
흐름 조정을 사용할 때 RSS는 더 나은 트래픽 격리를 제공하는 데 도움이 될 수 있습니다.
흐름 조정과 마찬가지로 ethtool을 사용하여 RSS를 구성할 수 있습니다. 애플리케이션을 실행하기 전에 RSS를 구성하는 것이 좋습니다.
다음 예시에서는 AF_XDP와 함께 작동하도록 RSS를 구성하는 방법을 보여줍니다.
# Example: Kernel queues 0-3, XDP queues 4-7 NUM_SOCKETS=4 bash prep_xdp.sh eth0 # Program flow rules ethtool -N eth0 flow-type udp4 dst-ip DST_IP dst-port DST_PORT_0 action 4 loc 0 ethtool -N eth0 flow-type udp4 dst-ip DST_IP dst-port DST_PORT_1 action 5 loc 1 ethtool -N eth0 flow-type udp4 dst-ip DST_IP dst-port DST_PORT_2 action 6 loc 2 ethtool -N eth0 flow-type udp4 dst-ip DST_IP dst-port DST_PORT_3 action 7 loc 3 # If there are more ports that the application polls on, flow rules can be added in a round-robin fashion in a script. # Program RSS ethtool -X eth0 start 0 equal 4 # Run the application ./path/to/application -a 0000:00:03.0 --vdev net_af_xdp,iface=eth0,start_queue=4,queue_count=4 -- APPLICATION_ARGS
RX 타임스탬프 지정
RX 타임스탬프 지정은 AF_XDP PMD의 업스트림 DPDK 저장소에서 지원되지 않지만 다음을 수행하여 RX 타임스탬프 지정을 사용할 수 있습니다.
DPDK 소스 트리에 필요한 패치 를 적용하고 DPDK 소스와 애플리케이션을 다시 컴파일합니다. 이러한 패치는 수신된
mbufs에서rte_eth_read_clock및 RX 타임스탬프 지원을 추가합니다.타임스탬프를 메타데이터에 로드하는 XDP 프로그램을 사용합니다.
DPDK 애플리케이션을 시작할 때 다음 추가 AF_XDP
vdev매개변수를 제공합니다.xdp_meta_rx_ts_offset: 64비트 RX 타임스탬프 값이 있는 XDP 메타데이터의 시작 부분에서 바이트 오프셋입니다.xdp_meta_valid_hint_offset: (선택사항) 타임스탬프가 유효한지 여부를 나타내는 1바이트 플래그 필드를 포함하는 바이트 오프셋입니다.xdp_meta_rx_ts_valid_mask: (선택사항) 유효한 플래그 비트를 추출하는 데 사용되는 비트마스크입니다.ctx가 메타데이터의 시작 부분이면(ctx->data_meta + xdp_meta_valid_hint_offset) & xdp_meta_rx_ts_valid_mask값은 타임스탬프가 유효한지 여부를 설명합니다.
다음 단계
- 인스턴스 시계를 호스트 서버의 실제 NIC 시계와 동기화하려면 정확한 시간 구성을 참조하세요.