123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- /*
- * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved.
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
- #include <linux/bitmap.h>
- #include <linux/file.h>
- #include <linux/module.h>
- #include <linux/slab.h>
- #include <net/inet_sock.h>
- #include "usnic_transport.h"
- #include "usnic_log.h"
- /* ROCE */
- static unsigned long *roce_bitmap;
- static u16 roce_next_port = 1;
- #define ROCE_BITMAP_SZ ((1 << (8 /*CHAR_BIT*/ * sizeof(u16)))/8 /*CHAR BIT*/)
- static DEFINE_SPINLOCK(roce_bitmap_lock);
- const char *usnic_transport_to_str(enum usnic_transport_type type)
- {
- switch (type) {
- case USNIC_TRANSPORT_UNKNOWN:
- return "Unknown";
- case USNIC_TRANSPORT_ROCE_CUSTOM:
- return "roce custom";
- case USNIC_TRANSPORT_IPV4_UDP:
- return "IPv4 UDP";
- case USNIC_TRANSPORT_MAX:
- return "Max?";
- default:
- return "Not known";
- }
- }
- int usnic_transport_sock_to_str(char *buf, int buf_sz,
- struct socket *sock)
- {
- int err;
- uint32_t addr;
- uint16_t port;
- int proto;
- memset(buf, 0, buf_sz);
- err = usnic_transport_sock_get_addr(sock, &proto, &addr, &port);
- if (err)
- return 0;
- return scnprintf(buf, buf_sz, "Proto:%u Addr:%pI4h Port:%hu",
- proto, &addr, port);
- }
- /*
- * reserve a port number. if "0" specified, we will try to pick one
- * starting at roce_next_port. roce_next_port will take on the values
- * 1..4096
- */
- u16 usnic_transport_rsrv_port(enum usnic_transport_type type, u16 port_num)
- {
- if (type == USNIC_TRANSPORT_ROCE_CUSTOM) {
- spin_lock(&roce_bitmap_lock);
- if (!port_num) {
- port_num = bitmap_find_next_zero_area(roce_bitmap,
- ROCE_BITMAP_SZ,
- roce_next_port /* start */,
- 1 /* nr */,
- 0 /* align */);
- roce_next_port = (port_num & 4095) + 1;
- } else if (test_bit(port_num, roce_bitmap)) {
- usnic_err("Failed to allocate port for %s\n",
- usnic_transport_to_str(type));
- spin_unlock(&roce_bitmap_lock);
- goto out_fail;
- }
- bitmap_set(roce_bitmap, port_num, 1);
- spin_unlock(&roce_bitmap_lock);
- } else {
- usnic_err("Failed to allocate port - transport %s unsupported\n",
- usnic_transport_to_str(type));
- goto out_fail;
- }
- usnic_dbg("Allocating port %hu for %s\n", port_num,
- usnic_transport_to_str(type));
- return port_num;
- out_fail:
- return 0;
- }
- void usnic_transport_unrsrv_port(enum usnic_transport_type type, u16 port_num)
- {
- if (type == USNIC_TRANSPORT_ROCE_CUSTOM) {
- spin_lock(&roce_bitmap_lock);
- if (!port_num) {
- usnic_err("Unreserved unvalid port num 0 for %s\n",
- usnic_transport_to_str(type));
- goto out_roce_custom;
- }
- if (!test_bit(port_num, roce_bitmap)) {
- usnic_err("Unreserving invalid %hu for %s\n",
- port_num,
- usnic_transport_to_str(type));
- goto out_roce_custom;
- }
- bitmap_clear(roce_bitmap, port_num, 1);
- usnic_dbg("Freeing port %hu for %s\n", port_num,
- usnic_transport_to_str(type));
- out_roce_custom:
- spin_unlock(&roce_bitmap_lock);
- } else {
- usnic_err("Freeing invalid port %hu for %d\n", port_num, type);
- }
- }
- struct socket *usnic_transport_get_socket(int sock_fd)
- {
- struct socket *sock;
- int err;
- char buf[25];
- /* sockfd_lookup will internally do a fget */
- sock = sockfd_lookup(sock_fd, &err);
- if (!sock) {
- usnic_err("Unable to lookup socket for fd %d with err %d\n",
- sock_fd, err);
- return ERR_PTR(-ENOENT);
- }
- usnic_transport_sock_to_str(buf, sizeof(buf), sock);
- usnic_dbg("Get sock %s\n", buf);
- return sock;
- }
- void usnic_transport_put_socket(struct socket *sock)
- {
- char buf[100];
- usnic_transport_sock_to_str(buf, sizeof(buf), sock);
- usnic_dbg("Put sock %s\n", buf);
- sockfd_put(sock);
- }
- int usnic_transport_sock_get_addr(struct socket *sock, int *proto,
- uint32_t *addr, uint16_t *port)
- {
- int len;
- int err;
- struct sockaddr_in sock_addr;
- err = sock->ops->getname(sock,
- (struct sockaddr *)&sock_addr,
- &len, 0);
- if (err)
- return err;
- if (sock_addr.sin_family != AF_INET)
- return -EINVAL;
- if (proto)
- *proto = sock->sk->sk_protocol;
- if (port)
- *port = ntohs(((struct sockaddr_in *)&sock_addr)->sin_port);
- if (addr)
- *addr = ntohl(((struct sockaddr_in *)
- &sock_addr)->sin_addr.s_addr);
- return 0;
- }
- int usnic_transport_init(void)
- {
- roce_bitmap = kzalloc(ROCE_BITMAP_SZ, GFP_KERNEL);
- if (!roce_bitmap) {
- usnic_err("Failed to allocate bit map");
- return -ENOMEM;
- }
- /* Do not ever allocate bit 0, hence set it here */
- bitmap_set(roce_bitmap, 0, 1);
- return 0;
- }
- void usnic_transport_fini(void)
- {
- kfree(roce_bitmap);
- }
|