162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci#include <linux/bitmap.h> 3462306a36Sopenharmony_ci#include <linux/file.h> 3562306a36Sopenharmony_ci#include <linux/slab.h> 3662306a36Sopenharmony_ci#include <net/inet_sock.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include "usnic_transport.h" 3962306a36Sopenharmony_ci#include "usnic_log.h" 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* ROCE */ 4262306a36Sopenharmony_cistatic unsigned long *roce_bitmap; 4362306a36Sopenharmony_cistatic u16 roce_next_port = 1; 4462306a36Sopenharmony_ci#define ROCE_BITMAP_SZ ((1 << (8 /*CHAR_BIT*/ * sizeof(u16)))/8 /*CHAR BIT*/) 4562306a36Sopenharmony_cistatic DEFINE_SPINLOCK(roce_bitmap_lock); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ciconst char *usnic_transport_to_str(enum usnic_transport_type type) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci switch (type) { 5062306a36Sopenharmony_ci case USNIC_TRANSPORT_UNKNOWN: 5162306a36Sopenharmony_ci return "Unknown"; 5262306a36Sopenharmony_ci case USNIC_TRANSPORT_ROCE_CUSTOM: 5362306a36Sopenharmony_ci return "roce custom"; 5462306a36Sopenharmony_ci case USNIC_TRANSPORT_IPV4_UDP: 5562306a36Sopenharmony_ci return "IPv4 UDP"; 5662306a36Sopenharmony_ci case USNIC_TRANSPORT_MAX: 5762306a36Sopenharmony_ci return "Max?"; 5862306a36Sopenharmony_ci default: 5962306a36Sopenharmony_ci return "Not known"; 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ciint usnic_transport_sock_to_str(char *buf, int buf_sz, 6462306a36Sopenharmony_ci struct socket *sock) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci int err; 6762306a36Sopenharmony_ci uint32_t addr; 6862306a36Sopenharmony_ci uint16_t port; 6962306a36Sopenharmony_ci int proto; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci memset(buf, 0, buf_sz); 7262306a36Sopenharmony_ci err = usnic_transport_sock_get_addr(sock, &proto, &addr, &port); 7362306a36Sopenharmony_ci if (err) 7462306a36Sopenharmony_ci return 0; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci return scnprintf(buf, buf_sz, "Proto:%u Addr:%pI4h Port:%hu", 7762306a36Sopenharmony_ci proto, &addr, port); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* 8162306a36Sopenharmony_ci * reserve a port number. if "0" specified, we will try to pick one 8262306a36Sopenharmony_ci * starting at roce_next_port. roce_next_port will take on the values 8362306a36Sopenharmony_ci * 1..4096 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_ciu16 usnic_transport_rsrv_port(enum usnic_transport_type type, u16 port_num) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci if (type == USNIC_TRANSPORT_ROCE_CUSTOM) { 8862306a36Sopenharmony_ci spin_lock(&roce_bitmap_lock); 8962306a36Sopenharmony_ci if (!port_num) { 9062306a36Sopenharmony_ci port_num = bitmap_find_next_zero_area(roce_bitmap, 9162306a36Sopenharmony_ci ROCE_BITMAP_SZ, 9262306a36Sopenharmony_ci roce_next_port /* start */, 9362306a36Sopenharmony_ci 1 /* nr */, 9462306a36Sopenharmony_ci 0 /* align */); 9562306a36Sopenharmony_ci roce_next_port = (port_num & 4095) + 1; 9662306a36Sopenharmony_ci } else if (test_bit(port_num, roce_bitmap)) { 9762306a36Sopenharmony_ci usnic_err("Failed to allocate port for %s\n", 9862306a36Sopenharmony_ci usnic_transport_to_str(type)); 9962306a36Sopenharmony_ci spin_unlock(&roce_bitmap_lock); 10062306a36Sopenharmony_ci goto out_fail; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci bitmap_set(roce_bitmap, port_num, 1); 10362306a36Sopenharmony_ci spin_unlock(&roce_bitmap_lock); 10462306a36Sopenharmony_ci } else { 10562306a36Sopenharmony_ci usnic_err("Failed to allocate port - transport %s unsupported\n", 10662306a36Sopenharmony_ci usnic_transport_to_str(type)); 10762306a36Sopenharmony_ci goto out_fail; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci usnic_dbg("Allocating port %hu for %s\n", port_num, 11162306a36Sopenharmony_ci usnic_transport_to_str(type)); 11262306a36Sopenharmony_ci return port_num; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ciout_fail: 11562306a36Sopenharmony_ci return 0; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_civoid usnic_transport_unrsrv_port(enum usnic_transport_type type, u16 port_num) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci if (type == USNIC_TRANSPORT_ROCE_CUSTOM) { 12162306a36Sopenharmony_ci spin_lock(&roce_bitmap_lock); 12262306a36Sopenharmony_ci if (!port_num) { 12362306a36Sopenharmony_ci usnic_err("Unreserved invalid port num 0 for %s\n", 12462306a36Sopenharmony_ci usnic_transport_to_str(type)); 12562306a36Sopenharmony_ci goto out_roce_custom; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (!test_bit(port_num, roce_bitmap)) { 12962306a36Sopenharmony_ci usnic_err("Unreserving invalid %hu for %s\n", 13062306a36Sopenharmony_ci port_num, 13162306a36Sopenharmony_ci usnic_transport_to_str(type)); 13262306a36Sopenharmony_ci goto out_roce_custom; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci bitmap_clear(roce_bitmap, port_num, 1); 13562306a36Sopenharmony_ci usnic_dbg("Freeing port %hu for %s\n", port_num, 13662306a36Sopenharmony_ci usnic_transport_to_str(type)); 13762306a36Sopenharmony_ciout_roce_custom: 13862306a36Sopenharmony_ci spin_unlock(&roce_bitmap_lock); 13962306a36Sopenharmony_ci } else { 14062306a36Sopenharmony_ci usnic_err("Freeing invalid port %hu for %d\n", port_num, type); 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistruct socket *usnic_transport_get_socket(int sock_fd) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci struct socket *sock; 14762306a36Sopenharmony_ci int err; 14862306a36Sopenharmony_ci char buf[25]; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* sockfd_lookup will internally do a fget */ 15162306a36Sopenharmony_ci sock = sockfd_lookup(sock_fd, &err); 15262306a36Sopenharmony_ci if (!sock) { 15362306a36Sopenharmony_ci usnic_err("Unable to lookup socket for fd %d with err %d\n", 15462306a36Sopenharmony_ci sock_fd, err); 15562306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci usnic_transport_sock_to_str(buf, sizeof(buf), sock); 15962306a36Sopenharmony_ci usnic_dbg("Get sock %s\n", buf); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return sock; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_civoid usnic_transport_put_socket(struct socket *sock) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci char buf[100]; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci usnic_transport_sock_to_str(buf, sizeof(buf), sock); 16962306a36Sopenharmony_ci usnic_dbg("Put sock %s\n", buf); 17062306a36Sopenharmony_ci sockfd_put(sock); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ciint usnic_transport_sock_get_addr(struct socket *sock, int *proto, 17462306a36Sopenharmony_ci uint32_t *addr, uint16_t *port) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci int err; 17762306a36Sopenharmony_ci struct sockaddr_in sock_addr; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci err = sock->ops->getname(sock, 18062306a36Sopenharmony_ci (struct sockaddr *)&sock_addr, 18162306a36Sopenharmony_ci 0); 18262306a36Sopenharmony_ci if (err < 0) 18362306a36Sopenharmony_ci return err; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (sock_addr.sin_family != AF_INET) 18662306a36Sopenharmony_ci return -EINVAL; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (proto) 18962306a36Sopenharmony_ci *proto = sock->sk->sk_protocol; 19062306a36Sopenharmony_ci if (port) 19162306a36Sopenharmony_ci *port = ntohs(((struct sockaddr_in *)&sock_addr)->sin_port); 19262306a36Sopenharmony_ci if (addr) 19362306a36Sopenharmony_ci *addr = ntohl(((struct sockaddr_in *) 19462306a36Sopenharmony_ci &sock_addr)->sin_addr.s_addr); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return 0; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ciint usnic_transport_init(void) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci roce_bitmap = kzalloc(ROCE_BITMAP_SZ, GFP_KERNEL); 20262306a36Sopenharmony_ci if (!roce_bitmap) 20362306a36Sopenharmony_ci return -ENOMEM; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* Do not ever allocate bit 0, hence set it here */ 20662306a36Sopenharmony_ci bitmap_set(roce_bitmap, 0, 1); 20762306a36Sopenharmony_ci return 0; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_civoid usnic_transport_fini(void) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci kfree(roce_bitmap); 21362306a36Sopenharmony_ci} 214