diff options
| author | Chuck Lever <chuck.lever@ORACLE.COM> | 2011-05-09 15:22:44 -0400 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-05-27 17:42:47 -0400 |
| commit | 176e21ee2ec89cae8d45cf1a850ea45a45428fb8 (patch) | |
| tree | 4e1231617d193b3fe62ea5bd4df5e4d8fe8b9e80 | |
| parent | 559649efb9b0d248541933197bdf7b75529da457 (diff) | |
SUNRPC: Support for RPC over AF_LOCAL transports
TI-RPC introduces the capability of performing RPC over AF_LOCAL
sockets. It uses this mainly for registering and unregistering
local RPC services securely with the local rpcbind, but we could
also conceivably use it as a generic upcall mechanism.
This patch provides a client-side only implementation for the moment.
We might also consider a server-side implementation to provide
AF_LOCAL access to NLM (for statd downcalls, and such like).
Autobinding is not supported on kernel AF_LOCAL transports at this
time. Kernel ULPs must specify the pathname of the remote endpoint
when an AF_LOCAL transport is created. rpcbind supports registering
services available via AF_LOCAL, so the kernel could handle it with
some adjustment to ->rpcbind and ->set_port. But we don't need this
feature for doing upcalls via well-known named sockets.
This has not been tested with ULPs that move a substantial amount of
data. Thus, I can't attest to how robust the write_space and
congestion management logic is.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
| -rw-r--r-- | include/linux/sunrpc/msg_prot.h | 1 | ||||
| -rw-r--r-- | include/linux/sunrpc/xprt.h | 3 | ||||
| -rw-r--r-- | net/sunrpc/clnt.c | 8 | ||||
| -rw-r--r-- | net/sunrpc/xprtsock.c | 395 |
4 files changed, 403 insertions, 4 deletions
diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h index 77e624883393..c68a147939a6 100644 --- a/include/linux/sunrpc/msg_prot.h +++ b/include/linux/sunrpc/msg_prot.h | |||
| @@ -145,6 +145,7 @@ typedef __be32 rpc_fraghdr; | |||
| 145 | #define RPCBIND_NETID_TCP "tcp" | 145 | #define RPCBIND_NETID_TCP "tcp" |
| 146 | #define RPCBIND_NETID_UDP6 "udp6" | 146 | #define RPCBIND_NETID_UDP6 "udp6" |
| 147 | #define RPCBIND_NETID_TCP6 "tcp6" | 147 | #define RPCBIND_NETID_TCP6 "tcp6" |
| 148 | #define RPCBIND_NETID_LOCAL "local" | ||
| 148 | 149 | ||
| 149 | /* | 150 | /* |
| 150 | * Note that RFC 1833 does not put any size restrictions on the | 151 | * Note that RFC 1833 does not put any size restrictions on the |
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index a0f998c07c65..81cce3b3ee66 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h | |||
| @@ -141,7 +141,8 @@ enum xprt_transports { | |||
| 141 | XPRT_TRANSPORT_UDP = IPPROTO_UDP, | 141 | XPRT_TRANSPORT_UDP = IPPROTO_UDP, |
| 142 | XPRT_TRANSPORT_TCP = IPPROTO_TCP, | 142 | XPRT_TRANSPORT_TCP = IPPROTO_TCP, |
| 143 | XPRT_TRANSPORT_BC_TCP = IPPROTO_TCP | XPRT_TRANSPORT_BC, | 143 | XPRT_TRANSPORT_BC_TCP = IPPROTO_TCP | XPRT_TRANSPORT_BC, |
| 144 | XPRT_TRANSPORT_RDMA = 256 | 144 | XPRT_TRANSPORT_RDMA = 256, |
| 145 | XPRT_TRANSPORT_LOCAL = 257, | ||
| 145 | }; | 146 | }; |
| 146 | 147 | ||
| 147 | struct rpc_xprt { | 148 | struct rpc_xprt { |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 08ed49629b86..b84d7395535e 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
| @@ -28,7 +28,9 @@ | |||
| 28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
| 29 | #include <linux/utsname.h> | 29 | #include <linux/utsname.h> |
| 30 | #include <linux/workqueue.h> | 30 | #include <linux/workqueue.h> |
| 31 | #include <linux/in.h> | ||
| 31 | #include <linux/in6.h> | 32 | #include <linux/in6.h> |
| 33 | #include <linux/un.h> | ||
| 32 | 34 | ||
| 33 | #include <linux/sunrpc/clnt.h> | 35 | #include <linux/sunrpc/clnt.h> |
| 34 | #include <linux/sunrpc/rpc_pipe_fs.h> | 36 | #include <linux/sunrpc/rpc_pipe_fs.h> |
| @@ -294,6 +296,8 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) | |||
| 294 | * up a string representation of the passed-in address. | 296 | * up a string representation of the passed-in address. |
| 295 | */ | 297 | */ |
| 296 | if (args->servername == NULL) { | 298 | if (args->servername == NULL) { |
| 299 | struct sockaddr_un *sun = | ||
| 300 | (struct sockaddr_un *)args->address; | ||
| 297 | struct sockaddr_in *sin = | 301 | struct sockaddr_in *sin = |
| 298 | (struct sockaddr_in *)args->address; | 302 | (struct sockaddr_in *)args->address; |
| 299 | struct sockaddr_in6 *sin6 = | 303 | struct sockaddr_in6 *sin6 = |
| @@ -301,6 +305,10 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) | |||
| 301 | 305 | ||
| 302 | servername[0] = '\0'; | 306 | servername[0] = '\0'; |
| 303 | switch (args->address->sa_family) { | 307 | switch (args->address->sa_family) { |
| 308 | case AF_LOCAL: | ||
| 309 | snprintf(servername, sizeof(servername), "%s", | ||
| 310 | sun->sun_path); | ||
| 311 | break; | ||
| 304 | case AF_INET: | 312 | case AF_INET: |
| 305 | snprintf(servername, sizeof(servername), "%pI4", | 313 | snprintf(servername, sizeof(servername), "%pI4", |
| 306 | &sin->sin_addr.s_addr); | 314 | &sin->sin_addr.s_addr); |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 079366974e1f..72abb7358933 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | */ | 19 | */ |
| 20 | 20 | ||
| 21 | #include <linux/types.h> | 21 | #include <linux/types.h> |
| 22 | #include <linux/string.h> | ||
| 22 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
| 23 | #include <linux/module.h> | 24 | #include <linux/module.h> |
| 24 | #include <linux/capability.h> | 25 | #include <linux/capability.h> |
| @@ -28,6 +29,7 @@ | |||
| 28 | #include <linux/in.h> | 29 | #include <linux/in.h> |
| 29 | #include <linux/net.h> | 30 | #include <linux/net.h> |
| 30 | #include <linux/mm.h> | 31 | #include <linux/mm.h> |
| 32 | #include <linux/un.h> | ||
| 31 | #include <linux/udp.h> | 33 | #include <linux/udp.h> |
| 32 | #include <linux/tcp.h> | 34 | #include <linux/tcp.h> |
| 33 | #include <linux/sunrpc/clnt.h> | 35 | #include <linux/sunrpc/clnt.h> |
| @@ -45,6 +47,9 @@ | |||
| 45 | #include <net/tcp.h> | 47 | #include <net/tcp.h> |
| 46 | 48 | ||
| 47 | #include "sunrpc.h" | 49 | #include "sunrpc.h" |
| 50 | |||
| 51 | static void xs_close(struct rpc_xprt *xprt); | ||
| 52 | |||
| 48 | /* | 53 | /* |
| 49 | * xprtsock tunables | 54 | * xprtsock tunables |
| 50 | */ | 55 | */ |
| @@ -261,6 +266,11 @@ static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt) | |||
| 261 | return (struct sockaddr *) &xprt->addr; | 266 | return (struct sockaddr *) &xprt->addr; |
| 262 | } | 267 | } |
| 263 | 268 | ||
| 269 | static inline struct sockaddr_un *xs_addr_un(struct rpc_xprt *xprt) | ||
| 270 | { | ||
| 271 | return (struct sockaddr_un *) &xprt->addr; | ||
| 272 | } | ||
| 273 | |||
| 264 | static inline struct sockaddr_in *xs_addr_in(struct rpc_xprt *xprt) | 274 | static inline struct sockaddr_in *xs_addr_in(struct rpc_xprt *xprt) |
| 265 | { | 275 | { |
| 266 | return (struct sockaddr_in *) &xprt->addr; | 276 | return (struct sockaddr_in *) &xprt->addr; |
| @@ -276,23 +286,34 @@ static void xs_format_common_peer_addresses(struct rpc_xprt *xprt) | |||
| 276 | struct sockaddr *sap = xs_addr(xprt); | 286 | struct sockaddr *sap = xs_addr(xprt); |
| 277 | struct sockaddr_in6 *sin6; | 287 | struct sockaddr_in6 *sin6; |
| 278 | struct sockaddr_in *sin; | 288 | struct sockaddr_in *sin; |
| 289 | struct sockaddr_un *sun; | ||
| 279 | char buf[128]; | 290 | char buf[128]; |
| 280 | 291 | ||
| 281 | (void)rpc_ntop(sap, buf, sizeof(buf)); | ||
| 282 | xprt->address_strings[RPC_DISPLAY_ADDR] = kstrdup(buf, GFP_KERNEL); | ||
| 283 | |||
| 284 | switch (sap->sa_family) { | 292 | switch (sap->sa_family) { |
| 293 | case AF_LOCAL: | ||
| 294 | sun = xs_addr_un(xprt); | ||
| 295 | strlcpy(buf, sun->sun_path, sizeof(buf)); | ||
| 296 | xprt->address_strings[RPC_DISPLAY_ADDR] = | ||
| 297 | kstrdup(buf, GFP_KERNEL); | ||
| 298 | break; | ||
| 285 | case AF_INET: | 299 | case AF_INET: |
| 300 | (void)rpc_ntop(sap, buf, sizeof(buf)); | ||
| 301 | xprt->address_strings[RPC_DISPLAY_ADDR] = | ||
| 302 | kstrdup(buf, GFP_KERNEL); | ||
| 286 | sin = xs_addr_in(xprt); | 303 | sin = xs_addr_in(xprt); |
| 287 | snprintf(buf, sizeof(buf), "%08x", ntohl(sin->sin_addr.s_addr)); | 304 | snprintf(buf, sizeof(buf), "%08x", ntohl(sin->sin_addr.s_addr)); |
| 288 | break; | 305 | break; |
| 289 | case AF_INET6: | 306 | case AF_INET6: |
| 307 | (void)rpc_ntop(sap, buf, sizeof(buf)); | ||
| 308 | xprt->address_strings[RPC_DISPLAY_ADDR] = | ||
| 309 | kstrdup(buf, GFP_KERNEL); | ||
| 290 | sin6 = xs_addr_in6(xprt); | 310 | sin6 = xs_addr_in6(xprt); |
| 291 | snprintf(buf, sizeof(buf), "%pi6", &sin6->sin6_addr); | 311 | snprintf(buf, sizeof(buf), "%pi6", &sin6->sin6_addr); |
| 292 | break; | 312 | break; |
| 293 | default: | 313 | default: |
| 294 | BUG(); | 314 | BUG(); |
| 295 | } | 315 | } |
| 316 | |||
| 296 | xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = kstrdup(buf, GFP_KERNEL); | 317 | xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = kstrdup(buf, GFP_KERNEL); |
| 297 | } | 318 | } |
| 298 | 319 | ||
| @@ -506,6 +527,60 @@ static inline void xs_encode_stream_record_marker(struct xdr_buf *buf) | |||
| 506 | } | 527 | } |
| 507 | 528 | ||
| 508 | /** | 529 | /** |
| 530 | * xs_local_send_request - write an RPC request to an AF_LOCAL socket | ||
| 531 | * @task: RPC task that manages the state of an RPC request | ||
| 532 | * | ||
| 533 | * Return values: | ||
| 534 | * 0: The request has been sent | ||
| 535 | * EAGAIN: The socket was blocked, please call again later to | ||
| 536 | * complete the request | ||
| 537 | * ENOTCONN: Caller needs to invoke connect logic then call again | ||
| 538 | * other: Some other error occured, the request was not sent | ||
| 539 | */ | ||
| 540 | static int xs_local_send_request(struct rpc_task *task) | ||
| 541 | { | ||
| 542 | struct rpc_rqst *req = task->tk_rqstp; | ||
| 543 | struct rpc_xprt *xprt = req->rq_xprt; | ||
| 544 | struct sock_xprt *transport = | ||
| 545 | container_of(xprt, struct sock_xprt, xprt); | ||
| 546 | struct xdr_buf *xdr = &req->rq_snd_buf; | ||
| 547 | int status; | ||
| 548 | |||
| 549 | xs_encode_stream_record_marker(&req->rq_snd_buf); | ||
| 550 | |||
| 551 | xs_pktdump("packet data:", | ||
