Skip to content

Commit

Permalink
RDMA/IWPM: Support no port mapping requirements
Browse files Browse the repository at this point in the history
A soft iwarp driver that uses the host TCP stack via a kernel mode socket
does not need port mapping.  In fact, if the port map daemon, iwpmd, is
running, then iwpmd must not try and create/bind a socket to the actual
port for a soft iwarp connection, since the driver already has that socket
bound.

Yet if the soft iwarp driver wants to interoperate with hard iwarp devices
that -are- using port mapping, then the soft iwarp driver's mappings still
need to be maintained and advertised by the iwpm protocol.

This patch enhances the rdma driver<->iwcm interface to allow an iwarp
driver to specify that it does not want port mapping.  The iwpm
kernel<->iwpmd interface is also enhanced to pass up this information on
map requests.

Care is taken to interoperate with the current iwpmd version (ABI version
3) and only use the new NL attributes if iwpmd supports ABI version 4.

The ABI version define has also been created in rdma_netlink.h so both
kernel and user code can share it.  The iwcm and iwpmd negotiate the ABI
version to use with a new HELLO netlink message.

Signed-off-by: Steve Wise <[email protected]>
Reviewed-by: Tatyana Nikolova <[email protected]>
Signed-off-by: Jason Gunthorpe <[email protected]>
  • Loading branch information
Steve Wise authored and jgunthorpe committed Feb 4, 2019
1 parent f76903d commit b0bad9a
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 7 deletions.
7 changes: 5 additions & 2 deletions drivers/infiniband/core/iwcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ static struct rdma_nl_cbs iwcm_nl_cb_table[RDMA_NL_IWPM_NUM_OPS] = {
[RDMA_NL_IWPM_REMOTE_INFO] = {.dump = iwpm_remote_info_cb},
[RDMA_NL_IWPM_HANDLE_ERR] = {.dump = iwpm_mapping_error_cb},
[RDMA_NL_IWPM_MAPINFO] = {.dump = iwpm_mapping_info_cb},
[RDMA_NL_IWPM_MAPINFO_NUM] = {.dump = iwpm_ack_mapping_info_cb}
[RDMA_NL_IWPM_MAPINFO_NUM] = {.dump = iwpm_ack_mapping_info_cb},
[RDMA_NL_IWPM_HELLO] = {.dump = iwpm_hello_cb}
};

static struct workqueue_struct *iwcm_wq;
Expand Down Expand Up @@ -525,6 +526,8 @@ static int iw_cm_map(struct iw_cm_id *cm_id, bool active)
cm_id->mapped = true;
pm_msg.loc_addr = cm_id->local_addr;
pm_msg.rem_addr = cm_id->remote_addr;
pm_msg.flags = (cm_id->device->iwcm->driver_flags & IW_F_NO_PORT_MAP) ?
IWPM_FLAGS_NO_PORT_MAP : 0;
if (active)
status = iwpm_add_and_query_mapping(&pm_msg,
RDMA_NL_IWCM);
Expand All @@ -543,7 +546,7 @@ static int iw_cm_map(struct iw_cm_id *cm_id, bool active)

return iwpm_create_mapinfo(&cm_id->local_addr,
&cm_id->m_local_addr,
RDMA_NL_IWCM);
RDMA_NL_IWCM, pm_msg.flags);
}

/*
Expand Down
80 changes: 77 additions & 3 deletions drivers/infiniband/core/iwpm_msg.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
#include "iwpm_util.h"

static const char iwpm_ulib_name[IWPM_ULIBNAME_SIZE] = "iWarpPortMapperUser";
static int iwpm_ulib_version = 3;
u16 iwpm_ulib_version = IWPM_UABI_VERSION_MIN;
static int iwpm_user_pid = IWPM_PID_UNDEFINED;
static atomic_t echo_nlmsg_seq;

Expand Down Expand Up @@ -130,6 +130,7 @@ int iwpm_register_pid(struct iwpm_dev_data *pm_msg, u8 nl_client)
* nlmsg attributes:
* [IWPM_NLA_MANAGE_MAPPING_SEQ]
* [IWPM_NLA_MANAGE_ADDR]
* [IWPM_NLA_MANAGE_FLAGS]
*/
int iwpm_add_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
{
Expand Down Expand Up @@ -173,6 +174,18 @@ int iwpm_add_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
if (ret)
goto add_mapping_error;

/* If flags are required and we're not V4, then return a quiet error */
if (pm_msg->flags && iwpm_ulib_version == IWPM_UABI_VERSION_MIN) {
ret = -EINVAL;
goto add_mapping_error_nowarn;
}
if (iwpm_ulib_version > IWPM_UABI_VERSION_MIN) {
ret = ibnl_put_attr(skb, nlh, sizeof(u32), &pm_msg->flags,
IWPM_NLA_MANAGE_FLAGS);
if (ret)
goto add_mapping_error;
}

nlmsg_end(skb, nlh);
nlmsg_request->req_buffer = pm_msg;

Expand All @@ -187,6 +200,7 @@ int iwpm_add_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
return ret;
add_mapping_error:
pr_info("%s: %s (client = %d)\n", __func__, err_str, nl_client);
add_mapping_error_nowarn:
if (skb)
dev_kfree_skb(skb);
if (nlmsg_request)
Expand All @@ -201,6 +215,7 @@ int iwpm_add_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
* [IWPM_NLA_QUERY_MAPPING_SEQ]
* [IWPM_NLA_QUERY_LOCAL_ADDR]
* [IWPM_NLA_QUERY_REMOTE_ADDR]
* [IWPM_NLA_QUERY_FLAGS]
*/
int iwpm_add_and_query_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
{
Expand Down Expand Up @@ -251,6 +266,18 @@ int iwpm_add_and_query_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
if (ret)
goto query_mapping_error;

/* If flags are required and we're not V4, then return a quite error */
if (pm_msg->flags && iwpm_ulib_version == IWPM_UABI_VERSION_MIN) {
ret = -EINVAL;
goto query_mapping_error_nowarn;
}
if (iwpm_ulib_version > IWPM_UABI_VERSION_MIN) {
ret = ibnl_put_attr(skb, nlh, sizeof(u32), &pm_msg->flags,
IWPM_NLA_QUERY_FLAGS);
if (ret)
goto query_mapping_error;
}

nlmsg_end(skb, nlh);
nlmsg_request->req_buffer = pm_msg;

Expand All @@ -264,6 +291,7 @@ int iwpm_add_and_query_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
return ret;
query_mapping_error:
pr_info("%s: %s (client = %d)\n", __func__, err_str, nl_client);
query_mapping_error_nowarn:
if (skb)
dev_kfree_skb(skb);
if (nlmsg_request)
Expand Down Expand Up @@ -379,14 +407,18 @@ int iwpm_register_pid_cb(struct sk_buff *skb, struct netlink_callback *cb)
/* check device name, ulib name and version */
if (strcmp(pm_msg->dev_name, dev_name) ||
strcmp(iwpm_ulib_name, iwpm_name) ||
iwpm_version != iwpm_ulib_version) {
iwpm_version < IWPM_UABI_VERSION_MIN) {

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;
}
iwpm_user_pid = cb->nlh->nlmsg_pid;
iwpm_ulib_version = iwpm_version;
if (iwpm_ulib_version < IWPM_UABI_VERSION)
pr_warn_once("%s: Down level iwpmd/pid %u. Continuing...",
__func__, iwpm_user_pid);
atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
pr_debug("%s: iWarp Port Mapper (pid = %d) is available!\n",
__func__, iwpm_user_pid);
Expand Down Expand Up @@ -661,7 +693,7 @@ int iwpm_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
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) {
iwpm_version < IWPM_UABI_VERSION_MIN) {
pr_info("%s: Invalid port mapper name = %s version = %d\n",
__func__, iwpm_name, iwpm_version);
return ret;
Expand All @@ -675,6 +707,11 @@ int iwpm_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
iwpm_set_registration(nl_client, IWPM_REG_INCOMPL);
atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
iwpm_user_pid = cb->nlh->nlmsg_pid;

if (iwpm_ulib_version < IWPM_UABI_VERSION)
pr_warn_once("%s: Down level iwpmd/pid %u. Continuing...",
__func__, iwpm_user_pid);

if (!iwpm_mapinfo_available())
return 0;
pr_debug("%s: iWarp Port Mapper (pid = %d) is available!\n",
Expand Down Expand Up @@ -754,3 +791,40 @@ int iwpm_mapping_error_cb(struct sk_buff *skb, struct netlink_callback *cb)
up(&nlmsg_request->sem);
return 0;
}

/* netlink attribute policy for the received hello request */
static const struct nla_policy hello_policy[IWPM_NLA_HELLO_MAX] = {
[IWPM_NLA_HELLO_ABI_VERSION] = { .type = NLA_U16 }
};

/*
* iwpm_hello_cb - Process a port mapper hello request
*/
int iwpm_hello_cb(struct sk_buff *skb, struct netlink_callback *cb)
{
struct nlattr *nltb[IWPM_NLA_HELLO_MAX];
const char *msg_type = "Hello request";
u8 nl_client;
u16 abi_version;
int ret = -EINVAL;

if (iwpm_parse_nlmsg(cb, IWPM_NLA_HELLO_MAX, hello_policy, nltb,
msg_type)) {
pr_info("%s: Unable to parse nlmsg\n", __func__);
return ret;
}
abi_version = nla_get_u16(nltb[IWPM_NLA_HELLO_ABI_VERSION]);
nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type);
if (!iwpm_valid_client(nl_client)) {
pr_info("%s: Invalid port mapper client = %d\n",
__func__, nl_client);
return ret;
}
iwpm_set_registration(nl_client, IWPM_REG_INCOMPL);
atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
iwpm_ulib_version = min_t(u16, IWPM_UABI_VERSION, abi_version);
pr_debug("Using ABI version %u\n", iwpm_ulib_version);
iwpm_user_pid = cb->nlh->nlmsg_pid;
ret = iwpm_send_hello(nl_client, iwpm_user_pid, iwpm_ulib_version);
return ret;
}
48 changes: 47 additions & 1 deletion drivers/infiniband/core/iwpm_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ static struct hlist_head *get_mapinfo_hash_bucket(struct sockaddr_storage *,

int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr,
struct sockaddr_storage *mapped_sockaddr,
u8 nl_client)
u8 nl_client, u32 map_flags)
{
struct hlist_head *hash_bucket_head = NULL;
struct iwpm_mapping_info *map_info;
Expand All @@ -132,6 +132,7 @@ int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr,
memcpy(&map_info->mapped_sockaddr, mapped_sockaddr,
sizeof(struct sockaddr_storage));
map_info->nl_client = nl_client;
map_info->map_flags = map_flags;

spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
if (iwpm_hash_bucket) {
Expand Down Expand Up @@ -686,6 +687,14 @@ int iwpm_send_mapinfo(u8 nl_client, int iwpm_pid)
if (ret)
goto send_mapping_info_unlock;

if (iwpm_ulib_version > IWPM_UABI_VERSION_MIN) {
ret = ibnl_put_attr(skb, nlh, sizeof(u32),
&map_info->map_flags,
IWPM_NLA_MAPINFO_FLAGS);
if (ret)
goto send_mapping_info_unlock;
}

nlmsg_end(skb, nlh);

iwpm_print_sockaddr(&map_info->local_sockaddr,
Expand Down Expand Up @@ -754,3 +763,40 @@ int iwpm_mapinfo_available(void)
spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
return full_bucket;
}

int iwpm_send_hello(u8 nl_client, int iwpm_pid, u16 abi_version)
{
struct sk_buff *skb = NULL;
struct nlmsghdr *nlh;
u32 msg_seq;
const char *err_str = "";
int ret = -EINVAL;

skb = iwpm_create_nlmsg(RDMA_NL_IWPM_HELLO, &nlh, nl_client);
if (!skb) {
err_str = "Unable to create a nlmsg";
goto hello_num_error;
}
nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
msg_seq = 0;
err_str = "Unable to put attribute of abi_version into nlmsg";
ret = ibnl_put_attr(skb, nlh, sizeof(u16), &abi_version,
IWPM_NLA_HELLO_ABI_VERSION);
if (ret)
goto hello_num_error;
nlmsg_end(skb, nlh);

ret = rdma_nl_unicast(skb, iwpm_pid);
if (ret) {
skb = NULL;
err_str = "Unable to send a nlmsg";
goto hello_num_error;
}
pr_debug("%s: Sent hello abi_version = %u\n", __func__, abi_version);
return 0;
hello_num_error:
pr_info("%s: %s\n", __func__, err_str);
if (skb)
dev_kfree_skb(skb);
return ret;
}
12 changes: 12 additions & 0 deletions drivers/infiniband/core/iwpm_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ struct iwpm_mapping_info {
struct sockaddr_storage local_sockaddr;
struct sockaddr_storage mapped_sockaddr;
u8 nl_client;
u32 map_flags;
};

struct iwpm_remote_info {
Expand Down Expand Up @@ -266,4 +267,15 @@ int iwpm_parse_nlmsg(struct netlink_callback *cb, int policy_max,
* @msg: Message to print
*/
void iwpm_print_sockaddr(struct sockaddr_storage *sockaddr, char *msg);

/**
* iwpm_send_hello - Send hello response to iwpmd
*
* @nl_client: The index of the netlink client
* @abi_version: The kernel's abi_version
*
* Returns 0 on success or a negative error code
*/
int iwpm_send_hello(u8 nl_client, int iwpm_pid, u16 abi_version);
extern u16 iwpm_ulib_version;
#endif
13 changes: 13 additions & 0 deletions include/rdma/iw_cm.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,18 @@ struct iw_cm_conn_param {
u32 qpn;
};

enum iw_flags {

/*
* This flag allows the iwcm and iwpmd to still advertise
* mappings but the real and mapped port numbers are the
* same. Further, iwpmd will not bind any user socket to
* reserve the port. This is required for soft iwarp
* to play in the port mapped iwarp space.
*/
IW_F_NO_PORT_MAP = (1 << 0),
};

struct iw_cm_verbs {
void (*add_ref)(struct ib_qp *qp);

Expand All @@ -127,6 +139,7 @@ struct iw_cm_verbs {

int (*destroy_listen)(struct iw_cm_id *cm_id);
char ifname[IFNAMSIZ];
enum iw_flags driver_flags;
};

/**
Expand Down
15 changes: 14 additions & 1 deletion include/rdma/iw_portmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ struct iwpm_sa_data {
struct sockaddr_storage mapped_loc_addr;
struct sockaddr_storage rem_addr;
struct sockaddr_storage mapped_rem_addr;
u32 flags;
};

/**
Expand Down Expand Up @@ -205,9 +206,11 @@ int iwpm_get_remote_info(struct sockaddr_storage *mapped_loc_addr,
* @local_addr: Local ip/tcp address
* @mapped_addr: Mapped local ip/tcp address
* @nl_client: The index of the netlink client
* @map_flags: IWPM mapping flags
*/
int iwpm_create_mapinfo(struct sockaddr_storage *local_addr,
struct sockaddr_storage *mapped_addr, u8 nl_client);
struct sockaddr_storage *mapped_addr, u8 nl_client,
u32 map_flags);

/**
* iwpm_remove_mapinfo - Remove local and mapped IPv4/IPv6 address
Expand All @@ -221,4 +224,14 @@ int iwpm_create_mapinfo(struct sockaddr_storage *local_addr,
int iwpm_remove_mapinfo(struct sockaddr_storage *local_addr,
struct sockaddr_storage *mapped_addr);

/**
* iwpm_hello_cb - Process a hello message from iwpmd
*
* @skb:
* @cb: Contains the received message (payload and netlink header)
*
* Using the received port mapper pid, send the kernel's abi_version
* after adjusting it to support the iwpmd version.
*/
int iwpm_hello_cb(struct sk_buff *skb, struct netlink_callback *cb);
#endif /* _IW_PORTMAP_H */
Loading

0 comments on commit b0bad9a

Please sign in to comment.