Skip to content

net/openvswitch - Open vSwitch

1. 模块架构

1.1 功能概述

Open vSwitch (OvS) 是一种多层虚拟交换机,支持 OpenFlow 协议,用于 SDN 环境。

1.2 关键源文件

文件作用
datapath/datapath.cOVS 数据路径
datapath/vport.c端口管理
datapath/flow.c流表
datapath/actions.c动作执行
include/openvswitch/datapath.h数据路径定义

2. 核心数据结构

2.1 struct sw_flow

c
// datapath/flow.h:50
struct sw_flow {
    struct rcu_head rcu;
    struct hlist_node hash_node[2];
    u32 hash;

    struct ovs_key_ipv4 key;          // 流键
    struct ovs_key_ipv4 mask;          // 掩码
    unsigned long *stats;              // 统计

    struct sw_flow_actions *sf_acts;  // 动作
    unsigned long used;                // 最后使用时间
    unsigned long tcp_flags;           // TCP 标志
};

2.2 struct ovs_action_set

c
// include/openvswitch/actions.h:40
struct ovs_action_set {
    __be16 ethertype;
    struct ethhdr eth;
    struct {
        __be32 src;
        __be32 dst;
    } ipv4;
    __be16 src_port;
    __be16 dst_port;
    __u8 ipv4_frag;
    __u8 ipv4_frag_max;
};

2.3 struct datapath

c
// include/openvswitch/datapath.h:50
struct datapath {
    struct rcu_head rcu;
    u32 dp_ifindex;

    struct list_head ports;            // 端口列表
    struct hlist_head *flow_table;    // 流表
    struct list_head pending_list;    // 待处理列表

    struct per_cpu *stats;
};

3. 数据路径

3.1 ovs_dp_process_packet()

c
// datapath/datapath.c:400
int ovs_dp_process_packet(struct sk_buff *skb, struct datapath *dp)
{
    struct sw_flow *flow;
    struct sw_flow_key key;
    struct ovs_actions *acts;

    // 提取流键
    ovs_flow_extract(skb, &key);

    // 查找流
    flow = ovsl_lookup_flow(dp, &key);
    if (!flow) {
        // 发送 upcall 到用户空间
        ovs_dp_upcall(dp, skb, &key);
        return -ENOENT;
    }

    // 获取动作
    acts = get_flow_actions(flow);

    // 执行动作
    ovs_execute_actions(dp, skb, acts);

    return 0;
}

3.2 ovs_execute_actions()

c
// datapath/actions.c:200
static int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
                               struct ovs_actions *acts)
{
    for each action in acts {
        switch (action->type) {
        case OVS_ACTION_ATTR_OUTPUT:
            // 输出到端口
            ovs_vport_output(dp, skb, action->port);
            break;
        case OVS_ACTION_ATTR_PUSH_VLAN:
            // 推送 VLAN 头
            __vlan_push(skb, action->vlan);
            break;
        case OVS_ACTION_ATTR_SET:
            // 修改字段
            ovs_set_action(skb, action->set);
            break;
        }
    }
}

4. 流表

4.1 流表查找

c
// datapath/flow.c:300
struct sw_flow *ovsl_lookup_flow(struct datapath *dp,
                                  struct sw_flow_key *key)
{
    struct hlist_head *head;
    struct sw_flow *flow;

    // 计算哈希
    u32 hash = flow_hash(key);

    // 查找
    head = &dp->flow_table[hash & (dp->flow_table_size - 1)];
    hlist_for_each_entry_rcu(flow, head, hash_node) {
        if (flow->hash == hash && flow_match(flow, key))
            return flow;
    }

    return NULL;
}

4.2 流表过期

c
// datapath/flow.c:500
void ovs_flow_free(struct rcu_head *rcu)
{
    struct sw_flow *flow = container_of(rcu, struct sw_flow, rcu);

    // 释放动作
    if (flow->sf_acts)
        release_flow_acts(flow->sf_acts);

    // 释放流
    kfree(flow);
}

5. Upcall

5.1 upcall 到用户空间

c
// datapath/datapath.c:600
int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
                 struct sw_flow_key *key)
{
    struct vport *vport;
    int err;

    // 获取输入端口
    vport = ovs_vport_rcu(dp, key->in_port);
    if (!vport)
        return -ENOENT;

    // 添加到 pending 列表
    queue_gso_packets(dp->dp, skb, vport);

    return 0;
}

5.2 处理用户空间响应

c
// datapath/datapath.c:700
static int ovs_dp_notify(struct datapath *dp, struct sk_buff *skb)
{
    struct ip_vs_mh_msg *msg = (void *)skb->data;

    switch (msg->type) {
    case OVS_PACKET_CMD_FLOW:
        // 添加/修改流
        ovs_flow_install(dp, &msg->key, msg->actions);
        break;
    case OVS_PACKET_CMD_EXECUTE:
        // 直接执行动作
        ovs_execute_actions(dp, skb, msg->actions);
        break;
    }
}

6. 端口

6.1 struct vport

c
// include/openvswitch/vport.h:40
struct vport {
    struct list_head dp_node;
    struct datapath *dp;

    char name[IFNAMSIZ];
    u32 port_id;

    const struct vport_ops *ops;

    struct net_device *dev;
    struct pcpu_tstats __percpu *stats;
};

6.2 vport 操作

c
// include/openvswitch/vport.h:60
struct vport_ops {
    enum ovs_vport_type type;
    struct vport *(*create)(const struct vport_parms *);
    int (*recv)(struct vport *, struct sk_buff *);
    void (*send)(struct vport *, struct sk_buff *);
};

7. OpenFlow 支持

7.1 消息类型

c
// 支持的 OpenFlow 消息:
// - OFPT_FLOW_MOD: 流表修改
// - OFPT_PACKET_IN: 数据包到达
// - OFPT_PACKET_OUT: 数据包输出
// - OFPT_STATS_REQUEST/REPLY: 统计信息

7.2 匹配字段

c
// 支持的匹配字段:
// - in_port: 输入端口
// - eth_src/dst: MAC 地址
// - vlan_vid: VLAN ID
// - eth_type: 以太网类型
// - ip_src/dst: IP 地址
// - tcp/udp src/dst_port: 端口

基于 VitePress 构建