Red de conocimiento informático - Conocimiento informático - Cómo escribir un controlador para una tarjeta de red

Cómo escribir un controlador para una tarjeta de red

Escribir controladores de red para sistemas operativos Linux

1. Descripción general de los controladores de dispositivos del sistema Linux

1.1 Clasificación de los controladores de dispositivos Linux

1.2 Algunos conceptos básicos de escritura de controladores

2. Controlador de dispositivo de red del sistema Linux

2.1 Estructura del controlador de red

2.2 Métodos básicos del controlador de red

2.3 Estructuras de datos utilizadas en los controladores de red

2.4 Soportes del sistema de uso común

3 Problemas que pueden surgir al escribir controladores de red para Linux

p><. p>3.1 Interrumpir *** compartir

3.2 Manejo cuando la transmisión de hardware está ocupada

3.3 Control de flujo (control de flujo)

3.4 Depuración

p>

4. Lecturas adicionales

5. Varios

1. Descripción general de los controladores de dispositivos del sistema Linux

1.1 Clasificación de controladores de dispositivos Linux

p>

p>

Los controladores de dispositivos Linux representan una gran proporción del código fuente del kernel de Linux, y la longitud del código fuente aumenta día a día, principalmente debido al aumento de controladores. Durante el proceso de actualización continua del kernel de Linux, la estructura del controlador

sigue siendo relativamente estable. En el cambio de 2.0.xx a 2.2.xx, se realizaron algunos cambios en la escritura del controlador, pero

La migración del controlador 2.0.xx a 2.2.xx solo requiere una pequeña cantidad de trabajo.

Los dispositivos del sistema Linux se dividen en tres tipos: dispositivo de caracteres (dispositivo char), dispositivo de bloque (dispositivo de bloque) y dispositivo de red (dispositivo de red)

Los dispositivos de caracteres son dispositivos que no se almacenan en caché cuando se accede a ellos. La lectura y escritura de dispositivos de bloques

son compatibles con la memoria caché, y los dispositivos de bloques deben tener capacidad de acceso aleatorio, mientras que los dispositivos de caracteres

no tienen este requisito. Los dispositivos de caracteres típicos incluyen mouse, teclado, puerto serie, etc. Los dispositivos de bloque incluyen principalmente discos duros, disquetes, CD-ROM, etc. Para que un sistema de archivos se instale en el sistema operativo, debe estar en un dispositivo de bloque.

Los equipos de red se procesan especialmente en Linux. El sistema de red Linux se basa principalmente en el mecanismo de socket de BSD Unix. Se define una estructura de datos especial (sk_buff) entre el sistema y el controlador para la transferencia de datos.

El sistema admite el almacenamiento en caché de los datos enviados y recibidos, proporciona un mecanismo de control de flujo y admite múltiples protocolos.

1.2 Algunos conceptos básicos al escribir controladores

No importa qué sistema operativo sea el controlador, existen algunos conceptos comunes. El soporte proporcionado por el sistema operativo al conductor también es más o menos el mismo. A continuación se ofrece una breve introducción a algunos requisitos básicos para los controladores de dispositivos de red.

1.2.1 Enviar y recibir

Esta es la función más básica de un dispositivo de red. Lo que hace una tarjeta de red no es más que enviar y recibir trabajo. Por lo tanto, el controlador

debe decirle al sistema dónde está su función de envío, y el sistema llamará a su programa de envío cuando haya datos para enviar

. Además, debido a que el controlador manipula directamente el hardware, cuando el hardware de la red recibe datos, el primero en obtenerlos es el controlador. Es responsable de realizar el procesamiento necesario de los datos originales y luego enviarlos al sistema. p>

sistema. Aquí, el sistema operativo debe proporcionar dos mecanismos, uno es encontrar la función de envío del controlador y el otro es que el controlador envíe los datos recibidos al sistema.

1.2.2 Interrupciones

Las interrupciones juegan un papel importante en la arquitectura informática moderna. El sistema operativo debe proporcionar al conductor la capacidad de responder a las interrupciones

. Generalmente, se registra un controlador de interrupciones en el sistema. El sistema operativo llama al controlador del controlador después de que ocurre una interrupción del hardware.

Linux admite el uso compartido de interrupciones, es decir, varios dispositivos pueden compartir una interrupción.

1.2.3 Reloj

Al implementar un controlador, los relojes se utilizan en muchos lugares. Como el procesamiento de tiempo de espera en algunos protocolos, el sondeo de hardware sin mecanismo de interrupción, etc. El sistema operativo debe proporcionar un mecanismo de sincronización para el conductor. Generalmente, la función de reloj registrada se vuelve a llamar después de que haya pasado el tiempo predeterminado. En el controlador de red, si el hardware no tiene una función de interrupción, el temporizador puede proporcionar acceso de sondeo al hardware. O el tiempo de espera requerido al implementar ciertos protocolos

Retransmisión, etc.

2. Controlador de dispositivo de red del sistema Linux

2.1 Estructura del controlador de red

Todos los controladores de red de Linux siguen una interfaz común. El diseño adopta un enfoque orientado a objetos.

Un dispositivo es un objeto (estructura de dispositivo), que tiene sus propios datos y métodos en su interior. El primer parámetro cuando se llama al método

de cada dispositivo es el propio objeto del dispositivo. De esta forma, este método puede acceder a sus propios datos

(similar a esta referencia en programación orientada a objetos).

Los métodos más básicos de un dispositivo de red son la inicialización, el envío y la recepción.

------------------ ------------------------- -

|entregar paquetes | |recibir cola de paquetes|

|(dev_queue_xmit()) |ellos(netif_rx())

---- ---- ---------- ---------------------

| p>/ |

-------------------------------- --------------

| métodos y variables(inicializar,abrir,cerrar,hard_xmit,|

| controlador de interrupciones,config, recursos, estado...)

---------------------------------- ----- ------------------

| ----- ------------ -----------------------

|enviar a hardware |recepción desde hardware

----------------- ------------------- ---

| ------ --------------------------

| medios de hardware

----- ---------------------------------------------

El programa de inicialización completa la inicialización del hardware, la inicialización de variables en el dispositivo y la aplicación de recursos del sistema. El programa de envío

se llama automáticamente cuando la capa de protocolo superior del controlador tiene datos para enviar. Generalmente, el controlador no almacena en caché los datos enviados, sino que utiliza directamente la función de envío del hardware para enviar los datos. La recepción de datos generalmente se notifica mediante interrupciones de hardware.

En el controlador de interrupciones, complete la información del marco de hardware en una estructura skbuff y luego

------------------ Escritura del controlador de red del sistema operativo Linux -- ----------------

--------------------- Contactar con el autor por mailto: bordi@bordi.dhs.org ------

y luego llame a netif_rx() para pasarlo a la capa superior para su procesamiento.

2.2 Métodos básicos del controlador de red

Como objeto, un dispositivo de red proporciona algunos métodos para acceder al sistema. Son estos métodos con interfaces unificadas los que enmascaran los detalles específicos del hardware, permitiendo que el sistema acceda a varios dispositivos de red de forma unificada, logrando independencia del hardware.

.

El método más básico se explica a continuación.

2.2.1 Inicialización (initialize)

El controlador debe tener un método de inicialización. Este programa de inicialización se llamará al cargar el controlador en el sistema

. Realiza las siguientes tareas. Equipos de prueba. En el programa de inicialización, puede verificar si el hardware existe según sus características

y luego decidir si desea iniciar el controlador. Configure e inicialice el hardware. En el programa de inicialización, puede completar la configuración de los recursos de hardware. Por ejemplo, en este momento se puede configurar hardware plug-and-play (el kernel de Linux no tiene mucho soporte para la función PnP). Buen soporte, esta función se puede completar en el controlador

). Después de configurar o negociar los recursos ocupados por el hardware, puede solicitar estos recursos desde el sistema. Algunos recursos se pueden compartir con otros dispositivos, como las interrupciones. Algunos no se pueden compartir, como IO y DMA. A continuación, debe inicializar las variables en la estructura del dispositivo. Finalmente, puedes poner el hardware a funcionar.

2.2.2 Abrir (abrir)

El método de apertura se llama en el controlador del dispositivo de red cuando el dispositivo de red está activado (es decir, el estado del dispositivo

El estado es de abajo-->arriba). En realidad, gran parte del trabajo de inicialización se puede realizar aquí. Por ejemplo, aplicación de recursos y activación de hardware. Si dev->open devuelve un valor distinto de 0 (error), el estado del hardware aún está inactivo.

Otra función del método open es que si el controlador se carga como módulo, es para evitar que el dispositivo se abra cuando se descarga el módulo.

La macro MOD_INC_USE_COUNT debe llamarse en el método abierto.

2.2.3 Cerrar (detener)

El método cerrar hace lo contrario que abrir. Se pueden liberar ciertos recursos para reducir la carga del sistema. Se llama a close cuando el estado del dispositivo cambia de arriba a abajo. Además, si el controlador se carga como un módulo, se debe llamar a MOD_DEC_USE_COUNT en close

para reducir la cantidad de veces que se hace referencia al dispositivo para que se pueda desinstalar el controlador.

Además, el método close debe devolver éxito (0==éxito).

2.2.4 Enviar (hard_start_xmit)

Todos los controladores de dispositivos de red deben tener este método de envío. Cuando el sistema llama al xmit del conductor

, los datos enviados se colocan en una estructura sk_buff. El controlador general pasa los datos al hardware y los envía.

También existen algunos dispositivos especiales, como el loopback, que combina los datos en datos recibidos y los envía de vuelta al sistema, o

dispositivo ficticio que descarta los datos directamente.

Si el envío es exitoso, el sk_buff se libera en el método hard_start_xmit y devuelve 0 (envío exitoso). Si

el dispositivo no puede manejarlo temporalmente, como si el hardware está ocupado, se devolverá 1.

En este momento, si dev->tbusy está configurado en distinto de 0, el sistema

considera que el hardware está ocupado y esperará hasta que dev->tbusy esté establecido en 0 antes de enviar nuevamente. La tarea de establecer tbusy en 0 generalmente se completa mediante una interrupción

. El hardware genera una interrupción una vez completada la transmisión. En este momento, puede configurar tbusy en 0 y luego usar mark_bh() para llamar a la notificación.

El sistema puede enviar nuevamente. En caso de que la transmisión no tenga éxito, también puede configurar dev->tbusy en un valor distinto de 0, para que el sistema continúe intentando reenviar. Si hard_start_xmit no se envía correctamente, no libere sk_buff.

Los datos en el sk_buff transmitido ya contienen el encabezado del marco requerido por el hardware. Por lo tanto, no es necesario completar el encabezado del marco del hardware en el método de envío y los datos se pueden enviar directamente al hardware para su envío. sk_buff está bloqueado para garantizar que otros programas no puedan acceder a él.

2.2.5 Recepción

El conductor no dispone de método de recepción. El conductor debe notificar al sistema cuando se reciben datos.

Generalmente, el dispositivo generará una interrupción después de recibir los datos. En el controlador de interrupciones, el controlador solicita una parte de sk_buff (skb), lee los datos del hardware y los coloca en el aplicado. Distrito de amortiguamiento. A continuación, complete cierta información en sk_buff

. skb->dev = dev, determina el tipo de protocolo de la trama recibida, completa skb->protocol (soporte multiprotocolo). Apunte el puntero skb->mac.raw a los datos del hardware y descarte el encabezado del marco del hardware (skb_pull). También

establezca skb->pkt_type para indicar el tipo de datos de la segunda capa (capa de enlace). Puede ser de los siguientes tipos:

PACKET_BROADCAST: Difusión de capa de enlace

PACKET_MULTICAST: Multidifusión de capa de enlace

PACKET_SELF: Trama enviada a sí misma

PACKET_OTHERHOST: Trama enviada a otros (este tipo de trama aparecerá en modo de escucha)

Finalmente, se llama a netif_rx() para transmitir los datos a la capa de protocolo. Los datos en netif_rx() se colocan en la cola de procesamiento y luego se devuelven. El procesamiento real se realiza después de que regresa la interrupción, lo que puede reducir el tiempo de interrupción. Después de llamar a netif_rx(),

el controlador ya no puede acceder al búfer de datos skb.

2.2.6 Encabezado de trama de hardware (hard_header)

El hardware generalmente agrega su propio encabezado de trama de hardware antes de enviar datos de capa superior, como Ethernet (Ethernet)

tiene un encabezado de trama de 14 bytes. Este encabezado de marco se agrega delante de la capa superior ip, ipx y otros paquetes de datos. El controlador proporciona un método hard_header. La capa de protocolo (ip, ipx, arp, etc.) llamará a este programa antes de enviar datos.

La longitud del encabezado de hardware debe completarse en dev->hard_header_len, para que la capa de protocolo reserve el espacio del encabezado de hardware antes de los datos.

De esta manera, el programa hard_header solo necesita llamar a skb_push y luego completar correctamente el encabezado del marco del hardware.

Eso es todo.

Al llamar a hard_header en la capa de protocolo, los parámetros transmitidos incluyen (2.0.xx): sk_buff de datos,

puntero del dispositivo, protocolo, dirección de destino (daddr), dirección de origen ( saddr) ), longitud de datos (len). Datos

No utilice los parámetros en sk_buff para la longitud, porque es posible que los datos no estén completamente organizados cuando se llama a hard_header.

Si saddr es NULL, se utiliza la dirección predeterminada (predeterminada).

daddr es NULL, lo que indica que la capa de protocolo no conoce la dirección del destino del hardware

. Si hard_header completa completamente el encabezado del hardware, se devuelve el número de bytes agregados. Si la información en el encabezado de la trama de hardware está incompleta (por ejemplo, daddr es NULL, pero se requiere la dirección del hardware de destino en el encabezado de la trama. Una situación típica es que Ethernet requiere resolución de dirección (arp)), devuelve un número negativo de. bytes. Cuando hard_header devuelve un número negativo, la capa de protocolo trabajará más para crear el encabezado. Actualmente, arp se realiza en el sistema Linux

(Si hard_header devuelve positivo, dev->arp=1, indica que no es necesario realizar arp y devuelve negativo, dev->arp=0 ,

hacer arp).

La llamada a hard_header está en el controlador de cada capa de protocolo. Como ip_output.

2.2.7 Resolución de direcciones (xarp)

Algunas redes tienen direcciones de hardware (como Ethernet) y es necesario conocer la dirección de hardware de destino al enviar tramas de hardware

. Esto requiere la correspondencia entre la dirección del protocolo de capa superior (ip, ipx) y la dirección del hardware. Esta correspondencia se realiza mediante resolución de domicilio

. Los dispositivos que requieren arp llamarán al método build_header del controlador antes de enviar. Los principales parámetros de la llamada incluyen el puntero al encabezado de la trama de hardware y la dirección de la capa de protocolo. Si el controlador puede resolver la dirección del hardware, devuelve 1; si no, devuelve 0.

La llamada a reconstruir_header está en do_dev_queue_xmit() en net/core/dev.c.

2.2.8 Configuración de parámetros y datos estadísticos

El controlador también proporciona algunos métodos para que el sistema configure los parámetros del dispositivo y lea información. General

Solo la autoridad de superusuario (root) puede configurar los parámetros del dispositivo. Los métodos de configuración son:

dev->set_mac_address()

Cuando el usuario llama al tipo ioctl como SIOCSIFHWADDR, se configura la dirección mac de este dispositivo. Generalmente

La configuración de la dirección mac no tiene mucho sentido.

dev->set_config()

----------------- Escritura del controlador de red del sistema operativo Linux----- - -------------

------------ Contactar con el autor por mailto:bordi@bordi.dhs.org ---- - -

Cuando el usuario llama a ioctl y el tipo es SIOCSIFMAP, el sistema llamará al método set_config

del controlador. El usuario pasará una estructura ifmap que contiene las E/S requeridas, interrupciones y otros parámetros.

dev->do_ioctl()

Si el tipo está entre SIOCDEVPRIVATE y SIOCDEVPRIVATE+15 cuando el usuario llama a ioctl, el sistema

llamará a este método de el conductor. Generalmente, es para configurar los datos especiales del dispositivo.

La lectura de información también se realiza mediante llamadas ioctl. Además de esto, el controlador también puede proporcionar un método

dev->get_stats, que devuelve una estructura enet_statistics que contiene información estadística sobre el envío y la recepción.

El procesamiento de ioctl está en dev_ioctl() y dev_ifsioc() de net/core/dev.c.