]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/rpc/clnt_bck.c
Optionally bind ktls threads to NUMA domains
[FreeBSD/FreeBSD.git] / sys / rpc / clnt_bck.c
1 /*      $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $ */
2
3 /*-
4  * Copyright (c) 2009, Sun Microsystems, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without 
8  * modification, are permitted provided that the following conditions are met:
9  * - Redistributions of source code must retain the above copyright notice, 
10  *   this list of conditions and the following disclaimer.
11  * - Redistributions in binary form must reproduce the above copyright notice, 
12  *   this list of conditions and the following disclaimer in the documentation 
13  *   and/or other materials provided with the distribution.
14  * - Neither the name of Sun Microsystems, Inc. nor the names of its 
15  *   contributors may be used to endorse or promote products derived 
16  *   from this software without specific prior written permission.
17  * 
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #if defined(LIBC_SCCS) && !defined(lint)
32 static char *sccsid2 = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
33 static char *sccsid = "@(#)clnt_tcp.c   2.2 88/08/01 4.0 RPCSRC";
34 static char sccsid3[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro";
35 #endif
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38  
39 /*
40  * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
41  *
42  * Copyright (C) 1984, Sun Microsystems, Inc.
43  *
44  * TCP based RPC supports 'batched calls'.
45  * A sequence of calls may be batched-up in a send buffer.  The rpc call
46  * return immediately to the client even though the call was not necessarily
47  * sent.  The batching occurs if the results' xdr routine is NULL (0) AND
48  * the rpc timeout value is zero (see clnt.h, rpc).
49  *
50  * Clients should NOT casually batch calls that in fact return results; that is,
51  * the server side should be aware that a call is batched and not produce any
52  * return message.  Batched calls that produce many result messages can
53  * deadlock (netlock) the client and the server....
54  *
55  * Now go hang yourself.
56  */
57
58 /*
59  * This code handles the special case of a NFSv4.n backchannel for
60  * callback RPCs. It is similar to clnt_vc.c, but uses the TCP
61  * connection provided by the client to the server.
62  */
63
64 #include "opt_kern_tls.h"
65
66 #include <sys/param.h>
67 #include <sys/systm.h>
68 #include <sys/ktls.h>
69 #include <sys/lock.h>
70 #include <sys/malloc.h>
71 #include <sys/mbuf.h>
72 #include <sys/mutex.h>
73 #include <sys/pcpu.h>
74 #include <sys/proc.h>
75 #include <sys/protosw.h>
76 #include <sys/socket.h>
77 #include <sys/socketvar.h>
78 #include <sys/sx.h>
79 #include <sys/syslog.h>
80 #include <sys/time.h>
81 #include <sys/uio.h>
82
83 #include <net/vnet.h>
84
85 #include <netinet/tcp.h>
86
87 #include <rpc/rpc.h>
88 #include <rpc/rpc_com.h>
89 #include <rpc/krpc.h>
90 #include <rpc/rpcsec_tls.h>
91
92 struct cmessage {
93         struct cmsghdr cmsg;
94         struct cmsgcred cmcred;
95 };
96
97 static void clnt_bck_geterr(CLIENT *, struct rpc_err *);
98 static bool_t clnt_bck_freeres(CLIENT *, xdrproc_t, void *);
99 static void clnt_bck_abort(CLIENT *);
100 static bool_t clnt_bck_control(CLIENT *, u_int, void *);
101 static void clnt_bck_close(CLIENT *);
102 static void clnt_bck_destroy(CLIENT *);
103
104 static struct clnt_ops clnt_bck_ops = {
105         .cl_abort =     clnt_bck_abort,
106         .cl_geterr =    clnt_bck_geterr,
107         .cl_freeres =   clnt_bck_freeres,
108         .cl_close =     clnt_bck_close,
109         .cl_destroy =   clnt_bck_destroy,
110         .cl_control =   clnt_bck_control
111 };
112
113 /*
114  * Create a client handle for a connection.
115  * Default options are set, which the user can change using clnt_control()'s.
116  * This code handles the special case of an NFSv4.1 session backchannel
117  * call, which is sent on a TCP connection created against the server
118  * by a client.
119  */
120 void *
121 clnt_bck_create(
122         struct socket *so,              /* Server transport socket. */
123         const rpcprog_t prog,           /* program number */
124         const rpcvers_t vers)           /* version number */
125 {
126         CLIENT *cl;                     /* client handle */
127         struct ct_data *ct = NULL;      /* client handle */
128         struct timeval now;
129         struct rpc_msg call_msg;
130         static uint32_t disrupt;
131         XDR xdrs;
132
133         if (disrupt == 0)
134                 disrupt = (uint32_t)(long)so;
135
136         cl = (CLIENT *)mem_alloc(sizeof (*cl));
137         ct = (struct ct_data *)mem_alloc(sizeof (*ct));
138
139         mtx_init(&ct->ct_lock, "ct->ct_lock", NULL, MTX_DEF);
140         ct->ct_threads = 0;
141         ct->ct_closing = FALSE;
142         ct->ct_closed = FALSE;
143         ct->ct_upcallrefs = 0;
144         ct->ct_closeit = FALSE;
145
146         /*
147          * Set up private data struct
148          */
149         ct->ct_wait.tv_sec = -1;
150         ct->ct_wait.tv_usec = -1;
151
152         /*
153          * Initialize call message
154          */
155         getmicrotime(&now);
156         ct->ct_xid = ((uint32_t)++disrupt) ^ __RPC_GETXID(&now);
157         call_msg.rm_xid = ct->ct_xid;
158         call_msg.rm_direction = CALL;
159         call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
160         call_msg.rm_call.cb_prog = (uint32_t)prog;
161         call_msg.rm_call.cb_vers = (uint32_t)vers;
162
163         /*
164          * pre-serialize the static part of the call msg and stash it away
165          */
166         xdrmem_create(&xdrs, ct->ct_mcallc, MCALL_MSG_SIZE,
167             XDR_ENCODE);
168         if (!xdr_callhdr(&xdrs, &call_msg))
169                 goto err;
170         ct->ct_mpos = XDR_GETPOS(&xdrs);
171         XDR_DESTROY(&xdrs);
172         ct->ct_waitchan = "rpcbck";
173         ct->ct_waitflag = 0;
174         cl->cl_refs = 1;
175         cl->cl_ops = &clnt_bck_ops;
176         cl->cl_private = ct;
177         cl->cl_auth = authnone_create();
178         TAILQ_INIT(&ct->ct_pending);
179         return (cl);
180
181 err:
182         mtx_destroy(&ct->ct_lock);
183         mem_free(ct, sizeof (struct ct_data));
184         mem_free(cl, sizeof (CLIENT));
185         return (NULL);
186 }
187
188 enum clnt_stat
189 clnt_bck_call(
190         CLIENT          *cl,            /* client handle */
191         struct rpc_callextra *ext,      /* call metadata */
192         rpcproc_t       proc,           /* procedure number */
193         struct mbuf     *args,          /* pointer to args */
194         struct mbuf     **resultsp,     /* pointer to results */
195         struct timeval  utimeout,
196         SVCXPRT         *xprt)
197 {
198         struct ct_data *ct = (struct ct_data *) cl->cl_private;
199         AUTH *auth;
200         struct rpc_err *errp;
201         enum clnt_stat stat;
202         XDR xdrs;
203         struct rpc_msg reply_msg;
204         bool_t ok;
205         int nrefreshes = 2;             /* number of times to refresh cred */
206         struct timeval timeout;
207         uint32_t xid;
208         struct mbuf *mreq = NULL, *results;
209         struct ct_request *cr;
210         int error, maxextsiz;
211 #ifdef KERN_TLS
212         u_int maxlen;
213 #endif
214
215         cr = malloc(sizeof(struct ct_request), M_RPC, M_WAITOK);
216
217         mtx_lock(&ct->ct_lock);
218
219         if (ct->ct_closing || ct->ct_closed) {
220                 mtx_unlock(&ct->ct_lock);
221                 free(cr, M_RPC);
222                 return (RPC_CANTSEND);
223         }
224         ct->ct_threads++;
225
226         if (ext) {
227                 auth = ext->rc_auth;
228                 errp = &ext->rc_err;
229         } else {
230                 auth = cl->cl_auth;
231                 errp = &ct->ct_error;
232         }
233
234         cr->cr_mrep = NULL;
235         cr->cr_error = 0;
236
237         if (ct->ct_wait.tv_usec == -1)
238                 timeout = utimeout;     /* use supplied timeout */
239         else
240                 timeout = ct->ct_wait;  /* use default timeout */
241
242 call_again:
243         mtx_assert(&ct->ct_lock, MA_OWNED);
244
245         ct->ct_xid++;
246         xid = ct->ct_xid;
247
248         mtx_unlock(&ct->ct_lock);
249
250         /*
251          * Leave space to pre-pend the record mark.
252          */
253         mreq = m_gethdr(M_WAITOK, MT_DATA);
254         mreq->m_data += sizeof(uint32_t);
255         KASSERT(ct->ct_mpos + sizeof(uint32_t) <= MHLEN,
256             ("RPC header too big"));
257         bcopy(ct->ct_mcallc, mreq->m_data, ct->ct_mpos);
258         mreq->m_len = ct->ct_mpos;
259
260         /*
261          * The XID is the first thing in the request.
262          */
263         *mtod(mreq, uint32_t *) = htonl(xid);
264
265         xdrmbuf_create(&xdrs, mreq, XDR_ENCODE);
266
267         errp->re_status = stat = RPC_SUCCESS;
268
269         if ((!XDR_PUTINT32(&xdrs, &proc)) ||
270             (!AUTH_MARSHALL(auth, xid, &xdrs,
271              m_copym(args, 0, M_COPYALL, M_WAITOK)))) {
272                 errp->re_status = stat = RPC_CANTENCODEARGS;
273                 mtx_lock(&ct->ct_lock);
274                 goto out;
275         }
276         mreq->m_pkthdr.len = m_length(mreq, NULL);
277
278         /*
279          * Prepend a record marker containing the packet length.
280          */
281         M_PREPEND(mreq, sizeof(uint32_t), M_WAITOK);
282         *mtod(mreq, uint32_t *) =
283             htonl(0x80000000 | (mreq->m_pkthdr.len - sizeof(uint32_t)));
284
285         cr->cr_xid = xid;
286         mtx_lock(&ct->ct_lock);
287         /*
288          * Check to see if the client end has already started to close down
289          * the connection. The svc code will have set ct_error.re_status
290          * to RPC_CANTRECV if this is the case.
291          * If the client starts to close down the connection after this
292          * point, it will be detected later when cr_error is checked,
293          * since the request is in the ct_pending queue.
294          */
295         if (ct->ct_error.re_status == RPC_CANTRECV) {
296                 if (errp != &ct->ct_error) {
297                         errp->re_errno = ct->ct_error.re_errno;
298                         errp->re_status = RPC_CANTRECV;
299                 }
300                 stat = RPC_CANTRECV;
301                 goto out;
302         }
303         TAILQ_INSERT_TAIL(&ct->ct_pending, cr, cr_link);
304         mtx_unlock(&ct->ct_lock);
305
306         /* For RPC-over-TLS, copy mrep to a chain of ext_pgs. */
307         if ((xprt->xp_tls & RPCTLS_FLAGS_HANDSHAKE) != 0) {
308                 /*
309                  * Copy the mbuf chain to a chain of
310                  * ext_pgs mbuf(s) as required by KERN_TLS.
311                  */
312                 maxextsiz = TLS_MAX_MSG_SIZE_V10_2;
313 #ifdef KERN_TLS
314                 if (rpctls_getinfo(&maxlen, false, false))
315                         maxextsiz = min(maxextsiz, maxlen);
316 #endif
317                 mreq = _rpc_copym_into_ext_pgs(mreq, maxextsiz);
318         }
319         /*
320          * sosend consumes mreq.
321          */
322         sx_xlock(&xprt->xp_lock);
323         error = sosend(xprt->xp_socket, NULL, NULL, mreq, NULL, 0, curthread);
324 if (error != 0) printf("sosend=%d\n", error);
325         mreq = NULL;
326         if (error == EMSGSIZE) {
327 printf("emsgsize\n");
328                 SOCKBUF_LOCK(&xprt->xp_socket->so_snd);
329                 sbwait(&xprt->xp_socket->so_snd);
330                 SOCKBUF_UNLOCK(&xprt->xp_socket->so_snd);
331                 sx_xunlock(&xprt->xp_lock);
332                 AUTH_VALIDATE(auth, xid, NULL, NULL);
333                 mtx_lock(&ct->ct_lock);
334                 TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
335                 goto call_again;
336         }
337         sx_xunlock(&xprt->xp_lock);
338
339         reply_msg.acpted_rply.ar_verf.oa_flavor = AUTH_NULL;
340         reply_msg.acpted_rply.ar_verf.oa_base = cr->cr_verf;
341         reply_msg.acpted_rply.ar_verf.oa_length = 0;
342         reply_msg.acpted_rply.ar_results.where = NULL;
343         reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
344
345         mtx_lock(&ct->ct_lock);
346         if (error) {
347                 TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
348                 errp->re_errno = error;
349                 errp->re_status = stat = RPC_CANTSEND;
350                 goto out;
351         }
352
353         /*
354          * Check to see if we got an upcall while waiting for the
355          * lock. In both these cases, the request has been removed
356          * from ct->ct_pending.
357          */
358         if (cr->cr_error) {
359                 TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
360                 errp->re_errno = cr->cr_error;
361                 errp->re_status = stat = RPC_CANTRECV;
362                 goto out;
363         }
364         if (cr->cr_mrep) {
365                 TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
366                 goto got_reply;
367         }
368
369         /*
370          * Hack to provide rpc-based message passing
371          */
372         if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
373                 TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
374                 errp->re_status = stat = RPC_TIMEDOUT;
375                 goto out;
376         }
377
378         error = msleep(cr, &ct->ct_lock, ct->ct_waitflag, ct->ct_waitchan,
379             tvtohz(&timeout));
380
381         TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
382
383         if (error) {
384                 /*
385                  * The sleep returned an error so our request is still
386                  * on the list. Turn the error code into an
387                  * appropriate client status.
388                  */
389                 errp->re_errno = error;
390                 switch (error) {
391                 case EINTR:
392                         stat = RPC_INTR;
393                         break;
394                 case EWOULDBLOCK:
395                         stat = RPC_TIMEDOUT;
396                         break;
397                 default:
398                         stat = RPC_CANTRECV;
399                 }
400                 errp->re_status = stat;
401                 goto out;
402         } else {
403                 /*
404                  * We were woken up by the svc thread.  If the
405                  * upcall had a receive error, report that,
406                  * otherwise we have a reply.
407                  */
408                 if (cr->cr_error) {
409                         errp->re_errno = cr->cr_error;
410                         errp->re_status = stat = RPC_CANTRECV;
411                         goto out;
412                 }
413         }
414
415 got_reply:
416         /*
417          * Now decode and validate the response. We need to drop the
418          * lock since xdr_replymsg may end up sleeping in malloc.
419          */
420         mtx_unlock(&ct->ct_lock);
421
422         if (ext && ext->rc_feedback)
423                 ext->rc_feedback(FEEDBACK_OK, proc, ext->rc_feedback_arg);
424
425         xdrmbuf_create(&xdrs, cr->cr_mrep, XDR_DECODE);
426         ok = xdr_replymsg(&xdrs, &reply_msg);
427         cr->cr_mrep = NULL;
428
429         if (ok) {
430                 if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
431                     (reply_msg.acpted_rply.ar_stat == SUCCESS))
432                         errp->re_status = stat = RPC_SUCCESS;
433                 else
434                         stat = _seterr_reply(&reply_msg, errp);
435
436                 if (stat == RPC_SUCCESS) {
437                         results = xdrmbuf_getall(&xdrs);
438                         if (!AUTH_VALIDATE(auth, xid,
439                             &reply_msg.acpted_rply.ar_verf, &results)) {
440                                 errp->re_status = stat = RPC_AUTHERROR;
441                                 errp->re_why = AUTH_INVALIDRESP;
442                         } else {
443                                 KASSERT(results,
444                                     ("auth validated but no result"));
445                                 *resultsp = results;
446                         }
447                 }               /* end successful completion */
448                 /*
449                  * If unsuccessful AND error is an authentication error
450                  * then refresh credentials and try again, else break
451                  */
452                 else if (stat == RPC_AUTHERROR)
453                         /* maybe our credentials need to be refreshed ... */
454                         if (nrefreshes > 0 && AUTH_REFRESH(auth, &reply_msg)) {
455                                 nrefreshes--;
456                                 XDR_DESTROY(&xdrs);
457                                 mtx_lock(&ct->ct_lock);
458                                 goto call_again;
459                         }
460                         /* end of unsuccessful completion */
461                 /* end of valid reply message */
462         } else
463                 errp->re_status = stat = RPC_CANTDECODERES;
464         XDR_DESTROY(&xdrs);
465         mtx_lock(&ct->ct_lock);
466 out:
467         mtx_assert(&ct->ct_lock, MA_OWNED);
468
469         KASSERT(stat != RPC_SUCCESS || *resultsp,
470             ("RPC_SUCCESS without reply"));
471
472         if (mreq != NULL)
473                 m_freem(mreq);
474         if (cr->cr_mrep != NULL)
475                 m_freem(cr->cr_mrep);
476
477         ct->ct_threads--;
478         if (ct->ct_closing)
479                 wakeup(ct);
480                 
481         mtx_unlock(&ct->ct_lock);
482
483         if (auth && stat != RPC_SUCCESS)
484                 AUTH_VALIDATE(auth, xid, NULL, NULL);
485
486         free(cr, M_RPC);
487
488         return (stat);
489 }
490
491 static void
492 clnt_bck_geterr(CLIENT *cl, struct rpc_err *errp)
493 {
494         struct ct_data *ct = (struct ct_data *) cl->cl_private;
495
496         *errp = ct->ct_error;
497 }
498
499 static bool_t
500 clnt_bck_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
501 {
502         XDR xdrs;
503         bool_t dummy;
504
505         xdrs.x_op = XDR_FREE;
506         dummy = (*xdr_res)(&xdrs, res_ptr);
507
508         return (dummy);
509 }
510
511 /*ARGSUSED*/
512 static void
513 clnt_bck_abort(CLIENT *cl)
514 {
515 }
516
517 static bool_t
518 clnt_bck_control(CLIENT *cl, u_int request, void *info)
519 {
520
521         return (TRUE);
522 }
523
524 static void
525 clnt_bck_close(CLIENT *cl)
526 {
527         struct ct_data *ct = (struct ct_data *) cl->cl_private;
528
529         mtx_lock(&ct->ct_lock);
530
531         if (ct->ct_closed) {
532                 mtx_unlock(&ct->ct_lock);
533                 return;
534         }
535
536         if (ct->ct_closing) {
537                 while (ct->ct_closing)
538                         msleep(ct, &ct->ct_lock, 0, "rpcclose", 0);
539                 KASSERT(ct->ct_closed, ("client should be closed"));
540                 mtx_unlock(&ct->ct_lock);
541                 return;
542         }
543
544         ct->ct_closing = FALSE;
545         ct->ct_closed = TRUE;
546         mtx_unlock(&ct->ct_lock);
547         wakeup(ct);
548 }
549
550 static void
551 clnt_bck_destroy(CLIENT *cl)
552 {
553         struct ct_data *ct = (struct ct_data *) cl->cl_private;
554
555         clnt_bck_close(cl);
556
557         mtx_destroy(&ct->ct_lock);
558         mem_free(ct, sizeof(struct ct_data));
559         if (cl->cl_netid && cl->cl_netid[0])
560                 mem_free(cl->cl_netid, strlen(cl->cl_netid) +1);
561         if (cl->cl_tp && cl->cl_tp[0])
562                 mem_free(cl->cl_tp, strlen(cl->cl_tp) +1);
563         mem_free(cl, sizeof(CLIENT));
564 }
565
566 /*
567  * This call is done by the svc code when a backchannel RPC reply is
568  * received.
569  */
570 void
571 clnt_bck_svccall(void *arg, struct mbuf *mrep, uint32_t xid)
572 {
573         struct ct_data *ct = (struct ct_data *)arg;
574         struct ct_request *cr;
575         int foundreq;
576
577         mtx_lock(&ct->ct_lock);
578         ct->ct_upcallrefs++;
579         /*
580          * See if we can match this reply to a request.
581          */
582         foundreq = 0;
583         TAILQ_FOREACH(cr, &ct->ct_pending, cr_link) {
584                 if (cr->cr_xid == xid) {
585                         /*
586                          * This one matches. We leave the reply mbuf list in
587                          * cr->cr_mrep. Set the XID to zero so that we will
588                          * ignore any duplicated replies.
589                          */
590                         cr->cr_xid = 0;
591                         cr->cr_mrep = mrep;
592                         cr->cr_error = 0;
593                         foundreq = 1;
594                         wakeup(cr);
595                         break;
596                 }
597         }
598
599         ct->ct_upcallrefs--;
600         if (ct->ct_upcallrefs < 0)
601                 panic("rpcvc svccall refcnt");
602         if (ct->ct_upcallrefs == 0)
603                 wakeup(&ct->ct_upcallrefs);
604         mtx_unlock(&ct->ct_lock);
605         if (foundreq == 0)
606                 m_freem(mrep);
607 }
608