Linux内核收包精髓

本文原创为freas_1990,转载请表明出处:http://blog.csdn.net/freas_1990/article/details/42033025

网卡和磁盘是现代服务器里面性能要求最为苛刻的2个外设,我们来看一下Linux内核是如何处理高性能的网卡的。

int netif_rx(struct sk_buff *skb)
{
	int this_cpu = smp_processor_id();
	struct softnet_data *queue;
	unsigned long flags;

	if (skb->stamp.tv_sec == 0)
		do_gettimeofday(&skb->stamp);

	/* The code is rearranged so that the path is the most
	   short when CPU is congested, but is still operating.
	 */
	queue = &softnet_data[this_cpu];

	local_irq_save(flags);

	netdev_rx_stat[this_cpu].total++;
	if (queue->input_pkt_queue.qlen <= netdev_max_backlog) {
		if (queue->input_pkt_queue.qlen) {
			if (queue->throttle)
				goto drop;

enqueue:
			dev_hold(skb->dev);
			__skb_queue_tail(&queue->input_pkt_queue,skb);
			/* Runs from irqs or BH's, no need to wake BH */
			cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ);
			local_irq_restore(flags);
#ifndef OFFLINE_SAMPLE
			get_sample_stats(this_cpu);
#endif
			return softnet_data[this_cpu].cng_level;
		}

		if (queue->throttle) {
			queue->throttle = 0;
#ifdef CONFIG_NET_HW_FLOWCONTROL
			if (atomic_dec_and_test(&netdev_dropping))
				netdev_wakeup();
#endif
		}
		goto enqueue;
	}

	if (queue->throttle == 0) {
		queue->throttle = 1;
		netdev_rx_stat[this_cpu].throttled++;
#ifdef CONFIG_NET_HW_FLOWCONTROL
		atomic_inc(&netdev_dropping);
#endif
	}

drop:
	netdev_rx_stat[this_cpu].dropped++;
	local_irq_restore(flags);

	kfree_skb(skb);
	return NET_RX_DROP;
}

/* Deliver skb to an old protocol, which is not threaded well
   or which do not understand shared skbs.
 */
static int deliver_to_old_ones(struct packet_type *pt, struct sk_buff *skb, int last)
{
	static spinlock_t net_bh_lock = SPIN_LOCK_UNLOCKED;
	int ret = NET_RX_DROP;

	if (!last) {
		skb = skb_clone(skb, GFP_ATOMIC);
		if (skb == NULL)
			return ret;
	}
	if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) {
		kfree_skb(skb);
		return ret;
	}

	/* The assumption (correct one) is that old protocols
	   did not depened on BHs different of NET_BH and TIMER_BH.
	 */

	/* Emulate NET_BH with special spinlock */
	spin_lock(&net_bh_lock);

	/* Disable timers and wait for all timers completion */
	tasklet_disable(bh_task_vec+TIMER_BH);

	ret = pt->func(skb, skb->dev, pt);

	tasklet_hi_enable(bh_task_vec+TIMER_BH);
	spin_unlock(&net_bh_lock);
	return ret;
}
static void net_rx_action(struct softirq_action *h)
{
	int this_cpu = smp_processor_id();
	struct softnet_data *queue = &softnet_data[this_cpu];
	unsigned long start_time = jiffies;
	int bugdet = netdev_max_backlog;

	br_read_lock(BR_NETPROTO_LOCK);

	for (;;) {
		struct sk_buff *skb;
		struct net_device *rx_dev;

		local_irq_disable();
		skb = __skb_dequeue(&queue->input_pkt_queue);
		local_irq_enable();

		if (skb == NULL)
			break;

		skb_bond(skb);

		rx_dev = skb->dev;

#ifdef CONFIG_NET_FASTROUTE
		if (skb->pkt_type == PACKET_FASTROUTE) {
			netdev_rx_stat[this_cpu].fastroute_deferred_out++;
			dev_queue_xmit(skb);
			dev_put(rx_dev);
			continue;
		}
#endif
		skb->h.raw = skb->nh.raw = skb->data;
		{
			struct packet_type *ptype, *pt_prev;
			unsigned short type = skb->protocol;

			pt_prev = NULL;
			for (ptype = ptype_all; ptype; ptype = ptype->next) {
				if (!ptype->dev || ptype->dev == skb->dev) {
					if (pt_prev) {
						if (!pt_prev->data) {
							deliver_to_old_ones(pt_prev, skb, 0);
						} else {
							atomic_inc(&skb->users);
							pt_prev->func(skb,
								      skb->dev,
								      pt_prev);
						}
					}
					pt_prev = ptype;
				}
			}

#ifdef CONFIG_NET_DIVERT
			if (skb->dev->divert && skb->dev->divert->divert)
				handle_diverter(skb);
#endif /* CONFIG_NET_DIVERT */

#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
			if (skb->dev->br_port != NULL &&
			    br_handle_frame_hook != NULL) {
				handle_bridge(skb, pt_prev);
				dev_put(rx_dev);
				continue;
			}
#endif

			for (ptype=ptype_base[ntohs(type)&15];ptype;ptype=ptype->next) {
				if (ptype->type == type &&
				    (!ptype->dev || ptype->dev == skb->dev)) {
					if (pt_prev) {
						if (!pt_prev->data)
							deliver_to_old_ones(pt_prev, skb, 0);
						else {
							atomic_inc(&skb->users);
							pt_prev->func(skb,
								      skb->dev,
								      pt_prev);
						}
					}
					pt_prev = ptype;
				}
			}

			if (pt_prev) {
				if (!pt_prev->data)
					deliver_to_old_ones(pt_prev, skb, 1);
				else
					pt_prev->func(skb, skb->dev, pt_prev);
			} else
				kfree_skb(skb);
		}

		dev_put(rx_dev);

		if (bugdet-- < 0 || jiffies - start_time > 1)
			goto softnet_break;

#ifdef CONFIG_NET_HW_FLOWCONTROL
	if (queue->throttle && queue->input_pkt_queue.qlen < no_cong_thresh ) {
		if (atomic_dec_and_test(&netdev_dropping)) {
			queue->throttle = 0;
			netdev_wakeup();
			goto softnet_break;
		}
	}
#endif

	}
	br_read_unlock(BR_NETPROTO_LOCK);

	local_irq_disable();
	if (queue->throttle) {
		queue->throttle = 0;
#ifdef CONFIG_NET_HW_FLOWCONTROL
		if (atomic_dec_and_test(&netdev_dropping))
			netdev_wakeup();
#endif
	}
	local_irq_enable();

	NET_PROFILE_LEAVE(softnet_process);
	return;

softnet_break:
	br_read_unlock(BR_NETPROTO_LOCK);

	local_irq_disable();
	netdev_rx_stat[this_cpu].time_squeeze++;
	/* This already runs in BH context, no need to wake up BH's */
	cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ);
	local_irq_enable();

	NET_PROFILE_LEAVE(softnet_process);
	return;
}

看懂了吧?

麻痹的,Linux内核在网卡异步处理机制上比传统的BSD激进多了,性能优越得多,不过稳定性也随之下降!

时间: 2024-10-13 22:18:35

Linux内核收包精髓的相关文章

linux内核数据包转发流程(二)中断

[版权声明:转载请保留出处:blog.csdn.net/gentleliu.邮箱:shallnew*163.com] 内核在处理2层数据包之前,必须先处理中断系统,设立中断系统,才有可能每秒处理成千的帧. 当收到一个帧时,驱动程序会代表内核指示设备产生一个硬件中断,内核将中断其他的活动,然后调用一个驱动程序所注册的处理函数,以满足设备的需要.当事件是接收到一个帧时,处理函数就会把该帧排入队列某处,然后通知内核. 使用轮询技术会轻易浪费掉很多系统资源,因为内核会持续去读取检查是否有有帧的到来.但使

linux下抓包工具tcpdump详解

本文转自:http://www.cnblogs.com/ggjucheng/archive/2012/01/14/2322659.html 简介 用简单的话来定义tcpdump,就是:dump the traffic on a network,根据使用者的定义对网络上的数据包进行截获的包分析工具. tcpdump可以将网络中传送的数据包的“头”完全截获下来提供分析.它支持针对网络层.协议.主机.网络或端口的过滤,并提供and.or.not等逻辑语句来帮助你去掉无用的信息. 实用命令实例 默认启动

linux下程序包管理

我是一个老实人从来不说实话,我是一个好人从来不说真话,学习linux有段时间了,太高深的东西还不懂,就写一下最近学习的程序包管理吧. 大家都知道在我们学习linux主要是搞运维的,那么我们每天上班的时候就避免不了跟程序包打交道,你不信啊?反正我上班的时候领导总是在我不经意的抬头瞬间给我抛一个媚眼,我立马就领悟了领导的意思,有活要干了,最好不是服务器挂了老天保佑. 有时候我们需要在系统上安装某个软件或者服务(就是程序包),可能需要现在本地磁盘上查一下有没有这些程序包,有的话我们可以直接使用rpm

Linux 下zip包的压缩与解压

范例: zip命令可以用来将文件压缩成为常用的zip格式.unzip命令则用来解压缩zip文件. 1. 我想把一个文件abc.txt和一个目录dir1压缩成为yasuo.zip: # zip -r yasuo.zip abc.txt dir1 2.我下载了一个yasuo.zip文件,想解压缩: # unzip yasuo.zip 3.我当前目录下有abc1.zip,abc2.zip和abc3.zip,我想一起解压缩它们: # unzip abc\?.zip 注释:?表示一个字符,如果用*表示任意

Linux内

body { font-family: @楷体; font-size: 11.5pt; line-height: 1.5; } html, body { color: black; background-color: #E0D1DE; } h1 { font-size:1.5em; font-weight:bold; } h2 { font-size:1.4em; font-weight:bold; } h3 { font-size:1.3em; font-weight:bold; } h4 {

10.6-10.10 监控io性能 free命令 ps命令 查看网络 linux下抓包

七周二次课(3月20日)10.6 监控io性能10.7 free命令10.8 ps命令10.9 查看网络状态10.10 linux下抓包 扩展tcp三次握手四次挥手 http://www.doc88.com/p-9913773324388.htmltshark几个用法:http://www.aminglinux.com/bbs/thread-995-1-1.html 10.6 监控io性能 磁盘状态的两个命令 iostat -x 磁盘使用 iotop  磁盘使用 我们在运维工作中,除了查看内存

Linux之rpm包管理

rpm包管理 注意:内核不推荐升级,如果需要新版内核,可进行安装,linux可多版本内核共存,启动时进行内核选择即可,以免造成不稳定因素./var/lib/rpm 不要破坏,几乎不可重建,重建后数据也没有 主要掌握:rpm -qa "vsft*" 查询vsft开头的包rpm -e vsftpd 卸载rpm -q vsftpd &> /dev/null | rpm -i /media/Packages/vsftpd- 安装rpm -ql tree:查询包内文件rpm -qf

10.6 监控io性能 - 10.7 free命令 - 10.8 ps命令 - 10.9 查看网络状态 - 10.10 linux下抓包

- 10.6 监控io性能 - 10.7 free命令 - 10.8 ps命令 - 10.9 查看网络状态 - 10.10 linux下抓包 - 扩展tcp三次握手四次挥手 http://www.doc88.com/p-9913773324388.html  - tshark几个用法:http://www.aminglinux.com/bbs/thread-995-1-1.html  # 10.6 监控io性能 ![mark](http://oqxf7c508.bkt.clouddn.com/b

linux源码包的安装

一.基础知识    编译源程序的步骤:     # tar xf testapp-version.tar.{xz|bz2|gz}     # cd testapp-version     # ./configure      还需通过许多选项指定编译特性     # make     # make install    ./configure脚本的使用:     1.获取帮助      ./configure --help     2.较通用的一些选项      安装路径相关:       --