Date: Mon, 18 Aug 2014 23:45:40 +0000 (UTC) From: Marcel Moolenaar <marcel@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r270158 - in head/sys: kern sys Message-ID: <201408182345.s7INjeWX066897@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: marcel Date: Mon Aug 18 23:45:40 2014 New Revision: 270158 URL: http://svnweb.freebsd.org/changeset/base/270158 Log: For vendors like Juniper, extensibility for sockets is important. A good example is socket options that aren't necessarily generic. To this end, OSD is added to the socket structure and hooks are defined for key operations on sockets. These are: o soalloc() and sodealloc() o Get and set socket options o Socket related kevent filters. One aspect about hhook that appears to be not fully baked is the return semantics (the return value from the hook is ignored in hhook_run_hooks() at the time of commit). To support return values, the socket_hhook_data structure contains a 'status' field to hold return values. Submitted by: Anuranjan Shukla <anshukla@juniper.net> Obtained from: Juniper Networks, Inc. Modified: head/sys/kern/uipc_socket.c head/sys/sys/hhook.h head/sys/sys/khelp.h head/sys/sys/socketvar.h Modified: head/sys/kern/uipc_socket.c ============================================================================== --- head/sys/kern/uipc_socket.c Mon Aug 18 22:53:48 2014 (r270157) +++ head/sys/kern/uipc_socket.c Mon Aug 18 23:45:40 2014 (r270158) @@ -118,7 +118,9 @@ __FBSDID("$FreeBSD$"); #include <sys/mutex.h> #include <sys/domain.h> #include <sys/file.h> /* for struct knote */ +#include <sys/hhook.h> #include <sys/kernel.h> +#include <sys/khelp.h> #include <sys/event.h> #include <sys/eventhandler.h> #include <sys/poll.h> @@ -157,6 +159,7 @@ static int filt_soread(struct knote *kn, static void filt_sowdetach(struct knote *kn); static int filt_sowrite(struct knote *kn, long hint); static int filt_solisten(struct knote *kn, long hint); +static int inline hhook_run_socket(struct socket *so, void *hctx, int32_t h_id); static struct filterops solisten_filtops = { .f_isfd = 1, @@ -183,6 +186,9 @@ MALLOC_DEFINE(M_PCB, "pcb", "protocol co VNET_ASSERT(curvnet != NULL, \ ("%s:%d curvnet is NULL, so=%p", __func__, __LINE__, (so))); +VNET_DEFINE(struct hhook_head *, socket_hhh[HHOOK_SOCKET_LAST + 1]); +#define V_socket_hhh VNET(socket_hhh) + /* * Limit on the number of connections in the listen queue waiting * for accept(2). @@ -255,8 +261,19 @@ socket_zone_change(void *tag) } static void +socket_hhook_register(int subtype) +{ + + if (hhook_head_register(HHOOK_TYPE_SOCKET, subtype, + &V_socket_hhh[subtype], + HHOOK_NOWAIT|HHOOK_HEADISINVNET) != 0) + printf("%s: WARNING: unable to register hook\n", __func__); +} + +static void socket_init(void *tag) { + int i; socket_zone = uma_zcreate("socket", sizeof(struct socket), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); @@ -264,6 +281,11 @@ socket_init(void *tag) uma_zone_set_warning(socket_zone, "kern.ipc.maxsockets limit reached"); EVENTHANDLER_REGISTER(maxsockets_change, socket_zone_change, NULL, EVENTHANDLER_PRI_FIRST); + + /* We expect a contiguous range */ + for (i = 0; i <= HHOOK_SOCKET_LAST; i++) { + socket_hhook_register(i); + } } SYSINIT(socket, SI_SUB_PROTO_DOMAININIT, SI_ORDER_ANY, socket_init, NULL); @@ -333,6 +355,11 @@ soalloc(struct vnet *vnet) return (NULL); } #endif + if (khelp_init_osd(HELPER_CLASS_SOCKET, &so->osd)) { + uma_zfree(socket_zone, so); + return (NULL); + } + SOCKBUF_LOCK_INIT(&so->so_snd, "so_snd"); SOCKBUF_LOCK_INIT(&so->so_rcv, "so_rcv"); sx_init(&so->so_snd.sb_sx, "so_snd_sx"); @@ -348,6 +375,13 @@ soalloc(struct vnet *vnet) so->so_vnet = vnet; #endif mtx_unlock(&so_global_mtx); + + /* We shouldn't need the so_global_mtx */ + if (V_socket_hhh[HHOOK_SOCKET_CREATE]->hhh_nhooks > 0) { + if (hhook_run_socket(so, NULL, HHOOK_SOCKET_CREATE)) + /* Do we need more comprehensive error returns? */ + return (NULL); + } return (so); } @@ -384,7 +418,11 @@ sodealloc(struct socket *so) #ifdef MAC mac_socket_destroy(so); #endif + if (V_socket_hhh[HHOOK_SOCKET_CLOSE]->hhh_nhooks > 0) + hhook_run_socket(so, NULL, HHOOK_SOCKET_CLOSE); + crfree(so->so_cred); + khelp_destroy_osd(&so->osd); sx_destroy(&so->so_snd.sb_sx); sx_destroy(&so->so_rcv.sb_sx); SOCKBUF_LOCK_DESTROY(&so->so_snd); @@ -2328,6 +2366,25 @@ sorflush(struct socket *so) } /* + * Wrapper for Socket established helper hook. + * Parameters: socket, context of the hook point, hook id. + */ +static int inline +hhook_run_socket(struct socket *so, void *hctx, int32_t h_id) +{ + struct socket_hhook_data hhook_data = { + .so = so, + .hctx = hctx, + .m = NULL + }; + + hhook_run_hooks(V_socket_hhh[h_id], &hhook_data, &so->osd); + + /* Ugly but needed, since hhooks return void for now */ + return (hhook_data.status); +} + +/* * Perhaps this routine, and sooptcopyout(), below, ought to come in an * additional variant to handle the case where the option value needs to be * some kind of integer, but not a specific size. In addition to their use @@ -2572,7 +2629,11 @@ sosetopt(struct socket *so, struct socko break; default: - error = ENOPROTOOPT; + if (V_socket_hhh[HHOOK_SOCKET_OPT]->hhh_nhooks > 0) + error = hhook_run_socket(so, sopt, + HHOOK_SOCKET_OPT); + else + error = ENOPROTOOPT; break; } if (error == 0 && so->so_proto->pr_ctloutput != NULL) @@ -2755,7 +2816,11 @@ integer: goto integer; default: - error = ENOPROTOOPT; + if (V_socket_hhh[HHOOK_SOCKET_OPT]->hhh_nhooks > 0) + error = hhook_run_socket(so, sopt, + HHOOK_SOCKET_OPT); + else + error = ENOPROTOOPT; break; } } @@ -3160,10 +3225,20 @@ filt_soread(struct knote *kn, long hint) return (1); } else if (so->so_error) /* temporary udp error */ return (1); - else if (kn->kn_sfflags & NOTE_LOWAT) - return (kn->kn_data >= kn->kn_sdata); - else - return (so->so_rcv.sb_cc >= so->so_rcv.sb_lowat); + + if (kn->kn_sfflags & NOTE_LOWAT) { + if (kn->kn_data >= kn->kn_sdata) + return 1; + } else { + if (so->so_rcv.sb_cc >= so->so_rcv.sb_lowat) + return 1; + } + + if (V_socket_hhh[HHOOK_FILT_SOREAD]->hhh_nhooks > 0) + /* This hook returning non-zero indicates an event, not error */ + return (hhook_run_socket(so, NULL, HHOOK_FILT_SOREAD)); + + return (0); } static void @@ -3187,6 +3262,10 @@ filt_sowrite(struct knote *kn, long hint so = kn->kn_fp->f_data; SOCKBUF_LOCK_ASSERT(&so->so_snd); kn->kn_data = sbspace(&so->so_snd); + + if (V_socket_hhh[HHOOK_FILT_SOWRITE]->hhh_nhooks > 0) + hhook_run_socket(so, kn, HHOOK_FILT_SOWRITE); + if (so->so_snd.sb_state & SBS_CANTSENDMORE) { kn->kn_flags |= EV_EOF; kn->kn_fflags = so->so_error; Modified: head/sys/sys/hhook.h ============================================================================== --- head/sys/sys/hhook.h Mon Aug 18 22:53:48 2014 (r270157) +++ head/sys/sys/hhook.h Mon Aug 18 23:45:40 2014 (r270158) @@ -64,6 +64,7 @@ /* Helper hook types. */ #define HHOOK_TYPE_TCP 1 +#define HHOOK_TYPE_SOCKET 2 struct helper; struct osd; Modified: head/sys/sys/khelp.h ============================================================================== --- head/sys/sys/khelp.h Mon Aug 18 22:53:48 2014 (r270157) +++ head/sys/sys/khelp.h Mon Aug 18 23:45:40 2014 (r270158) @@ -55,6 +55,7 @@ struct osd; /* Helper classes. */ #define HELPER_CLASS_TCP 0x00000001 +#define HELPER_CLASS_SOCKET 0x00000002 /* Public KPI functions. */ int khelp_register_helper(struct helper *h); Modified: head/sys/sys/socketvar.h ============================================================================== --- head/sys/sys/socketvar.h Mon Aug 18 22:53:48 2014 (r270157) +++ head/sys/sys/socketvar.h Mon Aug 18 23:45:40 2014 (r270158) @@ -38,6 +38,7 @@ #include <sys/selinfo.h> /* for struct selinfo */ #include <sys/_lock.h> #include <sys/_mutex.h> +#include <sys/osd.h> #include <sys/_sx.h> #include <sys/sockbuf.h> #include <sys/sockstate.h> @@ -117,6 +118,7 @@ struct socket { void *so_accept_filter_arg; /* saved filter args */ char *so_accept_filter_str; /* saved user args */ } *so_accf; + struct osd osd; /* Object Specific extensions */ /* * so_fibnum, so_user_cookie and friends can be used to attach * some user-specified metadata to a socket, which then can be @@ -292,6 +294,26 @@ MALLOC_DECLARE(M_PCB); MALLOC_DECLARE(M_SONAME); #endif +/* + * Socket specific helper hook point identifiers + * Do not leave holes in the sequence, hook registration is a loop. + */ +#define HHOOK_SOCKET_OPT 0 +#define HHOOK_SOCKET_CREATE 1 +#define HHOOK_SOCKET_RCV 2 +#define HHOOK_SOCKET_SND 3 +#define HHOOK_FILT_SOREAD 4 +#define HHOOK_FILT_SOWRITE 5 +#define HHOOK_SOCKET_CLOSE 6 +#define HHOOK_SOCKET_LAST HHOOK_SOCKET_CLOSE + +struct socket_hhook_data { + struct socket *so; + struct mbuf *m; + void *hctx; /* hook point specific data*/ + int status; +}; + extern int maxsockets; extern u_long sb_max; extern so_gen_t so_gencnt;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201408182345.s7INjeWX066897>