From: Amir Vadai Date: Mon, 27 Dec 2010 09:58:26 +0000 (+0200) Subject: sdp: ipv6 support X-Git-Tag: v4.1.12-92~264^2~5^2~53 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=f9e9eade23370be7b5594d6d4b457d7a848604f2;p=users%2Fjedix%2Flinux-maple.git sdp: ipv6 support Signed-off-by: Amir Vadai --- diff --git a/drivers/infiniband/ulp/sdp/sdp.h b/drivers/infiniband/ulp/sdp/sdp.h index 5bce6caa1c650..828f3c5802109 100644 --- a/drivers/infiniband/ulp/sdp/sdp.h +++ b/drivers/infiniband/ulp/sdp/sdp.h @@ -12,6 +12,36 @@ #include #include "sdp_dbg.h" +#ifndef NIPQUAD +#define NIPQUAD(addr) \ + ((unsigned char *)&addr)[0], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[3] +#endif + +#ifndef NIPQUAD_FMT +#define NIPQUAD_FMT "%u.%u.%u.%u" +#endif + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +#ifndef NIP6 +#define NIP6(addr) \ + ntohs((addr).s6_addr16[0]), \ + ntohs((addr).s6_addr16[1]), \ + ntohs((addr).s6_addr16[2]), \ + ntohs((addr).s6_addr16[3]), \ + ntohs((addr).s6_addr16[4]), \ + ntohs((addr).s6_addr16[5]), \ + ntohs((addr).s6_addr16[6]), \ + ntohs((addr).s6_addr16[7]) +#endif + +#ifndef NIP6_FMT +#define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" +#endif +#endif + #define sk_ssk(ssk) ((struct sock *)ssk) /* Interval between sucessive polls in the Tx routine when polling is used @@ -455,6 +485,9 @@ struct sdp_sock { int inline_thresh; int last_bind_err; + + /* ipv6_pinfo has to be the last member of tcp6_sock, see inet6_sk_generic */ + struct ipv6_pinfo inet6; }; static inline void tx_sa_reset(struct tx_srcavail_state *tx_sa) diff --git a/drivers/infiniband/ulp/sdp/sdp_cma.c b/drivers/infiniband/ulp/sdp/sdp_cma.c index bc1bf172e84dc..d06c01b6f9676 100644 --- a/drivers/infiniband/ulp/sdp/sdp_cma.c +++ b/drivers/infiniband/ulp/sdp/sdp_cma.c @@ -381,7 +381,12 @@ int sdp_cma_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) hh.bsdh.mid = SDP_MID_HELLO; hh.bsdh.len = htonl(sizeof(struct sdp_hh)); hh.max_adverts = 1; - hh.ipv_cap = 0x40; + + hh.ipv_cap = +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + inet6_sk(sk) ? 0x60 : +#endif + 0x40; hh.majv_minv = SDP_MAJV_MINV; sdp_init_buffers(sdp_sk(sk), rcvbuf_initial_size); hh.bsdh.bufs = htons(rx_ring_posted(sdp_sk(sk))); @@ -389,8 +394,17 @@ int sdp_cma_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) rx_ring_posted(sdp_sk(sk))); hh.localrcvsz = hh.desremrcvsz = htonl(sdp_sk(sk)->recv_frags * PAGE_SIZE + sizeof(struct sdp_bsdh)); - inet_sk(sk)->saddr = inet_sk(sk)->rcv_saddr = - ((struct sockaddr_in *)&id->route.addr.src_addr)->sin_addr.s_addr; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + if (inet6_sk(sk)) { + inet6_sk(sk)->saddr = inet6_sk(sk)->rcv_saddr = + ((struct sockaddr_in6 *)&id->route.addr.src_addr)->sin6_addr; + } + else +#endif + { + inet_sk(sk)->saddr = inet_sk(sk)->rcv_saddr = + ((struct sockaddr_in *)&id->route.addr.src_addr)->sin_addr.s_addr; + } memset(&conn_param, 0, sizeof conn_param); conn_param.private_data_len = sizeof hh; conn_param.private_data = &hh; diff --git a/drivers/infiniband/ulp/sdp/sdp_main.c b/drivers/infiniband/ulp/sdp/sdp_main.c index 7824ebd6023e3..f92d645605fb5 100644 --- a/drivers/infiniband/ulp/sdp/sdp_main.c +++ b/drivers/infiniband/ulp/sdp/sdp_main.c @@ -67,6 +67,7 @@ unsigned int csum_partial_copy_from_user_new (const char *src, char *dst, #include #include #include +#include #include #include #include @@ -149,17 +150,12 @@ static int sdp_get_port(struct sock *sk, unsigned short snum) { struct sdp_sock *ssk = sdp_sk(sk); struct sockaddr_in *src_addr; + int addr_len; int rc; - struct sockaddr_in addr = { - .sin_family = AF_INET, - .sin_port = htons(snum), - .sin_addr.s_addr = inet_sk(sk)->rcv_saddr, - }; + struct sockaddr_storage addr; sdp_add_to_history(sk, __func__); - sdp_dbg(sk, "%s: %u.%u.%u.%u:%hu\n", __func__, - NIPQUAD(addr.sin_addr.s_addr), ntohs(addr.sin_port)); if (!ssk->id) ssk->id = rdma_create_id(sdp_cma_handler, sk, RDMA_PS_SDP); @@ -167,9 +163,36 @@ static int sdp_get_port(struct sock *sk, unsigned short snum) if (!ssk->id) return -ENOMEM; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + if (inet6_sk(sk)) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; + addr6->sin6_family = AF_INET6, + addr6->sin6_port = htons(snum), + ipv6_addr_copy(&addr6->sin6_addr, &inet6_sk(sk)->rcv_saddr); + + addr_len = sizeof addr6; + + sdp_dbg(sk, "%s: " NIP6_FMT ":%u\n", __func__, + NIP6(addr6->sin6_addr), ntohs(addr6->sin6_port)); + } + else +#endif + { + struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; + + addr4->sin_family = AF_INET, + addr4->sin_port = htons(snum), + addr4->sin_addr.s_addr = inet_sk(sk)->rcv_saddr; + + addr_len = sizeof addr4; + + sdp_dbg(sk, "%s: " NIPQUAD_FMT ":%u\n", __func__, + NIPQUAD(addr4->sin_addr.s_addr), ntohs(addr4->sin_port)); + } + /* IP core seems to bind many times to the same address */ /* TODO: I don't really understand why. Find out. */ - if (!memcmp(&addr, &ssk->id->route.addr.src_addr, sizeof addr)) + if (!memcmp(&addr, &ssk->id->route.addr.src_addr, addr_len)) return 0; rc = ssk->last_bind_err = rdma_bind_addr(ssk->id, (struct sockaddr *)&addr); @@ -760,7 +783,49 @@ out: sdp_common_release(sk); } -static int sdp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +static int sdp_ipv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) +{ + struct sdp_sock *ssk = sdp_sk(sk); + struct sockaddr_in6 src_addr = { + .sin6_family = AF_INET6, + .sin6_port = htons(inet_sk(sk)->sport), + }; + int rc; + + if (addr_len < SIN6_LEN_RFC2133) + return -EINVAL; + + if (!inet6_sk(sk)) + return -EAFNOSUPPORT; + + src_addr.sin6_addr = inet6_sk(sk)->saddr; + + if (!ssk->id) { + rc = sdp_get_port(sk, 0); + if (rc) + return rc; + inet_sk(sk)->sport = htons(inet_sk(sk)->num); + } + + rc = rdma_resolve_addr(ssk->id, (struct sockaddr *)&src_addr, + uaddr, SDP_RESOLVE_TIMEOUT); + if (rc) { + sdp_dbg(sk, "rdma_resolve_addr failed: %d\n", rc); + return rc; + } + + sdp_dbg(sk, "%s " NIP6_FMT ":%hu -> " NIP6_FMT ":%hu\n", __func__, + NIP6(src_addr.sin6_addr), + ntohs(src_addr.sin6_port), + NIP6(((struct sockaddr_in6 *)uaddr)->sin6_addr), + ntohs(((struct sockaddr_in6 *)uaddr)->sin6_port)); + + return 0; +} +#endif + +static int sdp_ipv4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { struct sdp_sock *ssk = sdp_sk(sk); struct sockaddr_in src_addr = { @@ -770,25 +835,11 @@ static int sdp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) }; int rc; - sdp_add_to_history(sk, __func__); - ssk->cpu = smp_processor_id(); - release_sock(sk); - flush_workqueue(sdp_wq); - lock_sock(sk); - if (sk->sk_err) { - sdp_warn(sk, "Can't connect, socket marked with error: %d\n", - sk->sk_err); - return -sk->sk_err; - } + sdp_warn(sk, "Connecting. addr_len = %d\n", addr_len); if (addr_len < sizeof(struct sockaddr_in)) return -EINVAL; - if (uaddr->sa_family == AF_INET_SDP) - uaddr->sa_family = AF_INET; - else if (uaddr->sa_family != AF_INET) - return -EAFNOSUPPORT; - if (!ssk->id) { rc = sdp_get_port(sk, 0); if (rc) @@ -796,19 +847,58 @@ static int sdp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) inet_sk(sk)->sport = htons(inet_sk(sk)->num); } + rc = rdma_resolve_addr(ssk->id, (struct sockaddr *)&src_addr, + uaddr, SDP_RESOLVE_TIMEOUT); + if (rc) { + sdp_dbg(sk, "rdma_resolve_addr failed: %d\n", rc); + return rc; + } + sdp_dbg(sk, "%s %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", __func__, NIPQUAD(src_addr.sin_addr.s_addr), ntohs(src_addr.sin_port), NIPQUAD(((struct sockaddr_in *)uaddr)->sin_addr.s_addr), ntohs(((struct sockaddr_in *)uaddr)->sin_port)); - rc = rdma_resolve_addr(ssk->id, (struct sockaddr *)&src_addr, - uaddr, SDP_RESOLVE_TIMEOUT); - if (rc) { - sdp_dbg(sk, "rdma_resolve_addr failed: %d\n", rc); - return rc; + return 0; +} + +static int sdp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) +{ + struct sdp_sock *ssk = sdp_sk(sk); + int rc; + + sdp_add_to_history(sk, __func__); + ssk->cpu = smp_processor_id(); + release_sock(sk); + flush_workqueue(sdp_wq); + lock_sock(sk); + if (sk->sk_err) { + sdp_warn(sk, "Can't connect, socket marked with error: %d\n", + sk->sk_err); + return -sk->sk_err; } + /* Treat AF_INET_SDP as if it is AF_INET */ + if (uaddr->sa_family == AF_INET_SDP) + uaddr->sa_family = AF_INET; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + else if (uaddr->sa_family == AF_INET6_SDP) + uaddr->sa_family = AF_INET6; +#endif + + if (uaddr->sa_family == AF_INET) + rc = sdp_ipv4_connect(sk, uaddr, addr_len); +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + else if (uaddr->sa_family == AF_INET6) + rc = sdp_ipv6_connect(sk, uaddr, addr_len); +#endif + else + rc = -EAFNOSUPPORT; + + if (rc) + return rc; + sdp_exch_state(sk, TCPF_CLOSE, TCP_SYN_SENT); return 0; } @@ -2587,6 +2677,32 @@ recv_urg: goto out; } +static int sdp_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) +{ + struct sock *sk = sock->sk; + int rc = -EAFNOSUPPORT; + + switch (uaddr->sa_family) { + case AF_INET: +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + if (inet6_sk(sk)) + rc = -EINVAL; + else +#endif + rc = inet_bind(sock, uaddr, addr_len); + break; + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: + if (inet6_sk(sk)) + rc = inet6_bind(sock, uaddr, addr_len); + break; +#endif + } + + return rc; +} + static int sdp_listen(struct sock *sk, int backlog) { struct sdp_sock *ssk = sdp_sk(sk); @@ -2753,7 +2869,7 @@ static struct proto_ops sdp_proto_ops = { .family = PF_INET, .owner = THIS_MODULE, .release = inet_release, - .bind = inet_bind, + .bind = sdp_bind, .connect = inet_stream_connect, /* TODO: inet_datagram connect would autobind, but need to fix get_port with port 0 first. */ @@ -2772,7 +2888,7 @@ static struct proto_ops sdp_proto_ops = { .sendpage = sock_no_sendpage, }; -static int sdp_create_socket(struct net *net, struct socket *sock, int protocol) +static int sdp_create_ipvx_socket(struct net *net, struct socket *sock, int protocol) { struct sock *sk; int rc; @@ -2821,6 +2937,31 @@ static int sdp_create_socket(struct net *net, struct socket *sock, int protocol) return 0; } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +static inline struct ipv6_pinfo *inet6_sk_generic(struct sock *sk) +{ + const int offset = sk->sk_prot->obj_size - sizeof(struct ipv6_pinfo); + + return (struct ipv6_pinfo *)(((u8 *)sk) + offset); +} + +static int sdp_create_v6_socket(struct net *net, struct socket *sock, int protocol) +{ + int rc; + + rc = sdp_create_ipvx_socket(net, sock, protocol); + if (!rc) + inet_sk(sock->sk)->pinet6 = inet6_sk_generic(sock->sk); + + return rc; +} +#endif + +static int sdp_create_v4_socket(struct net *net, struct socket *sock, int protocol) +{ + return sdp_create_ipvx_socket(net, sock, protocol); +} + static void sdp_add_device(struct ib_device *device) { struct sdp_device *sdp_dev; @@ -2951,9 +3092,17 @@ kill_socks: static struct net_proto_family sdp_net_proto = { .family = AF_INET_SDP, - .create = sdp_create_socket, + .create = sdp_create_v4_socket, + .owner = THIS_MODULE, +}; + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +static struct net_proto_family sdp_net6_proto = { + .family = AF_INET6_SDP, + .create = sdp_create_v6_socket, .owner = THIS_MODULE, }; +#endif struct ib_client sdp_client = { .name = "sdp", @@ -2999,10 +3148,18 @@ static int __init sdp_init(void) rc = sock_register(&sdp_net_proto); if (rc) { - printk(KERN_WARNING "sock_register failed: %d\n", rc); + printk(KERN_WARNING "sock_register sdp IPv4 failed: %d\n", rc); goto error_sock_reg; } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + rc = sock_register(&sdp_net6_proto); + if (rc) { + printk(KERN_WARNING "sock_register sdp IPv6 failed: %d\n", rc); + goto error_sock_reg6; + } +#endif + sdp_proc_init(); atomic_set(&sdp_current_mem_usage, 0); @@ -3011,6 +3168,10 @@ static int __init sdp_init(void) return 0; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +error_sock_reg6: + sock_unregister(PF_INET_SDP); +#endif error_sock_reg: proto_unregister(&sdp_proto); error_proto_reg: @@ -3027,6 +3188,7 @@ no_mem_sockets_allocated: static void __exit sdp_exit(void) { + sock_unregister(PF_INET6_SDP); sock_unregister(PF_INET_SDP); proto_unregister(&sdp_proto); diff --git a/drivers/infiniband/ulp/sdp/sdp_proc.c b/drivers/infiniband/ulp/sdp/sdp_proc.c index d88d0d0747b21..bf41f5e9b7e40 100644 --- a/drivers/infiniband/ulp/sdp/sdp_proc.c +++ b/drivers/infiniband/ulp/sdp/sdp_proc.c @@ -139,10 +139,8 @@ static void sdp_seq_stop(struct seq_file *seq, void *v) #define TMPSZ 150 -static int sdp_seq_show(struct seq_file *seq, void *v) +static int sdp_v4_seq_show(struct seq_file *seq, int num, struct sock *sk) { - struct sdp_iter_state *st; - struct sock *sk = v; char tmpbuf[TMPSZ + 1]; unsigned int dest; unsigned int src; @@ -152,15 +150,6 @@ static int sdp_seq_show(struct seq_file *seq, void *v) __u16 srcp; __u32 rx_queue, tx_queue; - if (v == SEQ_START_TOKEN) { - seq_printf(seq, "%-*s\n", TMPSZ - 1, - " sl local_address rem_address " - "uid inode rx_queue tx_queue state"); - goto out; - } - - st = seq->private; - dest = inet_sk(sk)->daddr; src = inet_sk(sk)->rcv_saddr; destp = ntohs(inet_sk(sk)->dport); @@ -171,11 +160,71 @@ static int sdp_seq_show(struct seq_file *seq, void *v) tx_queue = sdp_sk(sk)->write_seq - sdp_sk(sk)->tx_ring.una_seq; sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X %5d %lu %08X:%08X %X", - st->num, src, srcp, dest, destp, uid, inode, + num, src, srcp, dest, destp, uid, inode, rx_queue, tx_queue, sk->sk_state); seq_printf(seq, "%-*s\n", TMPSZ - 1, tmpbuf); + return 0; +} + +static int sdp_v6_seq_show(struct seq_file *seq, int num, struct sock *sk) +{ + char tmpbuf[TMPSZ + 1]; + struct in6_addr *src; + struct in6_addr *dest; + int uid; + unsigned long inode; + __u16 destp; + __u16 srcp; + __u32 rx_queue, tx_queue; + + dest = &inet6_sk(sk)->daddr; + src = &inet6_sk(sk)->rcv_saddr; + destp = ntohs(inet_sk(sk)->dport); + srcp = ntohs(inet_sk(sk)->sport); + uid = sock_i_uid(sk); + inode = sock_i_ino(sk); + rx_queue = rcv_nxt(sdp_sk(sk)) - sdp_sk(sk)->copied_seq; + tx_queue = sdp_sk(sk)->write_seq - sdp_sk(sk)->tx_ring.una_seq; + + sprintf(tmpbuf, + "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " + "%5d %lu %08X:%08X %X", + num, + src->s6_addr32[0], src->s6_addr32[1], + src->s6_addr32[2], src->s6_addr32[3], + srcp, + dest->s6_addr32[0], dest->s6_addr32[1], + dest->s6_addr32[2], dest->s6_addr32[3], + destp, + uid, inode, + rx_queue, tx_queue, sk->sk_state); + + seq_printf(seq, "%-*s\n", TMPSZ - 1, tmpbuf); + + return 0; +} + +static int sdp_seq_show(struct seq_file *seq, void *v) +{ + struct sdp_iter_state *st; + struct sock *sk = v; + + if (v == SEQ_START_TOKEN) { + seq_printf(seq, "%-*s\n", TMPSZ - 1, + " sl local_address rem_address " + "uid inode rx_queue tx_queue state"); + goto out; + } + + st = seq->private; + + if (inet6_sk(sk)) + sdp_v6_seq_show(seq, st->num, sk); + else + sdp_v4_seq_show(seq, st->num, sk); + sock_put(sk, SOCK_REF_SEQ); out: return 0; diff --git a/include/rdma/sdp_socket.h b/include/rdma/sdp_socket.h index 902dc97443487..c289f99659824 100644 --- a/include/rdma/sdp_socket.h +++ b/include/rdma/sdp_socket.h @@ -8,6 +8,11 @@ #define PF_INET_SDP AF_INET_SDP #endif +#ifndef AF_INET6_SDP +#define AF_INET6_SDP 28 +#define PF_INET6_SDP AF_INET6_SDP +#endif + #ifndef SDP_ZCOPY_THRESH #define SDP_ZCOPY_THRESH 80 #endif @@ -16,6 +21,4 @@ #define SDP_LAST_BIND_ERR 81 #endif -/* TODO: AF_INET6_SDP ? */ - #endif