Commit a8907617 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'ndo_tunnel_ioctl'



Christoph Hellwig says:

====================
add a new ->ndo_tunnel_ctl method to avoid a few set_fs calls v2

both the ipv4 and ipv6 code have an ioctl each that can be used to create
a tunnel using code that doesn't live in the core kernel or ipv6 module.
Currently they call ioctls on the tunnel devices to create these, for
which the code needs to override the address limit, which is a "feature"
I plan to get rid of.

Instead this patchset adds a new ->ndo_tunnel_ctl that can be used for
the tunnel configuration using struct ip_tunnel_parm.  The method is
either invoked from a helper that does the uaccess and can be wired up
as ndo_do_ioctl method, or directly from the magic IPV4/6 ioctls that
create tunnels with kernel space arguments.

Changes since v2:
 - properly propagate errors in ipip6_tunnel_prl_ctl
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents befb270f 8e3db0bb
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ struct netpoll_info;
struct device;
struct phy_device;
struct dsa_port;
struct ip_tunnel_parm;
struct macsec_context;
struct macsec_ops;

@@ -1274,6 +1275,9 @@ struct netdev_net_notifier {
 *	Get devlink port instance associated with a given netdev.
 *	Called with a reference on the netdevice and devlink locks only,
 *	rtnl_lock is not held.
 * int (*ndo_tunnel_ctl)(struct net_device *dev, struct ip_tunnel_parm *p,
 *			 int cmd);
 *	Add, change, delete or get information on an IPv4 tunnel.
 */
struct net_device_ops {
	int			(*ndo_init)(struct net_device *dev);
@@ -1479,6 +1483,8 @@ struct net_device_ops {
	int			(*ndo_xsk_wakeup)(struct net_device *dev,
						  u32 queue_id, u32 flags);
	struct devlink_port *	(*ndo_get_devlink_port)(struct net_device *dev);
	int			(*ndo_tunnel_ctl)(struct net_device *dev,
						  struct ip_tunnel_parm *p, int cmd);
};

/**
+2 −1
Original line number Diff line number Diff line
@@ -269,7 +269,8 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
		    const struct iphdr *tnl_params, const u8 protocol);
void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
		       const u8 proto, int tunnel_hlen);
int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd);
int ip_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd);
int ip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
int __ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict);
int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu);

+14 −21
Original line number Diff line number Diff line
@@ -768,45 +768,37 @@ static void ipgre_link_update(struct net_device *dev, bool set_mtu)
	}
}

static int ipgre_tunnel_ioctl(struct net_device *dev,
			      struct ifreq *ifr, int cmd)
static int ipgre_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm *p,
			    int cmd)
{
	struct ip_tunnel_parm p;
	int err;

	if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
		return -EFAULT;

	if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
		if (p.iph.version != 4 || p.iph.protocol != IPPROTO_GRE ||
		    p.iph.ihl != 5 || (p.iph.frag_off & htons(~IP_DF)) ||
		    ((p.i_flags | p.o_flags) & (GRE_VERSION | GRE_ROUTING)))
		if (p->iph.version != 4 || p->iph.protocol != IPPROTO_GRE ||
		    p->iph.ihl != 5 || (p->iph.frag_off & htons(~IP_DF)) ||
		    ((p->i_flags | p->o_flags) & (GRE_VERSION | GRE_ROUTING)))
			return -EINVAL;
	}

	p.i_flags = gre_flags_to_tnl_flags(p.i_flags);
	p.o_flags = gre_flags_to_tnl_flags(p.o_flags);
	p->i_flags = gre_flags_to_tnl_flags(p->i_flags);
	p->o_flags = gre_flags_to_tnl_flags(p->o_flags);

	err = ip_tunnel_ioctl(dev, &p, cmd);
	err = ip_tunnel_ctl(dev, p, cmd);
	if (err)
		return err;

	if (cmd == SIOCCHGTUNNEL) {
		struct ip_tunnel *t = netdev_priv(dev);

		t->parms.i_flags = p.i_flags;
		t->parms.o_flags = p.o_flags;
		t->parms.i_flags = p->i_flags;
		t->parms.o_flags = p->o_flags;

		if (strcmp(dev->rtnl_link_ops->kind, "erspan"))
			ipgre_link_update(dev, true);
	}

	p.i_flags = gre_tnl_flags_to_gre_flags(p.i_flags);
	p.o_flags = gre_tnl_flags_to_gre_flags(p.o_flags);

	if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
		return -EFAULT;

	p->i_flags = gre_tnl_flags_to_gre_flags(p->i_flags);
	p->o_flags = gre_tnl_flags_to_gre_flags(p->o_flags);
	return 0;
}

@@ -924,10 +916,11 @@ static const struct net_device_ops ipgre_netdev_ops = {
	.ndo_stop		= ipgre_close,
#endif
	.ndo_start_xmit		= ipgre_xmit,
	.ndo_do_ioctl		= ipgre_tunnel_ioctl,
	.ndo_do_ioctl		= ip_tunnel_ioctl,
	.ndo_change_mtu		= ip_tunnel_change_mtu,
	.ndo_get_stats64	= ip_tunnel_get_stats64,
	.ndo_get_iflink		= ip_tunnel_get_iflink,
	.ndo_tunnel_ctl		= ipgre_tunnel_ctl,
};

#define GRE_FEATURES (NETIF_F_SG |		\
+15 −1
Original line number Diff line number Diff line
@@ -860,7 +860,7 @@ static void ip_tunnel_update(struct ip_tunnel_net *itn,
	netdev_state_change(dev);
}

int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
int ip_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
{
	int err = 0;
	struct ip_tunnel *t = netdev_priv(dev);
@@ -960,6 +960,20 @@ int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
done:
	return err;
}
EXPORT_SYMBOL_GPL(ip_tunnel_ctl);

int ip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
	struct ip_tunnel_parm p;
	int err;

	if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
		return -EFAULT;
	err = dev->netdev_ops->ndo_tunnel_ctl(dev, &p, cmd);
	if (!err && copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
		return -EFAULT;
	return err;
}
EXPORT_SYMBOL_GPL(ip_tunnel_ioctl);

int __ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict)
+13 −19
Original line number Diff line number Diff line
@@ -378,38 +378,31 @@ static int vti4_err(struct sk_buff *skb, u32 info)
}

static int
vti_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
vti_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
{
	int err = 0;
	struct ip_tunnel_parm p;

	if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
		return -EFAULT;

	if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
		if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPIP ||
		    p.iph.ihl != 5)
		if (p->iph.version != 4 || p->iph.protocol != IPPROTO_IPIP ||
		    p->iph.ihl != 5)
			return -EINVAL;
	}

	if (!(p.i_flags & GRE_KEY))
		p.i_key = 0;
	if (!(p.o_flags & GRE_KEY))
		p.o_key = 0;
	if (!(p->i_flags & GRE_KEY))
		p->i_key = 0;
	if (!(p->o_flags & GRE_KEY))
		p->o_key = 0;

	p.i_flags = VTI_ISVTI;
	p->i_flags = VTI_ISVTI;

	err = ip_tunnel_ioctl(dev, &p, cmd);
	err = ip_tunnel_ctl(dev, p, cmd);
	if (err)
		return err;

	if (cmd != SIOCDELTUNNEL) {
		p.i_flags |= GRE_KEY;
		p.o_flags |= GRE_KEY;
		p->i_flags |= GRE_KEY;
		p->o_flags |= GRE_KEY;
	}

	if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
		return -EFAULT;
	return 0;
}

@@ -417,10 +410,11 @@ static const struct net_device_ops vti_netdev_ops = {
	.ndo_init	= vti_tunnel_init,
	.ndo_uninit	= ip_tunnel_uninit,
	.ndo_start_xmit	= vti_tunnel_xmit,
	.ndo_do_ioctl	= vti_tunnel_ioctl,
	.ndo_do_ioctl	= ip_tunnel_ioctl,
	.ndo_change_mtu	= ip_tunnel_change_mtu,
	.ndo_get_stats64 = ip_tunnel_get_stats64,
	.ndo_get_iflink = ip_tunnel_get_iflink,
	.ndo_tunnel_ctl	= vti_tunnel_ctl,
};

static void vti_tunnel_setup(struct net_device *dev)
Loading