]> Git Repo - linux.git/blob - drivers/net/netdevsim/udp_tunnels.c
Linux 6.14-rc3
[linux.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         rtnl_lock();
116         if (dev->reg_state == NETREG_REGISTERED) {
117                 memset(ns->udp_ports.ports, 0, sizeof(ns->udp_ports.__ports));
118                 udp_tunnel_nic_reset_ntf(dev);
119         }
120         rtnl_unlock();
121
122         return count;
123 }
124
125 static const struct file_operations nsim_udp_tunnels_info_reset_fops = {
126         .open = simple_open,
127         .write = nsim_udp_tunnels_info_reset_write,
128         .llseek = generic_file_llseek,
129         .owner = THIS_MODULE,
130 };
131
132 int nsim_udp_tunnels_info_create(struct nsim_dev *nsim_dev,
133                                  struct net_device *dev)
134 {
135         struct netdevsim *ns = netdev_priv(dev);
136         struct udp_tunnel_nic_info *info;
137
138         if (nsim_dev->udp_ports.shared && nsim_dev->udp_ports.open_only) {
139                 dev_err(&nsim_dev->nsim_bus_dev->dev,
140                         "shared can't be used in conjunction with open_only\n");
141                 return -EINVAL;
142         }
143
144         if (!nsim_dev->udp_ports.shared)
145                 ns->udp_ports.ports = ns->udp_ports.__ports;
146         else
147                 ns->udp_ports.ports = nsim_dev->udp_ports.__ports;
148
149         ns->udp_ports.ddir = debugfs_create_dir("udp_ports",
150                                                 ns->nsim_dev_port->ddir);
151
152         debugfs_create_u32("inject_error", 0600, ns->udp_ports.ddir,
153                            &ns->udp_ports.inject_error);
154
155         ns->udp_ports.dfs_ports[0].array = ns->udp_ports.ports[0];
156         ns->udp_ports.dfs_ports[0].n_elements = NSIM_UDP_TUNNEL_N_PORTS;
157         debugfs_create_u32_array("table0", 0400, ns->udp_ports.ddir,
158                                  &ns->udp_ports.dfs_ports[0]);
159
160         ns->udp_ports.dfs_ports[1].array = ns->udp_ports.ports[1];
161         ns->udp_ports.dfs_ports[1].n_elements = NSIM_UDP_TUNNEL_N_PORTS;
162         debugfs_create_u32_array("table1", 0400, ns->udp_ports.ddir,
163                                  &ns->udp_ports.dfs_ports[1]);
164
165         debugfs_create_file("reset", 0200, ns->udp_ports.ddir,
166                             dev, &nsim_udp_tunnels_info_reset_fops);
167
168         /* Note: it's not normal to allocate the info struct like this!
169          * Drivers are expected to use a static const one, here we're testing.
170          */
171         info = kmemdup(&nsim_udp_tunnel_info, sizeof(nsim_udp_tunnel_info),
172                        GFP_KERNEL);
173         if (!info)
174                 return -ENOMEM;
175         ns->udp_ports.sleep = nsim_dev->udp_ports.sleep;
176
177         if (nsim_dev->udp_ports.sync_all) {
178                 info->set_port = NULL;
179                 info->unset_port = NULL;
180         } else {
181                 info->sync_table = NULL;
182         }
183
184         if (ns->udp_ports.sleep)
185                 info->flags |= UDP_TUNNEL_NIC_INFO_MAY_SLEEP;
186         if (nsim_dev->udp_ports.open_only)
187                 info->flags |= UDP_TUNNEL_NIC_INFO_OPEN_ONLY;
188         if (nsim_dev->udp_ports.ipv4_only)
189                 info->flags |= UDP_TUNNEL_NIC_INFO_IPV4_ONLY;
190         if (nsim_dev->udp_ports.shared)
191                 info->shared = &nsim_dev->udp_ports.utn_shared;
192         if (nsim_dev->udp_ports.static_iana_vxlan)
193                 info->flags |= UDP_TUNNEL_NIC_INFO_STATIC_IANA_VXLAN;
194
195         dev->udp_tunnel_nic_info = info;
196         return 0;
197 }
198
199 void nsim_udp_tunnels_info_destroy(struct net_device *dev)
200 {
201         struct netdevsim *ns = netdev_priv(dev);
202
203         debugfs_remove_recursive(ns->udp_ports.ddir);
204         kfree(dev->udp_tunnel_nic_info);
205         dev->udp_tunnel_nic_info = NULL;
206 }
207
208 void nsim_udp_tunnels_debugfs_create(struct nsim_dev *nsim_dev)
209 {
210         debugfs_create_bool("udp_ports_sync_all", 0600, nsim_dev->ddir,
211                             &nsim_dev->udp_ports.sync_all);
212         debugfs_create_bool("udp_ports_open_only", 0600, nsim_dev->ddir,
213                             &nsim_dev->udp_ports.open_only);
214         debugfs_create_bool("udp_ports_ipv4_only", 0600, nsim_dev->ddir,
215                             &nsim_dev->udp_ports.ipv4_only);
216         debugfs_create_bool("udp_ports_shared", 0600, nsim_dev->ddir,
217                             &nsim_dev->udp_ports.shared);
218         debugfs_create_bool("udp_ports_static_iana_vxlan", 0600, nsim_dev->ddir,
219                             &nsim_dev->udp_ports.static_iana_vxlan);
220         debugfs_create_u32("udp_ports_sleep", 0600, nsim_dev->ddir,
221                            &nsim_dev->udp_ports.sleep);
222 }
This page took 0.045122 seconds and 4 git commands to generate.