vpp本身支持线程之间的数据包调度——handoff。可以用这种特性来分发数据包至指定线程。

这里就从nat44的handoff开始来分析一下。简化掉拥塞,trace等处理,只看核心逻辑。

参考vpp代码版本号:2005

[ckun@localhost vpp]$ git status
# On branch 2005

初始化

设定nat44接口

snat_feature_command_fn函数

1. enable nat44-in2out-worker-handoff/nat44-out2in-worker-handoff  node

2. 初始化分发队列 vlib_frame_queue_main_init

vlib_frame_queue_main_init函数

1. new 一个vlib_frame_queue_main_t 结构, 追加到全局变量 vlib_thread_main的frame_queue_mains数组中。

这个 vlib_thread_main.frame_queue_mains在线程轮询时会去check,并get其中的数据包。

2. vlib_frame_queue_main_t结构内的初始化

typedef struct
{u32 node_index;         // 分发后线程转到对应node处理包u32 frame_queue_nelts;  // 队列中元素个数,默认64u32 queue_hi_thresh;    // 门限 64 - 线程数vlib_frame_queue_t **vlib_frame_queues;              // 线程数个frame_queuesvlib_frame_queue_per_thread_data_t *per_thread_data; //线程数个thread data/* for frame queue tracing */frame_queue_trace_t *frame_queue_traces;frame_queue_nelt_counter_t *frame_queue_histogram;
} vlib_frame_queue_main_t;

vlib_frame_queues

申请线程数个队列,每个队列中申请64个元素

typedef struct
{/* enqueue side */CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);volatile u64 tail;u64 enqueues;u64 enqueue_ticks;u64 enqueue_vectors;u32 enqueue_full_events;/* dequeue side */CLIB_CACHE_LINE_ALIGN_MARK (cacheline1);volatile u64 head;u64 dequeues;u64 dequeue_ticks;u64 dequeue_vectors;u64 trace;u64 vector_threshold;/* dequeue hint to enqueue side */CLIB_CACHE_LINE_ALIGN_MARK (cacheline2);volatile u64 head_hint;/* read-only, constant, shared */CLIB_CACHE_LINE_ALIGN_MARK (cacheline3);vlib_frame_queue_elt_t *elts;    // 64个元素u32 nelts;                       // 64个
}
vlib_frame_queue_t;

per_thread_data

申请线程数个thread_data。

每个thread_data中,再申请线程数个handoff_queue_elt_by_thread_index

typedef struct
{vlib_frame_queue_elt_t **handoff_queue_elt_by_thread_index;  // 记录本线程转发至目的线程的队列vlib_frame_queue_t **congested_handoff_queue_by_thread_index; //判断阻塞用的
} vlib_frame_queue_per_thread_data_t;

数据包分发至队列

1. 为数据包选择目的线程

这里按照数据包源地址哈希确定目的线程,确保某一用户的数据包一定落在同一个线程。

这里是in2out的例子,out2in根据端口决定线程,也能确保同一个用户一个线程。

static u32
snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0,u8 is_output)
{snat_main_t *sm = &snat_main;u32 next_worker_index = 0;u32 hash;next_worker_index = sm->first_worker_index;hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +(ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >> 24);if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];elsenext_worker_index += sm->workers[hash % _vec_len (sm->workers)];return next_worker_index;
}

2. 将数据包塞入分发队列 vlib_buffer_enqueue_to_thread

vlib_buffer_enqueue_to_thread (vlib_main_t * vm, u32 frame_queue_index, // fqm的index,在vlib_thead_main.frame_queue_mains中u32 * buffer_indices,  // 数据包的index们u16 * thread_indices,  // 目的线程标识,一个数据包对应一个线程idu32 n_packets,         // 数据包数int drop_on_congestion)

1. 获取队列元素

(每一个包处理)

vlib_frame_queue_elt_t*  hf  =   fqm->vlib_frame_queues[worker_thread_index]->elts[x]

从对应线程队列取一个可用的元素(闲置slot)

2. 将数据包index放入 hf->buffer_index数组中。

N个包处理完,某个线程的hf->buffer_index中会有多个数据包索引。

同时

fqm->per_thread_data[current_thread_index]->handoff_queue_elt_by_thread_index[worker_thread_index] = hf;

3. 遍历handoff_queue_elt_by_thread_index,获得每个操作过的hf

hf置为可用,工作线程置为需检查分发队列

       vlib_put_frame_queue_elt (hf); // hf->valid = 1vlib_mains[i]->check_frame_queues = 1;ptd->handoff_queue_elt_by_thread_index[i] = 0;

从队列取数据包

vlib_main_or_worker_loop 函数

函数循环体中,遍历所有fqm,尝试从fqm中取包

      if (!is_main){vlib_worker_thread_barrier_check ();if (PREDICT_FALSE (vm->check_frame_queues +frame_queue_check_counter)){u32 processed = 0;if (vm->check_frame_queues){frame_queue_check_counter = 100;vm->check_frame_queues = 0;}vec_foreach (fqm, tm->frame_queue_mains)        //遍历所有fqmprocessed += vlib_frame_queue_dequeue (vm, fqm);/* No handoff queue work found? */if (processed)frame_queue_check_counter = 100;elseframe_queue_check_counter--;}if (PREDICT_FALSE (vec_len (vm->worker_thread_main_loop_callbacks)))clib_call_callbacks (vm->worker_thread_main_loop_callbacks, vm);}

vlib_frame_queue_dequeue

1. 获取当前线程的队列 fq = fqm->vlib_frame_queues[worker_thread_index]

2.  fp->elts获取每一个有效的elt(etl->valid ==1)

3. 新建一个frame数据帧,隶属于fqm->node_index

4. 将elt元素中存有多个buffer_index, 传入到新建的frame数据帧里。

从而数据包顺利转入至目标线程和目标node。

vpp nat44 handoff数据包相关推荐

  1. 借助英特尔® AVX-512 指令集进行数据包处理

    点击上方蓝字 关注我们吧 原文作者 Ray Kinsella:Chris MacNamara:Georgii Tkachuk 英特尔® AVX-512 为数据包处理工具包增添了强大的助力.近期即将发布 ...

  2. wireshark官方文档第 9 章数据包解析

    第 9 章数据包解析 9.1. 数据包解析的工作原理 对于一个已封装好的协议包,每个解析器(dissector)对其负责的一部分协议进行解码,然后将解码过程交给后续的解析器. 每个解析都从帧(Fram ...

  3. 数据解析_485型风速和风向变送器数据包解析

    风向变送器有8方位风向和360度风向两种: 外壳分为铝合金和聚碳两种: 风向传感器/变速器测量方式分为: 模拟量(4-20mA/0-5V/0-10V) RS485 由于风速和风向变送器是分开的,所以我 ...

  4. linux禁止向指定ip发送数据包,Linux下使用iptables封锁端口禁止邮件发送

    原创文章,转载请注明出处:https://www.myzhenai.com/thread-17843-1-1.html https://www.myzhenai.com.cn/post/2161.ht ...

  5. python中的数据包处理模块scapy调研笔记

    Scapy简介 Scapy的是一个强大的交互式数据包处理程序(使用python编写).它能够伪造或者解码大量的网络协议数据包,能够发送.捕捉.匹配请求和回复包等等.它可以很容易地处理一些典型操作,比如 ...

  6. 网络数据包分析软件Wireshark简介

    Wireshark是被广泛使用的免费开源的网络协议分析软件(network protocol analyzer)或网络数据包分析软件,它可以让你在微观层面上查看网络上发生的事情,它的功能是截取网络数据 ...

  7. 一个最简单的通过WireShark破解SSL加密网络数据包的方法

    原文地址: http://article.yeeyan.org/view/530101/444688 一般来说,我们用WireShark来抓取包进行分析是没有多大问题的.但这里有个问题是,如果你碰到的 ...

  8. Linux内核--网络栈实现分析(二)--数据包的传递过程--转

    转载地址http://blog.csdn.net/yming0221/article/details/7492423 作者:闫明 本文分析基于Linux Kernel 1.2.13 注:标题中的&qu ...

  9. ESXi主机与网络中其他主机的网咯数据包捕获

    1.tcpdump-uw -i vmk0 -s 1514 host x.x.x.x   指定捕获与某台主机间的网络数据包 2.tcpdump -i vmk0 -s 1514 port not 22 a ...

最新文章

  1. Python安装及netcdf数据读写
  2. Spring Boot 缓存应用实践
  3. 机器物联网的四大价值流
  4. 双击U盘时既能运行程序又能打开U盘
  5. 列表,字典表达式以及三元表达式
  6. Mybatis面试题-日更
  7. jqGrid常用方法
  8. ssms中怎么设置自增_如何在SSMS状态栏中设置自定义颜色
  9. 误删数据库---恢复
  10. 利用场景法设计atm自动取款机的测试用例_黑盒测试之场景法
  11. Linux系统设置固定ip
  12. linux vi dd命令详解,Linux dd命令详解:数据备份,并在备份过程中进行格式转换...
  13. TS实现Base64的加密解密
  14. 谷歌浏览器安装vue-devtools插件
  15. 投影矩阵(投影变换)解惑
  16. html显示一条直线,如何在HTML中画一条线
  17. 论文超详细精读|五千字:STGR
  18. TINA导入Ti官网器件
  19. KPI与360度考核结合的应用落地方案
  20. java查询序列_基于JAVA的苹果序列号查询api调用代码实例

热门文章

  1. python写五子棋游戏下载_python实现简单五子棋游戏
  2. Ectd Raft 模块介绍(一)
  3. 2021备战金三银四血拼一波算法:字节+百度,java编程教程视频
  4. 2019考研浙大计算机经验帖
  5. 如何用Sketch制作精致的交互原型?
  6. [work]从贝叶斯方法谈到贝叶斯网络
  7. 游戏效果解密----水果忍者刀划痕效果
  8. WPF 控件自定义模板之:圆形进度条
  9. sourcetree安装遇到的各种坑
  10. 论如何创建APP打开提示手机框架不兼容(架构:32位和64位)