VLAN tunnel隧道映射根据tunnel id为数据包添加vlan信息。 以下bridge配置命令采用iproute2的版本4.17.0,低版本bridge命令可能不完全支持vlan_tunnel功能。
使能接口eth0的vlan与tunnel映射功能:
bridge link set dev eth0 vlan_tunnel on
或者:
ip link set dev eth0 type bridge_slave vlan_tunnel on
配置一个l2tp的控制隧道,隧道ID为1000,自此隧道接收到的数据包,如果没有vlan id,自动增加vlan id 20,如下:
ip l2tp add tunnel tunnel_id 2000 peer_tunnel_id 2000 encap udp local 192.168.1.1 remote 192.168.2.1 udp_sport 3300 udp_dport 5500
bridge vlan add dev eth0 vid 20 tunnel_info 2000
使能接口eth0的vlan与tunnel映射功能:
bridge link set dev eth0 vlan_tunnel on
或者:
ip link set dev eth0 type bridge_slave vlan_tunnel on
配置一个l2tp的控制隧道,隧道ID为1000,自此隧道接收到的数据包,如果没有vlan id,自动增加vlan id 20,如下:
ip l2tp add tunnel tunnel_id 2000 peer_tunnel_id 2000 encap udp local 192.168.1.1 remote 192.168.2.1 udp_sport 3300 udp_dport 5500
bridge vlan add dev eth0 vid 20 tunnel_info 2000
在接收网桥的数据包接收函数br_handle_frame中,调用br_handle_ingress_vlan_tunnel函数处理tunnel与vlan的映射关系。
rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
{
struct net_bridge_port *p;
struct sk_buff *skb = *pskb;
p = br_port_get_rcu(skb->dev);
if (p->flags & BR_VLAN_TUNNEL) {
if (br_handle_ingress_vlan_tunnel(skb, p, nbp_vlan_group_rcu(p)))
goto drop;
}
}
br_handle_ingress_vlan_tunnel函数为没有vlan信息的数据包添加vlan id。首先从skb的dst路由缓存中取得tunnel id信息,之后根据tunnel id在接口的vlan group的隧道hash列表中查找vlan信息。最后将找到的vlan id设置给skb。
int br_handle_ingress_vlan_tunnel(struct sk_buff *skb, struct net_bridge_port *p, struct net_bridge_vlan_group *vg)
{
if (skb_vlan_tagged(skb))
return 0;
vlan = br_vlan_tunnel_lookup(&vg->tunnel_hash, tinfo->key.tun_id);
skb_dst_drop(skb);
__vlan_hwaccel_put_tag(skb, p->br->vlan_proto, vlan->vid);
}
在数据包离开网桥的两个点(br_pass_frame_up和__br_forward)调用br_handle_egress_vlan_tunnel函数,处理vlan信息的剥离。
int br_handle_egress_vlan_tunnel(struct sk_buff *skb, struct net_bridge_vlan *vlan)
{
if (!vlan || !vlan->tinfo.tunnel_id)
return 0;
if (unlikely(!skb_vlan_tag_present(skb)))
return 0;
skb_dst_drop(skb);
err = skb_vlan_pop(skb);
skb_dst_set(skb, dst_clone(&vlan->tinfo.tunnel_dst->dst));
}
内核版本
linux-4.15