网络数据包发送之dev_hard_start_xmit

int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
			struct netdev_queue *txq)
{
	const struct net_device_ops *ops = dev->netdev_ops;
	int rc = NETDEV_TX_OK;
	unsigned int skb_len;
	/* 检查上层协议是否已经完成了数据包分片的工作? */
	if (likely(!skb->next)) {
		netdev_features_t features;

		/*
		 * If device doesn't need skb->dst, release it right now while
		 * its hot in this cpu cache
		 */
		if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
			skb_dst_drop(skb);

		features = netif_skb_features(skb);
		/* 上层协议要求驱动进行VLAN插入加速,但是当前网络设备不支持该功能时,则需要手动完成数据包的VLAN字段插入 */
		if (vlan_tx_tag_present(skb) &&
		    !vlan_hw_offload_capable(features, skb->vlan_proto)) {
			skb = __vlan_put_tag(skb, skb->vlan_proto,
					     vlan_tx_tag_get(skb));
			if (unlikely(!skb))
				goto out;

			/* 由于驱动根据该成员决定是否需要硬件插入VLAN,所以这里需要清除vlan_tci标志 */
			skb->vlan_tci = 0;
		}

		/* If encapsulation offload request, verify we are testing
		 * hardware encapsulation features instead of standard
		 * features for the netdev
		 */
		if (skb->encapsulation)
			features &= dev->hw_enc_features;
		/* 如果上层协议需要底层驱动执行数据包硬件分片操作,但是底层硬件不支持该功能时,则需要手动完成分片操作 */
		if (netif_needs_gso(skb, features)) {
			/* ok,这里开始手动分片操作 */
			if (unlikely(dev_gso_segment(skb, features)))
				goto out_kfree_skb;
			if (skb->next)
				goto gso;
		} else {
			/* 如果硬件不支持分离集合DMA操作而SKB带有非线性碎片数据的话,则需要对数据进行线性化拼接操作 */
			if (skb_needs_linearize(skb, features) &&
			    __skb_linearize(skb))
				goto out_kfree_skb;

			/* If packet is not checksummed and device does not
			 * support checksumming for this protocol, complete
			 * checksumming here.
			 * 上层协议要求底层计算校验,而底层硬件不支持校验时,需要手动计算校验值
			 */
			if (skb->ip_summed == CHECKSUM_PARTIAL) {
				if (skb->encapsulation)
					skb_set_inner_transport_header(skb,
						skb_checksum_start_offset(skb));
				else
					skb_set_transport_header(skb,
						skb_checksum_start_offset(skb));
				if (!(features & NETIF_F_ALL_CSUM) &&
				     skb_checksum_help(skb))
					goto out_kfree_skb;
			}
		}
		/* 这里把将要发给驱动的数据包提供给上层嗅探程序进行分析监控 */
		if (!list_empty(&ptype_all))
			dev_queue_xmit_nit(skb, dev);

		skb_len = skb->len;
		trace_net_dev_start_xmit(skb, dev);
		/* 到这里终于把数据包提交给底层驱动程序了,漫长的网络子系统漫游结束了,是该离开的时候了 */
		rc = ops->ndo_start_xmit(skb, dev);
		trace_net_dev_xmit(skb, rc, dev, skb_len);
		/* 发送成功的话,需要更新该传输队列的统计计数 */
		if (rc == NETDEV_TX_OK)
			txq_trans_update(txq);
		return rc;
	}
	/* 到这里的数据包都已经完成了分片,所以一个分片一个分片的发给底层驱动处理
	 * 这里注意第一个分片没有包括实际的数据包。。
	 */
gso:
	do {
		struct sk_buff *nskb = skb->next;

		skb->next = nskb->next;
		nskb->next = NULL;

		/* 嗅探工具监控这些数据包 */
		if (!list_empty(&ptype_all))
			dev_queue_xmit_nit(nskb, dev);

		skb_len = nskb->len;
		trace_net_dev_start_xmit(nskb, dev);
		rc = ops->ndo_start_xmit(nskb, dev);
		trace_net_dev_xmit(nskb, rc, dev, skb_len);
		if (unlikely(rc != NETDEV_TX_OK)) {
			if (rc & ~NETDEV_TX_MASK)
				goto out_kfree_gso_skb;
			nskb->next = skb->next;
			skb->next = nskb;
			return rc;
		}
		txq_trans_update(txq);
		/* 由于多个分片一起发送,需要查看底层硬件是否来得及发送出去 */
		if (unlikely(netif_xmit_stopped(txq) && skb->next))
			return NETDEV_TX_BUSY;
	} while (skb->next);

out_kfree_gso_skb:
	if (likely(skb->next == NULL)) {
		skb->destructor = DEV_GSO_CB(skb)->destructor;
		consume_skb(skb);
		return rc;
	}
out_kfree_skb:
	kfree_skb(skb);
out:
	return rc;
}

你可能感兴趣的:(linux驱动子系统)