linux dev queue xmit,dev_queue_xmit发送过程的理解

int dev_queue_xmit(struct sk_buff *skb)

{

struct net_device *dev = skb->dev;

struct Qdisc *q;

int rc = -ENOMEM;

/* 处理GSO 数据包. */

if (netif_needs_gso(dev, skb))

goto gso;

/*如果设备不支持sg,并且数据是分片的;数据包分片中至少有一个数据在高端内存位置,并且设备不支持dma

* 作线性华处理

*/

if (skb_shinfo(skb)->frag_list &&

!(dev->features & NETIF_F_FRAGLIST) &&

__skb_linearize(skb))

goto out_kfree_skb;

if (skb_shinfo(skb)->nr_frags &&

(!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) &&

__skb_linearize(skb))

goto out_kfree_skb;

/* 如果数据包为作校验和,并且设备对该协议不支持校验和计算,则在此处计算校验

*/

if (skb->ip_summed == CHECKSUM_PARTIAL) {

skb_set_transport_header(skb, skb->csum_start -

skb_headroom(skb));

if (!(dev->features & NETIF_F_GEN_CSUM) &&

!((dev->features & NETIF_F_IP_CSUM) &&

skb->protocol == htons(ETH_P_IP)) &&

!((dev->features & NETIF_F_IPV6_CSUM) &&

skb->protocol == htons(ETH_P_IPV6)))

if (skb_checksum_help(skb))

goto out_kfree_skb;

}

gso:

spin_lock_prefetch(&dev->queue_lock);

.....

/* 设备支持队列,则数据包入队列操作:如保序计算等*/

if (q->enqueue) {

/* Grab device queue */

spin_lock(&dev->queue_lock);

q = dev->qdisc;

if (q->enqueue) {

/* reset queue_mapping to zero */

skb->queue_mapping = 0;

rc = q->enqueue(skb, q);

qdisc_run(dev);

spin_unlock(&dev->queue_lock);

rc = rc == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : rc;

goto out;

}

spin_unlock(&dev->queue_lock);

}

/* 设备无队列*/

if (dev->flags & IFF_UP) {

int cpu = smp_processor_id(); /* ok because BHs are off */

/* 防止数据包循环处理 */

if (dev->xmit_lock_owner != cpu) {

HARD_TX_LOCK(dev, cpu);

if (!netif_queue_stopped(dev) &&

!netif_subqueue_stopped(dev, skb->queue_mapping)) {

rc = 0;

/* 发送数据*/

if (!dev_hard_start_xmit(skb, dev)) {

HARD_TX_UNLOCK(dev);

goto out;

}

}

HARD_TX_UNLOCK(dev);

if (net_ratelimit())

printk(KERN_CRIT "Virtual device %s asks to "

"queue packet!\n", dev->name);

} else {

if (net_ratelimit())

printk(KERN_CRIT "Dead loop on virtual device "

"%s, fix it urgently!\n", dev->name);

}

}

....

}

int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)

{

if (likely(!skb->next)) {

..............

/* 调用设备的发送函数接口*/

return dev->hard_start_xmit(skb, dev);

}

out_kfree_skb:

kfree_skb(skb);

return 0;

}

/* 这里借用了gre设备来掩饰设备发送接口的*/

static void ipgre_tunnel_setup(struct net_device *dev)

{

SET_MODULE_OWNER(dev);

dev->uninit        = ipgre_tunnel_uninit;

dev->destructor     = free_netdev;

dev->hard_start_xmit    = ipgre_tunnel_xmit;

dev->get_stats        = ipgre_tunnel_get_stats;

dev->do_ioctl        = ipgre_tunnel_ioctl;

dev->change_mtu        = ipgre_tunnel_change_mtu;

dev->type        = ARPHRD_IPGRE;

dev->hard_header_len     = LL_MAX_HEADER + sizeof(struct iphdr) + 4;

dev->mtu        = ETH_DATA_LEN - sizeof(struct iphdr) - 4;

dev->flags        = IFF_NOARP;

dev->iflink        = 0;

dev->addr_len        = 4;

}

在ipgre_tunnel_xmit的实现代码中 :有段代码如下  ,说明网卡先复制该skb,然后释放该skb

所以,释放 skb的动作是由网卡驱动来做的 .也就是说如果我们自己构造一个数据包调用xmit后.该包的释放不用我们自己来完成

if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) {

struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);

if (!new_skb) {

ip_rt_put(rt);

stats->tx_dropped++;

dev_kfree_skb(skb);

tunnel->recursion--;

return 0;

}

if (skb->sk)

skb_set_owner_w(new_skb, skb->sk);

dev_kfree_skb(skb);

skb = new_skb;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`queue.Queue()`是Python中的标准队列类,它可以用来实现队列的基本操作,如入队和出队等。`task_done()`是Queue类中的一个方法,用于通知队列,一个线程已经完成了它的任务,可以从队列中移除任务。 在使用队列时,当一个线程完成它的任务后,应该调用`task_done()`方法来通知队列。这样,队列就可以知道哪些任务已经完成,哪些任务还在等待处理。当队列中的所有任务都被标记为完成时,队列会解除阻塞状态,以便程序可以继续执行下一步操作。 下面是一个使用`queue.Queue()`和`task_done()`的示例代码: ```python import queue import threading def worker(q): while True: item = q.get() # 处理任务 print(f"Processing item: {item}") # 标记任务完成 q.task_done() q = queue.Queue() # 创建多个线程 for i in range(5): t = threading.Thread(target=worker, args=(q,)) t.daemon = True t.start() # 添加任务到队列 for item in range(10): q.put(item) # 等待队列中的任务完成 q.join() print("All tasks are done.") ``` 在这个示例中,我们创建了一个队列`q`,并启动了5个线程来处理队列中的任务。我们将10个任务添加到队列中,并使用`q.join()`等待队列中的所有任务完成。在每个线程中,我们使用`q.get()`获取队列中的任务,并在处理完任务后使用`q.task_done()`标记任务完成。最后,当所有任务都完成时,程序会输出"All tasks are done."。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值