kernel网络之vlan子接口

  1. 添加vlan子接口
    可以通过vconfig或者ip命令添加vlan子接口,命令如下:

vconfig add eth0 10
或者
ip link add link eth0 name vlan10 type vlan id 10

执行上面的vconfig命令时,在kernel中代码流程如下,通过ip link设置vlan子接口走的是rtnl_link这一套流程,这里暂时先不分析了。

vlan_ioctl_handler
    //添加vlan子接口
    ADD_VLAN_CMD: register_vlan_device
    //删除vlan子接口
    DEL_VLAN_CMD: unregister_vlan_dev

在register_vlan_device中:
a. 调用alloc_netdev分配new_dev结构体
struct net_device *new_dev;
new_dev = alloc_netdev(sizeof(struct vlan_dev_priv), name,
                   NET_NAME_UNKNOWN, vlan_setup);
    //在vlan_setup中,赋值如下
    dev->netdev_ops = &vlan_netdev_ops;
    dev->ethtool_ops    = &vlan_ethtool_ops;

b. 分配vlan私有结构体
struct vlan_dev_priv *vlan;
vlan = vlan_dev_priv(new_dev);
vlan->vlan_proto = htons(ETH_P_8021Q);
vlan->vlan_id = vlan_id;
vlan->real_dev = real_dev;
vlan->dent = NULL;
vlan->flags = VLAN_FLAG_REORDER_HDR;

new_dev->rtnl_link_ops = &vlan_link_ops;

c. 注册vlan子接口register_vlan_dev(new_dev)
register_netdevice(dev);->list_netdevice(dev);
/* Device list insertion */
static void list_netdevice(struct net_device *dev)
{
    struct net *net = dev_net(dev);
    write_lock_bh(&dev_base_lock);
    list_add_tail_rcu(&dev->dev_list, &net->dev_base_head);
    hlist_add_head_rcu(&dev->name_hlist, dev_name_hash(net, dev->name));
    hlist_add_head_rcu(&dev->index_hlist, dev_index_hash(net, dev->ifindex));
    write_unlock_bh(&dev_base_lock);
    dev_base_seq_inc(net);
}

在一个net网络空间中,不管物理网卡还是虚拟网卡,每次调用register_netdevice都会将此dev同时添加到此net空间中的三个链表中: net->dev_base_head, net->dev_name_head, net->dev_index_head.
我们通过ifconfig或者ip addr show命令时,都会通过这三个链表其中之一获取到net空间中的所有接口。
Linux下的网络设备net_dev并不一定都对应实际的硬件设备,只要注册一个struct net_device{}结构体(netdevice.h)到内核中,那么这个网络设备就存在了。

  1. vlan子接口发包流程
    调用vlan_dev_hard_start_xmit

a. 
    //如果mac头的协议类型不是vlan协议,说明还没有打上vlan 
    //tag,需要添加vlan tag。
    //但此时不会直接添加,而是设置标志位,让物理网卡发送函
    //数完成vlan添加的操作。
    if (veth->h_vlan_proto != vlan->vlan_proto ||
        vlan->flags & VLAN_FLAG_REORDER_HDR) {
        u16 vlan_tci;
        vlan_tci = vlan->vlan_id;
        vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb->priority);
        skb = __vlan_hwaccel_put_tag(skb, vlan->vlan_proto, vlan_tci);
    }

    //比如在ixgbe的发送函数中ixgbe_xmit_frame_ring会进行判
    //断,如果需要添加vlan,则设置相应标志,让网卡完成vlan
    //的添加
    /* if we have a HW VLAN tag being added default to the HW one */
    if (vlan_tx_tag_present(skb)) {
        tx_flags |= vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT;
        tx_flags |= IXGBE_TX_FLAGS_HW_VLAN;

b. 
    //将skb中的dev换成物理网卡的dev
    skb->dev = vlan->real_dev;
c.
    //调用物理网卡的xmit函数发送出去
    dev_queue_xmit(skb);

3.vlan的接收流程可参考neiif_receive_skb部分
注册vlan子接口时,会将创建的vlan子接口的net_device和其vid保存到父接口的net_device的vlan_info中,父接口收到报文时,如果报文携带vlan,则会查找其vlan_info确定是否有相关的vlan子接口,如果有,则将skb->dev换成vlan子接口的net_device,重新走一遍协议栈(neiif_receive_skb)。

也可参考:kernel网络之vlan子接口 - 简书 (jianshu.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值