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 = &eth_spec;
    pattern[0].mask = &eth_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;
}


putao
8 声望1 粉丝

推动世界向前发展,改善民生。