Commit 3c86aa70 authored by Eli Cohen's avatar Eli Cohen Committed by Roland Dreier

RDMA/cm: Add RDMA CM support for IBoE devices

Add support for IBoE device binding and IP --> GID resolution.  Path
resolving and multicast joining are implemented within cma.c by
filling in the responses and running callbacks in the CMA work queue.

IP --> GID resolution always yields IPv6 link local addresses; remote
GIDs are derived from the destination MAC address of the remote port.
Multicast GIDs are always mapped to multicast MACs as is done in IPv6.
(IPv4 multicast is enabled by translating IPv4 multicast addresses to
IPv6 multicast as described in
<http://www.mail-archive.com/ipng@sunroof.eng.sun.com/msg02134.html>.)

Some helper functions are added to ib_addr.h.
Signed-off-by: default avatarEli Cohen <eli@mellanox.co.il>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent fac70d51
This diff is collapsed.
......@@ -496,6 +496,7 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num,
{
int ret;
u16 gid_index;
int force_grh;
memset(ah_attr, 0, sizeof *ah_attr);
ah_attr->dlid = be16_to_cpu(rec->dlid);
......@@ -505,7 +506,9 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num,
ah_attr->port_num = port_num;
ah_attr->static_rate = rec->rate;
if (rec->hop_limit > 1) {
force_grh = rdma_port_get_link_layer(device, port_num) == IB_LINK_LAYER_ETHERNET;
if (rec->hop_limit > 1 || force_grh) {
ah_attr->ah_flags = IB_AH_GRH;
ah_attr->grh.dgid = rec->dgid;
......
......@@ -583,6 +583,34 @@ static void ucma_copy_ib_route(struct rdma_ucm_query_route_resp *resp,
}
}
static void ucma_copy_iboe_route(struct rdma_ucm_query_route_resp *resp,
struct rdma_route *route)
{
struct rdma_dev_addr *dev_addr;
resp->num_paths = route->num_paths;
switch (route->num_paths) {
case 0:
dev_addr = &route->addr.dev_addr;
iboe_mac_to_ll((union ib_gid *) &resp->ib_route[0].dgid,
dev_addr->dst_dev_addr);
iboe_addr_get_sgid(dev_addr,
(union ib_gid *) &resp->ib_route[0].sgid);
resp->ib_route[0].pkey = cpu_to_be16(0xffff);
break;
case 2:
ib_copy_path_rec_to_user(&resp->ib_route[1],
&route->path_rec[1]);
/* fall through */
case 1:
ib_copy_path_rec_to_user(&resp->ib_route[0],
&route->path_rec[0]);
break;
default:
break;
}
}
static ssize_t ucma_query_route(struct ucma_file *file,
const char __user *inbuf,
int in_len, int out_len)
......@@ -617,12 +645,17 @@ static ssize_t ucma_query_route(struct ucma_file *file,
resp.node_guid = (__force __u64) ctx->cm_id->device->node_guid;
resp.port_num = ctx->cm_id->port_num;
switch (rdma_node_get_transport(ctx->cm_id->device->node_type)) {
case RDMA_TRANSPORT_IB:
ucma_copy_ib_route(&resp, &ctx->cm_id->route);
break;
default:
break;
if (rdma_node_get_transport(ctx->cm_id->device->node_type) == RDMA_TRANSPORT_IB) {
switch (rdma_port_get_link_layer(ctx->cm_id->device, ctx->cm_id->port_num)) {
case IB_LINK_LAYER_INFINIBAND:
ucma_copy_ib_route(&resp, &ctx->cm_id->route);
break;
case IB_LINK_LAYER_ETHERNET:
ucma_copy_iboe_route(&resp, &ctx->cm_id->route);
break;
default:
break;
}
}
out:
......
......@@ -40,6 +40,7 @@
#include <linux/netdevice.h>
#include <linux/socket.h>
#include <rdma/ib_verbs.h>
#include <rdma/ib_pack.h>
struct rdma_addr_client {
atomic_t refcount;
......@@ -63,6 +64,7 @@ struct rdma_dev_addr {
unsigned char broadcast[MAX_ADDR_LEN];
unsigned short dev_type;
int bound_dev_if;
enum rdma_transport_type transport;
};
/**
......@@ -127,9 +129,31 @@ static inline int rdma_addr_gid_offset(struct rdma_dev_addr *dev_addr)
return dev_addr->dev_type == ARPHRD_INFINIBAND ? 4 : 0;
}
static inline void iboe_mac_to_ll(union ib_gid *gid, u8 *mac)
{
memset(gid->raw, 0, 16);
*((__be32 *) gid->raw) = cpu_to_be32(0xfe800000);
gid->raw[12] = 0xfe;
gid->raw[11] = 0xff;
memcpy(gid->raw + 13, mac + 3, 3);
memcpy(gid->raw + 8, mac, 3);
gid->raw[8] ^= 2;
}
static inline void iboe_addr_get_sgid(struct rdma_dev_addr *dev_addr,
union ib_gid *gid)
{
iboe_mac_to_ll(gid, dev_addr->src_dev_addr);
}
static inline void rdma_addr_get_sgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid)
{
memcpy(gid, dev_addr->src_dev_addr + rdma_addr_gid_offset(dev_addr), sizeof *gid);
if (dev_addr->transport == RDMA_TRANSPORT_IB &&
dev_addr->dev_type != ARPHRD_INFINIBAND)
iboe_addr_get_sgid(dev_addr, gid);
else
memcpy(gid, dev_addr->src_dev_addr +
rdma_addr_gid_offset(dev_addr), sizeof *gid);
}
static inline void rdma_addr_set_sgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid)
......@@ -147,4 +171,77 @@ static inline void rdma_addr_set_dgid(struct rdma_dev_addr *dev_addr, union ib_g
memcpy(dev_addr->dst_dev_addr + rdma_addr_gid_offset(dev_addr), gid, sizeof *gid);
}
static inline enum ib_mtu iboe_get_mtu(int mtu)
{
/*
* reduce IB headers from effective IBoE MTU. 28 stands for
* atomic header which is the biggest possible header after BTH
*/
mtu = mtu - IB_GRH_BYTES - IB_BTH_BYTES - 28;
if (mtu >= ib_mtu_enum_to_int(IB_MTU_4096))
return IB_MTU_4096;
else if (mtu >= ib_mtu_enum_to_int(IB_MTU_2048))
return IB_MTU_2048;
else if (mtu >= ib_mtu_enum_to_int(IB_MTU_1024))
return IB_MTU_1024;
else if (mtu >= ib_mtu_enum_to_int(IB_MTU_512))
return IB_MTU_512;
else if (mtu >= ib_mtu_enum_to_int(IB_MTU_256))
return IB_MTU_256;
else
return 0;
}
static inline int iboe_get_rate(struct net_device *dev)
{
struct ethtool_cmd cmd;
if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings ||
dev->ethtool_ops->get_settings(dev, &cmd))
return IB_RATE_PORT_CURRENT;
if (cmd.speed >= 40000)
return IB_RATE_40_GBPS;
else if (cmd.speed >= 30000)
return IB_RATE_30_GBPS;
else if (cmd.speed >= 20000)
return IB_RATE_20_GBPS;
else if (cmd.speed >= 10000)
return IB_RATE_10_GBPS;
else
return IB_RATE_PORT_CURRENT;
}
static inline int rdma_link_local_addr(struct in6_addr *addr)
{
if (addr->s6_addr32[0] == htonl(0xfe800000) &&
addr->s6_addr32[1] == 0)
return 1;
return 0;
}
static inline void rdma_get_ll_mac(struct in6_addr *addr, u8 *mac)
{
memcpy(mac, &addr->s6_addr[8], 3);
memcpy(mac + 3, &addr->s6_addr[13], 3);
mac[0] ^= 2;
}
static inline int rdma_is_multicast_addr(struct in6_addr *addr)
{
return addr->s6_addr[0] == 0xff;
}
static inline void rdma_get_mcast_mac(struct in6_addr *addr, u8 *mac)
{
int i;
mac[0] = 0x33;
mac[1] = 0x33;
for (i = 2; i < 6; ++i)
mac[i] = addr->s6_addr[i + 10];
}
#endif /* IB_ADDR_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment