• DPDK flow_classify 源码阅读


    代码部分

    1. /* SPDX-License-Identifier: BSD-3-Clause
    2. * Copyright(c) 2017 Intel Corporation
    3. */
    4. #include <stdint.h>
    5. #include <inttypes.h>
    6. #include <getopt.h>
    7. #include <rte_eal.h>
    8. #include <rte_ethdev.h>
    9. #include <rte_cycles.h>
    10. #include <rte_lcore.h>
    11. #include <rte_mbuf.h>
    12. #include <rte_flow.h>
    13. #include <rte_flow_classify.h>
    14. #include <rte_table_acl.h>
    15. #define RX_RING_SIZE 1024
    16. #define TX_RING_SIZE 1024
    17. #define NUM_MBUFS 8191
    18. #define MBUF_CACHE_SIZE 250
    19. #define BURST_SIZE 32
    20. #define MAX_NUM_CLASSIFY 30
    21. #define FLOW_CLASSIFY_MAX_RULE_NUM 91
    22. #define FLOW_CLASSIFY_MAX_PRIORITY 8
    23. #define FLOW_CLASSIFIER_NAME_SIZE 64
    24. #define COMMENT_LEAD_CHAR ('#')
    25. #define OPTION_RULE_IPV4 "rule_ipv4"
    26. #define RTE_LOGTYPE_FLOW_CLASSIFY RTE_LOGTYPE_USER3
    27. #define flow_classify_log(format, ...) \
    28. RTE_LOG(ERR, FLOW_CLASSIFY, format, ##__VA_ARGS__)
    29. #define uint32_t_to_char(ip, a, b, c, d) do {\
    30. *a = (unsigned char)(ip >> 24 & 0xff);\
    31. *b = (unsigned char)(ip >> 16 & 0xff);\
    32. *c = (unsigned char)(ip >> 8 & 0xff);\
    33. *d = (unsigned char)(ip & 0xff);\
    34. } while (0)
    35. enum {
    36. CB_FLD_SRC_ADDR, // 0
    37. CB_FLD_DST_ADDR, // 1
    38. CB_FLD_SRC_PORT, // 2
    39. CB_FLD_SRC_PORT_DLM, // 3
    40. CB_FLD_SRC_PORT_MASK,// 4
    41. CB_FLD_DST_PORT, // 5
    42. CB_FLD_DST_PORT_DLM, // 6
    43. CB_FLD_DST_PORT_MASK,// 7
    44. CB_FLD_PROTO, // 8
    45. CB_FLD_PRIORITY, // 9
    46. CB_FLD_NUM, // 10
    47. };
    48. static struct{
    49. const char *rule_ipv4_name;
    50. } parm_config; // 用于文件访问的。
    51. const char cb_port_delim[] = ":";
    52. static const struct rte_eth_conf port_conf_default = {
    53. .rxmode = {
    54. .max_rx_pkt_len = ETHER_MAX_LEN,
    55. .ignore_offload_bitfield = 1,
    56. },
    57. };
    58. struct flow_classifier {
    59. struct rte_flow_classifier *cls;
    60. };
    61. // flow_classifer 的结构要看 sample guide
    62. /*
    63. struct rte_flow_classifier {
    64. // classifier的参数,要 create() 时传入结构体。
    65. char name[RTE_FLOW_CLASSIFIER_MAX_NAME_SZ];
    66. int socket_id;
    67. // 其余的内部字段
    68. // n tuple 过滤器,也就是流规则的匹配项目了。
    69. struct rte_eth_ntuple_filter ntuple_filter;
    70. // tables
    71. struct rte_cls_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
    72. uint32_t table_mask;
    73. uint32_t num_tables;
    74. uint16_t nb_pkts;
    75. struct rte_flow_classify_table_entry
    76. *entries[RTE_PORT_IN_BURST_SIZE_MAX];
    77. } __rte_cache_aligned;
    78. */
    79. struct flow_classifier_acl {
    80. struct flow_classifier cls;
    81. } __rte_cache_aligned;
    82. /* ACL field definitions for IPv4 5 tuple rule */
    83. enum {
    84. PROTO_FIELD_IPV4, // 0
    85. SRC_FIELD_IPV4, // 1
    86. DST_FIELD_IPV4, // 2
    87. SRCP_FIELD_IPV4, // 3
    88. DSTP_FIELD_IPV4, // 4
    89. NUM_FIELDS_IPV4 // 5
    90. };
    91. enum {
    92. PROTO_INPUT_IPV4,
    93. SRC_INPUT_IPV4,
    94. DST_INPUT_IPV4,
    95. SRCP_DESTP_INPUT_IPV4
    96. };
    97. /* 数据结构 rte_acl_field_def:ACL 访问控制表的字段的定义
    98. ACL规则中的每个字段都有一个关联定义。有五个,分别是:
    99. 字段的类型 type
    100. 字段的字节数大小 size
    101. 字段的索引(指示哪一个字段)field_index 一个0开始的值,用来指定字段在规则内部的位置,0~n-1表示n个字段。
    102. 输入索引 input_index0-N) 所有输入字段,除了第一个,其他必须以4个连续字节分组,这个input_index就是来指定字段在那个组
    103. 偏移量offset 定义了字段的偏移量,为查找指定从缓冲区的起始位置的偏移。
    104. */
    105. /*
    106. rule “规则” 有一些独有规则:
    107. 1. 规则定义的第一个字段必须是一个字节的长度
    108. 2. 之后的字段必须以4个连续的字节分组
    109. 这主要是为性能考虑,查找函数处理第一个输入字节做为这个流的设置的一部分,然后这查找函数的内部循环被展开来同时处理4字节的输入。
    110. */
    111. static struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = { //5 个字段,每个字段都要有一个关联的五个定义
    112. /* first input field - always one byte long. */ // 第一个字段 1个字节
    113. {
    114. .type = RTE_ACL_FIELD_TYPE_BITMASK, // type 字段的类型,有3种选项,见https://www.cnblogs.com/danxi/p/6650757.html
    115. .size = sizeof(uint8_t), // 1个字节
    116. .field_index = PROTO_FIELD_IPV4, // 两个 index 都是 enum
    117. .input_index = PROTO_INPUT_IPV4,
    118. .offset = sizeof(struct ether_hdr) + // todo :数据结构
    119. offsetof(struct ipv4_hdr, next_proto_id),
    120. },
    121. /* next input field (IPv4 source address) - 4 consecutive bytes. */
    122. { // 第二个字段 源IP地址
    123. /* rte_flow uses a bit mask for IPv4 addresses */
    124. .type = RTE_ACL_FIELD_TYPE_BITMASK,
    125. .size = sizeof(uint32_t),
    126. .field_index = SRC_FIELD_IPV4,
    127. .input_index = SRC_INPUT_IPV4,
    128. .offset = sizeof(struct ether_hdr) +
    129. offsetof(struct ipv4_hdr, src_addr),
    130. },
    131. /* next input field (IPv4 destination address) - 4 consecutive bytes. */
    132. { // 第三个字段 目的IP地址
    133. /* rte_flow uses a bit mask for IPv4 addresses */
    134. .type = RTE_ACL_FIELD_TYPE_BITMASK,
    135. .size = sizeof(uint32_t),
    136. .field_index = DST_FIELD_IPV4,
    137. .input_index = DST_INPUT_IPV4,
    138. .offset = sizeof(struct ether_hdr) +
    139. offsetof(struct ipv4_hdr, dst_addr),
    140. },
    141. /*
    142. * Next 2 fields (src & dst ports) form 4 consecutive bytes.
    143. * They share the same input index.
    144. */
    145. // 接下来的 两个端口号 才组成一个 4 字节,所以共享同样的一个 input index
    146. {
    147. /* rte_flow uses a bit mask for protocol ports */
    148. .type = RTE_ACL_FIELD_TYPE_BITMASK,
    149. .size = sizeof(uint16_t),
    150. .field_index = SRCP_FIELD_IPV4,
    151. .input_index = SRCP_DESTP_INPUT_IPV4,
    152. .offset = sizeof(struct ether_hdr) + // (todo)
    153. sizeof(struct ipv4_hdr) +
    154. offsetof(struct tcp_hdr, src_port),
    155. },
    156. {
    157. /* rte_flow uses a bit mask for protocol ports */
    158. .type = RTE_ACL_FIELD_TYPE_BITMASK,
    159. .size = sizeof(uint16_t),
    160. .field_index = DSTP_FIELD_IPV4,
    161. .input_index = SRCP_DESTP_INPUT_IPV4,
    162. .offset = sizeof(struct ether_hdr) +
    163. sizeof(struct ipv4_hdr) +
    164. offsetof(struct tcp_hdr, dst_port),
    165. },
    166. };
    167. /* flow classify data */
    168. static int num_classify_rules; // rules数组的下标
    169. static struct rte_flow_classify_rule *rules[MAX_NUM_CLASSIFY]; // rules 数组
    170. static struct rte_flow_classify_ipv4_5tuple_stats ntuple_stats; // stats 结构体 (todo)
    171. static struct rte_flow_classify_stats classify_stats = { // 有计数功能
    172. .stats = (void **)&ntuple_stats
    173. };
    174. /* parameters for rte_flow_classify_validate and
    175. * rte_flow_classify_table_entry_add functions
    176. */
    177. /* rte_flow_item 四个字段:
    178. 1. type,是 enum 定义。见 rte_flow.h:http://doc.dpdk.org/api/rte__flow_8h_source.html
    179. 2. spec,指向相关项类型结构的有效指针,在许多情况下,可以设置成 NULL以请求广泛(非特定)匹配。在此情况下,last 和 mask 也要设置成 NULL
    180. 3. last,可以指向相同类型的结构,以定义包含范围。
    181. 4. Mask,是在解释spec和last的内容之前应用的简单位掩码
    182. */
    183. static struct rte_flow_item eth_item = { RTE_FLOW_ITEM_TYPE_ETH,
    184. 0, 0, 0 };
    185. static struct rte_flow_item end_item = { RTE_FLOW_ITEM_TYPE_END,
    186. 0, 0, 0 };
    187. /* sample actions:
    188. * "actions count / end"
    189. */
    190. struct rte_flow_query_count count = { // 计数器查询的结构体
    191. .reset = 1, // Reset counters after query
    192. .hits_set = 1, // 启用 hits 字段
    193. .bytes_set = 1, // 启用 bytes 字段
    194. .hits = 0, // Number of hits for this rule
    195. .bytes = 0, // Number of bytes through this rule
    196. };
    197. static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT, &count};
    198. static struct rte_flow_action end_action = { RTE_FLOW_ACTION_TYPE_END, 0}; // 本程序就用到了计数和end 两种 action
    199. static struct rte_flow_action actions[2];
    200. // rte_flow_action 见 programmers’ guides 的第九章 :http://doc.dpdk.org/guides/prog_guide/rte_flow.html
    201. // actions 数组代表当 pkt 被 pattern 匹配时要执行的一系列操作。
    202. // 在这个例子里,数组长度为二,actions[0] 就是计数,actions[1] 就是用来提示结尾。
    203. // rte_flow_action的具体定义不清楚
    204. // 估计第一个字段是 enum rte_flow_action_type ,具体的 enum 定义见:http://doc.dpdk.org/api/rte__flow_8h.html#a78f0386e683cfc491462a771df8b971a
    205. // 第二个字段计数器查询的
  • 相关阅读:
    C++基本知识(二)---函数重载、引用、内联函数、auto关键字
    Java基于JSP+Servlet的校友论坛管理系统
    MySQL中的多列子查询
    指针-矩阵变换
    【软件安装】docker 安装 elasticsearch 和 kibana
    数据结构与算法之排序: 冒泡排序 (Javascript版)
    Win11蓝屏代码IRQL NOT LESS OR EQUAL的处理方法
    预训练模型(Bert及GPT-2)相关资料整理
    Redash和Metabase深度比较之四:可视化种类
    Python读写文件代码
  • 原文地址:https://blog.csdn.net/lingshengxiyou/article/details/126563025