tldk之tle简单记录

文章目录

  • 1.tle简介
  • 2.tle处理tcp
  • 3.tle处理udp
  • 4.tle封装包头

项目中遇到了tldk中tle的使用,不太熟悉,这里记录一下,方便以后回顾
tldk源码位置: tldk源码
简单理解:这里我们项目大概dpdk从网卡收到数据包之后,将需要处理的用户数据放入tle_stream中,再从tle数据中封装好数据头部信息并发送到dpdk网卡
项目中用到的函数:

uint16_t tle_udp_rx_bulk(struct tle_dev *dev, struct rte_mbuf *pkt[], struct rte_mbuf *rp[], int32_t rc[], uint16_t 
num);

功能:接收并分发一批输入的 UDP 数据包到相应的打开的 UDP 流。
参数

  • dev:UDP 设备。
  • pkt:输入数据包的数组。
  • rp:未处理数据包的数组。
  • rc:错误代码数组。
  • num:输入数据包数组的元素数量。
    返回值:成功分发到 UDP 流的数据包数量。
uint16_t tle_udp_stream_recv(struct tle_stream *s, struct rte_mbuf *pkt[], uint16_t num);

功能:接收来自指定 UDP 流的多个数据包。
参数

  • s:UDP 流。
  • pkt:接收数据包的数组。
  • num:接收数据包数组的元素数量。
    返回值:成功接收到的数据包数量。
uint16_t tle_udp_stream_send(struct tle_stream *s, struct rte_mbuf *pkt[], uint16_t num, const struct sockaddr *
dst_addr);

功能:发送多个数据包到指定的 UDP 流。
参数

  • s:UDP 流。
  • pkt:待发送的数据包数组。
  • num:待发送数据包数组的元素数量。
  • dst_addr:目标地址。
    返回值:成功排队等待发送的数据包数量。
uint16_t tle_udp_tx_bulk(struct tle_dev *dev, struct rte_mbuf *pkt[], uint16_t num);

功能:获取并填充准备发送的数据包。
参数

  • dev:UDP 设备。
  • pkt:输出数据包的数组。
  • num:输出数据包数组的元素数量。
    返回值:成功填充的数据包数量。

1.tle简介

这里直接上代码注释

/*
本文档简要描述了用于 L4 数据包处理库(UDP 和 TCP)的公共 API。
目的是使配置 API(上下文创建/删除,添加/删除设备等)对所有支持的 L4 协议通用。
后端(BE)数据路径和前端(FE)API 不同,但尽可能保留相似的语法(和语义)。
*/tle_ctx.h
/**<tle_ctx> - 每个这样的 ctx 代表“独立的栈副本”。
它拥有 <stream> 和 <dev> 实体的集合,并提供将输入/输出数据包从设备(解)复用到流中/
流出的功能。<dev> 是对底层设备的抽象,能够接收/发送数据包,并且可能提供一些硬件卸载功能。
用户有责任在开始对上下文进行流操作(打开/发送/接收/
关闭)之前,将上下文需要管理的所有 <dev> 添加到 <ctx> 中。目前不支持在上下文中存在打开的流时添加/删除 <dev>。
<stream> 代表一个 L4(UDP/TCP 等)端点 <地址, 端口>,类似于套接字实体。
与套接字一样,可以通过它进行接收/发送操作。
<stream> 属于特定的 <ctx>
,但在整个进程中是全局可见的,即进程中的任何线程都可以在没有进一步同步的情况下通过它进行接收/发送操作。
虽然“上层”API 是线程安全的,但底层 API(rx_bulk/
tx_bulk)不是线程安全的,不应在多个线程上并行运行。因此,单个线程可以驱动多个 <ctx> 并进行 IO 
操作,但多个线程不能在没有某些显式同步的情况下驱动相同的 <ctx>。**/
struct tle_ctx;
struct tle_dev;
/*
设备参数。
*/
struct tle_dev_param {
uint32_t rx_offload; /**< 支持 DEV_RX_OFFLOAD_。 */
uint32_t tx_offload; /**< 支持 DEV_TX_OFFLOAD_。 */
struct in_addr local_addr4; /*< 分配的本地 IPv4 地址。 */
struct in6_addr local_addr6; /*< 分配的本地 IPv6 地址。 */
uint32_t nb_bl_ports; /*< 被阻止的端口数量。 */
uint16_t *bl_ports; /*< 被阻止的端口列表。 */
};
#define TLE_DST_MAX_HDR 0x60
struct tle_dest {
struct rte_mempool *head_mp; /*< 用于碎片头和控制数据包的 MP。 */
struct tle_dev *dev; /*< 用于发送数据包的设备。 */
uint16_t mtu; /*< 给定目的地的 MTU。 */
uint8_t l2_len; /*< L2 头的长度。 */
uint8_t l3_len; /*< L3 头的长度。 */
uint8_t hdr[TLE_DST_MAX_HDR]; /*< L2/L3 头。 */
};/*** 上下文创建参数。*/
enum { TLE_PROTO_UDP,TLE_PROTO_TCP,TLE_PROTO_NUM 
};struct tle_ctx_param { int32_t socket_id;         /**< 分配内存的套接字 ID。 */ uint32_t proto;            /**< 要处理的 L4 协议。 */uint32_t max_streams;      /**< 上下文中的最大流数。 */ uint32_t max_stream_rbufs; /**< 每个流的最大接收 mbuf 数。 */uint32_t max_stream_sbufs; /**< 每个流的最大发送 mbuf 数。 */uint32_t send_bulk_size;   /**< 每次发送调用的预期数据包数。 */int (*lookup4)(void *opaque, const struct in_addr *addr, struct tle_dest *res); /**< 由 send() 调用以获取 
IPv4 数据包的目的地信息。 */ void *lookup4_data;        /**< lookup4() 回调的非透明数据指针。 */int (*lookup6)(void *opaque, const struct in6_addr *addr, struct tle_dest *res); /**< 由 send() 调用以获取 
IPv6 数据包的目的地信息。 */ void *lookup6_data;        /**< lookup6() 回调的非透明数据指针。 */ 
};/*** 创建 L4 处理上下文。* @param ctx_prm*   用于创建和初始化 L4 上下文的参数。* @return*   可用于将来操作的上下文结构指针,或错误时返回 NULL,并在 rte_errno 
中设置错误代码。*   *   可能的 rte_errno 错误包括:*   - EINVAL - 传递给函数的参数无效*   - ENOMEM - 内存不足*/ 
struct tle_ctx * tle_ctx_create(const struct tle_ctx_param *ctx_prm);/*** 销毁给定的上下文。** @param ctx*   要销毁的上下文*/ 
void tle_ctx_destroy(struct tle_ctx *ctx);/*** 在给定上下文中添加新设备。* 该函数不是多线程安全的。** @param ctx*   要添加新设备的上下文。* @param dev_prm*   用于在上下文中创建和初始化新设备的参数。* @return*   可用于将来操作的设备结构指针,或错误时返回 NULL,并在 rte_errno 中设置错误代码。*   可能的 rte_errno 错误包括:*   - EINVAL - 传递给函数的参数无效*   - ENODEV - 已达到打开设备的最大可能值*   - ENOMEM - 内存不足*/ 
struct tle_dev * tle_add_dev(struct tle_ctx *ctx, const struct tle_dev_param *dev_prm);/*** 从给定上下文中移除并销毁先前添加的设备。* 该函数不是多线程安全的。** @param dev*   要移除和销毁的设备。* @return*   成功完成返回零。*   - -EINVAL - 传递给函数的参数无效*/ 
int tle_del_dev(struct tle_dev *dev);/*** 向上下文标记目的地信息可能已更改,* 因此如果它缓存了任何目的地数据,则必须将其无效化。* @param ctx*   要无效化的上下文。*/ 
void tle_ctx_invalidate(struct tle_ctx *ctx);/*** 流的异步通知机制:* a) 接收/发送回调。* 流的接收/发送通知回调行为是边沿触发(ET)。* 如果流接收缓冲区为空并且有新数据包到达,接收回调将被调用。* 
当流发送缓冲区已满,并且属于该流的一些数据包已发送(发送缓冲区的一部分再次变为�
�闲)时,将调用发送回调。* 
请注意,接收和发送回调都是在持有该流的某种读锁的情况下调用的。因此在回调函数中�
�用 stream_close() 是不允许的,这会导致死锁。* 虽然允许在回调中调用流发送/接收函数,但不推荐这样做:回调函数将在 tle_udp_rx_bulk/
tle_udp_tx_bulk 
上下文中被调用,回调函数中的一些繁重处理可能会导致性能下降甚至丢失进一步流的数�
�包。* b) 接收/发送事件。* 流的接收/发送事件行为是电平触发(LT)。* 只要流接收缓冲区内有任何剩余数据包,接收事件将由 tle_udp_rx_burst() 或 tle_udp_stream_recv
() 触发。* 只要流发送缓冲区内有任何空闲空间,发送事件将由 tle_udp_tx_burst() 或 tle_udp_stream_send() 
触发。* 请注意,回调和事件在 <stream, op> 基础上是互斥的。* 不可能在指定接收事件和回调的情况下打开流。* 虽然可以在指定接收回调和发送事件或反之的情况下打开流。* 如果用户不需要该流的任何通知机制,事件和回调都可以设置为零。*/
struct tle_event; 
struct tle_stream;/*** 流的接收/发送回调函数和数据。*/
struct tle_stream_cb { void (*func)(void *, struct tle_stream *); void *data; 
};
2. tle_tcp.h
------------
/*** TCP 流创建参数。*/
struct tle_tcp_stream_param {struct sockaddr_storage local_addr;  /**< 流本地地址。 */struct sockaddr_storage remote_addr; /**< 流远程地址。 */uint64_t linger_cycles;  /**< 延迟的周期数。 */uint32_t nb_retries;     /**< 最大重传尝试次数。 *//* _cb 和 _ev 是互斥的 */struct tle_event *err_ev;      /**< 使用的错误事件。 */struct tle_stream_cb err_cb;   /**< 使用的错误回调。 */struct tle_event *recv_ev;      /**< 使用的接收事件。 */struct tle_stream_cb recv_cb;   /**< 使用的接收回调。 */struct tle_event *send_ev;      /**< 使用的发送事件。 */struct tle_stream_cb send_cb;   /**< 使用的发送回调。 */
};/*** 在给定的 TCP 上下文中创建一个新流。* @param ctx*   要在其中创建新流的 TCP 上下文。* @param prm*   用于创建和初始化新流的参数。* @return*   可以在将来的 TCP API 调用中使用的 TCP 流结构指针,*   或错误时返回 NULL,并在 rte_errno 中设置错误代码。*   可能的 rte_errno 错误包括:*   - EINVAL - 传递给函数的参数无效*   - ENOFILE - 上下文中打开流的最大限制已达到*/
struct tle_stream * tle_tcp_stream_open(struct tle_ctx *ctx, const struct tle_tcp_stream_param *prm);/*** 关闭一个已打开的流。* 如果流处于连接状态,则:* - 将执行连接终止。* - 如果流包含未发送的数据,则实际关闭将被推迟,*   直到剩余数据被发送或延迟超时过期。* 所有属于该流并保留在设备 TX 队列中的数据包将被保留以供以后发送。* @param s*   要关闭的流的指针。* @return*   成功完成返回零。*   - -EINVAL - 传递给函数的参数无效*/
int tle_tcp_stream_close(struct tle_stream *s);/*** 获取打开流的参数。* @param s*   流的指针。* @return*   成功完成返回零。*   - EINVAL - 传递给函数的参数无效*/
int tle_tcp_stream_get_param(const struct tle_stream *s, struct tle_tcp_stream_param *prm);/*** 中止连接并关闭一个已打开的流。* 如果流处于连接状态,则:* 丢弃所有排队的数据并向对等端发送重置段。* 所有属于该流并保留在设备 TX 队列中的数据包将被保留以供以后发送。* @param s*   要中止的流的指针。* @return*   成功完成返回零。*   - -EINVAL - 传递给函数的参数无效*/
int tle_tcp_stream_abort(struct tle_stream *s);/*** 客户端模式连接 API。*/
/*** 尝试与目标 TCP 端点建立连接。* 如果连接成功建立,将触发流写入事件(或回调)。* 请注意,处于监听状态的流或已建立连接的流不能进行 connect() 调用。* 如果尝试失败,将激活错误事件(或回调)。* @param s*   流的指针。* @param addr*   目标端点的地址。* @return*   成功完成返回零。*   - -EINVAL - 传递给函数的参数无效*/
int tle_tcp_stream_connect(struct tle_stream *s, const struct sockaddr *addr);/** 服务器模式连接 API。* 服务器模式 API 使用的基本方案:** <stream 打开在此处进行>* tle_tcp_stream_listen(stream_to_listen);* <等待该流上的读取事件/回调>* n = tle_tcp_synreqs(stream_to_listen, syn_reqs, sizeof(syn_reqs));* for (i = 0, k = 0; i != n; i++) {*     rc = <决定是否允许来自该端点的连接>;*     if (rc == 0) {*         // 继续进行连接建立*         k++;*         accept_param[k].syn = syn_reqs[i];*         <为第 k 个连接填充 accept_param 其他字段>*     } else {*         // 静默忽略来自该端点的连接请求*         rte_pktmbuf_free(syn_reqs[i]);*     }* }* // 接受 k 个新连接* rc = tle_tcp_accept(stream_to_listen, accept_param, new_con_streams, k);* <处理错误>*/
/*** 将流设置为监听状态(被动打开),即使流准备接受新连接。* 当有新的 SYN 请求到达时,将激活流读取事件(或回调)。* 请注意,已建立(或正在建立)连接的流不能进行 listen() 调用。* @param s*   流的指针。* @return*   成功完成返回零。*   - -EINVAL - 传递给函数的参数无效*/
int tle_tcp_stream_listen(struct tle_stream *s);/*** 返回最多 *num* 个包含给定 TCP 端点接收的 SYN 请求的 mbuf。* 请注意,流必须处于监听状态。* 对于每个返回的 mbuf:* data_off 设置为数据包的起始位置* l2_len、l3_len、l4_len 设置为适当的值* (因此用户仍然可以在需要时提取 L2/L3/L4 头信息)* packet_type 的 RTE_PTYPE_L2/L3/L4 位设置为适当的值。* L3/L4 校验和已验证。* @param s*   接收数据包的 TCP 流。* @param pkt*   一个指向 *rte_mbuf* 结构的指针数组,*   必须足够大以存储最多 *num* 个指针。* @param num*   *pkt* 数组中的元素数量。* @return*   在 *pkt* 数组中填充的条目数量。*/
uint16_t tle_tcp_stream_synreqs(struct tle_stream *s, struct rte_mbuf *pkt[], uint32_t num);struct tle_tcp_accept_param {struct rte_mbuf *syn;  /**< 包含传入 SYN 请求的 mbuf。 */struct tle_tcp_stream_param prm; /**< 流打开参数。 */
};/*** 接受给定流的连接请求。* 请注意,流必须处于侦听状态。* 对于每个新连接,将打开一个新流。* @param s*   TCP 侦听流。* @param prm*   包含至少 *num* 个元素的 *tle_tcp_accept_param* 结构数组。* @param pkt*   一个指向 *tle_stream* 结构的指针数组,该数组必须足够大以存储最多 *num* 个指针。* @param num*   *prm* 和 *rs* 数组中的元素数量。* @return*   填充在 *rs* 数组中的条目数量。*   错误情况下,在 rte_errno 中设置错误代码。*   可能的 rte_errno 错误包括:*   - EINVAL - 传递给函数的参数无效*   - ENFILE - 无法打开更多流。*/
int tle_tcp_stream_accept(struct tle_stream *s, const struct tle_tcp_accept_param prm[], struct tle_stream *rs[], 
uint32_t num);/*** 返回为给定 TCP 流接收到的最多 *num* 个 mbuf。* 请注意,流必须处于连接状态。* 数据顺序被保留。* 对于每个返回的 mbuf:* data_off 设置为数据包的 TCP 数据起始位置* l2_len、l3_len、l4_len 设置正确* (因此用户仍然可以在需要时提取 L2/L3 地址信息)* packet_type RTE_PTYPE_L2/L3/L4 位设置正确。* 已验证 L3/L4 校验和。* @param s*   接收数据包的 TCP 流。* @param pkt*   一个指向 *rte_mbuf* 结构的指针数组,该数组必须足够大以存储最多 *num* 个指针。* @param num*   *pkt* 数组中的元素数量。* @return*   填充在 *pkt* 数组中的条目数量。*/
uint16_t tle_tcp_stream_recv(struct tle_stream *s, struct rte_mbuf *pkt[], uint16_t num);/*** 消耗并排队最多 *num* 个数据包,这些数据包将最终由 tle_tcp_tx_bulk() 发送。* 请注意,流必须处于连接状态。* 该函数负责确定给定数据包要通过哪个 TCP 设备发送,并进行必要的准备。* 根据 *dst_addr* 执行路由查找,填写 L2/L3/L4 头,并在必要时对数据包进行分片。* 根据底层设备信息,它要么在软件中执行 IP/TCP 校验和计算,要么正确设置 mbuf TX 
校验和卸载字段。* 对于每个输入 mbuf,必须满足以下条件:* - data_off 指向数据包的 TCP 数据起始位置。* - 有足够的头部空间预先添加 L2/L3/L4 头。* @param s*   用于发送数据包的 TCP 流。* @param pkt*   需要发送的输出数据包。* @param num*   *pkt* 数组中的元素数量。* @return*   成功排队到流发送缓冲区中的数据包数量。*/
uint16_t tle_tcp_stream_send(struct tle_stream *s, struct rte_mbuf *pkt[], uint16_t num);/*** 从给定的 TCP 流中读取最多 *iovcnt* 个缓冲区。* 请注意,流必须处于连接状态。* @param s*   用于读取数据的 TCP 流。* @param iov*   一个包含 *iovec* 结构的数组,该数组必须足够大以存储最多 *iovcnt* 个元素。* @param iovcnt*   *iov* 数组中的元素数量。* @return*   成功完成时读取的字节数。*   - EINVAL - 传递给函数的参数无效*   - ENOTCONN - 流未连接*/
ssize_t tle_tcp_readv(struct tle_stream *s, const struct iovec iov[], int iovcnt);/*** 向给定的 TCP 流写入最多 *iovcnt* 个缓冲区。* 请注意,流必须处于连接状态。* @param s*   用于写入数据的 TCP 流。* @param mp*   用于分配 mbuf 的内存池。* @param iov*   一个包含 *iovec* 结构的数组,该数组必须足够大以存储最多 *iovcnt* 个元素。* @param iovcnt*   *iov* 数组中的元素数量。* @return*   成功完成时写入的字节数。*   - EINVAL - 传递给函数的参数无效*   - ENOTCONN - 流未连接*/
ssize_t tle_tcp_writev(struct tle_stream *s, struct rte_mempool *mp, const struct iovec iov[], int iovcnt);/*** 后端 (BE) API。* BE API 函数不是多线程安全的。* 应由 L2/L3 处理层调用。*/
/*** 获取输入的 mbuf 并将它们分配给打开的 TCP 流。* 期望每个输入数据包:* - l2_len、l3_len、l4_len 设置正确* - (packet_type & (RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L3_IPV6)) != 0,* - (packet_type & RTE_PTYPE_L4_TCP) != 0,* 在传递过程中将验证 L3/L4 校验和* (要么依赖于硬件卸载,要么在软件中验证)。* 可能会导致一些额外的数据包排队等待 TX。* 此函数不是多线程安全的。* @param dev*   接收数据包的 TCP 设备。* @param pkt*   需要处理的输入数据包。* @param rp*   返回时将包含未处理数据包指针的数组。*   应包含至少 *num* 个元素。* @param rc*   将包含相应 rp[] 条目的错误代码的数组:*   - ENOENT - 没有匹配此数据包的打开流。*   - ENOBUFS - 目标流的接收缓冲区已满。*   应包含至少 *num* 个元素。* @param num*   *pkt* 输入数组中的元素数量。* @return*   传递到 TCP 流的数据包数量。*/
uint16_t tle_tcp_rx_bulk(struct tle_dev *dev, struct rte_mbuf *pkt[], struct rte_mbuf *rp[], int32_t rc[], uint16_t 
num);/*** 用指向要通过给定 TCP 设备传输的数据包的指针填充 *pkt*。* 输出数据包必须准备好直接传递给 rte_eth_tx_burst(),无需额外处理。* TCP/IPv4 校验和已计算,或适当的 mbuf 字段已正确设置以进行硬件卸载。* 此函数不是多线程安全的。* @param dev*   传输输出数据包的 TCP 设备。* @param pkt*   一个指向 *rte_mbuf* 结构的指针数组,该数组必须足够大以存储最多 *num* 个指针。* @param num*   *pkt* 数组中的元素数量。* @return*   填充在 *pkt* 数组中的条目数量。*/
uint16_t tle_tcp_tx_bulk(struct tle_dev *dev, struct rte_mbuf *pkt[], uint16_t num);/*** 对给定的 TCP 上下文执行内部处理。* 检查哪些定时器已过期并执行所需的操作* (重传/连接中止等)。* 可能会导致一些额外的数据包排队等待 TX。* 此函数不是多线程安全的。* @param ctx*   要处理的 TCP 上下文。* @return*   成功完成返回零。*   - EINVAL - 传递给函数的参数无效*/
int tle_tcp_process(struct tle_ctx *ctx);/*** UDP 流创建参数。*/
struct tle_udp_stream_param {struct sockaddr_storage local_addr;  /**< 流的本地地址。 */struct sockaddr_storage remote_addr; /**< 流的远程地址。 *//* _cb 和 _ev 是互斥的 */struct tle_event *recv_ev;           /**< 接收事件。 */struct tle_stream_cb recv_cb;        /**< 接收回调。 */struct tle_event *send_ev;           /**< 发送事件。 */struct tle_stream_cb send_cb;        /**< 发送回调。 */
};/*** 在给定的 UDP 上下文中创建新流。* @param ctx*   创建新流的 UDP 上下文。* @param prm*   用于创建和初始化新流的参数。* @return*   指向 UDP 流结构的指针,可在将来的 UDP API 调用中使用,*   出错时返回 NULL,并在 rte_errno 中设置错误代码。*   可能的 rte_errno 错误包括:*   - EINVAL - 传递给函数的参数无效*   - ENOFILE - 该上下文的打开流的最大限制已达到*/
struct tle_stream * tle_udp_stream_open(struct tle_ctx *ctx, const struct tle_udp_stream_param *prm);/*** 关闭打开的流。* 所有仍保留在流接收缓冲区中的数据包将被释放。* 所有仍保留在流传输缓冲区中的数据包将被保留以供将来传输。* @param s*   指向要关闭的流的指针。* @return*   成功完成返回零。*   - -EINVAL - 传递给函数的参数无效*/
int tle_udp_stream_close(struct tle_stream *s);/*** 获取打开的流参数。* @param s*   指向流的指针。* @param prm*   用于存储流参数的结构。* @return*   成功完成返回零。*   - EINVAL - 传递给函数的参数无效*/
int tle_udp_stream_get_param(const struct tle_stream *s, struct tle_udp_stream_param *prm);/*** 获取输入的 mbuf 并将它们分配给打开的 UDP 流。* 期望每个输入数据包:* - l2_len、l3_len、l4_len 设置正确* - (packet_type & (RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L3_IPV6)) != 0,* - (packet_type & RTE_PTYPE_L4_UDP) != 0,* 在传递过程中将验证 L3/L4 校验和* (要么依赖于硬件卸载,要么在软件中验证)。* 此函数不是多线程安全的。* @param dev*   接收数据包的 UDP 设备。* @param pkt*   需要处理的输入数据包。* @param rp*   返回时将包含未处理数据包指针的数组。*   应包含至少 *num* 个元素。* @param rc*   将包含相应 rp[] 条目的错误代码的数组:*   - ENOENT - 没有匹配此数据包的打开流。*   - ENOBUFS - 目标流的接收缓冲区已满。*   应包含至少 *num* 个元素。* @param num*   *pkt* 输入数组中的元素数量。* @return*   传递到 UDP 流的数据包数量。*/
uint16_t tle_udp_rx_bulk(struct tle_dev *dev, struct rte_mbuf *pkt[], struct rte_mbuf *rp[], int32_t rc[], uint16_t 
num);/*** 用指向要通过给定 UDP 设备传输的数据包的指针填充 *pkt*。* 输出数据包必须准备好直接传递给 rte_eth_tx_burst(),无需额外处理。* UDP/IPv4 校验和已计算,或适当的 mbuf 字段已正确设置以进行硬件卸载。* 此函数不是多线程安全的。* @param dev*   传输输出数据包的 UDP 设备。* @param pkt*   一个指向 *rte_mbuf* 结构的指针数组,该数组必须足够大以存储最多 *num* 个指针。* @param num*   *pkt* 数组中的元素数量。* @return*   填充在 *pkt* 数组中的条目数量。*/
uint16_t tle_udp_tx_bulk(struct tle_dev *dev, struct rte_mbuf *pkt[], uint16_t num);/*** 返回为给定 UDP 流接收到的最多 *num* 个 mbuf。* 对于每个返回的 mbuf:* data_off 设置为数据包的 UDP 数据起始位置* l2_len、l3_len、l4_len 设置正确* (因此用户仍然可以在需要时提取 L2/L3 地址信息)* packet_type RTE_PTYPE_L2/L3/L4 位设置正确。* 已验证 L3/L4 校验和。* 数据包具有无效的 L3/L4 校验和将被默默丢弃。* @param s*   接收数据包的 UDP 流。* @param pkt*   一个指向 *rte_mbuf* 结构的指针数组,该数组必须足够大以存储最多 *num* 个指针。* @param num*   *pkt* 数组中的元素数量。* @return*   填充在 *pkt* 数组中的条目数量。*/
uint16_t tle_udp_stream_recv(struct tle_stream *s, struct rte_mbuf *pkt[], uint16_t num);/*** 消耗并排队最多 *num* 个数据包,这些数据包将最终由 tle_udp_tx_bulk() 发送。* 如果 *dst_addr* 为 NULL,则将使用与该流关联的默认远程地址(如果有)。* 该函数的主要目的是确定给定数据包要通过哪个 UDP 设备发送,并进行必要的准备。* 根据 *dst_addr* 执行路由查找,填写 L2/L3/L4 头,并在必要时对数据包进行分片。* 根据底层设备信息,它要么在软件中执行 IP/UDP 校验和计算,要么正确设置 mbuf TX 
校验和卸载字段。* 对于每个输入 mbuf,必须满足以下条件:* - data_off 指向数据包的 UDP 数据起始位置。* - 有足够的头部空间预先添加 L2/L3/L4 头。* @param s*   用于发送数据包的 UDP 流。* @param pkt*   需要发送的输出数据包。* @param num*   *pkt* 数组中的元素数量。* @param dst_addr*   要发送数据包的目标地址。* @return*   成功排队到流发送缓冲区中的数据包数量。*/
uint16_t tle_udp_stream_send(struct tle_stream *s, struct rte_mbuf *pkt[], uint16_t num, const struct sockaddr *
dst_addr);

2.tle处理tcp

以下是一个使用TLE库进行TCP连接管理和数据传输的示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rte_eal.h>
#include <rte_mbuf.h>
#include <tle_tcp.h>
#include <tle_event.h>// 回调函数,用于处理接收的数据包
void recv_callback(struct tle_stream *s, struct rte_mbuf *pkt[], uint16_t num)
{for (uint16_t i = 0; i < num; i++) {// 处理接收到的数据包char *data = rte_pktmbuf_mtod(pkt[i], char *);printf("Received data: %s\n", data);// 释放mbufrte_pktmbuf_free(pkt[i]);}
}int main(int argc, char **argv)
{// 初始化环境抽象层(EAL)if (rte_eal_init(argc, argv) < 0) {rte_exit(EXIT_FAILURE, "EAL init failed\n");}// 创建TCP上下文struct tle_ctx_param ctx_prm = {0};struct tle_ctx *ctx = tle_ctx_create(&ctx_prm);if (ctx == NULL) {rte_exit(EXIT_FAILURE, "Context creation failed\n");}// 创建TCP监听流struct tle_tcp_stream_param listen_prm = {0};struct tle_stream *listen_stream = tle_tcp_stream_open(ctx, &listen_prm);if (listen_stream == NULL) {rte_exit(EXIT_FAILURE, "Stream open failed\n");}// 设置回调函数struct tle_event recv_event = {0};recv_event.data.stream = listen_stream;recv_event.cb.func = (tle_event_cb)recv_callback;// 添加监听事件if (tle_event_add(ctx, &recv_event) < 0) {rte_exit(EXIT_FAILURE, "Event add failed\n");}// 主循环,等待事件触发while (1) {// 处理事件tle_event_process(ctx);}// 关闭流和上下文tle_tcp_stream_close(listen_stream);tle_ctx_destroy(ctx);return 0;
}

代码说明

  • 初始化环境抽象层(EAL):TLE库依赖于DPDK(Data Plane Development Kit),需要首先初始化EAL。
  • 创建TCP上下文:调用 tle_ctx_create 创建一个TCP上下文,用于管理TCP连接。
  • 创建TCP监听流:调用 tle_tcp_stream_open 创建一个监听流,用于监听新的TCP连接请求。
  • 设置回调函数:定义一个回调函数 recv_callback,用于处理接收到的数据包。并将回调函数与事件关联。
  • 添加监听事件:调用 tle_event_add 将监听事件添加到上下文中。
  • 主循环:在主循环中调用 tle_event_process 处理事件,等待并处理接收到的数据包。
  • 关闭流和上下文:当不再需要时,关闭TCP流并销毁上下文。

3.tle处理udp

以下是一个使用TLE库进行UDP连接管理和数据传输的示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rte_eal.h>
#include <rte_mbuf.h>
#include <tle_udp.h>
#include <tle_event.h>// 回调函数,用于处理接收的数据包
void recv_callback(struct tle_stream *s, struct rte_mbuf *pkt[], uint16_t num)
{for (uint16_t i = 0; i < num; i++) {// 处理接收到的数据包char *data = rte_pktmbuf_mtod(pkt[i], char *);printf("Received data: %s\n", data);// 释放mbufrte_pktmbuf_free(pkt[i]);}
}int main(int argc, char **argv)
{// 初始化环境抽象层(EAL)if (rte_eal_init(argc, argv) < 0) {rte_exit(EXIT_FAILURE, "EAL init failed\n");}// 创建UDP上下文struct tle_ctx_param ctx_prm = {0};struct tle_ctx *ctx = tle_ctx_create(&ctx_prm);if (ctx == NULL) {rte_exit(EXIT_FAILURE, "Context creation failed\n");}// 创建UDP流参数struct tle_udp_stream_param stream_prm = {0};// 设置本地地址和端口struct sockaddr_in *local_addr = (struct sockaddr_in *)&stream_prm.local_addr;local_addr->sin_family = AF_INET;local_addr->sin_addr.s_addr = htonl(INADDR_ANY); // 监听所有本地地址local_addr->sin_port = htons(12345); // 设置本地端口为12345// 设置回调函数stream_prm.recv_cb.func = (tle_stream_cb)recv_callback;// 创建UDP流struct tle_stream *udp_stream = tle_udp_stream_open(ctx, &stream_prm);if (udp_stream == NULL) {rte_exit(EXIT_FAILURE, "Stream open failed\n");}// 主循环,等待事件触发while (1) {// 处理接收数据包struct rte_mbuf *pkts[32];uint16_t nb_rx = tle_udp_stream_recv(udp_stream, pkts, 32);if (nb_rx > 0) {// 调用回调函数处理接收的数据包recv_callback(udp_stream, pkts, nb_rx);}}// 关闭流和上下文tle_udp_stream_close(udp_stream);tle_ctx_destroy(ctx);return 0;
}

代码说明

  • 初始化环境抽象层(EAL):TLE库依赖于DPDK(Data Plane Development Kit),需要首先初始化EAL。

  • 创建UDP上下文:调用 tle_ctx_create 创建一个UDP上下文,用于管理UDP连接。

  • 创建UDP流参数:设置UDP流的参数,包括本地地址和端口,以及接收回调函数。

  • 设置本地地址和端口:通过 struct sockaddr_in 设置本地地址为 INADDR_ANY(监听所有本地地址),并设置本地端口为12345。

  • 设置回调函数:定义一个回调函数 recv_callback,用于处理接收到的数据包,并将回调函数与接收事件关联。

  • 创建UDP流:调用 tle_udp_stream_open 创建一个UDP流,用于接收和发送UDP数据包。

  • 主循环:在主循环中调用 tle_udp_stream_recv 接收数据包,并调用回调函数 recv_callback 处理接收到的数据包

  • 关闭流和上下文:当不再需要时,关闭UDP流并销毁上下文。

这个示例代码展示了如何使用TLE库进行UDP数据包的接收和处理。通过设置回调函数,接收到的数据包会被自动传递到回调函数进行处理。TLE库简化了UDP连接的管理和数据传输,使得开发高性能的网络应用程序变得更加容易。

4.tle封装包头

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rte_eal.h>
#include <rte_mbuf.h>
#include <tle_udp.h>
#include <tle_event.h>// 自定义包头结构
struct custom_header {uint32_t id;uint32_t length;
};// 回调函数,用于处理接收的数据包并添加自定义包头
void recv_callback(struct tle_stream *s, struct rte_mbuf *pkt[], uint16_t num)
{for (uint16_t i = 0; i < num; i++) {// 获取接收到的数据char *data = rte_pktmbuf_mtod(pkt[i], char *);uint16_t data_len = rte_pktmbuf_data_len(pkt[i]);// 分配新的mbuf来存储带有自定义包头的数据包struct rte_mbuf *new_pkt = rte_pktmbuf_alloc(pkt[i]->pool);if (new_pkt == NULL) {printf("Failed to allocate new mbuf\n");rte_pktmbuf_free(pkt[i]);continue;}// 添加自定义包头struct custom_header *hdr = (struct custom_header *)rte_pktmbuf_prepend(new_pkt, sizeof(struct custom_header));if (hdr == NULL) {printf("Failed to prepend custom header\n");rte_pktmbuf_free(pkt[i]);rte_pktmbuf_free(new_pkt);continue;}hdr->id = htonl(12345);  // 示例IDhdr->length = htonl(data_len);  // 数据长度// 复制接收到的数据到新的mbufchar *new_data = rte_pktmbuf_append(new_pkt, data_len);if (new_data == NULL) {printf("Failed to append data\n");rte_pktmbuf_free(pkt[i]);rte_pktmbuf_free(new_pkt);continue;}rte_memcpy(new_data, data, data_len);// 处理新的数据包printf("Added custom header and copied data. New packet length: %u\n", rte_pktmbuf_pkt_len(new_pkt));// 释放原来的mbufrte_pktmbuf_free(pkt[i]);// 假设发送或进一步处理新的数据包// 这里可以调用tle_udp_stream_send等函数发送新的数据包}
}int main(int argc, char **argv)
{// 初始化环境抽象层(EAL)if (rte_eal_init(argc, argv) < 0) {rte_exit(EXIT_FAILURE, "EAL init failed\n");}// 创建UDP上下文struct tle_ctx_param ctx_prm = {0};struct tle_ctx *ctx = tle_ctx_create(&ctx_prm);if (ctx == NULL) {rte_exit(EXIT_FAILURE, "Context creation failed\n");}// 创建UDP流参数struct tle_udp_stream_param stream_prm = {0};// 设置本地地址和端口struct sockaddr_in *local_addr = (struct sockaddr_in *)&stream_prm.local_addr;local_addr->sin_family = AF_INET;local_addr->sin_addr.s_addr = htonl(INADDR_ANY); // 监听所有本地地址local_addr->sin_port = htons(12345); // 设置本地端口为12345// 设置回调函数stream_prm.recv_cb.func = (tle_stream_cb)recv_callback;// 创建UDP流struct tle_stream *udp_stream = tle_udp_stream_open(ctx, &stream_prm);if (udp_stream == NULL) {rte_exit(EXIT_FAILURE, "Stream open failed\n");}// 主循环,等待事件触发while (1) {// 处理接收数据包struct rte_mbuf *pkts[32];uint16_t nb_rx = tle_udp_stream_recv(udp_stream, pkts, 32);if (nb_rx > 0) {// 调用回调函数处理接收的数据包recv_callback(udp_stream, pkts, nb_rx);}}// 关闭流和上下文tle_udp_stream_close(udp_stream);tle_ctx_destroy(ctx);return 0;
}

代码流程说明

  • 初始化环境抽象层(EAL):初始化DPDK的EAL。

  • 创建UDP上下文:调用 tle_ctx_create 创建一个UDP上下文。

  • 设置UDP流参数:配置UDP流参数,包括本地地址和端口,以及接收回调函数。

  • 创建UDP流:调用 tle_udp_stream_open 创建UDP流。

  • 回调函数 recv_callback:

  • 在接收数据包后,创建一个新的mbuf。

  • 在新的mbuf上添加自定义包头( struct custom_header )。

  • 将接收到的数据复制到新的mbuf中。

  • 处理新的数据包(可以是发送或进一步处理)。

  • 主循环:在主循环中不断接收数据包,并调用回调函数 recv_callback 进行处理。

  • 关闭流和上下文:当不再需要时,关闭UDP流并销毁上下文。

总结
这个示例展示了如何在接收数据包后,通过回调函数在数据包头部添加自定义包头,并处理新的数据包。TLE库通过这种方式简化了复杂的网络数据处理任务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/16371.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解决Jupyter运行代码显示Kernel Restarting的错误

在Jupyter notebook上运行代码时发现如下错误&#xff1a; 使用VS Code运行在日志表中发现错误存在&#xff1a; 它表明在初始化"libiomp5md.dll"库时发生问题&#xff0c;因为该库已经被初始化过了&#xff0c;这个错误可能是由于程序中重复初始化OpenMP库导致的&am…

深入探索C++ Vector容器:灵活的动态数组秘籍

目录 ​编辑 引言 一、初识vector&#xff1a;构造与初始化 二、动态管理&#xff1a;添加与删除元素 三、访问与遍历&#xff1a;多种方式直达元素 四、容量与大小&#xff1a;动态调整的艺术 五、进阶技巧&#xff1a;高效运用vector 结语 引言 在C编程的世界里&…

驱动命令之insmod depmod modprobe rmmod modinfo lsmod

insmod命令 insmod需指定所需加载模块的路径&#xff0c;且只加载所指定的模块&#xff0c;如果所指定的模块依赖于其他模块&#xff0c;insmod不会自动添加&#xff1b; 语法 insmod [-fkmpsvxX][-o <模块名称>][模块文件][符号名称 符号值] 参数说明&#xff1a; -f…

微信小程序如何跳转微信公众号

1. 微信小程序如何跳转微信公众号 1.2. 微信公众号配置 登录微信公众号&#xff0c;点击【小程序管理】&#xff1a;   点击【添加】&#xff1a;   点击【关联小程序】&#xff1a;   输入小程序进行关联&#xff1a; 1.2. 微信小程序配置 登录微信小程序&#xf…

vue-router配置路由重定向不生效问题

概述 在做前端vue项目测试时&#xff0c;发现在路由配置中配置访问地址“http://ip:port/” 重定向到某个地址时&#xff0c;界面没有显示重定向后的地址。 能保证的是我的vue写法绝对没错。 简要代码 App.vue: <template><div id"app"><rout…

SQL注释方法 -- 单行注释/多行注释

三种注释方法 # 注释同行后面的内容&#xff1b; /* */ 注释中间的内容&#xff0c;可多行&#xff1b; -- 行注释&#xff0c;-- 后必须加空格。 # 注释同行后面的内容&#xff1b;/* 注释中间的内容&#xff0c; 可多行&#xff1b; */ -- 行注释&#xff0c;-- 后…

Django之Ajax实战笔记--城市级联操作

1. 项目架构搭建 1.1 创建项目tpdemo,创建应用myapp # 创建项目框架tpdemo$ django-admin startproject tpdemo$ cd tpdemo# 在项目中创建一个myapp应用$ python manage.py startapp myapp# 创建模板目录$ mkdir templates$ mkdir templates/myapp$ cd ..$ tree tpdemotpdemo…

HTTP的由来以及发展史

HTML&HTML5的学习探索 01、Html的由来和发展史 01-01、Html的由来 HTML的英文全称是 Hypertext Marked Language&#xff0c;即超文本标记语言。HTML是由Web的发明者 Tim Berners-Lee&#xff08;蒂姆伯纳斯李&#xff09;于1990年创立的一种标记语言&#xff0c; 他是万…

Sip协议(一)

Sip协议(一) 本文主要介绍sip协议 1: 简介 ​ SIP&#xff08;Session Initiation Protocol&#xff0c;会话发起协议&#xff09;是一种应用层协议&#xff0c;它被广泛应用于VoIP&#xff08;Voice over Internet Protocol&#xff0c;互联网语音通信&#xff09;中。 ​…

返回枚举类给前端

1. 前言 在实际开发过程中&#xff0c;前端的下拉框或者单选按钮的内容通常的需要和后端匹配的&#xff0c;故一般会由后端将下拉框的内容或单选框的内容传给前端&#xff0c;而这些内容在后端一般是由枚举类存储的&#xff0c;如果后端直接返回枚举类&#xff0c;返回结果将会…

K-means聚类算法详细介绍

目录 &#x1f349;简介 &#x1f348;K-means聚类模型详解 &#x1f348;K-means聚类的基本原理 &#x1f348;K-means聚类的算法步骤 &#x1f348;K-means聚类的优缺点 &#x1f34d;优点 &#x1f34d;缺点 &#x1f348;K-means聚类的应用场景 &#x1f348;K-mea…

SQL Server2019安装步骤教程(图文)_最新教程

一、下载SQL Server2019 1.到微软官网下载SQL Server Developer版本&#xff0c;官网当前的2019版本下载需要注册账号。 不想注册的朋友&#xff0c;可以选择从网盘下载&#xff1a;点击此处直接下载 2.下载之后先解压&#xff0c;解压后执行exe安装程序。打开之后的界面如下…

学 Java 具体能干什么?

学习 Java 后&#xff0c;你可以从事许多不同的工作和项目&#xff0c;涵盖了广泛的应用领域。以下是一些具体的应用场景和工作方向&#xff1a; 1. 企业级应用开发 Java 是企业级应用开发的首选语言之一&#xff0c;特别适合开发大规模、分布式、多层次的企业应用程序。 Jav…

在UbuntuLinux系统上安装MySQL和使用

前言 最近开始计划在Ubuntu上写一个webserver的项目&#xff0c;看到一些比较好的类似的项目使用了MySQL&#xff0c;我就打算先把环境搞好跑一下试试&#xff0c;方便后面更进一步的学习。其实在本机windows上我已经有一个mysql&#xff0c;不过 在Unbuntu上安装MySQL 首先…

ai - RAG

RAG & web <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>ChatGPT 应用页面</title><…

1960-2022年世界银行WDI面板数据(1400+指标)

1960-2022年世界银行WDI面板数据&#xff08;1400指标&#xff09; 1、时间&#xff1a;1960-2022年 2、来源&#xff1a;世界银行WDI 指标&#xff1a;包括健康、公共部门、农业与农村发展、城市发展、基础设施、外债、性别、援助效率、教育、气候变化、环境、社会保护与劳…

【Python】机器学习中的过采样和欠采样:处理不平衡数据集的关键技术

原谅把你带走的雨天 在渐渐模糊的窗前 每个人最后都要说再见 原谅被你带走的永远 微笑着容易过一天 也许是我已经 老了一点 那些日子你会不会舍不得 思念就像关不紧的门 空气里有幸福的灰尘 否则为何闭上眼睛的时候 又全都想起了 谁都别说 让我一个人躲一躲 你的承诺 我竟然没怀…

【Vue2入门技能树】:Vue2项目从入门到放弃所遇到的问题汇总

1、body中自带 margin: 8px 的问题 解决办法&#xff1a;在 public 目录下的 index.html 中加入如下样式即可 <style>* {margin: 0;} </style>2、使用vue-router、vuex ①在项目所在文件夹下打开 cmd 终端&#xff0c;然后运行如下代码&#xff0c;等待安装 //…

【Python从入门到进阶】55、使用Python轻松操作Mysql数据库

一、引言 1、MySQL数据库简介 MySQL是一个开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它使用了一种名为Structured Query Language&#xff08;SQL&#xff09;的查询语言来管理数据。MySQL因其高性能、可扩展性、易用性和稳定性而广受欢迎&#x…

ARM+FPGA+NVIDIA AI摄像头软硬件定制

拥有资深ISP图像技术团队&#xff0c;是英伟达、地平线等合作伙伴&#xff0c;我们的团队掌握目前市面上大部分车载平台的ISP图像画质服务能力&#xff0c;能自主开发图像ISP和增强算法。我们具有多名经验丰富光学设计专家&#xff0c;掌握车载模组光学设计能力&#xff0c;资深…