/** * rpc_rdma_dispatcher_thread: setup NFS/RDMA engine * * Initially creates a listener and its connection manager epoll thread. * * Each connection request creates a child. * * The completion queue epoll thread is shared among all children. * * @param[in] xa must be init first * * @return NULL */ void * nfs_rdma_dispatcher_thread(void *nullarg) { struct rpc_rdma_attr xa = { .statistics_prefix = NULL, .node = "::", .port = "20049", .disconnect_cb = rpc_rdma_disconnect_callback, .request_cb = thr_decode_rpc_request, .timeout = 30000, /* in ms */ .sq_depth = 32, /* default was 50 */ .max_send_sge = 32, /* minimum 2 */ .rq_depth = 32, /* default was 50 */ .max_recv_sge = 31, /* minimum 1 */ .backlog = 10, /* minimum 2 */ .credits = 30, /* default 10 */ .worker_count = 4, /* default 0 */ .worker_queue_size = 256, /* default 0 */ .destroy_on_disconnect = true, .use_srq = false, }; SVCXPRT *l_xprt = rpc_rdma_create(&xa); if (!l_xprt) { LogCrit(COMPONENT_DISPATCH, "NFS/RDMA dispatcher could not start engine"); return NULL; } LogEvent(COMPONENT_DISPATCH, "NFS/RDMA engine initialized"); /* All clones and large allocations are done in this loop, * avoiding contention in the heap(s), serialized by the * connection_requests queue. */ while (l_xprt->xp_refs > 0) { /* values used in Mooshika were 8*1024, 4*8*1024; * should be configurable. */ SVCXPRT *c_xprt = svc_rdma_create(l_xprt, 4*1024, 4*1024, SVC_XPRT_FLAG_NONE); if (!c_xprt) { /* message already logged */ continue; } LogEvent(COMPONENT_DISPATCH, "cloned (child) transport %p", c_xprt); } /* We never get here, xp_refs is always > 0 until destroy */ SVC_DESTROY(l_xprt); return NULL; } /* rpc_rdma_dispatcher_thread */
int rpc_reg(const rpcprog_t prognum, const rpcvers_t versnum, const rpcproc_t procnum, char *(*progname)(), const xdrproc_t inproc, const xdrproc_t outproc, const char *nettype) { struct netconfig *nconf; int done = FALSE; void *handle; extern mutex_t proglst_lock; if (procnum == NULLPROC) { (void) syslog(LOG_ERR, (const char *) "%s: %s %d", rpc_reg_msg, (const char *) "can't reassign procedure number %d", NULLPROC); return (-1); } if (nettype == NULL) nettype = "netpath"; /* The default behavior */ if ((handle = __rpc_setconf((char *)nettype)) == NULL) { (void) syslog(LOG_ERR, rpc_reg_err, rpc_reg_msg, __reg_err1); return (-1); } /* VARIABLES PROTECTED BY proglst_lock: proglst */ (void) mutex_lock(&proglst_lock); while (nconf = __rpc_getconf(handle)) { struct proglst *pl; SVCXPRT *svcxprt; int madenow; uint_t recvsz; char *xdrbuf; char *netid; madenow = FALSE; svcxprt = NULL; for (pl = proglst; pl; pl = pl->p_nxt) if (strcmp(pl->p_netid, nconf->nc_netid) == 0) { svcxprt = pl->p_transp; xdrbuf = pl->p_xdrbuf; recvsz = pl->p_recvsz; netid = pl->p_netid; break; } if (svcxprt == NULL) { struct t_info tinfo; svcxprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0); if (svcxprt == NULL) continue; if (t_getinfo(svcxprt->xp_fd, &tinfo) == -1) { char errorstr[100]; __tli_sys_strerror(errorstr, sizeof (errorstr), t_errno, errno); (void) syslog(LOG_ERR, "%s : %s : %s", rpc_reg_msg, "t_getinfo failed", errorstr); SVC_DESTROY(svcxprt); continue; } if ((recvsz = __rpc_get_t_size(0, tinfo.tsdu)) == 0) { (void) syslog(LOG_ERR, rpc_reg_err, rpc_reg_msg, __reg_err3); SVC_DESTROY(svcxprt); continue; } if (((xdrbuf = malloc((unsigned)recvsz)) == NULL) || ((netid = strdup(nconf->nc_netid)) == NULL)) { (void) syslog(LOG_ERR, rpc_reg_err, rpc_reg_msg, __no_mem_str); SVC_DESTROY(svcxprt); break; } madenow = TRUE; } /* * Check if this (program, version, netid) had already been * registered. The check may save a few RPC calls to rpcbind */ for (pl = proglst; pl; pl = pl->p_nxt) if ((pl->p_prognum == prognum) && (pl->p_versnum == versnum) && (strcmp(pl->p_netid, netid) == 0)) break; if (pl == NULL) { /* Not yet */ /* * Note that if we're using a portmapper * instead of rpcbind then we can't do an * unregister operation here. * * The reason is that the portmapper unset * operation removes all the entries for a * given program/version regardelss of * transport protocol. * * The caller of this routine needs to ensure * that __pmap_unset() has been called for all * program/version service pairs they plan * to support before they start registering * each program/version/protocol triplet. */ if (!use_portmapper) (void) rpcb_unset(prognum, versnum, nconf); } else { /* so that svc_reg does not call rpcb_set() */ nconf = NULL; } if (!svc_reg(svcxprt, prognum, versnum, universal, nconf)) { (void) syslog(LOG_ERR, "%s couldn't register prog %d vers %d for %s", rpc_reg_msg, prognum, versnum, netid); if (madenow) { SVC_DESTROY(svcxprt); free(xdrbuf); free(netid); } continue; } pl = malloc(sizeof (struct proglst)); if (pl == NULL) { (void) syslog(LOG_ERR, rpc_reg_err, rpc_reg_msg, __no_mem_str); if (madenow) { SVC_DESTROY(svcxprt); free(xdrbuf); free(netid); } break; } pl->p_progname = progname; pl->p_prognum = prognum; pl->p_versnum = versnum; pl->p_procnum = procnum; pl->p_inproc = inproc; pl->p_outproc = outproc; pl->p_transp = svcxprt; pl->p_xdrbuf = xdrbuf; pl->p_recvsz = recvsz; pl->p_netid = netid; pl->p_nxt = proglst; proglst = pl; done = TRUE; } __rpc_endconf(handle); (void) mutex_unlock(&proglst_lock); if (done == FALSE) { (void) syslog(LOG_ERR, (const char *) "%s cant find suitable transport for %s", rpc_reg_msg, nettype); return (-1); } return (0); }
/* * Create the autofs service for amd */ int create_autofs_service(void) { struct t_bind *tbp = 0; int fd = -1, err = 1; /* assume failed */ plog(XLOG_INFO, "creating autofs service listener"); autofs_ncp = getnetconfigent(autofs_conftype); if (autofs_ncp == NULL) { plog(XLOG_ERROR, "create_autofs_service: cannot getnetconfigent for %s", autofs_conftype); goto out; } fd = t_open(autofs_ncp->nc_device, O_RDWR, NULL); if (fd < 0) { plog(XLOG_ERROR, "create_autofs_service: t_open failed (%s)", t_errlist[t_errno]); goto out; } tbp = (struct t_bind *) t_alloc(fd, T_BIND, T_ADDR); if (!tbp) { plog(XLOG_ERROR, "create_autofs_service: t_alloca failed"); goto out; } if (get_autofs_address(autofs_ncp, tbp) != 0) { plog(XLOG_ERROR, "create_autofs_service: get_autofs_address failed"); goto out; } autofs_xprt = svc_tli_create(fd, autofs_ncp, tbp, 0, 0); if (autofs_xprt == NULL) { plog(XLOG_ERROR, "cannot create autofs tli service for amd"); goto out; } rpcb_unset(AUTOFS_PROG, AUTOFS_VERS, autofs_ncp); if (svc_reg(autofs_xprt, AUTOFS_PROG, AUTOFS_VERS, autofs_program_1, autofs_ncp) == FALSE) { plog(XLOG_ERROR, "could not register amd AUTOFS service"); goto out; } err = 0; goto really_out; out: if (autofs_ncp) freenetconfigent(autofs_ncp); if (autofs_xprt) SVC_DESTROY(autofs_xprt); else { if (fd > 0) t_close(fd); } really_out: if (tbp) t_free((char *) tbp, T_BIND); dlog("create_autofs_service: returning %d\n", err); return err; }
void svc_getreq_common (const int fd) { enum xprt_stat stat; struct rpc_msg msg; register SVCXPRT *xprt; char cred_area[2 * MAX_AUTH_BYTES + RQCRED_SIZE]; msg.rm_call.cb_cred.oa_base = cred_area; msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); xprt = xports[fd]; /* Do we control fd? */ if (xprt == NULL) return; /* now receive msgs from xprtprt (support batch calls) */ do { if (SVC_RECV (xprt, &msg)) { /* now find the exported program and call it */ struct svc_callout *s; struct svc_req r; enum auth_stat why; rpcvers_t low_vers; rpcvers_t high_vers; int prog_found; r.rq_clntcred = &(cred_area[2 * MAX_AUTH_BYTES]); r.rq_xprt = xprt; r.rq_prog = msg.rm_call.cb_prog; r.rq_vers = msg.rm_call.cb_vers; r.rq_proc = msg.rm_call.cb_proc; r.rq_cred = msg.rm_call.cb_cred; /* first authenticate the message */ /* Check for null flavor and bypass these calls if possible */ if (msg.rm_call.cb_cred.oa_flavor == AUTH_NULL) { r.rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor; r.rq_xprt->xp_verf.oa_length = 0; } else if ((why = _authenticate (&r, &msg)) != AUTH_OK) { svcerr_auth (xprt, why); goto call_done; } /* now match message with a registered service */ prog_found = FALSE; low_vers = 0 - 1; high_vers = 0; for (s = svc_head; s != NULL_SVC; s = s->sc_next) { if (s->sc_prog == r.rq_prog) { if (s->sc_vers == r.rq_vers) { (*s->sc_dispatch) (&r, xprt); goto call_done; } /* found correct version */ prog_found = TRUE; if (s->sc_vers < low_vers) low_vers = s->sc_vers; if (s->sc_vers > high_vers) high_vers = s->sc_vers; } /* found correct program */ } /* if we got here, the program or version is not served ... */ if (prog_found) svcerr_progvers (xprt, low_vers, high_vers); else svcerr_noprog (xprt); /* Fall through to ... */ } call_done: if ((stat = SVC_STAT (xprt)) == XPRT_DIED) { SVC_DESTROY (xprt); break; } } while (stat == XPRT_MOREREQS); }
/* * The highest level interface for server creation. * Copied from svc_generic.c and cmd/keyserv/key_generic.c, but adapted * to work only for TPI_CLTS semantics, and to be called only once * from kwarnd.c. Returns 1 (interface created) on success and 0 * (no interfaces created) on failure. */ int svc_create_local_service(void (*dispatch) (), /* Dispatch function */ u_long prognum, /* Program number */ u_long versnum, /* Version number */ char *nettype, /* Networktype token */ char *servname) /* name of the srvc */ { int num = 0; SVCXPRT *xprt; struct netconfig *nconf; struct t_bind *bind_addr; void *net; int fd; struct nd_hostserv ns; struct nd_addrlist *nas; if ((net = __rpc_setconf(nettype)) == 0) { (void) syslog(LOG_ERR, gettext("svc_create: could not read netconfig database")); return (0); } while (nconf = __rpc_getconf(net)) { if ((strcmp(nconf->nc_protofmly, NC_LOOPBACK)) || (nconf->nc_semantics != NC_TPI_COTS_ORD)) continue; if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) < 0) { (void) syslog(LOG_ERR, gettext("svc_create: %s: cannot open connection: %s"), nconf->nc_netid, t_errlist[t_errno]); break; } /* * Negotiate for returning the uid of the caller. * This should be done before enabling the endpoint for * service via t_bind() (called in svc_tli_create()) * so that requests to kwarnd contain the uid. */ if (__rpc_negotiate_uid(fd) != 0) { syslog(LOG_ERR, gettext("Could not negotiate for" " uid with loopback transport %s"), nconf->nc_netid); t_close(fd); break; } /* LINTED pointer alignment */ bind_addr = (struct t_bind *) t_alloc(fd, T_BIND, T_ADDR); if ((bind_addr == NULL)) { (void) t_close(fd); (void) syslog(LOG_ERR, gettext("svc_create: t_alloc failed\n")); break; } ns.h_host = HOST_SELF; ns.h_serv = servname; if (!netdir_getbyname(nconf, &ns, &nas)) { /* Copy the address */ bind_addr->addr.len = nas->n_addrs->len; (void) memcpy(bind_addr->addr.buf, nas->n_addrs->buf, (int) nas->n_addrs->len); bind_addr->qlen = 8; netdir_free((char *) nas, ND_ADDRLIST); } else { (void) syslog(LOG_ERR, gettext("svc_create: no well known " "address for %s on %s\n"), servname, nconf->nc_netid); (void) t_free((char *) bind_addr, T_BIND); bind_addr = NULL; } xprt = svc_tli_create(fd, nconf, bind_addr, 0, 0); if (bind_addr) (void) t_free((char *) bind_addr, T_BIND); if (xprt == NULL) { (void) t_close(fd); (void) syslog(LOG_ERR, gettext("svc_create: svc_tli_create failed\n")); break; } else { (void) rpcb_unset(prognum, versnum, nconf); if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) { (void) syslog(LOG_ERR, gettext("svc_create: cannot" " register %d vers %d on %s"), prognum, versnum, nconf->nc_netid); SVC_DESTROY(xprt); /* also t_closes fd */ break; } num = 1; break; } } __rpc_endconf(net); return (num); }
static void push(int inlen, char *indata) { char host[MAXHOSTNAMELEN]; CLIENT *client; SVCXPRT *transp; int sock = RPC_ANYSOCK, status; u_int prog; bool_t sts = 0; pid_t pid; struct rusage res; snprintf(host, sizeof host, "%*.*s", inlen, inlen, indata); client = clnt_create(host, YPPROG, YPVERS, "tcp"); if (client == NULL) { if (Verbose) fprintf(stderr, "Target Host: %s\n", host); clnt_pcreateerror("yppush: Cannot create client"); return; } transp = svcudp_create(sock); if (transp == NULL) { fprintf(stderr, "yppush: Cannot create callback transport.\n"); return; } if (transp->xp_port >= IPPORT_RESERVED) { SVC_DESTROY(transp); fprintf(stderr, "yppush: Cannot allocate reserved port.\n"); return; } for (prog=0x40000000; prog<0x5fffffff; prog++) { if ((sts = svc_register(transp, prog, 1, yppush_xfrrespprog_1, IPPROTO_UDP))) break; } if (!sts) { fprintf(stderr, "yppush: Cannot register callback.\n"); return; } switch (pid=fork()) { case -1: fprintf(stderr, "yppush: Cannot fork.\n"); exit(1); case 0: my_svc_run(); exit(0); default: close(transp->xp_sock); transp->xp_sock = -1; req_xfr(pid, prog, transp, host, client); wait4(pid, &status, 0, &res); svc_unregister(prog, 1); if (client != NULL) clnt_destroy(client); /* XXX transp leak? */ } }
/* * For simplified, easy to use kind of rpc interfaces. * nettype indicates the type of transport on which the service will be * listening. Used for conservation of the system resource. Only one * handle is created for all the services (actually one of each netid) * and same xdrbuf is used for same netid. The size of the arguments * is also limited by the recvsize for that transport, even if it is * a COTS transport. This may be wrong, but for cases like these, they * should not use the simplified interfaces like this. * * prognum - program number * versnum - version number * procnum - procedure number * progname - Server routine * inproc, outproc - in/out XDR procedures * nettype - nettype */ int rpc_reg(rpcprog_t prognum, rpcvers_t versnum, rpcproc_t procnum, char *(*progname)(char *), xdrproc_t inproc, xdrproc_t outproc, char *nettype) { struct netconfig *nconf; int done = FALSE; void *handle; if (procnum == NULLPROC) { warnx("%s can't reassign procedure number %u", rpc_reg_msg, NULLPROC); return (-1); } if (nettype == NULL) nettype = "netpath"; /* The default behavior */ if ((handle = __rpc_setconf(nettype)) == NULL) { warnx(rpc_reg_err, rpc_reg_msg, __reg_err1); return (-1); } /* VARIABLES PROTECTED BY proglst_lock: proglst */ mutex_lock(&proglst_lock); while ((nconf = __rpc_getconf(handle)) != NULL) { struct proglst *pl; SVCXPRT *svcxprt; int madenow; u_int recvsz; char *xdrbuf; char *netid; madenow = FALSE; svcxprt = NULL; recvsz = 0; xdrbuf = netid = NULL; for (pl = proglst; pl; pl = pl->p_nxt) { if (strcmp(pl->p_netid, nconf->nc_netid) == 0) { svcxprt = pl->p_transp; xdrbuf = pl->p_xdrbuf; recvsz = pl->p_recvsz; netid = pl->p_netid; break; } } if (svcxprt == NULL) { struct __rpc_sockinfo si; svcxprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0); if (svcxprt == NULL) continue; if (!__rpc_fd2sockinfo(svcxprt->xp_fd, &si)) { warnx(rpc_reg_err, rpc_reg_msg, __reg_err2); SVC_DESTROY(svcxprt); continue; } recvsz = __rpc_get_t_size(si.si_af, si.si_proto, 0); if (recvsz == 0) { warnx(rpc_reg_err, rpc_reg_msg, __reg_err3); SVC_DESTROY(svcxprt); continue; } if (((xdrbuf = malloc((unsigned)recvsz)) == NULL) || ((netid = strdup(nconf->nc_netid)) == NULL)) { warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str); free(xdrbuf); free(netid); SVC_DESTROY(svcxprt); break; } madenow = TRUE; } /* * Check if this (program, version, netid) had already been * registered. The check may save a few RPC calls to rpcbind */ for (pl = proglst; pl; pl = pl->p_nxt) if ((pl->p_prognum == prognum) && (pl->p_versnum == versnum) && (strcmp(pl->p_netid, netid) == 0)) break; if (pl == NULL) { /* Not yet */ (void) rpcb_unset(prognum, versnum, nconf); } else { /* so that svc_reg does not call rpcb_set() */ nconf = NULL; } if (!svc_reg(svcxprt, prognum, versnum, universal, nconf)) { warnx("%s couldn't register prog %u vers %u for %s", rpc_reg_msg, (unsigned)prognum, (unsigned)versnum, netid); if (madenow) { SVC_DESTROY(svcxprt); free(xdrbuf); free(netid); } continue; } pl = malloc(sizeof (struct proglst)); if (pl == NULL) { warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str); if (madenow) { SVC_DESTROY(svcxprt); free(xdrbuf); free(netid); } break; } pl->p_progname = progname; pl->p_prognum = prognum; pl->p_versnum = versnum; pl->p_procnum = procnum; pl->p_inproc = inproc; pl->p_outproc = outproc; pl->p_transp = svcxprt; pl->p_xdrbuf = xdrbuf; pl->p_recvsz = recvsz; pl->p_netid = netid; pl->p_nxt = proglst; proglst = pl; done = TRUE; } __rpc_endconf(handle); mutex_unlock(&proglst_lock); if (done == FALSE) { warnx("%s can't find suitable transport for %s", rpc_reg_msg, nettype); return (-1); } return (0); }
void svc_getreq_common(int fd) { enum xprt_stat stat; struct rpc_msg msg; int prog_found; u_long low_vers; u_long high_vers; struct svc_req r; SVCXPRT *xprt; char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE]; msg.rm_call.cb_cred.oa_base = cred_area; msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]); /* sock has input waiting */ xprt = xports[fd]; if (xprt == NULL) /* But do we control the fd? */ return; /* now receive msgs from xprtprt (support batch calls) */ do { if (SVC_RECV(xprt, &msg)) { /* find the exported program and call it */ struct svc_callout *s; enum auth_stat why; r.rq_xprt = xprt; r.rq_prog = msg.rm_call.cb_prog; r.rq_vers = msg.rm_call.cb_vers; r.rq_proc = msg.rm_call.cb_proc; r.rq_cred = msg.rm_call.cb_cred; /* first authenticate the message */ if ((why= _authenticate(&r, &msg)) != AUTH_OK) { svcerr_auth(xprt, why); goto call_done; } /* now match message with a registered service*/ prog_found = FALSE; low_vers = (u_long) -1; high_vers = 0; for (s = svc_head; s != NULL; s = s->sc_next) { if (s->sc_prog == r.rq_prog) { if (s->sc_vers == r.rq_vers) { (*s->sc_dispatch)(&r, xprt); goto call_done; } /* found correct version */ prog_found = TRUE; if (s->sc_vers < low_vers) low_vers = s->sc_vers; if (s->sc_vers > high_vers) high_vers = s->sc_vers; } /* found correct program */ } /* * if we got here, the program or version * is not served ... */ if (prog_found) svcerr_progvers(xprt, low_vers, high_vers); else svcerr_noprog(xprt); /* Fall through to ... */ } call_done: if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ SVC_DESTROY(xprt); break; } } while (stat == XPRT_MOREREQS); }