iwcm: common code for port mapper
authorFaisal Latif <faisal.latif@intel.com>
Fri, 26 Feb 2016 15:18:00 +0000 (09:18 -0600)
committerDoug Ledford <dledford@redhat.com>
Wed, 16 Mar 2016 17:47:52 +0000 (13:47 -0400)
moved port mapper related code from drivers into common code

Signed-off-by: Mustafa Ismail <mustafa.ismail@intel.com>
Signed-off-by: Tatyana E. Nikolova <tatyana.e.nikolova@intel.com>
Signed-off-by: Faisal Latif <faisal.latif@intel.com>
Reviewed-by: Steve Wise <swise@opengridcomputing.com>
Tested-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/core/iwcm.c
drivers/infiniband/core/iwpm_msg.c
include/rdma/iw_cm.h
include/uapi/rdma/rdma_netlink.h

index ff9163dc159614fe76ca7c476ff80b64de9c4e54..e28a160cdab03650441cd0ff48b44e0cffce9a68 100644 (file)
@@ -50,6 +50,8 @@
 
 #include <rdma/iw_cm.h>
 #include <rdma/ib_addr.h>
+#include <rdma/iw_portmap.h>
+#include <rdma/rdma_netlink.h>
 
 #include "iwcm.h"
 
@@ -57,6 +59,16 @@ MODULE_AUTHOR("Tom Tucker");
 MODULE_DESCRIPTION("iWARP CM");
 MODULE_LICENSE("Dual BSD/GPL");
 
+static struct ibnl_client_cbs iwcm_nl_cb_table[] = {
+       [RDMA_NL_IWPM_REG_PID] = {.dump = iwpm_register_pid_cb},
+       [RDMA_NL_IWPM_ADD_MAPPING] = {.dump = iwpm_add_mapping_cb},
+       [RDMA_NL_IWPM_QUERY_MAPPING] = {.dump = iwpm_add_and_query_mapping_cb},
+       [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}
+};
+
 static struct workqueue_struct *iwcm_wq;
 struct iwcm_work {
        struct work_struct work;
@@ -402,6 +414,11 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
        }
        spin_unlock_irqrestore(&cm_id_priv->lock, flags);
 
+       if (cm_id->mapped) {
+               iwpm_remove_mapinfo(&cm_id->local_addr, &cm_id->m_local_addr);
+               iwpm_remove_mapping(&cm_id->local_addr, RDMA_NL_IWCM);
+       }
+
        (void)iwcm_deref_id(cm_id_priv);
 }
 
@@ -426,6 +443,97 @@ void iw_destroy_cm_id(struct iw_cm_id *cm_id)
 }
 EXPORT_SYMBOL(iw_destroy_cm_id);
 
+/**
+ * iw_cm_check_wildcard - If IP address is 0 then use original
+ * @pm_addr: sockaddr containing the ip to check for wildcard
+ * @cm_addr: sockaddr containing the actual IP address
+ * @cm_outaddr: sockaddr to set IP addr which leaving port
+ *
+ *  Checks the pm_addr for wildcard and then sets cm_outaddr's
+ *  IP to the actual (cm_addr).
+ */
+static void iw_cm_check_wildcard(struct sockaddr_storage *pm_addr,
+                                struct sockaddr_storage *cm_addr,
+                                struct sockaddr_storage *cm_outaddr)
+{
+       if (pm_addr->ss_family == AF_INET) {
+               struct sockaddr_in *pm4_addr = (struct sockaddr_in *)pm_addr;
+
+               if (pm4_addr->sin_addr.s_addr == INADDR_ANY) {
+                       struct sockaddr_in *cm4_addr =
+                               (struct sockaddr_in *)cm_addr;
+                       struct sockaddr_in *cm4_outaddr =
+                               (struct sockaddr_in *)cm_outaddr;
+
+                       cm4_outaddr->sin_addr = cm4_addr->sin_addr;
+               }
+       } else {
+               struct sockaddr_in6 *pm6_addr = (struct sockaddr_in6 *)pm_addr;
+
+               if (ipv6_addr_type(&pm6_addr->sin6_addr) == IPV6_ADDR_ANY) {
+                       struct sockaddr_in6 *cm6_addr =
+                               (struct sockaddr_in6 *)cm_addr;
+                       struct sockaddr_in6 *cm6_outaddr =
+                               (struct sockaddr_in6 *)cm_outaddr;
+
+                       cm6_outaddr->sin6_addr = cm6_addr->sin6_addr;
+               }
+       }
+}
+
+/**
+ * iw_cm_map - Use portmapper to map the ports
+ * @cm_id: connection manager pointer
+ * @active: Indicates the active side when true
+ * returns nonzero for error only if iwpm_create_mapinfo() fails
+ *
+ * Tries to add a mapping for a port using the Portmapper. If
+ * successful in mapping the IP/Port it will check the remote
+ * mapped IP address for a wildcard IP address and replace the
+ * zero IP address with the remote_addr.
+ */
+static int iw_cm_map(struct iw_cm_id *cm_id, bool active)
+{
+       struct iwpm_dev_data pm_reg_msg;
+       struct iwpm_sa_data pm_msg;
+       int status;
+
+       cm_id->m_local_addr = cm_id->local_addr;
+       cm_id->m_remote_addr = cm_id->remote_addr;
+
+       memcpy(pm_reg_msg.dev_name, cm_id->device->name,
+              sizeof(pm_reg_msg.dev_name));
+       memcpy(pm_reg_msg.if_name, cm_id->device->iwcm->ifname,
+              sizeof(pm_reg_msg.if_name));
+
+       if (iwpm_register_pid(&pm_reg_msg, RDMA_NL_IWCM) ||
+           !iwpm_valid_pid())
+               return 0;
+
+       cm_id->mapped = true;
+       pm_msg.loc_addr = cm_id->local_addr;
+       pm_msg.rem_addr = cm_id->remote_addr;
+       if (active)
+               status = iwpm_add_and_query_mapping(&pm_msg,
+                                                   RDMA_NL_IWCM);
+       else
+               status = iwpm_add_mapping(&pm_msg, RDMA_NL_IWCM);
+
+       if (!status) {
+               cm_id->m_local_addr = pm_msg.mapped_loc_addr;
+               if (active) {
+                       cm_id->m_remote_addr = pm_msg.mapped_rem_addr;
+                       iw_cm_check_wildcard(&pm_msg.mapped_rem_addr,
+                                            &cm_id->remote_addr,
+                                            &cm_id->m_remote_addr);
+               }
+       }
+
+       return iwpm_create_mapinfo(&cm_id->local_addr,
+                                  &cm_id->m_local_addr,
+                                  RDMA_NL_IWCM);
+}
+
 /*
  * CM_ID <-- LISTEN
  *
@@ -452,7 +560,9 @@ int iw_cm_listen(struct iw_cm_id *cm_id, int backlog)
        case IW_CM_STATE_IDLE:
                cm_id_priv->state = IW_CM_STATE_LISTEN;
                spin_unlock_irqrestore(&cm_id_priv->lock, flags);
-               ret = cm_id->device->iwcm->create_listen(cm_id, backlog);
+               ret = iw_cm_map(cm_id, false);
+               if (!ret)
+                       ret = cm_id->device->iwcm->create_listen(cm_id, backlog);
                if (ret)
                        cm_id_priv->state = IW_CM_STATE_IDLE;
                spin_lock_irqsave(&cm_id_priv->lock, flags);
@@ -582,39 +692,37 @@ int iw_cm_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
        spin_lock_irqsave(&cm_id_priv->lock, flags);
 
        if (cm_id_priv->state != IW_CM_STATE_IDLE) {
-               spin_unlock_irqrestore(&cm_id_priv->lock, flags);
-               clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
-               wake_up_all(&cm_id_priv->connect_wait);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err;
        }
 
        /* Get the ib_qp given the QPN */
        qp = cm_id->device->iwcm->get_qp(cm_id->device, iw_param->qpn);
        if (!qp) {
-               spin_unlock_irqrestore(&cm_id_priv->lock, flags);
-               clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
-               wake_up_all(&cm_id_priv->connect_wait);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err;
        }
        cm_id->device->iwcm->add_ref(qp);
        cm_id_priv->qp = qp;
        cm_id_priv->state = IW_CM_STATE_CONN_SENT;
        spin_unlock_irqrestore(&cm_id_priv->lock, flags);
 
-       ret = cm_id->device->iwcm->connect(cm_id, iw_param);
-       if (ret) {
-               spin_lock_irqsave(&cm_id_priv->lock, flags);
-               if (cm_id_priv->qp) {
-                       cm_id->device->iwcm->rem_ref(qp);
-                       cm_id_priv->qp = NULL;
-               }
-               spin_unlock_irqrestore(&cm_id_priv->lock, flags);
-               BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_SENT);
-               cm_id_priv->state = IW_CM_STATE_IDLE;
-               clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
-               wake_up_all(&cm_id_priv->connect_wait);
-       }
+       ret = iw_cm_map(cm_id, true);
+       if (!ret)
+               ret = cm_id->device->iwcm->connect(cm_id, iw_param);
+       if (!ret)
+               return 0;       /* success */
 
+       spin_lock_irqsave(&cm_id_priv->lock, flags);
+       if (cm_id_priv->qp) {
+               cm_id->device->iwcm->rem_ref(qp);
+               cm_id_priv->qp = NULL;
+       }
+       cm_id_priv->state = IW_CM_STATE_IDLE;
+err:
+       spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+       clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
+       wake_up_all(&cm_id_priv->connect_wait);
        return ret;
 }
 EXPORT_SYMBOL(iw_cm_connect);
@@ -656,8 +764,23 @@ static void cm_conn_req_handler(struct iwcm_id_private *listen_id_priv,
                goto out;
 
        cm_id->provider_data = iw_event->provider_data;
-       cm_id->local_addr = iw_event->local_addr;
-       cm_id->remote_addr = iw_event->remote_addr;
+       cm_id->m_local_addr = iw_event->local_addr;
+       cm_id->m_remote_addr = iw_event->remote_addr;
+       cm_id->local_addr = listen_id_priv->id.local_addr;
+
+       ret = iwpm_get_remote_info(&listen_id_priv->id.m_local_addr,
+                                  &iw_event->remote_addr,
+                                  &cm_id->remote_addr,
+                                  RDMA_NL_IWCM);
+       if (ret) {
+               cm_id->remote_addr = iw_event->remote_addr;
+       } else {
+               iw_cm_check_wildcard(&listen_id_priv->id.m_local_addr,
+                                    &iw_event->local_addr,
+                                    &cm_id->local_addr);
+               iw_event->local_addr = cm_id->local_addr;
+               iw_event->remote_addr = cm_id->remote_addr;
+       }
 
        cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
        cm_id_priv->state = IW_CM_STATE_CONN_RECV;
@@ -753,8 +876,10 @@ static int cm_conn_rep_handler(struct iwcm_id_private *cm_id_priv,
        clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
        BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_SENT);
        if (iw_event->status == 0) {
-               cm_id_priv->id.local_addr = iw_event->local_addr;
-               cm_id_priv->id.remote_addr = iw_event->remote_addr;
+               cm_id_priv->id.m_local_addr = iw_event->local_addr;
+               cm_id_priv->id.m_remote_addr = iw_event->remote_addr;
+               iw_event->local_addr = cm_id_priv->id.local_addr;
+               iw_event->remote_addr = cm_id_priv->id.remote_addr;
                cm_id_priv->state = IW_CM_STATE_ESTABLISHED;
        } else {
                /* REJECTED or RESET */
@@ -1044,6 +1169,17 @@ EXPORT_SYMBOL(iw_cm_init_qp_attr);
 
 static int __init iw_cm_init(void)
 {
+       int ret;
+
+       ret = iwpm_init(RDMA_NL_IWCM);
+       if (ret)
+               pr_err("iw_cm: couldn't init iwpm\n");
+
+       ret = ibnl_add_client(RDMA_NL_IWCM, RDMA_NL_IWPM_NUM_OPS,
+                             iwcm_nl_cb_table);
+       if (ret)
+               pr_err("iw_cm: couldn't register netlink callbacks\n");
+
        iwcm_wq = create_singlethread_workqueue("iw_cm_wq");
        if (!iwcm_wq)
                return -ENOMEM;
@@ -1063,6 +1199,8 @@ static void __exit iw_cm_cleanup(void)
 {
        unregister_net_sysctl_table(iwcm_ctl_table_hdr);
        destroy_workqueue(iwcm_wq);
+       ibnl_remove_client(RDMA_NL_IWCM);
+       iwpm_exit(RDMA_NL_IWCM);
 }
 
 module_init(iw_cm_init);
index 22a3abee2a54c0fdce95a4567ef3cc45a20901ad..c2b4ce67fd4afebbd1f8dec1ef9c1093f1d4fdc1 100644 (file)
@@ -88,7 +88,7 @@ int iwpm_register_pid(struct iwpm_dev_data *pm_msg, u8 nl_client)
        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,
+       ret = ibnl_put_attr(skb, nlh, IFNAMSIZ,
                                pm_msg->if_name, IWPM_NLA_REG_IF_NAME);
        if (ret)
                goto pid_query_error;
index 036bd277266254dba1ff5807a760e17da013667d..6d0065c322b706aaad7ac34703834f12e42ea39d 100644 (file)
@@ -83,8 +83,10 @@ struct iw_cm_id {
        iw_cm_handler           cm_handler;      /* client callback function */
        void                    *context;        /* client cb context */
        struct ib_device        *device;
-       struct sockaddr_storage local_addr;
+       struct sockaddr_storage local_addr;      /* local addr */
        struct sockaddr_storage remote_addr;
+       struct sockaddr_storage m_local_addr;    /* nmapped local addr */
+       struct sockaddr_storage m_remote_addr;   /* nmapped rem addr */
        void                    *provider_data;  /* provider private data */
        iw_event_handler        event_handler;   /* cb for provider
                                                    events */
@@ -92,6 +94,7 @@ struct iw_cm_id {
        void (*add_ref)(struct iw_cm_id *);
        void (*rem_ref)(struct iw_cm_id *);
        u8  tos;
+       bool mapped;
 };
 
 struct iw_cm_conn_param {
@@ -123,6 +126,7 @@ struct iw_cm_verbs {
                                         int backlog);
 
        int             (*destroy_listen)(struct iw_cm_id *cm_id);
+       char            ifname[IFNAMSIZ];
 };
 
 /**
index c19a5dc1531af5df6f58ec8fadb41fe51c7afc3d..f7d7b6fec9350fdfe01541716cee357fdf530435 100644 (file)
@@ -5,8 +5,8 @@
 
 enum {
        RDMA_NL_RDMA_CM = 1,
-       RDMA_NL_NES,
-       RDMA_NL_C4IW,
+       RDMA_NL_IWCM,
+       RDMA_NL_RSVD,
        RDMA_NL_LS,     /* RDMA Local Services */
        RDMA_NL_NUM_CLIENTS
 };