Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

RDMA: Add netlink infrastructure

Add basic RDMA netlink infrastructure that allows for registration of
RDMA clients for which data is to be exported and supplies message
construction callbacks.

Signed-off-by: Nir Muchtar <nirm@voltaire.com>

[ Reorganize a few things, add CONFIG_NET dependency. - Roland ]

Signed-off-by: Roland Dreier <roland@purestorage.com>

+271 -4
+1
drivers/infiniband/Kconfig
··· 2 2 tristate "InfiniBand support" 3 3 depends on PCI || BROKEN 4 4 depends on HAS_IOMEM 5 + depends on NET 5 6 ---help--- 6 7 Core support for InfiniBand (IB). Make sure to also select 7 8 any protocols you wish to use as well as drivers for your
+1 -1
drivers/infiniband/core/Makefile
··· 8 8 $(user_access-y) 9 9 10 10 ib_core-y := packer.o ud_header.o verbs.o sysfs.o \ 11 - device.o fmr_pool.o cache.o 11 + device.o fmr_pool.o cache.o netlink.o 12 12 ib_core-$(CONFIG_INFINIBAND_USER_MEM) += umem.o 13 13 14 14 ib_mad-y := mad.o smi.o agent.o mad_rmpp.o
+13 -2
drivers/infiniband/core/device.c
··· 38 38 #include <linux/slab.h> 39 39 #include <linux/init.h> 40 40 #include <linux/mutex.h> 41 + #include <rdma/rdma_netlink.h> 41 42 42 43 #include "core_priv.h" 43 44 ··· 731 730 goto err; 732 731 } 733 732 734 - ret = ib_cache_setup(); 733 + ret = ibnl_init(); 735 734 if (ret) { 736 - printk(KERN_WARNING "Couldn't set up InfiniBand P_Key/GID cache\n"); 735 + printk(KERN_WARNING "Couldn't init IB netlink interface\n"); 737 736 goto err_sysfs; 738 737 } 739 738 739 + ret = ib_cache_setup(); 740 + if (ret) { 741 + printk(KERN_WARNING "Couldn't set up InfiniBand P_Key/GID cache\n"); 742 + goto err_nl; 743 + } 744 + 740 745 return 0; 746 + 747 + err_nl: 748 + ibnl_cleanup(); 741 749 742 750 err_sysfs: 743 751 ib_sysfs_cleanup(); ··· 759 749 static void __exit ib_core_cleanup(void) 760 750 { 761 751 ib_cache_cleanup(); 752 + ibnl_cleanup(); 762 753 ib_sysfs_cleanup(); 763 754 /* Make sure that any pending umem accounting work is done. */ 764 755 destroy_workqueue(ib_wq);
+190
drivers/infiniband/core/netlink.c
··· 1 + /* 2 + * Copyright (c) 2010 Voltaire Inc. 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 + #define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__ 34 + 35 + #include <net/netlink.h> 36 + #include <net/net_namespace.h> 37 + #include <net/sock.h> 38 + #include <rdma/rdma_netlink.h> 39 + 40 + struct ibnl_client { 41 + struct list_head list; 42 + int index; 43 + int nops; 44 + const struct ibnl_client_cbs *cb_table; 45 + }; 46 + 47 + static DEFINE_MUTEX(ibnl_mutex); 48 + static struct sock *nls; 49 + static LIST_HEAD(client_list); 50 + 51 + int ibnl_add_client(int index, int nops, 52 + const struct ibnl_client_cbs cb_table[]) 53 + { 54 + struct ibnl_client *cur; 55 + struct ibnl_client *nl_client; 56 + 57 + nl_client = kmalloc(sizeof *nl_client, GFP_KERNEL); 58 + if (!nl_client) 59 + return -ENOMEM; 60 + 61 + nl_client->index = index; 62 + nl_client->nops = nops; 63 + nl_client->cb_table = cb_table; 64 + 65 + mutex_lock(&ibnl_mutex); 66 + 67 + list_for_each_entry(cur, &client_list, list) { 68 + if (cur->index == index) { 69 + pr_warn("Client for %d already exists\n", index); 70 + mutex_unlock(&ibnl_mutex); 71 + kfree(nl_client); 72 + return -EINVAL; 73 + } 74 + } 75 + 76 + list_add_tail(&nl_client->list, &client_list); 77 + 78 + mutex_unlock(&ibnl_mutex); 79 + 80 + return 0; 81 + } 82 + EXPORT_SYMBOL(ibnl_add_client); 83 + 84 + int ibnl_remove_client(int index) 85 + { 86 + struct ibnl_client *cur, *next; 87 + 88 + mutex_lock(&ibnl_mutex); 89 + list_for_each_entry_safe(cur, next, &client_list, list) { 90 + if (cur->index == index) { 91 + list_del(&(cur->list)); 92 + mutex_unlock(&ibnl_mutex); 93 + kfree(cur); 94 + return 0; 95 + } 96 + } 97 + pr_warn("Can't remove callback for client idx %d. Not found\n", index); 98 + mutex_unlock(&ibnl_mutex); 99 + 100 + return -EINVAL; 101 + } 102 + EXPORT_SYMBOL(ibnl_remove_client); 103 + 104 + void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq, 105 + int len, int client, int op) 106 + { 107 + unsigned char *prev_tail; 108 + 109 + prev_tail = skb_tail_pointer(skb); 110 + *nlh = NLMSG_NEW(skb, 0, seq, RDMA_NL_GET_TYPE(client, op), 111 + len, NLM_F_MULTI); 112 + (*nlh)->nlmsg_len = skb_tail_pointer(skb) - prev_tail; 113 + return NLMSG_DATA(*nlh); 114 + 115 + nlmsg_failure: 116 + nlmsg_trim(skb, prev_tail); 117 + return NULL; 118 + } 119 + EXPORT_SYMBOL(ibnl_put_msg); 120 + 121 + int ibnl_put_attr(struct sk_buff *skb, struct nlmsghdr *nlh, 122 + int len, void *data, int type) 123 + { 124 + unsigned char *prev_tail; 125 + 126 + prev_tail = skb_tail_pointer(skb); 127 + NLA_PUT(skb, type, len, data); 128 + nlh->nlmsg_len += skb_tail_pointer(skb) - prev_tail; 129 + return 0; 130 + 131 + nla_put_failure: 132 + nlmsg_trim(skb, prev_tail - nlh->nlmsg_len); 133 + return -EMSGSIZE; 134 + } 135 + EXPORT_SYMBOL(ibnl_put_attr); 136 + 137 + static int ibnl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 138 + { 139 + struct ibnl_client *client; 140 + int type = nlh->nlmsg_type; 141 + int index = RDMA_NL_GET_CLIENT(type); 142 + int op = RDMA_NL_GET_OP(type); 143 + 144 + list_for_each_entry(client, &client_list, list) { 145 + if (client->index == index) { 146 + if (op < 0 || op >= client->nops || 147 + !client->cb_table[RDMA_NL_GET_OP(op)].dump) 148 + return -EINVAL; 149 + return netlink_dump_start(nls, skb, nlh, 150 + client->cb_table[op].dump, 151 + NULL); 152 + } 153 + } 154 + 155 + pr_info("Index %d wasn't found in client list\n", index); 156 + return -EINVAL; 157 + } 158 + 159 + static void ibnl_rcv(struct sk_buff *skb) 160 + { 161 + mutex_lock(&ibnl_mutex); 162 + netlink_rcv_skb(skb, &ibnl_rcv_msg); 163 + mutex_unlock(&ibnl_mutex); 164 + } 165 + 166 + int __init ibnl_init(void) 167 + { 168 + nls = netlink_kernel_create(&init_net, NETLINK_RDMA, 0, ibnl_rcv, 169 + NULL, THIS_MODULE); 170 + if (!nls) { 171 + pr_warn("Failed to create netlink socket\n"); 172 + return -ENOMEM; 173 + } 174 + 175 + return 0; 176 + } 177 + 178 + void ibnl_cleanup(void) 179 + { 180 + struct ibnl_client *cur, *next; 181 + 182 + mutex_lock(&ibnl_mutex); 183 + list_for_each_entry_safe(cur, next, &client_list, list) { 184 + list_del(&(cur->list)); 185 + kfree(cur); 186 + } 187 + mutex_unlock(&ibnl_mutex); 188 + 189 + netlink_kernel_release(nls); 190 + }
+1 -1
drivers/infiniband/hw/qib/Kconfig
··· 1 1 config INFINIBAND_QIB 2 2 tristate "QLogic PCIe HCA support" 3 - depends on 64BIT && NET 3 + depends on 64BIT 4 4 ---help--- 5 5 This is a low-level driver for QLogic PCIe QLE InfiniBand host 6 6 channel adapters. This driver does not support the QLogic
+1
include/linux/netlink.h
··· 24 24 /* leave room for NETLINK_DM (DM Events) */ 25 25 #define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */ 26 26 #define NETLINK_ECRYPTFS 19 27 + #define NETLINK_RDMA 20 27 28 28 29 #define MAX_LINKS 32 29 30
+64
include/rdma/rdma_netlink.h
··· 1 + #ifndef _RDMA_NETLINK_H 2 + #define _RDMA_NETLINK_H 3 + 4 + #define RDMA_NL_GET_CLIENT(type) ((type & (((1 << 6) - 1) << 10)) >> 10) 5 + #define RDMA_NL_GET_OP(type) (type & ((1 << 10) - 1)) 6 + #define RDMA_NL_GET_TYPE(client, op) ((client << 10) + op) 7 + 8 + #ifdef __KERNEL__ 9 + 10 + #include <linux/netlink.h> 11 + 12 + struct ibnl_client_cbs { 13 + int (*dump)(struct sk_buff *skb, struct netlink_callback *nlcb); 14 + }; 15 + 16 + int ibnl_init(void); 17 + void ibnl_cleanup(void); 18 + 19 + /** 20 + * Add a a client to the list of IB netlink exporters. 21 + * @index: Index of the added client 22 + * @nops: Number of supported ops by the added client. 23 + * @cb_table: A table for op->callback 24 + * 25 + * Returns 0 on success or a negative error code. 26 + */ 27 + int ibnl_add_client(int index, int nops, 28 + const struct ibnl_client_cbs cb_table[]); 29 + 30 + /** 31 + * Remove a client from IB netlink. 32 + * @index: Index of the removed IB client. 33 + * 34 + * Returns 0 on success or a negative error code. 35 + */ 36 + int ibnl_remove_client(int index); 37 + 38 + /** 39 + * Put a new message in a supplied skb. 40 + * @skb: The netlink skb. 41 + * @nlh: Pointer to put the header of the new netlink message. 42 + * @seq: The message sequence number. 43 + * @len: The requested message length to allocate. 44 + * @client: Calling IB netlink client. 45 + * @op: message content op. 46 + * Returns the allocated buffer on success and NULL on failure. 47 + */ 48 + void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq, 49 + int len, int client, int op); 50 + /** 51 + * Put a new attribute in a supplied skb. 52 + * @skb: The netlink skb. 53 + * @nlh: Header of the netlink message to append the attribute to. 54 + * @len: The length of the attribute data. 55 + * @data: The attribute data to put. 56 + * @type: The attribute type. 57 + * Returns the 0 and a negative error code on failure. 58 + */ 59 + int ibnl_put_attr(struct sk_buff *skb, struct nlmsghdr *nlh, 60 + int len, void *data, int type); 61 + 62 + #endif /* __KERNEL__ */ 63 + 64 + #endif /* _RDMA_NETLINK_H */