Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

SUNRPC: Add API to acquire source address

NFSv4.0 clients must send endpoint information for their callback
service to NFSv4.0 servers during their first contact with a server.
Traditionally on Linux, user space provides the callback endpoint IP
address via the "clientaddr=" mount option.

During an NFSv4 migration event, it is possible that an FSID may be
migrated to a destination server that is accessible via a different
source IP address than the source server was. The client must update
callback endpoint information on the destination server so that it can
maintain leases and allow delegation.

Without a new "clientaddr=" option from user space, however, the
kernel itself must construct an appropriate IP address for the
callback update. Provide an API in the RPC client for upper layer
RPC consumers to acquire a source address for a remote.

The mechanism used by the mount.nfs command is copied: set up a
connected UDP socket to the designated remote, then scrape the source
address off the socket. We are careful to select the correct network
namespace when setting up the temporary UDP socket.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

authored by

Chuck Lever and committed by
Trond Myklebust
2e738fdc 4e0038b6

+150
+1
include/linux/sunrpc/clnt.h
··· 161 161 void rpc_force_rebind(struct rpc_clnt *); 162 162 size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); 163 163 const char *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t); 164 + int rpc_localaddr(struct rpc_clnt *, struct sockaddr *, size_t); 164 165 165 166 size_t rpc_ntop(const struct sockaddr *, char *, const size_t); 166 167 size_t rpc_pton(struct net *, const char *, const size_t,
+149
net/sunrpc/clnt.c
··· 914 914 } 915 915 EXPORT_SYMBOL_GPL(rpc_peeraddr2str); 916 916 917 + static const struct sockaddr_in rpc_inaddr_loopback = { 918 + .sin_family = AF_INET, 919 + .sin_addr.s_addr = htonl(INADDR_ANY), 920 + }; 921 + 922 + static const struct sockaddr_in6 rpc_in6addr_loopback = { 923 + .sin6_family = AF_INET6, 924 + .sin6_addr = IN6ADDR_ANY_INIT, 925 + }; 926 + 927 + /* 928 + * Try a getsockname() on a connected datagram socket. Using a 929 + * connected datagram socket prevents leaving a socket in TIME_WAIT. 930 + * This conserves the ephemeral port number space. 931 + * 932 + * Returns zero and fills in "buf" if successful; otherwise, a 933 + * negative errno is returned. 934 + */ 935 + static int rpc_sockname(struct net *net, struct sockaddr *sap, size_t salen, 936 + struct sockaddr *buf, int buflen) 937 + { 938 + struct socket *sock; 939 + int err; 940 + 941 + err = __sock_create(net, sap->sa_family, 942 + SOCK_DGRAM, IPPROTO_UDP, &sock, 1); 943 + if (err < 0) { 944 + dprintk("RPC: can't create UDP socket (%d)\n", err); 945 + goto out; 946 + } 947 + 948 + switch (sap->sa_family) { 949 + case AF_INET: 950 + err = kernel_bind(sock, 951 + (struct sockaddr *)&rpc_inaddr_loopback, 952 + sizeof(rpc_inaddr_loopback)); 953 + break; 954 + case AF_INET6: 955 + err = kernel_bind(sock, 956 + (struct sockaddr *)&rpc_in6addr_loopback, 957 + sizeof(rpc_in6addr_loopback)); 958 + break; 959 + default: 960 + err = -EAFNOSUPPORT; 961 + goto out; 962 + } 963 + if (err < 0) { 964 + dprintk("RPC: can't bind UDP socket (%d)\n", err); 965 + goto out_release; 966 + } 967 + 968 + err = kernel_connect(sock, sap, salen, 0); 969 + if (err < 0) { 970 + dprintk("RPC: can't connect UDP socket (%d)\n", err); 971 + goto out_release; 972 + } 973 + 974 + err = kernel_getsockname(sock, buf, &buflen); 975 + if (err < 0) { 976 + dprintk("RPC: getsockname failed (%d)\n", err); 977 + goto out_release; 978 + } 979 + 980 + err = 0; 981 + if (buf->sa_family == AF_INET6) { 982 + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)buf; 983 + sin6->sin6_scope_id = 0; 984 + } 985 + dprintk("RPC: %s succeeded\n", __func__); 986 + 987 + out_release: 988 + sock_release(sock); 989 + out: 990 + return err; 991 + } 992 + 993 + /* 994 + * Scraping a connected socket failed, so we don't have a useable 995 + * local address. Fallback: generate an address that will prevent 996 + * the server from calling us back. 997 + * 998 + * Returns zero and fills in "buf" if successful; otherwise, a 999 + * negative errno is returned. 1000 + */ 1001 + static int rpc_anyaddr(int family, struct sockaddr *buf, size_t buflen) 1002 + { 1003 + switch (family) { 1004 + case AF_INET: 1005 + if (buflen < sizeof(rpc_inaddr_loopback)) 1006 + return -EINVAL; 1007 + memcpy(buf, &rpc_inaddr_loopback, 1008 + sizeof(rpc_inaddr_loopback)); 1009 + break; 1010 + case AF_INET6: 1011 + if (buflen < sizeof(rpc_in6addr_loopback)) 1012 + return -EINVAL; 1013 + memcpy(buf, &rpc_in6addr_loopback, 1014 + sizeof(rpc_in6addr_loopback)); 1015 + default: 1016 + dprintk("RPC: %s: address family not supported\n", 1017 + __func__); 1018 + return -EAFNOSUPPORT; 1019 + } 1020 + dprintk("RPC: %s: succeeded\n", __func__); 1021 + return 0; 1022 + } 1023 + 1024 + /** 1025 + * rpc_localaddr - discover local endpoint address for an RPC client 1026 + * @clnt: RPC client structure 1027 + * @buf: target buffer 1028 + * @buflen: size of target buffer, in bytes 1029 + * 1030 + * Returns zero and fills in "buf" and "buflen" if successful; 1031 + * otherwise, a negative errno is returned. 1032 + * 1033 + * This works even if the underlying transport is not currently connected, 1034 + * or if the upper layer never previously provided a source address. 1035 + * 1036 + * The result of this function call is transient: multiple calls in 1037 + * succession may give different results, depending on how local 1038 + * networking configuration changes over time. 1039 + */ 1040 + int rpc_localaddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t buflen) 1041 + { 1042 + struct sockaddr_storage address; 1043 + struct sockaddr *sap = (struct sockaddr *)&address; 1044 + struct rpc_xprt *xprt; 1045 + struct net *net; 1046 + size_t salen; 1047 + int err; 1048 + 1049 + rcu_read_lock(); 1050 + xprt = rcu_dereference(clnt->cl_xprt); 1051 + salen = xprt->addrlen; 1052 + memcpy(sap, &xprt->addr, salen); 1053 + net = get_net(xprt->xprt_net); 1054 + rcu_read_unlock(); 1055 + 1056 + rpc_set_port(sap, 0); 1057 + err = rpc_sockname(net, sap, salen, buf, buflen); 1058 + put_net(net); 1059 + if (err != 0) 1060 + /* Couldn't discover local address, return ANYADDR */ 1061 + return rpc_anyaddr(sap->sa_family, buf, buflen); 1062 + return 0; 1063 + } 1064 + EXPORT_SYMBOL_GPL(rpc_localaddr); 1065 + 917 1066 void 918 1067 rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize) 919 1068 {