Linux内核里的传输层数据流

传输层发送数据包

socket sendto系统调用

应用程序通过socket调用sendto系统调用发送数据包,根据网络层协议调用inet_sendmsg或者inet6_sendmsg()函数,将数据包送入协议栈发送。

SYSCALL_DEFINE6(sendto...) - net/socket.c
    sock_sendmsg() - net/socket.c
        sock_sendmsg_nosec() - net/socket.c
            int ret = INDIRECT_CALL_INET(sock->ops->sendmsg, inet6_sendmsg, inet_sendmsg, sock, msg, msg_data_left(msg))

协议栈处理函数-L4

协议栈根据传输层协议调用对应的处理函数。这里以udp协议为例说明传输层发送过程。最后根据网络层协议,调用ip_output()、ip6_output()等将数据包发送到网络层处理。

inet_sendmsg() - net/ipv4/af_inet.c
    return INDIRECT_CALL_2(sk->sk_prot->sendmsg, tcp_sendmsg, udp_sendmsg, sk, msg, size)
        udp_sendmsg() - net/ipv4/udp.c
            udp_send_skb() - net/ipv4/udp.c
                ip_send_skb() - net/ipv4/ip_output.c
                    ip_local_out() - net/ipv4/ip_output.c
                        dst_output() - net/dst.h
                             return INDIRECT_CALL_INET(skb_dst(skb)->output, ip6_output, ip_output, net, sk, skb);

协议栈处理函数-L3

网络层处理后,调用neigh_output()函数将数据包送入邻居子系统发送或者转化为arp。

ip_output() - net/ipv4/ip_output.c
    ip_finish_output() - net/ipv4/ip_output.c
        __ip_finish_output() - net/ipv4/ip_output.c
            ip_finish_output_gso() - net/ipv4/ip_output.c
                ip_finish_output2() - net/ipv4/ip_output.c
                    neigh_output() - net/neighbor.h

邻居子系统处理函数

neigh_output() - net/neighbor.h
    return n->output(n, skb) - net/neighbor.h
    neigh_hh_output() - net/neighbor.h
        dev_queue_xmit() - net/core/dev.c

网络设备层处理函数

网络设备层调用驱动注册的ndo_start_xmit()函数发送数据包到驱动。以igb驱动为例,ndo_start_xmit()即igb_xmit_frame()函数。

dev_queue_xmit() - net/core/dev.c
    __dev_queue_xmit() - net/core/dev.c
        dev_hard_start_xmit() - net/core/dev.c
            xmit_one() - net/core/dev.c
                netdev_start_xmit() - include/linux/netdevice.h
                    __netdev_start_xmit() - include/linux/netdevice.h
                        return ops->ndo_start_xmit(skb, dev)

驱动程序处理函数

网卡驱动完成最后的数据包发送过程。

igb_xmit_frame() - drivers/net/ethernet/intel/igb/igb_main.c
    igb_xmit_frame_ring() - drivers/net/ethernet/intel/igb/igb_main.c
        igb_tx_map() - drivers/net/ethernet/intel/igb/igb_main.c

数据包内存释放函数

网卡发送完数据包后,会给cpu发送一个硬中断通知cpu,cpu简单处理后,发出软中断NET_RX_SOFTIRQ。最后的中断处理函数net_rx_action()中完成数据包的释放。

硬中断处理函数:

igb_msix_ring() - drivers/net/ethernet/intel/igb/igb_main.c
    __napi_schedule() - net/core/dev.c
        ____napi_schedule() - net/core/dev.c
            __raise_softirq_irqoff(NET_RX_SOFTIRQ) - net/core/dev.c

软中断处理函数:

ksoftirqd为软中断处理进程,ksoftirqd收到NET_RX_SOFTIRQ软中断后,执行软中断处理函数net_rx_action(),调用网卡驱动poll()函数收包。在poll()函数中调用igb_clean_tx_irq()完成数据包的释放。

run_ksoftirqd() - kernel/softirqd.c
    __do_softirq() - kernel/softirqd.c
        h->action(h) - kernel/softirqd.c
            net_rx_action() - net/core/dev.c
                napi_poll() - net/core/dev.c
                    __napi_poll - net/core/dev.c
                        work = n->poll(n, weight) - net/core/dev.c
                            igb_poll() - drivers/net/ethernet/intel/igb/igb_main.c
                                igb_clean_tx_irq() - drivers/net/ethernet/intel/igb/igb_main.c

传输层接收数据包

本文以Intel igb网卡驱动为例说明收包过程:

网卡驱动注册硬中断处理函数

网卡驱动注册中断处理函数igb_msix_ring()。

igb_open() - drivers/net/ethernet/intel/igb/igb_main.c
    igb_request_irq - drivers/net/ethernet/intel/igb/igb_main.c
        igb_request_msix - drivers/net/ethernet/intel/igb/igb_main.c
            igb_msix_ring() - drivers/net/ethernet/intel/igb/igb_main.c

系统启动时注册软中断处理函数

NET_RX_SOFTIRQ的软中断处理函数为net_rx_action()。

subsys_initcall(net_dev_init) - net/core/dev.c
    net_dev_init() - net/core/dev.c
        open_softirq(NET_RX_SOFTIRQ, net_rx_action) - net/core/dev.c

系统启动时注册协议栈处理函数

在网络层,以IPv4为例,注册的协议处理函数为ip_rcv()。在传输层,根据协议注册其处理函数upd_rcv()、tcp_v4_rcv()、icmp_rcv()等。

fs_initcall(inet_init) - net/ipv4/af_inet.c
    inet_init() - net/ipv4/af_inet.c
        inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) - net/ipv4/af_inet.c
        inet_add_protocol(&udp_protocol, IPPROTO_UDP) - net/ipv4/af_inet.c
        inet_add_protocol(&tcp_protocol, IPPROTO_TCP) - net/ipv4/af_inet.c
        dev_add_pack(&ip_packet_type) - net/ipv4/af_inet.c

硬中断处理函数

当有数据包到达网卡时,DMA把数据映射到内存,通知CPU硬中断,执行注册的硬中断处理函数igb_msix_ring(),简单处理后,发出软中断NET_RX_SOFTIRQ。

igb_msix_ring() - drivers/net/ethernet/intel/igb/igb_main.c
    __napi_schedule() - net/core/dev.c
        ____napi_schedule() - net/core/dev.c
            __raise_softirq_irqoff(NET_RX_SOFTIRQ) - net/core/dev.c

软中断处理函数

ksoftirqd为软中断处理进程,ksoftirqd收到NET_RX_SOFTIRQ软中断后,执行软中断处理函数net_rx_action(),调用网卡驱动poll()函数收包。最后通过调用注册的ip协议处理函数ip_rcv()将数据包送往协议栈。

run_ksoftirqd() - kernel/softirqd.c
    __do_softirq() - kernel/softirqd.c
        h->action(h) - kernel/softirqd.c
            net_rx_action() - net/core/dev.c
                napi_poll() - net/core/dev.c
                    __napi_poll - net/core/dev.c
                        work = n->poll(n, weight) - net/core/dev.c
                            igb_poll() - drivers/net/ethernet/intel/igb/igb_main.c
                                igb_clean_rx_irq() - drivers/net/ethernet/intel/igb/igb_main.c
                                    napi_gro_receive() - net/core/gro.c
                                        napi_skb_finish() - net/core/gro.c
                                            netif_receive_skb_list_internal() - net/core/dev.c
                                                __netif_receive_skb_list() - net/core/dev.c
                                                    __netif_receive_skb_list_core - net/core/dev.c
                                                        __netif_receive_skb_core - net/core/dev.c
                                                            deliver_skb() - net/core/dev.c
                                                                pt_prev->func(skb, skb->dev, pt_prev, orig_dev)

协议栈处理函数-L3

在软中断处理的最后,调用的pt_prev->func()函数即为协议栈注册ipv4处理函数ip_rcv()。网络层处理完成之后,根据传输协议执行注册的传输层处理函数tcp_v4_rcv或者udp_rcv()。

ip_rcv() - net/ipv4/ip_input.c
    ip_rcv_finish() - net/ipv4/ip_input.c
        dst_input() - include/net/dst.h
            ip_local_deliver() - net/ipv4/ip_input.c
                ip_local_deliver_finish() - net/ipv4/ip_input.c
                    ip_protocol_deliver_rcu() - net/ipv4/ip_input.c
                        ret = INDIRECT_CALL_2(ipprot->handler, tcp_v4_rcv, udp_rcv, skb)

协议栈处理函数-L4

这里以udp协议为例说明处理过程,tcp协议处理过程更复杂一些。最后将数据包添加到socket的接收队列。然后进入用户空间应用层面处理。

udp_rcv() - net/ipv4/udp.c
    udp_unicast_rcv_skb() - net/ipv4/udp.c
        udp_queue_rcv_skb() - net/ipv4/udp.c
            udp_queue_rcv_one_skb() - net/ipv4/udp.c
                __udp_queue_rcv_skb() - net/ipv4/udp.c
                    __udp_enqueue_schedule_skb() - net/ipv4/udp.c
                        __skb_queue_tail() - net/ipv4/udp.c

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值