tcp: add sysctl interface for setting socket options
This interface allows to set a socket option on a TCP endpoint, which is specified by its inp_gencnt. This interface will be used in an upcoming command line tool tcpsso. Reviewed by: glebius, rrs Sponsored by: Netflix, Inc. Differential Revision: https://reviews.freebsd.org/D34138
This commit is contained in:
parent
528c764924
commit
a35bdd4489
@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/priv.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/refcount.h>
|
||||
@ -2799,6 +2800,81 @@ in_pcbtoxinpcb(const struct inpcb *inp, struct xinpcb *xi)
|
||||
xi->inp_ip_minttl = inp->inp_ip_minttl;
|
||||
}
|
||||
|
||||
int
|
||||
sysctl_setsockopt(SYSCTL_HANDLER_ARGS, struct inpcbinfo *pcbinfo,
|
||||
int (*ctloutput_set)(struct inpcb *, struct sockopt *))
|
||||
{
|
||||
struct sockopt sopt;
|
||||
struct inpcb_iterator inpi = INP_ALL_ITERATOR(pcbinfo,
|
||||
INPLOOKUP_WLOCKPCB);
|
||||
struct inpcb *inp;
|
||||
struct sockopt_parameters *params;
|
||||
struct socket *so;
|
||||
int error;
|
||||
char buf[1024];
|
||||
|
||||
if (req->oldptr != NULL || req->oldlen != 0)
|
||||
return (EINVAL);
|
||||
if (req->newptr == NULL)
|
||||
return (EPERM);
|
||||
if (req->newlen > sizeof(buf))
|
||||
return (ENOMEM);
|
||||
error = SYSCTL_IN(req, buf, req->newlen);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
if (req->newlen < sizeof(struct sockopt_parameters))
|
||||
return (EINVAL);
|
||||
params = (struct sockopt_parameters *)buf;
|
||||
sopt.sopt_level = params->sop_level;
|
||||
sopt.sopt_name = params->sop_optname;
|
||||
sopt.sopt_dir = SOPT_SET;
|
||||
sopt.sopt_val = params->sop_optval;
|
||||
sopt.sopt_valsize = req->newlen - sizeof(struct sockopt_parameters);
|
||||
sopt.sopt_td = NULL;
|
||||
if (params->sop_inc.inc_flags & INC_ISIPV6) {
|
||||
if (IN6_IS_SCOPE_LINKLOCAL(¶ms->sop_inc.inc6_laddr))
|
||||
params->sop_inc.inc6_laddr.s6_addr16[1] =
|
||||
htons(params->sop_inc.inc6_zoneid & 0xffff);
|
||||
if (IN6_IS_SCOPE_LINKLOCAL(¶ms->sop_inc.inc6_faddr))
|
||||
params->sop_inc.inc6_faddr.s6_addr16[1] =
|
||||
htons(params->sop_inc.inc6_zoneid & 0xffff);
|
||||
}
|
||||
if (params->sop_inc.inc_lport != htons(0)) {
|
||||
if (params->sop_inc.inc_fport == htons(0))
|
||||
inpi.hash = INP_PCBHASH_WILD(params->sop_inc.inc_lport,
|
||||
pcbinfo->ipi_hashmask);
|
||||
else
|
||||
if (params->sop_inc.inc_flags & INC_ISIPV6)
|
||||
inpi.hash = INP6_PCBHASH(
|
||||
¶ms->sop_inc.inc6_faddr,
|
||||
params->sop_inc.inc_lport,
|
||||
params->sop_inc.inc_fport,
|
||||
pcbinfo->ipi_hashmask);
|
||||
else
|
||||
inpi.hash = INP_PCBHASH(
|
||||
¶ms->sop_inc.inc_faddr,
|
||||
params->sop_inc.inc_lport,
|
||||
params->sop_inc.inc_fport,
|
||||
pcbinfo->ipi_hashmask);
|
||||
}
|
||||
while ((inp = inp_next(&inpi)) != NULL)
|
||||
if (inp->inp_gencnt == params->sop_id) {
|
||||
if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
|
||||
INP_WUNLOCK(inp);
|
||||
return (ECONNRESET);
|
||||
}
|
||||
so = inp->inp_socket;
|
||||
KASSERT(so != NULL, ("inp_socket == NULL"));
|
||||
soref(so);
|
||||
error = (*ctloutput_set)(inp, &sopt);
|
||||
sorele(so);
|
||||
break;
|
||||
}
|
||||
if (inp == NULL)
|
||||
error = ESRCH;
|
||||
return (error);
|
||||
}
|
||||
|
||||
#ifdef DDB
|
||||
static void
|
||||
db_print_indent(int indent)
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include <sys/proc.h>
|
||||
#include <sys/rwlock.h>
|
||||
#include <sys/smr.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <net/vnet.h>
|
||||
#include <vm/uma.h>
|
||||
#endif
|
||||
@ -368,7 +369,18 @@ struct xinpgen {
|
||||
so_gen_t xig_sogen; /* socket generation count this time */
|
||||
uint64_t _xig_spare64[4];
|
||||
} __aligned(8);
|
||||
|
||||
struct sockopt_parameters {
|
||||
struct in_conninfo sop_inc;
|
||||
uint64_t sop_id;
|
||||
int sop_level;
|
||||
int sop_optname;
|
||||
char sop_optval[];
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
int sysctl_setsockopt(SYSCTL_HANDLER_ARGS, struct inpcbinfo *pcbinfo,
|
||||
int (*ctloutput_set)(struct inpcb *, struct sockopt *));
|
||||
void in_pcbtoxinpcb(const struct inpcb *, struct xinpcb *);
|
||||
#endif
|
||||
#endif /* _SYS_SOCKETVAR_H_ */
|
||||
|
@ -3834,6 +3834,18 @@ SYSCTL_PROC(_net_inet_tcp, TCPCTL_DROP, drop,
|
||||
CTLFLAG_NEEDGIANT, NULL, 0, sysctl_drop, "",
|
||||
"Drop TCP connection");
|
||||
|
||||
static int
|
||||
tcp_sysctl_setsockopt(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
return (sysctl_setsockopt(oidp, arg1, arg2, req, &V_tcbinfo,
|
||||
&tcp_ctloutput_set));
|
||||
}
|
||||
|
||||
SYSCTL_PROC(_net_inet_tcp, OID_AUTO, setsockopt,
|
||||
CTLFLAG_VNET | CTLTYPE_STRUCT | CTLFLAG_WR | CTLFLAG_SKIP |
|
||||
CTLFLAG_MPSAFE, NULL, 0, tcp_sysctl_setsockopt, "",
|
||||
"Set socket option for TCP endpoint");
|
||||
|
||||
#ifdef KERN_TLS
|
||||
static int
|
||||
sysctl_switch_tls(SYSCTL_HANDLER_ARGS)
|
||||
|
Loading…
Reference in New Issue
Block a user