[PATCH for-next V2 11/11] IB/cma: Join and leave multicast groups with IGMP

2015-12-03 Thread Matan Barak
From: Moni Shoua 

Since RoCEv2 is a protocol over IP header it is required to send IGMP
join and leave requests to the network when joining and leaving
multicast groups.

Signed-off-by: Moni Shoua 
---
 drivers/infiniband/core/cma.c   | 96 ++---
 drivers/infiniband/core/multicast.c | 17 ++-
 include/rdma/ib_sa.h|  2 +
 3 files changed, 106 insertions(+), 9 deletions(-)

diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 8fab267..c30bfe3 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -38,6 +38,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -304,6 +305,7 @@ struct cma_multicast {
void*context;
struct sockaddr_storage addr;
struct kref mcref;
+   booligmp_joined;
 };
 
 struct cma_work {
@@ -400,6 +402,26 @@ static inline void cma_set_ip_ver(struct cma_hdr *hdr, u8 
ip_ver)
hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF);
 }
 
+static int cma_igmp_send(struct net_device *ndev, union ib_gid *mgid, bool 
join)
+{
+   struct in_device *in_dev = NULL;
+
+   if (ndev) {
+   rtnl_lock();
+   in_dev = __in_dev_get_rtnl(ndev);
+   if (in_dev) {
+   if (join)
+   ip_mc_inc_group(in_dev,
+   *(__be32 *)(mgid->raw + 12));
+   else
+   ip_mc_dec_group(in_dev,
+   *(__be32 *)(mgid->raw + 12));
+   }
+   rtnl_unlock();
+   }
+   return (in_dev) ? 0 : -ENODEV;
+}
+
 static void _cma_attach_to_dev(struct rdma_id_private *id_priv,
   struct cma_device *cma_dev)
 {
@@ -1535,8 +1557,24 @@ static void cma_leave_mc_groups(struct rdma_id_private 
*id_priv)
  id_priv->id.port_num)) {
ib_sa_free_multicast(mc->multicast.ib);
kfree(mc);
-   } else
+   } else {
+   if (mc->igmp_joined) {
+   struct rdma_dev_addr *dev_addr =
+   _priv->id.route.addr.dev_addr;
+   struct net_device *ndev = NULL;
+
+   if (dev_addr->bound_dev_if)
+   ndev = dev_get_by_index(_net,
+   
dev_addr->bound_dev_if);
+   if (ndev) {
+   cma_igmp_send(ndev,
+ 
>multicast.ib->rec.mgid,
+ false);
+   dev_put(ndev);
+   }
+   }
kref_put(>mcref, release_mc);
+   }
}
 }
 
@@ -3656,12 +3694,23 @@ static int cma_ib_mc_handler(int status, struct 
ib_sa_multicast *multicast)
event.status = status;
event.param.ud.private_data = mc->context;
if (!status) {
+   struct rdma_dev_addr *dev_addr =
+   _priv->id.route.addr.dev_addr;
+   struct net_device *ndev =
+   dev_get_by_index(_net, dev_addr->bound_dev_if);
+   enum ib_gid_type gid_type =
+   id_priv->cma_dev->default_gid_type[id_priv->id.port_num 
-
+   rdma_start_port(id_priv->cma_dev->device)];
+
event.event = RDMA_CM_EVENT_MULTICAST_JOIN;
ib_init_ah_from_mcmember(id_priv->id.device,
 id_priv->id.port_num, >rec,
+ndev, gid_type,
 _attr);
event.param.ud.qp_num = 0xFF;
event.param.ud.qkey = be32_to_cpu(multicast->rec.qkey);
+   if (ndev)
+   dev_put(ndev);
} else
event.event = RDMA_CM_EVENT_MULTICAST_ERROR;
 
@@ -3794,9 +3843,10 @@ static int cma_iboe_join_multicast(struct 
rdma_id_private *id_priv,
 {
struct iboe_mcast_work *work;
struct rdma_dev_addr *dev_addr = _priv->id.route.addr.dev_addr;
-   int err;
+   int err = 0;
struct sockaddr *addr = (struct sockaddr *)>addr;
struct net_device *ndev = NULL;
+   enum ib_gid_type gid_type;
 
if (cma_zero_addr((struct sockaddr *)>addr))
return -EINVAL;
@@ -3826,9 +3876,25 @@ static int cma_iboe_join_multicast(struct 
rdma_id_private *id_priv,
mc->multicast.ib->rec.rate = iboe_get_rate(ndev);

[PATCH for-next V2 11/11] IB/cma: Join and leave multicast groups with IGMP

2015-12-03 Thread Matan Barak
From: Moni Shoua 

Since RoCEv2 is a protocol over IP header it is required to send IGMP
join and leave requests to the network when joining and leaving
multicast groups.

Signed-off-by: Moni Shoua 
---
 drivers/infiniband/core/cma.c   | 96 ++---
 drivers/infiniband/core/multicast.c | 17 ++-
 include/rdma/ib_sa.h|  2 +
 3 files changed, 106 insertions(+), 9 deletions(-)

diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 8fab267..c30bfe3 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -38,6 +38,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -304,6 +305,7 @@ struct cma_multicast {
void*context;
struct sockaddr_storage addr;
struct kref mcref;
+   booligmp_joined;
 };
 
 struct cma_work {
@@ -400,6 +402,26 @@ static inline void cma_set_ip_ver(struct cma_hdr *hdr, u8 
ip_ver)
hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF);
 }
 
+static int cma_igmp_send(struct net_device *ndev, union ib_gid *mgid, bool 
join)
+{
+   struct in_device *in_dev = NULL;
+
+   if (ndev) {
+   rtnl_lock();
+   in_dev = __in_dev_get_rtnl(ndev);
+   if (in_dev) {
+   if (join)
+   ip_mc_inc_group(in_dev,
+   *(__be32 *)(mgid->raw + 12));
+   else
+   ip_mc_dec_group(in_dev,
+   *(__be32 *)(mgid->raw + 12));
+   }
+   rtnl_unlock();
+   }
+   return (in_dev) ? 0 : -ENODEV;
+}
+
 static void _cma_attach_to_dev(struct rdma_id_private *id_priv,
   struct cma_device *cma_dev)
 {
@@ -1535,8 +1557,24 @@ static void cma_leave_mc_groups(struct rdma_id_private 
*id_priv)
  id_priv->id.port_num)) {
ib_sa_free_multicast(mc->multicast.ib);
kfree(mc);
-   } else
+   } else {
+   if (mc->igmp_joined) {
+   struct rdma_dev_addr *dev_addr =
+   _priv->id.route.addr.dev_addr;
+   struct net_device *ndev = NULL;
+
+   if (dev_addr->bound_dev_if)
+   ndev = dev_get_by_index(_net,
+   
dev_addr->bound_dev_if);
+   if (ndev) {
+   cma_igmp_send(ndev,
+ 
>multicast.ib->rec.mgid,
+ false);
+   dev_put(ndev);
+   }
+   }
kref_put(>mcref, release_mc);
+   }
}
 }
 
@@ -3656,12 +3694,23 @@ static int cma_ib_mc_handler(int status, struct 
ib_sa_multicast *multicast)
event.status = status;
event.param.ud.private_data = mc->context;
if (!status) {
+   struct rdma_dev_addr *dev_addr =
+   _priv->id.route.addr.dev_addr;
+   struct net_device *ndev =
+   dev_get_by_index(_net, dev_addr->bound_dev_if);
+   enum ib_gid_type gid_type =
+   id_priv->cma_dev->default_gid_type[id_priv->id.port_num 
-
+   rdma_start_port(id_priv->cma_dev->device)];
+
event.event = RDMA_CM_EVENT_MULTICAST_JOIN;
ib_init_ah_from_mcmember(id_priv->id.device,
 id_priv->id.port_num, >rec,
+ndev, gid_type,
 _attr);
event.param.ud.qp_num = 0xFF;
event.param.ud.qkey = be32_to_cpu(multicast->rec.qkey);
+   if (ndev)
+   dev_put(ndev);
} else
event.event = RDMA_CM_EVENT_MULTICAST_ERROR;
 
@@ -3794,9 +3843,10 @@ static int cma_iboe_join_multicast(struct 
rdma_id_private *id_priv,
 {
struct iboe_mcast_work *work;
struct rdma_dev_addr *dev_addr = _priv->id.route.addr.dev_addr;
-   int err;
+   int err = 0;
struct sockaddr *addr = (struct sockaddr *)>addr;
struct net_device *ndev = NULL;
+   enum ib_gid_type gid_type;
 
if (cma_zero_addr((struct sockaddr *)>addr))
return -EINVAL;
@@ -3826,9 +3876,25 @@ static int cma_iboe_join_multicast(struct 
rdma_id_private *id_priv,
mc->multicast.ib->rec.rate = iboe_get_rate(ndev);