Vamos revisar rapidamente os arquivos do dispositivo: No Linux, os programas aplicativos comunicam operações de rad e write ao kernel através de descritores de arquivos . Isso funciona muito bem para arquivos, e acabou que a mesma API pode ser usada para dispositivos de caracteres que produzem e consomem fluxos de caracteres e bloqueiam dispositivos que lêem e gravam blocos de tamanho fixo em um endereço de acesso aleatório, apenas fingindo que esses também são arquivos.
Mas era necessário um modo de configurar esses dispositivos (definir taxas de transmissão etc.) e, para isso, a chamada ioctl foi inventada. Ele apenas passa uma estrutura de dados específica para o dispositivo e o tipo de controle de E / S usado no kernel e retorna os resultados na mesma estrutura de dados, portanto, é uma API extensível muito genérica e pode ser usada para muitas coisas .
Agora, como as operações de rede se encaixam? Um aplicativo típico de servidor de rede deseja se conectar a algum endereço de rede, escutar em uma determinada porta (por exemplo, 80 para HTTP ou 22 para ssh) e, se um cliente se conectar , ele deseja enviar e receber dados desse cliente. E as operações duplas para o cliente.
Não é óbvio como encaixar isso nas operações de arquivo (embora isso possa ser feito, consulte o Plano 9 ), é por isso que os designers do UNIX inventaram uma nova API: sockets . Você pode encontrar mais detalhes nas páginas man Seção 2 para socket
, bind
, listen
, connect
, send
e recv
. Observe que, embora seja diferente da API de E / S do arquivo, a socket
chamada também retorna um descritor de arquivo. Existem inúmeros tutoriais sobre como usar soquetes na web, o google um pouco.
Até agora, tudo isso é puro UNIX, ninguém estava falando sobre interfaces de rede no momento em que os soquetes foram inventados. E como essa API é realmente antiga, é definida para uma variedade de protocolos de rede além do protocolo da Internet (observe as AF_*
constantes), embora apenas alguns sejam suportados no Linux.
Porém, quando os computadores começaram a receber várias placas de rede, era necessária alguma abstração para isso. No Linux, essa é a interface de rede (NI). Ele não é usado apenas para uma peça de hardware, mas também para vários túneis, pontos de extremidade de aplicativos do usuário que funcionam como túneis como o OpenVPN etc. Como explicado, a API do soquete não é baseada em arquivos (especiais) e independente do sistema de arquivos. Da mesma forma, as interfaces de rede também não aparecem no sistema de arquivos. No entanto, as NIs são disponibilizadas no sistema de arquivos /proc
e /sys
(assim como em outros ajustes de rede).
Uma NI é uma abstração simples de um ponto final em que os pacotes de rede entram e saem do kernel. Os soquetes, por outro lado, são usados para comunicar pacotes com aplicativos. Nenhum soquete precisa estar envolvido no processamento de um pacote. Por exemplo, quando o encaminhamento está ativado, um pacote pode entrar em um NI e sair no outro. Nesse sentido, soquetes e interfaces de rede são totalmente independentes.
Mas tinha que haver uma maneira de configurar as NIs, assim como você precisava de uma maneira de configurar dispositivos de blocos e caracteres. E como os soquetes já retornaram um descritor de arquivo, era lógico permitir apenas um ioctl
descritor nesse arquivo. Essa é a interface do netdevice que você vinculou.
Existem muitos outros abusos de chamadas do sistema de maneira semelhante, por exemplo, para filtragem de pacotes, captura de pacotes etc.
Tudo isso cresceu peça após peça e não é particularmente lógico em muitos lugares. Se tivesse sido projetado de uma só vez, provavelmente seria possível criar uma API mais ortogonal.