Il existe un pilote de périphérique pour chaque type de NIC. De l'intérieur, Linux appellera TOUJOURS une routine standard de haut niveau: "netif_rx [net/core/dev.c]", qui contrôlera à quel protocole de niveau 3 le cadre appartient, et il appellera la bonne fonction de niveau 3 (ainsi nous utiliserons un pointeur vers la fonction pour déterminer laquelle est la bonne). (There exists a device driver for each kind of NIC. Inside it, Linux will ALWAYS call a standard high level routing: "netif_rx [net/core/dev.c]", which will controls what 3 level protocol the frame belong to, and it will call the right 3 level function (so we'll use a pointer to the function to determine which is right).
Nous allons voir maintenant un exemple de ce qui se produit quand nous envoyons un paquet TCP à Linux, à partir de l'appel ''netif_rx [net/core/dev.c] ''.
|netif_rx |__skb_queue_tail |qlen++ |* simple pointer insertion * |cpu_raise_softirq |softirq_active(cpu) |= (1 << NET_RX_SOFTIRQ) // met l'octet NET_RX_SOFTIRQ dans le vecteur BH
Fonctions:
Une fois que l'interaction d'IRQ est finie, nous devons suivre la prochaine partie de la vie du cadre et examiner ce que fait NET_RX_SOFTIRQ.
Nous appellerons ensuite ''net_rx_action [net/core/dev.c]'' selon "net_dev_init [net/core/dev.c]".
|net_rx_action |skb = __skb_dequeue (the exact opposite of __skb_queue_tail) |for (ptype = first_protocol; ptype < max_protocol; ptype++) // Determine |if (skb->protocol == ptype) // what is the network protocol |ptype->func -> ip_rcv // according to ''struct ip_packet_type [net/ipv4/ip_output.c]'' **** MAINTENANT NOUS SAVONS QUEL PAQUET EST IP **** |ip_rcv |NF_HOOK (ip_rcv_finish) |ip_route_input // cherche dans la table de routage pour déterminer la fonction à appeler |skb->dst->input -> ip_local_deliver // selon la précédente vérification de la table de routage, la destination est la machine locale |ip_defrag // rassemble les fragments IP |NF_HOOK (ip_local_deliver_finish) |ipprot->handler -> tcp_v4_rcv // selon ''tcp_protocol [include/net/protocol.c]'' **** MAINTENANT NOUS SAVONS QUEL PAQUET EST TCP **** |tcp_v4_rcv |sk = __tcp_v4_lookup |tcp_v4_do_rcv |switch(sk->state) *** Le paquet peut être envoyé à la tâche qui utilise une connexion (socket) relative *** |case TCP_ESTABLISHED: |tcp_rcv_established |__skb_queue_tail // enfile le packet vers la connexion |sk->data_ready -> sock_def_readable |wake_up_interruptible *** Le packet est toujours pris en main par le 3-way TCP handshake *** |case TCP_LISTEN: |tcp_v4_hnd_req |tcp_v4_search_req |tcp_check_req |syn_recv_sock -> tcp_v4_syn_recv_sock |__tcp_v4_lookup_established |tcp_rcv_state_process *** 3-Way TCP Handshake *** |switch(sk->state) |case TCP_LISTEN: // We received SYN |conn_request -> tcp_v4_conn_request |tcp_v4_send_synack // Send SYN + ACK |tcp_v4_synq_add // set SYN state |case TCP_SYN_SENT: // we received SYN + ACK |tcp_rcv_synsent_state_process tcp_set_state(TCP_ESTABLISHED) |tcp_send_ack |tcp_transmit_skb |queue_xmit -> ip_queue_xmit |ip_queue_xmit2 |skb->dst->output |case TCP_SYN_RECV: // We received ACK |if (ACK) |tcp_set_state(TCP_ESTABLISHED)
Fonctions ci-dessous:
Description:
SERVEUR (ECOUTE) CLIENT (CONNECTING) SYN <------------------- SYN + ACK -------------------> ACK <------------------- 3-Way TCP handshake