Linux bridge代码分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hz5034/article/details/83476744

bridge是一个二层虚拟网络设备,通过brctl命令创建,提供了二层的ebtables,类似于三层的iptables
http://blog.chinaunix.net/uid-28315531-id-3572529.html
https://www.cnblogs.com/morphling/p/3458546.html

注册

module_init(br_init)

static int __init br_init(void)
{
    ...
    err = br_netfilter_init();
    ...
    br_handle_frame_hook = br_handle_frame; // 设置br_handle_frame_hook为br_handle_frame
    ...
}

int __init br_netfilter_init(void)
{
    ...
    ret = nf_register_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
    ...
}

static struct nf_hook_ops br_nf_ops[] __read_mostly = {
    {
        .hook = br_nf_pre_routing,
        .owner = THIS_MODULE,
        .pf = PF_BRIDGE,
        .hooknum = NF_BR_PRE_ROUTING,
        .priority = NF_BR_PRI_BRNF,
    },
    {
        .hook = br_nf_local_in,
        .owner = THIS_MODULE,
        .pf = PF_BRIDGE,
        .hooknum = NF_BR_LOCAL_IN,
        .priority = NF_BR_PRI_BRNF,
    },
    {
        .hook = br_nf_forward_ip,
        .owner = THIS_MODULE,
        .pf = PF_BRIDGE,
        .hooknum = NF_BR_FORWARD,
        .priority = NF_BR_PRI_BRNF - 1,
    },
    {
        .hook = br_nf_forward_arp,
        .owner = THIS_MODULE,
        .pf = PF_BRIDGE,
        .hooknum = NF_BR_FORWARD,
        .priority = NF_BR_PRI_BRNF,
    },
    {
        .hook = br_nf_local_out,
        .owner = THIS_MODULE,
        .pf = PF_BRIDGE,
        .hooknum = NF_BR_LOCAL_OUT,
        .priority = NF_BR_PRI_FIRST,
    },
    {
        .hook = br_nf_post_routing,
        .owner = THIS_MODULE,
        .pf = PF_BRIDGE,
        .hooknum = NF_BR_POST_ROUTING,
        .priority = NF_BR_PRI_LAST,
    },
    {
        .hook = ip_sabotage_in,
        .owner = THIS_MODULE,
        .pf = PF_INET,
        .hooknum = NF_INET_PRE_ROUTING,
        .priority = NF_IP_PRI_FIRST,
    },
    {
        .hook = ip_sabotage_in,
        .owner = THIS_MODULE,
        .pf = PF_INET6,
        .hooknum = NF_INET_PRE_ROUTING,
        .priority = NF_IP6_PRI_FIRST,
    },
};

数据流

以rx为例,eth0收到skb后通过netif_receive_skb()上送协议栈,netif_receive_skb()调用handle_bridge(),handle_bridge()判断skb->dev->br_port是否非空(eth0是否桥接),若是,调用br_handle_frame_hook()即br_handle_frame(),经过NF_BR_PRE_ROUTING链时调用br_nf_pre_routing(),经过NF_INET_PRE_ROUTING链后调用br_nf_pre_routing_finish(),再次经过NF_BR_PRE_ROUTING链,由于NF_BR_PRI_BRNF = 0 < 1,因此不调用br_nf_pre_routing(),直接调用br_handle_frame_finish()

在br_handle_frame_finish()中分两种情况:
1、skb的dmac地址是本机地址:在br_pass_frame_up()中修改skb->dev为网桥,重新交给netif_receive_skb(),此时skb->dev->br_port为空,不走桥接逻辑,直接上送ip_rcv()
2、其它:在br_forward()中转发

int netif_receive_skb(struct sk_buff *skb)
{
    ...
    skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);
    ...
}

static inline struct sk_buff *handle_bridge(struct sk_buff *skb,
                                            struct packet_type **pt_prev, int *ret,
                                            struct net_device *orig_dev)
{
    ...
    return br_handle_frame_hook(port, skb);
}

struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb)
{
    ...
    NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
            br_handle_frame_finish);
    ...
}

static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb,
                                        const struct net_device *in,
                                        const struct net_device *out,
                                        int (*okfn)(struct sk_buff *))
{
    ...
    if (!setup_pre_routing(skb)) // 标记BRNF_NF_BRIDGE_PREROUTING
        return NF_DROP;
    ...
    NF_HOOK(PF_INET, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
            br_nf_pre_routing_finish);

    return NF_STOLEN;
    ...
}

static unsigned int ip_sabotage_in(unsigned int hook, struct sk_buff *skb,
                                    const struct net_device *in,
                                    const struct net_device *out,
                                    int (*okfn)(struct sk_buff *))
{
    if (skb->nf_bridge &&
	    !(skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)) { // 检查标记NF_BR_PRE_ROUTING
	    return NF_STOP;  
    }

    return NF_ACCEPT;
}

static int br_nf_pre_routing_finish(struct sk_buff *skb)
{
    ...
    nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING; // 取消标记NF_BR_PRE_ROUTING
    ...
    NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
                    br_handle_frame_finish, 1);
    ...
}

int br_handle_frame_finish(struct sk_buff *skb)
{
    ...
    br_pass_frame_up(br, skb2); // 本地
    ...
    br_forward(dst->dst, skb); // 转发
    ...
}

static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
{
    ...
    // 修改skb->dev为网桥
    skb->dev = brdev;
    ...
    // 重新交给netif_receive_skb()
    NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
            netif_receive_skb);
}

void br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
{
    ...
    __br_forward(to, skb);
    ...
}

static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
{
    ...
    // 修改skb->dev为出设备
    skb->dev = to->dev;
    ...
    NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev,
            br_forward_finish);
}

猜你喜欢

转载自blog.csdn.net/hz5034/article/details/83476744
今日推荐