DPDK常用API合集三

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, &eth_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 :网络设备的端口id
  • rx_queue_id:接收队列的队列id
  • nb_rx_desv :接收队列的描述符数量,接收队列的描述符数量决定了队列能够同时处理的数据包数量。
  • socket_id:指定用于内存分配的UNMA节点的ID
  • rx_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;
}

  • 11
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 要生成DPDK 19.11的API手册,需要进行以下步骤: 1. 下载DPDK 19.11源代码:首先,需要从DPDK官方网站下载DPDK 19.11的源代码,并解压到本地目录。 2. 安装依赖:在生成API手册之前,需要先确保系统中已经安装了必要的依赖库,如gcc,doxygen等。可以通过运行DPDK提供的脚本(如usertools/dpdk-setup.sh)来安装依赖。 3. 配置编译选项:在源代码目录中,通过运行config脚本来配置编译选项。可以选择性地启用或禁用某些组件或驱动,并确保已开启生成API文档的选项。 4. 编译源代码:运行make命令来编译DPDK源代码。这会自动编译生成相应的API文档。 5. 生成API手册:在编译完成后,通过运行make doc命令来生成DPDK 19.11的API手册。这个命令会调用doxygen工具来分析源代码,并生成API文档。 6. 查看API手册:生成的API手册位于doc/api目录下。可以使用浏览器访问该目录下的index.html文件来查看API手册。通过索引、搜索等功能,可以快速定位和查找所需的API文档。 需要注意的是,生成API手册需要一定的系统配置和依赖库支持,且会占用一定的系统资源和时间。根据机器配置和网络状况的不同,生成API手册的时间可能会有所不同。 ### 回答2: 要生成DPDK 19.11版本的API手册,可以按照以下步骤进行操作: 1. 确保已经安装了必要的软件和工具,如doxygen和git。 * 安装doxygen:可以通过在操作系统中运行适当的包管理器或从doxygen官方网站下载和安装程序进行安装。 * 安装git:根据所使用的操作系统,可以使用适当的包管理器或从git官方网站下载和安装程序。 2. 在终端或命令提示符中,使用git命令从DPDK的官方Git仓库中克隆最新版本的源代码。 * 执行以下命令:git clone http://dpdk.org/git/dpdk 3. 进入克隆的dpdk目录。 * 执行以下命令:cd dpdk 4. 切换到DPDK 19.11版本的稳定分支。 * 执行以下命令:git checkout v19.11 5. 使用doxygen生成API手册。 * 执行以下命令:doxygen doc/guides/doxyfile-guides 6. 生成的API手册将保存在doc/api目录中。 通过以上步骤,你就可以生成DPDK 19.11版本的API手册。可以通过打开doc/api/index.html文件在浏览器中查看手册。手册将包含DPDK库中的各个模块和函数的详细说明,以及使用说明和示例代码,帮助开发人员了解和使用DPDK软件库。 ### 回答3: 要生成DPDK 1911版本的API手册,你可以按照以下步骤进行操作: 1. 确保你的开发环境已经配置好,包括DPDK的安装和设置。 2. 下载DPDK 1911版本的源代码,可以到DPDK官方网站上获取。 3. 进入DPDK源代码的根目录。 4. 打开终端,输入以下命令来生成API手册: ``` make doc-api-doc ``` 5. 等待编译和生成过程完成。这步可能需要一些时间,取决于你的机器性能和DPDK代码的大小。 6. 执行完上述命令后,你可以在源代码根目录下的`build/doc/api`目录中找到生成的API手册。手册以HTML格式显示。 7. 可以使用Web浏览器来打开手册,以查看和导航DPDK的各种API。 8. 如果你想将API手册导出为其他格式(如PDF),你可以使用相关工具将HTML转换为所需的格式。 请注意,生成API手册需要有适当的开发环境以及一些编译工具和依赖项。如果你遇到了问题,请参考DPDK的官方文档或向社区寻求帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

写一封情书

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值