Sophie

Sophie

distrib > Mandriva > 9.1 > i586 > by-pkgid > f1098342ec4a2b28475e34123ce17201 > files > 517

howto-html-it-9.1-0.5mdk.noarch.rpm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
 <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
 <TITLE>KernelAnalysis-HOWTO: La Rete su Linux</TITLE>
 <LINK HREF="KernelAnalysis-HOWTO-9.html" REL=next>
 <LINK HREF="KernelAnalysis-HOWTO-7.html" REL=previous>
 <LINK HREF="KernelAnalysis-HOWTO.html#toc8" REL=contents>
</HEAD>
<BODY>
<A HREF="KernelAnalysis-HOWTO-9.html">Next</A>
<A HREF="KernelAnalysis-HOWTO-7.html">Previous</A>
<A HREF="KernelAnalysis-HOWTO.html#toc8">Contents</A>
<HR>
<H2><A NAME="s8">8. La Rete su Linux</A></H2>

<H2><A NAME="ss8.1">8.1 Come viene gestita la Rete su Linux?</A>
</H2>

<P>Per ogni tipo di NIC vi e' un device driver che lo gestisce (ad
esempio per la il device NE2000 compatibile oppure per la periferica
3COM 3C59X, ecc.).
<P>Dopo il device a basso livello, Linux chiama SEMPRE la routine
di routing ad alto livello "netif_rx [net/core/dev.c]", che
controlla:
<P>
<UL>
<LI>A quale protocollo di 3 livello appartiene il pacchetto in questione</LI>
<LI>Quale chiamata (tramite puntatori virtuali) eseguire per gestirlo</LI>
</UL>
<H2><A NAME="ss8.2">8.2 Esempio pratico: TCP</A>
</H2>

<P>Vedremo un esempio di quello che accade quando mandamo dobbiamo
ricevere un pacchetto TCP, partendo dalla ''netif_rx [net/core/dev.c]''
(in sostanza analizziamo ''a grandi linee'' lo stack TCP/IP di Linux).
<H3>Gestione Interrupt: "netif_rx"</H3>

<P>
<PRE>
|netif_rx
   |__skb_queue_tail
      |qlen++
      |* Inserimento tramite puntatori nella coda pacchetti*    
   |cpu_raise_softirq
      |softirq_active(cpu) |= (1 &lt;&lt; NET_RX_SOFTIRQ) // settiamo il  bit NET_RX_SOFTIRQ nel vettore BH
 
</PRE>
<P>
<UL>
<LI>__skb_queue_tail [include/linux/skbuff.h]</LI>
<LI>cpu_raise_softirq [kernel/softirq.c]</LI>
</UL>
<H3>Gestione Post Interrupt: "net_rx_action"</H3>

<P>Una volta che l'interazione IRQ e' terminata, seguiamo cosa accade
in fase di scheduling quando si esegue il BH relativo alla rete che
abbiamo attivato tramite NET_RX_SOFTIRQ: in pratica andiamo a chiamare
la ''net_rx_action [net/core/dev.c]'' come specificato
da "net_dev_init [net/core/dev.c]".
<P>
<PRE>
|net_rx_action
   |skb = __skb_dequeue (operazione inversa della __skb_queue_tail)
   |for (ptype = first_protocol; ptype &lt; max_protocol; ptype++) // Determiniamo 
      |if (skb-&gt;protocol == ptype)                               // qual'e' il protocollo di rete
         |ptype-&gt;func -&gt; ip_rcv // come specificato sulla ''struct ip_packet_type [net/ipv4/ip_output.c]''
 
    **** ADESSO SAPPIAMO CHE IL PACCHETTO E' DI TIPO IP ****
         |ip_rcv
            |NF_HOOK (ip_rcv_finish)
               |ip_route_input // accediamo alla tabella di routing per capire qual e' la funzione da chiamare (qual e' cioe' l'interfaccia)
                  |skb-&gt;dst-&gt;input -&gt; ip_local_deliver // come da controllo della tabella di routing la destinazione e' la macchina locale
                     |ip_defrag // riassembliamo i frammenti IP
                        |NF_HOOK (ip_local_deliver_finish)
                           |ipprot-&gt;handler -&gt; tcp_v4_rcv // come da ''tcp_protocol [include/net/protocol.c]''
 
     **** ADESSO SAPPIAMO CHE IL PACCHETTO E' TCP ****
                           |tcp_v4_rcv   
                              |sk = __tcp_v4_lookup 
                              |tcp_v4_do_rcv
                                 |switch(sk-&gt;state) 

     *** Il pacchetto puo' essere mandato al Task tramite il socket aperto ***
                                 |case TCP_ESTABLISHED:
                                    |tcp_rcv_established
                                       |__skb_queue_tail // accoda il pacchetto sul socket
                                       |sk-&gt;data_ready -&gt; sock_def_readable 
                                          |wake_up_interruptible
                                

     *** Dobbiamo gestire il 3-way TCP handshake ***
                                 |case TCP_LISTEN:
                                    |tcp_v4_hnd_req
                                       |tcp_v4_search_req
                                       |tcp_check_req
                                          |syn_recv_sock -&gt; tcp_v4_syn_recv_sock
                                       |__tcp_v4_lookup_established
                                 |tcp_rcv_state_process

                    *** 3-Way TCP Handshake ***
                                    |switch(sk-&gt;state)
                                    |case TCP_LISTEN: // Riceviamo il SYN
                                       |conn_request -&gt; tcp_v4_conn_request
                                          |tcp_v4_send_synack // Mandiamo SYN + ACK
                                             |tcp_v4_synq_add // settiamo lo stato SYN
                                    |case TCP_SYN_SENT: // riceviamo SYN + ACK
                                       |tcp_rcv_synsent_state_process
                                          tcp_set_state(TCP_ESTABLISHED)
                                             |tcp_send_ack
                                                |tcp_transmit_skb
                                                   |queue_xmit -&gt; ip_queue_xmit
                                                      |ip_queue_xmit2
                                                         |skb-&gt;dst-&gt;output
                                    |case TCP_SYN_RECV: // Riceviamo ACK
                                       |if (ACK)
                                          |tcp_set_state(TCP_ESTABLISHED)
                              
</PRE>
<P>
<UL>
<LI>net_rx_action [net/core/dev.c]</LI>
<LI>__skb_dequeue [include/linux/skbuff.h]</LI>
<LI>ip_rcv [net/ipv4/ip_input.c]</LI>
<LI>NF_HOOK -&gt; nf_hook_slow [net/core/netfilter.c]</LI>
<LI>ip_rcv_finish [net/ipv4/ip_input.c]</LI>
<LI>ip_route_input [net/ipv4/route.c]</LI>
<LI>ip_local_deliver [net/ipv4/ip_input.c]</LI>
<LI>ip_defrag [net/ipv4/ip_fragment.c]</LI>
<LI>ip_local_deliver_finish [net/ipv4/ip_input.c]</LI>
<LI>tcp_v4_rcv [net/ipv4/tcp_ipv4.c]</LI>
<LI>__tcp_v4_lookup</LI>
<LI>tcp_v4_do_rcv</LI>
<LI>tcp_rcv_established [net/ipv4/tcp_input.c]</LI>
<LI>__skb_queue_tail [include/linux/skbuff.h]</LI>
<LI>sock_def_readable [net/core/sock.c]</LI>
<LI>wake_up_interruptible [include/linux/sched.h]</LI>
<LI>tcp_v4_hnd_req [net/ipv4/tcp_ipv4.c]</LI>
<LI>tcp_v4_search_req</LI>
<LI>tcp_check_req</LI>
<LI>tcp_v4_syn_recv_sock</LI>
<LI>__tcp_v4_lookup_established</LI>
<LI>tcp_rcv_state_process [net/ipv4/tcp_input.c]</LI>
<LI>tcp_v4_conn_request [net/ipv4/tcp_ipv4.c]</LI>
<LI>tcp_v4_send_synack</LI>
<LI>tcp_v4_synq_add</LI>
<LI>tcp_rcv_synsent_state_process [net/ipv4/tcp_input.c]</LI>
<LI>tcp_set_state [include/net/tcp.h]</LI>
<LI>tcp_send_ack [net/ipv4/tcp_output.c]</LI>
</UL>
<P>Descrizione:
<P>
<UL>
<LI>Prima determiniamo il tipo di protocollo (IP, poi TCP)</LI>
<LI>NF_HOOK (funzione) e' una routine di incapsulazione che prima
gestisce il filtro di rete (firewall), eppoi chiama la ''funzione''.</LI>
<LI>Dopo gestiamo il 3-way TCP Handshake:</LI>
</UL>
<P>
<PRE>
SERVER (LISTENING)                       CLIENT (CONNECTING)
                           SYN 
                   &lt;-------------------
 
 
                        SYN + ACK
                   -------------------&gt;

 
                           ACK 
                   &lt;-------------------

                    3-Way TCP handshake
</PRE>
<P>
<UL>
<LI>Alla fine dobbiamo solo piu' lanciare "tcp_rcv_established [net/ipv4/tcp_input.c]"
che manda il pacchetto al socket e sveglia il processo in attesa
dello stesso</LI>
</UL>
<HR>
<A HREF="KernelAnalysis-HOWTO-9.html">Next</A>
<A HREF="KernelAnalysis-HOWTO-7.html">Previous</A>
<A HREF="KernelAnalysis-HOWTO.html#toc8">Contents</A>
</BODY>
</HTML>