From patchwork Sat Aug 31 19:47:18 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Nikolova, Tatyana E" X-Patchwork-Id: 2852429 Return-Path: X-Original-To: patchwork-linux-rdma@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 874BD9F2F4 for ; Sat, 31 Aug 2013 19:47:35 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 84999202C0 for ; Sat, 31 Aug 2013 19:47:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id B611B202CC for ; Sat, 31 Aug 2013 19:47:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756822Ab3HaTr0 (ORCPT ); Sat, 31 Aug 2013 15:47:26 -0400 Received: from mga03.intel.com ([143.182.124.21]:23931 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756817Ab3HaTrY (ORCPT ); Sat, 31 Aug 2013 15:47:24 -0400 Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by azsmga101.ch.intel.com with ESMTP; 31 Aug 2013 12:47:23 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.89,998,1367996400"; d="scan'208";a="389355497" Received: from tenikolo-mobl1.amr.corp.intel.com (HELO tenikolo-mobl1) ([10.255.39.207]) by fmsmga001.fm.intel.com with SMTP; 31 Aug 2013 12:47:20 -0700 Received: by tenikolo-mobl1 (sSMTP sendmail emulation); Sat, 31 Aug 2013 14:47:18 -0500 Date: Sat, 31 Aug 2013 14:47:18 -0500 From: Tatyana Nikolova To: Roland Dreier Cc: robert.o.sharp@intel.com, john.s.lacombe@intel.com, vipul@chelsio.com, swise@opengridcomputing.com, linux-rdma@vger.kernel.org Subject: [PATCH 4/4] RDMA/cxgb4: Add support for iWARP Port Mapper user space service Message-ID: <20130831194718.GA7552@TENIKOLO-MOBL1> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-12-10) Sender: linux-rdma-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-rdma@vger.kernel.org X-Spam-Status: No, score=-9.4 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add support for iWARP Port Mapper (IWPM) user space service Signed-off-by: Vipul Pandya --- drivers/infiniband/hw/cxgb4/Makefile | 2 +- drivers/infiniband/hw/cxgb4/c4iw_netlink.c | 1021 ++++++++++++++++++++++++++++ drivers/infiniband/hw/cxgb4/c4iw_netlink.h | 273 ++++++++ drivers/infiniband/hw/cxgb4/cm.c | 138 ++++- drivers/infiniband/hw/cxgb4/device.c | 24 +- drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 16 + 6 files changed, 1448 insertions(+), 26 deletions(-) create mode 100644 drivers/infiniband/hw/cxgb4/c4iw_netlink.c create mode 100644 drivers/infiniband/hw/cxgb4/c4iw_netlink.h diff --git a/drivers/infiniband/hw/cxgb4/Makefile b/drivers/infiniband/hw/cxgb4/Makefile index e11cf72..7e4d948 100644 --- a/drivers/infiniband/hw/cxgb4/Makefile +++ b/drivers/infiniband/hw/cxgb4/Makefile @@ -2,4 +2,4 @@ ccflags-y := -Idrivers/net/ethernet/chelsio/cxgb4 obj-$(CONFIG_INFINIBAND_CXGB4) += iw_cxgb4.o -iw_cxgb4-y := device.o cm.o provider.o mem.o cq.o qp.o resource.o ev.o id_table.o +iw_cxgb4-y := device.o cm.o provider.o mem.o cq.o qp.o resource.o ev.o id_table.o c4iw_netlink.o diff --git a/drivers/infiniband/hw/cxgb4/c4iw_netlink.c b/drivers/infiniband/hw/cxgb4/c4iw_netlink.c new file mode 100644 index 0000000..001c0e3 --- /dev/null +++ b/drivers/infiniband/hw/cxgb4/c4iw_netlink.c @@ -0,0 +1,1021 @@ +/* + * Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iw_cxgb4.h" +#include "c4iw_netlink.h" + +spinlock_t c4iw_nlmsg_lock; +struct list_head c4iw_nlmsg_request_list; +struct list_head c4iw_mapping_info_list; +spinlock_t c4iw_mapping_lock; +atomic_t c4iw_nlmsg_seq; +atomic_t echo_nlmsg_seq; + +int c4iw_iwpm_pid = C4IW_IWPM_PID_UNDEFINED; +static char iwpm_ulib_name[] = "iWarpPortMapperUser"; +static int iwpm_ulib_version = 3; + +static char c4iw_ifname[IWPM_IFNAME_SIZE]; +static char c4iw_ibdev[IWPM_DEVNAME_SIZE]; + +static struct c4iw_nlmsg_request *c4iw_get_nlmsg_request(void); +static int c4iw_send_mapping_info(void); +static int c4iw_send_mapping_count(u32); +static int c4iw_parse_nlmsg(struct netlink_callback *, int, + const struct nla_policy *, struct nlattr *[], + const char *); + +/* c4iw netlink callbacks */ +static int c4iw_register_iwpm_pid_cb(struct sk_buff *, + struct netlink_callback *); +static int c4iw_add_mapping_cb(struct sk_buff *, struct netlink_callback *); +static int c4iw_add_and_query_mapping_cb(struct sk_buff *, + struct netlink_callback *); +static int c4iw_mapping_error_cb(struct sk_buff *, struct netlink_callback *); +static int c4iw_mapping_info_cb(struct sk_buff *, struct netlink_callback *); +static int c4iw_ack_mapping_info_cb(struct sk_buff *, + struct netlink_callback *); + +static struct c4iw_nlmsg_request *c4iw_get_nlmsg_request(void) +{ + unsigned long flags; + struct c4iw_nlmsg_request *nlmsg_request = NULL; + + nlmsg_request = kzalloc(sizeof(struct c4iw_nlmsg_request), GFP_ATOMIC); + if (!nlmsg_request) { + pr_err("%s Unable to allocate a nlmsg_request\n", __func__); + return NULL; + } + spin_lock_irqsave(&c4iw_nlmsg_lock, flags); + list_add_tail(&nlmsg_request->inprocess_list, &c4iw_nlmsg_request_list); + spin_unlock_irqrestore(&c4iw_nlmsg_lock, flags); + + atomic_set(&nlmsg_request->refcount, 1); + nlmsg_request->nlmsg_seq = atomic_inc_return(&c4iw_nlmsg_seq); + nlmsg_request->request_done = 0; + nlmsg_request->async = 0; + nlmsg_request->err_code = 0; + return nlmsg_request; +} + +static int c4iw_parse_nlmsg(struct netlink_callback *cb, int policy_max, + const struct nla_policy *nlmsg_policy, + struct nlattr *nltb[], const char *msg_type) +{ + int nlh_len = 0; + int ret; + const char *err_str = ""; + + ret = nlmsg_validate(cb->nlh, nlh_len, policy_max-1, nlmsg_policy); + if (ret) { + err_str = "Invalid attribute"; + goto parse_nlmsg_error; + } + ret = nlmsg_parse(cb->nlh, nlh_len, nltb, policy_max-1, nlmsg_policy); + if (ret) { + err_str = "Unable to parse the nlmsg"; + goto parse_nlmsg_error; + } + ret = c4iw_validate_nlmsg_attr(nltb, policy_max); + if (ret) { + err_str = "Invalid NULL attribute"; + goto parse_nlmsg_error; + } + return 0; +parse_nlmsg_error: + pr_warn("%s %s (msg type %s ret = %d)\n", + __func__, err_str, msg_type, ret); + return ret; +} + +static void c4iw_nlmsg_req_timer_free(unsigned long data) +{ + struct c4iw_nlmsg_request *nlmsg_request = (struct c4iw_nlmsg_request *) + data; + + if (!nlmsg_request->request_done && !nlmsg_request->err_code) + c4iw_iwpm_pid = C4IW_IWPM_PID_UNAVAILABLE; + + if (c4iw_iwpm_pid < 0) + pr_info("%s Port Mapper isn't available (err code = %d)\n" + , __func__, nlmsg_request->err_code); + rem_ref_nlmsg_request(nlmsg_request); +} + +static void c4iw_mapinfo_timer_send(unsigned long data) +{ + int mapping_num; + + c4iw_nlmsg_req_timer_free(data); + + if (c4iw_iwpm_pid < 0) + return; + mapping_num = c4iw_send_mapping_info(); + if (mapping_num < 0) { + pr_info("%s Unable to send mapping info\n", __func__); + return; + } + PDBG("%s Sending Mapping count msg (num = %d)\n", __func__ + , mapping_num); + + c4iw_send_mapping_count(mapping_num); +} + +static void c4iw_start_nlmsg_req_timer(struct c4iw_nlmsg_request *nlmsg_request, + void (*timer_func)(unsigned long), + u32 delay) +{ + init_timer(&nlmsg_request->service_timer); + setup_timer(&nlmsg_request->service_timer, timer_func, + (unsigned long) nlmsg_request); + mod_timer(&nlmsg_request->service_timer, jiffies + delay); +} + +/* + * Send a netlink query for the iwarp port mapper pid to the userspace + * nlmsg attributes: + * [IWPM_NLA_REG_PID_SEQ] + * [IWPM_NLA_REG_IF_NAME] + * [IWPM_NLA_REG_IBDEV_NAME] + * [IWPM_NLA_REG_ULIB_NAME] + */ +int c4iw_register_iwpm_pid(char *netdev_name, char *dev_name, int async, + void (*req_timer_func)(unsigned long)) +{ + struct sk_buff *skb = NULL; + struct c4iw_nlmsg_request *nlmsg_request = NULL; + struct nlmsghdr *nlh; + struct nlmsghdr **nlh_next = &nlh; + u32 msg_seq; + const char *err_str = ""; + int ret = -ENOMEM; + + skb = c4iw_create_nlmsg(RDMA_NL_IWPM_REG_PID, nlh_next); + if (!skb) { + err_str = "Unable to create a nlmsg"; + goto pid_query_error; + } + nlmsg_request = c4iw_get_nlmsg_request(); + if (!nlmsg_request) { + err_str = "Unable to allocate netlink request"; + goto pid_query_error; + } + msg_seq = atomic_read(&echo_nlmsg_seq); + + /* fill in the pid request message */ + nlh->nlmsg_seq = nlmsg_request->nlmsg_seq; + err_str = "Unable to put attribute of the nlmsg"; + ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, + IWPM_NLA_REG_PID_SEQ); + if (ret) + goto pid_query_error; + ret = ibnl_put_attr(skb, nlh, IWPM_IFNAME_SIZE, netdev_name, + IWPM_NLA_REG_IF_NAME); + if (ret) + goto pid_query_error; + ret = ibnl_put_attr(skb, nlh, IWPM_DEVNAME_SIZE, dev_name, + IWPM_NLA_REG_IBDEV_NAME); + if (ret) + goto pid_query_error; + ret = ibnl_put_attr(skb, nlh, IWPM_ULIBNAME_SIZE, iwpm_ulib_name, + IWPM_NLA_REG_ULIB_NAME); + if (ret) + goto pid_query_error; + memcpy(c4iw_ibdev, dev_name, IWPM_DEVNAME_SIZE); + memcpy(c4iw_ifname, netdev_name, IWPM_IFNAME_SIZE); + PDBG("%s Multicasting a nlmsg (echo seq = %u ibdevname = %s ifname = %s iwpm ulib name = %s) nlmsg len = %d request seq = %u\n" + , __func__, msg_seq, dev_name, netdev_name, iwpm_ulib_name + , nlh->nlmsg_len, nlmsg_request->nlmsg_seq); + + ret = ibnl_multicast(skb, nlh, RDMA_NL_GROUP_IWPM, GFP_KERNEL); + if (ret) { + skb = NULL; /* already freed in the netlink send-op handling */ + err_str = "Unable to send a nlmsg"; + goto pid_query_error; + } + nlmsg_request->async = async; + if (async) + c4iw_start_nlmsg_req_timer(nlmsg_request, req_timer_func, + C4IW_IWPM_NL_TIMEOUT); + else + ret = wait_complete_nlmsg_req(nlmsg_request, + C4IW_IWPM_PID_UNAVAILABLE); + return ret; +pid_query_error: + pr_warn("%s %s\n", __func__, err_str); + if (skb) + dev_kfree_skb(skb); + if (nlmsg_request) + free_nlmsg_request(nlmsg_request); + return ret; +} + +/* + * Send a netlink add mapping request + * for the listener ip/tcp address to the userspace port mapper + * nlmsg attributes: + * [IWPM_NLA_MANAGE_MAPPING_SEQ] + * [IWPM_NLA_MANAGE_ADDR] + */ +int c4iw_add_mapping(struct c4iw_listen_ep *ep) +{ + struct sk_buff *skb = NULL; + struct c4iw_nlmsg_request *nlmsg_request = NULL; + struct nlmsghdr *nlh; + struct nlmsghdr **nlh_next = &nlh; + u32 msg_seq; + struct sockaddr_in *laddr = (struct sockaddr_in *) + &ep->com.local_addr; + struct sockaddr_in6 *laddr6 = (struct sockaddr_in6 *) + &ep->com.local_addr; + const char *err_str = ""; + int ret = -ENOMEM; + + skb = c4iw_create_nlmsg(RDMA_NL_IWPM_ADD_MAPPING, nlh_next); + if (!skb) { + err_str = "Unable to create a nlmsg"; + goto add_mapping_error; + } + + nlmsg_request = c4iw_get_nlmsg_request(); + if (!nlmsg_request) { + err_str = "Unable to allocate netlink request"; + goto add_mapping_error; + } + + msg_seq = atomic_read(&echo_nlmsg_seq); + + /* fill in the add mapping message */ + nlh->nlmsg_seq = nlmsg_request->nlmsg_seq; + err_str = "Unable to put attribute of the nlmsg"; + ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, + IWPM_NLA_MANAGE_MAPPING_SEQ); + if (ret) + goto add_mapping_error; + ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage), + &ep->com.local_addr, IWPM_NLA_MANAGE_ADDR); + if (ret) + goto add_mapping_error; + + nlmsg_request->request_buffer = ep; + if (ep->com.local_addr.ss_family == AF_INET) + PDBG("%s Send a nlmsg (echo seq = %u, Local addr %pI4 [0x%04X]) request seq = %u\n" + , __func__, msg_seq, &laddr->sin_addr.s_addr + , ntohs(laddr->sin_port), nlmsg_request->nlmsg_seq); + else + PDBG("%s Send a nlmsg (echo seq = %u, Local addr %pI6 [0x%04X]) request seq = %u\n" + , __func__, msg_seq, &laddr6->sin6_addr.s6_addr + , ntohs(laddr6->sin6_port), nlmsg_request->nlmsg_seq); + + ret = ibnl_unicast(skb, nlh, c4iw_iwpm_pid); + if (ret) { + c4iw_iwpm_pid = C4IW_IWPM_PID_UNDEFINED; /* ret = -111 */ + skb = NULL; /* already freed in the netlink send-op handling */ + err_str = "Unable to send a nlmsg"; + goto add_mapping_error; + } + ret = wait_complete_nlmsg_req(nlmsg_request, C4IW_IWPM_PID_UNDEFINED); + return ret; +add_mapping_error: + pr_warn("%s %s\n", __func__, err_str); + if (skb) + dev_kfree_skb(skb); + if (nlmsg_request) + free_nlmsg_request(nlmsg_request); + return ret; +} + +/* + * Send both a netlink add mapping request for the connecting + * side ip/tcp address and a query for the accepting remote peer + * mapped ip/tcp address to the userspace port mapper + * nlmsg attributes: + * [IWPM_NLA_QUERY_MAPPING_SEQ] + * [IWPM_NLA_QUERY_LOCAL_ADDR] + * [IWPM_NLA_QUERY_REMOTE_ADDR] + */ +int c4iw_add_and_query_mapping(struct c4iw_ep *ep) +{ + struct sk_buff *skb = NULL; + struct c4iw_nlmsg_request *nlmsg_request = NULL; + struct nlmsghdr *nlh; + struct nlmsghdr **nlh_next = &nlh; + u32 msg_seq; + struct sockaddr_in *laddr = (struct sockaddr_in *) + &ep->com.local_addr; + struct sockaddr_in6 *laddr6 = (struct sockaddr_in6 *) + &ep->com.local_addr; + struct sockaddr_in *raddr = (struct sockaddr_in *) + &ep->com.remote_addr; + struct sockaddr_in6 *raddr6 = (struct sockaddr_in6 *) + &ep->com.remote_addr; + const char *err_str = ""; + int ret = -ENOMEM; + + skb = c4iw_create_nlmsg(RDMA_NL_IWPM_QUERY_MAPPING, nlh_next); + if (!skb) { + err_str = "Unable to create a nlmsg"; + goto query_mapping_error; + } + nlmsg_request = c4iw_get_nlmsg_request(); + if (!nlmsg_request) { + err_str = "Unable to allocate netlink request"; + goto query_mapping_error; + } + + msg_seq = atomic_read(&echo_nlmsg_seq); + /* fill in the query message */ + nlh->nlmsg_seq = nlmsg_request->nlmsg_seq; + err_str = "Unable to put attribute of the nlmsg"; + ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, + IWPM_NLA_QUERY_MAPPING_SEQ); + if (ret) + goto query_mapping_error; + ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage), + &ep->com.local_addr, + IWPM_NLA_QUERY_LOCAL_ADDR); + if (ret) + goto query_mapping_error; + ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage), + &ep->com.remote_addr, + IWPM_NLA_QUERY_REMOTE_ADDR); + if (ret) + goto query_mapping_error; + + nlmsg_request->request_buffer = ep; + if (ep->com.local_addr.ss_family == AF_INET) + PDBG("%s Send a nlmsg (echo seq = %u, Local addr %pI4 [0x%04X]) Remote addr %pI4 [0x%04X]) request seq = %u\n" + , __func__, msg_seq, &laddr->sin_addr.s_addr + , ntohs(laddr->sin_port), &raddr->sin_addr.s_addr + , ntohs(raddr->sin_port), nlmsg_request->nlmsg_seq); + else + PDBG("%s Send a nlmsg (echo seq = %u, Local addr %pI6 [0x%04X]) Remote addr %pI6 [0x%04X]) request seq = %u\n" + , __func__, msg_seq, &laddr6->sin6_addr.s6_addr + , ntohs(laddr6->sin6_port), &raddr6->sin6_addr.s6_addr + , ntohs(raddr6->sin6_port), nlmsg_request->nlmsg_seq); + + ret = ibnl_unicast(skb, nlh, c4iw_iwpm_pid); + if (ret) { + c4iw_iwpm_pid = C4IW_IWPM_PID_UNDEFINED; + skb = NULL; /* already freed in the netlink send-op handling */ + err_str = "Unable to send a nlmsg"; + goto query_mapping_error; + } + ret = wait_complete_nlmsg_req(nlmsg_request, C4IW_IWPM_PID_UNDEFINED); + return ret; +query_mapping_error: + pr_warn("%s %s\n", __func__, err_str); + if (skb) + dev_kfree_skb(skb); + if (nlmsg_request) + free_nlmsg_request(nlmsg_request); + return ret; +} + +/* + * Send a netlink remove mapping request to the userspace port mapper + * nlmsg attributes: + * [IWPM_NLA_MANAGE_MAPPING_SEQ] + * [IWPM_NLA_MANAGE_ADDR] + */ +int c4iw_remove_mapping(struct sockaddr_storage *mapped_local_addr) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + struct nlmsghdr **nlh_next = &nlh; + u32 msg_seq; + struct sockaddr_in *mapped_la = (struct sockaddr_in *) + mapped_local_addr; + struct sockaddr_in6 *mapped_la6 = (struct sockaddr_in6 *) + mapped_local_addr; + const char *err_str = ""; + int ret; + + if (c4iw_remove_mapinfo(mapped_local_addr)) { + if (mapped_local_addr->ss_family == AF_INET) + pr_warn("%s Fail to remove mapinfo (port = 0x%04X).\n" + , __func__, ntohs(mapped_la->sin_port)); + else + pr_warn("%s Fail to remove mapinfo (port = 0x%04X).\n" + , __func__, ntohs(mapped_la6->sin6_port)); + return -EINVAL; + } + if (c4iw_iwpm_pid < 0) + return 0; + + skb = c4iw_create_nlmsg(RDMA_NL_IWPM_REMOVE_MAPPING, nlh_next); + if (!skb) { + ret = -ENOMEM; + err_str = "Unable to create a nlmsg"; + goto remove_mapping_error; + } + msg_seq = atomic_read(&echo_nlmsg_seq); + + nlh->nlmsg_seq = atomic_inc_return(&c4iw_nlmsg_seq); + err_str = "Unable to put attribute of the nlmsg"; + ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, + IWPM_NLA_MANAGE_MAPPING_SEQ); + if (ret) + goto remove_mapping_error; + ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage), + mapped_local_addr, IWPM_NLA_MANAGE_ADDR); + if (ret) + goto remove_mapping_error; + + if (mapped_local_addr->ss_family == AF_INET) + PDBG("%s Send a nlmsg (echo seq = %u, Mapped local addr %pI4 [0x%04X])\n" + , __func__, msg_seq, &mapped_la->sin_addr.s_addr + , ntohs(mapped_la->sin_port)); + else + PDBG("%s Send a nlmsg (echo seq = %u, Mapped local addr %pI6 [0x%04X])\n" + , __func__, msg_seq, mapped_la6->sin6_addr.s6_addr + , ntohs(mapped_la6->sin6_port)); + + ret = ibnl_unicast(skb, nlh, c4iw_iwpm_pid); + if (ret) { + c4iw_iwpm_pid = C4IW_IWPM_PID_UNDEFINED; + skb = NULL; + err_str = "Unable to send a nlmsg"; + goto remove_mapping_error; + } + return 0; +remove_mapping_error: + pr_warn("%s %s\n", __func__, err_str); + if (skb) + dev_kfree_skb(skb); + return ret; +} + +/* registered netlink c4iw callbacks */ +struct ibnl_client_cbs c4iw_nl_cb_table[] = { + [RDMA_NL_IWPM_REG_PID] = {.dump = c4iw_register_iwpm_pid_cb}, + [RDMA_NL_IWPM_ADD_MAPPING] = {.dump = c4iw_add_mapping_cb}, + [RDMA_NL_IWPM_QUERY_MAPPING] = {.dump = c4iw_add_and_query_mapping_cb}, + [RDMA_NL_IWPM_HANDLE_ERR] = {.dump = c4iw_mapping_error_cb}, + [RDMA_NL_IWPM_MAP_INFO] = {.dump = c4iw_mapping_info_cb}, + [RDMA_NL_IWPM_MAP_INFO_NUM] = {.dump = c4iw_ack_mapping_info_cb} +}; + +static const struct nla_policy resp_reg_policy[IWPM_NLA_RREG_PID_MAX] = { + [IWPM_NLA_RREG_PID_SEQ] = { .type = NLA_U32 }, + [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_STRING, + .len = IWPM_DEVNAME_SIZE - 1 }, + [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_STRING, + .len = IWPM_ULIBNAME_SIZE - 1 }, + [IWPM_NLA_RREG_ULIB_VER] = { .type = NLA_U16 }, + [IWPM_NLA_RREG_PID_ERR] = { .type = NLA_U16 } +}; + +static int c4iw_register_iwpm_pid_cb(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct c4iw_nlmsg_request *nlmsg_request = NULL; + struct nlattr *nltb[IWPM_NLA_RREG_PID_MAX]; + char *dev_name, *iwpm_name; + u32 msg_seq; + u16 iwpm_version; + const char *msg_type = "Register Pid response"; + + c4iw_iwpm_pid = C4IW_IWPM_PID_ERROR; + + if (c4iw_parse_nlmsg(cb, IWPM_NLA_RREG_PID_MAX, resp_reg_policy, + nltb, msg_type)) + return -EINVAL; + + msg_seq = nla_get_u32(nltb[IWPM_NLA_RREG_PID_SEQ]); + nlmsg_request = c4iw_find_nlmsg_request(msg_seq); + if (!nlmsg_request) { + pr_warn("%s Could not find a matching request (seq = %u)\n" + , __func__, msg_seq); + return -EINVAL; + } + dev_name = (char *)nla_data(nltb[IWPM_NLA_RREG_IBDEV_NAME]); + iwpm_name = (char *)nla_data(nltb[IWPM_NLA_RREG_ULIB_NAME]); + iwpm_version = nla_get_u16(nltb[IWPM_NLA_RREG_ULIB_VER]); + + /* check device name, ulib name and version */ + if (strcmp(c4iw_ibdev, dev_name) || strcmp(iwpm_ulib_name, iwpm_name) || + iwpm_version != iwpm_ulib_version) { + pr_info("%s Incorrect info (dev = %s name = %s version = %d)\n" + , __func__, dev_name, iwpm_name, iwpm_version); + nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR; + goto register_pid_response_exit; + } + PDBG("%s Received info (dev = %s name = %s version = %d) request seq = %u\n" + , __func__, dev_name, iwpm_name, iwpm_version + , nlmsg_request->nlmsg_seq); + + c4iw_iwpm_pid = cb->nlh->nlmsg_pid; + atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq); + pr_info("%s iWarp Port Mapper (pid = %d) is successfully registered.\n" + , __func__, c4iw_iwpm_pid); +register_pid_response_exit: + nlmsg_request->request_done = 1; + /* always for found nlmsg_request */ + rem_ref_nlmsg_request(nlmsg_request); + barrier(); + if (!nlmsg_request->async) + wake_up(&nlmsg_request->waitq); + return 0; +} + +static const struct nla_policy resp_add_policy[IWPM_NLA_RMANAGE_MAPPING_MAX] = { + [IWPM_NLA_MANAGE_MAPPING_SEQ] = { .type = NLA_U32 }, + [IWPM_NLA_MANAGE_ADDR] = { + .len = sizeof(struct sockaddr_storage) }, + [IWPM_NLA_MANAGE_MAPPED_LOC_ADDR] = { + .len = sizeof(struct sockaddr_storage) }, + [IWPM_NLA_RMANAGE_MAPPING_ERR] = { .type = NLA_U16 } +}; + +static int c4iw_add_mapping_cb(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct c4iw_listen_ep *ep; + struct c4iw_nlmsg_request *nlmsg_request = NULL; + struct nlattr *nltb[IWPM_NLA_RMANAGE_MAPPING_MAX]; + u32 msg_seq; + struct sockaddr_storage *local_sockaddr, *mapped_sockaddr; + const char *msg_type; + + msg_type = "Add Mapping response"; + if (c4iw_parse_nlmsg(cb, IWPM_NLA_RMANAGE_MAPPING_MAX, resp_add_policy, + nltb, msg_type)) + return -EINVAL; + + msg_seq = nla_get_u32(nltb[IWPM_NLA_MANAGE_MAPPING_SEQ]); + nlmsg_request = c4iw_find_nlmsg_request(msg_seq); + if (!nlmsg_request) { + pr_warn("%s Could not find a matching request (seq = %u)\n" + , __func__, msg_seq); + return -EINVAL; + } + ep = nlmsg_request->request_buffer; + local_sockaddr = (struct sockaddr_storage *) + nla_data(nltb[IWPM_NLA_MANAGE_ADDR]); + mapped_sockaddr = (struct sockaddr_storage *) + nla_data(nltb[IWPM_NLA_MANAGE_MAPPED_LOC_ADDR]); + + if (memcmp(&ep->com.local_addr, local_sockaddr, + sizeof(ep->com.local_addr))) { + print_addr(&ep->com.local_addr, + "Invalid ip/tcp address Local: expected"); + print_addr(local_sockaddr, + "Invalid ip/tcp address Local: received"); + nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR; + goto add_mapping_response_exit; + } + + atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq); + memcpy(&ep->com.mapped_local_addr, mapped_sockaddr, + sizeof(ep->com.mapped_local_addr)); +add_mapping_response_exit: + print_addr(mapped_sockaddr, "Received a new mapping mapped local"); + nlmsg_request->request_done = 1; + /* always for found nlmsg_request */ + rem_ref_nlmsg_request(nlmsg_request); + barrier(); + wake_up(&nlmsg_request->waitq); + return 0; +} + +static const struct nla_policy + resp_query_policy[IWPM_NLA_RQUERY_MAPPING_MAX] = { + [IWPM_NLA_QUERY_MAPPING_SEQ] = { .type = NLA_U32 }, + [IWPM_NLA_QUERY_LOCAL_ADDR] = { + .len = sizeof(struct sockaddr_storage) }, + [IWPM_NLA_QUERY_REMOTE_ADDR] = { + .len = sizeof(struct sockaddr_storage) }, + [IWPM_NLA_RQUERY_MAPPED_LOC_ADDR] = { + .len = sizeof(struct sockaddr_storage) }, + [IWPM_NLA_RQUERY_MAPPED_REM_ADDR] = { + .len = sizeof(struct sockaddr_storage) }, + [IWPM_NLA_RQUERY_MAPPING_ERR] = { .type = NLA_U16 } +}; + +static int c4iw_add_and_query_mapping_cb(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct c4iw_ep *ep; + struct c4iw_nlmsg_request *nlmsg_request = NULL; + struct nlattr *nltb[IWPM_NLA_RQUERY_MAPPING_MAX]; + u32 msg_seq; + struct sockaddr_storage *local_sockaddr, *remote_sockaddr; + struct sockaddr_storage *mapped_loc_sockaddr, *mapped_rem_sockaddr; + struct sockaddr_in *laddr; + struct sockaddr_in6 *laddr6; + struct sockaddr_in *raddr; + struct sockaddr_in6 *raddr6; + struct sockaddr_in *map_laddr; + struct sockaddr_in6 *map_laddr6; + struct sockaddr_in *map_raddr; + struct sockaddr_in6 *map_raddr6; + const char *msg_type; + u16 err_code; + + msg_type = "Query Mapping response"; + if (c4iw_parse_nlmsg(cb, IWPM_NLA_RQUERY_MAPPING_MAX, + resp_query_policy, nltb, msg_type)) + return -EINVAL; + msg_seq = nla_get_u32(nltb[IWPM_NLA_QUERY_MAPPING_SEQ]); + nlmsg_request = c4iw_find_nlmsg_request(msg_seq); + if (!nlmsg_request) { + pr_warn("%s Could not find a matching request (seq = %u)\n" + , __func__, msg_seq); + return -EINVAL; + } + ep = nlmsg_request->request_buffer; + local_sockaddr = (struct sockaddr_storage *) + nla_data(nltb[IWPM_NLA_QUERY_LOCAL_ADDR]); + remote_sockaddr = (struct sockaddr_storage *) + nla_data(nltb[IWPM_NLA_QUERY_REMOTE_ADDR]); + mapped_loc_sockaddr = (struct sockaddr_storage *) + nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_LOC_ADDR]); + mapped_rem_sockaddr = (struct sockaddr_storage *) + nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_REM_ADDR]); + map_laddr = (struct sockaddr_in *)mapped_loc_sockaddr; + map_laddr6 = (struct sockaddr_in6 *)mapped_loc_sockaddr; + map_raddr = (struct sockaddr_in *)mapped_rem_sockaddr; + map_raddr6 = (struct sockaddr_in6 *) mapped_rem_sockaddr; + laddr = (struct sockaddr_in *)&ep->com.mapped_local_addr; + laddr6 = (struct sockaddr_in6 *)&ep->com.mapped_local_addr; + raddr = (struct sockaddr_in *)&ep->com.mapped_remote_addr; + raddr6 = (struct sockaddr_in6 *)&ep->com.mapped_remote_addr; + + err_code = nla_get_u16(nltb[IWPM_NLA_RQUERY_MAPPING_ERR]); + if (err_code == IWPM_REMOTE_QUERY_REJECT) { + pr_info("%s Received a Query Reject nlmsg. nlmsg (pid = %u, seq = %u) echo seq = %u.\n" + , __func__, cb->nlh->nlmsg_pid, cb->nlh->nlmsg_seq + , msg_seq); + nlmsg_request->err_code = IWPM_REMOTE_QUERY_REJECT; + } + if (memcmp(&ep->com.local_addr, local_sockaddr, + sizeof(ep->com.local_addr) != 0) || + memcmp(&ep->com.remote_addr, remote_sockaddr, + sizeof(ep->com.remote_addr) != 0)) { + print_addr(&ep->com.local_addr, + "Invalid ip/tcp address Local: expected"); + print_addr(local_sockaddr, + "Invalid ip/tcp address Local: received"); + print_addr(&ep->com.remote_addr, + "Invalid ip/tcp address Remote: expected"); + print_addr(remote_sockaddr, + "Invalid ip/tcp address Remote: received"); + nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR; + goto query_mapping_response_exit; + } + + atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq); + if (ep->com.local_addr.ss_family == AF_INET) { + laddr->sin_addr.s_addr = map_laddr->sin_addr.s_addr, + laddr->sin_port = map_laddr->sin_port; + raddr->sin_addr.s_addr = map_raddr->sin_addr.s_addr, + raddr->sin_port = map_raddr->sin_port; + } else { + memcpy(laddr6->sin6_addr.s6_addr, map_laddr6->sin6_addr.s6_addr, + IWPM_IPADDR_SIZE); + laddr6->sin6_port = map_laddr6->sin6_port; + memcpy(raddr6->sin6_addr.s6_addr, map_raddr6->sin6_addr.s6_addr, + IWPM_IPADDR_SIZE); + raddr6->sin6_port = map_raddr6->sin6_port; + } +query_mapping_response_exit: + print_addr(mapped_loc_sockaddr, "Received a new mapping mapped local"); + print_addr(mapped_rem_sockaddr, "Received a new mapping mapped remote"); + nlmsg_request->request_done = 1; + /* always for found nlmsg_request */ + rem_ref_nlmsg_request(nlmsg_request); + barrier(); + wake_up(&nlmsg_request->waitq); + return 0; +} + +static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = { + [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_STRING, + .len = IWPM_ULIBNAME_SIZE - 1 }, + [IWPM_NLA_MAPINFO_ULIB_VER] = { .type = NLA_U16 } +}; + +static int c4iw_mapping_info_cb(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct nlattr *nltb[IWPM_NLA_MAPINFO_REQ_MAX]; + char *iwpm_name; + u16 iwpm_version; + const char *msg_type = "Mapping Info response"; + void (*req_timer_func)(unsigned long) = NULL; + int async = 1; + + if (c4iw_parse_nlmsg(cb, IWPM_NLA_MAPINFO_REQ_MAX, resp_mapinfo_policy, + nltb, msg_type)) + return -EINVAL; + + iwpm_name = (char *)nla_data(nltb[IWPM_NLA_MAPINFO_ULIB_NAME]); + iwpm_version = nla_get_u16(nltb[IWPM_NLA_MAPINFO_ULIB_VER]); + if (strcmp(iwpm_ulib_name, iwpm_name) || + iwpm_version != iwpm_ulib_version) { + pr_info("%s Invalid iWarpPortMapper info (name = %s version = %d)\n" + , __func__, iwpm_name, iwpm_version); + return -EINVAL; + } + if (list_empty(&c4iw_mapping_info_list)) + req_timer_func = &c4iw_nlmsg_req_timer_free; + else + req_timer_func = &c4iw_mapinfo_timer_send; + + c4iw_register_iwpm_pid(c4iw_ifname, c4iw_ibdev, async, req_timer_func); + return 0; +} + +static int c4iw_send_mapping_count(u32 mapping_num) +{ + struct c4iw_nlmsg_request *nlmsg_request = NULL; + struct sk_buff *skb = NULL; + struct nlmsghdr *nlh; + struct nlmsghdr **nlh_next = &nlh; + u32 msg_seq; + const char *err_str = ""; + int ret = -EINVAL; + + skb = c4iw_create_nlmsg(RDMA_NL_IWPM_MAP_INFO_NUM, nlh_next); + if (!skb) { + err_str = "Unable to create a nlmsg"; + goto mapping_count_exit; + } + nlmsg_request = c4iw_get_nlmsg_request(); + if (!nlmsg_request) { + err_str = "Unable to allocate netlink request"; + goto mapping_count_exit; + } + + /* fill in the pid request message */ + msg_seq = atomic_read(&echo_nlmsg_seq); + nlh->nlmsg_seq = nlmsg_request->nlmsg_seq; + err_str = "Unable to put attribute of map count nlmsg"; + ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, + IWPM_NLA_MAPINFO_SEQ); + if (ret) + goto mapping_count_exit; + ret = ibnl_put_attr(skb, nlh, sizeof(u32), &mapping_num, + IWPM_NLA_MAPINFO_NUMBER); + if (ret) + goto mapping_count_exit; + + ret = ibnl_unicast(skb, nlh, c4iw_iwpm_pid); + if (ret) { + c4iw_iwpm_pid = C4IW_IWPM_PID_UNDEFINED; + /* already freed in the netlink send-op handling */ + skb = NULL; + err_str = "Unable to send a nlmsg"; + goto mapping_count_exit; + } + nlmsg_request->mapcount = mapping_num; + nlmsg_request->async = 1; + c4iw_start_nlmsg_req_timer(nlmsg_request, c4iw_nlmsg_req_timer_free, + C4IW_IWPM_NL_TIMEOUT); + return 0; +mapping_count_exit: + if (skb) + dev_kfree_skb(skb); + if (nlmsg_request) + free_nlmsg_request(nlmsg_request); + pr_warn("%s %s (ret = %d)\n", __func__, err_str, ret); + return ret; +} + +static int c4iw_send_nlmsg_done(struct sk_buff *skb) +{ + struct nlmsghdr *nlh = NULL; + int ret; + if (!(ibnl_put_msg(skb, &nlh, 0, 0, RDMA_NL_C4IW, + RDMA_NL_IWPM_MAP_INFO, NLM_F_MULTI))) { + pr_warn("%s Unable to put NLMSG_DONE\n", __func__); + return -ENOMEM; + } + nlh->nlmsg_type = NLMSG_DONE; + ret = ibnl_unicast(skb, (struct nlmsghdr *)skb->data, c4iw_iwpm_pid); + if (ret) { + c4iw_iwpm_pid = C4IW_IWPM_PID_UNDEFINED; + pr_warn("%s Unable to send a nlmsg\n", __func__); + } + return ret; +} + +static int c4iw_send_mapping_info(void) +{ + struct sk_buff *skb = NULL; + struct c4iw_mapping_info *map_info; + struct nlmsghdr *nlh; + int skb_num = 0, mapping_num = 0, nlmsg_bytes = 0; + unsigned long flags; + const char *err_str = ""; + int ret; + + skb = dev_alloc_skb(NLMSG_GOODSIZE); + if (!skb) { + ret = -ENOMEM; + err_str = "Unable to allocate skb"; + goto send_mapping_info_exit; + } + skb_num++; + spin_lock_irqsave(&c4iw_mapping_lock, flags); + list_for_each_entry(map_info, &c4iw_mapping_info_list, mapping_list) { + nlh = NULL; + if (!(ibnl_put_msg(skb, &nlh, 0, 0, RDMA_NL_C4IW, + RDMA_NL_IWPM_MAP_INFO, NLM_F_MULTI))) { + ret = -ENOMEM; + err_str = "Unable to put the nlmsg header"; + spin_unlock_irqrestore(&c4iw_mapping_lock, flags); + goto send_mapping_info_exit; + } + err_str = "Unable to put attribute of the nlmsg"; + ret = ibnl_put_attr(skb, nlh, + sizeof(struct sockaddr_storage), + &map_info->local_sockaddr, + IWPM_NLA_MAPINFO_LOCAL_ADDR); + if (ret) { + spin_unlock_irqrestore(&c4iw_mapping_lock, flags); + goto send_mapping_info_exit; + } + ret = ibnl_put_attr(skb, nlh, + sizeof(struct sockaddr_storage), + &map_info->mapped_sockaddr, + IWPM_NLA_MAPINFO_MAPPED_ADDR); + if (ret) { + spin_unlock_irqrestore(&c4iw_mapping_lock, flags); + goto send_mapping_info_exit; + } + mapping_num++; + nlmsg_bytes += nlh->nlmsg_len; + + /* check if all mappings can fit in one skb */ + if (NLMSG_GOODSIZE - nlmsg_bytes < nlh->nlmsg_len*2) { + nlmsg_bytes = 0; + skb_num++; + PDBG("%s Mappings Sent %d (nlmsg_bytes = %d nlmsg_len = %d). Allocating another skb (num = %d size = %lu)\n" + , __func__, mapping_num, nlmsg_bytes + , nlh->nlmsg_len, skb_num + , NLMSG_GOODSIZE); + /* and leave room for NLMSG_DONE */ + spin_unlock_irqrestore(&c4iw_mapping_lock, flags); + /* send the skb */ + ret = c4iw_send_nlmsg_done(skb); + skb = NULL; + if (ret) { + err_str = "Unable to send map info"; + goto send_mapping_info_exit; + } + if (skb_num == C4IW_MAP_INFO_SKB_COUNT) { + ret = -ENOMEM; + err_str = "Insufficient skbs for map info"; + goto send_mapping_info_exit; + } + skb = dev_alloc_skb(NLMSG_GOODSIZE); + if (!skb) { + ret = -ENOMEM; + err_str = "Unable to allocate skb"; + goto send_mapping_info_exit; + } + spin_lock_irqsave(&c4iw_mapping_lock, flags); + } + } + spin_unlock_irqrestore(&c4iw_mapping_lock, flags); + if (skb) + c4iw_send_nlmsg_done(skb); + return mapping_num; +send_mapping_info_exit: + if (skb) + dev_kfree_skb(skb); + if (ret > 0) + ret = -ret; + pr_warn("%s %s (ret = %d)\n", __func__, err_str, ret); + return ret; +} + +static const struct nla_policy + ack_mapinfo_policy[IWPM_NLA_MAPINFO_COUNT_MAX] = { + [IWPM_NLA_MAPINFO_SEQ] = { .type = NLA_U32 }, + [IWPM_NLA_MAPINFO_NUMBER] = { .type = NLA_U32 } +}; + +static int c4iw_ack_mapping_info_cb(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct c4iw_nlmsg_request *nlmsg_request = NULL; + struct nlattr *nltb[IWPM_NLA_MAPINFO_COUNT_MAX]; + u32 msg_seq, mapping_num; + const char *msg_type = "Mapping Info Ack"; + + if (c4iw_parse_nlmsg(cb, IWPM_NLA_MAPINFO_COUNT_MAX, ack_mapinfo_policy + , nltb, msg_type)) + return -EINVAL; + msg_seq = nla_get_u32(nltb[IWPM_NLA_MAPINFO_SEQ]); + nlmsg_request = c4iw_find_nlmsg_request(msg_seq); + if (!nlmsg_request) { + pr_warn("%s Could not find a matching request with seq = %u\n" + , __func__, msg_seq); + return -EINVAL; + } + mapping_num = nla_get_u32(nltb[IWPM_NLA_MAPINFO_NUMBER]); + if (nlmsg_request->mapcount != mapping_num) { + pr_info("%s Invalid map info count (sent = %u ack-ed = %u)\n" + , __func__, nlmsg_request->mapcount, mapping_num); + } + PDBG("%s Received ack for mapping count = %u\n", __func__, mapping_num); + atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq); + nlmsg_request->request_done = 1; + /* always for found nlmsg_request */ + rem_ref_nlmsg_request(nlmsg_request); + return 0; +} + +static const struct nla_policy map_error_policy[IWPM_NLA_ERR_MAX] = { + [IWPM_NLA_ERR_SEQ] = { .type = NLA_U32 }, + [IWPM_NLA_ERR_CODE] = { .type = NLA_U16 }, +}; + +static int c4iw_mapping_error_cb(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct c4iw_nlmsg_request *nlmsg_request = NULL; + struct nlattr *nltb[IWPM_NLA_ERR_MAX]; + u32 msg_seq; + u16 err_code; + const char *msg_type = "Mapping Error Msg"; + + if (c4iw_parse_nlmsg(cb, IWPM_NLA_ERR_MAX, map_error_policy, + nltb, msg_type)) + return -EINVAL; + + msg_seq = nla_get_u32(nltb[IWPM_NLA_ERR_SEQ]); + err_code = nla_get_u16(nltb[IWPM_NLA_ERR_CODE]); + pr_warn("%s Received msg_seq = %u err_code = %u\n" + , __func__, msg_seq, err_code); + /* look for nlmsg_request */ + nlmsg_request = c4iw_find_nlmsg_request(msg_seq); + if (!nlmsg_request) { + /* not all errors have associated requests */ + PDBG("%s Could not find a matching request with seq = %u\n" + , __func__, msg_seq); + return -EINVAL; + } + atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq); + nlmsg_request->err_code = err_code; + nlmsg_request->request_done = 1; + /* always for found nlmsg_request */ + rem_ref_nlmsg_request(nlmsg_request); + barrier(); + if (!nlmsg_request->async) + wake_up(&nlmsg_request->waitq); + return 0; +} diff --git a/drivers/infiniband/hw/cxgb4/c4iw_netlink.h b/drivers/infiniband/hw/cxgb4/c4iw_netlink.h new file mode 100644 index 0000000..aa1b66c --- /dev/null +++ b/drivers/infiniband/hw/cxgb4/c4iw_netlink.h @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 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. + */ + +#ifndef __C4IW_NETLINK_H +#define __C4IW_NETLINK_H + +#include +#include + +#define C4IW_IWPM_PID_UNDEFINED -1 +#define C4IW_IWPM_PID_UNAVAILABLE -2 +#define C4IW_IWPM_PID_ERROR -3 + +#define C4IW_IWPM_NL_RETRANS 3 +#define C4IW_IWPM_NL_TIMEOUT 10000 +#define C4IW_MAP_INFO_SKB_COUNT 20 + +#define IWPM_ULIBNAME_SIZE 32 +#define IWPM_DEVNAME_SIZE 32 +#define IWPM_IFNAME_SIZE 16 +#define IWPM_IPADDR_SIZE 16 + +extern struct list_head c4iw_nlmsg_request_list; +extern struct list_head c4iw_mapping_info_list; +extern spinlock_t c4iw_nlmsg_lock; +extern spinlock_t c4iw_mapping_lock; +extern atomic_t c4iw_nlmsg_seq; +extern atomic_t echo_nlmsg_seq; + +extern struct ibnl_client_cbs c4iw_nl_cb_table[]; +extern int c4iw_iwpm_pid; + +struct c4iw_nlmsg_request { + struct list_head inprocess_list; + __u32 nlmsg_seq; + void *request_buffer; + u8 request_done; + u8 async; + union { + wait_queue_head_t waitq; + struct timer_list service_timer; + }; + + atomic_t refcount; + u16 err_code; + int mapcount; + +}; + +struct c4iw_mapping_info { + struct list_head mapping_list; + struct sockaddr_storage local_sockaddr; + struct sockaddr_storage mapped_sockaddr; +}; + +enum { + IWPM_INVALID_NLMSG_ERR = 10, + IWPM_CREATE_MAPPING_ERR, + IWPM_DUPLICATE_MAPPING_ERR, + IWPM_UNKNOWN_MAPPING_ERR, + IWPM_CLIENT_DEV_INFO_ERR, + IWPM_USER_LIB_INFO_ERR, + IWPM_REMOTE_QUERY_REJECT +}; + +int c4iw_register_iwpm_pid(char *, char *, int, + void (*req_timer_func)(unsigned long)); +int c4iw_add_mapping(struct c4iw_listen_ep *ep); +int c4iw_add_and_query_mapping(struct c4iw_ep *ep); +int c4iw_remove_mapping(struct sockaddr_storage *mapped_local_addr); +void c4iw_timer_send_mapinfo(unsigned long); + +static inline int c4iw_validate_nlmsg_attr(struct nlattr *nltb[], + int nla_count) +{ + int i; + for (i = 1; i < nla_count; i++) { + if (!nltb[i]) + return -EINVAL; + } + return 0; +} + +static inline void c4iw_create_sockaddr(__be32 s_addr, __be16 s_port, + struct sockaddr_in *cm_sockaddr) +{ + cm_sockaddr->sin_family = AF_INET; + memcpy(&cm_sockaddr->sin_addr.s_addr, &s_addr, sizeof(__be32)); + cm_sockaddr->sin_port = s_port; +} + +static inline struct sk_buff *c4iw_create_nlmsg(u32 nl_op, + struct nlmsghdr **nlh) +{ + struct sk_buff *skb = NULL; + + skb = dev_alloc_skb(NLMSG_GOODSIZE); + if (!skb) { + pr_err("%s Unable to allocate skb\n", __func__); + goto create_nlmsg_exit; + } + if (!(ibnl_put_msg(skb, nlh, 0, 0, RDMA_NL_C4IW, nl_op, + NLM_F_REQUEST))) { + pr_warn("%s Unable to put the nlmsg header\n", __func__); + dev_kfree_skb(skb); + skb = NULL; + } +create_nlmsg_exit: + return skb; +} + +static inline void free_nlmsg_request(struct c4iw_nlmsg_request *nlmsg_request) +{ + unsigned long flags; + + spin_lock_irqsave(&c4iw_nlmsg_lock, flags); + list_del_init(&nlmsg_request->inprocess_list); + spin_unlock_irqrestore(&c4iw_nlmsg_lock, flags); + + if (nlmsg_request->async) + del_timer(&nlmsg_request->service_timer); + + if (!nlmsg_request->request_done) + pr_warn("%s Freeing incomplete nlmsg request (seq = %u).\n", + __func__, nlmsg_request->nlmsg_seq); + kfree(nlmsg_request); +} + +static void rem_ref_nlmsg_request(struct c4iw_nlmsg_request *nlmsg_request) +{ + if (atomic_dec_and_test(&nlmsg_request->refcount)) + free_nlmsg_request(nlmsg_request); +} + +static inline int wait_complete_nlmsg_req(struct c4iw_nlmsg_request + *nlmsg_request, int iwpm_pid) +{ + int ret; + init_waitqueue_head(&nlmsg_request->waitq); + + ret = wait_event_timeout(nlmsg_request->waitq, + (nlmsg_request->request_done != 0), + C4IW_IWPM_NL_TIMEOUT); + if (!ret) { + c4iw_iwpm_pid = iwpm_pid; + pr_warn("%s: Timeout %d sec for netlink request (seq = %u)\n" + , __func__, (C4IW_IWPM_NL_TIMEOUT/HZ) + , nlmsg_request->nlmsg_seq); + } else + ret = nlmsg_request->err_code; + + rem_ref_nlmsg_request(nlmsg_request); + return ret; +} + +static inline struct c4iw_nlmsg_request *c4iw_find_nlmsg_request(__u32 echo_seq) +{ + struct c4iw_nlmsg_request *nlmsg_request; + struct c4iw_nlmsg_request *found_request = NULL; + unsigned long flags; + + spin_lock_irqsave(&c4iw_nlmsg_lock, flags); + list_for_each_entry(nlmsg_request, &c4iw_nlmsg_request_list, + inprocess_list) { + PDBG("Looking at a request with seq = %u\n" + , nlmsg_request->nlmsg_seq); + if (nlmsg_request->nlmsg_seq == echo_seq) { + found_request = nlmsg_request; + atomic_inc(&nlmsg_request->refcount); + break; + } + } + spin_unlock_irqrestore(&c4iw_nlmsg_lock, flags); + return found_request; +} + +static inline int c4iw_create_mapinfo(struct sockaddr_storage *local_sockaddr, + struct sockaddr_storage *mapped_sockaddr, + const char *msg_type) +{ + struct c4iw_mapping_info *map_info; + unsigned long flags; + + map_info = kzalloc(sizeof(struct c4iw_mapping_info), GFP_KERNEL); + if (!map_info) { + pr_err("%s: Unable to allocate a mapping info\n", __func__); + return -ENOMEM; + } + + memcpy(&map_info->local_sockaddr, local_sockaddr, + sizeof(struct sockaddr_storage)); + memcpy(&map_info->mapped_sockaddr, mapped_sockaddr, + sizeof(struct sockaddr_storage)); + + spin_lock_irqsave(&c4iw_mapping_lock, flags); + list_add_tail(&map_info->mapping_list, &c4iw_mapping_info_list); + spin_unlock_irqrestore(&c4iw_mapping_lock, flags); + + return 0; +} + +static inline int c4iw_remove_mapinfo(struct sockaddr_storage + *mapped_local_addr) +{ + struct c4iw_mapping_info *map_info = NULL; + unsigned long flags; + int ret = -EINVAL; + const char *msg = "Remove mapped"; + + print_addr(mapped_local_addr, msg); + + spin_lock_irqsave(&c4iw_mapping_lock, flags); + list_for_each_entry(map_info, &c4iw_mapping_info_list, mapping_list) { + print_addr(&map_info->mapped_sockaddr + , "Going through mapinfo mapped local"); + if (!memcmp(&map_info->mapped_sockaddr, mapped_local_addr, + sizeof(struct sockaddr_storage))) { + list_del_init(&map_info->mapping_list); + kfree(map_info); + ret = 0; + break; + } + } + spin_unlock_irqrestore(&c4iw_mapping_lock, flags); + return ret; +} + +static inline void c4iw_destroy_mapinfo_list(void) +{ + struct c4iw_mapping_info *map_info, *map_info_tmp; + unsigned long flags; + + spin_lock_irqsave(&c4iw_mapping_lock, flags); + list_for_each_entry_safe(map_info, map_info_tmp, + &c4iw_mapping_info_list, mapping_list) { + print_addr(&map_info->mapped_sockaddr, + "Delete mapinfo mapped local"); + list_del(&map_info->mapping_list); + kfree(map_info); + } + spin_unlock_irqrestore(&c4iw_mapping_lock, flags); +} + +#endif /* __C4IW_NETLINK_H */ diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 12fef76..b8e2117 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,7 @@ #include #include "iw_cxgb4.h" +#include "c4iw_netlink.h" static char *states[] = { "idle", @@ -586,10 +588,14 @@ static int send_connect(struct c4iw_ep *ep) int sizev6 = is_t4(ep->com.dev->rdev.lldi.adapter_type) ? sizeof(struct cpl_act_open_req6) : sizeof(struct cpl_t5_act_open_req6); - struct sockaddr_in *la = (struct sockaddr_in *)&ep->com.local_addr; - struct sockaddr_in *ra = (struct sockaddr_in *)&ep->com.remote_addr; - struct sockaddr_in6 *la6 = (struct sockaddr_in6 *)&ep->com.local_addr; - struct sockaddr_in6 *ra6 = (struct sockaddr_in6 *)&ep->com.remote_addr; + struct sockaddr_in *la = (struct sockaddr_in *) + &ep->com.mapped_local_addr; + struct sockaddr_in *ra = (struct sockaddr_in *) + &ep->com.mapped_remote_addr; + struct sockaddr_in6 *la6 = (struct sockaddr_in6 *) + &ep->com.mapped_local_addr; + struct sockaddr_in6 *ra6 = (struct sockaddr_in6 *) + &ep->com.mapped_remote_addr; wrlen = (ep->com.remote_addr.ss_family == AF_INET) ? roundup(sizev4, 16) : @@ -1612,6 +1618,9 @@ static int abort_rpl(struct c4iw_dev *dev, struct sk_buff *skb) } mutex_unlock(&ep->com.mutex); + print_addr(&ep->com.mapped_local_addr, "Delete mapped local"); + c4iw_remove_mapping(&ep->com.mapped_local_addr); + if (release) release_ep_resources(ep); return 0; @@ -1866,10 +1875,10 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb) struct sockaddr_in6 *ra6; ep = lookup_atid(t, atid); - la = (struct sockaddr_in *)&ep->com.local_addr; - ra = (struct sockaddr_in *)&ep->com.remote_addr; - la6 = (struct sockaddr_in6 *)&ep->com.local_addr; - ra6 = (struct sockaddr_in6 *)&ep->com.remote_addr; + la = (struct sockaddr_in *)&ep->com.mapped_local_addr; + ra = (struct sockaddr_in *)&ep->com.mapped_remote_addr; + la6 = (struct sockaddr_in6 *)&ep->com.mapped_local_addr; + ra6 = (struct sockaddr_in6 *)&ep->com.mapped_remote_addr; PDBG("%s ep %p atid %u status %u errno %d\n", __func__, ep, atid, status, status2errno(status)); @@ -1971,6 +1980,10 @@ static int close_listsrv_rpl(struct c4iw_dev *dev, struct sk_buff *skb) PDBG("%s ep %p\n", __func__, ep); c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status)); + + print_addr(&ep->com.mapped_local_addr, "Delete mapped local"); + c4iw_remove_mapping(&ep->com.mapped_local_addr); + return 0; } @@ -2422,6 +2435,9 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb) rpl->cmd = CPL_ABORT_NO_RST; c4iw_ofld_send(&ep->com.dev->rdev, rpl_skb); out: + print_addr(&ep->com.mapped_local_addr, "Delete mapped local"); + c4iw_remove_mapping(&ep->com.mapped_local_addr); + if (release) release_ep_resources(ep); else if (ep->retry_with_mpa_v1) { @@ -2476,6 +2492,9 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb) break; } mutex_unlock(&ep->com.mutex); + print_addr(&ep->com.mapped_local_addr, "Delete mapped local"); + c4iw_remove_mapping(&ep->com.mapped_local_addr); + if (release) release_ep_resources(ep); return 0; @@ -2721,13 +2740,15 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) struct c4iw_dev *dev = to_c4iw_dev(cm_id->device); struct c4iw_ep *ep; int err = 0; - struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->local_addr; - struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_id->remote_addr; - struct sockaddr_in6 *laddr6 = (struct sockaddr_in6 *)&cm_id->local_addr; - struct sockaddr_in6 *raddr6 = (struct sockaddr_in6 *) - &cm_id->remote_addr; + struct sockaddr_in *laddr; + struct sockaddr_in *raddr; + struct sockaddr_in6 *laddr6; + struct sockaddr_in6 *raddr6; __u8 *ra; int iptype; + const char *msg_type = "Create Connect Mapping"; + int async = 0; + int iwpm_err = 0; if ((conn_param->ord > c4iw_max_read_depth) || (conn_param->ird > c4iw_max_read_depth)) { @@ -2775,6 +2796,44 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) } insert_handle(dev, &dev->atid_idr, ep, ep->atid); + memcpy(&ep->com.local_addr, &cm_id->local_addr, + sizeof(ep->com.local_addr)); + memcpy(&ep->com.remote_addr, &cm_id->remote_addr, + sizeof(ep->com.remote_addr)); + + /* No port mapper available, go with the specified peer information */ + memcpy(&ep->com.mapped_local_addr, &cm_id->local_addr, + sizeof(ep->com.mapped_local_addr)); + memcpy(&ep->com.mapped_remote_addr, &cm_id->remote_addr, + sizeof(ep->com.mapped_remote_addr)); + laddr = (struct sockaddr_in *)&ep->com.mapped_local_addr; + raddr = (struct sockaddr_in *)&ep->com.mapped_remote_addr; + laddr6 = (struct sockaddr_in6 *)&ep->com.mapped_local_addr; + raddr6 = (struct sockaddr_in6 *) &ep->com.mapped_remote_addr; + + if (c4iw_iwpm_pid == C4IW_IWPM_PID_UNDEFINED) { + iwpm_err = c4iw_register_iwpm_pid(dev->rdev.lldi.ports[0]->name, + dev->ibdev.name, async, NULL); + if (iwpm_err) { + c4iw_iwpm_pid = C4IW_IWPM_PID_ERROR; + PDBG("%s Port Mapper register pid failure (err_code = %d).\n" + , __func__, iwpm_err); + } + } + if (c4iw_iwpm_pid > 0) { /* valid iwpm pid */ + iwpm_err = c4iw_add_and_query_mapping(ep); + if (iwpm_err) + PDBG("%s Port Mapper query failure (err_code = %d).\n" + , __func__, iwpm_err); + } else + pr_warn("%s iWarp Port Mapper (pid = %d) is not available.\n" + , __func__, c4iw_iwpm_pid); + if (c4iw_create_mapinfo(&ep->com.local_addr, &ep->com.mapped_local_addr, + msg_type)) { + err = -ENOMEM; + goto fail3; + } + if (cm_id->remote_addr.ss_family == AF_INET) { iptype = 4; ra = (__u8 *)&raddr->sin_addr; @@ -2809,10 +2868,11 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) } /* find a route */ - PDBG("%s saddr %pI6 sport 0x%x raddr %pI6 rport 0x%x\n", + PDBG("%s saddr %pI6 sport 0x%x raddr %pI6 rport 0x%x sin6_scope_id %d\n", __func__, laddr6->sin6_addr.s6_addr, ntohs(laddr6->sin6_port), - raddr6->sin6_addr.s6_addr, ntohs(raddr6->sin6_port)); + raddr6->sin6_addr.s6_addr, ntohs(raddr6->sin6_port), + raddr6->sin6_scope_id); ep->dst = find_route6(dev, laddr6->sin6_addr.s6_addr, raddr6->sin6_addr.s6_addr, laddr6->sin6_port, raddr6->sin6_port, 0, @@ -2836,10 +2896,6 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) state_set(&ep->com, CONNECTING); ep->tos = 0; - memcpy(&ep->com.local_addr, &cm_id->local_addr, - sizeof(ep->com.local_addr)); - memcpy(&ep->com.remote_addr, &cm_id->remote_addr, - sizeof(ep->com.remote_addr)); /* send connect request to rnic */ err = send_connect(ep); @@ -2850,6 +2906,8 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) fail4: dst_release(ep->dst); fail3: + print_addr(&ep->com.mapped_local_addr, "Delete mapped local"); + c4iw_remove_mapping(&ep->com.mapped_local_addr); remove_handle(ep->com.dev, &ep->com.dev->atid_idr, ep->atid); cxgb4_free_atid(ep->com.dev->rdev.lldi.tids, ep->atid); fail2: @@ -2862,7 +2920,8 @@ out: static int create_server6(struct c4iw_dev *dev, struct c4iw_listen_ep *ep) { int err; - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ep->com.local_addr; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) + &ep->com.mapped_local_addr; c4iw_init_wr_wait(&ep->com.wr_wait); err = cxgb4_create_server6(ep->com.dev->rdev.lldi.ports[0], @@ -2883,7 +2942,8 @@ static int create_server6(struct c4iw_dev *dev, struct c4iw_listen_ep *ep) static int create_server4(struct c4iw_dev *dev, struct c4iw_listen_ep *ep) { int err; - struct sockaddr_in *sin = (struct sockaddr_in *)&ep->com.local_addr; + struct sockaddr_in *sin = (struct sockaddr_in *) + &ep->com.mapped_local_addr; if (dev->rdev.lldi.enable_fw_ofld_conn) { do { @@ -2918,6 +2978,9 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog) int err = 0; struct c4iw_dev *dev = to_c4iw_dev(cm_id->device); struct c4iw_listen_ep *ep; + const char *msg_type = "Create Listen Mapping"; + int async = 0; + int iwpm_err = 0; might_sleep(); @@ -2932,6 +2995,7 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog) ep->com.cm_id = cm_id; ep->com.dev = dev; ep->backlog = backlog; + memcpy(&ep->com.local_addr, &cm_id->local_addr, sizeof(ep->com.local_addr)); @@ -2951,6 +3015,34 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog) goto fail2; } insert_handle(dev, &dev->stid_idr, ep, ep->stid); + + /* No port mapper available, go with the specified info */ + memcpy(&ep->com.mapped_local_addr, &cm_id->local_addr, + sizeof(ep->com.mapped_local_addr)); + + if (c4iw_iwpm_pid == C4IW_IWPM_PID_UNDEFINED) { + iwpm_err = c4iw_register_iwpm_pid(dev->rdev.lldi.ports[0]->name, + dev->ibdev.name, async, NULL); + if (iwpm_err) { + c4iw_iwpm_pid = C4IW_IWPM_PID_ERROR; + PDBG("%s Port Mapper register pid failure (err_code = %d).\n" + , __func__, iwpm_err); + } + } + if (c4iw_iwpm_pid > 0) { /* valid iwpm pid */ + iwpm_err = c4iw_add_mapping(ep); + if (iwpm_err) + PDBG("%s Port Mapper query failure (err_code = %d).\n" + , __func__, iwpm_err); + } else + pr_warn("%s iWarp Port Mapper (pid = %d) is not available.\n" + , __func__, c4iw_iwpm_pid); + if (c4iw_create_mapinfo(&ep->com.local_addr, &ep->com.mapped_local_addr, + msg_type)) { + err = -ENOMEM; + goto fail3; + } + state_set(&ep->com, LISTEN); if (ep->com.local_addr.ss_family == AF_INET) err = create_server4(dev, ep); @@ -2960,6 +3052,10 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog) cm_id->provider_data = ep; goto out; } + +fail3: + print_addr(&ep->com.mapped_local_addr, "Delete mapped local"); + c4iw_remove_mapping(&ep->com.mapped_local_addr); cxgb4_free_stid(ep->com.dev->rdev.lldi.tids, ep->stid, ep->com.local_addr.ss_family); fail2: diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c index 33d2cc6..8810f78 100644 --- a/drivers/infiniband/hw/cxgb4/device.c +++ b/drivers/infiniband/hw/cxgb4/device.c @@ -37,6 +37,7 @@ #include #include "iw_cxgb4.h" +#include "c4iw_netlink.h" #define DRV_VERSION "0.1" @@ -106,9 +107,9 @@ static int dump_qp(int id, void *p, void *data) if (qp->ep) { if (qp->ep->com.local_addr.ss_family == AF_INET) { struct sockaddr_in *lsin = (struct sockaddr_in *) - &qp->ep->com.local_addr; + &qp->ep->com.mapped_local_addr; struct sockaddr_in *rsin = (struct sockaddr_in *) - &qp->ep->com.remote_addr; + &qp->ep->com.mapped_remote_addr; cc = snprintf(qpd->buf + qpd->pos, space, "rc qp sq id %u rq id %u state %u " @@ -122,9 +123,9 @@ static int dump_qp(int id, void *p, void *data) &rsin->sin_addr, ntohs(rsin->sin_port)); } else { struct sockaddr_in6 *lsin6 = (struct sockaddr_in6 *) - &qp->ep->com.local_addr; + &qp->ep->com.mapped_local_addr; struct sockaddr_in6 *rsin6 = (struct sockaddr_in6 *) - &qp->ep->com.remote_addr; + &qp->ep->com.mapped_remote_addr; cc = snprintf(qpd->buf + qpd->pos, space, "rc qp sq id %u rq id %u state %u " @@ -1210,6 +1211,19 @@ static int __init c4iw_init_module(void) printk(KERN_WARNING MOD "could not create debugfs entry, continuing\n"); + spin_lock_init(&c4iw_nlmsg_lock); + spin_lock_init(&c4iw_mapping_lock); + + /* List of submitted requests, searched for completions */ + INIT_LIST_HEAD(&c4iw_nlmsg_request_list); + /* List of iwpm mappings in use */ + INIT_LIST_HEAD(&c4iw_mapping_info_list); + + if (ibnl_add_client(RDMA_NL_C4IW, RDMA_NL_IWPM_NUM_OPS, + c4iw_nl_cb_table)) + pr_err("%s[%u]: Failed to add netlink callback\n" + , __func__, __LINE__); + cxgb4_register_uld(CXGB4_ULD_RDMA, &c4iw_uld_info); return 0; @@ -1227,6 +1241,8 @@ static void __exit c4iw_exit_module(void) } mutex_unlock(&dev_mutex); cxgb4_unregister_uld(CXGB4_ULD_RDMA); + ibnl_remove_client(RDMA_NL_C4IW); + c4iw_destroy_mapinfo_list(); c4iw_cm_term(); debugfs_remove_recursive(c4iw_debugfs_root); } diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h index 23eaeab..7b3405d 100644 --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h @@ -152,6 +152,20 @@ struct c4iw_rdev { struct c4iw_stats stats; }; +static inline void print_addr(struct sockaddr_storage *addr, + const char *msg) +{ + struct sockaddr_in *laddr = (struct sockaddr_in *)addr; + struct sockaddr_in6 *laddr6 = (struct sockaddr_in6 *)addr; + + if (addr->ss_family == AF_INET) + PDBG("%s %s addr %pI4 port 0x%04X\n", __func__, msg + , &laddr->sin_addr.s_addr, ntohs(laddr->sin_port)); + else + PDBG("%s %s addr %pI6 port 0x%04X\n", __func__, msg + , laddr6->sin6_addr.s6_addr, ntohs(laddr6->sin6_port)); +} + static inline int c4iw_fatal_error(struct c4iw_rdev *rdev) { return rdev->flags & T4_FATAL_ERROR; @@ -754,6 +768,8 @@ struct c4iw_ep_common { struct mutex mutex; struct sockaddr_storage local_addr; struct sockaddr_storage remote_addr; + struct sockaddr_storage mapped_local_addr; + struct sockaddr_storage mapped_remote_addr; struct c4iw_wr_wait wr_wait; unsigned long flags; unsigned long history;