1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (c) 2020 Facebook Inc.
4 #include <linux/debugfs.h>
5 #include <linux/netdevice.h>
6 #include <linux/slab.h>
7 #include <net/udp_tunnel.h>
12 nsim_udp_tunnel_set_port(struct net_device
*dev
, unsigned int table
,
13 unsigned int entry
, struct udp_tunnel_info
*ti
)
15 struct netdevsim
*ns
= netdev_priv(dev
);
18 ret
= -ns
->udp_ports
.inject_error
;
19 ns
->udp_ports
.inject_error
= 0;
21 if (ns
->udp_ports
.sleep
)
22 msleep(ns
->udp_ports
.sleep
);
25 if (ns
->udp_ports
.ports
[table
][entry
]) {
26 WARN(1, "entry already in use\n");
29 ns
->udp_ports
.ports
[table
][entry
] =
30 be16_to_cpu(ti
->port
) << 16 | ti
->type
;
34 netdev_info(dev
, "set [%d, %d] type %d family %d port %d - %d\n",
35 table
, entry
, ti
->type
, ti
->sa_family
, ntohs(ti
->port
),
41 nsim_udp_tunnel_unset_port(struct net_device
*dev
, unsigned int table
,
42 unsigned int entry
, struct udp_tunnel_info
*ti
)
44 struct netdevsim
*ns
= netdev_priv(dev
);
47 ret
= -ns
->udp_ports
.inject_error
;
48 ns
->udp_ports
.inject_error
= 0;
50 if (ns
->udp_ports
.sleep
)
51 msleep(ns
->udp_ports
.sleep
);
53 u32 val
= be16_to_cpu(ti
->port
) << 16 | ti
->type
;
55 if (val
== ns
->udp_ports
.ports
[table
][entry
]) {
56 ns
->udp_ports
.ports
[table
][entry
] = 0;
58 WARN(1, "entry not installed %x vs %x\n",
59 val
, ns
->udp_ports
.ports
[table
][entry
]);
64 netdev_info(dev
, "unset [%d, %d] type %d family %d port %d - %d\n",
65 table
, entry
, ti
->type
, ti
->sa_family
, ntohs(ti
->port
),
71 nsim_udp_tunnel_sync_table(struct net_device
*dev
, unsigned int table
)
73 struct netdevsim
*ns
= netdev_priv(dev
);
74 struct udp_tunnel_info ti
;
78 ret
= -ns
->udp_ports
.inject_error
;
79 ns
->udp_ports
.inject_error
= 0;
81 for (i
= 0; i
< NSIM_UDP_TUNNEL_N_PORTS
; i
++) {
82 udp_tunnel_nic_get_port(dev
, table
, i
, &ti
);
83 ns
->udp_ports
.ports
[table
][i
] =
84 be16_to_cpu(ti
.port
) << 16 | ti
.type
;
90 static const struct udp_tunnel_nic_info nsim_udp_tunnel_info
= {
91 .set_port
= nsim_udp_tunnel_set_port
,
92 .unset_port
= nsim_udp_tunnel_unset_port
,
93 .sync_table
= nsim_udp_tunnel_sync_table
,
97 .n_entries
= NSIM_UDP_TUNNEL_N_PORTS
,
98 .tunnel_types
= UDP_TUNNEL_TYPE_VXLAN
,
101 .n_entries
= NSIM_UDP_TUNNEL_N_PORTS
,
102 .tunnel_types
= UDP_TUNNEL_TYPE_GENEVE
|
103 UDP_TUNNEL_TYPE_VXLAN_GPE
,
109 nsim_udp_tunnels_info_reset_write(struct file
*file
, const char __user
*data
,
110 size_t count
, loff_t
*ppos
)
112 struct net_device
*dev
= file
->private_data
;
113 struct netdevsim
*ns
= netdev_priv(dev
);
115 memset(ns
->udp_ports
.ports
, 0, sizeof(ns
->udp_ports
.__ports
));
117 udp_tunnel_nic_reset_ntf(dev
);
123 static const struct file_operations nsim_udp_tunnels_info_reset_fops
= {
125 .write
= nsim_udp_tunnels_info_reset_write
,
126 .llseek
= generic_file_llseek
,
127 .owner
= THIS_MODULE
,
130 int nsim_udp_tunnels_info_create(struct nsim_dev
*nsim_dev
,
131 struct net_device
*dev
)
133 struct netdevsim
*ns
= netdev_priv(dev
);
134 struct udp_tunnel_nic_info
*info
;
136 if (nsim_dev
->udp_ports
.shared
&& nsim_dev
->udp_ports
.open_only
) {
137 dev_err(&nsim_dev
->nsim_bus_dev
->dev
,
138 "shared can't be used in conjunction with open_only\n");
142 if (!nsim_dev
->udp_ports
.shared
)
143 ns
->udp_ports
.ports
= ns
->udp_ports
.__ports
;
145 ns
->udp_ports
.ports
= nsim_dev
->udp_ports
.__ports
;
147 debugfs_create_u32("udp_ports_inject_error", 0600,
148 ns
->nsim_dev_port
->ddir
,
149 &ns
->udp_ports
.inject_error
);
151 ns
->udp_ports
.dfs_ports
[0].array
= ns
->udp_ports
.ports
[0];
152 ns
->udp_ports
.dfs_ports
[0].n_elements
= NSIM_UDP_TUNNEL_N_PORTS
;
153 debugfs_create_u32_array("udp_ports_table0", 0400,
154 ns
->nsim_dev_port
->ddir
,
155 &ns
->udp_ports
.dfs_ports
[0]);
157 ns
->udp_ports
.dfs_ports
[1].array
= ns
->udp_ports
.ports
[1];
158 ns
->udp_ports
.dfs_ports
[1].n_elements
= NSIM_UDP_TUNNEL_N_PORTS
;
159 debugfs_create_u32_array("udp_ports_table1", 0400,
160 ns
->nsim_dev_port
->ddir
,
161 &ns
->udp_ports
.dfs_ports
[1]);
163 debugfs_create_file("udp_ports_reset", 0200, ns
->nsim_dev_port
->ddir
,
164 dev
, &nsim_udp_tunnels_info_reset_fops
);
166 /* Note: it's not normal to allocate the info struct like this!
167 * Drivers are expected to use a static const one, here we're testing.
169 info
= kmemdup(&nsim_udp_tunnel_info
, sizeof(nsim_udp_tunnel_info
),
173 ns
->udp_ports
.sleep
= nsim_dev
->udp_ports
.sleep
;
175 if (nsim_dev
->udp_ports
.sync_all
) {
176 info
->set_port
= NULL
;
177 info
->unset_port
= NULL
;
179 info
->sync_table
= NULL
;
182 if (ns
->udp_ports
.sleep
)
183 info
->flags
|= UDP_TUNNEL_NIC_INFO_MAY_SLEEP
;
184 if (nsim_dev
->udp_ports
.open_only
)
185 info
->flags
|= UDP_TUNNEL_NIC_INFO_OPEN_ONLY
;
186 if (nsim_dev
->udp_ports
.ipv4_only
)
187 info
->flags
|= UDP_TUNNEL_NIC_INFO_IPV4_ONLY
;
188 if (nsim_dev
->udp_ports
.shared
)
189 info
->shared
= &nsim_dev
->udp_ports
.utn_shared
;
190 if (nsim_dev
->udp_ports
.static_iana_vxlan
)
191 info
->flags
|= UDP_TUNNEL_NIC_INFO_STATIC_IANA_VXLAN
;
193 dev
->udp_tunnel_nic_info
= info
;
197 void nsim_udp_tunnels_info_destroy(struct net_device
*dev
)
199 kfree(dev
->udp_tunnel_nic_info
);
200 dev
->udp_tunnel_nic_info
= NULL
;
203 void nsim_udp_tunnels_debugfs_create(struct nsim_dev
*nsim_dev
)
205 debugfs_create_bool("udp_ports_sync_all", 0600, nsim_dev
->ddir
,
206 &nsim_dev
->udp_ports
.sync_all
);
207 debugfs_create_bool("udp_ports_open_only", 0600, nsim_dev
->ddir
,
208 &nsim_dev
->udp_ports
.open_only
);
209 debugfs_create_bool("udp_ports_ipv4_only", 0600, nsim_dev
->ddir
,
210 &nsim_dev
->udp_ports
.ipv4_only
);
211 debugfs_create_bool("udp_ports_shared", 0600, nsim_dev
->ddir
,
212 &nsim_dev
->udp_ports
.shared
);
213 debugfs_create_bool("udp_ports_static_iana_vxlan", 0600, nsim_dev
->ddir
,
214 &nsim_dev
->udp_ports
.static_iana_vxlan
);
215 debugfs_create_u32("udp_ports_sleep", 0600, nsim_dev
->ddir
,
216 &nsim_dev
->udp_ports
.sleep
);