众所周知,Linux的vxlan实现不支持穿透NAT网络环境。并且由于它没有分离listen port和dst port(两者都使用dst_port),没法整活UDPspeeder这种暴力发包工具。
- 为什么要折腾Linux vxlan?只是因为直面kernel性能好,实现(网络层面)简单高效,用来作为隧道传输通道,在带宽和延迟上爆杀一众用户态VPN工具。在我的测试环境,vxlan能随便跑满千兆接口,而openvpn即使去掉加密选项也只能跑250M
言归正传,要让vxlan支持NAT穿透,必然要改造源码,直接贴patch(针对linux-5.10.146)
Index: linux-5.10.146/drivers/net/vxlan.c
===================================================================
--- linux-5.10.146.orig/drivers/net/vxlan.c
+++ linux-5.10.146/drivers/net/vxlan.c
@@ -84,6 +84,14 @@ struct vxlan_fdb {
struct vxlan_dev __rcu *vdev;
};
+struct extra_config_req_t {
+ u8 daddr[4];
+ u32 kal;
+ u8 spl : 1;
+ u8 dpl : 1;
+ u8 bk: 1;
+};
+
#define NTF_VXLAN_ADDED_BY_USER 0x100
/* salt for hash table */
@@ -1460,7 +1468,7 @@ errout:
*/
static bool vxlan_snoop(struct net_device *dev,
union vxlan_addr *src_ip, const u8 *src_mac,
- u32 src_ifindex, __be32 vni)
+ u32 src_ifindex, __be32 vni, __be16 dstport)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_fdb *f;
@@ -1477,7 +1485,7 @@ static bool vxlan_snoop(struct net_devic
struct vxlan_rdst *rdst = first_remote_rcu(f);
if (likely(vxlan_addr_equal(&rdst->remote_ip, src_ip) &&
- rdst->remote_ifindex == ifindex))
+ rdst->remote_ifindex == ifindex && rdst->remote_port == dstport))
return false;
/* Don't migrate static entries, drop packets */
@@ -1494,6 +1502,7 @@ static bool vxlan_snoop(struct net_devic
src_mac, &rdst->remote_ip.sa, &src_ip->sa);
rdst->remote_ip = *src_ip;
+ rdst->remote_port = dstport;
f->updated = jiffies;
vxlan_fdb_notify(vxlan, f, rdst, RTM_NEWNEIGH, true, NULL);
} else {
@@ -1507,7 +1516,7 @@ static bool vxlan_snoop(struct net_devic
vxlan_fdb_update(vxlan, src_mac, src_ip,
NUD_REACHABLE,
NLM_F_EXCL|NLM_F_CREATE,
- vxlan->cfg.dst_port,
+ dstport,
vni,
vxlan->default_dst.remote_vni,
ifindex, NTF_SELF, 0, true, NULL);
@@ -1791,9 +1800,10 @@ static bool vxlan_set_mac(struct vxlan_d
saddr.sa.sa_family = AF_INET6;
#endif
}
-
+
+ struct udphdr *udph = udp_hdr(skb);
if ((vxlan->cfg.flags & VXLAN_F_LEARN) &&
- vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source, ifindex, vni))
+ vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source, ifindex, vni, vxlan->cfg.dpl ? udph->source : vxlan->cfg.dst_port))
return false;
return true;
@@ -2506,6 +2516,8 @@ static void vxlan_encap_bypass(struct sk
union vxlan_addr *remote_ip = &dst_vxlan->default_dst.remote_ip;
struct net_device *dev;
int len = skb->len;
+
+ //printk("in vxlan_encap_bypass: vni %d, snoop %d\n", ntohl(vni), (int)snoop);
tx_stats = this_cpu_ptr(src_vxlan->dev->tstats);
rx_stats = this_cpu_ptr(dst_vxlan->dev->tstats);
@@ -2532,7 +2544,7 @@ static void vxlan_encap_bypass(struct sk
}
if ((dst_vxlan->cfg.flags & VXLAN_F_LEARN) && snoop)
- vxlan_snoop(dev, &loopback, eth_hdr(skb)->h_source, 0, vni);
+ vxlan_snoop(dev, &loopback, eth_hdr(skb)->h_source, 0, vni, dst_vxlan->cfg.dst_port);
u64_stats_update_begin(&tx_stats->syncp);
tx_stats->tx_packets++;
@@ -2566,20 +2578,30 @@ static int encap_bypass_if_local(struct
BUILD_BUG_ON(RTCF_LOCAL != RTF_LOCAL);
#endif
/* Bypass encapsulation if the destination is local */
+ //printk("in encap_bypass_if_local step1: rt_flags %d, dst_port %d\n", rt_flags, ntohs(dst_port));
+
if (rt_flags & RTCF_LOCAL &&
!(rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))) {
struct vxlan_dev *dst_vxlan;
- dst_release(dst);
dst_vxlan = vxlan_find_vni(vxlan->net, dst_ifindex, vni,
daddr->sa.sa_family, dst_port,
vxlan->cfg.flags);
+
+ //printk("in encap_bypass_if_local step2: vxlan %lld dst_vxlan %lld\n", vxlan, dst_vxlan);
+
+ /*
if (!dst_vxlan) {
dev->stats.tx_errors++;
kfree_skb(skb);
return -ENOENT;
- }
+ }*/
+
+ if(!dst_vxlan)
+ return 0;
+
+ dst_release(dst);
vxlan_encap_bypass(skb, vxlan, dst_vxlan, vni, true);
return 1;
}
@@ -2675,7 +2697,7 @@ static void vxlan_xmit_one(struct sk_buf
label = info->key.label