diff mbox series

[net-next,v3,05/24] ovpn: implement interface creation/destruction via netlink

Message ID 20240506011637.27272-6-antonio@openvpn.net (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series Introducing OpenVPN Data Channel Offload | expand

Checks

Context Check Description
netdev/series_format fail Series longer than 15 patches
netdev/tree_selection success Clearly marked for net-next, async
netdev/ynl success Generated files up to date; no warnings/errors; GEN HAS DIFF 2 files changed, 2613 insertions(+);
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 926 this patch: 926
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers warning 1 maintainers not CCed: openvpn-devel@lists.sourceforge.net
netdev/build_clang success Errors and warnings before: 937 this patch: 937
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api warning Found: 'dev_put(' was: 0 now: 1
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 937 this patch: 937
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 79 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 2 this patch: 2
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2024-05-07--03-00 (tests: 1000)

Commit Message

Antonio Quartulli May 6, 2024, 1:16 a.m. UTC
Allow userspace to create and destroy an interface using netlink
commands.

Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
---
 drivers/net/ovpn/main.h    |  2 ++
 drivers/net/ovpn/netlink.c | 55 ++++++++++++++++++++++++++++++++++++--
 2 files changed, 55 insertions(+), 2 deletions(-)

Comments

Jakub Kicinski May 8, 2024, 12:21 a.m. UTC | #1
On Mon,  6 May 2024 03:16:18 +0200 Antonio Quartulli wrote:
>  int ovpn_nl_new_iface_doit(struct sk_buff *skb, struct genl_info *info)
>  {
> -	return -ENOTSUPP;
> +	const char *ifname = OVPN_DEFAULT_IFNAME;
> +	enum ovpn_mode mode = OVPN_MODE_P2P;
> +	struct net_device *dev;
> +	struct sk_buff *msg;
> +	void *hdr;
> +
> +	if (info->attrs[OVPN_A_IFNAME])
> +		ifname = nla_data(info->attrs[OVPN_A_IFNAME]);
> +
> +	if (info->attrs[OVPN_A_MODE]) {
> +		mode = nla_get_u32(info->attrs[OVPN_A_MODE]);
> +		pr_debug("ovpn: setting device (%s) mode: %u\n", ifname, mode);
> +	}
> +
> +	dev = ovpn_iface_create(ifname, mode, genl_info_net(info));
> +	if (IS_ERR(dev)) {
> +		pr_err("ovpn: error while creating interface %s: %ld\n", ifname,
> +		       PTR_ERR(dev));

Better to send the error to the caller with NL_SET_ERR_MSG_MOD()

> +		return PTR_ERR(dev);
> +	}
> +
> +	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
> +	if (!msg)
> +		return -ENOMEM;
> +
> +	hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &ovpn_nl_family,
> +			  0, OVPN_CMD_NEW_IFACE);

genlmsg_iput() will save you a lot of typing

> +	if (!hdr) {
> +		netdev_err(dev, "%s: cannot create message header\n", __func__);
> +		return -EMSGSIZE;
> +	}
> +
> +	if (nla_put(msg, OVPN_A_IFNAME, strlen(dev->name) + 1, dev->name)) {

nla_put_string() ?

> +		netdev_err(dev, "%s: cannot add ifname to reply\n", __func__);

Probably not worth it, can't happen given the message size

> +		genlmsg_cancel(msg, hdr);
> +		nlmsg_free(msg);
> +		return -EMSGSIZE;
> +	}
> +
> +	genlmsg_end(msg, hdr);
> +
> +	return genlmsg_reply(msg, info);
>  }
>  
>  int ovpn_nl_del_iface_doit(struct sk_buff *skb, struct genl_info *info)
>  {
> -	return -ENOTSUPP;
> +	struct ovpn_struct *ovpn = info->user_ptr[0];
> +
> +	rtnl_lock();
> +	ovpn_iface_destruct(ovpn);
> +	dev_put(ovpn->dev);
> +	rtnl_unlock();
> +
> +	synchronize_net();

Why? 
Antonio Quartulli May 8, 2024, 9:49 a.m. UTC | #2
On 08/05/2024 02:21, Jakub Kicinski wrote:
> On Mon,  6 May 2024 03:16:18 +0200 Antonio Quartulli wrote:
>>   int ovpn_nl_new_iface_doit(struct sk_buff *skb, struct genl_info *info)
>>   {
>> -	return -ENOTSUPP;
>> +	const char *ifname = OVPN_DEFAULT_IFNAME;
>> +	enum ovpn_mode mode = OVPN_MODE_P2P;
>> +	struct net_device *dev;
>> +	struct sk_buff *msg;
>> +	void *hdr;
>> +
>> +	if (info->attrs[OVPN_A_IFNAME])
>> +		ifname = nla_data(info->attrs[OVPN_A_IFNAME]);
>> +
>> +	if (info->attrs[OVPN_A_MODE]) {
>> +		mode = nla_get_u32(info->attrs[OVPN_A_MODE]);
>> +		pr_debug("ovpn: setting device (%s) mode: %u\n", ifname, mode);
>> +	}
>> +
>> +	dev = ovpn_iface_create(ifname, mode, genl_info_net(info));
>> +	if (IS_ERR(dev)) {
>> +		pr_err("ovpn: error while creating interface %s: %ld\n", ifname,
>> +		       PTR_ERR(dev));
> 
> Better to send the error to the caller with NL_SET_ERR_MSG_MOD()

yeah, makes sense. I guess I can do the same for every other error 
generated in any netlink handler.

> 
>> +		return PTR_ERR(dev);
>> +	}
>> +
>> +	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
>> +	if (!msg)
>> +		return -ENOMEM;
>> +
>> +	hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &ovpn_nl_family,
>> +			  0, OVPN_CMD_NEW_IFACE);
> 
> genlmsg_iput() will save you a lot of typing

oh, wow, nice one :) will switch to iput()

> 
>> +	if (!hdr) {
>> +		netdev_err(dev, "%s: cannot create message header\n", __func__);
>> +		return -EMSGSIZE;
>> +	}
>> +
>> +	if (nla_put(msg, OVPN_A_IFNAME, strlen(dev->name) + 1, dev->name)) {
> 
> nla_put_string() ?
> 

right.

>> +		netdev_err(dev, "%s: cannot add ifname to reply\n", __func__);
> 
> Probably not worth it, can't happen given the message size

Personally I still prefer to check the return value of functions that 
may fail, because somebody may break the assumption (i.e. message large 
enough by design) without realizing that this call was relying on that.

If you want, I could still add a comment saying that we don't expect 
this to happen.

> 
>> +		genlmsg_cancel(msg, hdr);
>> +		nlmsg_free(msg);
>> +		return -EMSGSIZE;
>> +	}
>> +
>> +	genlmsg_end(msg, hdr);
>> +
>> +	return genlmsg_reply(msg, info);
>>   }
>>   
>>   int ovpn_nl_del_iface_doit(struct sk_buff *skb, struct genl_info *info)
>>   {
>> -	return -ENOTSUPP;
>> +	struct ovpn_struct *ovpn = info->user_ptr[0];
>> +
>> +	rtnl_lock();
>> +	ovpn_iface_destruct(ovpn);
>> +	dev_put(ovpn->dev);
>> +	rtnl_unlock();
>> +
>> +	synchronize_net();
> 
> Why? 
Jakub Kicinski May 9, 2024, 1:09 a.m. UTC | #3
On Wed, 8 May 2024 11:49:07 +0200 Antonio Quartulli wrote:
> >> +		netdev_err(dev, "%s: cannot add ifname to reply\n", __func__);  
> > 
> > Probably not worth it, can't happen given the message size  
> 
> Personally I still prefer to check the return value of functions that 
> may fail, because somebody may break the assumption (i.e. message large 
> enough by design) without realizing that this call was relying on that.
> 
> If you want, I could still add a comment saying that we don't expect 
> this to happen.

In a few other places we put a WARN_ON_ONCE() on messages size errors.
That way syzbot usually catches the miscalculation rather quickly.
But no strong objections if you prefer the print.
  
> >> +		genlmsg_cancel(msg, hdr);
> >> +		nlmsg_free(msg);
> >> +		return -EMSGSIZE;
> >> +	}
> >> +
> >> +	genlmsg_end(msg, hdr);
> >> +
> >> +	return genlmsg_reply(msg, info);
> >>   }
> >>   
> >>   int ovpn_nl_del_iface_doit(struct sk_buff *skb, struct genl_info *info)
> >>   {
> >> -	return -ENOTSUPP;
> >> +	struct ovpn_struct *ovpn = info->user_ptr[0];
> >> +
> >> +	rtnl_lock();
> >> +	ovpn_iface_destruct(ovpn);
> >> +	dev_put(ovpn->dev);
> >> +	rtnl_unlock();
> >> +
> >> +	synchronize_net();  
> > 
> > Why? 
Antonio Quartulli May 9, 2024, 8:30 a.m. UTC | #4
On 09/05/2024 03:09, Jakub Kicinski wrote:
> On Wed, 8 May 2024 11:49:07 +0200 Antonio Quartulli wrote:
>>>> +		netdev_err(dev, "%s: cannot add ifname to reply\n", __func__);
>>>
>>> Probably not worth it, can't happen given the message size
>>
>> Personally I still prefer to check the return value of functions that
>> may fail, because somebody may break the assumption (i.e. message large
>> enough by design) without realizing that this call was relying on that.
>>
>> If you want, I could still add a comment saying that we don't expect
>> this to happen.
> 
> In a few other places we put a WARN_ON_ONCE() on messages size errors.
> That way syzbot usually catches the miscalculation rather quickly.
> But no strong objections if you prefer the print.

I am fine as long as we have some check.
If WARN_ON_ONCE() helps syzbot, then I'll go with it.

>    
>>>> +		genlmsg_cancel(msg, hdr);
>>>> +		nlmsg_free(msg);
>>>> +		return -EMSGSIZE;
>>>> +	}
>>>> +
>>>> +	genlmsg_end(msg, hdr);
>>>> +
>>>> +	return genlmsg_reply(msg, info);
>>>>    }
>>>>    
>>>>    int ovpn_nl_del_iface_doit(struct sk_buff *skb, struct genl_info *info)
>>>>    {
>>>> -	return -ENOTSUPP;
>>>> +	struct ovpn_struct *ovpn = info->user_ptr[0];
>>>> +
>>>> +	rtnl_lock();
>>>> +	ovpn_iface_destruct(ovpn);
>>>> +	dev_put(ovpn->dev);
>>>> +	rtnl_unlock();
>>>> +
>>>> +	synchronize_net();
>>>
>>> Why? 
diff mbox series

Patch

diff --git a/drivers/net/ovpn/main.h b/drivers/net/ovpn/main.h
index 21d6bfb27d67..12b8d7e4a0fe 100644
--- a/drivers/net/ovpn/main.h
+++ b/drivers/net/ovpn/main.h
@@ -10,6 +10,8 @@ 
 #ifndef _NET_OVPN_MAIN_H_
 #define _NET_OVPN_MAIN_H_
 
+#define OVPN_DEFAULT_IFNAME "ovpn%d"
+
 /**
  * ovpn_iface_create - create and initialize a new 'ovpn' netdevice
  * @name: the name of the new device
diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c
index c0a9f58e0e87..66f5c6fbe8e4 100644
--- a/drivers/net/ovpn/netlink.c
+++ b/drivers/net/ovpn/netlink.c
@@ -7,6 +7,7 @@ 
  */
 
 #include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
 #include <net/genetlink.h>
 
 #include <uapi/linux/ovpn.h>
@@ -78,12 +79,62 @@  void ovpn_nl_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb,
 
 int ovpn_nl_new_iface_doit(struct sk_buff *skb, struct genl_info *info)
 {
-	return -ENOTSUPP;
+	const char *ifname = OVPN_DEFAULT_IFNAME;
+	enum ovpn_mode mode = OVPN_MODE_P2P;
+	struct net_device *dev;
+	struct sk_buff *msg;
+	void *hdr;
+
+	if (info->attrs[OVPN_A_IFNAME])
+		ifname = nla_data(info->attrs[OVPN_A_IFNAME]);
+
+	if (info->attrs[OVPN_A_MODE]) {
+		mode = nla_get_u32(info->attrs[OVPN_A_MODE]);
+		pr_debug("ovpn: setting device (%s) mode: %u\n", ifname, mode);
+	}
+
+	dev = ovpn_iface_create(ifname, mode, genl_info_net(info));
+	if (IS_ERR(dev)) {
+		pr_err("ovpn: error while creating interface %s: %ld\n", ifname,
+		       PTR_ERR(dev));
+		return PTR_ERR(dev);
+	}
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &ovpn_nl_family,
+			  0, OVPN_CMD_NEW_IFACE);
+	if (!hdr) {
+		netdev_err(dev, "%s: cannot create message header\n", __func__);
+		return -EMSGSIZE;
+	}
+
+	if (nla_put(msg, OVPN_A_IFNAME, strlen(dev->name) + 1, dev->name)) {
+		netdev_err(dev, "%s: cannot add ifname to reply\n", __func__);
+		genlmsg_cancel(msg, hdr);
+		nlmsg_free(msg);
+		return -EMSGSIZE;
+	}
+
+	genlmsg_end(msg, hdr);
+
+	return genlmsg_reply(msg, info);
 }
 
 int ovpn_nl_del_iface_doit(struct sk_buff *skb, struct genl_info *info)
 {
-	return -ENOTSUPP;
+	struct ovpn_struct *ovpn = info->user_ptr[0];
+
+	rtnl_lock();
+	ovpn_iface_destruct(ovpn);
+	dev_put(ovpn->dev);
+	rtnl_unlock();
+
+	synchronize_net();
+
+	return 0;
 }
 
 int ovpn_nl_set_peer_doit(struct sk_buff *skb, struct genl_info *info)