4

Linux内核网络发包过程函数调用分析

 1 year ago
source link: https://blog.51cto.com/u_15109148/5470017
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Linux内核网络发包过程函数调用分析

  • 应用通过socket将数据包送入协议中处理
  • 在协议栈中从传输层发送到网络层,最后发送给邻居子系统
  • 邻居子系统将数据包转化为arp或者调用网络设备层函数将数据包发到下层驱动
  • 驱动完成数据最后的发送,并发送硬中断信号给cpu
  • cpu简单处理后发出RX软中断完成数据包的释放

本文以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_TX_SOFTIRQ的软中断处理函数为net_tx_action()

subsys_initcall(net_dev_init) - net/core/dev.c
    net_dev_init() - net/core/dev.c
        open_softirq(NET_TX_SOFTIRQ, net_tx_action) - net/core/dev.c

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

系统启动时,注册ipv4对应的发送函数inet_sendmsg(),注册各个传输层协议对应的发送函数udp_prot()、tcp_prot()、ping_prot()、raw_prot()等。同时注册arp output()函数。

fs_initcall(inet_init) - net/ipv4/af_inet.c
    inet_init() - net/ipv4/af_inet.c
        inet_register_protosw() - net/ipv4/af_inet.c
        arp_init() - net/ipv4/arp.c
            neigh_table_init() - net/ipv4/arp.c

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
                        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

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK