Trabaja con DPDK
En esta página, se describe cómo usar el Data Plane Development Kit (DPDK) en instancias de Compute Engine U4C.
Acerca de DPDK sobre AF_XDP
El Data Plane Development Kit (DPDK) es un framework para aplicaciones de alto rendimiento que requieren un procesamiento de paquetes rápido, baja latencia y rendimiento coherente. DPDK omite la pila de red del kernel de Linux y se ejecuta directamente en el espacio del usuario. Puedes ejecutar DPDK en instancias U4C con una arquitectura AF_XDP.
DPDK proporciona un controlador de modo de sondeo AF_XDP (PMD), que es un dispositivo virtual (vdev) que permite que las aplicaciones DPDK se ejecuten sobre AF_XDP en modo de copia o de copia cero. Para obtener más información, consulta
Controlador de modo de sondeo AF_XDP en la
documentación de DPDK. A diferencia de
las implementaciones típicas en Compute Engine,
DPDK sobre AF_XDP en instancias U4C no requiere configurar VFIO, UIO ni
dpdk-devbind.py.
El uso de DPDK con la solución ULL incluye compatibilidad con el direccionamiento de flujo. Puedes omitir el hash de Receive Side Scaling (RSS) predeterminado si diriges flujos de tráfico específicos directamente a una cola de recepción (RX) designada. La solución ULL admite el direccionamiento de flujo de 3 tuplas (protocolo, dirección IP de destino y puerto de destino) para el tráfico de unidifusión y multidifusión de ULL.
Antes de comenzar
Antes de trabajar con DPDK en instancias de Compute Engine U4C, debes cumplir con los siguientes requisitos.
Crea una instancia U4C
Si aún no lo hiciste, crea una instancia de hardware físico U4C. Consulta Crea ULL instancias de Compute Engine.
Conéctate a tu instancia con SSH
Si aún no lo hiciste, conéctate a tu instancia con SSH.
Cambia al usuario raíz
Los comandos y las secuencias de comandos de los siguientes procedimientos modifican la configuración a nivel del sistema, los parámetros del kernel y las interfaces de red. Para ejecutarlos correctamente, debes hacerlo como usuario raíz. Puedes cambiar a un shell raíz ejecutando
sudo su o agregar sudo antes de ejecutar los comandos según sea necesario.
Instala DPDK en tu instancia U4C
Para instalar DPDK en tu instancia U4C, sigue estos pasos:
Configura las dependencias para la instalación de 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 mesonInstala DPDK.
wget https://fast.dpdk.org/rel/dpdk-VERSION.tar.xz tar xvf dpdk-VERSION.tar.xz cd dpdk-VERSION
Reemplaza
VERSIONpor la versión de DPDK que deseas instalar, como26.07. Si es necesario, consulta la página de descarga de DPDK.Para compilar DPDK con los ejemplos, haz lo siguiente:
meson setup -Dexamples=all build ninja -C build install; ldconfig
Configura interfaces de red para AF_XDP
Para usar AF_XDP en la NIC virtual de Google (gVNIC), debes ajustar las funciones predeterminadas del controlador para preparar la interfaz de red.
Puedes realizar estos pasos de forma manual o usar una secuencia de comandos de configuración automatizada. Selecciona una de las siguientes pestañas:
Manual
Sigue estos pasos para cada interfaz de red que deseas configurar.
Reduce los recuentos de colas de RX y TX: gVNIC usa de forma predeterminada la cantidad máxima admitida de colas de RX y TX, pero debes reducirla a la mitad para asegurarte de que haya suficientes colas de TX para el tráfico normal del kernel.
ethtool -L NIC_NAME rx NUM_SOCKETS \ tx NUM_SOCKETS
Reemplaza lo siguiente:
NIC_NAME: Es el nombre del SO de la interfaz de red, comoeth1.NUM_SOCKETS: Es la cantidad de sockets AF_XDP que se configurarán. Establece este valor en un valor que no sea mayor que la mitad de las colas máximas para la interfaz. Para las instancias U4C, suele ser8(la mitad de las 16 colas predeterminadas). Puedes verificar las colas máximas ejecutandoethtool -l NIC_NAME.
Inhabilita GRO y LRO de hardware: Como gVNIC no admite XDP de varios búferes, debes inhabilitar la descarga de recepción grande (LRO) y la descarga de recepción genérica (GRO) de hardware:
ethtool -K NIC_NAME rx-gro-hw off ethtool -K NIC_NAME lro off
Reduce la longitud del búfer de RX: De forma predeterminada, los controladores más recientes publican búferes de 4 KB (4,096 bytes) en la interfaz de red para RX, pero XDP requiere una longitud de búfer de
2048:ethtool -G NIC_NAME rx-buf-len 2048
Secuencia de comandos
Como alternativa, puedes ejecutar la siguiente secuencia de comandos de Bash para cada interfaz de red que deseas configurar. La secuencia de comandos prepara automáticamente una interfaz de red determinada para XDP reduciendo los recuentos de colas, inhabilitando las descargas y ajustando la longitud del búfer de RX:
#!/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
Ejecuta tu aplicación DPDK
Para usar el PMD de AF_XDP, incluye la marca --vdev en los argumentos de la capa de abstracción del entorno (EAL) de tu aplicación DPDK.
El siguiente comando de ejemplo incluye varios parámetros clave. Para obtener información detallada sobre la configuración y los parámetros, consulta Controlador de modo de sondeo AF_XDP en la documentación de DPDK.
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
Reemplaza lo siguiente:
DPDK_APPLICATION: Es el objeto binario de la aplicación DPDK que se ejecutará.PCIE_BDF: Es la dirección PCI de la interfaz de red. Para encontrar este valor, ejecutaethtool -i NIC_NAMEy verifica el valorbus-info, como0000:00:04.0.NIC_NAME: Es el nombre del SO de la interfaz de red, comoeth1.NUM_SOCKETS: Es la cantidad de sockets AF_XDP que se abrirán. Cada socket se conecta a un solo par de colas. Este valor debe coincidir con el recuento de colas que configuraste en la interfaz.START_QUEUE: Es el índice de la cola inicial para los sockets AF_XDP.XDP_PROG: Es un programa XDP personalizado que se ejecutará en los paquetes recibidos. Si se omite, DPDK usa el programa XDP predeterminado que proporcionalibxdp.APPLICATION_ARGS: Son argumentos específicos de tu aplicación DPDK.
Usa las funciones del controlador
En esta sección, se proporciona información sobre el uso del direccionamiento de flujo y las marcas de tiempo de RX.
Direccionamiento de flujo
Puedes usar el direccionamiento de flujo con XDP para dirigir paquetes de aplicaciones a un subconjunto específico de colas, dejando las colas restantes para el tráfico del kernel. En las siguientes secciones, se describen dos enfoques que puedes usar para la programación de reglas de flujo.
Direccionamiento de flujo preprogramado (recomendado)
Como el PMD de AF_XDP no admite la programación de flujo sobre la marcha con llamadas ioctl y requiere modificar tu aplicación DPDK, te recomendamos que preprogrames tus reglas de flujo con ethtool antes de iniciar la aplicación.
Por ejemplo, para programar una regla de flujo que dirija el tráfico UDP de IPv4 a la cola 0, haz lo siguiente:
ethtool -N NIC_NAME flow-type udp4 \ dst-ip DST_IP dst-port DST_PORT action 0 loc 0
Reemplaza lo siguiente:
NIC_NAME: Es el nombre del SO de la interfaz de red, comoeth1.DST_IP: Es la dirección IP de destino del tráfico que se dirigirá.DST_PORT: Es el puerto de destino del tráfico que se dirigirá.
Programa reglas de flujo sobre la marcha
El PMD de AF_XDP no admite la programación de flujo sobre la marcha. Para usar este método, debes modificar tu aplicación DPDK para enviar manualmente llamadas ioctl de ethtool.
Te recomendamos que evites este enfoque, a menos que tu aplicación controle una gran cantidad de conexiones efímeras. gVNIC admite hasta 20,000 reglas de direccionamiento de flujo de 3 tuplas. Si necesitas menos reglas y conoces tus direcciones IP y puertos de destino con anticipación, preprograma tus reglas.
Si debes programar reglas de forma dinámica, consulta el siguiente ejemplo de código C:
Expandir para ver el ejemplo de código 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); ... }
Programación de RSS
Cuando se usa el direccionamiento de flujo, RSS puede ayudar a proporcionar un mejor aislamiento del tráfico.
Al igual que con el direccionamiento de flujo, puedes configurar RSS con ethtool. Te recomendamos que configures RSS antes de ejecutar tu aplicación.
En el siguiente ejemplo, se muestra cómo configurar RSS para que funcione con AF_XDP:
# 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
Marcas de tiempo de RX
Aunque las marcas de tiempo de RX no son compatibles con el repositorio DPDK ascendente para el PMD de AF_XDP, puedes usarlas de la siguiente manera:
Aplica los parches necesarios al árbol de origen de DPDK y vuelve a compilar el origen de DPDK y tu aplicación. Estos parches agregan compatibilidad con
rte_eth_read_clocky marcas de tiempo de RX enmbufsrecibidos.Usa un programa XDP que cargue la marca de tiempo en los metadatos.
Proporciona los siguientes parámetros
vdevde AF_XDP adicionales cuando inicies tu aplicación DPDK:xdp_meta_rx_ts_offset: Es el desplazamiento de bytes desde el inicio de los metadatos de XDP donde se encuentra el valor de la marca de tiempo de RX de 64 bits.xdp_meta_valid_hint_offset: Es el desplazamiento de bytes que abarca un campo de marca de 1 byte que indica si la marca de tiempo es válida (opcional).xdp_meta_rx_ts_valid_mask: Es la máscara de bits que se usa para extraer los bits de marca válidos (opcional).Si
ctxes el inicio de los metadatos, el valor de(ctx->data_meta + xdp_meta_valid_hint_offset) & xdp_meta_rx_ts_valid_maskdescribe si la marca de tiempo es válida.
¿Qué sigue?
- Para sincronizar el reloj de la instancia con el reloj de la NIC física de su servidor host, consulta Configura la hora exacta.