218 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2// 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 11static int12nsim_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 40static int41nsim_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 70static int71nsim_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 90static 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 108static ssize_t109nsim_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 123static 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 130int 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 else145 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 197void 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 203void 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}218