vpp 主要数据结构


难度 中等
  • vlib_main_t

    vpp最顶层结构,其中包含了vpp执行的绝大部分信息,后续注册加载都是填充该数据结构。执行都需要从该数据结构中获取相关信息。

    其中节点存在node_main中,即:

    /* Node graph main structure. */
    vlib_node_main_t node_main;
  • vlib_node_main_t

    存放节点图。其中节点实际存放位置为:

    /* Public nodes. */
    vlib_node_t **nodes; // 存储非VLIB_NODE_TYPE_PROCESS节点
    
    /* Vector of process nodes.
         One for each node of type VLIB_NODE_TYPE_PROCESS. */
    vlib_process_t **processes; // 存储VLIB_NODE_TYPE_PROCESS节点
    
    /* Node index hashed by node name. */
    uword *node_by_name; // 根据名字取节点
    
    /* Nodes segregated by type for cache locality.
         Does not apply to nodes of type VLIB_NODE_TYPE_INTERNAL. */
    vlib_node_runtime_t *nodes_by_type[VLIB_N_NODE_TYPE]; // 存放各节点对应的runtime
  • vlib_process_t

    存放VLIB_NODE_TYPE_PROCESS类型的节点的信息。

    /* Node runtime for this process. */
     vlib_node_runtime_t node_runtime;
  • vlib_node_t

    /* Vector processing function for this node. */
    vlib_node_function_t *function;
    
     /* Index of corresponding node runtime. */
     u32 runtime_index; // 对于VLIB_NODE_TYPE_PROCESS节点是在vlib_node_main_t的proceses中的索引
              // 对于非VLIB_NODE_TYPE_PROCESS节点是在vlib_node_main_t的nodes中的索引
  • vlib_node_runtime_t

    调度框架实际频繁使用的结构,从vlib_node_t拷贝了部分信息,以及私有的频繁变动的信息。

  • vlib_frame_t

    每个node都有一个对应的vlib_frame_t,用来保存供node使用的数据包集合。这是每个node最终处理数据的内存所在地。

      /* Frame flags. */
      u16 frame_flags;
    
      /* User flags. Used for sending hints to the next node. */
      u16 flags;
    
      /* Number of scalar bytes in arguments. */
      u8 scalar_size;
     
      /* Number of bytes per vector argument. */
      u8 vector_size;
    
      /* Number of vector elements currently in frame. */
      u16 n_vectors;
    
    /* Scalar and vector arguments to next node. */
      u8 arguments[0];
  • vlib_pending_frame_t

    当一个node处理完数据包,则填充该数据结构,并加入到全局链表,调度框架便能在下一次调度时找到需要 接手该数据包的下一个node

    /* A frame pending dispatch by main loop. */
    typedef struct
    {
      /* Node and runtime for this frame. */
      u32 node_runtime_index;
    
      /* Frame index (in the heap). */
      u32 frame_index;
        /* Start of next frames for this node. */
      u32 next_frame_index;
    
      /* Special value for next_frame_index when there is no next frame. */
    #define VLIB_PENDING_FRAME_NO_NEXT_FRAME ((u32) ~0)
    } vlib_pending_frame_t;
  • vlib_next_frame_t

    主要是node内部逻辑使用,定位该node的下一条信息。

    /* Frame index. */
      u32 frame_index;
    
      /* Node runtime for this next. */
      u32 node_runtime_index;
    
      /* Next frame flags. */
      u32 flags;
    
     /* Number of vectors enqueue to this next since last overflow. */
      u32 vectors_since_last_overflow;

报文流转

报文处理主要包含如下三个方面:

  • 存储节点
  • 存储报文
  • 报文传送

报文流转的流程如下:

  1. 确定报文发送给哪个孩子节点

    确定把报文送给哪个孩子节点处理,是由该 node 的业务逻辑决定的,通常有两种方式:一是通过解析报文的内容来决定,比如 ethernet-input 节点通过解析报文是 ipv4 还是 ipv6 报文把报文发送给ip4-input 或 ip6-input 去处理;二是通过查找转发表来决定,比如 ip4-lookup 通过查找路由表来决定
    把报文发送给 ip4-arp 还是 ip4-rewrite 节点来处理。

  2. 找到孩子节点对应的用于存放报文的结构vlib_frame_t

    确定把报文发送给第几个孩子节点之后,就可以获取该孩子节点对应的 vlib_next_frame_t 结构了。vlib_next_frame_t 结构中的 frame_index 字段指向vlib_frame_t 结构,vlib_frame_t 结构是存放报文的地方

  3. 把报文放入vlib_frame_t结构

    vlib_frame_t 结构最后一个字段为可变数组,初始化的时候会分配一块内存,用于存放报文的索引。

  4. 创建 vlib_pending_frame_t 结构,并把它加入数组 vm->node_main. pending_frames 等待调度

vlib_pending_frame_t 结构记录报文所在的结构 vlib_next_frame_t 的 index,以及处理这些报文的node 的 vlib_node_runtime_t 结构的索引,这样通过 vlib_pending_frame_t 结构里面的信息就可以把报文分发给指定的 node 处理了

graph TB vlib_get_next_frame-->vlib_get_next_frame_internal-->vlib_frame_alloc-->vlib_frame_alloc_to_node-->vlib_put_next_frame

文章作者: growdu
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 growdu !
  目录
分类导航
随笔2 AI27 算法1 计算机基础13 博客搭建7 ChatGPT2 集群63 计算机通信1 数据库34 数据库深入80 DPDK26 Docker11 Elasticsearch4 编辑工具4 FAQ1 Go Web1 hometown2 编程语言16 网络9 OPC1 Linux38 openGauss4 页面12 PostgreSQL54 程序员自我修养1 协议11 成长之路1 stock1 存储5 工具20 VPP18 视频作品1 Vue13 Web1 代码示例11 数据库15 BenchmarkSQL1 PostgreSQL 源码修炼之路14
最热文章
1
13 逻辑复制深入
数据库深入🔥 1570
2
0 Postgresql存储、索引及系统优化、主备切换
PostgreSQL🔥 1495
3
一文读懂openguass dcf网络模块
集群🔥 1420
4
逻辑复制源码分析
数据库深入🔥 1327
5
PostgreSQL 分区表:从一行 `PARTITION BY` 到路由热路径的全链路拆解
数据库🔥 1094
6
applyparallelworker.c 之 LA 端源码深度解析:Leader Apply Worker 的指挥中枢
数据库深入🔥 1082
7
PostgreSQL Background Worker 全解:从 `RegisterBackgroundWorker` 到逻辑复制 4 类 worker 的全生命周期
数据库🔥 1078
8
PostgreSQL的后台进程walsender分析 - 关系型数据库 - 亿速云
PostgreSQL🔥 1033
9
PostgreSQL 逻辑复制的监控:六张视图 + 一组可执行 SQL,把 publisher/subscriber 的速率与健康度彻底看透
数据库🔥 1032
10
PostgreSQL 逻辑复制支持 DDL 之后:DDL 与 DML 的时序难题(重点:分区表)
数据库🔥 999
11
reorderbuffer.c 源码深度解析:PostgreSQL 逻辑复制的"事务重组引擎
数据库深入🔥 953
12
PostgreSQL 内核开发:读取一张表的 9 步标准流程与缓存全景
数据库🔥 938
13
从 `postgres` 二进制到生产级守护 —— PostgreSQL 最外层模块与启动全流程拆解
数据库🔥 936
14
支持逻辑复制同步 DDL 适配 SQL Server 方案
数据库深入🔥 934
15
PostgreSQL 逻辑复制的 ReorderBuffer 与事务机制:从一行 WAL 到一致性变更流的全链路绑定
数据库🔥 913
16
DDL同步架构(美化版)
数据库深入🔥 908
17
PostgreSQL Latch 机制详解:从一行 SetLatch 到 epoll 的内核之旅
数据库🔥 871
18
pgbench 源码全解:一个 C 文件如何撑起 PostgreSQL 官方压测工具
数据库🔥 860
19
PostgreSQL libpq 机制与缓冲区详解
数据库🔥 850
20
PostgreSQL 逻辑复制 spill 文件深度剖析:从 `xid-*.spill` 到 TPC-C 的增长方程
数据库🔥 845