Add callbacks and data types for statistics export. One callback is implemented that exports all of the current devices/ids. Add/remove the callback to IB Netlink on init/cleanup.
Signed-off-by: Nir Muchtar <[email protected]> --- drivers/infiniband/core/cma.c | 97 +++++++++++++++++++++++++++++++++++++++++ include/rdma/rdma_cm.h | 14 ++++++ 2 files changed, 111 insertions(+), 0 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 5821f93..9c6ce73 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -51,6 +51,7 @@ #include <rdma/ib_cm.h> #include <rdma/ib_sa.h> #include <rdma/iw_cm.h> +#include <rdma/ib_netlink.h> MODULE_AUTHOR("Sean Hefty"); MODULE_DESCRIPTION("Generic RDMA CM Agent"); @@ -134,6 +135,7 @@ struct rdma_id_private { u32 qp_num; u8 srq; u8 tos; + pid_t owner; }; struct cma_multicast { @@ -418,6 +420,7 @@ struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler, if (!id_priv) return ERR_PTR(-ENOMEM); + id_priv->owner = current->pid; id_priv->state = RDMA_CM_IDLE; id_priv->id.context = context; id_priv->id.event_handler = event_handler; @@ -2671,8 +2674,14 @@ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) { struct rdma_id_private *id_priv; int ret; + unsigned long flags; id_priv = container_of(id, struct rdma_id_private, id); + + spin_lock_irqsave(&id_priv->lock, flags); + id_priv->owner = current->pid; + spin_unlock_irqrestore(&id_priv->lock, flags); + if (!cma_comp(id_priv, RDMA_CM_CONNECT)) return -EINVAL; @@ -3243,6 +3252,91 @@ static void cma_remove_one(struct ib_device *device) kfree(cma_dev); } +static int cma_get_stats(struct sk_buff **nl_skb, int pid) +{ + struct rdma_cm_id_stats *id_stats; + struct rdma_id_private *id_priv; + struct rdma_cm_id *id = NULL; + struct cma_device *cma_dev; + char *dev_name; + struct sockaddr_in *src, *dst; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct sockaddr_in6 *src6, *dst6; +#endif + int seq = 0; + + mutex_lock(&lock); + list_for_each_entry(cma_dev, &dev_list, list) { + dev_name = ibnl_put(nl_skb, pid, seq++, + strlen(cma_dev->device->name) + 1, + IBNL_RDMA_CM, + IBNL_RDMA_CM_DEVICE_NAME); + if (!dev_name) + goto errmem; + strcpy(dev_name, cma_dev->device->name); + list_for_each_entry(id_priv, &cma_dev->id_list, list) { + id_stats = ibnl_put(nl_skb, pid, seq++, + sizeof *id_stats, IBNL_RDMA_CM, + IBNL_RDMA_CM_ID_STATS); + if (!id_stats) + goto errmem; + memset(id_stats, 0, sizeof *id_stats); + id = &id_priv->id; + id_stats->nt = id->route.addr.dev_addr.dev_type; + id_stats->port_num = id->port_num; + id_stats->bound_dev_if = + id->route.addr.dev_addr.bound_dev_if; + + if (id->route.addr.src_addr.ss_family == AF_INET && + id->route.addr.dst_addr.ss_family == AF_INET) { + src = (struct sockaddr_in *) + (&id->route.addr.src_addr); + dst = (struct sockaddr_in *) + (&id->route.addr.dst_addr); + id_stats->local_port = src->sin_port; + id_stats->remote_port = dst->sin_port; + id_stats->local_addr[0] = src->sin_addr.s_addr; + id_stats->remote_addr[0] = dst->sin_addr.s_addr; + } + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + if (id->route.addr.src_addr.ss_family == AF_INET6 && + id->route.addr.dst_addr.ss_family == AF_INET6) { + src6 = (struct sockaddr_in6 *) + (&id->route.addr.src_addr); + dst6 = (struct sockaddr_in6 *) + (&id->route.addr.dst_addr); + + ipv6_addr_copy((struct in6_addr *) + (id_stats->local_addr), + &src6->sin6_addr); + ipv6_addr_copy((struct in6_addr *) + (id_stats->remote_addr), + &dst6->sin6_addr); + } +#endif + id_stats->ps = id->ps; + id_stats->cm_state = id_priv->state; + id_stats->qp_num = id_priv->qp_num; + id_stats->pid = id_priv->owner; + } + } + mutex_unlock(&lock); + return 0; +errmem: + printk(KERN_INFO "RDMA CM failed to export data.\n"); + mutex_unlock(&lock); + return -ENOMEM; +} + +static int cma_get_data(int op, struct sk_buff **nl_skb, int pid) +{ + if (op == IBNL_RDMA_CM_STATS) + return cma_get_stats(nl_skb, pid); + printk(KERN_NOTICE "RDMA CM Invalid netlink operation (%d)\n", op); + return -EINVAL; +} + static int __init cma_init(void) { int ret; @@ -3258,6 +3352,8 @@ static int __init cma_init(void) ret = ib_register_client(&cma_client); if (ret) goto err; + if (ibnl_add_cb(IBNL_RDMA_CM, cma_get_data)) + printk(KERN_WARNING "RDMA CM failed to add netlink callback\n"); return 0; err: @@ -3270,6 +3366,7 @@ err: static void __exit cma_cleanup(void) { + ibnl_remove_cb(IBNL_RDMA_CM); ib_unregister_client(&cma_client); unregister_netdevice_notifier(&cma_nb); rdma_addr_unregister_client(&addr_client); diff --git a/include/rdma/rdma_cm.h b/include/rdma/rdma_cm.h index c766da9..7f341bb 100644 --- a/include/rdma/rdma_cm.h +++ b/include/rdma/rdma_cm.h @@ -147,6 +147,20 @@ struct rdma_cm_id { u8 port_num; }; +struct rdma_cm_id_stats { + enum rdma_node_type nt; + int port_num; + int bound_dev_if; + __be16 local_port; + __be16 remote_port; + __be32 local_addr[4]; + __be32 remote_addr[4]; + enum rdma_port_space ps; + enum rdma_cm_state cm_state; + u32 qp_num; + pid_t pid; +}; + /** * rdma_create_id - Create an RDMA identifier. * -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
