TCP/IP学习(36)——IP包的发送流程(3)

简介:

原文地址:TCP/IP学习(36)——IP包的发送流程(3) 作者:GFree_Wind

本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
作者:gfree.wind@gmail.com
博客:linuxfocus.blog.chinaunix.net
   

前文已经学习到了sch_direct_xmit函数,下面进入下一级函数。
  1. int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
  2.             struct netdev_queue *txq)
  3. {
  4.     const struct net_device_ops *ops = dev->netdev_ops;
  5.     int rc = NETDEV_TX_OK;

  6.     if (likely(!skb->next)) {
         /* skb->next为null,即只发送一个skb */

  1.         if (!list_empty(&ptype_all))
  2.             dev_queue_xmit_nit(skb, dev); //ptype_all上的协议处理,如tcpdump

  3.         /*
  4.          * If device doesnt need skb->dst, release it right now while
  5.          * its hot in this cpu cache
  6.          */
  7.         /* device 不需要dst */
  8.         if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
  9.             skb_dst_drop(skb);

         /* 使该skb不属于任何一个socket */
  1.         skb_orphan_try(skb);

  2.         if (netif_needs_gso(dev, skb)) {
  3.             /* 需要scatter gather功能 */
             
              /*
              从注释上看,是进行perform protocol segmentation on skb。
              但是实际工作,目前我不清楚
              */
  1.             if (unlikely(dev_gso_segment(skb)))
  2.                 goto out_kfree_skb;
  3.             if (skb->next)
  4.                 goto gso;
  5.         } else {
  6.             //不需要scatter gather
            
             /*
             如需要连续内存,则将skb内存线性化,即连续内存 
             */
  1.             if (skb_needs_linearize(skb, dev) &&
  2.              __skb_linearize(skb))
  3.                 goto out_kfree_skb;

  4.             /* If packet is not checksummed and device does not
  5.              * support checksumming for this protocol, complete
  6.              * checksumming here.
  7.              */
  8.             if (skb->ip_summed == CHECKSUM_PARTIAL) {
  9.                 /* 计算checksum */
  10.                 skb_set_transport_header(skb, skb->csum_start -
  11.                      skb_headroom(skb));
  12.                 if (!dev_can_checksum(dev, skb) &&
  13.                  skb_checksum_help(skb))
  14.                     goto out_kfree_skb;
  15.             }
  16.         }

         /* 发送skb数据 */
  1.         rc = ops->ndo_start_xmit(skb, dev);
  2.         if (rc == NETDEV_TX_OK)
  3.             txq_trans_update(txq);
  4.         return rc;
  5.     }

  6. gso:
  7.     /* 循环发送数据包 */
  8.     do {
  9.         struct sk_buff *nskb = skb->next;

  10.         skb->next = nskb->next;
  11.         nskb->next = NULL;

  12.         /*
  13.          * If device doesnt need nskb->dst, release it right now while
  14.          * its hot in this cpu cache
  15.          */
  16.         if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
  17.             skb_dst_drop(nskb);

  18.         rc = ops->ndo_start_xmit(nskb, dev);
  19.         if (unlikely(rc != NETDEV_TX_OK)) {
  20.             if (rc & ~NETDEV_TX_MASK)
  21.                 goto out_kfree_gso_skb;
  22.             nskb->next = skb->next;
  23.             skb->next = nskb;
  24.             return rc;
  25.         }
  26.         txq_trans_update(txq);
  27.         if (unlikely(netif_tx_queue_stopped(txq) && skb->next))
  28.             return NETDEV_TX_BUSY;
  29.     } while (skb->next);

  30. out_kfree_gso_skb:
  31.     if (likely(skb->next == NULL))
  32.         skb->destructor = DEV_GSO_CB(skb)->destructor;
  33. out_kfree_skb:
  34.     kfree_skb(skb);
  35.     return rc;
  36. }
继续下一个函数,ops->ndo_start_xmit。又是一个回调函数,这个回调函数由驱动所决定。以e1000_main.c为例,
  1. static const struct net_device_ops e1000_netdev_ops = {
  2.     .ndo_open        = e1000_open,
  3.     .ndo_stop        = e1000_close,
  4.     .ndo_start_xmit        = e1000_xmit_frame,
  5.     .ndo_get_stats        = e1000_get_stats,
  6.     .ndo_set_rx_mode    = e1000_set_rx_mode,
  7.     .ndo_set_mac_address    = e1000_set_mac,
  8.     .ndo_tx_timeout     = e1000_tx_timeout,
  9.     .ndo_change_mtu        = e1000_change_mtu,
  10.     .ndo_do_ioctl        = e1000_ioctl,
  11.     .ndo_validate_addr    = eth_validate_addr,

  12.     .ndo_vlan_rx_register    = e1000_vlan_rx_register,
  13.     .ndo_vlan_rx_add_vid    = e1000_vlan_rx_add_vid,
  14.     .ndo_vlan_rx_kill_vid    = e1000_vlan_rx_kill_vid,
  15. #ifdef CONFIG_NET_POLL_CONTROLLER
  16.     .ndo_poll_controller    = e1000_netpoll,
  17. #endif
  18. };
从这里可以看出,对于e1000_main来说,该回调函数为e1000_xmit_frame。这个涉及到驱动层,一般都与硬件相关,在此就不继续探讨了。

那么现在,一个基本的IP包发送流程,基本上浏览完毕。小小的总结一下,当linux发送IP数据包时,数据包有可能是立刻发送出去,也有可能由下一次的软中断发送。
目录
相关文章
|
2月前
|
机器学习/深度学习 人工智能 网络协议
TCP/IP五层(或四层)模型,IP和TCP到底在哪层?
TCP/IP五层(或四层)模型,IP和TCP到底在哪层?
59 4
|
15天前
|
网络协议 程序员 定位技术
学习网络的第一步:全面解析OSI与TCP/IP模型
**网络基础知识概览:** 探索网络通信的关键模型——OSI七层模型和TCP/IP五层模型。OSI模型(物理、数据链路、网络、传输、会话、表示、应用层)提供理论框架,而TCP/IP模型(物理、数据链路、网络、传输、应用层)更为实际,合并了会话、表示和应用层。两者帮助理解数据在网络中的传输过程,为网络设计和管理提供理论支持。了解这些模型,如同在复杂的网络世界中持有了地图。
26 2
|
1月前
|
网络协议 Java 程序员
TCP/IP协议栈是网络通信基础,Java的`java.net`包提供工具,使开发者能利用TCP/IP创建网络应用
【6月更文挑战第23天】 **TCP/IP协议栈是网络通信基础,它包含应用层(HTTP, FTP等)、传输层(TCP, UDP)、网络层(IP)、数据链路层(帧, MAC地址)和物理层(硬件信号)。Java的`java.net`包提供工具,使开发者能利用TCP/IP创建网络应用,如Socket和ServerSocket用于客户端和服务器通信。**
37 3
|
11月前
|
监控 网络协议 网络架构
IP协议【图解TCP/IP(笔记九)】
IP协议【图解TCP/IP(笔记九)】
|
存储 缓存 网络协议
网络基础学习:什么是tcp/ip协议
网络基础学习:什么是tcp/ip协议
128 0
|
域名解析 网络协议
IP协议, TCP协议 和DNS 服务分别是干什么的?
大家好,我是阿萨。昨天讲解了网络四层协议[TCP/IP协议族分为哪4层?]今天我们学习下IP 协议, TCP 协议和DNS 协议分别是干什么的。
256 0
IP协议, TCP协议 和DNS 服务分别是干什么的?
|
监控 网络协议 安全
一文了解HTTP、HTTPS、TCP、UDP、Websocket(论点:概念、通信流程、异同点、应用领域)
一文了解HTTP、HTTPS、TCP、UDP、Websocket(论点:概念、通信流程、异同点、应用领域)
|
网络协议 算法
【网络篇】第十二篇——TCP协议通讯流程
【网络篇】第十二篇——TCP协议通讯流程
【网络篇】第十二篇——TCP协议通讯流程
|
网络协议 网络架构
六、TCP/IP模型 和 5层参考模型
六、TCP/IP模型 和 5层参考模型
六、TCP/IP模型 和 5层参考模型
|
网络协议
TCP/IP协议的介绍
TCP/IP协议是众多协议的统称,通过分层结构来管理。可分为七层模型或四层结构