您的位置:首页 > 理论基础 > 计算机网络

网络数据包发送之dev_hard_start_xmit

2014-11-24 10:21 1071 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: