Commit c2e1b09ff237c0a3687b9a804cc8bf489743cffc

Authored by Chuck Lever
Committed by Trond Myklebust
1 parent babe80eb49

SUNRPC: Support registering IPv6 interfaces with local rpcbind daemon

Introduce a new API to register RPC services on IPv6 interfaces to allow
the NFS server and lockd to advertise on IPv6 networks.

Unlike rpcb_register(), the new rpcb_v4_register() function uses rpcbind
protocol version 4 to contact the local rpcbind daemon.  The version 4
SET/UNSET procedures allow services to register address families besides
AF_INET, register at specific network interfaces, and register transport
protocols besides UDP and TCP.  All of this functionality is exposed via
the new rpcb_v4_register() kernel API.

A user-space rpcbind daemon implementation that supports version 4 of the
rpcbind protocol is required in order to make use of this new API.

Note that rpcbind version 3 is sufficient to support the new rpcbind
facilities listed above, but most extant implementations use version 4.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

Showing 2 changed files with 177 additions and 4 deletions Side-by-side Diff

include/linux/sunrpc/clnt.h
... ... @@ -125,6 +125,9 @@
125 125 void rpc_release_client(struct rpc_clnt *);
126 126  
127 127 int rpcb_register(u32, u32, int, unsigned short, int *);
  128 +int rpcb_v4_register(const u32 program, const u32 version,
  129 + const struct sockaddr *address,
  130 + const char *netid, int *result);
128 131 int rpcb_getport_sync(struct sockaddr_in *, u32, u32, int);
129 132 void rpcb_getport_async(struct rpc_task *);
130 133  
net/sunrpc/rpcb_clnt.c
... ... @@ -87,6 +87,7 @@
87 87  
88 88 static struct rpc_procinfo rpcb_procedures2[];
89 89 static struct rpc_procinfo rpcb_procedures3[];
  90 +static struct rpc_procinfo rpcb_procedures4[];
90 91  
91 92 struct rpcb_info {
92 93 u32 rpc_vers;
... ... @@ -122,6 +123,12 @@
122 123 .sin_port = htons(RPCBIND_PORT),
123 124 };
124 125  
  126 +static const struct sockaddr_in6 rpcb_in6addr_loopback = {
  127 + .sin6_family = AF_INET6,
  128 + .sin6_addr = IN6ADDR_LOOPBACK_INIT,
  129 + .sin6_port = htons(RPCBIND_PORT),
  130 +};
  131 +
125 132 static struct rpc_clnt *rpcb_create_local(struct sockaddr *addr,
126 133 size_t addrlen, u32 version)
127 134 {
128 135  
129 136  
130 137  
... ... @@ -196,13 +203,38 @@
196 203 * rpcb_register - set or unset a port registration with the local rpcbind svc
197 204 * @prog: RPC program number to bind
198 205 * @vers: RPC version number to bind
199   - * @prot: transport protocol to use to make this request
  206 + * @prot: transport protocol to register
200 207 * @port: port value to register
201   - * @okay: result code
  208 + * @okay: OUT: result code
202 209 *
203   - * port == 0 means unregister, port != 0 means register.
  210 + * RPC services invoke this function to advertise their contact
  211 + * information via the system's rpcbind daemon. RPC services
  212 + * invoke this function once for each [program, version, transport]
  213 + * tuple they wish to advertise.
204 214 *
205   - * This routine supports only rpcbind version 2.
  215 + * Callers may also unregister RPC services that are no longer
  216 + * available by setting the passed-in port to zero. This removes
  217 + * all registered transports for [program, version] from the local
  218 + * rpcbind database.
  219 + *
  220 + * Returns zero if the registration request was dispatched
  221 + * successfully and a reply was received. The rpcbind daemon's
  222 + * boolean result code is stored in *okay.
  223 + *
  224 + * Returns an errno value and sets *result to zero if there was
  225 + * some problem that prevented the rpcbind request from being
  226 + * dispatched, or if the rpcbind daemon did not respond within
  227 + * the timeout.
  228 + *
  229 + * This function uses rpcbind protocol version 2 to contact the
  230 + * local rpcbind daemon.
  231 + *
  232 + * Registration works over both AF_INET and AF_INET6, and services
  233 + * registered via this function are advertised as available for any
  234 + * address. If the local rpcbind daemon is listening on AF_INET6,
  235 + * services registered via this function will be advertised on
  236 + * IN6ADDR_ANY (ie available for all AF_INET and AF_INET6
  237 + * addresses).
206 238 */
207 239 int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
208 240 {
... ... @@ -228,6 +260,144 @@
228 260 return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
229 261 sizeof(rpcb_inaddr_loopback),
230 262 RPCBVERS_2, &msg, okay);
  263 +}
  264 +
  265 +/*
  266 + * Fill in AF_INET family-specific arguments to register
  267 + */
  268 +static int rpcb_register_netid4(struct sockaddr_in *address_to_register,
  269 + struct rpc_message *msg)
  270 +{
  271 + struct rpcbind_args *map = msg->rpc_argp;
  272 + unsigned short port = ntohs(address_to_register->sin_port);
  273 + char buf[32];
  274 +
  275 + /* Construct AF_INET universal address */
  276 + snprintf(buf, sizeof(buf),
  277 + NIPQUAD_FMT".%u.%u",
  278 + NIPQUAD(address_to_register->sin_addr.s_addr),
  279 + port >> 8, port & 0xff);
  280 + map->r_addr = buf;
  281 +
  282 + dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with "
  283 + "local rpcbind\n", (port ? "" : "un"),
  284 + map->r_prog, map->r_vers,
  285 + map->r_addr, map->r_netid);
  286 +
  287 + msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
  288 + if (port)
  289 + msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
  290 +
  291 + return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
  292 + sizeof(rpcb_inaddr_loopback),
  293 + RPCBVERS_4, msg, msg->rpc_resp);
  294 +}
  295 +
  296 +/*
  297 + * Fill in AF_INET6 family-specific arguments to register
  298 + */
  299 +static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
  300 + struct rpc_message *msg)
  301 +{
  302 + struct rpcbind_args *map = msg->rpc_argp;
  303 + unsigned short port = ntohs(address_to_register->sin6_port);
  304 + char buf[64];
  305 +
  306 + /* Construct AF_INET6 universal address */
  307 + snprintf(buf, sizeof(buf),
  308 + NIP6_FMT".%u.%u",
  309 + NIP6(address_to_register->sin6_addr),
  310 + port >> 8, port & 0xff);
  311 + map->r_addr = buf;
  312 +
  313 + dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with "
  314 + "local rpcbind\n", (port ? "" : "un"),
  315 + map->r_prog, map->r_vers,
  316 + map->r_addr, map->r_netid);
  317 +
  318 + msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
  319 + if (port)
  320 + msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
  321 +
  322 + return rpcb_register_call((struct sockaddr *)&rpcb_in6addr_loopback,
  323 + sizeof(rpcb_in6addr_loopback),
  324 + RPCBVERS_4, msg, msg->rpc_resp);
  325 +}
  326 +
  327 +/**
  328 + * rpcb_v4_register - set or unset a port registration with the local rpcbind
  329 + * @program: RPC program number of service to (un)register
  330 + * @version: RPC version number of service to (un)register
  331 + * @address: address family, IP address, and port to (un)register
  332 + * @netid: netid of transport protocol to (un)register
  333 + * @result: result code from rpcbind RPC call
  334 + *
  335 + * RPC services invoke this function to advertise their contact
  336 + * information via the system's rpcbind daemon. RPC services
  337 + * invoke this function once for each [program, version, address,
  338 + * netid] tuple they wish to advertise.
  339 + *
  340 + * Callers may also unregister RPC services that are no longer
  341 + * available by setting the port number in the passed-in address
  342 + * to zero. Callers pass a netid of "" to unregister all
  343 + * transport netids associated with [program, version, address].
  344 + *
  345 + * Returns zero if the registration request was dispatched
  346 + * successfully and a reply was received. The rpcbind daemon's
  347 + * result code is stored in *result.
  348 + *
  349 + * Returns an errno value and sets *result to zero if there was
  350 + * some problem that prevented the rpcbind request from being
  351 + * dispatched, or if the rpcbind daemon did not respond within
  352 + * the timeout.
  353 + *
  354 + * This function uses rpcbind protocol version 4 to contact the
  355 + * local rpcbind daemon. The local rpcbind daemon must support
  356 + * version 4 of the rpcbind protocol in order for these functions
  357 + * to register a service successfully.
  358 + *
  359 + * Supported netids include "udp" and "tcp" for UDP and TCP over
  360 + * IPv4, and "udp6" and "tcp6" for UDP and TCP over IPv6,
  361 + * respectively.
  362 + *
  363 + * The contents of @address determine the address family and the
  364 + * port to be registered. The usual practice is to pass INADDR_ANY
  365 + * as the raw address, but specifying a non-zero address is also
  366 + * supported by this API if the caller wishes to advertise an RPC
  367 + * service on a specific network interface.
  368 + *
  369 + * Note that passing in INADDR_ANY does not create the same service
  370 + * registration as IN6ADDR_ANY. The former advertises an RPC
  371 + * service on any IPv4 address, but not on IPv6. The latter
  372 + * advertises the service on all IPv4 and IPv6 addresses.
  373 + */
  374 +int rpcb_v4_register(const u32 program, const u32 version,
  375 + const struct sockaddr *address, const char *netid,
  376 + int *result)
  377 +{
  378 + struct rpcbind_args map = {
  379 + .r_prog = program,
  380 + .r_vers = version,
  381 + .r_netid = netid,
  382 + .r_owner = RPCB_OWNER_STRING,
  383 + };
  384 + struct rpc_message msg = {
  385 + .rpc_argp = &map,
  386 + .rpc_resp = result,
  387 + };
  388 +
  389 + *result = 0;
  390 +
  391 + switch (address->sa_family) {
  392 + case AF_INET:
  393 + return rpcb_register_netid4((struct sockaddr_in *)address,
  394 + &msg);
  395 + case AF_INET6:
  396 + return rpcb_register_netid6((struct sockaddr_in6 *)address,
  397 + &msg);
  398 + }
  399 +
  400 + return -EAFNOSUPPORT;
231 401 }
232 402  
233 403 /**