]>
Commit | Line | Data |
---|---|---|
e3cf00d0 UM |
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> | |
62141054 | 19 | #include <linux/file.h> |
e3cf00d0 UM |
20 | #include <linux/module.h> |
21 | #include <linux/slab.h> | |
62141054 | 22 | #include <net/inet_sock.h> |
e3cf00d0 UM |
23 | |
24 | #include "usnic_transport.h" | |
25 | #include "usnic_log.h" | |
26 | ||
27 | /* ROCE */ | |
28 | static unsigned long *roce_bitmap; | |
29 | static u16 roce_next_port = 1; | |
30 | #define ROCE_BITMAP_SZ ((1 << (8 /*CHAR_BIT*/ * sizeof(u16)))/8 /*CHAR BIT*/) | |
31 | static DEFINE_SPINLOCK(roce_bitmap_lock); | |
32 | ||
62141054 | 33 | const char *usnic_transport_to_str(enum usnic_transport_type type) |
e3cf00d0 UM |
34 | { |
35 | switch (type) { | |
36 | case USNIC_TRANSPORT_UNKNOWN: | |
37 | return "Unknown"; | |
38 | case USNIC_TRANSPORT_ROCE_CUSTOM: | |
39 | return "roce custom"; | |
62141054 UM |
40 | case USNIC_TRANSPORT_IPV4_UDP: |
41 | return "IPv4 UDP"; | |
e3cf00d0 UM |
42 | case USNIC_TRANSPORT_MAX: |
43 | return "Max?"; | |
44 | default: | |
45 | return "Not known"; | |
46 | } | |
47 | } | |
48 | ||
62141054 UM |
49 | int 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 | ||
4942c0b4 | 62 | return scnprintf(buf, buf_sz, "Proto:%u Addr:%pI4h Port:%hu", |
62141054 UM |
63 | proto, &addr, port); |
64 | } | |
65 | ||
e3cf00d0 UM |
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 | */ | |
71 | u16 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", | |
62141054 | 84 | usnic_transport_to_str(type)); |
e3cf00d0 UM |
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", | |
62141054 | 92 | usnic_transport_to_str(type)); |
e3cf00d0 UM |
93 | goto out_fail; |
94 | } | |
95 | ||
96 | usnic_dbg("Allocating port %hu for %s\n", port_num, | |
62141054 | 97 | usnic_transport_to_str(type)); |
e3cf00d0 UM |
98 | return port_num; |
99 | ||
100 | out_fail: | |
101 | return 0; | |
102 | } | |
103 | ||
104 | void 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", | |
62141054 | 110 | usnic_transport_to_str(type)); |
e3cf00d0 UM |
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, | |
62141054 | 117 | usnic_transport_to_str(type)); |
e3cf00d0 UM |
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, | |
62141054 | 122 | usnic_transport_to_str(type)); |
e3cf00d0 UM |
123 | out_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 | ||
62141054 UM |
130 | struct 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 | ||
150 | void 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 | ||
159 | int 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 | ||
e3cf00d0 UM |
186 | int 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 | ||
199 | void usnic_transport_fini(void) | |
200 | { | |
201 | kfree(roce_bitmap); | |
202 | } |