精华内容
下载资源
问答
  • 个人整理的关于linux内核协议栈的代码流程
  • 如何定义linux协议栈 真实的报文是怎么样的 linux收发包大概流程 linux协议栈分层设计思想 linux分层究竟对报文做了什么 总结 写在前面的话 本人所从事开发以来,一直在做数据面相关。数据面是一个通信设备最终好...

    写在前面的话

    本人所从事开发以来,一直在做数据面相关。数据面是一个通信设备最终好不好用最直接的体现。
    因为一个网络设备,好不好用,数据转发快不快,数据转发稳定不稳定,全部都是用户最直接体
    现。所以工作八年以来,对linux内核协议栈业也积累了自己的一些心得。现在想通过系列博文,
    写出来,也算是对自己的一个好的总结。如果有人看到该系列博文,而且有所帮助,那也是我的
    最大的荣幸所在了。

    如何定义linux协议栈

    写这个标题我心里其实非常发虚,为毛?因为这个概念实在有点大,好比小时候我们谈到理想,要成为接班人一样。到后面就会发现,接班人这个概念很大,这些年一直做的事情其实就是学习,工作,赚钱,买房结婚等等。

    同样,linux协议栈很大。最开始我们接触TCP/IP中提到过一个概念,就是分层。比如比较认可的分层方法如下图:

    常规的分层

    除此之外,还有比较经典的osi七层模型。不管是tcpip中的分层或者是osi的分层,都无所谓。这里我们会不会问一个问题:为什么需要分层?不分行不行?

    关于这个问题,我试图从以下两个方面来说下我自己对这个问题的看法:

    真实的报文是怎么样的?

    真实的报文,我们都在谈论报文,说明是报文?小明和女朋友两地分居,到晚上,经不住思念困扰,小明拿起手机打开微信给女朋友发了一条信息:我想你亲爱的。这条信息经过手机系统里通信协议栈处理,最后通过驱动层变成一堆比特流发送出去,这就是一个报文,当然更加确切说,是在驱动层发送出去之前。那么。一个报文的样子其实是这样的,见下图:
    一个TCP报文

    没错,不那么好看,和我们想象中真的不太一样。然而,这就是真实的报文。仔细看会发现,一个以太网数据报,拿tcp为例子,包含以下信息:

    • 以太网头
    • IP头
    • tcp头
    • http/ssh 等头
    • 数据部分(比如小明发送的:亲爱的,我想你)

    这个例子中的是一个tcp报文,不同报文的结构是不一样的,从上面的图中可以发现,报文像是穿了一层层的衣服,剥开这一层层的衣服,才可以看到里面的奥妙。这就是协议栈采用分层后的效果。这些也就是我接下来要系统写的协议栈内容。

    linux收发包大概流程

    为了更加清晰的看到协议栈分层思想,我们不妨从一个报文从进入linux机器网卡开始追踪报文的一生。人总有一死,或重于泰山,或轻于鸿毛。报文也一样,从生到死,一样精彩,一样要不停的选路,走路。那么究竟一个报文从进入linux中之后,要经历怎样的有趣旅程呢?看下面这一附图:

    报文旅程

    linux协议栈分层设计思想

    • 分层就像一栋大楼里的每层楼一样,层次分明。你要办理什么事情,该去哪一层的办理就去哪一层办理。与之不太一样的是,linux协议栈的分层设计,可以确保报文在每一层的独立性以及整个报文转发的逻辑性稳定性。

    因为linux每个层面只用关心本层需要的报文信息和内容,不需要关心其它的任何多余信息。举例来说,L2层中,主要就是linux的bridge转发处理。那么只需要关注报文的eth_headr中的内容,就可以完成学习,转发。也就是只关心报文的MAC地址以及下一层的协议号即可。(L2转发后续会详细写文分析)。

    • 分层让整个协议栈看起来分工明确,协议标准化操作中,也有固化下来的流程组成完整架构,这样的话,即便有需求实现自己独有功能,从现有协议栈中比较轻易的切入和二次扩展开发。

    linux分层究竟对报文做了什么

    其实,总体说来,就是一年四季来回变化,我们不得不加衣服,去衣服。

    对于linux内核来说,协议栈处理网络报文也是这么一个类似过程。首先我们要知道,每一层都有对应的协议头,比如L2层是ETH头,L3层是IP头/ARP头。等等。

    那么,我把linux接收报文流程称作上行,发送一个报文称作下行。上行就是脱衣服的过程,报文从驱动进入时候,穿的非常齐整,经过L2层要去掉ETH头,经过L3层要去掉IP头,再后面就是依次脱掉TCP/UDP头,接下来是具体应用层协议头比如ftp/http等等。

    详细可以参考下图:

    linux协议栈发包流程

    经过这样的处理,一个消息就发送出去了。可以看到,这样发送流程其实就是层层加头的流程。当然了,这幅图画的仅仅是个粗略的大概括,真实情况的封包转发远比这幅图复杂多了,后面我会详细写到。

    同样道理,收包流程就是层层去头的过程。

    总结

    linux协议栈,就是一个报文从进入驱动开始,经过层层转发传输处理,最终达到报文终点,这一些列的流程,都是协议栈处理范围。也是我之后要重点写的内容。

    展开全文
  • 该图描述了网络数据从linux驱动接收数据一直到上层应用socket调用的整个流程,为很多搞linux网络朋友提供帮助。
  • fs_initcall(inet_init) ->inet_init ->dev_add_pack ( ip_packet_type {.func = ip_rcv})
  • linux网络协议栈流程

    2014-04-27 22:40:17
    本文主要是根据之前学习网络协议栈

       本文主要是根据之前学习网络协议栈所画的UDP协议函数流程图来描述下网络协议栈的大致流程。

       由于之前分析的流程图,是通过visio画的,无法在本文中显示,故将visio文件已上传到http://download.csdn.net/detail/jobzhangbo/7262651

    1. init

    详情请见 init.vsd

    2. udp recv

    详情请见 net_recv.vsd

    3. udp send

    详情请见 net_send.vsd

     
    展开全文
  • linux协议栈实现

    2011-08-22 23:51:28
    linux IP协议栈原理,主要是函数的功能介绍与系统流程
  • Linux协议栈报文收发流程记录

    千次阅读 2014-04-07 12:26:09
    RX流程 1. 非NAPI的RX driver的isr调用eth_type_trans //确定skb->pkt_type和skb->protocol driver的isr调用netif_rx //可查看返回值,NET_RX_DROP表示丢包, __skb_queue_tail(&queue->input_pkt_queue, skb); ...

    RX流程

    1. 非NAPI的RX

    driver的isr调用eth_type_trans //确定skb->pkt_type和skb->protocol

    driver的isr调用netif_rx //可查看返回值,NET_RX_DROP表示丢包,

    __skb_queue_tail(&queue->input_pkt_queue, skb); //input_pkt_queue最大值为netdev_max_backlog=1000

    napi_schedule(&queue->backlog); //添加backlog到poll_list,触发NET_RX_SOFTIRQ

    net_rx_action //收多少包受到netdev_budget、device的weight和时间限制

    process_backlog

    netif_receive_skb

    NAPI的RX

    driver的isr关闭NIC中断

    driver的isr调用__netif_rx_schedule(&nic->napi); //添加device自己的napi到poll_list,触发NET_RX_SOFTIRQ

    net_rx_action //收多少包受到netdev_budget、device的weight和时间的限制

    driver的poll //上传全部skb之后开启NIC中断,driver通常自己维护队列,

    //或者直接从ring buffer中取出

    eth_type_trans //确定skb->pkt_type和skb->protocol

    netif_receive_skb

    备忘:

    NAPI的优势在于:

    中断少,softirq被触发的次数少,CPU占用率低;

    关中断,先前收到报文的处理不容易被打断,buffer不容易被溢出,所以吞吐率高;

    NAPI和硬件的“收多个包产生一个中断”的区别:

    NAPI的队列由driver维护,通常就是RX的ring buffer,当这个buffer满了,如果链路支持流控,NIC就会发送PAUSE帧,从而避免丢包;

    如果使用netif_rx,假设硬件可以做到多包一个中断,还是有可能会使得input_pkt_queue满,从而丢包,这个丢包和NIC发送PAUSE帧的时刻并不一定一致

    查看统计信息:cat /proc/net/softnet_stat

    2.

    netif_receive_skb

    deliver_skb //deliver给第三层的protocol

    //若有多个packet_type来接收,会共享skb(增加users)

    atomic_inc(&skb->users)

    pt_prev(packet_type)->func //struct packet_type

    //ptype_all是用AF_PACKET注册的socket?

    3.

    packet_type->func == ip_rcv

    NF_HOOK(NF_INET_PRE_ROUTING)

    ip_rcv_finish

    ip_route_input //查找路由,确定dst->input/dst->output,struct dst_entry。

    //先查找路由cache(struct rtable)

    //查找键值是src/dst ip、interface等算出的hash值

    ip_route_input_slow //若cache中没有,查找FIB(struct fib_table等),查找键值是struct flowi,并创建cache

    dst_input

    备忘:

    struct rtable包含struct dst_entry、struct flowi、struct in_device等

    路由命令:

    route -n

    route -C -n //查看路由cache

    route add default gw 192.168.99.254

    route add -net 192.168.98.0 netmask 255.255.255.0 gw 192.168.99.1

    route add -host 192.168.98.42 gw 192.168.99.1

    ip route show

    FIB表分local和main两个表,前者用于本地分配的ip地址,后者存放到外部节点的路由,由route等命令操作

    当需要复杂规则选择路由时(不仅仅依靠ip地址来选择),可启用基于policy路由,基于policy路由会建立多个FIB表

    比如:ip rule add tos 0x04 table 252

    如果是基于policy的路由,会先匹配规则,查找路由表,然后再查找路由

    查看路由规则:ip rule show

    Cache路由表查找算法是hash查找,FIB的是LPM (Longest Prefix Match)等

    cat /proc/sys/net/ipv4/ip_forward

    4.

    dst->input == ip_local_deliver(or ip_forward) //本地ip_local_deliver,转发是ip_forward,ip_forward会减少TTL

    ip_defrag //struct ipq,在成功完全重组完整个ip之后才继续,否则返回;超时会清除;

    ip_find //找到对应未完成重组的队列,未找到则创建,struct inet_frag_queue

    ip4_frag_match //根据src/dst ip、id等计算hash值来match

    ip_frag_queue //将分片挂到队列上,struct inet_frag_queue的fragments是单向链表

    ip_frag_reasm //把ipq上的分片挂在一个skb的frag_list里面

    NF_HOOK(NF_IP_LOCAL_IN)

    ip_local_deliver_finish

    5.

    ip_local_deliver_finish //递交给第四层

    (raw_local_deliver/__raw_v4_lookup/raw_rcv_skb) //raw socket处理

    ipprot->handler //struct net_protocol

    6.

    ipprot->handler == udp_rcv (or tcp_v4_rcv, icmp_rcv)

    udp_v4_lookup //根据ip地址、端口来查找对应的socket,一个skb通常属于某个socket

    udp_queue_rcv_skb(sk, skb)

    sock_queue_rcv_skb(sk, skb) //接收缓冲区不够会丢包,sk->sk_rmem_alloc skb->truesize >= sk->sk_rcvbuf

    //sk->sk_rcvbuf是接收缓冲区的大小,可以通过netstat -s来查看

    skb_set_owner_r(skb, sk) //skb属于某个sk、增加sk->sk_rmem_alloc,skb->destructor=sock_rfree,

    //应用程序进程取走数据后会释放接收缓冲区空间

    skb_queue_tail(&sk->sk_receive_queue, skb)

    sk->sk_data_ready == sock_def_readable //唤醒阻塞的应用程序进程

    wake_up_interruptible_sync(sk->sk_sleep)

    7. //从下往上看,因为是应用程序调用

    sk->sk_prot->recvmsg == udp_recvmsg //struct proto

    skb_recv_datagram //从sk->sk_receive_queue读取

    wait_for_packet //如果没有包,挂在sk->sk_sleep队列

    skb_copy_datagram_iovec //struct msghdr, copy skb_shinfo(skb)->frags[i]/frag_list to msg->msg_iov

    sock->ops->recvmsg == sock_common_recvmsg //ops is struct proto_ops

    __sock_recvmsg

    sock_recvmsg

    sys_recvfrom

    sys_recv

    sys_socketcall

    recvfrom

    +++++++++++++++++++++++++++++++++++++++++++++++++

    TX流程

    1.

    sys_send

    sockfd_lookup_light

    sock_sendmsg

    sock->ops->sendmsg == inet_sendmsg //struct proto_ops

    sk->sk_prot->sendmsg //struct proto

    2.

    sk->sk_prot->sendmsg == udp_sendmsg

    ip_route_output_flow

    ip_append_data //根据MTU分割,创建多个skb,挂在sk_write_queue上

    sock_alloc_send_skb //分配skb空间

    sock_wait_for_wmem //sk->sk_wmem_alloc与sk->sk_sndbuf比较,不够会挂起

    //UDP也会因发送缓冲区不够而刮起?

    skb_set_owner_w //设置skb的sk、增加sk->sk_wmem_alloc、skb->destructor=sock_wfree

    //sock_wfree在__kfree_skb的时候得以执行,它减少sk->sk_wmem_alloc

    //并且它调用sk->sk_write_space=sock_def_write_space唤醒等待的进程

    getfrag == ip_generic_getfrag //拷贝数据到skb

    3.

    udp_flush_pending_frames

    udp_push_pending_frames //填充第四层报头\计算校验和

    ip_push_pending_frames //sk->sk_write_queue队列被flush,里面的skb除了第一个都会追加到第一个skb的frag_list上

    ip_select_ident //计算ip头的ID,struct inet_peer

    NF_HOOK(NF_INET_LOCAL_OUT)

    4.

    dst_output

    dst->output == ip_output(or ip_mc_output)

    NF_HOOK(NF_INET_POST_ROUTING)

    ip_finish_output

    备忘:

    ip_queue_xmit--->ip_route_output_flow--->ip_local_out--->dst_output for TCP

    5.

    ip_fragment(skb, ip_finish_output2) //判断fast或者slow分片,fast分片表示上层已经做过准备,分片都在frag_list上,

    //直接为frag_list上的分片添加IP头,并调用output(即ip_finish_output2)

    //slow分片根据MTU来分配,有复制和创建skb的操作

    ip_finish_output2

    备忘:

    讲述分片:

    http://simohayha.iteye.com/blog/433178

    http://www.cnblogs.com/jinrize/archive/2009/11/28/1612567.html

    6.

    neigh_hh_output(有hh)/dst->neighbour->output //struct neighbour,struct neigh_table

    dev_queue_xmit

    q->enqueue=pfifo_fast_enqueue //struct Qdisc,pfifo队列满会丢包

    //dev->tx_queue_len=1000,ether_setup中赋值

    //丢包的错误会返回到上层处理

    qdisc_run //qdisc选择适合的skb来发送

    qdisc_restart

    q->dequeue=pfifo_fast_dequeue

    dev_hard_start_xmit

    dev->netdev_ops->ndo_start_xmit

    备忘:

    tc命令用于控制qdisc,用于替换掉默认的pfifo_fast_enqueue/dequeue

    对于NIC不能发送的情况(tx buffer满),qdisc会调用dev_requeue_skb,再调用__netif_schedule触发net_tx_action,由软中断发送,长期发送不成功会造成pfifo队列满

    dev_queue_xmit是第一次发送skb,net_tx_action发送qdisc队列里的skb和清理completion_queue

    arp命令:

    arp -na

    ip neighbor show

    +++++++++++++++++++++++++++++++++++++++++++++++++

    收发包大蓝图:

    +++++++++++++++++++++++++++++++++++++++++++++++++

    协议栈初始化

    1.

    start_kernel

    rest_init

    kernel_thread(init)

    init

    do_basic_setup

    do_initcalls

    2.

    sock_init //core_initcall阶段

    sk_init

    skb_init //初始化两个skb slab cache: skbuff_head_cache、skbuff_fclone_cache

    //slab预先分配好数据类型,由一个或多个page组成

    register_filesystem(&sock_fs_type);

    kern_mount(&sock_fs_type); //注册和挂在socket文件系统

    备忘:

    查看slab的使用情况:cat /proc/slabinfo

    查看文件系统:cat /proc/filesystem

    3.

    inet_init //fs_initcall阶段

    proto_register(&tcp_prot, 1);

    proto_register(&udp_prot, 1);

    proto_register(&raw_prot, 1); //协议相关的socket

    //struct udp_sock包含struct inet_sock,后者又包含struct sock

    sock_register(&inet_family_ops); //注册INET socket地址族

    inet_add_protocol(&icmp_protocol, IPPROTO_ICMP)

    inet_add_protocol(&udp_protocol, IPPROTO_UDP)

    inet_add_protocol(&tcp_protocol, IPPROTO_TCP)

    inet_register_protosw

    arp_init

    ip_init

    tcp_v4_init

    tcp_init

    udp_init

    icmp_init

    net_dev_init //subsys_initcall阶段

    NIC device初始化

    +++++++++++++++++++++++++++++++++++++++++++++++++

    一些数据结构

    常用的地址族:

    #define AF_UNSPEC 0

    #define AF_UNIX 1 //Unix domain sockets

    #define AF_INET 2 //Internet IP Protocol

    #define AF_INET6 10 //IP version 6

    #define AF_SECURITY 14 //Security callback pseudo AF

    #define AF_KEY 15 //PF_KEY key management API

    #define AF_NETLINK 16

    #define AF_ROUTE AF_NETLINK

    #define AF_PACKET 17 //Packet family

    PF_XXX和AF_XXX是一样的

    struct socket --BSD套接字层的操作对象,支持各种socket地址族;

    --int socket(int protocol_family, int socket_type, int protocol_id);

    struct sock --用于网络协议栈;

    struct net_proto_family --通用结构,支持各种socket地址族,实例为inet_family_ops;

    struct inet_protosw --描述INET socket地址族,根据socket()中的type和protocol分类,inetsw_array[]定义了三个实例,有面向stream的TCP、面向dgram的UDP和RAW,struct inet_protosw中含有struct proto_ops和struct proto;

    struct net_protocol --第三层到第四层,实例有tcp_protocol、udp_protocol,实例的方法有tcp_v4_rcv,udp_rcv,icmp_rcv,都放在一个inet_protos的数组中;

    struct proto_ops --socket层到INET层(之前叫inet_protocol?),描述stream、dgram、raw的ops,实例有inet_stream_ops、inet_dgram_ops、inet_sockraw_ops等,sock->ops->sendmsg;

    struct proto --INET层到传输层,描述具体协议的ops,实例有udp_prot、tcp_prot、raw_prot等,sk->prot->sendmsg;

    struct packet_type --第二层到第三层,实例有ip_packet_type;

    struct net_device,struct in_device

    struct rtable,struct dst_entry

    struct neighbour,struct hh_cache

    struct ifreq //ifconfig 调用的 ioctl 码依次是 SIOCSIFADDR,SIOCSIFFLAGS,SIOCSIFNETMASK

    在BSD Socket层使用struct msghdr来存储数据包,使用struct socket来字处理控制socket。

    在INET Socket以下层中使用struct sk_buff 来存储数据包,使用struct sock来处理控制socket。

    在driver和协议栈(比如IP层)之间有一层generic dev层(/net/core/dev.c)

    struct softnet_data{

    struct Qdisc *output_queue; //通过__netif_reschedule将不能发送的device的qdisc入队,

    //通过net_tx_action出队

    struct sk_buff_head input_pkt_queue; //所有非NAPI device的接收队列,通过netif_rx将skb入队,

    //通过process_backlog出队

    struct list_head poll_list; //struct napi_struct链表,通过__napi_schedule入队,通过net_rx_action出队

    struct sk_buff *completion_queue; //待释放skb队列,通过dev_kfree_skb_irq入队,通过net_tx_action出队

    struct napi_struct backlog; //所有非NAPI device借此以符合NAPI的调用方法,由netif_rx操作

    };

    struct sk_buff

    skb->csum: 对tx来说,是第四层头中checksum的位置;对rx来说,是checksum的值

    skb->len: 是所有的数据,线性段+frag_list(分片链表)+frags(page)

    skb->data_len: skb的frag_list(分片链表)+frags(page)

    skb->users: 引用参考,每次skb被共享增加1,每次skb被free减少1,为0时被释放

    data, head, tail, end:

    初始化时data, head, tail指向线性数据段开始,end指向线性数据段结束,skb_shared_info在end后一个字节开始,len为0;

    实际kmalloc的区域是指定的size加上sizeof(struct skb_shared_info),size还有可能被align;

    head和end自分配好之后就不再变化

    skb_shinfo(skb)->dataref:

    对skb的数据的引用计数

    skb_clone会增加这个值,它拷贝sk_buff头,但共享数据

    skb_shinfo(skb)->frag_list:

    ip的分片和重组用,ip_frag_reasm和ip_push_pending_frames会用到,链接了有多个skb

    skb_shinfo(skb)->frags:

    支持SG,用page存放数据,只有一个skb

    skb_shinfo(skb)->nr_frags:

    page的个数

    一些使用场合:

    skb_reserve(): tx时,预留包头

    skb_put(): rx时,driver收到包时调用;tx时,copy_from_user时调用

    skb_push(): tx时,构建包头

    skb_poll(): rx时,去掉包头

    skb_trim(): rx时,去掉包尾的padding,当心有page区域,使用pskb_trim()

    skb_headlen(): skb->len - skb->data_len,即kmalloc分配的数据区域大小

    skb_is_nonlinear(): skb->data_len非0即非线性

    struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, int fclone, int node)

    skb->data由kmalloc分配

    skb从skbuff_head_cache或skbuff_fclone_cache中分配

    如果有fclone标志,从skbuff_fclone_cache分配,一次分配2*sizeof(struct sk_buff)+sizeof(atomic_t)的大小

    主skb->fclone=SKB_FCLONE_ORIG,从child->fclone = SKB_FCLONE_UNAVAILABLE

    atomic_t的变量是fclone_ref,它是主从skb共同的引用计数

    之所以需要skbuff_fclone_cache这种分配策略是因为传输层往往需要保留skb的一份拷贝,同时传递另一份skb给下层

    struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)

    会判断skb是否来自skbuff_fclone_cache,若是的话,判断其次skb的fclone是否为SKB_FCLONE_UNAVAILABLE

    SKB_FCLONE_UNAVAILABLE表示没有使用;SKB_FCLONE_CLONE表示已经被使用;

    若skb不是来自skbuff_fclone_cache,则在skbuff_head_cache上新建一个skb用于克隆

    当一个skb被clone之后,数据区不能被修改的,通过pskb_copy复制线性数据段,skb_copy复制所有数据段,包括frags[i]

    而skb_copy是在skbuff_head_cache上进行分配的

    struct sk_buff_head {

    struct sk_buff *next; //与sk_buff的第1、2个成员一样

    struct sk_buff *prev; //与sk_buff的第1、2个成员一样

    __u32 qlen; //队列大小

    spinlock_t lock; //操作队列时,必须先获得lock

    };

    skb的队列操作函数略

    +++++++++++++++++++++++++++++++++++++++++++++++++

    应用程序、系统调用、协议栈

    iputils工具包含有ping, arping等命令

    net­tools工具包含有ifconfig, netstat, route, arp等命令

    IPROUTE2含有ip命令

    netfilter用于包的Filtering, Changing packets (masquerading), Connection Tracking等,通过iptable配置

    etable相当于二层的netfilter

    xfrm与IPSEC有关

    +++++++++++++++++++++++++++++++++++++++++++++++++

    参考

    Understanding Linux Network Internals

    http://basiccoder.com/intro-linux-kernel-hash-rt-1.html

    http://www.cnblogs.com/jinrize/archive/2009/11/29/1612872.html

    http://blog.chinaunix.net/uid-127037-id-2919560.html

    http://simohayha.iteye.com/

    The journey of a packet through the linux 2.4/6 network stack

    netinit.pdf

    Linux TCP IP 协议栈分析.pdf

    展开全文
  • Linux协议栈(2)——发送流程及函数本章会一步一步的分析,在linux内核中,数据是如何从网络中接收并最后到达应用程序的。用户数据的发送流程如下图所示,不管是tfp,telnet,http都是类似的。当然我们在使用应用的时候...

    Linux协议栈(2)——发送流程及函数

    本章会一步一步的分析,在linux内核中,数据是如何从网络中接收并最后到达应用程序的。

    用户数据的发送流程如下图所示,不管是tfp,telnet,http都是类似的。当然我们在使用应用的时候,根本不会关注到这些加头的措施,因为要么是程序要么是内核帮助我们完成了。而我们现在所做的就是层层拨开他们去理解这协议栈的整个过程。发送过程中数据的变化如下:


    1.1.1.1  应用层

      首先网络应用调用Socket 的API函数 socket ()(该函数定义在/usr/include/sys/socket.h文件中) ,创建一个 socket(函数会调用系统调用 socket() ),并最终调用内核函数的 sock_create (定义在net/socket.c)方法,成功后返回一个socket描述符。

      对于TCP,应用接着调用 connect()函数,使得客户端和服务器端通过该 socket 建立一个连接。然后可以调用send函数发出一个 message 给接收端。sock_sendmsg 被调用,调用相应协议的发送函数。

    1.1.1.2  传输层

    数据到了传输层的处理,以TCP协议为例。TCP主要处理:(1)构造 TCP segment (2)计算 checksum (3)发送回复(ACK)包 (4)滑动窗口(sliding windown)等保证可靠性的操作。

    不同的协议针对的发送函数不一样:

    TCP调用 tcp_sendmsg 函数。

    UDP可以调用 send()/sendto()/sendmsg() 三个 system call 中的任意一个来发送 message,最终都会调用内核中的 udp_sendmsg() 函数。

      如果是tcp协议的流程,tcp_sendmsg()的主要工作是把用户层的数据,填充到skb中。然后调用tcp_push_one()来发送,tcp_push_one函数调用tcp_write_xmit()函数,其又将调用发送函数tcp_transmit_skb,所有的SKB都经过该函数进行发送。最后进入到ip_queue_xmit到网络层。因为tcp会进行重传控制,所以有tcp_write_timer函数,进行定时。

      udp协议使用udp_sendmsg函数,调用udp_send_skb函数,然后通过ip_append_data进入到网络层。

    1.1.1.3  网络层

      ip_queue_xmit(skb)会检查skb->dst路由信息。如果没有,就会去选择一个路由。

      填充IP包的各个字段,比如版本、包头长度、TOS等。当报文的长度大于mtu,gso的长度不为0就会调用 ip_fragment 进行分片。ip_fragment 函数中,会检查 IP_DF 标志位,如果待分片IP数据包禁止分片,则调用 icmp_send()向发送方发送一个原因为需要分片而设置了不分片标志的目的不可达ICMP报文,并丢弃报文,即设置IP状态为分片失败,释放skb,返回消息过长错误码。

    1.1.1.4  链路层

      数据链路层在不可靠的物理介质上提供可靠的传输。该层的作用包括:物理地址寻址、数据的成帧、流量控制、数据的检错、重发等。这一层数据的单位称为帧(frame)。从dev_queue_xmit函数开始,位于net/core/dev.c文件中。

           注意底层的net_rx、net_tx是在驱动中实现的。

    如下图。


    展开全文
  • Linux协议栈实现分析

    2008-04-26 11:15:23
    Linux协议栈实现分析 关于TCP/IP协议流程分析
  • Linux协议栈(3)——接收流程及函数 本章来看下,数据是如何从网络中接收并最后到达应用程序的。 网络层将数据链路层提供的帧组成数据包,包中封装有网络层包头,其中含有逻辑地址信息。 1.1.1.1 链路层 包到达机器...
  • Linux协议栈(1)——协议介绍 本系列材料是关于Linux网络内核协议栈的,总体上将其分10个文章,主要目的是简明扼要的描述Linux协议栈在内核中的实现,从总体上掌握linux网络协议栈。因为操作系统中的网络子系统非常...
  • linux内核协议栈剖析

    2018-06-02 09:34:28
    linux内核协议栈调用解析,数据包走向流程。 网络数据包走向
  • http://blog.csdn.net/jobzhangbo/article/details/24603713 对应的visio文件
  • ifconfig eth0 txqueuelen 10000
  • Linux协议栈-netfilter(2)-conntrack

    万次阅读 2015-04-04 17:37:40
    连接跟踪(conntrack)用来跟踪和记录一个连接的状态,它为经过协议栈的数据包记录状态,这为防火墙检测连接状态提供了参考,同时在数据包需要做NAT时也为转换工作提供便利。本文基于Linux内核2.6.31实现的conntrack...
  • 详解Linux协议栈的数据流向,SOCKET的操作流程,unicast multicast等等的区别。
  • Linux内核-协议栈-初始化流程分析

    千次阅读 2015-10-31 10:35:16
    本文主要针对Linux-3.19.3版本的内核简单分析内核协议栈初始化涉及到的主要步骤和关键函数,不针对协议的解析以及数据包的处理流程做具体分析,后续有机会再详细分析(主要是作者目前这块才涉及…)1.准备 Linux内核...
  • 1.1 发送端1.1.1 应用层(1) Socket应用层的各种网络应用程序基本上都是通过 Linux Socket 编程接口来和内核空间的网络协议栈通信的。Linux Socket 是从 BSD Socket 发展而来的,它是 Linux 操作系统的重要组成部分...
  • Linux协议栈accept和syn队列问题

    千次阅读 2015-05-21 10:23:41
    Linux协议栈accept和syn队列问题 2014-03-19 11:30:06 分类: LINUX 环境:  Client 通过tcp 连接server,server端只是listen,但是不调用accept。通过netstat –ant查看两端的连接情况。 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 28,354
精华内容 11,341
关键字:

linux协议栈流程

linux 订阅