Linux,了解setsockopt()用于网络扩展的PACKET_FANOUT
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Linux,了解setsockopt()用于网络扩展的PACKET_FANOUT,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3835字,纯文字阅读大概需要6分钟。
内容图文
![Linux,了解setsockopt()用于网络扩展的PACKET_FANOUT](/upload/InfoBanner/zyjiaocheng/954/530564d368b34ed6ad8e895593461aeb.jpg)
我已经阅读了packet手册页和一些blog | posts试图了解如何使用PACKET_FANOUT套接字选项来扩展接收数据的处理(我希望使用SOCK_RAW以高速捕获流量,> 10Gbps).我已经阅读了this示例代码(下面复制了),但我不确定我是否完全理解它.
让我们想象一个场景;已在NIC上设置RSS,并且在RX队列之间均匀分配入口流量,有8个核心CPU和8个NIC RX队列,每个RX队列[0-7]分别向CPU [0-7]发送中断(关于MMAP,零拷贝,poll()等的进一步讨论是关于这里的主题).
这是我在示例代码中看到的事件顺序:
> 8个工作线程[0-7]启动,每个线程固定到CPU [0-7].
>每个线程使用与同一物理网卡绑定的setup_socket(),在promisc模式下,以及同一个FANOUT组的所有部分创建一个套接字(我们再说0-7).
>现在我们(例如)工作线程0绑定到CPU 0,它创建了套接字0.此线程进入一个无限循环,仅对套接字0调用read().
>当数据包进入NIC RX队列0时,会向CPU 0发送一个中断.CPU 0将数据包DMA发送到内核接收缓冲区空间. PACKET_FANOUT套接字选项应用了标志PACKET_FANOUT_CPU,因此只有与数据包进入相同CPU核心上的套接字(核心0)才会显示对该套接字进行read()调用时可用的数据(因此创建了套接字0)仅通过线程0)然后将数据复制到该线程的用户区接收缓冲区,因为这个标志.
在我对这个过程的理解中,第4点是主要的疑点.我是否正确理解了在这种情况下如何使用PACKET_FANOUT进行扩展以及如何将工作线程锁定到处理中断的同一核心?
void start_af_packet_capture(std::string interface_name, int fanout_group_id) {
// setup_socket() calls socket() (using SOCK_RAW) to created the socketFD,
// setsockopt() to enable promisc mode on the NIC,
// bind() to bind the socketFD to NIC,
// and setsockopt() again to set PACKET_FANOUT + PACKET_FANOUT_CPU
int packet_socket = setup_socket(interface_name, fanout_group_id);
if (packet_socket == -1) {
printf("Can't create socket\n");
return;
}
unsigned int capture_length = 1500;
char buffer[capture_length];
while (true) {
received_packets++;
int readed_bytes = read(packet_socket, buffer, capture_length);
// printf("Got %d bytes from interface\n", readed_bytes);
consume_pkt((u_char*)buffer, readed_bytes);
if (readed_bytes < 0) {
break;
}
}
}
...
bool use_multiple_fanout_processes = true;
// Could get some speed up on NUMA servers
bool execute_strict_cpu_affinity = false;
int main() {
boost::thread speed_printer_thread( speed_printer );
int fanout_group_id = getpid() & 0xffff;
if (use_multiple_fanout_processes) {
boost::thread_group packet_receiver_thread_group;
unsigned int num_cpus = 8;
for (int cpu = 0; cpu < num_cpus; cpu++) {
boost::thread::attributes thread_attrs;
if (execute_strict_cpu_affinity) {
cpu_set_t current_cpu_set;
int cpu_to_bind = cpu % num_cpus;
CPU_ZERO(¤t_cpu_set);
// We count cpus from zero
CPU_SET(cpu_to_bind, ¤t_cpu_set);
int set_affinity_result = pthread_attr_setaffinity_np(thread_attrs.native_handle(), sizeof(cpu_set_t), ¤t_cpu_set);
if (set_affinity_result != 0) {
printf("Can't set CPU affinity for thread\n");
}
}
packet_receiver_thread_group.add_thread(
new boost::thread(thread_attrs, boost::bind(start_af_packet_capture, "eth6", fanout_group_id))
);
}
// Wait all processes for finish
packet_receiver_thread_group.join_all();
} else {
start_af_packet_capture("eth6", 0);
}
speed_printer_thread.join();
}
编辑:奖金问题
这可能太不相关了,在这种情况下请建议,我将开始一个单独的SO帖子.这里的目标不仅是扩展多个核心的数据包处理,而且还将数据包处理代码放在接收该数据包的同一核心上(稍后将探索MMAP和RX_RING),以便减少上下文切换和缓存未命中CPU.我的理解是,这个目标正在这里实现,有人可以确认或否认吗?
解决方法:
我可以说,不,不完全. fanout_demux_cpu使用cpu和扇出组中的套接字数计算“哈希”,恰好是smp_processor_id()%num. packet_rcv_fanout然后使用它作为扇出组中套接字数组的索引,以确定哪个套接字获取它.
一旦你看到扇出组的整个设计是基于根据接收到的数据包的属性创建某种散列,而不是基于尝试读取套接字的线程的属性,你应该只是让调度程序解决问题,而不是固定线程.
或者,您可以进一步深入研究代码以对数组中套接字的顺序进行反向工程,但这很脆弱,您可能希望使用systemtap验证是否已正确完成.然后,您可以创建套接字.确定性顺序(希望在数组中产生确定性顺序)并将侦听给定套接字的线程固定到适当的cpu.
内容总结
以上是互联网集市为您收集整理的Linux,了解setsockopt()用于网络扩展的PACKET_FANOUT全部内容,希望文章能够帮你解决Linux,了解setsockopt()用于网络扩展的PACKET_FANOUT所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。