librte_timer
此库为 DPDK 执行单元提供定时器服务,提供异步执行函数的能力。它可以是周期性的函数调用,也可以是一次性调用。它使用环境抽象层(EAL)提供的定时器接口获取精确的时间参考,并可以根据需要以每个核心为基础进行初始化
1.1 rte_timer_subsystem_init
函数是 DPDK 中 librte_timer 模块的初始化函数,用于初始化定时器子系统。
void rte_timer_subsystem_init(void);
该函数没有参数,用于初始化 DPDK 的定时器子系统。
使用场景:
- 在需要使用 DPDK 定时器功能之前,通常需要先调用该函数进行初始化。
- 在 DPDK 应用程序的初始化阶段调用该函数。
#include <rte_timer.h>
int main(int argc, char *argv[]) {
// 初始化 EAL
int ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Error initializing EAL\n");
// 初始化定时器子系统
rte_timer_subsystem_init();
// 其他初始化操作...
// 应用程序主逻辑...
return 0;
}
1.2 rte_timer_init
该函数用于初始化一个指定的定时器结构体 struct rte_timer
int rte_timer_init(struct rte_timer *tim);
使用场景:
- 在需要使用定时器功能之前,通常需要先初始化定时器。
- 在 DPDK 应用程序的初始化阶段调用该函数来初始化定时器
#include <rte_timer.h>
int main(int argc, char *argv[]) {
// 初始化 EAL
int ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Error initializing EAL\n");
// 初始化定时器结构体
struct rte_timer my_timer;
ret = rte_timer_init(&my_timer);
if (ret != 0)
rte_exit(EXIT_FAILURE, "Error initializing timer\n");
// 其他初始化操作...
// 应用程序主逻辑...
return 0;
}
1.3 rte_timer_reset
void rte_timer_reset(struct rte_timer *tim, uint64_t ticks, enum rte_timer_type type, uint16_t tim_lcore_id, rte_timer_cb_t fct, void *arg);
该函数用于重置指定的定时器,设置定时器的定时参数和回调函数。
- tim: 要重置的定时器结构体指针。
- ticks: 定时器的周期,以 CPU 的时钟周期为单位。
- type: 定时器的类型,可以是 RTE_TIMER_SINGLE(单次触发)或 RTE_TIMER_PERIODICAL(周期触发)。
- tim_lcore_id: 定时器运行的 CPU 核心 ID。
- fct: 定时器超时时要调用的回调函数。
- arg: 回调函数的参数。
使用场景:
- 在需要设置定时器的超时事件和回调函数时调用该函数。
- 可以在程序中多次调用该函数,以便在不同的时间点设置不同的定时器参数和回调函数。
1.4 rte_timer_stop
void rte_timer_stop(struct rte_timer *tim);
该函数用于停止指定的定时器。
- tim: 要停止的定时器结构体指针。
使用场景:
- 在不需要定时器继续工作时调用该函数,停止定时器的计时。
- 可以在程序中多次调用该函数,以停止不同的定时器。
#include <rte_timer.h>
int main(int argc, char *argv[]) {
// 初始化 EAL
int ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Error initializing EAL\n");
// 初始化定时器结构体
struct rte_timer my_timer;
ret = rte_timer_init(&my_timer);
if (ret != 0)
rte_exit(EXIT_FAILURE, "Error initializing timer\n");
// 启动定时器
rte_timer_reset(&my_timer, 1000000, RTE_TIMER_SINGLE, rte_lcore_id(), NULL, NULL);
// 其他操作...
// 暂停定时器
rte_timer_stop(&my_timer);
// 其他操作...
return 0;
}
1.5 rte_timer_reset_sync
void rte_timer_reset_sync(struct rte_timer *tim, uint64_t ticks, enum rte_timer_type type, uint16_t tim_lcore_id, rte_timer_cb_t fct, void *arg);
该函数用于同步方式重置指定的定时器,设置定时器的定时参数和回调函数,并等待重置完成。
同步方式重置定时器时,是对一个已经存在的定时器实例进行重置,设置新的定时参数和回调函数
- tim: 要重置的定时器结构体指针。
- ticks: 定时器的周期,以 CPU 的时钟周期为单位。
- type: 定时器的类型,可以是 RTE_TIMER_SINGLE(单次触发)或 RTE_TIMER_PERIODICAL(周期触发)。
- tim_lcore_id: 定时器运行的 CPU 核心 ID。
- fct: 定时器超时时要调用的回调函数。
- arg: 回调函数的参数。
使用场景: - 在需要设置定时器的超时事件和回调函数,并且需要等待定时器重置完成后再继续执行后续操作时使用。
- 通常在初始化阶段调用该函数来初始化定时器,确保定时器的状态已经被完全重置。
#include <rte_timer.h>
// 定时器超时时要调用的回调函数
void timer_callback(struct rte_timer *tim, void *arg) {
printf("Timer callback function called\n");
}
int main(int argc, char *argv[]) {
// 初始化 EAL
int ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Error initializing EAL\n");
// 初始化定时器结构体
struct rte_timer my_timer;
ret = rte_timer_init(&my_timer);
if (ret != 0)
rte_exit(EXIT_FAILURE, "Error initializing timer\n");
// 同步方式重置定时器,并等待重置完成
rte_timer_reset_sync(&my_timer, 1000000, RTE_TIMER_SINGLE, rte_lcore_id(), timer_callback, NULL);
// 其他操作...
return 0;
}
1.6 rte_timer_stop_sync
int rte_timer_stop_sync(struct rte_timer *tim);
该函数用于同步方式停止指定的定时器,并等待停止完成。
- tim: 要停止的定时器结构体指针。
使用场景:
- 在需要停止定时器的情况下,可以使用该函数来确保定时器被完全停止后再继续后续操作。
- 通常在程序的运行时,当不再需要某个定时器时,可以调用该函数来停止定时器的计时
#include <stdio.h>
#include <rte_timer.h>
// 定时器超时时要调用的回调函数
void timer_callback(struct rte_timer *tim, void *arg) {
printf("Timer callback function called\n");
// 执行一些操作...
}
int main(int argc, char *argv[]) {
// 初始化 EAL
int ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Error initializing EAL\n");
// 初始化定时器结构体
struct rte_timer my_timer;
ret = rte_timer_init(&my_timer);
if (ret != 0)
rte_exit(EXIT_FAILURE, "Error initializing timer\n");
// 启动定时器
rte_timer_reset(&my_timer, 1000000, RTE_TIMER_SINGLE, rte_lcore_id(), timer_callback, NULL);
// 其他操作...
// 暂停定时器,并等待停止完成
ret = rte_timer_stop_sync(&my_timer);
if (ret != 0)
rte_exit(EXIT_FAILURE, "Error stopping timer\n");
// 其他操作...
return 0;
}
rte_timer_stop_sync
和 rte_timer_stop
是停止定时器的两个不同函数,它们的区别在于:
同步方式停止 vs 异步方式停止:
rte_timer_stop_sync 是同步方式停止定时器,调用该函数会阻塞当前线程,直到定时器被完全停止后才会返回。
rte_timer_stop 是异步方式停止定时器,调用该函数会立即返回,不会等待定时器被停止。
1.7 rte_timer_manage
函数用于管理 DPDK 中的定时器,在主循环中周期性地检查和处理定时器的到期事件
void rte_timer_manage(void);
-
函数定义: rte_timer_manage 函数没有参数,返回值为 void,用于周期性地检查和处理定时器的到期事件。
-
用法: 在主循环中调用 rte_timer_manage 函数以触发定时器事件的处理。通常在主循环的适当位置调用此函数。
使用场景:
- 当需要使用定时器功能实现周期性任务或处理延时事件时,可以使用 rte_timer_manage 函数。
- 适用于需要实现轮询定时器事件并在事件到期时执行相应操作的场景。
#include <rte_timer.h>
// 定时器回调函数
static void timer_callback(struct rte_timer *tim, void *arg) {
// 处理定时器事件
printf("Timer event occurred!\n");
}
int main(int argc, char *argv[]) {
// 初始化 DPDK 库
rte_eal_init(argc, argv);
// 创建定时器
struct rte_timer timer;
rte_timer_init(&timer);
// 设置定时器参数
rte_timer_reset(&timer, TIMER_INTERVAL, PERIODICAL, rte_lcore_id(), timer_callback, NULL);
// 主循环
while (1) {
// 执行 DPDK 库的主循环任务
rte_timer_manage(); // 管理定时器事件
// 其他主循环任务
}
return 0;
}
感觉鸡肋,不如直接rte_eal_alarm_set
1.8 rte_eal_alarm_set
函数用于设置一个在指定时间后触发的定时器,它可以在 DPDK 应用程序中用于执行延时操作
int rte_eal_alarm_set(uint64_t us_delay, rte_eal_alarm_callback cb, void *arg);
函数定义
: rte_eal_alarm_set 函数用于设置一个在指定时间后触发的定时器,当定时器到期时,指定的回调函数将被调用。
参数:
- us_delay:定时器的延迟时间,以微秒为单位。
- cb:定时器到期时调用的回调函数。
- arg:传递给回调函数的参数。
返回值: 如果设置成功,则返回 0;如果出现错误,则返回负数。
使用场景:
- 当需要在一定延迟后执行某些操作时,可以使用 rte_eal_alarm_set 函数来设置延时触发的定时器。
- 适用于需要在延时触发时执行异步操作的场景。
1.9 rte_eal_alarm_cancel
void rte_eal_alarm_cancel(rte_eal_alarm_callback cb, void *arg);
函数定义:
rte_eal_alarm_cancel 函数用于取消之前设置的定时器,取消后不再触发定时器到期时的回调函数。
参数:
- cb:要取消的定时器的回调函数。
- arg:传递给回调函数的参数。
返回值: 无。
使用场景:
- 当不再需要之前设置的定时器时,可以使用 rte_eal_alarm_cancel 函数将其取消,以避免触发不再需要的回调函数。
- 适用于需要在特定条件下取消定时器的场景
librte_hash
2.1 rte_hash_create
函数用于创建一个哈希表
struct rte_hash *rte_hash_create(const struct rte_hash_parameters *params);
- params:指向一个 rte_hash_parameters 结构体的指针,包含了创建哈希表所需的参数。
#include <rte_hash.h>
#include <stdio.h>
#define MAX_ENTRIES 1024
int main() {
// 定义哈希表的参数
struct rte_hash_parameters hash_params = {
.name = "example_hash",
.entries = MAX_ENTRIES,
.key_len = sizeof(uint32_t),
.hash_func = rte_jhash,
.hash_func_init_val = 0,
.socket_id = SOCKET_ID_ANY
};
// 创建哈希表
struct rte_hash *hash_table = rte_hash_create(&hash_params);
if (hash_table == NULL) {
printf("Failed to create hash table\n");
return -1;
}
// 向哈希表中添加一些键值对
uint32_t keys[MAX_ENTRIES] = {1, 2, 3, 4, 5};
uint32_t values[MAX_ENTRIES] = {10, 20, 30, 40, 50};
for (int i = 0; i < 5; i++) {
rte_hash_add_key_data(hash_table, &keys[i], &values[i]);
}
// 查找键值对并打印结果
uint32_t lookup_key = 3;
void *lookup_value;
int ret = rte_hash_lookup_data(hash_table, &lookup_key, &lookup_value);
if (ret == 0) {
printf("Value for key %u is %u\n", lookup_key, *((uint32_t *)lookup_value));
} else {
printf("Key %u not found\n", lookup_key);
}
// 删除一个键值对
uint32_t delete_key = 2;
ret = rte_hash_del_key(hash_table, &delete_key);
if (ret == 0) {
printf("Key %u deleted successfully\n", delete_key);
} else {
printf("Failed to delete key %u\n", delete_key);
}
// 释放哈希表资源
rte_hash_free(hash_table);
return 0;
}
2.2 rte_hash_free
函数用于释放之前使用rte_hash_create创建的哈希表的资源
void rte_hash_free(struct rte_hash *h);
- h:要释放的哈希表的指针。
#include <rte_hash.h>
#include <stdio.h>
#define MAX_ENTRIES 1024
int main() {
// 定义哈希表的参数
struct rte_hash_parameters hash_params = {
.name = "example_hash",
.entries = MAX_ENTRIES,
.key_len = sizeof(uint32_t),
.hash_func = rte_jhash,
.hash_func_init_val = 0,
.socket_id = SOCKET_ID_ANY
};
// 创建哈希表
struct rte_hash *hash_table = rte_hash_create(&hash_params);
if (hash_table == NULL) {
printf("Failed to create hash table\n");
return -1;
}
// 向哈希表中添加一些键值对
uint32_t keys[MAX_ENTRIES] = {1, 2, 3, 4, 5};
uint32_t values[MAX_ENTRIES] = {10, 20, 30, 40, 50};
for (int i = 0; i < 5; i++) {
rte_hash_add_key_data(hash_table, &keys[i], &values[i]);
}
// 释放哈希表资源
rte_hash_free(hash_table);
// 尝试查找键值对并打印结果(应该会失败)
uint32_t lookup_key = 3;
void *lookup_value;
int ret = rte_hash_lookup_data(hash_table, &lookup_key, &lookup_value);
if (ret == 0) {
printf("Value for key %u is %u\n", lookup_key, *((uint32_t *)lookup_value));
} else {
printf("Key %u not found\n", lookup_key);
}
return 0;
}
2.3 rte_hash_lookup
函数用于在哈希表中查找指定键的值,根据键值获取对应的value
int rte_hash_lookup(const struct rte_hash *h, const void *key);
- h:要查找的哈希表的指针。
- key:要查找的键的指针。
该函数将返回查找结果的索引,如果未找到键,则返回负数
#include <rte_hash.h>
#include <stdio.h>
#include <stdint.h>
#define MAX_ENTRIES 1024
// 定义一个示例的结构体
struct my_struct {
uint32_t id;
char name[20];
};
int main() {
// 定义哈希表的参数
struct rte_hash_parameters hash_params = {
.name = "example_hash",
.entries = MAX_ENTRIES,
.key_len = sizeof(uint32_t),
.hash_func = rte_jhash,
.hash_func_init_val = 0,
.socket_id = SOCKET_ID_ANY
};
// 创建哈希表
struct rte_hash *hash_table = rte_hash_create(&hash_params);
if (hash_table == NULL) {
printf("Failed to create hash table\n");
return -1;
}
// 向哈希表中添加一些键值对
struct my_struct values[MAX_ENTRIES] = {
{1, "Alice"},
{2, "Bob"},
{3, "Charlie"},
{4, "David"},
{5, "Eve"}
};
uint32_t keys[MAX_ENTRIES] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++) {
rte_hash_add_key_data(hash_table, &keys[i], &values[i]);
}
// 查找键值对并打印结果
uint32_t lookup_key = 3;
void *lookup_value;
int ret = rte_hash_lookup_data(hash_table, &lookup_key, &lookup_value);
if (ret == 0) {
struct my_struct *result = (struct my_struct *)lookup_value;
printf("Value for key %u: ID=%u, Name=%s\n", lookup_key, result->id, result->name);
} else {
printf("Key %u not found\n", lookup_key);
}
// 尝试查找不存在的键值对并打印结果
uint32_t non_existent_key = 10;
ret = rte_hash_lookup_data(hash_table, &non_existent_key, &lookup_value);
if (ret == 0) {
struct my_struct *result = (struct my_struct *)lookup_value;
printf("Value for key %u: ID=%u, Name=%s\n", non_existent_key, result->id, result->name);
} else {
printf("Key %u not found\n", non_existent_key);
}
// 释放哈希表资源
rte_hash_free(hash_table);
return 0;
}
2.4 rte_hash_add_key_data
函数用于向哈希表中添加一个键值对
int rte_hash_add_key_data(struct rte_hash *h, const void *key, void *data);
- h:要添加键值对的哈希表的指针。
- key:要添加的键的指针。
- data:要与键关联的数据的指针
函数返回值为0表示成功添加键值对,负数表示添加失败
#include <rte_hash.h>
#include <stdio.h>
#include <stdint.h>
#define MAX_ENTRIES 1024
// 定义一个示例的结构体
struct my_struct {
uint32_t id;
char name[20];
};
int main() {
// 定义哈希表的参数
struct rte_hash_parameters hash_params = {
.name = "example_hash",
.entries = MAX_ENTRIES,
.key_len = sizeof(uint32_t),
.hash_func = rte_jhash,
.hash_func_init_val = 0,
.socket_id = SOCKET_ID_ANY
};
// 创建哈希表
struct rte_hash *hash_table = rte_hash_create(&hash_params);
if (hash_table == NULL) {
printf("Failed to create hash table\n");
return -1;
}
// 向哈希表中添加一些键值对
struct my_struct values[MAX_ENTRIES] = {
{1, "Alice"},
{2, "Bob"},
{3, "Charlie"},
{4, "David"},
{5, "Eve"}
};
uint32_t keys[MAX_ENTRIES] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++) {
int ret = rte_hash_add_key_data(hash_table, &keys[i], &values[i]);
if (ret == 0) {
printf("Key %u added successfully with data: ID=%u, Name=%s\n", keys[i], values[i].id, values[i].name);
} else {
printf("Failed to add key %u\n", keys[i]);
}
}
// 释放哈希表资源
rte_hash_free(hash_table);
return 0;
}
2.5 rte_hash_iterate
函数用于迭代哈希表中的每个条目,并对每个条目执行指定的操作
int32_t
rte_hash_iterate(const struct rte_hash *h, const void **key, void **data, uint32_t *next)
- const struct rte_hash *h:指向要遍历的哈希表结构的指针。
- const void **key:用于存储遍历到的键的指针的指针。在每次调用时,这个函数会更新此指针,使其指向下一个键。
- void **data:用于存储与遍历到的键相关联的数据的指针的指针。
- uint32_t *next:这是一个用于迭代过程的内部索引。在首次调用时,应将其设置为 0。每次函数被调用时,它都会更新此索引,以便下次调用时从正确的位置开始。
#include <stdio.h>
#include <rte_hash.h>
#define HASH_ENTRIES 1024
int main() {
struct rte_hash *hash_table;
struct rte_hash_parameters hash_params = {
.name = "my_hash_table",
.entries = HASH_ENTRIES,
.key_len = sizeof(uint32_t),
.hash_func = rte_hash_crc,
.hash_func_init_val = 0,
.socket_id = SOCKET_ID_ANY,
};
// 创建哈希表
hash_table = rte_hash_create(&hash_params);
if (hash_table == NULL) {
printf("Failed to create hash table\n");
return -1;
}
// 添加一些键值对到哈希表
uint32_t keys[] = {1, 2, 3, 4, 5};
uint32_t values[] = {10, 20, 30, 40, 50};
for (int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
rte_hash_add_key_data(hash_table, &keys[i], &values[i]);
}
// 遍历哈希表
const void *key;
void *data;
uint32_t next = 0;
int32_t ret;
printf("Hash Table Contents:\n");
while ((ret = rte_hash_iterate(hash_table, &key, &data, &next)) == 0) {
printf("Key: %u, Value: %u\n", *(uint32_t *)key, *(uint32_t *)data);
}
if (ret == -ENOENT) {
printf("End of hash table\n");
} else if (ret < 0) {
printf("Error iterating hash table\n");
}
// 销毁哈希表
rte_hash_free(hash_table);
return 0;
}
2.6 rte_hash_del_key
函数用于从哈希表中删除指定的键,并返回相应的数据
int rte_hash_del_key(struct rte_hash *h, const void *key);
- h:要删除键的哈希表的指针。
- key:要删除的键的指针
函数返回值为0表示成功删除键,负数表示删除失败
#include <rte_hash.h>
#include <stdio.h>
#include <stdint.h>
#define MAX_ENTRIES 1024
int main() {
// 定义哈希表的参数
struct rte_hash_parameters hash_params = {
.name = "example_hash",
.entries = MAX_ENTRIES,
.key_len = sizeof(uint32_t),
.hash_func = rte_jhash,
.hash_func_init_val = 0,
.socket_id = SOCKET_ID_ANY
};
// 创建哈希表
struct rte_hash *hash_table = rte_hash_create(&hash_params);
if (hash_table == NULL) {
printf("Failed to create hash table\n");
return -1;
}
// 向哈希表中添加一些键值对
uint32_t keys[MAX_ENTRIES] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++) {
rte_hash_add_key(hash_table, &keys[i]);
}
// 删除一个键值对
uint32_t delete_key = 2;
int ret = rte_hash_del_key(hash_table, &delete_key);
if (ret == 0) {
printf("Key %u deleted successfully\n", delete_key);
} else {
printf("Failed to delete key %u\n", delete_key);
}
// 尝试查找被删除的键值对并打印结果(应该会失败)
void *lookup_value;
ret = rte_hash_lookup_data(hash_table, &delete_key, &lookup_value);
if (ret == 0) {
printf("Value for key %u is %p\n", delete_key, lookup_value);
} else {
printf("Key %u not found\n", delete_key);
}
// 释放哈希表资源
rte_hash_free(hash_table);
return 0;
}
2.7 rte_hash_reset
函数用于重置哈希表,清除其中所有的键值对
void rte_hash_reset(struct rte_hash *h);
- h:要重置的哈希表的指针
#include <rte_hash.h>
#include <stdio.h>
#include <stdint.h>
#define MAX_ENTRIES 1024
// 定义一个示例的结构体
struct my_struct {
uint32_t id;
char name[20];
};
int main() {
// 定义哈希表的参数
struct rte_hash_parameters hash_params = {
.name = "example_hash",
.entries = MAX_ENTRIES,
.key_len = sizeof(uint32_t),
.hash_func = rte_jhash,
.hash_func_init_val = 0,
.socket_id = SOCKET_ID_ANY
};
// 创建哈希表
struct rte_hash *hash_table = rte_hash_create(&hash_params);
if (hash_table == NULL) {
printf("Failed to create hash table\n");
return -1;
}
// 向哈希表中添加一些键值对
struct my_struct values[MAX_ENTRIES] = {
{1, "Alice"},
{2, "Bob"},
{3, "Charlie"},
{4, "David"},
{5, "Eve"}
};
uint32_t keys[MAX_ENTRIES] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++) {
rte_hash_add_key_data(hash_table, &keys[i], &values[i]);
}
// 打印添加键值对后的哈希表内容
printf("Hash table before reset:\n");
rte_hash_iterate(hash_table, print_entry, NULL);
// 重置哈希表
rte_hash_reset(hash_table);
// 打印重置后的哈希表内容(应该为空)
printf("\nHash table after reset:\n");
rte_hash_iterate(hash_table, print_entry, NULL);
// 释放哈希表资源
rte_hash_free(hash_table);
return 0;
}
2.8 rte_hash_get_stats
函数用于获取哈希表的统计信息,如插入次数、删除次数、碰撞次数等
void rte_hash_get_stats(const struct rte_hash *h, struct rte_hash_stats *stats);
- h:要获取统计信息的哈希表的指针。
- stats:用于存储统计信息的结构体指针。
结构体 rte_hash_stats 包含了哈希表的统计信息,具体如下:
struct rte_hash_stats {
uint64_t inserts; // 插入次数
uint64_t deletes; // 删除次数
uint64_t collisions; // 碰撞次数
uint64_t lookups; // 查找次数
};
#include <rte_hash.h>
#include <stdio.h>
#include <stdint.h>
#define MAX_ENTRIES 1024
// 定义一个示例的结构体
struct my_struct {
uint32_t id;
char name[20];
};
int main() {
// 定义哈希表的参数
struct rte_hash_parameters hash_params = {
.name = "example_hash",
.entries = MAX_ENTRIES,
.key_len = sizeof(uint32_t),
.hash_func = rte_jhash,
.hash_func_init_val = 0,
.socket_id = SOCKET_ID_ANY
};
// 创建哈希表
struct rte_hash *hash_table = rte_hash_create(&hash_params);
if (hash_table == NULL) {
printf("Failed to create hash table\n");
return -1;
}
// 向哈希表中添加一些键值对
struct my_struct values[MAX_ENTRIES] = {
{1, "Alice"},
{2, "Bob"},
{3, "Charlie"},
{4, "David"},
{5, "Eve"}
};
uint32_t keys[MAX_ENTRIES] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++) {
rte_hash_add_key_data(hash_table, &keys[i], &values[i]);
}
// 获取哈希表的统计信息
struct rte_hash_stats stats;
rte_hash_get_stats(hash_table, &stats);
// 打印哈希表的统计信息
printf("Hash table statistics:\n");
printf("Inserts: %lu\n", stats.inserts);
printf("Deletes: %lu\n", stats.deletes);
printf("Collisions: %lu\n", stats.collisions);
printf("Lookups: %lu\n", stats.lookups);
// 释放哈希表资源
rte_hash_free(hash_table);
return 0;
}
2.9 rte_hash_reset_stats
函数用于重置哈希表的统计信息,将所有统计计数器归零
void rte_hash_reset_stats(struct rte_hash *h);
- h:要重置统计信息的哈希表的指针。
#include <rte_hash.h>
#include <stdio.h>
#include <stdint.h>
#define MAX_ENTRIES 1024
// 定义一个示例的结构体
struct my_struct {
uint32_t id;
char name[20];
};
int main() {
// 定义哈希表的参数
struct rte_hash_parameters hash_params = {
.name = "example_hash",
.entries = MAX_ENTRIES,
.key_len = sizeof(uint32_t),
.hash_func = rte_jhash,
.hash_func_init_val = 0,
.socket_id = SOCKET_ID_ANY
};
// 创建哈希表
struct rte_hash *hash_table = rte_hash_create(&hash_params);
if (hash_table == NULL) {
printf("Failed to create hash table\n");
return -1;
}
// 向哈希表中添加一些键值对
struct my_struct values[MAX_ENTRIES] = {
{1, "Alice"},
{2, "Bob"},
{3, "Charlie"},
{4, "David"},
{5, "Eve"}
};
uint32_t keys[MAX_ENTRIES] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++) {
rte_hash_add_key_data(hash_table, &keys[i], &values[i]);
}
// 获取并打印哈希表的统计信息(重置前)
struct rte_hash_stats stats_before;
rte_hash_get_stats(hash_table, &stats_before);
printf("Hash table statistics before reset:\n");
printf("Inserts: %lu\n", stats_before.inserts);
printf("Deletes: %lu\n", stats_before.deletes);
printf("Collisions: %lu\n", stats_before.collisions);
printf("Lookups: %lu\n", stats_before.lookups);
// 重置哈希表的统计信息
rte_hash_reset_stats(hash_table);
// 获取并打印哈希表的统计信息(重置后)
struct rte_hash_stats stats_after;
rte_hash_get_stats(hash_table, &stats_after);
printf("\nHash table statistics after reset:\n");
printf("Inserts: %lu\n", stats_after.inserts);
printf("Deletes: %lu\n", stats_after.deletes);
printf("Collisions: %lu\n", stats_after.collisions);
printf("Lookups: %lu\n", stats_after.lookups);
// 释放哈希表资源
rte_hash_free(hash_table);
return 0;
}
2.10 rte_hash_lookup_bulk
函数用于批量查找哈希表中的键对应的值
void rte_hash_lookup_bulk(const struct rte_hash *h, const void **keys, uint32_t num_keys, int32_t *positions);
- h:要查找的哈希表的指针。
- keys:一个包含要查找的键的指针数组。
- num_keys:要查找的键的数量。
- positions:一个用于存储查找结果的数组。每个位置的值表示对应键的查找结果:如果键存在,则为其在哈希表中的位置索引(非负数);如果键不存在,则为-1。
#include <rte_hash.h>
#include <stdio.h>
#include <stdint.h>
#define MAX_ENTRIES 1024
int main() {
// 定义哈希表的参数
struct rte_hash_parameters hash_params = {
.name = "example_hash",
.entries = MAX_ENTRIES,
.key_len = sizeof(uint32_t),
.hash_func = rte_jhash,
.hash_func_init_val = 0,
.socket_id = SOCKET_ID_ANY
};
// 创建哈希表
struct rte_hash *hash_table = rte_hash_create(&hash_params);
if (hash_table == NULL) {
printf("Failed to create hash table\n");
return -1;
}
// 向哈希表中添加一些键值对
uint32_t keys[MAX_ENTRIES] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++) {
rte_hash_add_key(hash_table, &keys[i]);
}
// 批量查找键值对并打印结果
const void *lookup_keys[3] = {&keys[0], &keys[2], &keys[4]};
int32_t positions[3];
rte_hash_lookup_bulk(hash_table, lookup_keys, 3, positions);
printf("Results of bulk lookup:\n");
for (int i = 0; i < 3; i++) {
if (positions[i] >= 0) {
printf("Key %u found at position %d\n", *((uint32_t *)lookup_keys[i]), positions[i]);
} else {
printf("Key %u not found\n", *((uint32_t *)lookup_keys[i]));
}
}
// 释放哈希表资源
rte_hash_free(hash_table);
return 0;
}
2.11 rte_hash_add_key
函数用于向哈希表中添加一个键
int rte_hash_add_key(struct rte_hash *h, const void *key);
- h:要添加键的哈希表的指针。
- key:要添加的键的指针
函数返回值为0表示成功添加键,负数表示添加失败
在一些情况下,我们可能只关心键而不关心对应的值,这时就只添加键而不添加对应的数据。以下是一些可能出现这种情况的情景:
集合操作:
如果我们只关心某个数据是否存在于集合中,而不需要具体的值,可以使用哈希表来表示集合,只需将数据的键添加到哈希表中即可。
去重操作:
当我们需要对一组数据进行去重操作时,可以使用哈希表。只需将每个数据作为键添加到哈希表中,重复的数据会被自动去重。
标记存在性:
在一些算法中,可能只需要记录某些数据是否存在,而不需要具体的值。这时可以使用哈希表来记录数据的存在性,只需将数据的键添加到哈希表中,不需要关联具体的值。
#include <rte_hash.h>
#include <stdio.h>
#include <stdint.h>
#define MAX_ENTRIES 1024
int main() {
// 定义哈希表的参数
struct rte_hash_parameters hash_params = {
.name = "example_hash",
.entries = MAX_ENTRIES,
.key_len = sizeof(uint32_t),
.hash_func = rte_jhash,
.hash_func_init_val = 0,
.socket_id = SOCKET_ID_ANY
};
// 创建哈希表
struct rte_hash *hash_table = rte_hash_create(&hash_params);
if (hash_table == NULL) {
printf("Failed to create hash table\n");
return -1;
}
// 向哈希表中添加一个键
uint32_t key = 1;
int ret = rte_hash_add_key(hash_table, &key);
if (ret == 0) {
printf("Key %u added successfully\n", key);
} else {
printf("Failed to add key %u\n", key);
}
// 尝试添加重复的键
ret = rte_hash_add_key(hash_table, &key);
if (ret == 0) {
printf("Key %u added successfully (again)\n", key);
} else {
printf("Failed to add key %u (again)\n", key);
}
// 释放哈希表资源
rte_hash_free(hash_table);
return 0;
}
librte_net
关键结构体:
/**
* 以太网设备信息
*/
/**
* 用于检索以太网设备的上下文信息的结构体,
* 如设备的控制驱动程序等...
*/
struct rte_eth_dev_info {
struct rte_device *device; /**< 通用设备信息 */
const char *driver_name; /**< 设备驱动程序名称 */
unsigned int if_index; /**< 绑定的主机接口索引,如果没有绑定则为0。
可以使用 if_indextoname() 函数将其转换为接口名称。 */
uint16_t min_mtu; /**< 允许的最小 MTU */
uint16_t max_mtu; /**< 允许的最大 MTU */
const uint32_t *dev_flags; /**< 设备标志 */
uint32_t min_rx_bufsize; /**< RX 缓冲区的最小大小 */
uint32_t max_rx_pktlen; /**< 可配置的最大 RX 包长度 */
/** LRO 聚合包的最大可配置大小 */
uint32_t max_lro_pkt_size;
uint16_t max_rx_queues; /**< 最大 RX 队列数 */
uint16_t max_tx_queues; /**< 最大 TX 队列数 */
uint32_t max_mac_addrs; /**< 最大 MAC 地址数 */
/** 用于 MTA 和 UTA 的最大哈希 MAC 地址数 */
uint32_t max_hash_mac_addrs;
uint16_t max_vfs; /**< 最大 VF 数 */
uint16_t max_vmdq_pools; /**< 最大 VMDq 池数 */
uint64_t rx_offload_capa;
/**< 所有 RX 卸载功能,包括所有每队列的功能 */
uint64_t tx_offload_capa;
/**< 所有 TX 卸载功能,包括所有每队列的功能 */
uint64_t rx_queue_offload_capa;
/**< 设备每队列 RX 卸载功能 */
uint64_t tx_queue_offload_capa;
/**< 设备每队列 TX 卸载功能 */
uint16_t reta_size;
/**< 设备重定向表大小,总条目数 */
uint8_t hash_key_size; /**< 哈希键大小(字节) */
/** RSS 卸载的位掩码,位偏移也表示流类型 */
uint64_t flow_type_rss_offloads;
struct rte_eth_rxconf default_rxconf; /**< 默认 RX 配置 */
struct rte_eth_txconf default_txconf; /**< 默认 TX 配置 */
uint16_t vmdq_queue_base; /**< VMDq 池的第一个队列 ID */
uint16_t vmdq_queue_num; /**< VMDq 池的队列数 */
uint16_t vmdq_pool_base; /**< VMDq 池的第一个 ID */
struct rte_eth_desc_lim rx_desc_lim; /**< RX 描述符限制 */
struct rte_eth_desc_lim tx_desc_lim; /**< TX 描述符限制 */
uint32_t speed_capa; /**< 支持的速度位图(ETH_LINK_SPEED_)。 */
/** 配置的 rx/tx 队列数 */
uint16_t nb_rx_queues; /**< RX 队列数 */
uint16_t nb_tx_queues; /**< TX 队列数 */
/** RX 参数建议 */
struct rte_eth_dev_portconf default_rxportconf;
/** TX 参数建议 */
struct rte_eth_dev_portconf default_txportconf;
/** 通用设备功能(RTE_ETH_DEV_CAPA_)。 */
uint64_t dev_capa;
/**
* 在具有嵌入式托管互连/交换的设备上,
* 用于端口的交换信息。
*/
struct rte_eth_switch_info switch_info;
uint64_t reserved_64s[2]; /**< 保留字段,用于未来扩展 */
void *reserved_ptrs[2]; /**< 保留字段,用于未来扩展 */
};
3.1 rte_eth_promiscuous_disable
函数用于禁用指定网络设备的混杂模式。混杂模式允许网络接口接收其不是直接发送给它的数据包,这对于网络监控和数据包分析等应用非常有用。
void rte_eth_promiscuous_disable(uint16_t port_id);
- port_id:网络设备的端口 ID。
#include <rte_ethdev.h>
#include <stdio.h>
int main() {
// 假设要禁用的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 禁用指定网络设备的混杂模式
rte_eth_promiscuous_disable(port_id);
// 打印结果
printf("Port %u promiscuous mode disabled.\n", port_id);
return 0;
}
3.2 rte_eth_dev_configure
函数用于配置指定网络设备的端口,包括设置接收和发送队列的数量以及配置设备的其他参数
int rte_eth_dev_configure(uint16_t port_id, uint16_t nb_rx_queue, uint16_t nb_tx_queue, const struct rte_eth_conf *eth_conf);
- port_id:网络设备的端口 ID。
- nb_rx_queue:接收队列的数量。
- nb_tx_queue:发送队列的数量。
- eth_conf:指向rte_eth_conf结构的指针,包含了要应用的网络设备配置。
#include <stdio.h>
#include <rte_ethdev.h>
int main() {
// 假设要配置的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 假设要配置的接收队列和发送队列的数量分别为 2
uint16_t nb_rx_queue = 2;
uint16_t nb_tx_queue = 2;
// 配置网络设备的端口
struct rte_eth_conf eth_conf;
int ret = rte_eth_dev_configure(port_id, nb_rx_queue, nb_tx_queue, ð_conf);
// 打印结果
if (ret == 0) {
printf("Port %u configured successfully.\n", port_id);
} else {
printf("Failed to configure port %u.\n", port_id);
}
return 0;
}
3.3 rte_eth_rx_queue_setup
函数用于配置网络设备的接收队列。接收队列是用来接收网络数据包的缓冲区,配置接收队列可以指定接收队列的参数,例如描述符数量、队列深度等
int rte_eth_rx_queue_setup(uint16_t port_id, uint16_t rx_queue_id,
uint16_t nb_rx_desc, )
port_id
:网络设备的端口idrx_queue_id
:接收队列的队列idnb_rx_desv
:接收队列的描述符数量,接收队列的描述符数量决定了队列能够同时处理的数据包数量。socket_id
:指定用于内存分配的UNMA节点的IDrx_conf
:接收队列的配置参数,是一个指向rte_eth_rxconf结构的指针mb_pool
:用于存储接受数据包的内存池
#include <stdio.h>
#include <rte_ethdev.h>
int main() {
// 假设要配置的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 假设要配置的接收队列的队列 ID 为 0
uint16_t rx_queue_id = 0;
// 假设要配置的接收队列的描述符数量为 128
uint16_t nb_rx_desc = 128;
// 假设要指定的 NUMA 节点的 ID 为 0
unsigned int socket_id = 0;
// 假设使用默认的接收队列配置
struct rte_eth_rxconf rx_conf = rte_eth_rxconf_default;
// 假设已经创建了一个内存池 mb_pool 来存储接收数据包
struct rte_mempool *mb_pool;
// 配置接收队列
int ret = rte_eth_rx_queue_setup(port_id, rx_queue_id, nb_rx_desc, socket_id, &rx_conf, mb_pool);
// 打印配置结果
if (ret == 0) {
printf("RX queue %u for port %u configured successfully.\n", rx_queue_id, port_id);
} else {
printf("Failed to configure RX queue %u for port %u.\n", rx_queue_id, port_id);
return ret;
}
return 0;
}
3.4 rte_eth_tx_queue_setup
函数用于配置网络设备的发送队列。发送队列用于发送数据包,配置发送队列可以指定发送队列的参数,例如描述符数量、队列深度等
int rte_eth_tx_queue_setup(uint16_t port_id, uint16_t tx_queue_id,
uint16_t nb_tx_desc, unsigned int socket_id,
const struct rte_eth_txconf *tx_conf);
- port_id:网络设备的端口 ID。
- tx_queue_id:发送队列的队列 ID。
- nb_tx_desc:发送队列的描述符数量。
- socket_id:指定用于内存分配的 NUMA 节点的 ID。
- tx_conf:发送队列的配置参数,是一个指向rte_eth_txconf结构的指针。
#include <stdio.h>
#include <rte_ethdev.h>
int main() {
// 假设要配置的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 假设要配置的发送队列的队列 ID 为 0
uint16_t tx_queue_id = 0;
// 假设要配置的发送队列的描述符数量为 128
uint16_t nb_tx_desc = 128;
// 假设要指定的 NUMA 节点的 ID 为 0
unsigned int socket_id = 0;
// 假设使用默认的发送队列配置
struct rte_eth_txconf tx_conf = rte_eth_txconf_default;
// 配置发送队列
int ret = rte_eth_tx_queue_setup(port_id, tx_queue_id, nb_tx_desc, socket_id, &tx_conf);
// 打印配置结果
if (ret == 0) {
printf("TX queue %u for port %u configured successfully.\n", tx_queue_id, port_id);
} else {
printf("Failed to configure TX queue %u for port %u.\n", tx_queue_id, port_id);
return ret;
}
return 0;
}
3.5 rte_eth_dev_start
函数用于启动指定端口的以太网设备。启动以太网设备后,它将开始接收和发送数据包
int rte_eth_dev_start(uint16_t port_id);
- port_id:网络设备的端口 ID
#include <stdio.h>
#include <rte_ethdev.h>
int main() {
// 假设要启动的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 启动网络设备
int ret = rte_eth_dev_start(port_id);
// 打印启动结果
if (ret == 0) {
printf("Ethernet device on port %u started successfully.\n", port_id);
} else {
printf("Failed to start Ethernet device on port %u.\n", port_id);
return ret;
}
return 0;
}
3.6 rte_eth_promiscuous_enable
函数用于启用指定端口的以太网设备的混杂模式。在混杂模式下,网络接口会接收通过网络上的所有数据包,而不仅仅是发送给它的数据包。这对于网络流量监控、数据包捕获和分析等场景非常有用
void rte_eth_promiscuous_enable(uint16_t port_id);
- port_id:网络设备的端口 ID。
#include <stdio.h>
#include <rte_ethdev.h>
int main() {
// 假设要启用混杂模式的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 启用混杂模式
rte_eth_promiscuous_enable(port_id);
// 打印结果
printf("Ethernet device on port %u is now in promiscuous mode.\n", port_id);
return 0;
}
3.7 rte_eth_dev_stop
函数用于停止指定端口的以太网设备,即暂停其接收和发送数据包的功能
void rte_eth_dev_stop(uint16_t port_id);
- port_id:网络设备的端口 ID。
#include <stdio.h>
#include <rte_ethdev.h>
int main() {
// 假设要停止的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 停止网络设备
rte_eth_dev_stop(port_id);
// 打印结果
printf("Ethernet device on port %u stopped.\n", port_id);
return 0;
}
3.8 rte_eth_dev_close
函数用于关闭指定端口的以太网设备,释放其资源并清理相关状态。关闭网络设备后,该设备将不再可用
void rte_eth_dev_close(uint16_t port_id);
- port_id:网络设备的端口 ID
#include <stdio.h>
#include <rte_ethdev.h>
int main() {
// 假设要关闭的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 关闭网络设备
rte_eth_dev_close(port_id);
// 打印结果
printf("Ethernet device on port %u closed.\n", port_id);
return 0;
}
3.9 rte_eth_stats_get
函数用于获取指定端口的以太网设备的统计信息,包括接收和发送的数据包数量、错误计数等
void rte_eth_stats_get(uint16_t port_id, struct rte_eth_stats *stats);
- port_id:网络设备的端口 ID。
- stats:用于存储获取到的统计信息的结构体指针,类型为struct rte_eth_stats。
#include <stdio.h>
#include <rte_ethdev.h>
int main() {
// 假设要获取统计信息的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 创建一个结构体来存储统计信息
struct rte_eth_stats stats;
// 获取指定端口的以太网设备的统计信息
rte_eth_stats_get(port_id, &stats);
// 打印获取到的统计信息
printf("Statistics for Ethernet device on port %u:\n", port_id);
printf(" - Received packets: %lu\n", stats.ipackets);
printf(" - Sent packets: %lu\n", stats.opackets);
printf(" - Received packet errors: %lu\n", stats.ierrors);
printf(" - Sent packet errors: %lu\n", stats.oerrors);
// 其他统计信息的打印...
return 0;
}
3.10 rte_eth_link_get
函数用于获取指定端口的以太网设备的链路状态信息,包括连接速率、双工模式、链路状态等。这些信息对于监控网络设备的连接状态和性能非常重要。
int rte_eth_link_get(uint16_t port_id, struct rte_eth_link *link);
- port_id:网络设备的端口 ID。
- link:用于存储获取到的链路状态信息的结构体指针,类型为struct rte_eth_link。
#include <stdio.h>
#include <rte_ethdev.h>
int main() {
// 假设要获取链路状态信息的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 创建一个结构体来存储链路状态信息
struct rte_eth_link link;
// 获取指定端口的以太网设备的链路状态信息
int ret = rte_eth_link_get(port_id, &link);
// 打印获取到的链路状态信息
if (ret == 0) {
printf("Link status for Ethernet device on port %u:\n", port_id);
printf(" - Link speed: %u Mbps\n", link.link_speed);
printf(" - Link duplex mode: %s\n", (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? "Full duplex" : "Half duplex");
printf(" - Link status: %s\n", (link.link_status == ETH_LINK_UP) ? "Up" : "Down");
} else {
printf("Failed to get link status for Ethernet device on port %u.\n", port_id);
return ret;
}
return 0;
}
3.11 rte_eth_dev_info_get
函数用于获取指定端口的以太网设备的设备信息,包括设备支持的特性、队列配置、设备类型等
void rte_eth_dev_info_get(uint16_t port_id, struct rte_eth_dev_info *dev_info);
- port_id:网络设备的端口 ID。
- dev_info:用于存储获取到的设备信息的结构体指针,类型为struct rte_eth_dev_info。
#include <stdio.h>
#include <rte_ethdev.h>
// 定义一个函数,用于打印设备信息
void print_dev_info(const struct rte_eth_dev_info *dev_info) {
printf("Device information:\n");
printf(" - Driver name: %s\n", dev_info->driver_name);
printf(" - Maximum number of queues: %u\n", dev_info->max_rx_queues);
printf(" - Maximum number of TX queues: %u\n", dev_info->max_tx_queues);
printf(" - Maximum number of MAC addresses: %u\n", dev_info->max_mac_addrs);
// 其他设备信息的打印...
}
int main() {
// 假设要获取设备信息的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 创建一个结构体来存储设备信息
struct rte_eth_dev_info dev_info;
// 获取指定端口的以太网设备的设备信息
rte_eth_dev_info_get(port_id, &dev_info);
// 打印获取到的设备信息
print_dev_info(&dev_info);
return 0;
}
3.12 rte_eth_dev_set_mtu
函数用于设置指定端口的以太网设备的最大传输单元(MTU)。MTU 是网络中可以传输的最大数据包的大小,通过设置 MTU,可以控制数据包的大小,从而影响网络的性能和效率
int rte_eth_dev_set_mtu(uint16_t port_id, uint16_t mtu);
- port_id:网络设备的端口 ID。
- mtu:要设置的最大传输单元大小,以字节为单位。
#include <stdio.h>
#include <rte_ethdev.h>
int main() {
// 假设要设置 MTU 的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 要设置的 MTU 大小
uint16_t mtu = 1500;
// 设置指定端口的以太网设备的 MTU
int ret = rte_eth_dev_set_mtu(port_id, mtu);
// 打印设置结果
if (ret == 0) {
printf("Successfully set MTU for Ethernet device on port %u to %u bytes.\n", port_id, mtu);
} else {
printf("Failed to set MTU for Ethernet device on port %u.\n", port_id);
return ret;
}
return 0;
}
3.13 rte_eth_dev_set_rx_callback
函数用于设置指定端口的以太网设备的接收数据包回调函数。当网络设备接收到数据包时,将调用注册的回调函数来处理接收到的数据包。这样的回调函数可以用于实现自定义的数据包处理逻辑,例如数据包分析、过滤、修改等。
int rte_eth_dev_set_rx_callback(uint16_t port_id,
rte_rx_callback_fn rx_cb,
void *callback_arg);
- port_id:网络设备的端口 ID。
- rx_cb:指向回调函数的指针,用于处理接收到的数据包。
- callback_arg:回调函数的参数,将传递给回调函数。
#include <stdio.h>
#include <rte_ethdev.h>
// 自定义的回调函数,用于处理接收到的数据包
static uint16_t rx_callback(uint16_t port_id, uint16_t queue_id,
struct rte_mbuf *pkts[], uint16_t nb_pkts,
void *user_param) {
printf("Received %u packets on port %u, queue %u.\n", nb_pkts, port_id, queue_id);
// 在这里可以添加自定义的数据包处理逻辑
return nb_pkts;
}
int main() {
// 假设要设置回调函数的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 设置指定端口的以太网设备的接收数据包回调函数
int ret = rte_eth_dev_set_rx_callback(port_id, rx_callback, NULL);
// 打印设置结果
if (ret == 0) {
printf("Successfully set RX callback function for Ethernet device on port %u.\n", port_id);
} else {
printf("Failed to set RX callback function for Ethernet device on port %u.\n", port_id);
return ret;
}
// 在这里可以启动接收数据包的处理过程
return 0;
}
3.14 rte_eth_dev_set_tx_callback
函数用于设置指定端口的以太网设备的发送数据包回调函数。当应用程序尝试发送数据包时,将调用注册的回调函数来处理要发送的数据包。这样的回调函数可以用于实现自定义的数据包发送逻辑,例如数据包修改、加密、压缩等。
- port_id:网络设备的端口 ID。
- tx_cb:指向回调函数的指针,用于处理要发送的数据包。
- callback_arg:回调函数的参数,将传递给回调函数
#include <stdio.h>
#include <rte_ethdev.h>
// 自定义的回调函数,用于处理要发送的数据包
static uint16_t tx_callback(uint16_t port_id, uint16_t queue_id,
struct rte_mbuf *pkts[], uint16_t nb_pkts,
void *user_param) {
printf("Trying to send %u packets on port %u, queue %u.\n", nb_pkts, port_id, queue_id);
// 在这里可以添加自定义的数据包发送逻辑
// 模拟成功发送所有数据包
return nb_pkts;
}
int main() {
// 假设要设置回调函数的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 设置指定端口的以太网设备的发送数据包回调函数
int ret = rte_eth_dev_set_tx_callback(port_id, tx_callback, NULL);
// 打印设置结果
if (ret == 0) {
printf("Successfully set TX callback function for Ethernet device on port %u.\n", port_id);
} else {
printf("Failed to set TX callback function for Ethernet device on port %u.\n", port_id);
return ret;
}
// 在这里可以启动发送数据包的处理过程
return 0;
}
3.15 rte_eth_dev_set_ptypes
函数用于设置指定端口的以太网设备的数据包类型(Packet Types)。数据包类型是指数据包的协议类型,例如以太网、IP、TCP、UDP等。通过设置数据包类型,可以告诉硬件如何解析数据包的各个字段,并提供更加精细的数据包处理能力。
int rte_eth_dev_set_ptypes(uint16_t port_id, uint32_t ptype_mask);
- port_id:网络设备的端口 ID。
- ptype_mask:要设置的数据包类型掩码,指定了需要解析的数据包类型
#include <stdio.h>
#include <rte_ethdev.h>
// 定义数据包处理函数,用于处理接收到的数据包
void process_packet(struct rte_mbuf *pkt) {
printf("Received a packet with type 0x%X\n", pkt->packet_type);
// 在这里添加处理数据包的逻辑
}
int main() {
// 假设要设置数据包类型的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 要设置的数据包类型掩码,这里假设要解析以太网、IPv4、IPv6和TCP数据包
uint32_t ptype_mask = RTE_PTYPE_L2_ETHER |
RTE_PTYPE_L3_IPV4 |
RTE_PTYPE_L3_IPV6 |
RTE_PTYPE_L4_TCP;
// 设置指定端口的以太网设备的数据包类型
int ret = rte_eth_dev_set_ptypes(port_id, ptype_mask);
if (ret != 0) {
printf("Failed to set packet types for Ethernet device on port %u.\n", port_id);
return ret;
}
// 在这里开始接收数据包
struct rte_mbuf *pkts[32];
uint16_t nb_rx;
while (1) {
// 从端口接收数据包
nb_rx = rte_eth_rx_burst(port_id, 0, pkts, 32);
if (nb_rx == 0) {
continue;
}
// 处理接收到的数据包
for (uint16_t i = 0; i < nb_rx; ++i) {
if (pkts[i]->packet_type & ptype_mask) {
// 如果数据包类型符合设置的掩码,则进行处理
process_packet(pkts[i]);
} else {
// 如果数据包类型不符合设置的掩码,则丢弃该数据包
rte_pktmbuf_free(pkts[i]);
}
}
}
return 0;
}
3.16 rte_eth_rx_burst
函数用于从指定的以太网设备接收数据包,它会将接收到的数据包存储在预先分配的数据包缓冲区中,并返回实际接收到的数据包数量。
#include <stdio.h>
#include <rte_ethdev.h>
/**
* 从指定端口接收数据包
*
* @param port_id 网络设备的端口 ID。
* @param queue_id 网络设备的队列 ID,用于多队列接收情况下指定接收队列,一般为0。
* @param rx_pkts 用于存储接收到的数据包的指针数组,数组大小至少为 nb_pkts。
* @param nb_pkts 期望接收的数据包数量,即 rx_pkts 数组的大小。
* @return 实际接收到的数据包数量。
*/
uint16_t rte_eth_rx_burst(uint16_t port_id,
uint16_t queue_id,
struct rte_mbuf **rx_pkts,
const uint16_t nb_pkts);
int main() {
// 假设要接收数据包的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 每次接收的数据包数量
const uint16_t nb_pkts = 32;
// 用于存储接收到的数据包的指针数组
struct rte_mbuf *rx_pkts[nb_pkts];
// 实际接收到的数据包数量
uint16_t nb_rx;
// 从指定端口接收数据包
nb_rx = rte_eth_rx_burst(port_id, 0, rx_pkts, nb_pkts);
if (nb_rx == 0) {
printf("No packets received on port %u.\n", port_id);
return 0;
}
// 打印接收到的数据包信息
printf("Received %u packets on port %u:\n", nb_rx, port_id);
for (uint16_t i = 0; i < nb_rx; ++i) {
printf("Packet %u: Length = %u bytes\n", i + 1, rte_pktmbuf_pkt_len(rx_pkts[i]));
// 这里可以添加更多的数据包信息打印
}
// 在这里可以继续处理接收到的数据包
return 0;
}
3.17 rte_eth_tx_burst
函数用于向指定的以太网设备发送数据包,它会将预先存储在数据包缓冲区中的数据包发送出去,并返回实际发送的数据包数量。
#include <stdio.h>
#include <rte_ethdev.h>
/**
* 向指定端口发送数据包
*
* @param port_id 网络设备的端口 ID。
* @param queue_id 网络设备的队列 ID,用于多队列发送情况下指定发送队列,一般为0。
* @param tx_pkts 存储待发送的数据包的指针数组。
* @param nb_pkts 待发送的数据包数量,即 tx_pkts 数组中待发送数据包的数量。
* @return 实际发送的数据包数量。
*/
uint16_t rte_eth_tx_burst(uint16_t port_id,
uint16_t queue_id,
struct rte_mbuf **tx_pkts,
uint16_t nb_pkts);
int main() {
// 假设要发送数据包的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 每次发送的数据包数量
const uint16_t nb_pkts = 32;
// 用于存储待发送的数据包的指针数组
struct rte_mbuf *tx_pkts[nb_pkts];
// 实际发送的数据包数量
uint16_t nb_tx;
// 在这里填充待发送的数据包到 tx_pkts 数组中
// 向指定端口发送数据包
nb_tx = rte_eth_tx_burst(port_id, 0, tx_pkts, nb_pkts);
if (nb_tx == 0) {
printf("No packets sent on port %u.\n", port_id);
return 0;
}
// 打印发送的数据包信息
printf("Sent %u packets on port %u:\n", nb_tx, port_id);
for (uint16_t i = 0; i < nb_tx; ++i) {
printf("Packet %u: Length = %u bytes\n", i + 1, rte_pktmbuf_pkt_len(tx_pkts[i]));
// 这里可以添加更多的数据包信息打印
}
// 在这里可以继续处理发送的数据包
return 0;
}
3.18 rte_eth_rx_queue_count
#include <stdio.h>
#include <rte_ethdev.h>
/**
* 获取指定端口指定队列中当前排队的数据包数量
*
* @param port_id 网络设备的端口 ID。
* @param queue_id 网络设备的队列 ID,用于多队列接收情况下指定接收队列。
* @return 当前排队的数据包数量。
*/
uint16_t rte_eth_rx_queue_count(uint16_t port_id, uint16_t queue_id);
int main() {
// 假设要查询的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 假设要查询的接收队列的队列 ID 为 0
uint16_t queue_id = 0;
// 获取指定端口指定队列中当前排队的数据包数量
uint16_t pkt_count = rte_eth_rx_queue_count(port_id, queue_id);
// 打印结果
printf("Number of packets queued in port %u, queue %u: %u\n", port_id, queue_id, pkt_count);
return 0;
}
3.19 rte_eth_tx_queue_count
获取指定端口指定队列中当前排队的数据包数量
#include <stdio.h>
#include <rte_ethdev.h>
/**
* 获取指定端口指定队列中当前排队的数据包数量
*
* @param port_id 网络设备的端口 ID。
* @param queue_id 网络设备的队列 ID,用于多队列发送情况下指定发送队列。
* @return 当前排队的数据包数量。
*/
uint16_t rte_eth_tx_queue_count(uint16_t port_id, uint16_t queue_id);
int main() {
// 假设要查询的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 假设要查询的发送队列的队列 ID 为 0
uint16_t queue_id = 0;
// 获取指定端口指定队列中当前排队的数据包数量
uint16_t pkt_count = rte_eth_tx_queue_count(port_id, queue_id);
// 打印结果
printf("Number of packets queued in port %u, queue %u: %u\n", port_id, queue_id, pkt_count);
return 0;
}
3.20 rte_eth_dev_get_port_by_name
通过设备名称获取对应的端口 ID
#include <stdio.h>
#include <string.h>
#include <rte_ethdev.h>
/**
* 通过设备名称获取对应的端口 ID
*
* @param name 网络设备的名称。
* @param port_id 存储获取到的端口 ID 的指针。
* @return 0 表示成功获取到端口 ID,负值表示失败。
*/
int rte_eth_dev_get_port_by_name(const char *name, uint16_t *port_id);
int main() {
// 假设要查询的网络设备的名称为 "eth0"
const char *dev_name = "eth0";
// 存储获取到的端口 ID
uint16_t port_id;
// 通过设备名称获取对应的端口 ID
int ret = rte_eth_dev_get_port_by_name(dev_name, &port_id);
if (ret == 0) {
// 打印结果
printf("Port ID for device %s is %u\n", dev_name, port_id);
} else {
printf("Failed to get port ID for device %s\n", dev_name);
}
return 0;
}
3.21 rte_eth_dev_count_total
获取系统中总共的以太网设备数量
#include <stdio.h>
#include <rte_ethdev.h>
/**
* 获取系统中总共的以太网设备数量
*
* @return 总共的以太网设备数量。
*/
uint16_t rte_eth_dev_count_total(void);
int main() {
// 获取系统中总共的以太网设备数量
uint16_t total_count = rte_eth_dev_count_total();
// 打印结果
printf("Total number of Ethernet devices in the system: %u\n", total_count);
return 0;
}
3.22 rte_eth_dev_count_avail
获取系统中可用的以太网设备数量
#include <stdio.h>
#include <rte_ethdev.h>
/**
* 获取系统中可用的以太网设备数量
*
* @return 可用的以太网设备数量。
*/
uint16_t rte_eth_dev_count_avail(void);
int main() {
// 获取系统中可用的以太网设备数量
uint16_t avail_count = rte_eth_dev_count_avail();
// 打印结果
printf("Number of available Ethernet devices in the system: %u\n", avail_count);
return 0;
}
3.23 rte_eth_dev_get_name_by_port
通过端口 ID 获取对应的设备名称
#include <stdio.h>
#include <rte_ethdev.h>
/**
* 通过端口 ID 获取对应的设备名称
*
* @param port_id 网络设备的端口 ID。
* @param name 存储获取到的设备名称的指针。
* @return 0 表示成功获取到设备名称,负值表示失败。
*/
int rte_eth_dev_get_name_by_port(uint16_t port_id, const char **name);
int main() {
// 假设要查询的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 存储获取到的设备名称
const char *dev_name;
// 通过端口 ID 获取对应的设备名称
int ret = rte_eth_dev_get_name_by_port(port_id, &dev_name);
if (ret == 0) {
// 打印结果
printf("Device name for port %u is %s\n", port_id, dev_name);
} else {
printf("Failed to get device name for port %u\n", port_id);
}
return 0;
}
3.24 rte_eth_dev_socket_id
获取指定以太网设备所在的 NUMA 节点的编号
#include <stdio.h>
#include <rte_ethdev.h>
/**
* 获取指定以太网设备所在的 NUMA 节点的编号
*
* @param port_id 网络设备的端口 ID。
* @return 设备所在的 NUMA 节点的编号,-1 表示失败。
*/
int rte_eth_dev_socket_id(uint16_t port_id);
int main() {
// 假设要查询的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 获取指定以太网设备所在的 NUMA 节点的编号
int socket_id = rte_eth_dev_socket_id(port_id);
if (socket_id >= 0) {
// 打印结果
printf("Socket ID for port %u is %d\n", port_id, socket_id);
} else {
printf("Failed to get socket ID for port %u\n", port_id);
}
return 0;
}
3.25 rte_eth_dev_filter_supported
检查指定以太网设备是否支持特定类型的过滤器
#include <stdio.h>
#include <rte_ethdev.h>
/**
* 检查指定以太网设备是否支持特定类型的过滤器
*
* @param port_id 网络设备的端口 ID。
* @param filter_type 要检查的过滤器类型。
* @return 1 表示设备支持该类型的过滤器,0 表示设备不支持,负值表示出错。
*/
int rte_eth_dev_filter_supported(uint16_t port_id, enum rte_filter_type filter_type);
int main() {
// 假设要查询的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 假设要检查的过滤器类型为 MACVLAN
enum rte_filter_type filter_type = RTE_ETH_FILTER_MACVLAN;
// 检查指定以太网设备是否支持特定类型的过滤器
int supported = rte_eth_dev_filter_supported(port_id, filter_type);
if (supported == 1) {
// 打印结果
printf("Port %u supports MACVLAN filter\n", port_id);
} else if (supported == 0) {
printf("Port %u does not support MACVLAN filter\n", port_id);
} else {
printf("Failed to check filter support for port %u\n", port_id);
}
return 0;
}
过滤器类型:
RTE_ETH_FILTER_NONE
:表示不使用任何过滤器。
RTE_ETH_FILTER_MACVLAN
:表示 MACVLAN 过滤器,用于过滤基于 MAC 地址和 VLAN ID 的数据包。
RTE_ETH_FILTER_VLAN
:表示 VLAN 过滤器,用于过滤基于 VLAN ID 的数据包。
RTE_ETH_FILTER_FDIR
:表示流量识别过滤器,用于流量识别和流量分类。
RTE_ETH_FILTER_HASH
:表示哈希过滤器,用于基于哈希值的流量分类。
RTE_ETH_FILTER_L2_TUNNEL
:表示 L2 隧道过滤器,用于 L2 隧道流量过滤。
RTE_ETH_FILTER_FLEXIBLE
:表示灵活过滤器,用于自定义的灵活过滤器匹配规则。
RTE_ETH_FILTER_SYN
:表示 SYN 过滤器,用于过滤 TCP SYN 数据包
3.26 rte_eth_dev_filter_ctrl
控制以太网设备的过滤器
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <rte_ethdev.h>
/**
* 控制以太网设备的过滤器
*
* @param port_id 网络设备的端口 ID。
* @param filter_type 过滤器类型。
* @param filter_op 过滤器操作。
* @param arg 过滤器操作参数。
* @return 0 表示成功执行过滤器操作,负值表示失败。
*/
int rte_eth_dev_filter_ctrl(uint16_t port_id, enum rte_filter_type filter_type,
enum rte_filter_op filter_op, void *arg);
int main() {
// 假设要控制的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 假设要控制的过滤器类型为 MACVLAN
enum rte_filter_type filter_type = RTE_ETH_FILTER_MACVLAN;
// 假设要执行的过滤器操作为设置过滤器
enum rte_filter_op filter_op = RTE_ETH_FILTER_ADD;
// 假设要设置的过滤器参数
// 示例参数:MAC地址为 01:23:45:67:89:ab,VLAN ID为100
struct rte_eth_macvlan_filter_conf filter_conf;
memset(&filter_conf, 0, sizeof(filter_conf));
filter_conf.mac_addr.addr_bytes[0] = 0x01;
filter_conf.mac_addr.addr_bytes[1] = 0x23;
filter_conf.mac_addr.addr_bytes[2] = 0x45;
filter_conf.mac_addr.addr_bytes[3] = 0x67;
filter_conf.mac_addr.addr_bytes[4] = 0x89;
filter_conf.mac_addr.addr_bytes[5] = 0xab;
filter_conf.vlan_id = 100;
// 控制以太网设备的过滤器
int ret = rte_eth_dev_filter_ctrl(port_id, filter_type, filter_op, &filter_conf);
if (ret == 0) {
// 打印结果
printf("Successfully set MACVLAN filter on port %u\n", port_id);
} else {
printf("Failed to set MACVLAN filter on port %u\n", port_id);
}
return 0;
}
3.27 rte_eth_add_rx_callback
向以太网设备添加接收回调函数
#include <stdio.h>
#include <stdint.h>
#include <rte_ethdev.h>
// 定义接收回调函数的原型
typedef void (*rx_callback_fn)(uint16_t port_id, uint16_t queue_id, struct rte_mbuf *pkts[], uint16_t nb_pkts, void *user_param);
/**
* 向以太网设备添加接收回调函数
*
* @param port_id 网络设备的端口 ID。
* @param queue_id 接收队列的队列 ID。
* @param callback_fn 接收回调函数的指针。
* @param user_param 用户参数,传递给接收回调函数。
* @return 0 表示成功添加接收回调函数,负值表示失败。
*/
int rte_eth_add_rx_callback(uint16_t port_id, uint16_t queue_id, rx_callback_fn callback_fn, void *user_param);
// 示例接收回调函数,简单打印接收到的数据包数量
void rx_callback(uint16_t port_id, uint16_t queue_id, struct rte_mbuf *pkts[], uint16_t nb_pkts, void *user_param) {
printf("Received %u packets on port %u, queue %u\n", nb_pkts, port_id, queue_id);
}
int main() {
// 假设要添加接收回调函数的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 假设要添加接收回调函数的接收队列的队列 ID 为 0
uint16_t queue_id = 0;
// 向以太网设备添加接收回调函数
int ret = rte_eth_add_rx_callback(port_id, queue_id, rx_callback, NULL);
if (ret == 0) {
// 打印结果
printf("Successfully added RX callback for port %u, queue %u\n", port_id, queue_id);
} else {
printf("Failed to add RX callback for port %u, queue %u\n", port_id, queue_id);
}
return 0;
}
3.28 rte_eth_remove_rx_callback
从以太网设备移除接收回调函数
#include <stdio.h>
#include <stdint.h>
#include <rte_ethdev.h>
// 定义接收回调函数的原型
typedef void (*rx_callback_fn)(uint16_t port_id, uint16_t queue_id, struct rte_mbuf *pkts[], uint16_t nb_pkts, void *user_param);
/**
* 从以太网设备移除接收回调函数
*
* @param port_id 网络设备的端口 ID。
* @param queue_id 接收队列的队列 ID。
* @param callback_fn 接收回调函数的指针。
* @param user_param 用户参数,传递给接收回调函数。
* @return 0 表示成功移除接收回调函数,负值表示失败。
*/
int rte_eth_remove_rx_callback(uint16_t port_id, uint16_t queue_id, rx_callback_fn callback_fn, void *user_param);
// 示例接收回调函数,简单打印接收到的数据包数量
void rx_callback(uint16_t port_id, uint16_t queue_id, struct rte_mbuf *pkts[], uint16_t nb_pkts, void *user_param) {
printf("Received %u packets on port %u, queue %u\n", nb_pkts, port_id, queue_id);
}
int main() {
// 假设要移除接收回调函数的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 假设要移除接收回调函数的接收队列的队列 ID 为 0
uint16_t queue_id = 0;
// 向以太网设备添加接收回调函数
int ret = rte_eth_remove_rx_callback(port_id, queue_id, rx_callback, NULL);
if (ret == 0) {
// 打印结果
printf("Successfully removed RX callback for port %u, queue %u\n", port_id, queue_id);
} else {
printf("Failed to remove RX callback for port %u, queue %u\n", port_id, queue_id);
}
return 0;
}
3.29 rte_eth_add_tx_callback
向以太网设备添加发送回调函数
#include <stdio.h>
#include <stdint.h>
#include <rte_ethdev.h>
// 定义发送回调函数的原型
typedef void (*tx_callback_fn)(uint16_t port_id, uint16_t queue_id, struct rte_mbuf *pkts[], uint16_t nb_pkts, void *user_param);
/**
* 向以太网设备添加发送回调函数
*
* @param port_id 网络设备的端口 ID。
* @param queue_id 发送队列的队列 ID。
* @param callback_fn 发送回调函数的指针。
* @param user_param 用户参数,传递给发送回调函数。
* @return 0 表示成功添加发送回调函数,负值表示失败。
*/
int rte_eth_add_tx_callback(uint16_t port_id, uint16_t queue_id, tx_callback_fn callback_fn, void *user_param);
// 示例发送回调函数,简单打印发送的数据包数量
void tx_callback(uint16_t port_id, uint16_t queue_id, struct rte_mbuf *pkts[], uint16_t nb_pkts, void *user_param) {
printf("Transmitted %u packets on port %u, queue %u\n", nb_pkts, port_id, queue_id);
}
int main() {
// 假设要添加发送回调函数的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 假设要添加发送回调函数的发送队列的队列 ID 为 0
uint16_t queue_id = 0;
// 向以太网设备添加发送回调函数
int ret = rte_eth_add_tx_callback(port_id, queue_id, tx_callback, NULL);
if (ret == 0) {
// 打印结果
printf("Successfully added TX callback for port %u, queue %u\n", port_id, queue_id);
} else {
printf("Failed to add TX callback for port %u, queue %u\n", port_id, queue_id);
}
return 0;
}
3.30 rte_eth_remove_tx_callback
从以太网设备移除发送回调函数
#include <stdio.h>
#include <stdint.h>
#include <rte_ethdev.h>
// 定义发送回调函数的原型
typedef void (*tx_callback_fn)(uint16_t port_id, uint16_t queue_id, struct rte_mbuf *pkts[], uint16_t nb_pkts, void *user_param);
/**
* 从以太网设备移除发送回调函数
*
* @param port_id 网络设备的端口 ID。
* @param queue_id 发送队列的队列 ID。
* @param callback_fn 发送回调函数的指针。
* @param user_param 用户参数,传递给发送回调函数。
* @return 0 表示成功移除发送回调函数,负值表示失败。
*/
int rte_eth_remove_tx_callback(uint16_t port_id, uint16_t queue_id, tx_callback_fn callback_fn, void *user_param);
// 示例发送回调函数,简单打印发送的数据包数量
void tx_callback(uint16_t port_id, uint16_t queue_id, struct rte_mbuf *pkts[], uint16_t nb_pkts, void *user_param) {
printf("Transmitted %u packets on port %u, queue %u\n", nb_pkts, port_id, queue_id);
}
int main() {
// 假设要移除发送回调函数的网络设备的端口 ID 为 0
uint16_t port_id = 0;
// 假设要移除发送回调函数的发送队列的队列 ID 为 0
uint16_t queue_id = 0;
// 向以太网设备添加发送回调函数
int ret = rte_eth_remove_tx_callback(port_id, queue_id, tx_callback, NULL);
if (ret == 0) {
// 打印结果
printf("Successfully removed TX callback for port %u, queue %u\n", port_id, queue_id);
} else {
printf("Failed to remove TX callback for port %u, queue %u\n", port_id, queue_id);
}
return 0;
}