cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vxlan.c (5215B)


      1/*
      2 * Copyright (c) 2016, Mellanox Technologies, Ltd.  All rights reserved.
      3 *
      4 * This software is available to you under a choice of one of two
      5 * licenses.  You may choose to be licensed under the terms of the GNU
      6 * General Public License (GPL) Version 2, available from the file
      7 * COPYING in the main directory of this source tree, or the
      8 * OpenIB.org BSD license below:
      9 *
     10 *     Redistribution and use in source and binary forms, with or
     11 *     without modification, are permitted provided that the following
     12 *     conditions are met:
     13 *
     14 *      - Redistributions of source code must retain the above
     15 *        copyright notice, this list of conditions and the following
     16 *        disclaimer.
     17 *
     18 *      - Redistributions in binary form must reproduce the above
     19 *        copyright notice, this list of conditions and the following
     20 *        disclaimer in the documentation and/or other materials
     21 *        provided with the distribution.
     22 *
     23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
     27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     30 * SOFTWARE.
     31 */
     32
     33#include <linux/kernel.h>
     34#include <linux/refcount.h>
     35#include <linux/mlx5/driver.h>
     36#include <net/vxlan.h>
     37#include "mlx5_core.h"
     38#include "vxlan.h"
     39
     40struct mlx5_vxlan {
     41	struct mlx5_core_dev		*mdev;
     42	/* max_num_ports is usually 4, 16 buckets is more than enough */
     43	DECLARE_HASHTABLE(htable, 4);
     44	struct mutex                    sync_lock; /* sync add/del port HW operations */
     45};
     46
     47struct mlx5_vxlan_port {
     48	struct hlist_node hlist;
     49	u16 udp_port;
     50};
     51
     52static int mlx5_vxlan_core_add_port_cmd(struct mlx5_core_dev *mdev, u16 port)
     53{
     54	u32 in[MLX5_ST_SZ_DW(add_vxlan_udp_dport_in)] = {};
     55
     56	MLX5_SET(add_vxlan_udp_dport_in, in, opcode,
     57		 MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT);
     58	MLX5_SET(add_vxlan_udp_dport_in, in, vxlan_udp_port, port);
     59	return mlx5_cmd_exec_in(mdev, add_vxlan_udp_dport, in);
     60}
     61
     62static int mlx5_vxlan_core_del_port_cmd(struct mlx5_core_dev *mdev, u16 port)
     63{
     64	u32 in[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_in)] = {};
     65
     66	MLX5_SET(delete_vxlan_udp_dport_in, in, opcode,
     67		 MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT);
     68	MLX5_SET(delete_vxlan_udp_dport_in, in, vxlan_udp_port, port);
     69	return mlx5_cmd_exec_in(mdev, delete_vxlan_udp_dport, in);
     70}
     71
     72bool mlx5_vxlan_lookup_port(struct mlx5_vxlan *vxlan, u16 port)
     73{
     74	struct mlx5_vxlan_port *vxlanp;
     75	bool found = false;
     76
     77	if (!mlx5_vxlan_allowed(vxlan))
     78		return NULL;
     79
     80	rcu_read_lock();
     81	hash_for_each_possible_rcu(vxlan->htable, vxlanp, hlist, port)
     82		if (vxlanp->udp_port == port) {
     83			found = true;
     84			break;
     85		}
     86	rcu_read_unlock();
     87
     88	return found;
     89}
     90
     91static struct mlx5_vxlan_port *vxlan_lookup_port(struct mlx5_vxlan *vxlan, u16 port)
     92{
     93	struct mlx5_vxlan_port *vxlanp;
     94
     95	hash_for_each_possible(vxlan->htable, vxlanp, hlist, port)
     96		if (vxlanp->udp_port == port)
     97			return vxlanp;
     98	return NULL;
     99}
    100
    101int mlx5_vxlan_add_port(struct mlx5_vxlan *vxlan, u16 port)
    102{
    103	struct mlx5_vxlan_port *vxlanp;
    104	int ret;
    105
    106	vxlanp = kzalloc(sizeof(*vxlanp), GFP_KERNEL);
    107	if (!vxlanp)
    108		return -ENOMEM;
    109	vxlanp->udp_port = port;
    110
    111	ret = mlx5_vxlan_core_add_port_cmd(vxlan->mdev, port);
    112	if (ret) {
    113		kfree(vxlanp);
    114		return ret;
    115	}
    116
    117	mutex_lock(&vxlan->sync_lock);
    118	hash_add_rcu(vxlan->htable, &vxlanp->hlist, port);
    119	mutex_unlock(&vxlan->sync_lock);
    120
    121	return 0;
    122}
    123
    124int mlx5_vxlan_del_port(struct mlx5_vxlan *vxlan, u16 port)
    125{
    126	struct mlx5_vxlan_port *vxlanp;
    127	int ret = 0;
    128
    129	mutex_lock(&vxlan->sync_lock);
    130
    131	vxlanp = vxlan_lookup_port(vxlan, port);
    132	if (WARN_ON(!vxlanp)) {
    133		ret = -ENOENT;
    134		goto out_unlock;
    135	}
    136
    137	hash_del_rcu(&vxlanp->hlist);
    138	synchronize_rcu();
    139	mlx5_vxlan_core_del_port_cmd(vxlan->mdev, port);
    140	kfree(vxlanp);
    141
    142out_unlock:
    143	mutex_unlock(&vxlan->sync_lock);
    144	return ret;
    145}
    146
    147struct mlx5_vxlan *mlx5_vxlan_create(struct mlx5_core_dev *mdev)
    148{
    149	struct mlx5_vxlan *vxlan;
    150
    151	if (!MLX5_CAP_ETH(mdev, tunnel_stateless_vxlan) || !mlx5_core_is_pf(mdev))
    152		return ERR_PTR(-ENOTSUPP);
    153
    154	vxlan = kzalloc(sizeof(*vxlan), GFP_KERNEL);
    155	if (!vxlan)
    156		return ERR_PTR(-ENOMEM);
    157
    158	vxlan->mdev = mdev;
    159	mutex_init(&vxlan->sync_lock);
    160	hash_init(vxlan->htable);
    161
    162	/* Hardware adds 4789 (IANA_VXLAN_UDP_PORT) by default */
    163	mlx5_vxlan_add_port(vxlan, IANA_VXLAN_UDP_PORT);
    164
    165	return vxlan;
    166}
    167
    168void mlx5_vxlan_destroy(struct mlx5_vxlan *vxlan)
    169{
    170	if (!mlx5_vxlan_allowed(vxlan))
    171		return;
    172
    173	mlx5_vxlan_del_port(vxlan, IANA_VXLAN_UDP_PORT);
    174	WARN_ON(!hash_empty(vxlan->htable));
    175
    176	kfree(vxlan);
    177}
    178
    179void mlx5_vxlan_reset_to_default(struct mlx5_vxlan *vxlan)
    180{
    181	struct mlx5_vxlan_port *vxlanp;
    182	struct hlist_node *tmp;
    183	int bkt;
    184
    185	if (!mlx5_vxlan_allowed(vxlan))
    186		return;
    187
    188	hash_for_each_safe(vxlan->htable, bkt, tmp, vxlanp, hlist) {
    189		/* Don't delete default UDP port added by the HW.
    190		 * Remove only user configured ports
    191		 */
    192		if (vxlanp->udp_port == IANA_VXLAN_UDP_PORT)
    193			continue;
    194		mlx5_vxlan_del_port(vxlan, vxlanp->udp_port);
    195	}
    196}