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

Merge branch 'dsa_master_ioctl-notifier'

Vladimir Oltean says:

====================
net: Convert dsa_master_ioctl() to netdev notifier

This is preparatory work in order for Maxim Georgiev to be able to start
the API conversion process of hardware timestamping from ndo_eth_ioctl()
to ndo_hwtstamp_set():
https://lore.kernel.org/netdev/20230331045619.40256-1-glipus@gmail.com/

In turn, Maxim Georgiev's work is a preparation so that Köry Maincent is
able to make the active hardware timestamping layer selectable by user
space.
https://lore.kernel.org/netdev/20230308135936.761794-1-kory.maincent@bootlin.com/



So, quite some dependency chain.

Before this patch set, DSA prevented the conversion of any networking
driver from the ndo_eth_ioctl() API to the ndo_hwtstamp_set() API,
because it wanted to validate the hwtstamping settings on the DSA
master, and it was only coded up to do this using the old API.

After this patch set, a new netdev notifier exists, which does not
depend on anything that would constitute the "soon-to-be-legacy" API,
but rather, it uses a newly introduced struct kernel_hwtstamp_config,
and it doesn't issue any ioctl at all, being thus compatible both with
ndo_eth_ioctl(), and with the not-yet-introduced, but now possible,
ndo_hwtstamp_set().
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 51aaa682 88c0a6b5
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */

#ifndef _LINUX_NET_TIMESTAMPING_H_
#define _LINUX_NET_TIMESTAMPING_H_

#include <uapi/linux/net_tstamp.h>

/**
 * struct kernel_hwtstamp_config - Kernel copy of struct hwtstamp_config
 *
 * @flags: see struct hwtstamp_config
 * @tx_type: see struct hwtstamp_config
 * @rx_filter: see struct hwtstamp_config
 *
 * Prefer using this structure for in-kernel processing of hardware
 * timestamping configuration, over the inextensible struct hwtstamp_config
 * exposed to the %SIOCGHWTSTAMP and %SIOCSHWTSTAMP ioctl UAPI.
 */
struct kernel_hwtstamp_config {
	int flags;
	int tx_type;
	int rx_filter;
};

static inline void hwtstamp_config_to_kernel(struct kernel_hwtstamp_config *kernel_cfg,
					     const struct hwtstamp_config *cfg)
{
	kernel_cfg->flags = cfg->flags;
	kernel_cfg->tx_type = cfg->tx_type;
	kernel_cfg->rx_filter = cfg->rx_filter;
}

#endif /* _LINUX_NET_TIMESTAMPING_H_ */
+8 −1
Original line number Diff line number Diff line
@@ -2878,6 +2878,7 @@ enum netdev_cmd {
	NETDEV_OFFLOAD_XSTATS_REPORT_USED,
	NETDEV_OFFLOAD_XSTATS_REPORT_DELTA,
	NETDEV_XDP_FEAT_CHANGE,
	NETDEV_PRE_CHANGE_HWTSTAMP,
};
const char *netdev_cmd_to_name(enum netdev_cmd cmd);

@@ -2928,6 +2929,11 @@ struct netdev_notifier_pre_changeaddr_info {
	const unsigned char *dev_addr;
};

struct netdev_notifier_hwtstamp_info {
	struct netdev_notifier_info info; /* must be first */
	struct kernel_hwtstamp_config *config;
};

enum netdev_offload_xstats_type {
	NETDEV_OFFLOAD_XSTATS_TYPE_L3 = 1,
};
@@ -2984,7 +2990,8 @@ netdev_notifier_info_to_extack(const struct netdev_notifier_info *info)
}

int call_netdevice_notifiers(unsigned long val, struct net_device *dev);

int call_netdevice_notifiers_info(unsigned long val,
				  struct netdev_notifier_info *info);

extern rwlock_t				dev_base_lock;		/* Device list lock */

+0 −51
Original line number Diff line number Diff line
@@ -109,16 +109,6 @@ struct dsa_device_ops {
	bool promisc_on_master;
};

/* This structure defines the control interfaces that are overlayed by the
 * DSA layer on top of the DSA CPU/management net_device instance. This is
 * used by the core net_device layer while calling various net_device_ops
 * function pointers.
 */
struct dsa_netdevice_ops {
	int (*ndo_eth_ioctl)(struct net_device *dev, struct ifreq *ifr,
			     int cmd);
};

struct dsa_lag {
	struct net_device *dev;
	unsigned int id;
@@ -317,11 +307,6 @@ struct dsa_port {
	 */
	const struct ethtool_ops *orig_ethtool_ops;

	/*
	 * Original copy of the master netdev net_device_ops
	 */
	const struct dsa_netdevice_ops *netdev_ops;

	/* List of MAC addresses that must be forwarded on this port.
	 * These are only valid on CPU ports and DSA links.
	 */
@@ -1339,42 +1324,6 @@ static inline void dsa_tag_generic_flow_dissect(const struct sk_buff *skb,
#endif
}

#if IS_ENABLED(CONFIG_NET_DSA)
static inline int __dsa_netdevice_ops_check(struct net_device *dev)
{
	int err = -EOPNOTSUPP;

	if (!dev->dsa_ptr)
		return err;

	if (!dev->dsa_ptr->netdev_ops)
		return err;

	return 0;
}

static inline int dsa_ndo_eth_ioctl(struct net_device *dev, struct ifreq *ifr,
				    int cmd)
{
	const struct dsa_netdevice_ops *ops;
	int err;

	err = __dsa_netdevice_ops_check(dev);
	if (err)
		return err;

	ops = dev->dsa_ptr->netdev_ops;

	return ops->ndo_eth_ioctl(dev, ifr, cmd);
}
#else
static inline int dsa_ndo_eth_ioctl(struct net_device *dev, struct ifreq *ifr,
				    int cmd)
{
	return -EOPNOTSUPP;
}
#endif

void dsa_unregister_switch(struct dsa_switch *ds);
int dsa_register_switch(struct dsa_switch *ds);
void dsa_switch_shutdown(struct dsa_switch *ds);
+3 −5
Original line number Diff line number Diff line
@@ -160,8 +160,6 @@ struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;
struct list_head ptype_all __read_mostly;	/* Taps */

static int netif_rx_internal(struct sk_buff *skb);
static int call_netdevice_notifiers_info(unsigned long val,
					 struct netdev_notifier_info *info);
static int call_netdevice_notifiers_extack(unsigned long val,
					   struct net_device *dev,
					   struct netlink_ext_ack *extack);
@@ -1614,7 +1612,7 @@ const char *netdev_cmd_to_name(enum netdev_cmd cmd)
	N(SVLAN_FILTER_PUSH_INFO) N(SVLAN_FILTER_DROP_INFO)
	N(PRE_CHANGEADDR) N(OFFLOAD_XSTATS_ENABLE) N(OFFLOAD_XSTATS_DISABLE)
	N(OFFLOAD_XSTATS_REPORT_USED) N(OFFLOAD_XSTATS_REPORT_DELTA)
	N(XDP_FEAT_CHANGE)
	N(XDP_FEAT_CHANGE) N(PRE_CHANGE_HWTSTAMP)
	}
#undef N
	return "UNKNOWN_NETDEV_EVENT";
@@ -1919,7 +1917,7 @@ static void move_netdevice_notifiers_dev_net(struct net_device *dev,
 *	are as for raw_notifier_call_chain().
 */

static int call_netdevice_notifiers_info(unsigned long val,
int call_netdevice_notifiers_info(unsigned long val,
				  struct netdev_notifier_info *info)
{
	struct net *net = dev_net(info->dev);
+67 −43
Original line number Diff line number Diff line
@@ -183,22 +183,18 @@ static int dev_ifsioc_locked(struct net *net, struct ifreq *ifr, unsigned int cm
	return err;
}

static int net_hwtstamp_validate(struct ifreq *ifr)
static int net_hwtstamp_validate(const struct kernel_hwtstamp_config *cfg)
{
	struct hwtstamp_config cfg;
	enum hwtstamp_tx_types tx_type;
	enum hwtstamp_rx_filters rx_filter;
	int tx_type_valid = 0;
	int rx_filter_valid = 0;

	if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
		return -EFAULT;

	if (cfg.flags & ~HWTSTAMP_FLAG_MASK)
	if (cfg->flags & ~HWTSTAMP_FLAG_MASK)
		return -EINVAL;

	tx_type = cfg.tx_type;
	rx_filter = cfg.rx_filter;
	tx_type = cfg->tx_type;
	rx_filter = cfg->rx_filter;

	switch (tx_type) {
	case HWTSTAMP_TX_OFF:
@@ -246,22 +242,55 @@ static int dev_eth_ioctl(struct net_device *dev,
			 struct ifreq *ifr, unsigned int cmd)
{
	const struct net_device_ops *ops = dev->netdev_ops;

	if (!ops->ndo_eth_ioctl)
		return -EOPNOTSUPP;

	if (!netif_device_present(dev))
		return -ENODEV;

	return ops->ndo_eth_ioctl(dev, ifr, cmd);
}

static int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr)
{
	return dev_eth_ioctl(dev, ifr, SIOCGHWTSTAMP);
}

static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr)
{
	struct netdev_notifier_hwtstamp_info info = {
		.info.dev = dev,
	};
	struct kernel_hwtstamp_config kernel_cfg;
	struct netlink_ext_ack extack = {};
	struct hwtstamp_config cfg;
	int err;

	err = dsa_ndo_eth_ioctl(dev, ifr, cmd);
	if (err == 0 || err != -EOPNOTSUPP)
	if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
		return -EFAULT;

	hwtstamp_config_to_kernel(&kernel_cfg, &cfg);

	err = net_hwtstamp_validate(&kernel_cfg);
	if (err)
		return err;

	if (ops->ndo_eth_ioctl) {
		if (netif_device_present(dev))
			err = ops->ndo_eth_ioctl(dev, ifr, cmd);
		else
			err = -ENODEV;
	}
	info.info.extack = &extack;
	info.config = &kernel_cfg;

	err = call_netdevice_notifiers_info(NETDEV_PRE_CHANGE_HWTSTAMP,
					    &info.info);
	err = notifier_to_errno(err);
	if (err) {
		if (extack._msg)
			netdev_err(dev, "%s\n", extack._msg);
		return err;
	}

	return dev_eth_ioctl(dev, ifr, SIOCSHWTSTAMP);
}

static int dev_siocbond(struct net_device *dev,
			struct ifreq *ifr, unsigned int cmd)
{
@@ -391,36 +420,31 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, void __user *data,
		rtnl_lock();
		return err;

	case SIOCDEVPRIVATE ... SIOCDEVPRIVATE + 15:
		return dev_siocdevprivate(dev, ifr, data, cmd);

	case SIOCSHWTSTAMP:
		err = net_hwtstamp_validate(ifr);
		if (err)
			return err;
		fallthrough;
		return dev_set_hwtstamp(dev, ifr);

	/*
	 *	Unknown or private ioctl
	 */
	default:
		if (cmd >= SIOCDEVPRIVATE &&
		    cmd <= SIOCDEVPRIVATE + 15)
			return dev_siocdevprivate(dev, ifr, data, cmd);
	case SIOCGHWTSTAMP:
		return dev_get_hwtstamp(dev, ifr);

		if (cmd == SIOCGMIIPHY ||
		    cmd == SIOCGMIIREG ||
		    cmd == SIOCSMIIREG ||
		    cmd == SIOCSHWTSTAMP ||
		    cmd == SIOCGHWTSTAMP) {
			err = dev_eth_ioctl(dev, ifr, cmd);
		} else if (cmd == SIOCBONDENSLAVE ||
		    cmd == SIOCBONDRELEASE ||
		    cmd == SIOCBONDSETHWADDR ||
		    cmd == SIOCBONDSLAVEINFOQUERY ||
		    cmd == SIOCBONDINFOQUERY ||
		    cmd == SIOCBONDCHANGEACTIVE) {
			err = dev_siocbond(dev, ifr, cmd);
		} else
			err = -EINVAL;
	case SIOCGMIIPHY:
	case SIOCGMIIREG:
	case SIOCSMIIREG:
		return dev_eth_ioctl(dev, ifr, cmd);

	case SIOCBONDENSLAVE:
	case SIOCBONDRELEASE:
	case SIOCBONDSETHWADDR:
	case SIOCBONDSLAVEINFOQUERY:
	case SIOCBONDINFOQUERY:
	case SIOCBONDCHANGEACTIVE:
		return dev_siocbond(dev, ifr, cmd);

	/* Unknown ioctl */
	default:
		err = -EINVAL;
	}
	return err;
}
Loading