DPDK常用API合集五

1.1 librte_fib 简介

librte_fib 是 Data Plane Development Kit (DPDK) 的一部分,用于实现前缀匹配和路由表查找功能。它提供了一种高效的方式来管理和查询前缀路由表,对于需要快速查找 IP 路由的应用特别有用,如网络交换机和路由器

1.2 librte_fib 原理

librte_fib 基于前缀树(也称为 Trie)或基于 Hash 表的算法来实现前缀匹配。其核心思想是将路由前缀组织成一种树形结构,使得查找过程可以通过逐层匹配前缀位来快速定位目标路由。常见的实现方式包括:

Trie:使用前缀树(如 Patricia Trie 或 LC-Trie)来存储路由前缀。每个节点代表一个前缀,查找时从根节点开始逐级匹配。
Hash 表:使用带前缀长度的 Hash 表来存储和查找路由条目,通过哈希函数快速定位路由项。

1.3 rte_fib.h

#ifndef _RTE_FIB_H_
#define _RTE_FIB_H_

/**
 * @file
 *
 * RTE FIB 库。
 *
 * 用于IPv4最长前缀匹配的FIB(转发信息库)实现
 */

#include <stdint.h>


#ifdef __cplusplus
extern "C" {
#endif

struct rte_fib;
struct rte_rib;

/** IPv4 FIB的最大深度值。 */
#define RTE_FIB_MAXDEPTH	32

/** FIB结构类型 */
enum rte_fib_type {
	RTE_FIB_DUMMY,		/**< 基于RIB树的FIB */
	RTE_FIB_DIR24_8		/**< 基于DIR24_8的FIB */
};

/** 修改FIB函数 */
typedef int (*rte_fib_modify_fn_t)(struct rte_fib *fib, uint32_t ip,
	uint8_t depth, uint64_t next_hop, int op);
/** FIB批量查找函数 */
typedef void (*rte_fib_lookup_fn_t)(void *fib, const uint32_t *ips,
	uint64_t *next_hops, const unsigned int n);

enum rte_fib_op {
	RTE_FIB_ADD,
	RTE_FIB_DEL,
};

/** DIR24_8 基于FIB的下一跳(1 << nh_sz)位的大小 */
enum rte_fib_dir24_8_nh_sz {
	RTE_FIB_DIR24_8_1B,
	RTE_FIB_DIR24_8_2B,
	RTE_FIB_DIR24_8_4B,
	RTE_FIB_DIR24_8_8B
};

/** 查找函数实现类型 */
enum rte_fib_lookup_type {
	RTE_FIB_LOOKUP_DEFAULT,
	/**< 基于最大SIMD位宽选择最佳实现 */
	RTE_FIB_LOOKUP_DIR24_8_SCALAR_MACRO,
	/**< 基于宏的查找函数 */
	RTE_FIB_LOOKUP_DIR24_8_SCALAR_INLINE,
	/**< 使用内联函数的查找实现,用于不同的下一跳大小 */
	RTE_FIB_LOOKUP_DIR24_8_SCALAR_UNI,
	/**< 用于所有下一跳大小的统一查找函数 */
	RTE_FIB_LOOKUP_DIR24_8_VECTOR_AVX512
	/**< 使用AVX512的向量实现 */
};

/** FIB配置结构 */
struct rte_fib_conf {
	enum rte_fib_type type; /**< FIB结构类型 */
	/** 查找时如果没有路由返回的默认值 */
	uint64_t default_nh;
	int	max_routes;
	/** 内部RIB结构中节点扩展的大小 */
	unsigned int rib_ext_sz;
	union {
		struct {
			enum rte_fib_dir24_8_nh_sz nh_sz;
			uint32_t	num_tbl8;
		} dir24_8;
	};
};

/**
 * 创建FIB
 *
 * @param name
 *  FIB名称
 * @param socket_id
 *  用于FIB表内存分配的NUMA节点ID
 * @param conf
 *  包含配置信息的结构
 * @return
 *  成功时返回FIB对象的句柄
 *  否则返回NULL,并设置rte_errno为适当的值。
 */
struct rte_fib *
rte_fib_create(const char *name, int socket_id, struct rte_fib_conf *conf);

/**
 * 查找现有的FIB对象并返回指向它的指针。
 *
 * @param name
 *  传递给rte_fib_create()的FIB对象名称
 * @return
 *  成功时返回指向FIB对象的指针,否则返回NULL,并适当设置rte_errno。
 *  可能的rte_errno值包括:
 *   - ENOENT - 所需条目不可用。
 */
struct rte_fib *
rte_fib_find_existing(const char *name);

/**
 * 释放FIB对象。
 *
 * @param fib
 *   由rte_fib_create()创建的FIB对象句柄。
 *   如果fib为NULL,则不执行任何操作。
 */
void
rte_fib_free(struct rte_fib *fib);

/**
 * 向FIB添加路由。
 *
 * @param fib
 *   FIB对象句柄
 * @param ip
 *   要添加到FIB的IPv4前缀地址
 * @param depth
 *   前缀长度
 * @param next_hop
 *   要添加到FIB的下一跳
 * @return
 *   成功时返回0,否则返回负值
 */
int
rte_fib_add(struct rte_fib *fib, uint32_t ip, uint8_t depth, uint64_t next_hop);

/**
 * 从FIB中删除规则。
 *
 * @param fib
 *   FIB对象句柄
 * @param ip
 *   要从FIB中删除的IPv4前缀地址
 * @param depth
 *   前缀长度
 * @return
 *   成功时返回0,否则返回负值
 */
int
rte_fib_delete(struct rte_fib *fib, uint32_t ip, uint8_t depth);

/**
 * 批量查找FIB中的多个IP地址。
 *
 * @param fib
 *   FIB对象句柄
 * @param ips
 *   要在FIB中查找的IP数组
 * @param next_hops
 *   为IP找到的最具体规则的下一跳。
 *   这是一个八字节值的数组。
 *   如果给定IP的查找失败,则对应的元素将包含为FIB配置的默认下一跳值。
 * @param n
 *   要查找的ips(和next_hops)数组中的元素数量。
 *  @return
 *   对于不正确的参数返回-EINVAL,否则返回0
 */
int
rte_fib_lookup_bulk(struct rte_fib *fib, uint32_t *ips,
		uint64_t *next_hops, int n);

/**
 * 获取指向特定数据平面结构的指针
 *
 * @param fib
 *   FIB对象句柄
 * @return
 *   成功时返回数据平面结构的指针
 *   否则返回NULL
 */
void *
rte_fib_get_dp(struct rte_fib *fib);

/**
 * 获取指向RIB的指针
 *
 * @param fib
 *   FIB对象句柄
 * @return
 *   成功时返回RIB的指针
 *   否则返回NULL
 */
struct rte_rib *
rte_fib_get_rib(struct rte_fib *fib);

/**
 * 根据类型设置查找函数
 *
 * @param fib
 *   FIB对象句柄
 * @param type
 *   查找函数的类型
 *
 * @return
 *   成功时返回0
 *   失败时返回-EINVAL
 */
int
rte_fib_select_lookup(struct rte_fib *fib, enum rte_fib_lookup_type type);

#ifdef __cplusplus
}
#endif

#endif /* _RTE_FIB_H_ */

1.4 rte_fib_create

1.4.1 使用场景

rte_fib_create 用于在网络设备或应用中创建一个前缀匹配的数据结构,以实现高效的IP路由查找。这对于路由器、交换机、防火墙等需要快速转发数据包的设备尤为重要。通过创建FIB(Forwarding Information Base),可以根据最长前缀匹配原则快速找到下一跳地址,从而提高数据包转发的效率。

1.4.2 函数原型和参数

struct rte_fib *rte_fib_create(const char *name, int socket_id, struct rte_fib_conf *conf);

name: FIB对象的名称,字符串格式。
socket_id: 用于内存分配的NUMA节点ID。
conf: FIB配置结构,包含FIB的类型、默认下一跳、最大路由数等配置信息。

1.4.3 示例代码

#include <stdio.h>
#include <stdint.h>
#include <rte_fib.h>
#include <rte_malloc.h>
#include <rte_eal.h>

#define SOCKET_ID 0
#define MAX_ROUTES 1024
#define DEFAULT_NH 0

void print_next_hops(uint64_t *next_hops, int n) {
    for (int i = 0; i < n; i++) {
        printf("Next hop for IP %d: %lu\n", i, next_hops[i]);
    }
}

void forward_packet(uint32_t ip, uint64_t next_hop) {
    // 模拟数据包转发,根据下一跳选择输出接口
    printf("Forwarding packet with destination IP %u to next hop %lu\n", ip, next_hop);
}

int main(int argc, char **argv) {
    // 初始化DPDK环境
    rte_eal_init(argc, argv);

    // 配置FIB
    struct rte_fib_conf fib_conf = {
        .type = RTE_FIB_DIR24_8,
        .default_nh = DEFAULT_NH,
        .max_routes = MAX_ROUTES,
        .rib_ext_sz = 0,
        .dir24_8 = {
            .nh_sz = RTE_FIB_DIR24_8_4B,
            .num_tbl8 = 256
        }
    };

    // 创建FIB
    struct rte_fib *fib = rte_fib_create("example_fib", SOCKET_ID, &fib_conf);
    if (fib == NULL) {
        printf("Failed to create FIB\n");
        return -1;
    }

    // 添加路由
    uint32_t ip1 = RTE_IPV4(192, 168, 1, 0);
    uint32_t ip2 = RTE_IPV4(10, 0, 0, 0);
    uint8_t depth1 = 24;
    uint8_t depth2 = 8;
    uint64_t next_hop1 = 1;
    uint64_t next_hop2 = 2;

    rte_fib_add(fib, ip1, depth1, next_hop1);
    rte_fib_add(fib, ip2, depth2, next_hop2);

    // 查找路由
    uint32_t ips_to_lookup[2] = {RTE_IPV4(192, 168, 1, 100), RTE_IPV4(10, 0, 1, 1)};
    uint64_t next_hops[2];

    rte_fib_lookup_bulk(fib, ips_to_lookup, next_hops, 2);
    print_next_hops(next_hops, 2);

    // 模拟数据包转发
    for (int i = 0; i < 2; i++) {
        forward_packet(ips_to_lookup[i], next_hops[i]);
    }

    // 删除路由
    rte_fib_delete(fib, ip1, depth1);
    rte_fib_delete(fib, ip2, depth2);

    // 查找路由,查看默认下一跳
    rte_fib_lookup_bulk(fib, ips_to_lookup, next_hops, 2);
    print_next_hops(next_hops, 2);

    // 模拟数据包转发
    for (int i = 0; i < 2; i++) {
        forward_packet(ips_to_lookup[i], next_hops[i]);
    }

    // 释放FIB
    rte_fib_free(fib);

    // 关闭DPDK环境
    rte_eal_cleanup();

    return 0;
}

1.5 rte_fib_find_existing

rte_fib_find_existing 函数用于查找已经存在的 FIB(Forwarding Information Base)对象,便于在应用程序的不同部分之间共享 FIB 对象,从而避免重复创建。

1.5.1 函数原型及参数

struct rte_fib *rte_fib_find_existing(const char *name);

参数

  • name:字符串类型,FIB 对象的名称。此名称是在使用 rte_fib_create 函数创建 FIB 时指定的。

返回值

  • 成功:返回一个指向 struct rte_fib 的指针,即找到的 FIB 对象。
  • 失败:返回 NULL,并设置 rte_errno 以指示错误。

1.5.2 使用场景

假设有一个需要在多个模块之间共享 FIB 的应用程序。首先在一个模块中创建 FIB 对象,然后在其他模块中查找并使用该 FIB 对象。

1.5.3 代码示例

#include <stdio.h>
#include <stdint.h>
#include <rte_fib.h>
#include <rte_eal.h>

#define SOCKET_ID 0

void print_next_hops(uint64_t *next_hops, int n) {
    for (int i = 0; i < n; i++) {
        printf("Next hop for IP %d: %lu\n", i, next_hops[i]);
    }
}

int main(int argc, char **argv) {
    // 初始化DPDK环境
    if (rte_eal_init(argc, argv) < 0) {
        fprintf(stderr, "Failed to initialize EAL\n");
        return -1;
    }

    // 查找现有FIB
    struct rte_fib *fib = rte_fib_find_existing("shared_fib");
    if (fib == NULL) {
        printf("Failed to find existing FIB\n");
        return -1;
    }

    // 查找路由
    uint32_t ips_to_lookup[2] = {RTE_IPV4(192, 168, 1, 100), RTE_IPV4(10, 0, 1, 1)};
    uint64_t next_hops[2];

    rte_fib_lookup_bulk(fib, ips_to_lookup, next_hops, 2);
    print_next_hops(next_hops, 2);

    // 关闭DPDK环境
    rte_eal_cleanup();

    return 0;
}


1.6 rte_fib_select_lookup

rte_fib_select_lookup 是 DPDK(Data Plane Development Kit)中用于选择 FIB(Forwarding Information Base)对象的查找函数。它允许根据不同的查找策略选择适当的查找函数,从而优化性能。

1.6.1 函数原型及参数返回值

int rte_fib_select_lookup(struct rte_fib *fib, enum rte_fib_lookup_type type);

参数
fib: 指向 struct rte_fib 的指针,该结构体表示一个 FIB 对象。
type: enum rte_fib_lookup_type 类型的查找类型,指示使用哪种查找策略。常见查找类型包括 RTE_FIB_LOOKUP_TRIE 和 RTE_FIB_LOOKUP_AVX512。
返回值
返回值为 0 表示成功,负值表示失败

1.6.2 使用场景

rte_fib_select_lookup 用于在创建 FIB 对象后,根据需要选择适当的查找策略。这在不同的硬件架构或特定的性能优化需求下非常有用。

代码示例

主要是查找之前,切换不同的查找策略,不切换则为默认或者根据创建参数指定

#include <stdio.h>
#include <stdint.h>
#include <rte_fib.h>
#include <rte_fib4.h>
#include <rte_eal.h>

#define MAX_ROUTES 1024

int main(int argc, char **argv) {
    // Initialize the Environment Abstraction Layer (EAL)
    rte_eal_init(argc, argv);

    struct rte_fib *fib;
    struct rte_fib_conf fib_conf;
    int socket_id = rte_socket_id();
    uint64_t next_hop = 0x1234;

    // Configuration for FIB
    fib_conf.type = RTE_FIB_TRIE;
    fib_conf.default_nh = 0;
    fib_conf.max_routes = MAX_ROUTES;
    fib_conf.trie.nh_sz = RTE_FIB4_TRIE_2B;

    // Create FIB
    fib = rte_fib_create("example_fib", socket_id, &fib_conf);
    if (fib == NULL) {
        fprintf(stderr, "Failed to create FIB\n");
        return -1;
    }

    // Add routes to FIB
    rte_fib4_add(fib, 0xC0A80000, 24, next_hop); // 192.168.0.0/24
    rte_fib4_add(fib, 0xC0A80100, 24, next_hop + 1); // 192.168.1.0/24

    // Select lookup function
    if (rte_fib_select_lookup(fib, RTE_FIB_LOOKUP_TRIE) < 0) {
        fprintf(stderr, "Failed to select FIB lookup function\n");
        return -1;
    }

    // Perform a route lookup
    uint64_t nh;
    int ret;

    ret = rte_fib4_lookup(fib, 0xC0A80001, &nh); // 192.168.0.1
    if (ret == 0) {
        printf("Lookup successful using TRIE, next hop: 0x%lx\n", nh);
    } else {
        printf("Lookup failed using TRIE\n");
    }

    // Switch to another lookup type if supported
    if (rte_fib_select_lookup(fib, RTE_FIB_LOOKUP_AVX512) < 0) {
        fprintf(stderr, "Failed to select AVX512 lookup function or not supported\n");
    } else {
        ret = rte_fib4_lookup(fib, 0xC0A80101, &nh); // 192.168.1.1
        if (ret == 0) {
            printf("Lookup successful using AVX512, next hop: 0x%lx\n", nh);
        } else {
            printf("Lookup failed using AVX512\n");
        }
    }

    // Clean up
    rte_fib_free(fib);

    return 0;
}

2 librte_fib ipv6

2.1 rte_fib6_create

2.1.1 rte_fib6_create

rte_fib6_create 是 DPDK(Data Plane Development Kit)中用于创建 IPv6 FIB(Forwarding Information Base)对象的函数。这个函数会根据指定的配置参数创建一个 FIB 实例,用于高性能网络应用中的路由查找。

2.1.2 函数原型

struct rte_fib6 *rte_fib6_create(const char *name, int socket_id, const struct rte_fib6_conf *conf);

参数

  • name: 创建的 FIB 对象的名称。
  • socket_id: 分配 FIB 对象的 NUMA 节点。
  • conf: 指向 struct rte_fib6_conf 结构的指针,包含 FIB 的配置参数。

返回值

  • 成功时返回指向新创建的 FIB 对象的指针,失败时返回 NULL。

2.1.3 struct rte_fib6_conf 结构体

struct rte_fib6_conf {
    enum rte_fib6_type type; // FIB 类型,例如 RTE_FIB6_TRIE。
    uint64_t default_nh;     // 默认下一跳。
    uint32_t max_routes;     // 最大路由数量。
    union {
        struct {
            uint32_t nh_sz;  // 下一跳大小。
            uint32_t num_tbl8s; // 8位段表数量。
        } trie;
        // 其他可能的配置
    };
};

2.1.4 使用场景

rte_fib6_create 用于在需要处理 IPv6 路由的高性能网络应用中创建 FIB 实例。例如,构建一个支持快速 IPv6 路由查找的高性能路由器或防火墙。

2.1.5 代码示例

#include <stdio.h>
#include <stdint.h>
#include <rte_fib.h>
#include <rte_fib6.h>
#include <rte_eal.h>

#define MAX_ROUTES 1024

int main(int argc, char **argv) {
    // Initialize the Environment Abstraction Layer (EAL)
    if (rte_eal_init(argc, argv) < 0) {
        fprintf(stderr, "Failed to initialize EAL\n");
        return -1;
    }

    struct rte_fib6 *fib;
    struct rte_fib6_conf fib_conf;
    int socket_id = rte_socket_id();
    uint64_t next_hop1 = 0x1234;
    uint64_t next_hop2 = 0x5678;

    // Configuration for FIB
    fib_conf.type = RTE_FIB6_TRIE;
    fib_conf.default_nh = 0;
    fib_conf.max_routes = MAX_ROUTES;
    fib_conf.trie.nh_sz = RTE_FIB6_TRIE_2B;
    fib_conf.trie.num_tbl8s = 256; // Example value, adjust as needed

    // Create FIB
    fib = rte_fib6_create("example_fib6", socket_id, &fib_conf);
    if (fib == NULL) {
        fprintf(stderr, "Failed to create FIB6\n");
        return -1;
    }

    // Add routes to FIB
    rte_fib6_add(fib, (uint8_t *)"\x20\x01\x0d\xb8\x85\xa3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 64, next_hop1);
    rte_fib6_add(fib, (uint8_t *)"\x20\x01\x0d\xb8\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 64, next_hop2);

    // Perform a route lookup
    uint64_t nh;
    int ret;

    ret = rte_fib6_lookup(fib, (uint8_t *)"\x20\x01\x0d\xb8\x85\xa3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", &nh);
    if (ret == 0) {
        printf("Lookup successful for 2001:db8:85a3::1, next hop: 0x%lx\n", nh);
    } else {
        printf("Lookup failed for 2001:db8:85a3::1\n");
    }

    ret = rte_fib6_lookup(fib, (uint8_t *)"\x20\x01\x0d\xb8\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", &nh);
    if (ret == 0) {
        printf("Lookup successful for 2001:db8:10::1, next hop: 0x%lx\n", nh);
    } else {
        printf("Lookup failed for 2001:db8:10::1\n");
    }

    // Clean up
    rte_fib6_free(fib);

    return 0;
}

2.2 rte_fib6_select_lookup

rte_fib6_select_lookup 是 DPDK 中用于选择 IPv6 FIB(Forwarding Information Base)对象的查找函数。这个函数允许在不同的查找算法之间切换,从而优化性能。

2.2.1 函数原型

int rte_fib6_select_lookup(struct rte_fib6 *fib, enum rte_fib6_lookup_type type);

参数

  • fib: 指向 struct rte_fib6 的指针,该结构体表示一个 FIB 对象。
  • type: enum rte_fib6_lookup_type 类型的查找类型,指示使用哪种查找策略。常见查找类型包括 RTE_FIB6_LOOKUP_TRIE 和 RTE_FIB6_LOOKUP_AVX512.

返回值
返回值为 0 表示成功,负值表示失败。

2.2.1 使用场景

rte_fib6_select_lookup 用于在创建 FIB 对象后,根据需要选择适当的查找策略。这在不同的硬件架构或特定的性能优化需求下非常有用。

2.2.1 代码示例

#include <stdio.h>
#include <stdint.h>
#include <rte_fib.h>
#include <rte_fib6.h>
#include <rte_eal.h>

#define MAX_ROUTES 1024

int main(int argc, char **argv) {
    // Initialize the Environment Abstraction Layer (EAL)
    if (rte_eal_init(argc, argv) < 0) {
        fprintf(stderr, "Failed to initialize EAL\n");
        return -1;
    }

    struct rte_fib6 *fib;
    struct rte_fib6_conf fib_conf;
    int socket_id = rte_socket_id();
    uint64_t next_hop1 = 0x1234;
    uint64_t next_hop2 = 0x5678;

    // Configuration for FIB
    fib_conf.type = RTE_FIB6_TRIE;
    fib_conf.default_nh = 0;
    fib_conf.max_routes = MAX_ROUTES;
    fib_conf.trie.nh_sz = RTE_FIB6_TRIE_2B;
    fib_conf.trie.num_tbl8s = 256; // Example value, adjust as needed

    // Create FIB
    fib = rte_fib6_create("example_fib6", socket_id, &fib_conf);
    if (fib == NULL) {
        fprintf(stderr, "Failed to create FIB6\n");
        return -1;
    }

    // Add routes to FIB
    rte_fib6_add(fib, (uint8_t *)"\x20\x01\x0d\xb8\x85\xa3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 64, next_hop1);
    rte_fib6_add(fib, (uint8_t *)"\x20\x01\x0d\xb8\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 64, next_hop2);

    // Select lookup function - use TRIE
    if (rte_fib6_select_lookup(fib, RTE_FIB6_LOOKUP_TRIE) < 0) {
        fprintf(stderr, "Failed to select FIB lookup function\n");
        return -1;
    }

    // Perform a route lookup using TRIE
    uint64_t nh;
    int ret;

    ret = rte_fib6_lookup(fib, (uint8_t *)"\x20\x01\x0d\xb8\x85\xa3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", &nh);
    if (ret == 0) {
        printf("Lookup successful using TRIE for 2001:db8:85a3::1, next hop: 0x%lx\n", nh);
    } else {
        printf("Lookup failed using TRIE for 2001:db8:85a3::1\n");
    }

    // Switch to another lookup type if supported
    if (rte_fib6_select_lookup(fib, RTE_FIB6_LOOKUP_AVX512) < 0) {
        fprintf(stderr, "Failed to select AVX512 lookup function or not supported\n");
    } else {
        ret = rte_fib6_lookup(fib, (uint8_t *)"\x20\x01\x0d\xb8\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", &nh);
        if (ret == 0) {
            printf("Lookup successful using AVX512 for 2001:db8:10::1, next hop: 0x%lx\n", nh);
        } else {
            printf("Lookup failed using AVX512 for 2001:db8:10::1\n");
        }
    }

    // Clean up
    rte_fib6_free(fib);

    return 0;
}

该示例展示了如何创建和配置 IPv6 FIB,对其添加路由,选择查找函数,并进行路由查找。通过 rte_fib6_select_lookup,可以根据不同的查找策略优化路由查找的性能。

与lpm的区别

LPM(Longest Prefix Match)FIB(Forwarding Information Base)在网络处理中有相似的功能,但它们在实现细节和应用场景上有所不同。下面是对LPM和FIB的详细介绍,以及它们之间的区别和联系。

3.1 LPM(Longest Prefix Match)

LPM是一种用于查找路由前缀的算法,其核心思想是找到与目标IP地址匹配的最长前缀。LPM通常用于路由表查找,确定数据包应该转发到哪个下一跳。LPM查找需要高效的数据结构和算法,因为它在处理每个数据包时都需要执行查找操作。

3.2 FIB(Forwarding Information Base)

FIB是路由器用来存储路由信息的表,它包含了目的地IP地址前缀和对应的下一跳信息。FIB是根据路由表(RIB,Routing Information Base)生成的,RIB包含更全面的路由信息,包括未被选为最佳路径的路由。FIB只包含最佳路径,并用于快速查找。

3.3区别和联系

  • 用途:
    LPM:用于实现最长前缀匹配算法,通常是FIB查找的一部分。
    FIB:用于存储和查找实际的路由信息,包含多个前缀和对应的下一跳信息。

  • 数据结构:
    LPM:通常使用特定的数据结构如Trie(前缀树)或哈希表来实现高效的前缀匹配。
    FIB:可以使用LPM算法进行查找,也可以使用其他高效的数据结构,如哈希表、压缩前缀树等。

  • 性能:
    LPM:关注查找算法的效率,以保证在大规模路由表中能快速找到最长匹配前缀。
    FIB:关注整体路由查找的效率和内存占用,因为它直接影响数据包的转发性能。

3.4 实例:LPM与FIB的使用

  • 场景
    假设我们有一台路由器,需要配置和查询路由信息以决定数据包的转发路径。我们有以下路由条目:

目的网络:192.168.1.0/24,下一跳:1
目的网络:10.0.0.0/8,下一跳:2

  • 我们需要进行以下操作:

添加上述路由条目。
查询以下IP地址的下一跳:192.168.1.100 和 10.0.1.1。
删除上述路由条目。
再次查询上述IP地址,查看默认下一跳

3.5 使用LPM进行操作

#include <stdio.h>
#include <stdint.h>
#include <rte_lpm.h>
#include <rte_malloc.h>
#include <rte_eal.h>

#define SOCKET_ID 0
#define MAX_ROUTES 1024
#define DEFAULT_NH 0

void print_next_hops(uint32_t *next_hops, int n) {
    for (int i = 0; i < n; i++) {
        printf("Next hop for IP %d: %u\n", i, next_hops[i]);
    }
}

int main(int argc, char **argv) {
    // 初始化DPDK环境
    rte_eal_init(argc, argv);

    // 配置LPM
    struct rte_lpm_config lpm_conf = {
        .max_rules = MAX_ROUTES,
        .number_tbl8s = (1 << 8),
        .flags = 0
    };

    // 创建LPM
    struct rte_lpm *lpm = rte_lpm_create("example_lpm", SOCKET_ID, &lpm_conf);
    if (lpm == NULL) {
        printf("Failed to create LPM\n");
        return -1;
    }

    // 添加路由
    uint32_t ip1 = RTE_IPV4(192, 168, 1, 0);
    uint32_t ip2 = RTE_IPV4(10, 0, 0, 0);
    uint8_t depth1 = 24;
    uint8_t depth2 = 8;
    uint32_t next_hop1 = 1;
    uint32_t next_hop2 = 2;

    rte_lpm_add(lpm, ip1, depth1, next_hop1);
    rte_lpm_add(lpm, ip2, depth2, next_hop2);

    // 查找路由
    uint32_t ips_to_lookup[2] = {RTE_IPV4(192, 168, 1, 100), RTE_IPV4(10, 0, 1, 1)};
    uint32_t next_hops[2];

    rte_lpm_lookup_bulk(lpm, ips_to_lookup, next_hops, 2);
    print_next_hops(next_hops, 2);

    // 删除路由
    rte_lpm_delete(lpm, ip1, depth1);
    rte_lpm_delete(lpm, ip2, depth2);

    // 查找路由,查看默认下一跳
    rte_lpm_lookup_bulk(lpm, ips_to_lookup, next_hops, 2);
    print_next_hops(next_hops, 2);

    // 释放LPM
    rte_lpm_free(lpm);

    // 关闭DPDK环境
    rte_eal_cleanup();

    return 0;
}

输出结果

Next hop for IP 0: 1
Next hop for IP 1: 2
Next hop for IP 0: 0
Next hop for IP 1: 0

3.6 使用FIB进行操作

#include <stdio.h>
#include <stdint.h>
#include <rte_fib.h>
#include <rte_malloc.h>
#include <rte_eal.h>

#define SOCKET_ID 0
#define MAX_ROUTES 1024
#define DEFAULT_NH 0

void print_next_hops(uint64_t *next_hops, int n) {
    for (int i = 0; i < n; i++) {
        printf("Next hop for IP %d: %lu\n", i, next_hops[i]);
    }
}

int main(int argc, char **argv) {
    // 初始化DPDK环境
    rte_eal_init(argc, argv);

    // 配置FIB
    struct rte_fib_conf fib_conf = {
        .type = RTE_FIB_DIR24_8,
        .default_nh = DEFAULT_NH,
        .max_routes = MAX_ROUTES,
        .rib_ext_sz = 0,
        .dir24_8 = {
            .nh_sz = RTE_FIB_DIR24_8_4B,
            .num_tbl8 = 256
        }
    };

    // 创建FIB
    struct rte_fib *fib = rte_fib_create("example_fib", SOCKET_ID, &fib_conf);
    if (fib == NULL) {
        printf("Failed to create FIB\n");
        return -1;
    }

    // 添加路由
    uint32_t ip1 = RTE_IPV4(192, 168, 1, 0);
    uint32_t ip2 = RTE_IPV4(10, 0, 0, 0);
    uint8_t depth1 = 24;
    uint8_t depth2 = 8;
    uint64_t next_hop1 = 1;
    uint64_t next_hop2 = 2;

    rte_fib_add(fib, ip1, depth1, next_hop1);
    rte_fib_add(fib, ip2, depth2, next_hop2);

    // 查找路由
    uint32_t ips_to_lookup[2] = {RTE_IPV4(192, 168, 1, 100), RTE_IPV4(10, 0, 1, 1)};
    uint64_t next_hops[2];

    rte_fib_lookup_bulk(fib, ips_to_lookup, next_hops, 2);
    print_next_hops(next_hops, 2);

    // 删除路由
    rte_fib_delete(fib, ip1, depth1);
    rte_fib_delete(fib, ip2, depth2);

    // 查找路由,查看默认下一跳
    rte_fib_lookup_bulk(fib, ips_to_lookup, next_hops, 2);
    print_next_hops(next_hops, 2);

    // 释放FIB
    rte_fib_free(fib);

    // 关闭DPDK环境
    rte_eal_cleanup();

    return 0;
}

输出结果

Next hop for IP 0: 1
Next hop for IP 1: 2
Next hop for IP 0: 0
Next hop for IP 1: 0

3.7 详细分析

LPM

  • 创建和配置:使用rte_lpm_create创建LPM表,并配置最大规则数和表大小。
  • 添加路由:使用rte_lpm_add添加路由条目。
  • 查找路由:使用rte_lpm_lookup_bulk进行批量查找。
  • 删除路由:使用rte_lpm_delete删除路由条目。

FIB

  • 创建和配置:使用rte_fib_create创建FIB,并配置FIB类型、默认下一跳和最大路由数。
  • 添加路由:使用rte_fib_add添加路由条目。
  • 查找路由:使用rte_fib_lookup_bulk进行批量查找。
  • 删除路由:使用rte_fib_delete删除路由条目。

使用场景和性能

  • LPM:适用于需要高效前缀匹配的场景,通常用于快速查找和路由决策。
  • FIB:适用于需要存储和查找完整路由信息的场景,提供更多的灵活性和功能。

LPM和FIB在很多方面功能重叠,但它们的实现细节和性能特性决定了它们的最佳应用场景。LPM专注于高效的前缀匹配,而FIB则提供了更完整的路由信息存储和查找能力。根据具体需求选择合适的技术,可以在性能和功能之间取得平衡。

  • 35
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

写一封情书

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

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

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

打赏作者

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

抵扣说明:

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

余额充值