From owner-svn-src-head@FreeBSD.ORG Mon Aug 18 23:45:41 2014 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 5E01E9B1; Mon, 18 Aug 2014 23:45:41 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 4917C350F; Mon, 18 Aug 2014 23:45:41 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s7INjfgC066905; Mon, 18 Aug 2014 23:45:41 GMT (envelope-from marcel@FreeBSD.org) Received: (from marcel@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s7INjeWX066897; Mon, 18 Aug 2014 23:45:40 GMT (envelope-from marcel@FreeBSD.org) Message-Id: <201408182345.s7INjeWX066897@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: marcel set sender to marcel@FreeBSD.org using -f From: Marcel Moolenaar Date: Mon, 18 Aug 2014 23:45:40 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r270158 - in head/sys: kern sys X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 18 Aug 2014 23:45:41 -0000 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 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 #include #include /* for struct knote */ +#include #include +#include #include #include #include @@ -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 /* for struct selinfo */ #include #include +#include #include #include #include @@ -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;