Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1623770 > unrolled thread
| Started by | Matthias Schiffer <mschiffer@universe-factory.net> |
|---|---|
| First post | 2017-04-14 18:50 +0200 |
| Last post | 2017-04-14 18:50 +0200 |
| Articles | 3 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH net-next v2 0/6] vxlan: cleanup and IPv6 link-local support Matthias Schiffer <mschiffer@universe-factory.net> - 2017-04-14 18:50 +0200
[PATCH net-next v2 3/6] vxlan: improve validation of address family configuration Matthias Schiffer <mschiffer@universe-factory.net> - 2017-04-14 18:50 +0200
[PATCH net-next v2 1/6] vxlan: refactor verification and application of configuration Matthias Schiffer <mschiffer@universe-factory.net> - 2017-04-14 18:50 +0200
| From | Matthias Schiffer <mschiffer@universe-factory.net> |
|---|---|
| Date | 2017-04-14 18:50 +0200 |
| Subject | [PATCH net-next v2 0/6] vxlan: cleanup and IPv6 link-local support |
| Message-ID | <twcA1-3pr-3@gated-at.bofh.it> |
Running VXLANs over IPv6 link-local addresses allows to use them as a
drop-in replacement for VLANs, avoiding to allocate additional outer IP
addresses to run the VXLAN over.
Since v1, I have added a lot more consistency checks to the address
configuration, making sure address families and scopes match. To simplify
the implementation, I also did some general refactoring of the
configuration handling in the new first patch of the series.
The second patch is more cleanup; is slightly touches OVS code, so that
list is in CC this time, too.
As in v1, the last two patches actually make VXLAN over IPv6 link-local
work, and allow multiple VXLANs wit the same VNI and port, as long as
link-local addresses on different interfaces are used. As suggested, I now
store in the flags field if the VXLAN uses link-local addresses or not.
Matthias Schiffer (6):
vxlan: refactor verification and application of configuration
vxlan: get rid of redundant vxlan_dev.flags
vxlan: improve validation of address family configuration
vxlan: check valid combinations of address scopes
vxlan: fix snooping for link-local IPv6 addresses
vxlan: allow multiple VXLANs with same VNI for IPv6 link-local
addresses
drivers/net/vxlan.c | 411 ++++++++++++++++++++++++++----------------
include/net/vxlan.h | 3 +-
net/openvswitch/vport-vxlan.c | 4 +-
3 files changed, 263 insertions(+), 155 deletions(-)
--
2.12.2
[toc] | [next] | [standalone]
| From | Matthias Schiffer <mschiffer@universe-factory.net> |
|---|---|
| Date | 2017-04-14 18:50 +0200 |
| Subject | [PATCH net-next v2 3/6] vxlan: improve validation of address family configuration |
| Message-ID | <twcA2-3pr-27@gated-at.bofh.it> |
| In reply to | #1623770 |
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 <mschiffer@universe-factory.net>
---
v2: new patch
drivers/net/vxlan.c | 39 ++++++++++++++++++++++++++++-----------
1 file changed, 28 insertions(+), 11 deletions(-)
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index bdd19e5037b0..07f89b037681 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -2459,10 +2459,7 @@ static int vxlan_change_mtu(struct net_device *dev, int new_mtu)
struct vxlan_rdst *dst = &vxlan->default_dst;
struct net_device *lowerdev = __dev_get_by_index(vxlan->net,
dst->remote_ifindex);
- bool use_ipv6 = false;
-
- if (dst->remote_ip.sa.sa_family == AF_INET6)
- use_ipv6 = true;
+ bool use_ipv6 = !!(vxlan->cfg.flags & VXLAN_F_IPV6);
/* This check is different than dev->max_mtu, because it looks at
* the lowerdev->mtu, rather than the static dev->max_mtu
@@ -2871,11 +2868,20 @@ static int vxlan_config_validate(struct net *src_net, struct vxlan_config *conf,
}
}
- if (!conf->remote_ip.sa.sa_family)
+ if (!conf->remote_ip.sa.sa_family && !conf->saddr.sa.sa_family) {
+ /* Unless IPv6 is explicitly requested, assume IPv4 */
conf->remote_ip.sa.sa_family = AF_INET;
+ conf->saddr.sa.sa_family = AF_INET;
+ } else if (!conf->remote_ip.sa.sa_family) {
+ conf->remote_ip.sa.sa_family = conf->saddr.sa.sa_family;
+ } else if (!conf->saddr.sa.sa_family) {
+ conf->saddr.sa.sa_family = conf->remote_ip.sa.sa_family;
+ }
+
+ if (conf->saddr.sa.sa_family != conf->remote_ip.sa.sa_family)
+ return -EINVAL;
- if (conf->remote_ip.sa.sa_family == AF_INET6 ||
- conf->saddr.sa.sa_family == AF_INET6) {
+ if (conf->saddr.sa.sa_family == AF_INET6) {
if (!IS_ENABLED(CONFIG_IPV6))
return -EPFNOSUPPORT;
use_ipv6 = true;
@@ -2932,11 +2938,9 @@ static int vxlan_config_validate(struct net *src_net, struct vxlan_config *conf,
continue;
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 == conf->dst_port &&
- (tmp->cfg.flags & VXLAN_F_RCV_FLAGS) ==
- (conf->flags & VXLAN_F_RCV_FLAGS)) {
+ (tmp->cfg.flags & (VXLAN_F_RCV_FLAGS | VXLAN_F_IPV6)) ==
+ (conf->flags & (VXLAN_F_RCV_FLAGS | VXLAN_F_IPV6))) {
pr_info("duplicate VNI %u\n", be32_to_cpu(conf->vni));
return -EEXIST;
}
@@ -3069,22 +3073,35 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[],
}
if (data[IFLA_VXLAN_GROUP]) {
+ if (changelink && (conf->remote_ip.sa.sa_family != AF_INET))
+ return -EOPNOTSUPP;
+
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;
+ if (changelink && (conf->remote_ip.sa.sa_family != AF_INET6))
+ return -EOPNOTSUPP;
+
conf->remote_ip.sin6.sin6_addr = nla_get_in6_addr(data[IFLA_VXLAN_GROUP6]);
conf->remote_ip.sa.sa_family = AF_INET6;
}
if (data[IFLA_VXLAN_LOCAL]) {
+ if (changelink && (conf->saddr.sa.sa_family != AF_INET))
+ return -EOPNOTSUPP;
+
conf->saddr.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_LOCAL]);
conf->saddr.sa.sa_family = AF_INET;
} else if (data[IFLA_VXLAN_LOCAL6]) {
if (!IS_ENABLED(CONFIG_IPV6))
return -EPFNOSUPPORT;
+ if (changelink && (conf->saddr.sa.sa_family != AF_INET6))
+ return -EOPNOTSUPP;
+
/* TODO: respect scope id */
conf->saddr.sin6.sin6_addr = nla_get_in6_addr(data[IFLA_VXLAN_LOCAL6]);
conf->saddr.sa.sa_family = AF_INET6;
--
2.12.2
[toc] | [prev] | [next] | [standalone]
| From | Matthias Schiffer <mschiffer@universe-factory.net> |
|---|---|
| Date | 2017-04-14 18:50 +0200 |
| Subject | [PATCH net-next v2 1/6] vxlan: refactor verification and application of configuration |
| Message-ID | <twcA2-3pr-29@gated-at.bofh.it> |
| In reply to | #1623770 |
The vxlan_dev_configure function was mixing validation and application of
the vxlan configuration; this could easily lead to bugs with the changelink
operation, as it was hard to see if the function wcould return an error
after parts of the configuration had already been applied.
This commit splits validation and application out of vxlan_dev_configure as
separate functions to make it clearer where error returns are allowed and
where the vxlan_dev or net_device may be configured.
In addition, some validation is moved to vxlan_validate and some
initialization to vxlan_setup where this improves grouping of similar
settings.
Finally, this also fixes two actual bugs:
* if set, conf->mtu would overwrite dev->mtu in each changelink operation,
reverting other changes of dev->mtu
* the "if (!conf->dst_port)" branch would never be run, as conf->dst_port
was set in vxlan_setup before. This caused VXLAN-GPE to use the same
default port as other VXLAN sockets instead of the intended IANA-assigned
4790.
Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
---
v2: new patch
drivers/net/vxlan.c | 202 +++++++++++++++++++++++++++++-----------------------
1 file changed, 114 insertions(+), 88 deletions(-)
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index ebc98bb17a51..86471e961708 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -2598,6 +2598,10 @@ static void vxlan_setup(struct net_device *dev)
netif_keep_dst(dev);
dev->priv_flags |= IFF_NO_QUEUE;
+ /* MTU range: 68 - 65535 */
+ dev->min_mtu = ETH_MIN_MTU;
+ dev->max_mtu = ETH_MAX_MTU;
+
INIT_LIST_HEAD(&vxlan->next);
spin_lock_init(&vxlan->hash_lock);
@@ -2605,9 +2609,8 @@ static void vxlan_setup(struct net_device *dev)
vxlan->age_timer.function = vxlan_cleanup;
vxlan->age_timer.data = (unsigned long) vxlan;
- vxlan->cfg.dst_port = htons(vxlan_port);
-
vxlan->dev = dev;
+ vxlan->net = dev_net(dev);
gro_cells_init(&vxlan->gro_cells, dev);
@@ -2676,11 +2679,19 @@ static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[])
}
}
+ if (tb[IFLA_MTU]) {
+ u32 mtu = nla_get_u32(data[IFLA_MTU]);
+
+ if (mtu < ETH_MIN_MTU || mtu > ETH_MAX_MTU)
+ return -EINVAL;
+ }
+
if (!data)
return -EINVAL;
if (data[IFLA_VXLAN_ID]) {
- __u32 id = nla_get_u32(data[IFLA_VXLAN_ID]);
+ u32 id = nla_get_u32(data[IFLA_VXLAN_ID]);
+
if (id >= VXLAN_N_VID)
return -ERANGE;
}
@@ -2839,55 +2850,36 @@ static int vxlan_sock_add(struct vxlan_dev *vxlan)
return ret;
}
-static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,
- struct vxlan_config *conf,
- bool changelink)
+static int vxlan_config_validate(struct net *src_net, struct vxlan_config *conf,
+ struct net_device **lower,
+ struct vxlan_dev *old)
{
struct vxlan_net *vn = net_generic(src_net, vxlan_net_id);
- struct vxlan_dev *vxlan = netdev_priv(dev), *tmp;
- struct vxlan_rdst *dst = &vxlan->default_dst;
- unsigned short needed_headroom = ETH_HLEN;
+ struct vxlan_dev *tmp;
bool use_ipv6 = false;
- __be16 default_port = vxlan->cfg.dst_port;
- struct net_device *lowerdev = NULL;
- if (!changelink) {
- if (conf->flags & VXLAN_F_GPE) {
- /* For now, allow GPE only together with
- * COLLECT_METADATA. This can be relaxed later; in such
- * case, the other side of the PtP link will have to be
- * provided.
- */
- if ((conf->flags & ~VXLAN_F_ALLOWED_GPE) ||
- !(conf->flags & VXLAN_F_COLLECT_METADATA)) {
- pr_info("unsupported combination of extensions\n");
- return -EINVAL;
- }
- vxlan_raw_setup(dev);
- } else {
- vxlan_ether_setup(dev);
+ if (conf->flags & VXLAN_F_GPE) {
+ /* For now, allow GPE only together with
+ * COLLECT_METADATA. This can be relaxed later; in such
+ * case, the other side of the PtP link will have to be
+ * provided.
+ */
+ if ((conf->flags & ~VXLAN_F_ALLOWED_GPE) ||
+ !(conf->flags & VXLAN_F_COLLECT_METADATA)) {
+ pr_info("unsupported combination of extensions\n");
+ return -EINVAL;
}
-
- /* MTU range: 68 - 65535 */
- dev->min_mtu = ETH_MIN_MTU;
- dev->max_mtu = ETH_MAX_MTU;
- vxlan->net = src_net;
}
- dst->remote_vni = conf->vni;
-
- 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)
- dst->remote_ip.sa.sa_family = AF_INET;
+ if (!conf->remote_ip.sa.sa_family)
+ conf->remote_ip.sa.sa_family = AF_INET;
- if (dst->remote_ip.sa.sa_family == AF_INET6 ||
- vxlan->cfg.saddr.sa.sa_family == AF_INET6) {
+ if (conf->remote_ip.sa.sa_family == AF_INET6 ||
+ conf->saddr.sa.sa_family == AF_INET6) {
if (!IS_ENABLED(CONFIG_IPV6))
return -EPFNOSUPPORT;
use_ipv6 = true;
- vxlan->flags |= VXLAN_F_IPV6;
+ conf->flags |= VXLAN_F_IPV6;
}
if (conf->label && !use_ipv6) {
@@ -2895,14 +2887,13 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,
return -EINVAL;
}
- if (conf->remote_ifindex &&
- conf->remote_ifindex != vxlan->cfg.remote_ifindex) {
- lowerdev = __dev_get_by_index(src_net, conf->remote_ifindex);
- dst->remote_ifindex = conf->remote_ifindex;
+ if (conf->remote_ifindex) {
+ struct net_device *lowerdev;
+ lowerdev = __dev_get_by_index(src_net, conf->remote_ifindex);
if (!lowerdev) {
pr_info("ifindex %d does not exist\n",
- dst->remote_ifindex);
+ conf->remote_ifindex);
return -ENODEV;
}
@@ -2916,39 +2907,83 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,
}
#endif
- if (!conf->mtu)
- dev->mtu = lowerdev->mtu -
- (use_ipv6 ? VXLAN6_HEADROOM : VXLAN_HEADROOM);
+ *lower = lowerdev;
+ } else {
+ if (vxlan_addr_multicast(&conf->remote_ip)) {
+ pr_info("multicast destination requires interface to be specified\n");
+ return -EINVAL;
+ }
- needed_headroom = lowerdev->hard_header_len;
- } else if (!conf->remote_ifindex &&
- vxlan_addr_multicast(&dst->remote_ip)) {
- pr_info("multicast destination requires interface to be specified\n");
- return -EINVAL;
+ *lower = NULL;
}
- if (lowerdev) {
- dev->gso_max_size = lowerdev->gso_max_size;
- dev->gso_max_segs = lowerdev->gso_max_segs;
+ if (!conf->dst_port) {
+ if (conf->flags & VXLAN_F_GPE)
+ conf->dst_port = htons(4790); /* IANA VXLAN-GPE port */
+ else
+ conf->dst_port = htons(vxlan_port);
}
- if (conf->mtu) {
- int max_mtu = ETH_MAX_MTU;
+ if (!conf->age_interval)
+ conf->age_interval = FDB_AGE_DEFAULT;
- if (lowerdev)
- max_mtu = lowerdev->mtu;
+ list_for_each_entry(tmp, &vn->vxlan_list, next) {
+ if (tmp == old)
+ continue;
- max_mtu -= (use_ipv6 ? VXLAN6_HEADROOM : VXLAN_HEADROOM);
+ 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 == conf->dst_port &&
+ (tmp->flags & VXLAN_F_RCV_FLAGS) ==
+ (conf->flags & VXLAN_F_RCV_FLAGS)) {
+ pr_info("duplicate VNI %u\n", be32_to_cpu(conf->vni));
+ return -EEXIST;
+ }
+ }
- if (conf->mtu < dev->min_mtu || conf->mtu > dev->max_mtu)
- return -EINVAL;
+ return 0;
+}
- dev->mtu = conf->mtu;
+static void vxlan_config_apply(struct net_device *dev,
+ struct vxlan_config *conf,
+ struct net_device *lowerdev, bool changelink)
+{
+ struct vxlan_dev *vxlan = netdev_priv(dev);
+ struct vxlan_rdst *dst = &vxlan->default_dst;
+ unsigned short needed_headroom = ETH_HLEN;
+ bool use_ipv6 = !!(conf->flags & VXLAN_F_IPV6);
+ int max_mtu = ETH_MAX_MTU;
- if (conf->mtu > max_mtu)
- dev->mtu = max_mtu;
+ if (!changelink) {
+ if (conf->flags & VXLAN_F_GPE)
+ vxlan_raw_setup(dev);
+ else
+ vxlan_ether_setup(dev);
+
+ if (conf->mtu)
+ dev->mtu = conf->mtu;
}
+ dst->remote_vni = conf->vni;
+
+ memcpy(&dst->remote_ip, &conf->remote_ip, sizeof(conf->remote_ip));
+
+ if (lowerdev) {
+ dst->remote_ifindex = conf->remote_ifindex;
+
+ dev->gso_max_size = lowerdev->gso_max_size;
+ dev->gso_max_segs = lowerdev->gso_max_segs;
+
+ needed_headroom = lowerdev->hard_header_len;
+
+ max_mtu = lowerdev->mtu - (use_ipv6 ? VXLAN6_HEADROOM :
+ VXLAN_HEADROOM);
+ }
+
+ if (dev->mtu > max_mtu)
+ dev->mtu = max_mtu;
+
if (use_ipv6 || conf->flags & VXLAN_F_COLLECT_METADATA)
needed_headroom += VXLAN6_HEADROOM;
else
@@ -2956,31 +2991,22 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,
dev->needed_headroom = needed_headroom;
memcpy(&vxlan->cfg, conf, sizeof(*conf));
- if (!vxlan->cfg.dst_port) {
- if (conf->flags & VXLAN_F_GPE)
- vxlan->cfg.dst_port = htons(4790); /* IANA VXLAN-GPE port */
- else
- vxlan->cfg.dst_port = default_port;
- }
vxlan->flags |= conf->flags;
+}
- if (!vxlan->cfg.age_interval)
- vxlan->cfg.age_interval = FDB_AGE_DEFAULT;
+static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,
+ struct vxlan_config *conf,
+ bool changelink)
+{
+ struct vxlan_dev *vxlan = netdev_priv(dev);
+ struct net_device *lowerdev;
+ int ret;
- if (changelink)
- return 0;
+ ret = vxlan_config_validate(src_net, conf, &lowerdev, vxlan);
+ if (ret)
+ return ret;
- 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)) {
- pr_info("duplicate VNI %u\n", be32_to_cpu(conf->vni));
- return -EEXIST;
- }
- }
+ vxlan_config_apply(dev, conf, lowerdev, changelink);
return 0;
}
--
2.12.2
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web