162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (C) 2017 Netronome Systems, Inc.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * This software is licensed under the GNU General License Version 2,
562306a36Sopenharmony_ci * June 1991 as shown in the file COPYING in the top-level directory of this
662306a36Sopenharmony_ci * source tree.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
962306a36Sopenharmony_ci * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
1062306a36Sopenharmony_ci * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
1162306a36Sopenharmony_ci * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
1262306a36Sopenharmony_ci * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
1362306a36Sopenharmony_ci * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
1462306a36Sopenharmony_ci */
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <linux/debugfs.h>
1762306a36Sopenharmony_ci#include <linux/etherdevice.h>
1862306a36Sopenharmony_ci#include <linux/kernel.h>
1962306a36Sopenharmony_ci#include <linux/module.h>
2062306a36Sopenharmony_ci#include <linux/netdevice.h>
2162306a36Sopenharmony_ci#include <linux/slab.h>
2262306a36Sopenharmony_ci#include <net/netlink.h>
2362306a36Sopenharmony_ci#include <net/pkt_cls.h>
2462306a36Sopenharmony_ci#include <net/rtnetlink.h>
2562306a36Sopenharmony_ci#include <net/udp_tunnel.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include "netdevsim.h"
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	struct netdevsim *ns = netdev_priv(dev);
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	if (!nsim_ipsec_tx(ns, skb))
3462306a36Sopenharmony_ci		goto out;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	u64_stats_update_begin(&ns->syncp);
3762306a36Sopenharmony_ci	ns->tx_packets++;
3862306a36Sopenharmony_ci	ns->tx_bytes += skb->len;
3962306a36Sopenharmony_ci	u64_stats_update_end(&ns->syncp);
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ciout:
4262306a36Sopenharmony_ci	dev_kfree_skb(skb);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	return NETDEV_TX_OK;
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic void nsim_set_rx_mode(struct net_device *dev)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic int nsim_change_mtu(struct net_device *dev, int new_mtu)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	struct netdevsim *ns = netdev_priv(dev);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	if (ns->xdp.prog && new_mtu > NSIM_XDP_MAX_MTU)
5662306a36Sopenharmony_ci		return -EBUSY;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	dev->mtu = new_mtu;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	return 0;
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic void
6462306a36Sopenharmony_cinsim_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	struct netdevsim *ns = netdev_priv(dev);
6762306a36Sopenharmony_ci	unsigned int start;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	do {
7062306a36Sopenharmony_ci		start = u64_stats_fetch_begin(&ns->syncp);
7162306a36Sopenharmony_ci		stats->tx_bytes = ns->tx_bytes;
7262306a36Sopenharmony_ci		stats->tx_packets = ns->tx_packets;
7362306a36Sopenharmony_ci	} while (u64_stats_fetch_retry(&ns->syncp, start));
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic int
7762306a36Sopenharmony_cinsim_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	return nsim_bpf_setup_tc_block_cb(type, type_data, cb_priv);
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic int nsim_set_vf_mac(struct net_device *dev, int vf, u8 *mac)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	struct netdevsim *ns = netdev_priv(dev);
8562306a36Sopenharmony_ci	struct nsim_dev *nsim_dev = ns->nsim_dev;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	/* Only refuse multicast addresses, zero address can mean unset/any. */
8862306a36Sopenharmony_ci	if (vf >= nsim_dev_get_vfs(nsim_dev) || is_multicast_ether_addr(mac))
8962306a36Sopenharmony_ci		return -EINVAL;
9062306a36Sopenharmony_ci	memcpy(nsim_dev->vfconfigs[vf].vf_mac, mac, ETH_ALEN);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	return 0;
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic int nsim_set_vf_vlan(struct net_device *dev, int vf,
9662306a36Sopenharmony_ci			    u16 vlan, u8 qos, __be16 vlan_proto)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	struct netdevsim *ns = netdev_priv(dev);
9962306a36Sopenharmony_ci	struct nsim_dev *nsim_dev = ns->nsim_dev;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	if (vf >= nsim_dev_get_vfs(nsim_dev) || vlan > 4095 || qos > 7)
10262306a36Sopenharmony_ci		return -EINVAL;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	nsim_dev->vfconfigs[vf].vlan = vlan;
10562306a36Sopenharmony_ci	nsim_dev->vfconfigs[vf].qos = qos;
10662306a36Sopenharmony_ci	nsim_dev->vfconfigs[vf].vlan_proto = vlan_proto;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	return 0;
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic int nsim_set_vf_rate(struct net_device *dev, int vf, int min, int max)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	struct netdevsim *ns = netdev_priv(dev);
11462306a36Sopenharmony_ci	struct nsim_dev *nsim_dev = ns->nsim_dev;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if (nsim_esw_mode_is_switchdev(ns->nsim_dev)) {
11762306a36Sopenharmony_ci		pr_err("Not supported in switchdev mode. Please use devlink API.\n");
11862306a36Sopenharmony_ci		return -EOPNOTSUPP;
11962306a36Sopenharmony_ci	}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (vf >= nsim_dev_get_vfs(nsim_dev))
12262306a36Sopenharmony_ci		return -EINVAL;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	nsim_dev->vfconfigs[vf].min_tx_rate = min;
12562306a36Sopenharmony_ci	nsim_dev->vfconfigs[vf].max_tx_rate = max;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	return 0;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic int nsim_set_vf_spoofchk(struct net_device *dev, int vf, bool val)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	struct netdevsim *ns = netdev_priv(dev);
13362306a36Sopenharmony_ci	struct nsim_dev *nsim_dev = ns->nsim_dev;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	if (vf >= nsim_dev_get_vfs(nsim_dev))
13662306a36Sopenharmony_ci		return -EINVAL;
13762306a36Sopenharmony_ci	nsim_dev->vfconfigs[vf].spoofchk_enabled = val;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	return 0;
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic int nsim_set_vf_rss_query_en(struct net_device *dev, int vf, bool val)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	struct netdevsim *ns = netdev_priv(dev);
14562306a36Sopenharmony_ci	struct nsim_dev *nsim_dev = ns->nsim_dev;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	if (vf >= nsim_dev_get_vfs(nsim_dev))
14862306a36Sopenharmony_ci		return -EINVAL;
14962306a36Sopenharmony_ci	nsim_dev->vfconfigs[vf].rss_query_enabled = val;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	return 0;
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic int nsim_set_vf_trust(struct net_device *dev, int vf, bool val)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	struct netdevsim *ns = netdev_priv(dev);
15762306a36Sopenharmony_ci	struct nsim_dev *nsim_dev = ns->nsim_dev;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	if (vf >= nsim_dev_get_vfs(nsim_dev))
16062306a36Sopenharmony_ci		return -EINVAL;
16162306a36Sopenharmony_ci	nsim_dev->vfconfigs[vf].trusted = val;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	return 0;
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistatic int
16762306a36Sopenharmony_cinsim_get_vf_config(struct net_device *dev, int vf, struct ifla_vf_info *ivi)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	struct netdevsim *ns = netdev_priv(dev);
17062306a36Sopenharmony_ci	struct nsim_dev *nsim_dev = ns->nsim_dev;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (vf >= nsim_dev_get_vfs(nsim_dev))
17362306a36Sopenharmony_ci		return -EINVAL;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	ivi->vf = vf;
17662306a36Sopenharmony_ci	ivi->linkstate = nsim_dev->vfconfigs[vf].link_state;
17762306a36Sopenharmony_ci	ivi->min_tx_rate = nsim_dev->vfconfigs[vf].min_tx_rate;
17862306a36Sopenharmony_ci	ivi->max_tx_rate = nsim_dev->vfconfigs[vf].max_tx_rate;
17962306a36Sopenharmony_ci	ivi->vlan = nsim_dev->vfconfigs[vf].vlan;
18062306a36Sopenharmony_ci	ivi->vlan_proto = nsim_dev->vfconfigs[vf].vlan_proto;
18162306a36Sopenharmony_ci	ivi->qos = nsim_dev->vfconfigs[vf].qos;
18262306a36Sopenharmony_ci	memcpy(&ivi->mac, nsim_dev->vfconfigs[vf].vf_mac, ETH_ALEN);
18362306a36Sopenharmony_ci	ivi->spoofchk = nsim_dev->vfconfigs[vf].spoofchk_enabled;
18462306a36Sopenharmony_ci	ivi->trusted = nsim_dev->vfconfigs[vf].trusted;
18562306a36Sopenharmony_ci	ivi->rss_query_en = nsim_dev->vfconfigs[vf].rss_query_enabled;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	return 0;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic int nsim_set_vf_link_state(struct net_device *dev, int vf, int state)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	struct netdevsim *ns = netdev_priv(dev);
19362306a36Sopenharmony_ci	struct nsim_dev *nsim_dev = ns->nsim_dev;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	if (vf >= nsim_dev_get_vfs(nsim_dev))
19662306a36Sopenharmony_ci		return -EINVAL;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	switch (state) {
19962306a36Sopenharmony_ci	case IFLA_VF_LINK_STATE_AUTO:
20062306a36Sopenharmony_ci	case IFLA_VF_LINK_STATE_ENABLE:
20162306a36Sopenharmony_ci	case IFLA_VF_LINK_STATE_DISABLE:
20262306a36Sopenharmony_ci		break;
20362306a36Sopenharmony_ci	default:
20462306a36Sopenharmony_ci		return -EINVAL;
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	nsim_dev->vfconfigs[vf].link_state = state;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	return 0;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic void nsim_taprio_stats(struct tc_taprio_qopt_stats *stats)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	stats->window_drops = 0;
21562306a36Sopenharmony_ci	stats->tx_overruns = 0;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic int nsim_setup_tc_taprio(struct net_device *dev,
21962306a36Sopenharmony_ci				struct tc_taprio_qopt_offload *offload)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	int err = 0;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	switch (offload->cmd) {
22462306a36Sopenharmony_ci	case TAPRIO_CMD_REPLACE:
22562306a36Sopenharmony_ci	case TAPRIO_CMD_DESTROY:
22662306a36Sopenharmony_ci		break;
22762306a36Sopenharmony_ci	case TAPRIO_CMD_STATS:
22862306a36Sopenharmony_ci		nsim_taprio_stats(&offload->stats);
22962306a36Sopenharmony_ci		break;
23062306a36Sopenharmony_ci	default:
23162306a36Sopenharmony_ci		err = -EOPNOTSUPP;
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	return err;
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic LIST_HEAD(nsim_block_cb_list);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic int
24062306a36Sopenharmony_cinsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	struct netdevsim *ns = netdev_priv(dev);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	switch (type) {
24562306a36Sopenharmony_ci	case TC_SETUP_QDISC_TAPRIO:
24662306a36Sopenharmony_ci		return nsim_setup_tc_taprio(dev, type_data);
24762306a36Sopenharmony_ci	case TC_SETUP_BLOCK:
24862306a36Sopenharmony_ci		return flow_block_cb_setup_simple(type_data,
24962306a36Sopenharmony_ci						  &nsim_block_cb_list,
25062306a36Sopenharmony_ci						  nsim_setup_tc_block_cb,
25162306a36Sopenharmony_ci						  ns, ns, true);
25262306a36Sopenharmony_ci	default:
25362306a36Sopenharmony_ci		return -EOPNOTSUPP;
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic int
25862306a36Sopenharmony_cinsim_set_features(struct net_device *dev, netdev_features_t features)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	struct netdevsim *ns = netdev_priv(dev);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	if ((dev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC))
26362306a36Sopenharmony_ci		return nsim_bpf_disable_tc(ns);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	return 0;
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic const struct net_device_ops nsim_netdev_ops = {
26962306a36Sopenharmony_ci	.ndo_start_xmit		= nsim_start_xmit,
27062306a36Sopenharmony_ci	.ndo_set_rx_mode	= nsim_set_rx_mode,
27162306a36Sopenharmony_ci	.ndo_set_mac_address	= eth_mac_addr,
27262306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
27362306a36Sopenharmony_ci	.ndo_change_mtu		= nsim_change_mtu,
27462306a36Sopenharmony_ci	.ndo_get_stats64	= nsim_get_stats64,
27562306a36Sopenharmony_ci	.ndo_set_vf_mac		= nsim_set_vf_mac,
27662306a36Sopenharmony_ci	.ndo_set_vf_vlan	= nsim_set_vf_vlan,
27762306a36Sopenharmony_ci	.ndo_set_vf_rate	= nsim_set_vf_rate,
27862306a36Sopenharmony_ci	.ndo_set_vf_spoofchk	= nsim_set_vf_spoofchk,
27962306a36Sopenharmony_ci	.ndo_set_vf_trust	= nsim_set_vf_trust,
28062306a36Sopenharmony_ci	.ndo_get_vf_config	= nsim_get_vf_config,
28162306a36Sopenharmony_ci	.ndo_set_vf_link_state	= nsim_set_vf_link_state,
28262306a36Sopenharmony_ci	.ndo_set_vf_rss_query_en = nsim_set_vf_rss_query_en,
28362306a36Sopenharmony_ci	.ndo_setup_tc		= nsim_setup_tc,
28462306a36Sopenharmony_ci	.ndo_set_features	= nsim_set_features,
28562306a36Sopenharmony_ci	.ndo_bpf		= nsim_bpf,
28662306a36Sopenharmony_ci};
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic const struct net_device_ops nsim_vf_netdev_ops = {
28962306a36Sopenharmony_ci	.ndo_start_xmit		= nsim_start_xmit,
29062306a36Sopenharmony_ci	.ndo_set_rx_mode	= nsim_set_rx_mode,
29162306a36Sopenharmony_ci	.ndo_set_mac_address	= eth_mac_addr,
29262306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
29362306a36Sopenharmony_ci	.ndo_change_mtu		= nsim_change_mtu,
29462306a36Sopenharmony_ci	.ndo_get_stats64	= nsim_get_stats64,
29562306a36Sopenharmony_ci	.ndo_setup_tc		= nsim_setup_tc,
29662306a36Sopenharmony_ci	.ndo_set_features	= nsim_set_features,
29762306a36Sopenharmony_ci};
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic void nsim_setup(struct net_device *dev)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	ether_setup(dev);
30262306a36Sopenharmony_ci	eth_hw_addr_random(dev);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	dev->tx_queue_len = 0;
30562306a36Sopenharmony_ci	dev->flags |= IFF_NOARP;
30662306a36Sopenharmony_ci	dev->flags &= ~IFF_MULTICAST;
30762306a36Sopenharmony_ci	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE |
30862306a36Sopenharmony_ci			   IFF_NO_QUEUE;
30962306a36Sopenharmony_ci	dev->features |= NETIF_F_HIGHDMA |
31062306a36Sopenharmony_ci			 NETIF_F_SG |
31162306a36Sopenharmony_ci			 NETIF_F_FRAGLIST |
31262306a36Sopenharmony_ci			 NETIF_F_HW_CSUM |
31362306a36Sopenharmony_ci			 NETIF_F_TSO;
31462306a36Sopenharmony_ci	dev->hw_features |= NETIF_F_HW_TC;
31562306a36Sopenharmony_ci	dev->max_mtu = ETH_MAX_MTU;
31662306a36Sopenharmony_ci	dev->xdp_features = NETDEV_XDP_ACT_HW_OFFLOAD;
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistatic int nsim_init_netdevsim(struct netdevsim *ns)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	struct mock_phc *phc;
32262306a36Sopenharmony_ci	int err;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	phc = mock_phc_create(&ns->nsim_bus_dev->dev);
32562306a36Sopenharmony_ci	if (IS_ERR(phc))
32662306a36Sopenharmony_ci		return PTR_ERR(phc);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	ns->phc = phc;
32962306a36Sopenharmony_ci	ns->netdev->netdev_ops = &nsim_netdev_ops;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	err = nsim_udp_tunnels_info_create(ns->nsim_dev, ns->netdev);
33262306a36Sopenharmony_ci	if (err)
33362306a36Sopenharmony_ci		goto err_phc_destroy;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	rtnl_lock();
33662306a36Sopenharmony_ci	err = nsim_bpf_init(ns);
33762306a36Sopenharmony_ci	if (err)
33862306a36Sopenharmony_ci		goto err_utn_destroy;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	nsim_macsec_init(ns);
34162306a36Sopenharmony_ci	nsim_ipsec_init(ns);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	err = register_netdevice(ns->netdev);
34462306a36Sopenharmony_ci	if (err)
34562306a36Sopenharmony_ci		goto err_ipsec_teardown;
34662306a36Sopenharmony_ci	rtnl_unlock();
34762306a36Sopenharmony_ci	return 0;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cierr_ipsec_teardown:
35062306a36Sopenharmony_ci	nsim_ipsec_teardown(ns);
35162306a36Sopenharmony_ci	nsim_macsec_teardown(ns);
35262306a36Sopenharmony_ci	nsim_bpf_uninit(ns);
35362306a36Sopenharmony_cierr_utn_destroy:
35462306a36Sopenharmony_ci	rtnl_unlock();
35562306a36Sopenharmony_ci	nsim_udp_tunnels_info_destroy(ns->netdev);
35662306a36Sopenharmony_cierr_phc_destroy:
35762306a36Sopenharmony_ci	mock_phc_destroy(ns->phc);
35862306a36Sopenharmony_ci	return err;
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic int nsim_init_netdevsim_vf(struct netdevsim *ns)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	int err;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	ns->netdev->netdev_ops = &nsim_vf_netdev_ops;
36662306a36Sopenharmony_ci	rtnl_lock();
36762306a36Sopenharmony_ci	err = register_netdevice(ns->netdev);
36862306a36Sopenharmony_ci	rtnl_unlock();
36962306a36Sopenharmony_ci	return err;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic void nsim_exit_netdevsim(struct netdevsim *ns)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	nsim_udp_tunnels_info_destroy(ns->netdev);
37562306a36Sopenharmony_ci	mock_phc_destroy(ns->phc);
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistruct netdevsim *
37962306a36Sopenharmony_cinsim_create(struct nsim_dev *nsim_dev, struct nsim_dev_port *nsim_dev_port)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	struct net_device *dev;
38262306a36Sopenharmony_ci	struct netdevsim *ns;
38362306a36Sopenharmony_ci	int err;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	dev = alloc_netdev_mq(sizeof(*ns), "eth%d", NET_NAME_UNKNOWN, nsim_setup,
38662306a36Sopenharmony_ci			      nsim_dev->nsim_bus_dev->num_queues);
38762306a36Sopenharmony_ci	if (!dev)
38862306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	dev_net_set(dev, nsim_dev_net(nsim_dev));
39162306a36Sopenharmony_ci	ns = netdev_priv(dev);
39262306a36Sopenharmony_ci	ns->netdev = dev;
39362306a36Sopenharmony_ci	u64_stats_init(&ns->syncp);
39462306a36Sopenharmony_ci	ns->nsim_dev = nsim_dev;
39562306a36Sopenharmony_ci	ns->nsim_dev_port = nsim_dev_port;
39662306a36Sopenharmony_ci	ns->nsim_bus_dev = nsim_dev->nsim_bus_dev;
39762306a36Sopenharmony_ci	SET_NETDEV_DEV(dev, &ns->nsim_bus_dev->dev);
39862306a36Sopenharmony_ci	SET_NETDEV_DEVLINK_PORT(dev, &nsim_dev_port->devlink_port);
39962306a36Sopenharmony_ci	nsim_ethtool_init(ns);
40062306a36Sopenharmony_ci	if (nsim_dev_port_is_pf(nsim_dev_port))
40162306a36Sopenharmony_ci		err = nsim_init_netdevsim(ns);
40262306a36Sopenharmony_ci	else
40362306a36Sopenharmony_ci		err = nsim_init_netdevsim_vf(ns);
40462306a36Sopenharmony_ci	if (err)
40562306a36Sopenharmony_ci		goto err_free_netdev;
40662306a36Sopenharmony_ci	return ns;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cierr_free_netdev:
40962306a36Sopenharmony_ci	free_netdev(dev);
41062306a36Sopenharmony_ci	return ERR_PTR(err);
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_civoid nsim_destroy(struct netdevsim *ns)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	struct net_device *dev = ns->netdev;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	rtnl_lock();
41862306a36Sopenharmony_ci	unregister_netdevice(dev);
41962306a36Sopenharmony_ci	if (nsim_dev_port_is_pf(ns->nsim_dev_port)) {
42062306a36Sopenharmony_ci		nsim_macsec_teardown(ns);
42162306a36Sopenharmony_ci		nsim_ipsec_teardown(ns);
42262306a36Sopenharmony_ci		nsim_bpf_uninit(ns);
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci	rtnl_unlock();
42562306a36Sopenharmony_ci	if (nsim_dev_port_is_pf(ns->nsim_dev_port))
42662306a36Sopenharmony_ci		nsim_exit_netdevsim(ns);
42762306a36Sopenharmony_ci	free_netdev(dev);
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic int nsim_validate(struct nlattr *tb[], struct nlattr *data[],
43162306a36Sopenharmony_ci			 struct netlink_ext_ack *extack)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	NL_SET_ERR_MSG_MOD(extack,
43462306a36Sopenharmony_ci			   "Please use: echo \"[ID] [PORT_COUNT] [NUM_QUEUES]\" > /sys/bus/netdevsim/new_device");
43562306a36Sopenharmony_ci	return -EOPNOTSUPP;
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cistatic struct rtnl_link_ops nsim_link_ops __read_mostly = {
43962306a36Sopenharmony_ci	.kind		= DRV_NAME,
44062306a36Sopenharmony_ci	.validate	= nsim_validate,
44162306a36Sopenharmony_ci};
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cistatic int __init nsim_module_init(void)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci	int err;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	err = nsim_dev_init();
44862306a36Sopenharmony_ci	if (err)
44962306a36Sopenharmony_ci		return err;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	err = nsim_bus_init();
45262306a36Sopenharmony_ci	if (err)
45362306a36Sopenharmony_ci		goto err_dev_exit;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	err = rtnl_link_register(&nsim_link_ops);
45662306a36Sopenharmony_ci	if (err)
45762306a36Sopenharmony_ci		goto err_bus_exit;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	return 0;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cierr_bus_exit:
46262306a36Sopenharmony_ci	nsim_bus_exit();
46362306a36Sopenharmony_cierr_dev_exit:
46462306a36Sopenharmony_ci	nsim_dev_exit();
46562306a36Sopenharmony_ci	return err;
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cistatic void __exit nsim_module_exit(void)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	rtnl_link_unregister(&nsim_link_ops);
47162306a36Sopenharmony_ci	nsim_bus_exit();
47262306a36Sopenharmony_ci	nsim_dev_exit();
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cimodule_init(nsim_module_init);
47662306a36Sopenharmony_cimodule_exit(nsim_module_exit);
47762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
47862306a36Sopenharmony_ciMODULE_ALIAS_RTNL_LINK(DRV_NAME);
479