1276 lines · 29.2 KB · C
RawDownload
static int nsim_open(struct net_device *dev){	struct netdevsim *ns = netdev_priv(dev);	struct netdevsim *peer;	int err; 	netdev_assert_locked(dev); 	err = nsim_init_napi(ns);	if (err)		return err; 	nsim_enable_napi(ns); 	peer = rtnl_dereference(ns->peer);	if (peer && netif_running(peer->netdev)) {		netif_carrier_on(dev);		netif_carrier_on(peer->netdev);	} 	return 0;} static void nsim_del_napi(struct netdevsim *ns){	struct net_device *dev = ns->netdev;	int i; 	for (i = 0; i < dev->num_rx_queues; i++) {		struct nsim_rq *rq = ns->rq[i]; 		napi_disable_locked(&rq->napi);		__netif_napi_del_locked(&rq->napi);	}	synchronize_net(); 	for (i = 0; i < dev->num_rx_queues; i++) {		page_pool_destroy(ns->rq[i]->page_pool);		ns->rq[i]->page_pool = NULL;	}} static int nsim_stop(struct net_device *dev){	struct netdevsim *ns = netdev_priv(dev);	struct netdevsim *peer; 	netdev_assert_locked(dev); 	netif_carrier_off(dev);	peer = rtnl_dereference(ns->peer);	if (peer)		netif_carrier_off(peer->netdev); 	nsim_del_napi(ns); 	return 0;} static int nsim_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid){	struct netdevsim *ns = netdev_priv(dev); 	if (vid >= VLAN_N_VID)		return -EINVAL; 	if (proto == htons(ETH_P_8021Q))		WARN_ON_ONCE(test_and_set_bit(vid, ns->vlan.ctag));	else if (proto == htons(ETH_P_8021AD))		WARN_ON_ONCE(test_and_set_bit(vid, ns->vlan.stag)); 	return 0;} static int nsim_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid){	struct netdevsim *ns = netdev_priv(dev); 	if (vid >= VLAN_N_VID)		return -EINVAL; 	if (proto == htons(ETH_P_8021Q))		WARN_ON_ONCE(!test_and_clear_bit(vid, ns->vlan.ctag));	else if (proto == htons(ETH_P_8021AD))		WARN_ON_ONCE(!test_and_clear_bit(vid, ns->vlan.stag)); 	return 0;} static int nsim_shaper_set(struct net_shaper_binding *binding,			   const struct net_shaper *shaper,			   struct netlink_ext_ack *extack){	return 0;} static int nsim_shaper_del(struct net_shaper_binding *binding,			   const struct net_shaper_handle *handle,			   struct netlink_ext_ack *extack){	return 0;} static int nsim_shaper_group(struct net_shaper_binding *binding,			     int leaves_count,			     const struct net_shaper *leaves,			     const struct net_shaper *root,			     struct netlink_ext_ack *extack){	return 0;} static void nsim_shaper_cap(struct net_shaper_binding *binding,			    enum net_shaper_scope scope,			    unsigned long *flags){	*flags = ULONG_MAX;} static const struct net_shaper_ops nsim_shaper_ops = {	.set			= nsim_shaper_set,	.delete			= nsim_shaper_del,	.group			= nsim_shaper_group,	.capabilities		= nsim_shaper_cap,}; static const struct net_device_ops nsim_netdev_ops = {	.ndo_start_xmit		= nsim_start_xmit,	.ndo_set_rx_mode_async	= nsim_set_rx_mode,	.ndo_set_mac_address	= eth_mac_addr,	.ndo_validate_addr	= eth_validate_addr,	.ndo_change_mtu		= nsim_change_mtu,	.ndo_set_vf_mac		= nsim_set_vf_mac,	.ndo_set_vf_vlan	= nsim_set_vf_vlan,	.ndo_set_vf_rate	= nsim_set_vf_rate,	.ndo_set_vf_spoofchk	= nsim_set_vf_spoofchk,	.ndo_set_vf_trust	= nsim_set_vf_trust,	.ndo_get_vf_config	= nsim_get_vf_config,	.ndo_set_vf_link_state	= nsim_set_vf_link_state,	.ndo_set_vf_rss_query_en = nsim_set_vf_rss_query_en,	.ndo_setup_tc		= nsim_setup_tc,	.ndo_set_features	= nsim_set_features,	.ndo_get_iflink		= nsim_get_iflink,	.ndo_bpf		= nsim_bpf,	.ndo_open		= nsim_open,	.ndo_stop		= nsim_stop,	.ndo_vlan_rx_add_vid	= nsim_vlan_rx_add_vid,	.ndo_vlan_rx_kill_vid	= nsim_vlan_rx_kill_vid,	.net_shaper_ops		= &nsim_shaper_ops,}; static const struct net_device_ops nsim_vf_netdev_ops = {	.ndo_start_xmit		= nsim_start_xmit,	.ndo_set_rx_mode_async	= nsim_set_rx_mode,	.ndo_set_mac_address	= eth_mac_addr,	.ndo_validate_addr	= eth_validate_addr,	.ndo_change_mtu		= nsim_change_mtu,	.ndo_setup_tc		= nsim_setup_tc,	.ndo_set_features	= nsim_set_features,	.ndo_vlan_rx_add_vid	= nsim_vlan_rx_add_vid,	.ndo_vlan_rx_kill_vid	= nsim_vlan_rx_kill_vid,}; /* We don't have true per-queue stats, yet, so do some random fakery here. * Only report stuff for queue 0. */static void nsim_get_queue_stats_rx(struct net_device *dev, int idx,				    struct netdev_queue_stats_rx *stats){	struct rtnl_link_stats64 rtstats = {}; 	if (!idx)		dev_get_stats(dev, &rtstats); 	stats->packets = rtstats.rx_packets - !!rtstats.rx_packets;	stats->bytes = rtstats.rx_bytes;} static void nsim_get_queue_stats_tx(struct net_device *dev, int idx,				    struct netdev_queue_stats_tx *stats){	struct rtnl_link_stats64 rtstats = {}; 	if (!idx)		dev_get_stats(dev, &rtstats); 	stats->packets = rtstats.tx_packets - !!rtstats.tx_packets;	stats->bytes = rtstats.tx_bytes;} static void nsim_get_base_stats(struct net_device *dev,				struct netdev_queue_stats_rx *rx,				struct netdev_queue_stats_tx *tx){	struct rtnl_link_stats64 rtstats = {}; 	dev_get_stats(dev, &rtstats); 	rx->packets = !!rtstats.rx_packets;	rx->bytes = 0;	tx->packets = !!rtstats.tx_packets;	tx->bytes = 0;} static const struct netdev_stat_ops nsim_stat_ops = {	.get_queue_stats_tx	= nsim_get_queue_stats_tx,	.get_queue_stats_rx	= nsim_get_queue_stats_rx,	.get_base_stats		= nsim_get_base_stats,}; static struct nsim_rq *nsim_queue_alloc(void){	struct nsim_rq *rq; 	rq = kzalloc_obj(*rq, GFP_KERNEL_ACCOUNT);	if (!rq)		return NULL; 	skb_queue_head_init(&rq->skb_queue);	nsim_rq_timer_init(rq);	return rq;} static void nsim_queue_free(struct net_device *dev, struct nsim_rq *rq){	hrtimer_cancel(&rq->napi_timer); 	if (rq->skb_queue.qlen) {		local_bh_disable();		dev_dstats_rx_dropped_add(dev, rq->skb_queue.qlen);		local_bh_enable();	} 	skb_queue_purge_reason(&rq->skb_queue, SKB_DROP_REASON_QUEUE_PURGE);	kfree(rq);} /* Queue reset mode is controlled by ns->rq_reset_mode. * - normal - new NAPI new pool (old NAPI enabled when new added) * - mode 1 - allocate new pool (NAPI is only disabled / enabled) * - mode 2 - new NAPI new pool (old NAPI removed before new added) * - mode 3 - new NAPI new pool (old NAPI disabled when new added) */struct nsim_queue_mem {	struct nsim_rq *rq;	struct page_pool *pp;}; static intnsim_queue_mem_alloc(struct net_device *dev,		     struct netdev_queue_config *qcfg,		     void *per_queue_mem, int idx){	struct nsim_queue_mem *qmem = per_queue_mem;	struct netdevsim *ns = netdev_priv(dev);	int err; 	if (ns->rq_reset_mode > 3)		return -EINVAL; 	if (ns->rq_reset_mode == 1) {		if (!netif_running(ns->netdev))			return -ENETDOWN;		return nsim_create_page_pool(&qmem->pp, &ns->rq[idx]->napi);	} 	qmem->rq = nsim_queue_alloc();	if (!qmem->rq)		return -ENOMEM; 	err = nsim_create_page_pool(&qmem->rq->page_pool, &qmem->rq->napi);	if (err)		goto err_free; 	if (!ns->rq_reset_mode)		netif_napi_add_config_locked(dev, &qmem->rq->napi, nsim_poll,					     idx); 	return 0; err_free:	nsim_queue_free(dev, qmem->rq);	return err;} static void nsim_queue_mem_free(struct net_device *dev, void *per_queue_mem){	struct nsim_queue_mem *qmem = per_queue_mem;	struct netdevsim *ns = netdev_priv(dev); 	page_pool_destroy(qmem->pp);	if (qmem->rq) {		if (!ns->rq_reset_mode)			netif_napi_del_locked(&qmem->rq->napi);		page_pool_destroy(qmem->rq->page_pool);		nsim_queue_free(dev, qmem->rq);	}} static intnsim_queue_start(struct net_device *dev, struct netdev_queue_config *qcfg,		 void *per_queue_mem, int idx){	struct nsim_queue_mem *qmem = per_queue_mem;	struct netdevsim *ns = netdev_priv(dev); 	netdev_assert_locked(dev); 	if (ns->rq_reset_mode == 1) {		ns->rq[idx]->page_pool = qmem->pp;		napi_enable_locked(&ns->rq[idx]->napi);		return 0;	} 	/* netif_napi_add()/_del() should normally be called from alloc/free,	 * here we want to test various call orders.	 */	if (ns->rq_reset_mode == 2) {		netif_napi_del_locked(&ns->rq[idx]->napi);		netif_napi_add_config_locked(dev, &qmem->rq->napi, nsim_poll,					     idx);	} else if (ns->rq_reset_mode == 3) {		netif_napi_add_config_locked(dev, &qmem->rq->napi, nsim_poll,					     idx);		netif_napi_del_locked(&ns->rq[idx]->napi);	} 	ns->rq[idx] = qmem->rq;	napi_enable_locked(&ns->rq[idx]->napi); 	return 0;} static int nsim_queue_stop(struct net_device *dev, void *per_queue_mem, int idx){	struct nsim_queue_mem *qmem = per_queue_mem;	struct netdevsim *ns = netdev_priv(dev); 	netdev_assert_locked(dev); 	napi_disable_locked(&ns->rq[idx]->napi); 	if (ns->rq_reset_mode == 1) {		qmem->pp = ns->rq[idx]->page_pool;		page_pool_disable_direct_recycling(qmem->pp);	} else {		qmem->rq = ns->rq[idx];	} 	return 0;} static const struct netdev_queue_mgmt_ops nsim_queue_mgmt_ops = {	.ndo_queue_mem_size	= sizeof(struct nsim_queue_mem),	.ndo_queue_mem_alloc	= nsim_queue_mem_alloc,	.ndo_queue_mem_free	= nsim_queue_mem_free,	.ndo_queue_start	= nsim_queue_start,	.ndo_queue_stop		= nsim_queue_stop,}; static ssize_tnsim_qreset_write(struct file *file, const char __user *data,		  size_t count, loff_t *ppos){	struct netdevsim *ns = file->private_data;	unsigned int queue, mode;	char buf[32];	ssize_t ret; 	if (count >= sizeof(buf))		return -EINVAL;	if (copy_from_user(buf, data, count))		return -EFAULT;	buf[count] = '\0'; 	ret = sscanf(buf, "%u %u", &queue, &mode);	if (ret != 2)		return -EINVAL; 	netdev_lock(ns->netdev);	if (queue >= ns->netdev->real_num_rx_queues) {		ret = -EINVAL;		goto exit_unlock;	} 	ns->rq_reset_mode = mode;	ret = netdev_rx_queue_restart(ns->netdev, queue);	ns->rq_reset_mode = 0;	if (ret)		goto exit_unlock; 	ret = count;exit_unlock:	netdev_unlock(ns->netdev);	return ret;} static const struct file_operations nsim_qreset_fops = {	.open = simple_open,	.write = nsim_qreset_write,	.owner = THIS_MODULE,}; static ssize_tnsim_pp_hold_read(struct file *file, char __user *data,		  size_t count, loff_t *ppos){	struct netdevsim *ns = file->private_data;	char buf[3] = "n\n"; 	if (ns->page)		buf[0] = 'y'; 	return simple_read_from_buffer(data, count, ppos, buf, 2);} static ssize_tnsim_pp_hold_write(struct file *file, const char __user *data,		   size_t count, loff_t *ppos){	struct netdevsim *ns = file->private_data;	ssize_t ret;	bool val; 	ret = kstrtobool_from_user(data, count, &val);	if (ret)		return ret; 	rtnl_lock();	ret = count;	if (val == !!ns->page)		goto exit; 	if (!netif_running(ns->netdev) && val) {		ret = -ENETDOWN;	} else if (val) {		ns->page = page_pool_dev_alloc_pages(ns->rq[0]->page_pool);		if (!ns->page)			ret = -ENOMEM;	} else {		page_pool_put_full_page(pp_page_to_nmdesc(ns->page)->pp,					ns->page, false);		ns->page = NULL;	} exit:	rtnl_unlock();	return ret;} static const struct file_operations nsim_pp_hold_fops = {	.open = simple_open,	.read = nsim_pp_hold_read,	.write = nsim_pp_hold_write,	.llseek = generic_file_llseek,	.owner = THIS_MODULE,}; static int nsim_vlan_show(struct seq_file *s, void *data){	struct netdevsim *ns = s->private;	int vid; 	for_each_set_bit(vid, ns->vlan.ctag, VLAN_N_VID)		seq_printf(s, "ctag %d\n", vid);	for_each_set_bit(vid, ns->vlan.stag, VLAN_N_VID)		seq_printf(s, "stag %d\n", vid); 	return 0;}DEFINE_SHOW_ATTRIBUTE(nsim_vlan); static void nsim_setup(struct net_device *dev){	ether_setup(dev);	eth_hw_addr_random(dev); 	dev->flags &= ~IFF_MULTICAST;	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;	dev->features |= NETIF_F_HIGHDMA |			 NETIF_F_SG |			 NETIF_F_FRAGLIST |			 NETIF_F_HW_CSUM |			 NETIF_F_LRO |			 NETIF_F_TSO |			 NETIF_F_HW_VLAN_CTAG_FILTER |			 NETIF_F_HW_VLAN_STAG_FILTER;	dev->hw_features |= NETIF_F_HW_TC |			    NETIF_F_SG |			    NETIF_F_FRAGLIST |			    NETIF_F_HW_CSUM |			    NETIF_F_LRO |			    NETIF_F_TSO |			    NETIF_F_LOOPBACK |			    NETIF_F_HW_VLAN_CTAG_FILTER |			    NETIF_F_HW_VLAN_STAG_FILTER;	dev->pcpu_stat_type = NETDEV_PCPU_STAT_DSTATS;	dev->max_mtu = ETH_MAX_MTU;	dev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_HW_OFFLOAD;}

Lines 501–1000 of 1276. Previous lines