1276 lines · 29.2 KB · C
RawDownload
 static int nsim_queue_init(struct netdevsim *ns){	struct net_device *dev = ns->netdev;	int i; 	ns->rq = kzalloc_objs(*ns->rq, dev->num_rx_queues, GFP_KERNEL_ACCOUNT);	if (!ns->rq)		return -ENOMEM; 	for (i = 0; i < dev->num_rx_queues; i++) {		ns->rq[i] = nsim_queue_alloc();		if (!ns->rq[i])			goto err_free_prev;	} 	return 0; err_free_prev:	while (i--)		kfree(ns->rq[i]);	kfree(ns->rq);	return -ENOMEM;} static void nsim_queue_uninit(struct netdevsim *ns){	struct net_device *dev = ns->netdev;	int i; 	for (i = 0; i < dev->num_rx_queues; i++)		nsim_queue_free(dev, ns->rq[i]); 	kfree(ns->rq);	ns->rq = NULL;} static int nsim_init_netdevsim(struct netdevsim *ns){	struct netdevsim *peer;	struct mock_phc *phc;	int err; 	phc = mock_phc_create(&ns->nsim_bus_dev->dev);	if (IS_ERR(phc))		return PTR_ERR(phc); 	ns->phc = phc;	ns->netdev->netdev_ops = &nsim_netdev_ops;	ns->netdev->stat_ops = &nsim_stat_ops;	ns->netdev->queue_mgmt_ops = &nsim_queue_mgmt_ops;	netdev_lockdep_set_classes(ns->netdev); 	err = nsim_udp_tunnels_info_create(ns->nsim_dev, ns->netdev);	if (err)		goto err_phc_destroy; 	rtnl_lock();	err = nsim_queue_init(ns);	if (err)		goto err_utn_destroy; 	err = nsim_bpf_init(ns);	if (err)		goto err_rq_destroy; 	nsim_macsec_init(ns);	nsim_ipsec_init(ns); 	err = register_netdevice(ns->netdev);	if (err)		goto err_ipsec_teardown;	rtnl_unlock(); 	err = nsim_psp_init(ns);	if (err)		goto err_unregister_netdev; 	if (IS_ENABLED(CONFIG_DEBUG_NET)) {		ns->nb.notifier_call = netdev_debug_event;		if (register_netdevice_notifier_dev_net(ns->netdev, &ns->nb,							&ns->nn))			ns->nb.notifier_call = NULL;	} 	return 0; err_unregister_netdev:	rtnl_lock();	peer = rtnl_dereference(ns->peer);	if (peer)		RCU_INIT_POINTER(peer->peer, NULL);	RCU_INIT_POINTER(ns->peer, NULL);	unregister_netdevice(ns->netdev);err_ipsec_teardown:	nsim_ipsec_teardown(ns);	nsim_macsec_teardown(ns);	nsim_bpf_uninit(ns);err_rq_destroy:	nsim_queue_uninit(ns);err_utn_destroy:	rtnl_unlock();	nsim_udp_tunnels_info_destroy(ns->netdev);err_phc_destroy:	mock_phc_destroy(ns->phc);	return err;} static int nsim_init_netdevsim_vf(struct netdevsim *ns){	int err; 	ns->netdev->netdev_ops = &nsim_vf_netdev_ops;	rtnl_lock();	err = register_netdevice(ns->netdev);	rtnl_unlock();	return err;} static void nsim_exit_netdevsim(struct netdevsim *ns){	nsim_udp_tunnels_info_destroy(ns->netdev);	mock_phc_destroy(ns->phc);} struct netdevsim *nsim_create(struct nsim_dev *nsim_dev,			      struct nsim_dev_port *nsim_dev_port,			      u8 perm_addr[ETH_ALEN]){	struct net_device *dev;	struct netdevsim *ns;	int err; 	dev = alloc_netdev_mq(sizeof(*ns), "eth%d", NET_NAME_UNKNOWN, nsim_setup,			      nsim_dev->nsim_bus_dev->num_queues);	if (!dev)		return ERR_PTR(-ENOMEM); 	if (perm_addr)		memcpy(dev->perm_addr, perm_addr, ETH_ALEN); 	dev_net_set(dev, nsim_dev_net(nsim_dev));	ns = netdev_priv(dev);	ns->netdev = dev;	ns->nsim_dev = nsim_dev;	ns->nsim_dev_port = nsim_dev_port;	ns->nsim_bus_dev = nsim_dev->nsim_bus_dev;	SET_NETDEV_DEV(dev, &ns->nsim_bus_dev->dev);	SET_NETDEV_DEVLINK_PORT(dev, &nsim_dev_port->devlink_port);	nsim_ethtool_init(ns);	if (nsim_dev_port_is_pf(nsim_dev_port))		err = nsim_init_netdevsim(ns);	else		err = nsim_init_netdevsim_vf(ns);	if (err)		goto err_free_netdev; 	ns->pp_dfs = debugfs_create_file("pp_hold", 0600, nsim_dev_port->ddir,					 ns, &nsim_pp_hold_fops);	ns->qr_dfs = debugfs_create_file("queue_reset", 0200,					 nsim_dev_port->ddir, ns,					 &nsim_qreset_fops);	ns->vlan_dfs = debugfs_create_file("vlan", 0400, nsim_dev_port->ddir,					   ns, &nsim_vlan_fops);	return ns; err_free_netdev:	nsim_ethtool_fini(ns);	free_netdev(dev);	return ERR_PTR(err);} void nsim_destroy(struct netdevsim *ns){	struct net_device *dev = ns->netdev;	struct netdevsim *peer;	u16 vid; 	debugfs_remove(ns->vlan_dfs);	debugfs_remove(ns->qr_dfs);	debugfs_remove(ns->pp_dfs);	nsim_ethtool_fini(ns); 	if (ns->nb.notifier_call)		unregister_netdevice_notifier_dev_net(ns->netdev, &ns->nb,						      &ns->nn); 	if (nsim_dev_port_is_pf(ns->nsim_dev_port))		nsim_psp_uninit(ns); 	rtnl_lock();	peer = rtnl_dereference(ns->peer);	if (peer)		RCU_INIT_POINTER(peer->peer, NULL);	RCU_INIT_POINTER(ns->peer, NULL);	unregister_netdevice(dev);	if (nsim_dev_port_is_pf(ns->nsim_dev_port)) {		nsim_macsec_teardown(ns);		nsim_ipsec_teardown(ns);		nsim_bpf_uninit(ns);		nsim_queue_uninit(ns);	}	rtnl_unlock();	if (nsim_dev_port_is_pf(ns->nsim_dev_port))		nsim_exit_netdevsim(ns); 	for_each_set_bit(vid, ns->vlan.ctag, VLAN_N_VID)		WARN_ON_ONCE(1);	for_each_set_bit(vid, ns->vlan.stag, VLAN_N_VID)		WARN_ON_ONCE(1); 	/* Put this intentionally late to exercise the orphaning path */	if (ns->page) {		page_pool_put_full_page(pp_page_to_nmdesc(ns->page)->pp,					ns->page, false);		ns->page = NULL;	} 	free_netdev(dev);} bool netdev_is_nsim(struct net_device *dev){	return dev->netdev_ops == &nsim_netdev_ops;} static int nsim_validate(struct nlattr *tb[], struct nlattr *data[],			 struct netlink_ext_ack *extack){	NL_SET_ERR_MSG_MOD(extack,			   "Please use: echo \"[ID] [PORT_COUNT] [NUM_QUEUES]\" > /sys/bus/netdevsim/new_device");	return -EOPNOTSUPP;} static struct rtnl_link_ops nsim_link_ops __read_mostly = {	.kind		= DRV_NAME,	.validate	= nsim_validate,}; static int __init nsim_module_init(void){	int err; 	err = nsim_dev_init();	if (err)		return err; 	err = nsim_bus_init();	if (err)		goto err_dev_exit; 	err = rtnl_link_register(&nsim_link_ops);	if (err)		goto err_bus_exit; 	return 0; err_bus_exit:	nsim_bus_exit();err_dev_exit:	nsim_dev_exit();	return err;} static void __exit nsim_module_exit(void){	rtnl_link_unregister(&nsim_link_ops);	nsim_bus_exit();	nsim_dev_exit();} module_init(nsim_module_init);module_exit(nsim_module_exit);MODULE_LICENSE("GPL");MODULE_DESCRIPTION("Simulated networking device for testing");MODULE_ALIAS_RTNL_LINK(DRV_NAME);

Lines 1001–1276 of 1276. Previous lines