summaryrefslogtreecommitdiffstats
path: root/drivers/net/netdevsim/netdevsim.h
blob: bf02efa10956a631adaafbd96c95b3f098d5092b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
/*
 * Copyright (C) 2017 Netronome Systems, Inc.
 *
 * This software is licensed under the GNU General License Version 2,
 * June 1991 as shown in the file COPYING in the top-level directory of this
 * source tree.
 *
 * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
 * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
 * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
 * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
 */

#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/ethtool.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <linux/ptp_mock.h>
#include <linux/u64_stats_sync.h>
#include <net/devlink.h>
#include <net/udp_tunnel.h>
#include <net/xdp.h>
#include <net/macsec.h>

#define DRV_NAME	"netdevsim"

#define NSIM_XDP_MAX_MTU	4000

#define NSIM_EA(extack, msg)	NL_SET_ERR_MSG_MOD((extack), msg)

#define NSIM_IPSEC_MAX_SA_COUNT		33
#define NSIM_IPSEC_VALID		BIT(31)
#define NSIM_UDP_TUNNEL_N_PORTS		4

struct nsim_sa {
	struct xfrm_state *xs;
	__be32 ipaddr[4];
	u32 key[4];
	u32 salt;
	bool used;
	bool crypt;
	bool rx;
};

struct nsim_ipsec {
	struct nsim_sa sa[NSIM_IPSEC_MAX_SA_COUNT];
	struct dentry *pfile;
	u32 count;
	u32 tx;
	u32 ok;
};

#define NSIM_MACSEC_MAX_SECY_COUNT 3
#define NSIM_MACSEC_MAX_RXSC_COUNT 1
struct nsim_rxsc {
	sci_t sci;
	bool used;
};

struct nsim_secy {
	sci_t sci;
	struct nsim_rxsc nsim_rxsc[NSIM_MACSEC_MAX_RXSC_COUNT];
	u8 nsim_rxsc_count;
	bool used;
};

struct nsim_macsec {
	struct nsim_secy nsim_secy[NSIM_MACSEC_MAX_SECY_COUNT];
	u8 nsim_secy_count;
};

struct nsim_ethtool_pauseparam {
	bool rx;
	bool tx;
	bool report_stats_rx;
	bool report_stats_tx;
};

struct nsim_ethtool {
	u32 get_err;
	u32 set_err;
	u32 channels;
	struct nsim_ethtool_pauseparam pauseparam;
	struct ethtool_coalesce coalesce;
	struct ethtool_ringparam ring;
	struct ethtool_fecparam fec;
};

struct nsim_rq {
	struct napi_struct napi;
	struct sk_buff_head skb_queue;
	struct page_pool *page_pool;
};

struct netdevsim {
	struct net_device *netdev;
	struct nsim_dev *nsim_dev;
	struct nsim_dev_port *nsim_dev_port;
	struct mock_phc *phc;
	struct nsim_rq *rq;

	u64 tx_packets;
	u64 tx_bytes;
	u64 tx_dropped;
	struct u64_stats_sync syncp;

	struct nsim_bus_dev *nsim_bus_dev;

	struct bpf_prog	*bpf_offloaded;
	u32 bpf_offloaded_id;

	struct xdp_attachment_info xdp;
	struct xdp_attachment_info xdp_hw;

	bool bpf_tc_accept;
	bool bpf_tc_non_bound_accept;
	bool bpf_xdpdrv_accept;
	bool bpf_xdpoffload_accept;

	bool bpf_map_accept;
	struct nsim_ipsec ipsec;
	struct nsim_macsec macsec;
	struct {
		u32 inject_error;
		u32 sleep;
		u32 __ports[2][NSIM_UDP_TUNNEL_N_PORTS];
		u32 (*ports)[NSIM_UDP_TUNNEL_N_PORTS];
		struct debugfs_u32_array dfs_ports[2];
	} udp_ports;

	struct page *page;
	struct dentry *pp_dfs;

	struct nsim_ethtool ethtool;
	struct netdevsim __rcu *peer;
};

struct netdevsim *
nsim_create(struct nsim_dev *nsim_dev, struct nsim_dev_port *nsim_dev_port);
void nsim_destroy(struct netdevsim *ns);
bool netdev_is_nsim(struct net_device *dev);

void nsim_ethtool_init(struct netdevsim *ns);

void nsim_udp_tunnels_debugfs_create(struct nsim_dev *nsim_dev);
int nsim_udp_tunnels_info_create(struct nsim_dev *nsim_dev,
				 struct net_device *dev);
void nsim_udp_tunnels_info_destroy(struct net_device *dev);

#ifdef CONFIG_BPF_SYSCALL
int nsim_bpf_dev_init(struct nsim_dev *nsim_dev);
void nsim_bpf_dev_exit(struct nsim_dev *nsim_dev);
int nsim_bpf_init(struct netdevsim *ns);
void nsim_bpf_uninit(struct netdevsim *ns);
int nsim_bpf(struct net_device *dev, struct netdev_bpf *bpf);
int nsim_bpf_disable_tc(struct netdevsim *ns);
int nsim_bpf_setup_tc_block_cb(enum tc_setup_type type,
			       void *type_data, void *cb_priv);
#else

static inline int nsim_bpf_dev_init(struct nsim_dev *nsim_dev)
{
	return 0;
}

static inline void nsim_bpf_dev_exit(struct nsim_dev *nsim_dev)
{
}
static inline int nsim_bpf_init(struct netdevsim *ns)
{
	return 0;
}

static inline void nsim_bpf_uninit(struct netdevsim *ns)
{
}

static inline int nsim_bpf(struct net_device *dev, struct netdev_bpf *bpf)
{
	return -EOPNOTSUPP;
}

static inline int nsim_bpf_disable_tc(struct netdevsim *ns)
{
	return 0;
}

static inline int
nsim_bpf_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
			   void *cb_priv)
{
	return -EOPNOTSUPP;
}
#endif

enum nsim_resource_id {
	NSIM_RESOURCE_NONE,   /* DEVLINK_RESOURCE_ID_PARENT_TOP */
	NSIM_RESOURCE_IPV4,
	NSIM_RESOURCE_IPV4_FIB,
	NSIM_RESOURCE_IPV4_FIB_RULES,
	NSIM_RESOURCE_IPV6,
	NSIM_RESOURCE_IPV6_FIB,
	NSIM_RESOURCE_IPV6_FIB_RULES,
	NSIM_RESOURCE_NEXTHOPS,
};

struct nsim_dev_health {
	struct devlink_health_reporter *empty_reporter;
	struct devlink_health_reporter *dummy_reporter;
	struct dentry *ddir;
	char *recovered_break_msg;
	u32 binary_len;
	bool fail_recover;
};

int nsim_dev_health_init(struct nsim_dev *nsim_dev, struct devlink *devlink);
void nsim_dev_health_exit(struct nsim_dev *nsim_dev);

struct nsim_dev_hwstats_netdev {
	struct list_head list;
	struct net_device *netdev;
	struct rtnl_hw_stats64 stats;
	bool enabled;
	bool fail_enable;
};

struct nsim_dev_hwstats {
	struct dentry *ddir;
	struct dentry *l3_ddir;

	struct mutex hwsdev_list_lock; /* protects hwsdev list(s) */
	struct list_head l3_list;

	struct notifier_block netdevice_nb;
	struct delayed_work traffic_dw;
};

int nsim_dev_hwstats_init(struct nsim_dev *nsim_dev);
void nsim_dev_hwstats_exit(struct nsim_dev *nsim_dev);

#if IS_ENABLED(CONFIG_PSAMPLE)
int nsim_dev_psample_init(struct nsim_dev *nsim_dev);
void nsim_dev_psample_exit(struct nsim_dev *nsim_dev);
#else
static inline int nsim_dev_psample_init(struct nsim_dev *nsim_dev)
{
	return 0;
}

static inline void nsim_dev_psample_exit(struct nsim_dev *nsim_dev)
{
}
#endif

enum nsim_dev_port_type {
	NSIM_DEV_PORT_TYPE_PF,
	NSIM_DEV_PORT_TYPE_VF,
};

#define NSIM_DEV_VF_PORT_INDEX_BASE 128
#define NSIM_DEV_VF_PORT_INDEX_MAX UINT_MAX

struct nsim_dev_port {
	struct list_head list;
	struct devlink_port devlink_port;
	unsigned int port_index;
	enum nsim_dev_port_type port_type;
	struct dentry *ddir;
	struct dentry *rate_parent;
	char *parent_name;
	struct netdevsim *ns;
};

struct nsim_vf_config {
	int link_state;
	u16 min_tx_rate;
	u16 max_tx_rate;
	u16 vlan;
	__be16 vlan_proto;
	u16 qos;
	u8 vf_mac[ETH_ALEN];
	bool spoofchk_enabled;
	bool trusted;
	bool rss_query_enabled;
};

struct nsim_dev {
	struct nsim_bus_dev *nsim_bus_dev;
	struct nsim_fib_data *fib_data;
	struct nsim_trap_data *trap_data;
	struct dentry *ddir;
	struct dentry *ports_ddir;
	struct dentry *take_snapshot;
	struct dentry *nodes_ddir;

	struct nsim_vf_config *vfconfigs;

	struct bpf_offload_dev *bpf_dev;
	bool bpf_bind_accept;
	bool bpf_bind_verifier_accept;
	u32 bpf_bind_verifier_delay;
	struct dentry *ddir_bpf_bound_progs;
	u32 prog_id_gen;
	struct list_head bpf_bound_progs;
	struct list_head bpf_bound_maps;
	struct netdev_phys_item_id switch_id;
	struct list_head port_list;
	bool fw_update_status;
	u32 fw_update_overwrite_mask;
	u32 max_macs;
	bool test1;
	bool dont_allow_reload;
	bool fail_reload;
	struct devlink_region *dummy_region;
	struct nsim_dev_health health;
	struct nsim_dev_hwstats hwstats;
	struct flow_action_cookie *fa_cookie;
	spinlock_t fa_cookie_lock; /* protects fa_cookie */
	bool fail_trap_group_set;
	bool fail_trap_policer_set;
	bool fail_trap_policer_counter_get;
	bool fail_trap_drop_counter_get;
	struct {
		struct udp_tunnel_nic_shared utn_shared;
		u32 __ports[2][NSIM_UDP_TUNNEL_N_PORTS];
		bool sync_all;
		bool open_only;
		bool ipv4_only;
		bool shared;
		bool static_iana_vxlan;
		u32 sleep;
	} udp_ports;
	struct nsim_dev_psample *psample;
	u16 esw_mode;
};

static inline bool nsim_esw_mode_is_legacy(struct nsim_dev *nsim_dev)
{
	return nsim_dev->esw_mode == DEVLINK_ESWITCH_MODE_LEGACY;
}

static inline bool nsim_esw_mode_is_switchdev(struct nsim_dev *nsim_dev)
{
	return nsim_dev->esw_mode == DEVLINK_ESWITCH_MODE_SWITCHDEV;
}

static inline struct net *nsim_dev_net(struct nsim_dev *nsim_dev)
{
	return devlink_net(priv_to_devlink(nsim_dev));
}

int nsim_dev_init(void);
void nsim_dev_exit(void);
int nsim_drv_probe(struct nsim_bus_dev *nsim_bus_dev);
void nsim_drv_remove(struct nsim_bus_dev *nsim_bus_dev);
int nsim_drv_port_add(struct nsim_bus_dev *nsim_bus_dev,
		      enum nsim_dev_port_type type,
		      unsigned int port_index);
int nsim_drv_port_del(struct nsim_bus_dev *nsim_bus_dev,
		      enum nsim_dev_port_type type,
		      unsigned int port_index);
int nsim_drv_configure_vfs(struct nsim_bus_dev *nsim_bus_dev,
			   unsigned int num_vfs);

unsigned int nsim_dev_get_vfs(struct nsim_dev *nsim_dev);

struct nsim_fib_data *nsim_fib_create(struct devlink *devlink,
				      struct netlink_ext_ack *extack);
void nsim_fib_destroy(struct devlink *devlink, struct nsim_fib_data *fib_data);
u64 nsim_fib_get_val(struct nsim_fib_data *fib_data,
		     enum nsim_resource_id res_id, bool max);

static inline bool nsim_dev_port_is_pf(struct nsim_dev_port *nsim_dev_port)
{
	return nsim_dev_port->port_type == NSIM_DEV_PORT_TYPE_PF;
}

static inline bool nsim_dev_port_is_vf(struct nsim_dev_port *nsim_dev_port)
{
	return nsim_dev_port->port_type == NSIM_DEV_PORT_TYPE_VF;
}
#if IS_ENABLED(CONFIG_XFRM_OFFLOAD)
void nsim_ipsec_init(struct netdevsim *ns);
void nsim_ipsec_teardown(struct netdevsim *ns);
bool nsim_ipsec_tx(struct netdevsim *ns, struct sk_buff *skb);
#else
static inline void nsim_ipsec_init(struct netdevsim *ns)
{
}

static inline void nsim_ipsec_teardown(struct netdevsim *ns)
{
}

static inline bool nsim_ipsec_tx(struct netdevsim *ns, struct sk_buff *skb)
{
	return true;
}
#endif

#if IS_ENABLED(CONFIG_MACSEC)
void nsim_macsec_init(struct netdevsim *ns);
void nsim_macsec_teardown(struct netdevsim *ns);
#else
static inline void nsim_macsec_init(struct netdevsim *ns)
{
}

static inline void nsim_macsec_teardown(struct netdevsim *ns)
{
}
#endif

struct nsim_bus_dev {
	struct device dev;
	struct list_head list;
	unsigned int port_count;
	unsigned int num_queues; /* Number of queues for each port on this bus */
	struct net *initial_net; /* Purpose of this is to carry net pointer
				  * during the probe time only.
				  */
	unsigned int max_vfs;
	unsigned int num_vfs;
	bool init;
};

int nsim_bus_init(void);
void nsim_bus_exit(void);