关于linux中自定义第2层实现的说明

时间:2012-12-07 13:01:05

标签: linux network-programming linux-kernel network-protocols

我有一些机器在同一个网络上运行。一个节点是控制节点,它将流向它的流量分配给其他节点。问题是我想在MAC头和输入到控制节点的IP(或其他)有效载荷之间有一个自定义协议头。

控制节点收到这样的任何数据包:

------------------------------------------------
| Layer 2 | IP(or whatever protocol) | Payload |
------------------------------------------------

此数据包应该像这样分发给其他节点

----------------------------------------------------------------
| Layer 2 | Custom Header | IP(or whatever protocol) | Payload |
----------------------------------------------------------------

我想要一些方向来做这样的事情,有没有我可以使用的当前解决方案,我必须从头开始破解内核。类似的方法是使用L2TP,但是在IP层上运行,所以我不想要它。

我还希望这个通信在linux中作为一个单独的接口出现,就像tun0而不是物理eth0接口。

任何帮助或想法都将受到高度赞赏。

我不知道这个问题属于哪个堆栈交换网站,所以也非常感谢正确网站的指示。

1 个答案:

答案 0 :(得分:2)

您的情况与VLAN非常相似,其中VLAN标头也位于L2标头和IP标头之间。您可以查看VLAN代码,尤其是net / 8021q / vlan_dev.c。

这里的关键是你需要构建自己的L2头,所以你需要注册自己的header_ops,就像VLAN一样:

static const struct header_ops vlan_header_ops = {
        .create  = vlan_dev_hard_header,
        .rebuild = vlan_dev_rebuild_header,
        .parse   = eth_header_parse,
};

并在初始化期间注册:

dev->header_ops      = &vlan_header_ops;
dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN;

此处的> create()函数指针用于创建自定义标题:

static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
                unsigned short type,
                const void *daddr, const void *saddr,
                unsigned int len)
{
    struct vlan_hdr *vhdr;
    unsigned int vhdrlen = 0;
    u16 vlan_tci = 0;
    int rc;

    if (!(vlan_dev_priv(dev)->flags & VLAN_FLAG_REORDER_HDR)) {
        vhdr = (struct vlan_hdr *) skb_push(skb, VLAN_HLEN);

        vlan_tci = vlan_dev_priv(dev)->vlan_id;
        vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb);
        vhdr->h_vlan_TCI = htons(vlan_tci);

        /*
         *  Set the protocol type. For a packet of type ETH_P_802_3/2 we
         *  put the length in here instead.
         */
        if (type != ETH_P_802_3 && type != ETH_P_802_2)
            vhdr->h_vlan_encapsulated_proto = htons(type);
        else
            vhdr->h_vlan_encapsulated_proto = htons(len);

        skb->protocol = htons(ETH_P_8021Q);
        type = ETH_P_8021Q;
        vhdrlen = VLAN_HLEN;
    }

    /* Before delegating work to the lower layer, enter our MAC-address */
    if (saddr == NULL)
        saddr = dev->dev_addr;

    /* Now make the underlying real hard header */
    dev = vlan_dev_priv(dev)->real_dev;
    rc = dev_hard_header(skb, dev, type, daddr, saddr, len + vhdrlen);
    if (rc > 0)
        rc += vhdrlen;
    return rc;
}