diff --git a/patches/lede/0032-generic-vxlan-backport-support-for-VXLAN-over-link-local-IPv6.patch b/patches/lede/0032-generic-vxlan-backport-support-for-VXLAN-over-link-local-IPv6.patch new file mode 100644 index 00000000..43bbf105 --- /dev/null +++ b/patches/lede/0032-generic-vxlan-backport-support-for-VXLAN-over-link-local-IPv6.patch @@ -0,0 +1,436 @@ +From: Matthias Schiffer +Date: Wed, 21 Jun 2017 00:54:57 +0200 +Subject: generic: vxlan: backport support for VXLAN over link-local IPv6 + +diff --git a/target/linux/generic/patches-4.4/075-0001-vxlan-improve-validation-of-address-family-configura.patch b/target/linux/generic/patches-4.4/075-0001-vxlan-improve-validation-of-address-family-configura.patch +new file mode 100644 +index 0000000000000000000000000000000000000000..439eb5d0f769f1cde23ff4deacc80728e82605f2 +--- /dev/null ++++ b/target/linux/generic/patches-4.4/075-0001-vxlan-improve-validation-of-address-family-configura.patch +@@ -0,0 +1,68 @@ ++From 434a1bb54b24b538f81d7945128b7ca25976d19b Mon Sep 17 00:00:00 2001 ++Message-Id: <434a1bb54b24b538f81d7945128b7ca25976d19b.1498005061.git.mschiffer@universe-factory.net> ++From: Matthias Schiffer ++Date: Mon, 19 Jun 2017 10:03:57 +0200 ++Subject: [PATCH 1/4] vxlan: improve validation of address family configuration ++ ++Address families of source and destination addresses must match, and ++changelink operations can't change the address family. ++ ++In addition, always use the VXLAN_F_IPV6 to check if a VXLAN device uses ++IPv4 or IPv6. ++ ++Signed-off-by: Matthias Schiffer ++Signed-off-by: David S. Miller ++[Matthias Schiffer: rebase to v4.4.y] ++--- ++ drivers/net/vxlan.c | 23 +++++++++++++++-------- ++ 1 file changed, 15 insertions(+), 8 deletions(-) ++ ++--- a/drivers/net/vxlan.c +++++ b/drivers/net/vxlan.c ++@@ -2784,12 +2784,20 @@ static int vxlan_dev_configure(struct ne ++ ++ memcpy(&dst->remote_ip, &conf->remote_ip, sizeof(conf->remote_ip)); ++ ++- /* Unless IPv6 is explicitly requested, assume IPv4 */ ++- if (!dst->remote_ip.sa.sa_family) +++ if (!dst->remote_ip.sa.sa_family && !conf->saddr.sa.sa_family) { +++ /* Unless IPv6 is explicitly requested, assume IPv4 */ ++ dst->remote_ip.sa.sa_family = AF_INET; +++ conf->saddr.sa.sa_family = AF_INET; +++ } else if (!dst->remote_ip.sa.sa_family) { +++ dst->remote_ip.sa.sa_family = conf->saddr.sa.sa_family; +++ } else if (!conf->saddr.sa.sa_family) { +++ conf->saddr.sa.sa_family = dst->remote_ip.sa.sa_family; +++ } +++ +++ if (conf->saddr.sa.sa_family != dst->remote_ip.sa.sa_family) +++ return -EINVAL; ++ ++- if (dst->remote_ip.sa.sa_family == AF_INET6 || ++- vxlan->cfg.saddr.sa.sa_family == AF_INET6) { +++ if (conf->saddr.sa.sa_family == AF_INET6) { ++ if (!IS_ENABLED(CONFIG_IPV6)) ++ return -EPFNOSUPPORT; ++ use_ipv6 = true; ++@@ -2843,11 +2851,9 @@ static int vxlan_dev_configure(struct ne ++ ++ list_for_each_entry(tmp, &vn->vxlan_list, next) { ++ if (tmp->cfg.vni == conf->vni && ++- (tmp->default_dst.remote_ip.sa.sa_family == AF_INET6 || ++- tmp->cfg.saddr.sa.sa_family == AF_INET6) == use_ipv6 && ++ tmp->cfg.dst_port == vxlan->cfg.dst_port && ++- (tmp->flags & VXLAN_F_RCV_FLAGS) == ++- (vxlan->flags & VXLAN_F_RCV_FLAGS)) +++ (tmp->flags & (VXLAN_F_RCV_FLAGS | VXLAN_F_IPV6)) == +++ (vxlan->flags & (VXLAN_F_RCV_FLAGS | VXLAN_F_IPV6))) ++ return -EEXIST; ++ } ++ ++@@ -2915,6 +2921,7 @@ static int vxlan_newlink(struct net *src ++ ++ if (data[IFLA_VXLAN_GROUP]) { ++ conf.remote_ip.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_GROUP]); +++ conf.remote_ip.sa.sa_family = AF_INET; ++ } else if (data[IFLA_VXLAN_GROUP6]) { ++ if (!IS_ENABLED(CONFIG_IPV6)) ++ return -EPFNOSUPPORT; +diff --git a/target/linux/generic/patches-4.4/075-0002-vxlan-check-valid-combinations-of-address-scopes.patch b/target/linux/generic/patches-4.4/075-0002-vxlan-check-valid-combinations-of-address-scopes.patch +new file mode 100644 +index 0000000000000000000000000000000000000000..abf9b8a0eae88aa5a64be5cc82a6827d4d562c55 +--- /dev/null ++++ b/target/linux/generic/patches-4.4/075-0002-vxlan-check-valid-combinations-of-address-scopes.patch +@@ -0,0 +1,84 @@ ++From 8956b9db43347a51e88dddc3c08fb88ff60dea54 Mon Sep 17 00:00:00 2001 ++Message-Id: <8956b9db43347a51e88dddc3c08fb88ff60dea54.1498005061.git.mschiffer@universe-factory.net> ++In-Reply-To: <434a1bb54b24b538f81d7945128b7ca25976d19b.1498005061.git.mschiffer@universe-factory.net> ++References: <434a1bb54b24b538f81d7945128b7ca25976d19b.1498005061.git.mschiffer@universe-factory.net> ++From: Matthias Schiffer ++Date: Mon, 19 Jun 2017 10:03:58 +0200 ++Subject: [PATCH 2/4] vxlan: check valid combinations of address scopes ++ ++* Multicast addresses are never valid as local address ++* Link-local IPv6 unicast addresses may only be used as remote when the ++ local address is link-local as well ++* Don't allow link-local IPv6 local/remote addresses without interface ++ ++We also store in the flags field if link-local addresses are used for the ++follow-up patches that actually make VXLAN over link-local IPv6 work. ++ ++Signed-off-by: Matthias Schiffer ++Signed-off-by: David S. Miller ++[Matthias Schiffer: rebase to v4.4.y] ++--- ++ drivers/net/vxlan.c | 29 +++++++++++++++++++++++++++++ ++ include/net/vxlan.h | 1 + ++ 2 files changed, 30 insertions(+) ++ ++--- a/drivers/net/vxlan.c +++++ b/drivers/net/vxlan.c ++@@ -2797,11 +2797,35 @@ static int vxlan_dev_configure(struct ne ++ if (conf->saddr.sa.sa_family != dst->remote_ip.sa.sa_family) ++ return -EINVAL; ++ +++ if (vxlan_addr_multicast(&conf->saddr)) +++ return -EINVAL; +++ ++ if (conf->saddr.sa.sa_family == AF_INET6) { ++ if (!IS_ENABLED(CONFIG_IPV6)) ++ return -EPFNOSUPPORT; ++ use_ipv6 = true; ++ vxlan->flags |= VXLAN_F_IPV6; +++ +++ if (!(conf->flags & VXLAN_F_COLLECT_METADATA)) { +++ int local_type = +++ ipv6_addr_type(&conf->saddr.sin6.sin6_addr); +++ int remote_type = +++ ipv6_addr_type(&dst->remote_ip.sin6.sin6_addr); +++ +++ if (local_type & IPV6_ADDR_LINKLOCAL) { +++ if (!(remote_type & IPV6_ADDR_LINKLOCAL) && +++ (remote_type != IPV6_ADDR_ANY)) +++ return -EINVAL; +++ +++ vxlan->flags |= VXLAN_F_IPV6_LINKLOCAL; +++ } else { +++ if (remote_type == +++ (IPV6_ADDR_UNICAST | IPV6_ADDR_LINKLOCAL)) +++ return -EINVAL; +++ +++ vxlan->flags &= ~VXLAN_F_IPV6_LINKLOCAL; +++ } +++ } ++ } ++ ++ if (conf->remote_ifindex) { ++@@ -2827,6 +2851,11 @@ static int vxlan_dev_configure(struct ne ++ dev->mtu = lowerdev->mtu - (use_ipv6 ? VXLAN6_HEADROOM : VXLAN_HEADROOM); ++ ++ needed_headroom = lowerdev->hard_header_len; +++ } else { +++#if IS_ENABLED(CONFIG_IPV6) +++ if (vxlan->flags & VXLAN_F_IPV6_LINKLOCAL) +++ return -EINVAL; +++#endif ++ } ++ ++ if (conf->mtu) { ++--- a/include/net/vxlan.h +++++ b/include/net/vxlan.h ++@@ -185,6 +185,7 @@ struct vxlan_dev { ++ #define VXLAN_F_GBP 0x800 ++ #define VXLAN_F_REMCSUM_NOPARTIAL 0x1000 ++ #define VXLAN_F_COLLECT_METADATA 0x2000 +++#define VXLAN_F_IPV6_LINKLOCAL 0x8000 ++ ++ /* Flags that are used in the receive path. These flags must match in ++ * order for a socket to be shareable +diff --git a/target/linux/generic/patches-4.4/075-0003-vxlan-fix-snooping-for-link-local-IPv6-addresses.patch b/target/linux/generic/patches-4.4/075-0003-vxlan-fix-snooping-for-link-local-IPv6-addresses.patch +new file mode 100644 +index 0000000000000000000000000000000000000000..5ebbce6e0682fff11b0d86c8df781a5c2fab5125 +--- /dev/null ++++ b/target/linux/generic/patches-4.4/075-0003-vxlan-fix-snooping-for-link-local-IPv6-addresses.patch +@@ -0,0 +1,88 @@ ++From e3bdb4bc6c4020e90c1bbafd91645ff3ae8966b9 Mon Sep 17 00:00:00 2001 ++Message-Id: ++In-Reply-To: <434a1bb54b24b538f81d7945128b7ca25976d19b.1498005061.git.mschiffer@universe-factory.net> ++References: <434a1bb54b24b538f81d7945128b7ca25976d19b.1498005061.git.mschiffer@universe-factory.net> ++From: Matthias Schiffer ++Date: Mon, 19 Jun 2017 10:03:59 +0200 ++Subject: [PATCH 3/4] vxlan: fix snooping for link-local IPv6 addresses ++ ++If VXLAN is run over link-local IPv6 addresses, it is necessary to store ++the ifindex in the FDB entries. Otherwise, the used interface is undefined ++and unicast communication will most likely fail. ++ ++Support for link-local IPv4 addresses should be possible as well, but as ++the semantics aren't as well defined as for IPv6, and there doesn't seem to ++be much interest in having the support, it's not implemented for now. ++ ++Signed-off-by: Matthias Schiffer ++Signed-off-by: David S. Miller ++[Matthias Schiffer: rebase to v4.4.y] ++--- ++ drivers/net/vxlan.c | 20 +++++++++++++++----- ++ 1 file changed, 15 insertions(+), 5 deletions(-) ++ ++--- a/drivers/net/vxlan.c +++++ b/drivers/net/vxlan.c ++@@ -947,16 +947,25 @@ out: ++ * Return true if packet is bogus and should be dropped. ++ */ ++ static bool vxlan_snoop(struct net_device *dev, ++- union vxlan_addr *src_ip, const u8 *src_mac) +++ union vxlan_addr *src_ip, const u8 *src_mac, +++ u32 src_ifindex) ++ { ++ struct vxlan_dev *vxlan = netdev_priv(dev); ++ struct vxlan_fdb *f; +++ u32 ifindex = 0; +++ +++#if IS_ENABLED(CONFIG_IPV6) +++ if (src_ip->sa.sa_family == AF_INET6 && +++ (ipv6_addr_type(&src_ip->sin6.sin6_addr) & IPV6_ADDR_LINKLOCAL)) +++ ifindex = src_ifindex; +++#endif ++ ++ f = vxlan_find_mac(vxlan, src_mac); ++ if (likely(f)) { ++ struct vxlan_rdst *rdst = first_remote_rcu(f); ++ ++- if (likely(vxlan_addr_equal(&rdst->remote_ip, src_ip))) +++ if (likely(vxlan_addr_equal(&rdst->remote_ip, src_ip) && +++ rdst->remote_ifindex == ifindex)) ++ return false; ++ ++ /* Don't migrate static entries, drop packets */ ++@@ -982,7 +991,7 @@ static bool vxlan_snoop(struct net_devic ++ NLM_F_EXCL|NLM_F_CREATE, ++ vxlan->cfg.dst_port, ++ vxlan->default_dst.remote_vni, ++- 0, NTF_SELF); +++ ifindex, NTF_SELF); ++ spin_unlock(&vxlan->hash_lock); ++ } ++ ++@@ -1157,6 +1166,7 @@ static void vxlan_rcv(struct vxlan_sock ++ struct vxlan_dev *vxlan; ++ struct pcpu_sw_netstats *stats; ++ union vxlan_addr saddr; +++ u32 ifindex = skb->dev->ifindex; ++ int err = 0; ++ ++ /* For flow based devices, map all packets to VNI 0 */ ++@@ -1196,7 +1206,7 @@ static void vxlan_rcv(struct vxlan_sock ++ } ++ ++ if ((vxlan->flags & VXLAN_F_LEARN) && ++- vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source)) +++ vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source, ifindex)) ++ goto drop; ++ ++ skb_reset_network_header(skb); ++@@ -1898,7 +1908,7 @@ static void vxlan_encap_bypass(struct sk ++ } ++ ++ if (dst_vxlan->flags & VXLAN_F_LEARN) ++- vxlan_snoop(skb->dev, &loopback, eth_hdr(skb)->h_source); +++ vxlan_snoop(skb->dev, &loopback, eth_hdr(skb)->h_source, 0); ++ ++ u64_stats_update_begin(&tx_stats->syncp); ++ tx_stats->tx_packets++; +diff --git a/target/linux/generic/patches-4.4/075-0004-vxlan-allow-multiple-VXLANs-with-same-VNI-for-IPv6-l.patch b/target/linux/generic/patches-4.4/075-0004-vxlan-allow-multiple-VXLANs-with-same-VNI-for-IPv6-l.patch +new file mode 100644 +index 0000000000000000000000000000000000000000..c184c32385e6c802f1bed7647ce720f0e429f4a5 +--- /dev/null ++++ b/target/linux/generic/patches-4.4/075-0004-vxlan-allow-multiple-VXLANs-with-same-VNI-for-IPv6-l.patch +@@ -0,0 +1,168 @@ ++From 7a1fa05f8d460e2a81cb724f441f7346f950680a Mon Sep 17 00:00:00 2001 ++Message-Id: <7a1fa05f8d460e2a81cb724f441f7346f950680a.1498005061.git.mschiffer@universe-factory.net> ++In-Reply-To: <434a1bb54b24b538f81d7945128b7ca25976d19b.1498005061.git.mschiffer@universe-factory.net> ++References: <434a1bb54b24b538f81d7945128b7ca25976d19b.1498005061.git.mschiffer@universe-factory.net> ++From: Matthias Schiffer ++Date: Mon, 19 Jun 2017 10:04:00 +0200 ++Subject: [PATCH 4/4] vxlan: allow multiple VXLANs with same VNI for IPv6 ++ link-local addresses ++ ++As link-local addresses are only valid for a single interface, we can allow ++to use the same VNI for multiple independent VXLANs, as long as the used ++interfaces are distinct. This way, VXLANs can always be used as a drop-in ++replacement for VLANs with greater ID space. ++ ++This also extends VNI lookup to respect the ifindex when link-local IPv6 ++addresses are used, so using the same VNI on multiple interfaces can ++actually work. ++ ++Signed-off-by: Matthias Schiffer ++Signed-off-by: David S. Miller ++[Matthias Schiffer: rebase to v4.4.y] ++--- ++ drivers/net/vxlan.c | 53 +++++++++++++++++++++++++++++++++++++---------------- ++ 1 file changed, 37 insertions(+), 16 deletions(-) ++ ++--- a/drivers/net/vxlan.c +++++ b/drivers/net/vxlan.c ++@@ -242,22 +242,33 @@ static struct vxlan_sock *vxlan_find_soc ++ return NULL; ++ } ++ ++-static struct vxlan_dev *vxlan_vs_find_vni(struct vxlan_sock *vs, u32 id) +++static struct vxlan_dev *vxlan_vs_find_vni(struct vxlan_sock *vs, int ifindex, +++ u32 id) ++ { ++ struct vxlan_dev *vxlan; ++ ++ hlist_for_each_entry_rcu(vxlan, vni_head(vs, id), hlist) { ++- if (vxlan->default_dst.remote_vni == id) ++- return vxlan; +++ if (vxlan->default_dst.remote_vni != id) +++ continue; +++ +++ if (IS_ENABLED(CONFIG_IPV6)) { +++ const struct vxlan_config *cfg = &vxlan->cfg; +++ +++ if ((vxlan->flags & VXLAN_F_IPV6_LINKLOCAL) && +++ cfg->remote_ifindex != ifindex) +++ continue; +++ } +++ +++ return vxlan; ++ } ++ ++ return NULL; ++ } ++ ++ /* Look up VNI in a per net namespace table */ ++-static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id, ++- sa_family_t family, __be16 port, ++- u32 flags) +++static struct vxlan_dev *vxlan_find_vni(struct net *net, int ifindex, +++ u32 id, sa_family_t family, +++ __be16 port, u32 flags) ++ { ++ struct vxlan_sock *vs; ++ ++@@ -265,7 +276,7 @@ static struct vxlan_dev *vxlan_find_vni( ++ if (!vs) ++ return NULL; ++ ++- return vxlan_vs_find_vni(vs, id); +++ return vxlan_vs_find_vni(vs, ifindex, id); ++ } ++ ++ /* Fill in neighbour message in skbuff. */ ++@@ -1174,7 +1185,7 @@ static void vxlan_rcv(struct vxlan_sock ++ vni = 0; ++ ++ /* Is this VNI defined? */ ++- vxlan = vxlan_vs_find_vni(vs, vni); +++ vxlan = vxlan_vs_find_vni(vs, skb->dev->ifindex, vni); ++ if (!vxlan) ++ goto drop; ++ ++@@ -1942,6 +1953,7 @@ static void vxlan_xmit_one(struct sk_buf ++ u32 vni; ++ __be16 df = 0; ++ __u8 tos, ttl; +++ int ifindex; ++ int err; ++ u32 flags = vxlan->flags; ++ ++@@ -1950,6 +1962,7 @@ static void vxlan_xmit_one(struct sk_buf ++ if (rdst) { ++ dst_port = rdst->remote_port ? rdst->remote_port : vxlan->cfg.dst_port; ++ vni = rdst->remote_vni; +++ ifindex = rdst->remote_ifindex; ++ dst = &rdst->remote_ip; ++ } else { ++ if (!info) { ++@@ -1959,6 +1972,7 @@ static void vxlan_xmit_one(struct sk_buf ++ } ++ dst_port = info->key.tp_dst ? : vxlan->cfg.dst_port; ++ vni = be64_to_cpu(info->key.tun_id); +++ ifindex = 0; ++ remote_ip.sa.sa_family = ip_tunnel_info_af(info); ++ if (remote_ip.sa.sa_family == AF_INET) ++ remote_ip.sin.sin_addr.s_addr = info->key.u.ipv4.dst; ++@@ -2015,7 +2029,7 @@ static void vxlan_xmit_one(struct sk_buf ++ } ++ ++ memset(&fl4, 0, sizeof(fl4)); ++- fl4.flowi4_oif = rdst ? rdst->remote_ifindex : 0; +++ fl4.flowi4_oif = ifindex; ++ fl4.flowi4_tos = RT_TOS(tos); ++ fl4.flowi4_mark = skb->mark; ++ fl4.flowi4_proto = IPPROTO_UDP; ++@@ -2043,7 +2057,7 @@ static void vxlan_xmit_one(struct sk_buf ++ struct vxlan_dev *dst_vxlan; ++ ++ ip_rt_put(rt); ++- dst_vxlan = vxlan_find_vni(vxlan->net, vni, +++ dst_vxlan = vxlan_find_vni(vxlan->net, ifindex, vni, ++ dst->sa.sa_family, dst_port, ++ vxlan->flags); ++ if (!dst_vxlan) ++@@ -2076,8 +2090,7 @@ static void vxlan_xmit_one(struct sk_buf ++ goto drop; ++ sk = vxlan->vn6_sock->sock->sk; ++ ++- ndst = vxlan6_get_route(vxlan, skb, ++- rdst ? rdst->remote_ifindex : 0, +++ ndst = vxlan6_get_route(vxlan, skb, ifindex, ++ &dst->sin6.sin6_addr, &saddr); ++ if (IS_ERR(ndst)) { ++ netdev_dbg(dev, "no route to %pI6\n", ++@@ -2101,7 +2114,7 @@ static void vxlan_xmit_one(struct sk_buf ++ struct vxlan_dev *dst_vxlan; ++ ++ dst_release(ndst); ++- dst_vxlan = vxlan_find_vni(vxlan->net, vni, +++ dst_vxlan = vxlan_find_vni(vxlan->net, ifindex, vni, ++ dst->sa.sa_family, dst_port, ++ vxlan->flags); ++ if (!dst_vxlan) ++@@ -2889,10 +2902,18 @@ static int vxlan_dev_configure(struct ne ++ vxlan->cfg.age_interval = FDB_AGE_DEFAULT; ++ ++ list_for_each_entry(tmp, &vn->vxlan_list, next) { ++- if (tmp->cfg.vni == conf->vni && ++- tmp->cfg.dst_port == vxlan->cfg.dst_port && ++- (tmp->flags & (VXLAN_F_RCV_FLAGS | VXLAN_F_IPV6)) == +++ if (tmp->cfg.vni != conf->vni) +++ continue; +++ if (tmp->cfg.dst_port != vxlan->cfg.dst_port) +++ continue; +++ if ((tmp->flags & (VXLAN_F_RCV_FLAGS | VXLAN_F_IPV6)) != ++ (vxlan->flags & (VXLAN_F_RCV_FLAGS | VXLAN_F_IPV6))) +++ continue; +++ +++ if ((vxlan->flags & VXLAN_F_IPV6_LINKLOCAL) && +++ tmp->cfg.remote_ifindex != vxlan->cfg.remote_ifindex) +++ continue; +++ ++ return -EEXIST; ++ } ++