转载地址
作者:闫明
本文分析基于Linux Kernel 1.2.13
注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析、”(下)“表示分析是从上向下分析。
?上篇:
上一篇博文中我们从宏观上分析了Linux内核中网络栈的初始化过程,这里我们再从宏观上分析一下一个数据包在各网络层的传递的过程。
我们知道网络的OSI模型和TCP/IP模型层次结构如下:

上文中我们看到了网络栈的层次结构:

我们就从最底层开始追溯一个数据包的传递流程。
1、网络接口层
* 硬件监听物理介质,进行数据的接收,当接收的数据填满了缓冲区,硬件就会产生中断,中断产生后,系统会转向中断服务子程序。
* 在中断服务子程序中,数据会从硬件的缓冲区复制到内核的空间缓冲区,并包装成一个数据结构(sk_buff),然后调用对驱动层的接口函数netif_rx()将数据包发送给链路层。该函数的实现在net/inet/dev.c中,(在整个网络栈实现中dev.c文件的作用重大,它衔接了其下的驱动层和其上的网络层,可以称它为链路层模块的实现)
该函数的实现如下:
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools">
[cpp]?<a class="ViewSource" title="view plain" href="http://blog.csdn.net/geekcome/article/details/7492423">view plain<a class="CopyToClipboard" title="copy" href="http://blog.csdn.net/geekcome/article/details/7492423">copy
?
- ??
- ?netif_rx(?sk_buff?*skb)??
- {??
- ??????dropping?=?0;??
- ??
- ????
- ????skb->sk?=?NULL;??
- ????skb->free?=?1;??
- ????(skb->stamp.tv_sec==0)??
- ????????skb->stamp?=?xtime;??
- ??
- ????
- ??
- ?????(!backlog_size)??
- ????????dropping?=?0;??
- ??????(backlog_size?>?300)??
- ????????dropping?=?1;??
- ??
- ?????(dropping)???
- ????{??
- ????????kfree_skb(skb,?FREE_READ);??
- ????????;??
- ????}??
- ??
- ????
- ??
- ????IS_SKB(skb);??
- ??
- ????skb_queue_tail(&backlog,skb);
- ????backlog_size++;??
- ????
- ????
- ??
- ????mark_bh(NET_BH);
- ????;??
- }??
该函数中用到了bootom half技术,该技术的原理是将中断处理程序人为的分为两部分,上半部分是实时性要求较高的任务,后半部分可以稍后完成,这样就可以节省中断程序的处理时间。可整体的提高系统的性能。该技术将会在后续的博文中详细分析。
我们从上一篇分析中知道,在网络栈初始化的时候,已经将NET的下半部分执行函数定义成了net_bh(在socket.c文件中1375行左右)
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools">
[cpp]?<a class="ViewSource" title="view plain" href="http://blog.csdn.net/geekcome/article/details/7492423">view plain<a class="CopyToClipboard" title="copy" href="http://blog.csdn.net/geekcome/article/details/7492423">copy
?
bh_base[NET_BH].routine=?net_bh;
* 函数net_bh的实现在net/inet/dev.c中
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools">
[cpp]?<a class="ViewSource" title="view plain" href="http://blog.csdn.net/geekcome/article/details/7492423">view plain<a class="CopyToClipboard" title="copy" href="http://blog.csdn.net/geekcome/article/details/7492423">copy
?
- ???
- ?net_bh(?*tmp)??
- {??
- ?????sk_buff?*skb;??
- ?????packet_type?*ptype;??
- ?????packet_type?*pt_prev;??
- ????unsigned??type;??
- ??
- ????
- ??
- ?????(set_bit(1,?(*)&in_bh))
- ????????;??
- ??
- ????
- ??
- ????dev_transmit();
- ????
- ????
- ??
- ????cli();
- ??????
- ????
- ???????
- ????((skb=skb_dequeue(&backlog))!=NULL)
- ????{??
- ????????
- ????????backlog_size--;
- ??
- ????????sti();??
- ??????????
- ???????????
- ??
- ????????skb->h.raw?=?skb->data?+?skb->dev->hard_header_len;??
- ????????skb->len?-=?skb->dev->hard_header_len;??
- ??
- ???????????
- ??????????
- ????????type?=?skb->dev->type_trans(skb,?skb->dev);
- ??
- ????????
- ????????pt_prev?=?NULL;??
- ?????????(ptype?=?ptype_base;?ptype?!=?NULL;?ptype?=?ptype->next)?
- ????????{??
- ????????????
- ?????????????((ptype->type?==?type?||?ptype->type?==?htons(ETH_P_ALL))?&&?(!ptype->dev?||?ptype->dev==skb->dev))??
- ????????????{??
- ????????????????
- ????????????????(pt_prev)??
- ????????????????{??
- ?????????????????????sk_buff?*skb2;??
- ??
- ????????????????????skb2=skb_clone(skb,?GFP_ATOMIC);
- ??
- ????????????????????
- ??
- ????????????????????(skb2)??
- ????????????????????????pt_prev->func(skb2,?skb->dev,?pt_prev);
- ????????????????????????????????????????????
- ????????????????????????????????????????????
- ????????????????}??
- ????????????????
- ????????????????pt_prev=ptype;??
- ????????????}??
- ????????}?
- ??????????
- ????????
- ??
- ????????(pt_prev)??
- ????????????pt_prev->func(skb,?pt_prev);??
- ????????
- ???????
- ??????????
- ????????????kfree_skb(skb,?FREE_WRITE);??
- ??
- ????????
- ??
- ????????dev_transmit();??
- ????????cli();??
- ????}???
- ??????
- ????
- ???????
- ????in_bh?=?0;
- ????sti();??
- ??????
- ????
- ???????
- ????dev_transmit();
- }??
2、网络层* 就以IP数据包为例来说明,那么从链路层向网络层传递时将调用ip_rcv函数。该函数完成本层的处理后会根据IP首部中使用的传输层协议来调用相应协议的处理函数。
UDP对应udp_rcv、TCP对应tcp_rcv、ICMP对应icmp_rcv、IGMP对应igmp_rcv(虽然这里的ICMP,IGMP一般成为网络层协议,但是实际上他们都封装在IP协议里面,作为传输层对待)
这个函数比较复杂,后续会详细分析。这里粘贴一下,让我们对整体了解更清楚
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools">
[cpp]?<a class="ViewSource" title="view plain" href="http://blog.csdn.net/geekcome/article/details/7492423">view plain<a class="CopyToClipboard" title="copy" href="http://blog.csdn.net/geekcome/article/details/7492423">copy
?
- ??
- ?ip_rcv(?sk_buff?*skb,??device?*dev,??packet_type?*pt)??
- {??
- ?????iphdr?*iph?=?skb->h.iph;??
- ?????sock?*raw_sk=NULL;??
- ????unsigned??hash;??
- ????unsigned??flag?=?0;??
- ????unsigned??opts_p?=?0;???
- ?????inet_protocol?*ipprot;??
- ??????options?opt;?
- ?????brd=IS_MYADDR;??
- ?????is_frag=0;??
- ??
- ?????err;??
- ??
- ??
- ????ip_statistics.IpInReceives++;??
- ??
- ????
- ??
- ????skb->ip_hdr?=?iph;??
- ??
- ????
- ??
- ?????(skb->len<(?iphdr)?||?iph->ihl<5?||?iph->version?!=?4?||??
- ????????skb->lentot_len)?||?ip_fast_csum((unsigned??*)iph,?iph->ihl)?!=0)??
- ????{??
- ????????ip_statistics.IpInHdrErrors++;??
- ????????kfree_skb(skb,?FREE_WRITE);??
- ????????(0);??
- ????}??
- ??????
- ????
- ??
- ??
- ??????
- ?????((err=ip_fw_chk(iph,dev,ip_fw_blk_chain,ip_fw_blk_policy,?0))!=1)??
- ????{??
- ????????(err==-1)??
- ????????????icmp_send(skb,?ICMP_DEST_UNREACH,?ICMP_PORT_UNREACH,?0,?dev);??
- ????????kfree_skb(skb,?FREE_WRITE);??
- ?????????0;?????
- ????}??
- ??
- ??
- ??????
- ????
- ??
- ????skb->len=ntohs(iph->tot_len);??
- ??
- ????
- ??
- ?????(iph->ihl?!=?5)??
- ????{???
- ????????memset((?*)?&opt,?(opt));??
- ?????????(do_options(iph,?&opt)?!=?0)??
- ?????????????0;??
- ????????opts_p?=?1;??
- ????}??
- ??
- ????
- ???????
- ????(iph->frag_off)??
- ????{??
- ?????????(iph->frag_off?&?0x0020)??
- ????????????is_frag|=1;??
- ????????
- ??????
- ?????????(ntohs(iph->frag_off)?&?0x1fff)??
- ????????????is_frag|=2;??
- ????}??
- ??????
- ????
- ??
- ?????(?iph->daddr?!=?skb->dev->pa_addr?&&?(brd?=?ip_chk_addr(iph->daddr))?==?0)??
- ????{??
- ????????
- ??
- ????????(skb->pkt_type!=PACKET_HOST?||?brd==IS_BROADCAST)??
- ????????{??
- ????????????kfree_skb(skb,FREE_WRITE);??
- ?????????????0;??
- ????????}??
- ??
- ????????
- ??
- ??
- ????????ip_forward(skb,?dev,?is_frag);??
- ??
- ??
- ????????ip_statistics.IpInAddrErrors++;??
- ??
- ????????
- ??
- ????????kfree_skb(skb,?FREE_WRITE);??
- ????????(0);??
- ????}??
- ??????
- ??
- ??
- ????(brd==IS_MULTICAST?&&?iph->daddr!=IGMP_ALL_HOSTS?&&?!(dev->flags&IFF_LOOPBACK))??
- ????{??
- ????????
- ?????????ip_mc_list?*ip_mc=dev->ip_mc_list;??
- ??????????
- ????????{??
- ????????????(ip_mc==NULL)??
- ????????????{?????
- ????????????????kfree_skb(skb,?FREE_WRITE);??
- ?????????????????0;??
- ????????????}??
- ????????????(ip_mc->multiaddr==iph->daddr)??
- ????????????????;??
- ????????????ip_mc=ip_mc->next;??
- ????????}??
- ????????(1);??
- ????}??
- ??
- ????
- ???????
- ??
- ????ip_acct_cnt(iph,?ip_acct_chain);??
- ??
- ??
- ????
- ??
- ????(is_frag)??
- ????{??
- ????????
- ????????skb=ip_defrag(iph,skb,dev);??
- ????????(skb==NULL)??
- ?????????????0;??
- ????????skb->dev?=?dev;??
- ????????iph=skb->h.iph;??
- ????}??
- ??????
- ???????????
- ??
- ????
- ??
- ????skb->ip_hdr?=?iph;??
- ????skb->h.raw?+=?iph->ihl*4;??
- ??????
- ????
- ???????
- ????hash?=?iph->protocol?&?(SOCK_ARRAY_SIZE-1);??
- ??????
- ????
- ????((raw_sk=raw_prot.sock_array[hash])!=NULL)??
- ????{??
- ?????????sock?*sknext=NULL;??
- ?????????sk_buff?*skb1;??
- ????????raw_sk=get_sock_raw(raw_sk,?hash,??iph->saddr,?iph->daddr);??
- ????????(raw_sk)??
- ????????{??
- ??????????????
- ????????????{??
- ????????????????
- ????????????????sknext=get_sock_raw(raw_sk->next,?iph->saddr,?iph->daddr);??
- ????????????????(sknext)??
- ????????????????????skb1=skb_clone(skb,?GFP_ATOMIC);??
- ??????????????????
- ????????????????????;??
- ????????????????(skb1)??
- ????????????????????raw_rcv(raw_sk,?skb1,iph->daddr);??
- ????????????????raw_sk=sknext;??
- ????????????}??
- ????????????(raw_sk!=NULL);??
- ????????????
- ????????????
- ????????}??
- ????}??
- ??????
- ????
- ?
- ??
- ????hash?=?iph->protocol?&?(MAX_INET_PROTOS?-1);??
- ?????(ipprot?=?(?inet_protocol?*)inet_protos[hash];ipprot?!=?NULL;ipprot=(?inet_protocol?*)ipprot->next)??
- ????{??
- ?????????sk_buff?*skb2;??
- ??
- ?????????(ipprot->protocol?!=?iph->protocol)??
- ????????????;??
- ???????
- ?????????(ipprot->copy?||?raw_sk)??
- ????????{??
- ????????????skb2?=?skb_clone(skb,?GFP_ATOMIC);??
- ????????????(skb2==NULL)??
- ????????????????;??
- ????????}??
- ??????????
- ????????{??
- ????????????skb2?=?skb;??
- ????????}??
- ????????flag?=?1;??
- ??
- ???????????
- ????????ipprot->handler(skb2,?opts_p???&opt?:?0,?iph->daddr,??
- ????????????????(ntohs(iph->tot_len)?-?(iph->ihl?*?4)),??
- ????????????????iph->saddr,?ipprot);??
- ??
- ????}??
- ??
- ????
- ??
- ????(raw_sk!=NULL)????
- ????????raw_rcv(raw_sk,?skb,?iph->daddr);??
- ??????(!flag)?????
- ????{??
- ?????????(brd?!=?IS_BROADCAST?&&?brd!=IS_MULTICAST)??
- ????????????icmp_send(skb,?ICMP_PROT_UNREACH,?FREE_WRITE);??
- ????}??
- ??
- ????(0);??
- }??
3、传输层
如果在IP数据报的首部标明的是使用TCP传输数据,则在上述函数中会调用tcp_rcv函数。该函数的大体处理流程为:
“所有使用TCP 协议的套接字对应sock 结构都被挂入tcp_prot 全局变量表示的proto 结构之sock_array 数组中,采用以本地端口号为索引的插入方式,所以当tcp_rcv 函数接收到一个数据包,在完成必要的检查和处理后,其将以TCP 协议首部中目的端口号(对于一个接收的数据包而言,其目的端口号就是本地所使用的端口号)为索引,在tcp_prot 对应sock 结构之sock_array 数组中得到正确的sock 结构队列,在辅之以其他条件遍历该队列进行对应sock 结构的查询,在得到匹配的sock 结构后,将数据包挂入该sock 结构中的缓存队列中(由sock 结构中receive_queue 字段指向),从而完成数据包的最终接收。”
该函数的实现也会比较复杂,这是由TCP协议的复杂功能决定的。附代码如下:
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools">
[cpp]?<a class="ViewSource" title="view plain" href="http://blog.csdn.net/geekcome/article/details/7492423">view plain<a class="CopyToClipboard" title="copy" href="http://blog.csdn.net/geekcome/article/details/7492423">copy
?
- ???
- ?tcp_rcv(?sk_buff?*skb,??options?*opt,??
- ????unsigned??daddr,?unsigned??len,??
- ????unsigned??saddr,??redo,??inet_protocol?*?protocol)??
- {??
- ?????tcphdr?*th;??
- ?????sock?*sk;??
- ?????syn_ok=0;??
- ??????
- ?????(!skb)???
- ????{??
- ????????printk();??
- ????????(0);??
- ????}??
- ??
- ?????(!dev)???
- ????{??
- ????????printk();??
- ????????(0);??
- ????}??
- ????
- ????tcp_statistics.TcpInSegs++;??
- ????
- ????(skb->pkt_type!=PACKET_HOST)??
- ????{??
- ????????kfree_skb(skb,FREE_READ);??
- ????????(0);??
- ????}??
- ????
- ????th?=?skb->h.th;??
- ??
- ????
- ??
- ????sk?=?get_sock(&tcp_prot,?th->dest,?saddr,?th->source,?daddr);??
- ??
- ????
- ???????
- ?????(sk!=NULL?&&?(sk->zapped?||?sk->state==TCP_CLOSE))??
- ????????sk=NULL;??
- ??
- ?????(!redo)???
- ????{??
- ?????????(tcp_check(th,?len,?daddr?))???
- ????????{??
- ????????????skb->sk?=?NULL;??
- ????????????kfree_skb(skb,FREE_READ);??
- ????????????
- ????????????(0);??
- ????????}??
- ????????th->seq?=?ntohl(th->seq);??
- ??
- ????????
- ?????????(sk?==?NULL)???
- ????????{??
- ????????????
- ?
- ????????????tcp_reset(daddr,?th,?&tcp_prot,?opt,skb->ip_hdr->tos,255);??
- ????????????skb->sk?=?NULL;??
- ????????????
- ????????????kfree_skb(skb,?FREE_READ);??
- ????????????(0);??
- ????????}??
- ??
- ????????skb->len?=?len;??
- ????????skb->acked?=?0;??
- ????????skb->used?=?0;??
- ????????skb->free?=?0;??
- ????????skb->saddr?=?daddr;??
- ????????skb->daddr?=?saddr;??
- ??????
- ????????
- ????????cli();??
- ?????????(sk->inuse)???
- ????????{??
- ????????????skb_queue_tail(&sk->back_log,?skb);??
- ????????????sti();??
- ????????????(0);??
- ????????}??
- ????????sk->inuse?=?1;??
- ????????sti();??
- ????}??
- ??????
- ????{??
- ?????????(sk==NULL)???
- ????????{??
- ????????????tcp_reset(daddr,255);??
- ????????????skb->sk?=?NULL;??
- ????????????kfree_skb(skb,?FREE_READ);??
- ????????????(0);??
- ????????}??
- ????}??
- ??
- ??
- ?????(!sk->prot)???
- ????{??
- ????????printk();??
- ????????(0);??
- ????}??
- ??
- ??
- ????
- ???????
- ?????(sk->rmem_alloc?+?skb->mem_len?>=?sk->rcvbuf)???
- ????{??
- ????????kfree_skb(skb,?FREE_READ);??
- ????????release_sock(sk);??
- ????????(0);??
- ????}??
- ??
- ????skb->sk=sk;??
- ????sk->rmem_alloc?+=?skb->mem_len;??
- ??
- ????
- ??
- ????(sk->state!=TCP_ESTABLISHED)???????
- ????{??
- ??????
- ????????
- ???????
- ????????(sk->state==TCP_LISTEN)??
- ????????{??
- ????????????(th->ack)??
- ????????????????tcp_reset(daddr,saddr,th,sk->prot,opt,sk->ip_tos,?sk->ip_ttl);??
- ??
- ????????????
- ?????????????????
- ????????????(th->rst?||?!th->syn?||?th->ack?||?ip_chk_addr(daddr)!=IS_MYADDR)??
- ????????????{??
- ????????????????kfree_skb(skb,?FREE_READ);??
- ????????????????release_sock(sk);??
- ?????????????????0;??
- ????????????}??
- ??????????
- ????????????
- ??????????
- ????????????tcp_conn_request(sk,?daddr,?tcp_init_seq());??
- ??????????
- ????????????
- ???????????????
- ????????????release_sock(sk);??
- ?????????????0;??
- ????????}??
- ??????
- ????????
- ?????????(sk->state?==?TCP_SYN_RECV?&&?th->syn?&&?th->seq+1?==?sk->acked_seq)??
- ????????{??
- ????????????kfree_skb(skb,?FREE_READ);??
- ????????????release_sock(sk);??
- ?????????????0;??
- ????????}??
- ??????????
- ????????
- ?????????
- ????????(sk->state==TCP_SYN_SENT)??
- ????????{??
- ????????????
- ????????????(th->ack)??
- ????????????{??
- ????????????????
- ????????????????(!tcp_ack(sk,len))??
- ????????????????{??
- ????????????????????
- ??
- ????????????????????tcp_statistics.TcpAttemptFails++;??
- ????????????????????tcp_reset(daddr,??
- ????????????????????????sk->prot,sk->ip_ttl);??
- ????????????????????kfree_skb(skb,?FREE_READ);??
- ????????????????????release_sock(sk);??
- ????????????????????(0);??
- ????????????????}??
- ????????????????(th->rst)??
- ?????????????????????tcp_std_reset(sk,skb);??
- ????????????????(!th->syn)??
- ????????????????{??
- ????????????????????
- ????????????????????kfree_skb(skb,?FREE_READ);??
- ????????????????????release_sock(sk);??
- ?????????????????????0;??
- ????????????????}??
- ????????????????
- ????????????????syn_ok=1;???
- ????????????????sk->acked_seq=th->seq+1;??
- ????????????????sk->fin_seq=th->seq;??
- ????????????????tcp_send_ack(sk->sent_seq,sk->acked_seq,sk,sk->daddr);??
- ????????????????tcp_set_state(sk,?TCP_ESTABLISHED);??
- ????????????????tcp_options(sk,th);??
- ????????????????sk->dummy_th.dest=th->source;??
- ????????????????sk->copied_seq?=?sk->acked_seq;??
- ????????????????(!sk->dead)??
- ????????????????{??
- ????????????????????sk->state_change(sk);??
- ????????????????????sock_wake_async(sk->socket,?0);??
- ????????????????}??
- ????????????????(sk->max_window==0)??
- ????????????????{??
- ????????????????????sk->max_window?=?32;??
- ????????????????????sk->mss?=?min(sk->max_window,?sk->mtu);??
- ????????????????}??
- ????????????}??
- ??????????????
- ????????????{??
- ????????????????
- ????????????????(th->syn?&&?!th->rst)??
- ????????????????{??
- ????????????????????
- ????????????????????(sk->saddr==saddr?&&?sk->daddr==daddr?&&??
- ????????????????????????sk->dummy_th.source==th->source?&&??
- ????????????????????????sk->dummy_th.dest==th->dest)??
- ????????????????????{??
- ????????????????????????tcp_statistics.TcpAttemptFails++;??
- ?????????????????????????tcp_std_reset(sk,skb);??
- ????????????????????}??
- ????????????????????tcp_set_state(sk,TCP_SYN_RECV);??
- ??????????????????????
- ????????????????????
- ????????????????}?????????
- ????????????????
- ????????????????kfree_skb(skb,?FREE_READ);??
- ????????????????release_sock(sk);??
- ?????????????????0;??
- ????????????}??
- ????????????
- ?????????????rfc_step6;??
- ????????}??
- ??
- ????
- ??????
- ??
- ??
- ?????????(sk->state?==?TCP_TIME_WAIT?&&?th->syn?&&?sk->dead?&&???
- ????????????after(th->seq,?sk->acked_seq)?&&?!th->rst)??
- ????????{??
- ?????????????seq=sk->write_seq;??
- ????????????(sk->debug)??
- ????????????????printk();??
- ????????????tcp_statistics.TcpEstabResets++;?????????
- ????????????sk->rmem_alloc?-=?skb->mem_len;??
- ????????????skb->sk?=?NULL;??
- ????????????sk->err=ECONNRESET;??
- ????????????tcp_set_state(sk,?TCP_CLOSE);??
- ????????????sk->shutdown?=?SHUTDOWN_MASK;??
- ????????????release_sock(sk);??
- ????????????sk=get_sock(&tcp_prot,?daddr);??
- ?????????????(sk?&&?sk->state==TCP_LISTEN)??
- ????????????{??
- ????????????????sk->inuse=1;??
- ????????????????skb->sk?=?sk;??
- ????????????????sk->rmem_alloc?+=?skb->mem_len;??
- ????????????????tcp_conn_request(sk,seq+128000);??
- ????????????????release_sock(sk);??
- ?????????????????0;??
- ????????????}??
- ????????????kfree_skb(skb,?FREE_READ);??
- ?????????????0;??
- ????????}??
- ??
- ????}??
- ??
- ????
- ??????
- ????(!tcp_sequence(sk,len,dev))??
- ????{??
- ????????kfree_skb(skb,?FREE_READ);??
- ????????release_sock(sk);??
- ?????????0;??
- ????}??
- ??
- ????(th->rst)??
- ?????????tcp_std_reset(sk,skb);??
- ??????
- ????
- ???????
- ????(th->syn?&&?!syn_ok)??
- ????{??
- ????????tcp_reset(daddr,?skb->ip_hdr->tos,?255);??
- ?????????tcp_std_reset(sk,skb);?????
- ????}??
- ??
- ????
- ???????
- ??
- ????(th->ack?&&?!tcp_ack(sk,len))??
- ????{??
- ????????
- ???????????
- ????????(sk->state==TCP_SYN_RECV)??
- ????????{??
- ????????????tcp_reset(daddr,sk->ip_ttl);??
- ????????}??
- ????????kfree_skb(skb,?FREE_READ);??
- ????????release_sock(sk);??
- ?????????0;??
- ????}??
- ??????
- rfc_step6:??????
- ??
- ????
- ??????????
- ????(tcp_urg(sk,?len))??
- ????{??
- ????????kfree_skb(skb,?FREE_READ);??
- ????????release_sock(sk);??
- ?????????0;??
- ????}??
- ??????
- ??????
- ????
- ??????
- ????(tcp_data(skb,?FREE_READ);??
- ????????release_sock(sk);??
- ?????????0;??
- ????}??
- ??
- ????
- ??????
- ????release_sock(sk);??
- ?????0;??
- }??
4、应用层
当用户需要接收数据时,首先根据文件描述符inode得到socket结构和sock结构,然后从sock结构中指向的队列recieve_queue中读取数据包,将数据包COPY到用户空间缓冲区。数据就完整的从硬件中传输到用户空间。这样也完成了一次完整的从下到上的传输。
下篇:
在博文中分析了数据包从网卡设备经过驱动链路层,网络层,传输层到应用层的过程。
本文就分析一下本机产生数据是如何通过传输层,网络层到达物理层的。
综述来说,数据流程图如下:

一、应用层
应用层可以通过系统调用或文件操作来调用内核函数,BSD层的sock_write()函数会调用INET层的inet_wirte()函数。
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools">
[cpp]?<a class="ViewSource" title="view plain" href="http://blog.csdn.net/geekcome/article/details/7545855">view plain<a class="CopyToClipboard" title="copy" href="http://blog.csdn.net/geekcome/article/details/7545855">copy
?
- ??
- ??sock_write(?inode?*inode,??file?*file,??*ubuf,??size)??
- {??
- ?????socket?*sock;??
- ?????err;??
- ??????
- ?????(!(sock?=?socki_lookup(inode)))???
- ????{??
- ????????printk();??
- ????????(-EBADF);??
- ????}??
- ??
- ?????(sock->flags?&?SO_ACCEPTCON)???
- ????????(-EINVAL);??
- ??????
- ????(size<0)??
- ?????????-EINVAL;??
- ????(size==0)??
- ?????????0;??
- ??????????
- ?????((err=verify_area(VERIFY_READ,ubuf,size))<0)??
- ?????????err;??
- ????(sock->ops->write(sock,?ubuf,?size,(file->f_flags?&?O_NONBLOCK)));??
- }??
INET层会调用具体传输层协议的write函数,该函数是通过调用本层的inet_send()函数实现功能的,inet_send()函数的UDP协议对应的函数为udp_write()
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools">
[cpp]?<a class="ViewSource" title="view plain" href="http://blog.csdn.net/geekcome/article/details/7545855">view plain<a class="CopyToClipboard" title="copy" href="http://blog.csdn.net/geekcome/article/details/7545855">copy
?
??inet_send(?socket?*sock,??*ubuf,??size,??noblock,???
- ???????????unsigned?flags)??
- {??
- ?????sock?*sk?=?(?sock?*)?sock->data;??
- ?????(sk->shutdown?&?SEND_SHUTDOWN)???
- ????{??
- ????????send_sig(SIGPIPE,?current,?1);??
- ????????(-EPIPE);??
- ????}??
- ????(sk->err)??
- ?????????inet_error(sk);??
- ????
- ????(inet_autobind(sk)!=0)??
- ????????(-EAGAIN);??
- ????(sk->prot->write(sk,?(unsigned??*)?ubuf,?noblock,?flags));??
- }??
- ??
- ??inet_write(?socket?*sock,??noblock)??
- {??
- ?????inet_send(sock,size,noblock,0);??
- }??
二、传输层
在传输层udp_write()函数调用本层的udp_sendto()函数完成功能。
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools">
[cpp]?<a class="ViewSource" title="view plain" href="http://blog.csdn.net/geekcome/article/details/7545855">view plain<a class="CopyToClipboard" title="copy" href="http://blog.csdn.net/geekcome/article/details/7545855">copy
?
- ??
- ??udp_write(?sock?*sk,?unsigned??*buff,??len,??
- ??????unsigned?flags)??
- {??
- ????(udp_sendto(sk,?buff,?flags,?NULL,?0));??
- }??
udp_send()函数完成sk_buff结构相应的设置和报头的填写后会调用udp_send()来发送数据。具体的实现过程后面会详细分析。
而在udp_send()函数中,最后会调用ip_queue_xmit()函数,将数据包下放的网络层。
下面是udp_prot定义:
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools">
[cpp]?<a class="ViewSource" title="view plain" href="http://blog.csdn.net/geekcome/article/details/7545855">view plain<a class="CopyToClipboard" title="copy" href="http://blog.csdn.net/geekcome/article/details/7545855">copy
?
?proto?udp_prot?=?{??
- ????sock_wmalloc,??
- ????sock_rmalloc,??
- ????sock_wfree,??
- ????sock_rfree,??
- ????sock_rspace,??
- ????sock_wspace,??
- ????udp_close,??
- ????udp_read,??
- ????udp_write,??
- ????udp_sendto,??
- ????udp_recvfrom,??
- ????ip_build_header,??
- ????udp_connect,??
- ????NULL,??
- ????ip_queue_xmit,??
- ????NULL,??
- ????udp_rcv,??
- ????datagram_select,??
- ????udp_ioctl,??
- ????ip_setsockopt,??
- ????ip_getsockopt,??
- ????128,??
- ????0,??
- ????{NULL,},??
- ????,??
- ????0,?0??
- };??
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools">
[cpp]?<a class="ViewSource" title="view plain" href="http://blog.csdn.net/geekcome/article/details/7545855">view plain<a class="CopyToClipboard" title="copy" href="http://blog.csdn.net/geekcome/article/details/7545855">copy
?
??udp_send(?sock?*sk,??sockaddr_in?*sin,??
- ?????unsigned??*from,??rt)??
- {??
- ?????sk_buff?*skb;??
- ?????device?*dev;??
- ?????udphdr?*uh;??
- ????unsigned??*buff;??
- ????unsigned??saddr;??
- ?????size,?tmp;??
- ?????ttl;??
- ????
- ????
- ???????
- ????........................??
- ??
- ????
- ???????
- ????..........................??
- ????
- ???????
- ????..............................??
- ??
- ????
- ???????
- ????memcpy_fromfs(buff,?from,?len);??
- ??
- ????
- ???????
- ????udp_send_check(uh,?sin->sin_addr.s_addr,?skb->len?-?tmp,?sk);??
- ??
- ????
- ???????
- ????udp_statistics.UdpOutDatagrams++;??
- ???????
- ????sk->prot->queue_xmit(sk,?1);??
- ????(len);??
- }??
三、网络层
?在网络层,函数ip_queue_xmit()的功能是将数据包进行一系列复杂的操作,比如是检查数据包是否需要分片,是否是多播等一系列检查,最后调用dev_queue_xmit()函数发送数据。
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools">
[cpp]?<a class="ViewSource" title="view plain" href="http://blog.csdn.net/geekcome/article/details/7545855">view plain<a class="CopyToClipboard" title="copy" href="http://blog.csdn.net/geekcome/article/details/7545855">copy
?
- ??
- ?ip_queue_xmit(?sock?*sk,??
- ???????????sk_buff?*skb,??free)??
- {??
- ?????iphdr?*iph;??
- ????unsigned??*ptr;??
- ??
- ????
- ????............??
- ????
- ??
- ??
- ????...........??
- ??
- ????
- ?
- ??
- ????..............??
- ????
- ??
- ????(free!=2)??
- ????????iph->id??????=?htons(ip_id_count++);??
- ??????
- ????????free=1;??
- ??
- ????
- ?????(sk?==?NULL)??
- ????????free?=?1;??
- ??
- ????skb->free?=?free;??
- ??
- ????
- ??
- ????................??
- ??
- ????
- ??
- ????ip_send_check(iph);??
- ??
- ????
- ??
- ????
- ????.......................??
- ??
- ????
- ??
- ????......................??
- ????
- ???????
- ????ip_statistics.IpOutRequests++;??
- ????????.............................??
- ????.............................??
- ????????((dev->flags&IFF_BROADCAST)?&&?iph->daddr==dev->pa_brdaddr?&&?!(dev->flags&IFF_LOOPBACK))??
- ????????ip_loopback(dev,skb);??
- ??????????
- ?????(dev->flags?&?IFF_UP)??
- ????{??
- ????????
- ??
- ?????????(sk?!=?NULL)??
- ????????{??
- ????????????dev_queue_xmit(skb,?sk->priority);??
- ????????}??
- ??????????
- ????????{??
- ????????????dev_queue_xmit(skb,?SOPRI_NORMAL);??
- ????????}??
- ????}??
- ??????
- ????{??
- ????????ip_statistics.IpOutDiscards++;??
- ?????????(free)??
- ????????????kfree_skb(skb,?FREE_WRITE);??
- ????}??
- }??
四、驱动层(链路层)
在函数中,函数调用会调用具体设备的发送函数来发送数据包
dev->hard_start_xmit(skb,dev);
具体设备的发送函数在网络初始化的时候已经设置了。
这里以8390网卡为例来说明驱动层的工作原理,在net/drivers/8390.c中函数ethdev_init()函数中设置如下:
<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools">
[cpp]?<a class="ViewSource" title="view plain" href="http://blog.csdn.net/geekcome/article/details/7545855">view plain<a class="CopyToClipboard" title="copy" href="http://blog.csdn.net/geekcome/article/details/7545855">copy
?
- ?ethdev_init(?device?*dev)??
- {??
- ?????(ei_debug?>?1)??
- ????????printk(version);??
- ??????
- ?????(dev->priv?==?NULL)?{
- ?????????ei_device?*ei_local;
- ??????????
- ????????dev->priv?=?kmalloc((?ei_device),?GFP_KERNEL);
- ????????memset(dev->priv,?(?ei_device));??
- ????????ei_local?=?(?ei_device?*)dev->priv;??
- ??
- ????????ei_local->pingpong?=?1;??
- ??
- ????}??
- ??????
- ????
- ?????(dev->open?==?NULL)??
- ????????dev->open?=?&ei_open;
- ??????
- ????dev->hard_start_xmit?=?&ei_start_xmit;
- ????dev->get_stats???=?get_stats;??
- ??
- ????dev->set_multicast_list?=?&set_multicast_list;??
- ??
- ??
- ????ether_setup(dev);??
- ??????????
- ?????0;??
- }??
驱动中的发送函数比较复杂,和硬件关系紧密,这里不再详细分析。
这样就大体分析了下网络数据从应用层到物理层的数据通路,后面会详细分析。 (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|