Merge tag 'powerpc-5.15-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[linux-2.6-microblaze.git] / drivers / net / netdevsim / udp_tunnels.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (c) 2020 Facebook Inc.
3
4 #include <linux/debugfs.h>
5 #include <linux/netdevice.h>
6 #include <linux/slab.h>
7 #include <net/udp_tunnel.h>
8
9 #include "netdevsim.h"
10
11 static int
12 nsim_udp_tunnel_set_port(struct net_device *dev, unsigned int table,
13                          unsigned int entry, struct udp_tunnel_info *ti)
14 {
15         struct netdevsim *ns = netdev_priv(dev);
16         int ret;
17
18         ret = -ns->udp_ports.inject_error;
19         ns->udp_ports.inject_error = 0;
20
21         if (ns->udp_ports.sleep)
22                 msleep(ns->udp_ports.sleep);
23
24         if (!ret) {
25                 if (ns->udp_ports.ports[table][entry]) {
26                         WARN(1, "entry already in use\n");
27                         ret = -EBUSY;
28                 } else {
29                         ns->udp_ports.ports[table][entry] =
30                                 be16_to_cpu(ti->port) << 16 | ti->type;
31                 }
32         }
33
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),
36                     ret);
37         return ret;
38 }
39
40 static int
41 nsim_udp_tunnel_unset_port(struct net_device *dev, unsigned int table,
42                            unsigned int entry, struct udp_tunnel_info *ti)
43 {
44         struct netdevsim *ns = netdev_priv(dev);
45         int ret;
46
47         ret = -ns->udp_ports.inject_error;
48         ns->udp_ports.inject_error = 0;
49
50         if (ns->udp_ports.sleep)
51                 msleep(ns->udp_ports.sleep);
52         if (!ret) {
53                 u32 val = be16_to_cpu(ti->port) << 16 | ti->type;
54
55                 if (val == ns->udp_ports.ports[table][entry]) {
56                         ns->udp_ports.ports[table][entry] = 0;
57                 } else {
58                         WARN(1, "entry not installed %x vs %x\n",
59                              val, ns->udp_ports.ports[table][entry]);
60                         ret = -ENOENT;
61                 }
62         }
63
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),
66                     ret);
67         return ret;
68 }
69
70 static int
71 nsim_udp_tunnel_sync_table(struct net_device *dev, unsigned int table)
72 {
73         struct netdevsim *ns = netdev_priv(dev);
74         struct udp_tunnel_info ti;
75         unsigned int i;
76         int ret;
77
78         ret = -ns->udp_ports.inject_error;
79         ns->udp_ports.inject_error = 0;
80
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;
85         }
86
87         return ret;
88 }
89
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,
94
95         .tables = {
96                 {
97                         .n_entries      = NSIM_UDP_TUNNEL_N_PORTS,
98                         .tunnel_types   = UDP_TUNNEL_TYPE_VXLAN,
99                 },
100                 {
101                         .n_entries      = NSIM_UDP_TUNNEL_N_PORTS,
102                         .tunnel_types   = UDP_TUNNEL_TYPE_GENEVE |
103                                           UDP_TUNNEL_TYPE_VXLAN_GPE,
104                 },
105         },
106 };
107
108 static ssize_t
109 nsim_udp_tunnels_info_reset_write(struct file *file, const char __user *data,
110                                   size_t count, loff_t *ppos)
111 {
112         struct net_device *dev = file->private_data;
113         struct netdevsim *ns = netdev_priv(dev);
114
115         memset(ns->udp_ports.ports, 0, sizeof(ns->udp_ports.__ports));
116         rtnl_lock();
117         udp_tunnel_nic_reset_ntf(dev);
118         rtnl_unlock();
119
120         return count;
121 }
122
123 static const struct file_operations nsim_udp_tunnels_info_reset_fops = {
124         .open = simple_open,
125         .write = nsim_udp_tunnels_info_reset_write,
126         .llseek = generic_file_llseek,
127         .owner = THIS_MODULE,
128 };
129
130 int nsim_udp_tunnels_info_create(struct nsim_dev *nsim_dev,
131                                  struct net_device *dev)
132 {
133         struct netdevsim *ns = netdev_priv(dev);
134         struct udp_tunnel_nic_info *info;
135
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");
139                 return -EINVAL;
140         }
141
142         if (!nsim_dev->udp_ports.shared)
143                 ns->udp_ports.ports = ns->udp_ports.__ports;
144         else
145                 ns->udp_ports.ports = nsim_dev->udp_ports.__ports;
146
147         debugfs_create_u32("udp_ports_inject_error", 0600,
148                            ns->nsim_dev_port->ddir,
149                            &ns->udp_ports.inject_error);
150
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]);
156
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]);
162
163         debugfs_create_file("udp_ports_reset", 0200, ns->nsim_dev_port->ddir,
164                             dev, &nsim_udp_tunnels_info_reset_fops);
165
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.
168          */
169         info = kmemdup(&nsim_udp_tunnel_info, sizeof(nsim_udp_tunnel_info),
170                        GFP_KERNEL);
171         if (!info)
172                 return -ENOMEM;
173         ns->udp_ports.sleep = nsim_dev->udp_ports.sleep;
174
175         if (nsim_dev->udp_ports.sync_all) {
176                 info->set_port = NULL;
177                 info->unset_port = NULL;
178         } else {
179                 info->sync_table = NULL;
180         }
181
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;
192
193         dev->udp_tunnel_nic_info = info;
194         return 0;
195 }
196
197 void nsim_udp_tunnels_info_destroy(struct net_device *dev)
198 {
199         kfree(dev->udp_tunnel_nic_info);
200         dev->udp_tunnel_nic_info = NULL;
201 }
202
203 void nsim_udp_tunnels_debugfs_create(struct nsim_dev *nsim_dev)
204 {
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);
217 }