-
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;
-
-
if (likely(!skb->next)) {
/* skb->next为null,即只发送一个skb */
-
if (!list_empty(&ptype_all))
-
dev_queue_xmit_nit(skb, dev); //ptype_all上的协议处理,如tcpdump
-
-
/*
-
* If device doesnt need skb->dst, release it right now while
-
* its hot in this cpu cache
-
*/
-
/* device 不需要dst */
-
if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
-
skb_dst_drop(skb);
/* 使该skb不属于任何一个socket */
-
skb_orphan_try(skb);
-
-
if (netif_needs_gso(dev, skb)) {
-
/* 需要scatter gather功能 */
/*
从注释上看,是进行perform protocol segmentation on skb。
但是实际工作,目前我不清楚
*/
-
if (unlikely(dev_gso_segment(skb)))
-
goto out_kfree_skb;
-
if (skb->next)
-
goto gso;
-
} else {
-
//不需要scatter gather
/*
如需要连续内存,则将skb内存线性化,即连续内存
*/
-
if (skb_needs_linearize(skb, dev) &&
-
__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) {
-
/* 计算checksum */
-
skb_set_transport_header(skb, skb->csum_start -
-
skb_headroom(skb));
-
if (!dev_can_checksum(dev, skb) &&
-
skb_checksum_help(skb))
-
goto out_kfree_skb;
-
}
-
}
/* 发送skb数据 */
-
rc = ops->ndo_start_xmit(skb, dev);
-
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 device doesnt need nskb->dst, release it right now while
-
* its hot in this cpu cache
-
*/
-
if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
-
skb_dst_drop(nskb);
-
-
rc = ops->ndo_start_xmit(nskb, dev);
-
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_tx_queue_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;
-
out_kfree_skb:
-
kfree_skb(skb);
-
return rc;
-
}