1/* 2 * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved. 3 * 4 * This program is free software; you may redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; version 2 of the License. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 9 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 10 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 11 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 12 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 13 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 15 * SOFTWARE. 16 * 17 */ 18#include <linux/bitmap.h> 19#include <linux/file.h> 20#include <linux/module.h> 21#include <linux/slab.h> 22#include <net/inet_sock.h> 23 24#include "usnic_transport.h" 25#include "usnic_log.h" 26 27/* ROCE */ 28static unsigned long *roce_bitmap; 29static u16 roce_next_port = 1; 30#define ROCE_BITMAP_SZ ((1 << (8 /*CHAR_BIT*/ * sizeof(u16)))/8 /*CHAR BIT*/) 31static DEFINE_SPINLOCK(roce_bitmap_lock); 32 33const char *usnic_transport_to_str(enum usnic_transport_type type) 34{ 35 switch (type) { 36 case USNIC_TRANSPORT_UNKNOWN: 37 return "Unknown"; 38 case USNIC_TRANSPORT_ROCE_CUSTOM: 39 return "roce custom"; 40 case USNIC_TRANSPORT_IPV4_UDP: 41 return "IPv4 UDP"; 42 case USNIC_TRANSPORT_MAX: 43 return "Max?"; 44 default: 45 return "Not known"; 46 } 47} 48 49int usnic_transport_sock_to_str(char *buf, int buf_sz, 50 struct socket *sock) 51{ 52 int err; 53 uint32_t addr; 54 uint16_t port; 55 int proto; 56 57 memset(buf, 0, buf_sz); 58 err = usnic_transport_sock_get_addr(sock, &proto, &addr, &port); 59 if (err) 60 return 0; 61 62 return scnprintf(buf, buf_sz, "Proto:%u Addr:%pI4h Port:%hu", 63 proto, &addr, port); 64} 65 66/* 67 * reserve a port number. if "0" specified, we will try to pick one 68 * starting at roce_next_port. roce_next_port will take on the values 69 * 1..4096 70 */ 71u16 usnic_transport_rsrv_port(enum usnic_transport_type type, u16 port_num) 72{ 73 if (type == USNIC_TRANSPORT_ROCE_CUSTOM) { 74 spin_lock(&roce_bitmap_lock); 75 if (!port_num) { 76 port_num = bitmap_find_next_zero_area(roce_bitmap, 77 ROCE_BITMAP_SZ, 78 roce_next_port /* start */, 79 1 /* nr */, 80 0 /* align */); 81 roce_next_port = (port_num & 4095) + 1; 82 } else if (test_bit(port_num, roce_bitmap)) { 83 usnic_err("Failed to allocate port for %s\n", 84 usnic_transport_to_str(type)); 85 spin_unlock(&roce_bitmap_lock); 86 goto out_fail; 87 } 88 bitmap_set(roce_bitmap, port_num, 1); 89 spin_unlock(&roce_bitmap_lock); 90 } else { 91 usnic_err("Failed to allocate port - transport %s unsupported\n", 92 usnic_transport_to_str(type)); 93 goto out_fail; 94 } 95 96 usnic_dbg("Allocating port %hu for %s\n", port_num, 97 usnic_transport_to_str(type)); 98 return port_num; 99 100out_fail: 101 return 0; 102} 103 104void usnic_transport_unrsrv_port(enum usnic_transport_type type, u16 port_num) 105{ 106 if (type == USNIC_TRANSPORT_ROCE_CUSTOM) { 107 spin_lock(&roce_bitmap_lock); 108 if (!port_num) { 109 usnic_err("Unreserved unvalid port num 0 for %s\n", 110 usnic_transport_to_str(type)); 111 goto out_roce_custom; 112 } 113 114 if (!test_bit(port_num, roce_bitmap)) { 115 usnic_err("Unreserving invalid %hu for %s\n", 116 port_num, 117 usnic_transport_to_str(type)); 118 goto out_roce_custom; 119 } 120 bitmap_clear(roce_bitmap, port_num, 1); 121 usnic_dbg("Freeing port %hu for %s\n", port_num, 122 usnic_transport_to_str(type)); 123out_roce_custom: 124 spin_unlock(&roce_bitmap_lock); 125 } else { 126 usnic_err("Freeing invalid port %hu for %d\n", port_num, type); 127 } 128} 129 130struct socket *usnic_transport_get_socket(int sock_fd) 131{ 132 struct socket *sock; 133 int err; 134 char buf[25]; 135 136 /* sockfd_lookup will internally do a fget */ 137 sock = sockfd_lookup(sock_fd, &err); 138 if (!sock) { 139 usnic_err("Unable to lookup socket for fd %d with err %d\n", 140 sock_fd, err); 141 return ERR_PTR(-ENOENT); 142 } 143 144 usnic_transport_sock_to_str(buf, sizeof(buf), sock); 145 usnic_dbg("Get sock %s\n", buf); 146 147 return sock; 148} 149 150void usnic_transport_put_socket(struct socket *sock) 151{ 152 char buf[100]; 153 154 usnic_transport_sock_to_str(buf, sizeof(buf), sock); 155 usnic_dbg("Put sock %s\n", buf); 156 sockfd_put(sock); 157} 158 159int usnic_transport_sock_get_addr(struct socket *sock, int *proto, 160 uint32_t *addr, uint16_t *port) 161{ 162 int len; 163 int err; 164 struct sockaddr_in sock_addr; 165 166 err = sock->ops->getname(sock, 167 (struct sockaddr *)&sock_addr, 168 &len, 0); 169 if (err) 170 return err; 171 172 if (sock_addr.sin_family != AF_INET) 173 return -EINVAL; 174 175 if (proto) 176 *proto = sock->sk->sk_protocol; 177 if (port) 178 *port = ntohs(((struct sockaddr_in *)&sock_addr)->sin_port); 179 if (addr) 180 *addr = ntohl(((struct sockaddr_in *) 181 &sock_addr)->sin_addr.s_addr); 182 183 return 0; 184} 185 186int usnic_transport_init(void) 187{ 188 roce_bitmap = kzalloc(ROCE_BITMAP_SZ, GFP_KERNEL); 189 if (!roce_bitmap) { 190 usnic_err("Failed to allocate bit map"); 191 return -ENOMEM; 192 } 193 194 /* Do not ever allocate bit 0, hence set it here */ 195 bitmap_set(roce_bitmap, 0, 1); 196 return 0; 197} 198 199void usnic_transport_fini(void) 200{ 201 kfree(roce_bitmap); 202} 203