<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 TRANSITIONAL//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8">
<META NAME="GENERATOR" CONTENT="GtkHTML/3.18.1">
</HEAD>
<BODY>
Patch adds IPv6 support for RDMA CM operations. It provides basic support and have limitations bellow:<BR>
<BR>
No support for link-local addresses.<BR>
Can't use mixed IPv6 and IPv4 addresses as source and destinations<BR>
Not perform checks against ANYCAST address type.<BR>
<BR>
<BR>
Details:<BR>
<BR>
struct addr_req extended to support sockaddr_in6 family<BR>
Functions like address_resolve_local, addr_resolve_remote changed to get pointer to generic sockaddr struct insted of sockadd_in. Such functions used as upper layer, and after parsing sa_family call corresponding IPv6 ot IPv4 function.<BR>
To perform network discovery and to symbols should be exported:<BR>
nd_table<BR>
ndisc_send_ns<BR>
<BR>
The points that must be improved to specified above are:<BR>
recognition of local device by given IP address<BR>
sending network discovery without exporting symbols<BR>
<BR>
<BR>
Waiting for feedback, suggestions. <BR>
<BR>
<BR>
-----------------<BR>
<BR>
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c<BR>
index 09a2bec..3c3f665 100644<BR>
--- a/drivers/infiniband/core/addr.c<BR>
+++ b/drivers/infiniband/core/addr.c<BR>
@@ -38,10 +38,13 @@<BR>
#include <linux/workqueue.h><BR>
#include <linux/if_arp.h><BR>
#include <net/arp.h><BR>
+#include <net/ndisc.h><BR>
+#include <net/ip6_route.h><BR>
#include <net/neighbour.h><BR>
#include <net/route.h><BR>
#include <net/netevent.h><BR>
#include <rdma/ib_addr.h><BR>
+#include <net/addrconf.h><BR>
<BR>
MODULE_AUTHOR("Sean Hefty");<BR>
MODULE_DESCRIPTION("IB Address Translation");<BR>
@@ -50,7 +53,9 @@ MODULE_LICENSE("Dual BSD/GPL");<BR>
struct addr_req {<BR>
struct list_head list;<BR>
struct sockaddr src_addr;<BR>
+ u8 src_pad[sizeof(struct sockaddr_in6) - sizeof(struct sockaddr)];<BR>
struct sockaddr dst_addr;<BR>
+ u8 dst_pad[sizeof(struct sockaddr_in6) - sizeof(struct sockaddr)];<BR>
struct rdma_dev_addr *addr;<BR>
struct rdma_addr_client *client;<BR>
void *context;<BR>
@@ -113,15 +118,24 @@ EXPORT_SYMBOL(rdma_copy_addr);<BR>
int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)<BR>
{<BR>
struct net_device *dev;<BR>
- __be32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr;<BR>
int ret;<BR>
<BR>
- dev = ip_dev_find(&init_net, ip);<BR>
- if (!dev)<BR>
+ if (addr->sa_family == AF_INET ) {<BR>
+ __be32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr;<BR>
+ dev = ip_dev_find(&init_net, ip);<BR>
+ if (!dev)<BR>
return -EADDRNOTAVAIL;<BR>
<BR>
- ret = rdma_copy_addr(dev_addr, dev, NULL);<BR>
- dev_put(dev);<BR>
+ ret = rdma_copy_addr(dev_addr, dev, NULL);<BR>
+ dev_put(dev);<BR>
+ } else {<BR>
+ for_each_netdev(&init_net, dev)<BR>
+ if ( ipv6_chk_addr(&init_net, &((struct sockaddr_in6*)addr)->sin6_addr, dev, 1) ) {<BR>
+ ret = rdma_copy_addr(dev_addr, dev, NULL);<BR>
+ break;<BR>
+ }<BR>
+ }<BR>
+<BR>
return ret;<BR>
}<BR>
EXPORT_SYMBOL(rdma_translate_ip);<BR>
@@ -171,7 +185,8 @@ static void addr_send_arp(struct sockaddr_in *dst_in)<BR>
ip_rt_put(rt);<BR>
}<BR>
<BR>
-static int addr_resolve_remote(struct sockaddr_in *src_in,<BR>
+<BR>
+static int addr4_resolve_remote(struct sockaddr_in *src_in,<BR>
struct sockaddr_in *dst_in,<BR>
struct rdma_dev_addr *addr)<BR>
{<BR>
@@ -220,10 +235,78 @@ out:<BR>
return ret;<BR>
}<BR>
<BR>
+static int addr6_resolve_remote(struct sockaddr_in6 *src_in,<BR>
+ struct sockaddr_in6 *dst_in,<BR>
+ struct rdma_dev_addr *addr)<BR>
+{<BR>
+<BR>
+ struct neighbour *neigh;<BR>
+ int ret=-ENODATA;<BR>
+ struct dst_entry *dst;<BR>
+ struct in6_addr *target;<BR>
+ struct in6_addr mcaddr;<BR>
+<BR>
+ struct flowi fl = {<BR>
+ .nl_u = {<BR>
+ .ip6_u = {<BR>
+ .daddr = dst_in->sin6_addr,<BR>
+ .saddr = src_in->sin6_addr,<BR>
+ },<BR>
+ },<BR>
+ };<BR>
+<BR>
+ dst = ip6_route_output(&init_net, NULL, &fl);<BR>
+ if(!dst)<BR>
+ goto out;<BR>
+<BR>
+ /* If the device does ARP internally, return 'done' */<BR>
+ if (dst->dev->flags & IFF_NOARP) {<BR>
+ ret = rdma_copy_addr(addr, dst->dev, NULL);<BR>
+ goto put;<BR>
+ }<BR>
+<BR>
+ neigh = ndisc_get_neigh(dst->dev, &dst_in->sin6_addr);<BR>
+ if (!neigh) {<BR>
+ ret = -ENOMEM;<BR>
+ goto put;<BR>
+ }<BR>
+<BR>
+ if (!(neigh->nud_state & NUD_VALID)) {<BR>
+ target = (struct in6_addr*)&neigh->primary_key;<BR>
+ addrconf_addr_solict_mult(target, &mcaddr);<BR>
+ ndisc_send_ns(dst->dev, neigh, target, &mcaddr , NULL);<BR>
+ /* ret = rdma_copy_addr(addr, neigh->dev, neigh->ha); */<BR>
+<BR>
+ ret = -ENODATA;<BR>
+ goto release;<BR>
+ }<BR>
+ ret = rdma_copy_addr(addr, neigh->dev, neigh->ha);<BR>
+<BR>
+<BR>
+release:<BR>
+ neigh_release(neigh);<BR>
+put:<BR>
+ dst_release(dst);<BR>
+out:<BR>
+ return ret;<BR>
+}<BR>
+<BR>
+static int addr_resolve_remote(struct sockaddr *src_in,<BR>
+ struct sockaddr *dst_in,<BR>
+ struct rdma_dev_addr *addr)<BR>
+{<BR>
+ int ret = -ENODATA;<BR>
+ if ( src_in->sa_family == AF_INET ) {<BR>
+ ret = addr4_resolve_remote((struct sockaddr_in*)src_in, (struct sockaddr_in*)dst_in, addr);<BR>
+ } else if ( src_in->sa_family == AF_INET6 ) {<BR>
+ ret = addr6_resolve_remote((struct sockaddr_in6*)src_in, (struct sockaddr_in6*)dst_in, addr);<BR>
+ }<BR>
+ return ret;<BR>
+}<BR>
+<BR>
static void process_req(struct work_struct *work)<BR>
{<BR>
struct addr_req *req, *temp_req;<BR>
- struct sockaddr_in *src_in, *dst_in;<BR>
struct list_head done_list;<BR>
<BR>
INIT_LIST_HEAD(&done_list);<BR>
@@ -231,10 +314,7 @@ static void process_req(struct work_struct *work)<BR>
mutex_lock(&lock);<BR>
list_for_each_entry_safe(req, temp_req, &req_list, list) {<BR>
if (req->status == -ENODATA) {<BR>
- src_in = (struct sockaddr_in *) &req->src_addr;<BR>
- dst_in = (struct sockaddr_in *) &req->dst_addr;<BR>
- req->status = addr_resolve_remote(src_in, dst_in,<BR>
- req->addr);<BR>
+ req->status = addr_resolve_remote(&req->src_addr, &req->dst_addr, req->addr);<BR>
if (req->status && time_after_eq(jiffies, req->timeout))<BR>
req->status = -ETIMEDOUT;<BR>
else if (req->status == -ENODATA)<BR>
@@ -258,7 +338,7 @@ static void process_req(struct work_struct *work)<BR>
}<BR>
}<BR>
<BR>
-static int addr_resolve_local(struct sockaddr_in *src_in,<BR>
+static int addr4_resolve_local(struct sockaddr_in *src_in,<BR>
struct sockaddr_in *dst_in,<BR>
struct rdma_dev_addr *addr)<BR>
{<BR>
@@ -289,6 +369,24 @@ static int addr_resolve_local(struct sockaddr_in *src_in,<BR>
return ret;<BR>
}<BR>
<BR>
+static int addr6_resolve_local(struct sockaddr_in6 *src_in,<BR>
+ struct sockaddr_in6 *dst_in,<BR>
+ struct rdma_dev_addr *addr)<BR>
+{<BR>
+ return -EADDRNOTAVAIL;<BR>
+}<BR>
+<BR>
+static int addr_resolve_local(struct sockaddr *src_in,<BR>
+ struct sockaddr *dst_in,<BR>
+ struct rdma_dev_addr *addr)<BR>
+{<BR>
+ if ( src_in->sa_family == AF_INET ) {<BR>
+ return addr4_resolve_local((struct sockaddr_in*)src_in, (struct sockaddr_in*)dst_in, addr);<BR>
+ } else<BR>
+ return addr6_resolve_local((struct sockaddr_in6*)src_in, (struct sockaddr_in6*)dst_in, addr);<BR>
+}<BR>
+<BR>
+<BR>
int rdma_resolve_ip(struct rdma_addr_client *client,<BR>
struct sockaddr *src_addr, struct sockaddr *dst_addr,<BR>
struct rdma_dev_addr *addr, int timeout_ms,<BR>
@@ -296,7 +394,6 @@ int rdma_resolve_ip(struct rdma_addr_client *client,<BR>
struct rdma_dev_addr *addr, void *context),<BR>
void *context)<BR>
{<BR>
- struct sockaddr_in *src_in, *dst_in;<BR>
struct addr_req *req;<BR>
int ret = 0;<BR>
<BR>
@@ -313,12 +410,10 @@ int rdma_resolve_ip(struct rdma_addr_client *client,<BR>
req->client = client;<BR>
atomic_inc(&client->refcount);<BR>
<BR>
- src_in = (struct sockaddr_in *) &req->src_addr;<BR>
- dst_in = (struct sockaddr_in *) &req->dst_addr;<BR>
-<BR>
- req->status = addr_resolve_local(src_in, dst_in, addr);<BR>
- if (req->status == -EADDRNOTAVAIL)<BR>
- req->status = addr_resolve_remote(src_in, dst_in, addr);<BR>
+ req->status = addr_resolve_local(&req->src_addr, &req->dst_addr, addr);<BR>
+ if (req->status == -EADDRNOTAVAIL) {<BR>
+ req->status = addr_resolve_remote(&req->src_addr, &req->dst_addr, addr);<BR>
+ }<BR>
<BR>
switch (req->status) {<BR>
case 0:<BR>
@@ -328,7 +423,8 @@ int rdma_resolve_ip(struct rdma_addr_client *client,<BR>
case -ENODATA:<BR>
req->timeout = msecs_to_jiffies(timeout_ms) + jiffies;<BR>
queue_req(req);<BR>
- addr_send_arp(dst_in);<BR>
+ if(req->dst_addr.sa_family == AF_INET )<BR>
+ addr_send_arp((struct sockaddr_in*)&req->dst_addr);<BR>
break;<BR>
default:<BR>
ret = req->status;<BR>
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c<BR>
index e980ff3..87ae995 100644<BR>
--- a/drivers/infiniband/core/cma.c<BR>
+++ b/drivers/infiniband/core/cma.c<BR>
@@ -2074,7 +2074,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)<BR>
struct rdma_id_private *id_priv;<BR>
int ret;<BR>
<BR>
- if (addr->sa_family != AF_INET)<BR>
+ if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6 )<BR>
return -EAFNOSUPPORT;<BR>
<BR>
id_priv = container_of(id, struct rdma_id_private, id);<BR>
@@ -2115,30 +2115,58 @@ static int cma_format_hdr(void *hdr, enum rdma_port_space ps,<BR>
struct rdma_route *route)<BR>
{<BR>
struct sockaddr_in *src4, *dst4;<BR>
+ struct sockaddr_in6 *src6, *dst6;<BR>
struct cma_hdr *cma_hdr;<BR>
struct sdp_hh *sdp_hdr;<BR>
-<BR>
- src4 = (struct sockaddr_in *) &route->addr.src_addr;<BR>
- dst4 = (struct sockaddr_in *) &route->addr.dst_addr;<BR>
-<BR>
- switch (ps) {<BR>
- case RDMA_PS_SDP:<BR>
- sdp_hdr = hdr;<BR>
- if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)<BR>
- return -EINVAL;<BR>
- sdp_set_ip_ver(sdp_hdr, 4);<BR>
- sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;<BR>
- sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;<BR>
- sdp_hdr->port = src4->sin_port;<BR>
- break;<BR>
- default:<BR>
- cma_hdr = hdr;<BR>
- cma_hdr->cma_version = CMA_VERSION;<BR>
- cma_set_ip_ver(cma_hdr, 4);<BR>
- cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;<BR>
- cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;<BR>
- cma_hdr->port = src4->sin_port;<BR>
- break;<BR>
+ if ( route->addr.src_addr.sa_family == AF_INET) {<BR>
+ src4 = (struct sockaddr_in *) &route->addr.src_addr;<BR>
+ dst4 = (struct sockaddr_in *) &route->addr.dst_addr;<BR>
+ }else if (route->addr.src_addr.sa_family == AF_INET6) {<BR>
+ src6 = (struct sockaddr_in6 *) &route->addr.src_addr;<BR>
+ dst6 = (struct sockaddr_in6 *) &route->addr.dst_addr;<BR>
+ }else<BR>
+ return -EINVAL;<BR>
+<BR>
+ if ( route->addr.src_addr.sa_family == AF_INET) {<BR>
+ switch (ps) {<BR>
+ case RDMA_PS_SDP:<BR>
+ sdp_hdr = hdr;<BR>
+ if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)<BR>
+ return -EINVAL;<BR>
+ sdp_set_ip_ver(sdp_hdr, 4);<BR>
+ sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;<BR>
+ sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;<BR>
+ sdp_hdr->port = src4->sin_port;<BR>
+ break;<BR>
+ default:<BR>
+ cma_hdr = hdr;<BR>
+ cma_hdr->cma_version = CMA_VERSION;<BR>
+ cma_set_ip_ver(cma_hdr, 4);<BR>
+ cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;<BR>
+ cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;<BR>
+ cma_hdr->port = src4->sin_port;<BR>
+ break;<BR>
+ }<BR>
+ }else {<BR>
+ switch (ps) {<BR>
+ case RDMA_PS_SDP:<BR>
+ sdp_hdr = hdr;<BR>
+ if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)<BR>
+ return -EINVAL;<BR>
+ sdp_set_ip_ver(sdp_hdr, 6);<BR>
+ sdp_hdr->src_addr.ip6 = src6->sin6_addr;<BR>
+ sdp_hdr->dst_addr.ip6 = dst6->sin6_addr;<BR>
+ sdp_hdr->port = src6->sin6_port;<BR>
+ break;<BR>
+ default:<BR>
+ cma_hdr = hdr;<BR>
+ cma_hdr->cma_version = CMA_VERSION;<BR>
+ cma_set_ip_ver(cma_hdr, 6);<BR>
+ cma_hdr->src_addr.ip6 = src6->sin6_addr;<BR>
+ cma_hdr->dst_addr.ip6 = dst6->sin6_addr;<BR>
+ cma_hdr->port = src6->sin6_port;<BR>
+ break;<BR>
+ }<BR>
}<BR>
return 0;<BR>
}<BR>
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c<BR>
index beb48e3..fb1f59c 100644<BR>
--- a/net/ipv6/ndisc.c<BR>
+++ b/net/ipv6/ndisc.c<BR>
@@ -157,6 +157,7 @@ struct neigh_table nd_tbl = {<BR>
.gc_thresh3 = 1024,<BR>
};<BR>
<BR>
+EXPORT_SYMBOL(nd_tbl);<BR>
/* ND options */<BR>
struct ndisc_options {<BR>
struct nd_opt_hdr *nd_opt_array[__ND_OPT_ARRAY_MAX];<BR>
@@ -586,6 +587,8 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,<BR>
!ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0);<BR>
}<BR>
<BR>
+EXPORT_SYMBOL(ndisc_send_ns);<BR>
+<BR>
void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,<BR>
const struct in6_addr *daddr)<BR>
{<BR>
<BR>
</BODY>
</HTML>