rte_flow
它允许用户在网卡(NIC)上配置复杂的数据包过滤和处理规则,以实现高效的数据包分类和处理。rte_flow 可以用于各种网络应用场景,如防火墙、负载均衡、流量监控等。
rte_flow 的作用
数据包过滤:通过定义过滤规则,可以在网卡级别过滤不需要的数据包,从而减少 CPU 处理负载。
数据包分类:根据特定的规则将数据包分类到不同的队列或内存区域,以便进行进一步处理。
数据包转发:可以配置规则将数据包转发到指定的端口或队列,实现高效的数据包转发。
流量监控:通过定义规则,可以监控特定类型的数据包流量,实现流量统计和分析。
#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_flow.h>
#include <stdio.h>
#define PORT_ID 0
int main(int argc, char **argv) {
struct rte_flow_error error;
struct rte_flow_attr attr;
struct rte_flow_item pattern[4];
struct rte_flow_action action[2];
struct rte_flow *flow;
struct rte_eth_conf port_conf = {0};
// 初始化 DPDK 环境
if (rte_eal_init(argc, argv) < 0)
rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
// 配置并启动以太网设备
if (rte_eth_dev_configure(PORT_ID, 1, 1, &port_conf) < 0)
rte_exit(EXIT_FAILURE, "Error configuring Ethernet device\n");
if (rte_eth_dev_start(PORT_ID) < 0)
rte_exit(EXIT_FAILURE, "Error starting Ethernet device\n");
// 配置流属性
memset(&attr, 0, sizeof(struct rte_flow_attr));
attr.ingress = 1;
// 配置流模式(匹配特定 IP 地址)
struct rte_flow_item_eth eth_spec = {
.hdr = {
.dst_addr = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55},
},
};
struct rte_flow_item_eth eth_mask = {
.hdr = {
.dst_addr = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
},
};
struct rte_flow_item_ipv4 ipv4_spec = {
.hdr = {
.src_addr = rte_cpu_to_be_32(0xC0A80002), // 192.168.0.2
},
};
struct rte_flow_item_ipv4 ipv4_mask = {
.hdr = {
.src_addr = 0xFFFFFFFF,
},
};
memset(pattern, 0, sizeof(pattern));
pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
pattern[0].spec = ð_spec;
pattern[0].mask = ð_mask;
pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
pattern[1].spec = &ipv4_spec;
pattern[1].mask = &ipv4_mask;
pattern[2].type = RTE_FLOW_ITEM_TYPE_TCP;
pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
// 配置流动作(丢弃数据包)
memset(action, 0, sizeof(action));
action[0].type = RTE_FLOW_ACTION_TYPE_DROP;
action[1].type = RTE_FLOW_ACTION_TYPE_END;
// 创建流规则
flow = rte_flow_create(PORT_ID, &attr, pattern, action, &error);
if (!flow) {
printf("Flow creation failed: %s\n", error.message);
return -1;
}
printf("Flow created successfully\n");
// 主循环
while (1) {
// 在此处理数据包
// 根据业务需求动态删除过滤规则
// 示例:在特定条件下删除过滤规则
if (/* 条件满足 */) {
if (rte_flow_destroy(PORT_ID, flow, &error) < 0) {
printf("Flow destruction failed: %s\n", error.message);
return -1;
}
printf("Flow destroyed successfully\n");
break;
}
}
// 销毁流规则
if (rte_flow_destroy(PORT_ID, flow, &error) < 0) {
printf("Flow destruction failed: %s\n", error.message);
return -1;
}
printf("Flow destroyed successfully\n");
// 停止并关闭以太网设备
rte_eth_dev_stop(PORT_ID);
rte_eth_dev_close(PORT_ID);
return 0;
}
常见的 RTE_FLOW_ITEM_TYPE_ 类型
RTE_FLOW_ITEM_TYPE_END:表示匹配模式的结束。
RTE_FLOW_ITEM_TYPE_VOID:表示忽略此项,不参与匹配。
RTE_FLOW_ITEM_TYPE_INVERT:表示反转匹配结果。
RTE_FLOW_ITEM_TYPE_ANY:匹配任意数据包。
RTE_FLOW_ITEM_TYPE_RAW:匹配原始字节流。
RTE_FLOW_ITEM_TYPE_ETH:匹配以太网帧。
RTE_FLOW_ITEM_TYPE_VLAN:匹配 VLAN 标签。
RTE_FLOW_ITEM_TYPE_IPV4:匹配 IPv4 数据包。
RTE_FLOW_ITEM_TYPE_IPV6:匹配 IPv6 数据包。
RTE_FLOW_ITEM_TYPE_ICMP:匹配 ICMP 数据包。
RTE_FLOW_ITEM_TYPE_UDP:匹配 UDP 数据包。
RTE_FLOW_ITEM_TYPE_TCP:匹配 TCP 数据包。
RTE_FLOW_ITEM_TYPE_SCTP:匹配 SCTP 数据包。
RTE_FLOW_ITEM_TYPE_GRE:匹配 GRE 隧道。
RTE_FLOW_ITEM_TYPE_NVGRE:匹配 NVGRE 隧道。
RTE_FLOW_ITEM_TYPE_VXLAN:匹配 VXLAN 隧道。
RTE_FLOW_ITEM_TYPE_GENEVE:匹配 GENEVE 隧道。
RTE_FLOW_ITEM_TYPE_GTP:匹配 GTP 数据包。
RTE_FLOW_ITEM_TYPE_GTP_PSC:匹配 GTP PSC 数据包。
RTE_FLOW_ITEM_TYPE_MPLS:匹配 MPLS 标签。
RTE_FLOW_ITEM_TYPE_MARK:匹配带有特定标记的数据包。
RTE_FLOW_ITEM_TYPE_META:匹配带有特定元数据的数据包。
RTE_FLOW_ITEM_TYPE_TAG:匹配带有特定标签的数据包。
RTE_FLOW_ITEM_TYPE_FUZZY:模糊匹配,允许一定范围内的变化。
RTE_FLOW_ITEM_TYPE_GTPU:匹配 GTP-U 数据包。
RTE_FLOW_ITEM_TYPE_ECPRI:匹配 eCPRI 数据包。
RTE_FLOW_ITEM_TYPE_IPV6_EXT:匹配 IPv6 扩展头。
RTE_FLOW_ITEM_TYPE_ICMP6:匹配 ICMPv6 数据包。
RTE_FLOW_ITEM_TYPE_ARP:匹配 ARP 数据包。
RTE_FLOW_ITEM_TYPE_RARP:匹配 RARP 数据包。
RTE_FLOW_ITEM_TYPE_NSH:匹配 NSH 数据包。
RTE_FLOW_ITEM_TYPE_VXLAN_GPE:匹配 VXLAN-GPE 隧道。
RTE_FLOW_ITEM_TYPE_GENEVE_OPT:匹配 GENEVE 选项。
有啥场景, 是根据业务的需要, 动态的添加和删除过滤的规则的吗?
场景一:防火墙和安全网关
- 动态过滤规则
入侵检测和防御(IDS/IPS):
根据实时检测到的威胁,动态添加或删除过滤规则,以阻止恶意流量。
例如,当检测到某个 IP 地址的异常行为时,可以立即添加规则阻止该 IP 地址的流量。
static struct rte_flow *create_block_ip_rule(uint16_t port_id, uint32_t ip, struct rte_flow_error *error) {
struct rte_flow_attr attr;
struct rte_flow_item pattern[3];
struct rte_flow_action action[2];
struct rte_flow *flow;
// 配置流属性
memset(&attr, 0, sizeof(struct rte_flow_attr));
attr.ingress = 1;
// 配置流模式(匹配特定 IP 地址)
struct rte_flow_item_ipv4 ipv4_spec = {
.hdr = {
.src_addr = rte_cpu_to_be_32(ip), // 源 IP 地址
},
};
struct rte_flow_item_ipv4 ipv4_mask = {
.hdr = {
.src_addr = 0xFFFFFFFF,
},
};
memset(pattern, 0, sizeof(pattern));
pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
pattern[1].spec = &ipv4_spec;
pattern[1].mask = &ipv4_mask;
pattern[2].type = RTE_FLOW_ITEM_TYPE_END;
// 配置流动作(丢弃数据包)
memset(action, 0, sizeof(action));
action[0].type = RTE_FLOW_ACTION_TYPE_DROP;
action[1].type = RTE_FLOW_ACTION_TYPE_END;
// 创建流规则
flow = rte_flow_create(port_id, &attr, pattern, action, error);
return flow;
}
DDoS 防护:
在检测到 DDoS 攻击时,动态添加过滤规则以丢弃攻击流量。
例如,当某个端口或 IP 地址的流量异常增大时,可以添加规则限制或丢弃该流量。
static struct rte_flow *create_block_port_rule(uint16_t port_id, uint16_t port, struct rte_flow_error *error) {
struct rte_flow_attr attr;
struct rte_flow_item pattern[3];
struct rte_flow_action action[2];
struct rte_flow *flow;
// 配置流属性
memset(&attr, 0, sizeof(struct rte_flow_attr));
attr.ingress = 1;
// 配置流模式(匹配特定端口)
struct rte_flow_item_udp udp_spec = {
.hdr = {
.dst_port = rte_cpu_to_be_16(port), // 目标端口
},
};
struct rte_flow_item_udp udp_mask = {
.hdr = {
.dst_port = 0xFFFF,
},
};
memset(pattern, 0, sizeof(pattern));
pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
pattern[1].type = RTE_FLOW_ITEM_TYPE_UDP;
pattern[1].spec = &udp_spec;
pattern[1].mask = &udp_mask;
pattern[2].type = RTE_FLOW_ITEM_TYPE_END;
// 配置流动作(丢弃数据包)
memset(action, 0, sizeof(action));
action[0].type = RTE_FLOW_ACTION_TYPE_DROP;
action[1].type = RTE_FLOW_ACTION_TYPE_END;
// 创建流规则
flow = rte_flow_create(port_id, &attr, pattern, action, error);
return flow;
}
场景二:负载均衡器
- 动态流量分配
流量分配策略:
根据服务器的负载情况,动态调整流量分配规则。
例如,当某个服务器的负载过高时,可以动态添加规则将部分流量分配到其他服务器。
static struct rte_flow *create_redirect_rule(uint16_t port_id, uint32_t dst_ip, struct rte_flow_error *error) {
struct rte_flow_attr attr;
struct rte_flow_item pattern[3];
struct rte_flow_action action[3];
struct rte_flow *flow;
// 配置流属性
memset(&attr, 0, sizeof(struct rte_flow_attr));
attr.ingress = 1;
// 配置流模式(匹配所有流量)
memset(pattern, 0, sizeof(pattern));
pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
pattern[1].type = RTE_FLOW_ITEM_TYPE_END;
// 配置流动作(重定向到特定 IP 地址)
struct rte_flow_action_raw_encap encap_action = {
.data = (uint8_t *)&dst_ip,
.size = sizeof(dst_ip),
};
memset(action, 0, sizeof(action));
action[0].type = RTE_FLOW_ACTION_TYPE_RAW_ENCAP;
action[0].conf = &encap_action;
action[1].type = RTE_FLOW_ACTION_TYPE_END;
// 创建流规则
flow = rte_flow_create(port_id, &attr, pattern, action, error);
return flow;
}
健康检查:
根据服务器的健康状态,动态添加或删除流量转发规则。
例如,当某个服务器故障时,可以立即删除其相关的流量转发规则。
场景三:虚拟化和云计算
- 动态网络配置
虚拟机迁移:
在虚拟机迁移过程中,动态调整网络过滤规则以确保流量的正确转发。
例如,当虚拟机从一个物理主机迁移到另一个物理主机时,需要动态更新流量转发规则。
多租户隔离:
根据租户的需求,动态添加或删除隔离规则。
例如,为特定租户配置独立的网络过滤规则,以确保租户之间的流量隔离。
场景四:服务质量(QoS)管理
- 动态带宽控制
带宽管理:
根据实时流量情况,动态调整带宽限制规则。
例如,当某个应用的流量超过预设的带宽限制时,可以动态添加规则限制其带宽。
static struct rte_flow *create_bandwidth_limit_rule(uint16_t port_id, uint32_t ip, uint32_t rate_limit, struct rte_flow_error *error) {
struct rte_flow_attr attr;
struct rte_flow_item pattern[3];
struct rte_flow_action action[3];
struct rte_flow *flow;
// 配置流属性
memset(&attr, 0, sizeof(struct rte_flow_attr));
attr.ingress = 1;
// 配置流模式(匹配特定 IP 地址)
struct rte_flow_item_ipv4 ipv4_spec = {
.hdr = {
.src_addr = rte_cpu_to_be_32(ip), // 源 IP 地址
},
};
struct rte_flow_item_ipv4 ipv4_mask = {
.hdr = {
.src_addr = 0xFFFFFFFF,
},
};
memset(pattern, 0, sizeof(pattern));
pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
pattern[1].spec = &ipv4_spec;
pattern[1].mask = &ipv4_mask;
pattern[2].type = RTE_FLOW_ITEM_TYPE_END;
// 配置流动作(限速)
struct rte_flow_action_meter meter_action = {
.mtr_id = rate_limit,
};
memset(action, 0, sizeof(action));
action[0].type = RTE_FLOW_ACTION_TYPE_METER;
action[0].conf = &meter_action;
action[1].type = RTE_FLOW_ACTION_TYPE_END;
// 创建流规则
flow = rte_flow_create(port_id, &attr, pattern, action, error);
return flow;
}
优先级控制:
根据业务需求,动态调整流量优先级规则。
例如,为高优先级的流量动态添加规则,以确保其在网络拥塞时优先传输。
int main(int argc, char **argv) {
struct rte_flow_error error;
struct rte_flow *flow_low, *flow_high;
struct rte_eth_conf port_conf = {0};
struct rte_eth_rxconf rxq_conf;
struct rte_eth_txconf txq_conf;
uint16_t nb_rxd = 128;
uint16_t nb_txd = 512;
uint16_t nb_rx_queues = 2;
uint16_t nb_tx_queues = 2;
// 初始化 DPDK 环境
if (rte_eal_init(argc, argv) < 0)
rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
// 配置以太网设备
port_conf.rxmode.max_rx_pkt_len = RTE_ETHER_MAX_LEN;
if (rte_eth_dev_configure(PORT_ID, nb_rx_queues, nb_tx_queues, &port_conf) < 0)
rte_exit(EXIT_FAILURE, "Error configuring Ethernet device\n");
// 分配并启动 RX 队列
for (uint16_t q = 0; q < nb_rx_queues; q++) {
if (rte_eth_rx_queue_setup(PORT_ID, q, nb_rxd, rte_eth_dev_socket_id(PORT_ID), &rxq_conf, rte_pktmbuf_pool_create("MBUF_POOL", 8192, 250, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id())) < 0)
rte_exit(EXIT_FAILURE, "Error setting up RX queue\n");
}
// 分配并启动 TX 队列
for (uint16_t q = 0; q < nb_tx_queues; q++) {
if (rte_eth_tx_queue_setup(PORT_ID, q, nb_txd, rte_eth_dev_socket_id(PORT_ID), &txq_conf) < 0)
rte_exit(EXIT_FAILURE, "Error setting up TX queue\n");
}
// 启动以太网设备
if (rte_eth_dev_start(PORT_ID) < 0)
rte_exit(EXIT_FAILURE, "Error starting Ethernet device\n");
// 动态添加优先级过滤规则
uint32_t ip_low = 0xC0A80002; // 192.168.0.2
uint32_t ip_high = 0xC0A80003; // 192.168.0.3
// 低优先级流量分配到队列 0
flow_low = create_priority_rule(PORT_ID, ip_low, 0, &error);
if (!flow_low) {
printf("Flow creation failed for low priority: %s\n", error.message);
return -1;
}
printf("Flow created successfully to prioritize IP: 192.168.0.2 to queue: 0\n");
// 高优先级流量分配到队列 1
flow_high = create_priority_rule(PORT_ID, ip_high, 1, &error);
if (!flow_high) {
printf("Flow creation failed for high priority: %s\n", error.message);
return -1;
}
printf("Flow created successfully to prioritize IP: 192.168.0.3 to queue: 1\n");
// 主循环
while (1) {
// 在此处理数据包
// 从不同队列中接收数据包并进行处理
for (uint16_t q = 0; q < nb_rx_queues; q++) {
struct rte_mbuf *bufs[nb_rxd];
const uint16_t nb_rx = rte_eth_rx_burst(PORT_ID, q, bufs, nb_rxd);
if (nb_rx > 0) {
printf("Received %u packets on queue %u\n", nb_rx, q);
// 在此处理接收到的数据包
for (uint16_t i = 0; i < nb_rx; i++) {
rte_pktmbuf_free(bufs[i]);
}
}
}
// 根据业务需求动态删除过滤规则
// 示例:在特定条件下删除过滤规则
if (/* 条件满足 */) {
if (rte_flow_destroy(PORT_ID, flow_low, &error) < 0) {
printf("Flow destruction failed for low priority: %s\n", error.message);
return -1;
}
printf("Flow destroyed successfully for low priority\n");
if (rte_flow_destroy(PORT_ID, flow_high, &error) < 0) {
printf("Flow destruction failed for high priority: %s\n", error.message);
return -1;
}
printf("Flow destroyed successfully for high priority\n");
break;
}
}
// 停止并关闭以太网设备
rte_eth_dev_stop(PORT_ID);
rte_eth_dev_close(PORT_ID);
return 0;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。