以下,整理出了 ping request 报文,从应用层,经内核,到达硬件,的 data path。
1. 应用层
// 应用层
busybox/ping.c
== ping_main()
== common_ping_main()
== ping()
== create_icmp_socket()
== socket(AF_INET, SOCK_RAW, 1);
== ping4()
== sendping4()
== sendping_tail()
== xsendto()
== sendto() // 系统调用
2. 内核
2.1 内核-网络
// (1)内核-网络
// net/socket.c
== __sys_sendto() // sendto() 在内核的系统调用服务程序为 __sys_sendto()
== sock_sendmsg()
== sock_sendmsg_nosec()
== raw_sendmsg() // sock->ops->sendmsg,应用层使用 SOCK_RAW 创建 socket,故 sock->ops->sendmsg 指向 raw_sendmsg()
// net/ipv4/ip_output.c
== ip_push_pending_frames()
== ip_send_skb()
== ip_local_out()
== __ip_local_out() // 经过 NF 的 LOCAL_OUT 钩子点
== dst_output()
== ip_output() // skb_dst(skb)->output
== ip_finish_output()
== __ip_finish_output()
== ip_finish_output2()
// net/core/neighbour.c/h
== neigh_output()
== neigh_resolve_output()
// net/core/dev.c
== dev_queue_xmit()
== __dev_queue_xmit()
== dev_hard_start_xmit()
== xmit_one()
// include/linux/netdevice.h
== netdev_start_xmit()
== __netdev_start_xmit()
== ops->ndo_start_xmit(skb, dev); // 送入驱动
== dev_open(struct net_device *dev);
== __dev_open();
== ops->ndo_open(dev);
== eth_open(struct net_device *net);
== eth_start(struct eth_dev *dev, gfp_t gfp_flags);
== rx_fill(struct eth_dev *dev, gfp_t gfp_flags);
== rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags);
req->complete = rx_complete;
== rx_complete(struct usb_ep *ep, struct usb_request *req);
== dev->unwrap(dev->port_usb, skb, &dev->rx_frames);
== eem_unwrap();
2.2 内核-驱动
// (2)内核-驱动
// drivers/net/usb/lan78xx.c
== lan78xx_start_xmit() // .ndo_start_xmit = lan78xx_start_xmit
== skb_queue_tail() // 插入队列
== tasklet_schedule(&dev->bh); // 触发任务调度 lan78xx_bh
== lan78xx_bh()
== lan78xx_tx_bh()
== skb_dequeue() // 取出数据
== usb_fill_bulk_urb() // 填充数据到 USB
// drivers/usb/core
== usb_submit_urb() // USB 发送数据
对于usb gadget 模式下,使用 function eem 的网卡驱动:
// \drivers\usb\gadget\function\u_ether.c // .ndo_start_xmit = eth_start_xmit,
== eth_start_xmit(struct sk_buff *skb, struct net_device *net)
== usb_ep_queue(struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags) // 插入队列
== ret = ep->ops->queue(ep, req, gfp_flags);
== dwc3_gadget_ep_queue();
== __dwc3_gadget_ep_queue();
== __dwc3_gadget_kick_transfer();
== dwc3_prepare_trbs();
== dwc3_send_gadget_ep_cmd(); trace_dwc3_gadget_ep_cmd(dep, cmd, params, cmd_status);
== dwc3_writel(dep->regs, DWC3_DEPCMDPAR0, params->param0);
3. 硬件
// 硬件
== usb_submit_urb(cmdinfo->cmd_urb, GFP_ATOMIC);
== usb_hcd_submit_urb(struct urb *urb, gfp_t mem_flags)
hcd->driver->urb_enqueue(hcd, urb, mem_flags);
== xhci_urb_enqueue(); trace_xhci_urb_enqueue(urb);
== xhci_queue_bulk_tx(); //批量传输
== prepare_transfer();
== usb_hcd_link_urb_to_ep() //add an URB to its endpoint queue
== list_add_tail(&urb->urb_list, &urb->ep->urb_list);
== queue_trb() trace_xhci_queue_trb(ring, trb); //queueing a TRB on a ring
== inc_enq() trace_xhci_inc_enq(ring);
== giveback_first_trb() //Pass all the TRBs to the hardware at once and make sure this write isn't reordered.
== xhci_ring_ep_doorbell() trace_xhci_ring_ep_doorbell(slot_id, DB_VALUE(ep_index, stream_id));
== writel(DB_VALUE(ep_index, stream_id), db_addr);