1*45a4b79dSSebastien Roy /*
2*45a4b79dSSebastien Roy * Copyright (c) 2007-2008
3*45a4b79dSSebastien Roy * Swinburne University of Technology, Melbourne, Australia.
4*45a4b79dSSebastien Roy * Copyright (c) 2009-2010 Lawrence Stewart <lstewart@freebsd.org>
5*45a4b79dSSebastien Roy * Copyright (c) 2010 The FreeBSD Foundation
6*45a4b79dSSebastien Roy * All rights reserved.
7*45a4b79dSSebastien Roy * Copyright (c) 2017 by Delphix. All rights reserved.
8*45a4b79dSSebastien Roy *
9*45a4b79dSSebastien Roy * This software was developed at the Centre for Advanced Internet
10*45a4b79dSSebastien Roy * Architectures, Swinburne University of Technology, by Lawrence Stewart and
11*45a4b79dSSebastien Roy * James Healy, made possible in part by a grant from the Cisco University
12*45a4b79dSSebastien Roy * Research Program Fund at Community Foundation Silicon Valley.
13*45a4b79dSSebastien Roy *
14*45a4b79dSSebastien Roy * Portions of this software were developed at the Centre for Advanced
15*45a4b79dSSebastien Roy * Internet Architectures, Swinburne University of Technology, Melbourne,
16*45a4b79dSSebastien Roy * Australia by David Hayes under sponsorship from the FreeBSD Foundation.
17*45a4b79dSSebastien Roy *
18*45a4b79dSSebastien Roy * Redistribution and use in source and binary forms, with or without
19*45a4b79dSSebastien Roy * modification, are permitted provided that the following conditions
20*45a4b79dSSebastien Roy * are met:
21*45a4b79dSSebastien Roy * 1. Redistributions of source code must retain the above copyright
22*45a4b79dSSebastien Roy * notice, this list of conditions and the following disclaimer.
23*45a4b79dSSebastien Roy * 2. Redistributions in binary form must reproduce the above copyright
24*45a4b79dSSebastien Roy * notice, this list of conditions and the following disclaimer in the
25*45a4b79dSSebastien Roy * documentation and/or other materials provided with the distribution.
26*45a4b79dSSebastien Roy *
27*45a4b79dSSebastien Roy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
28*45a4b79dSSebastien Roy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29*45a4b79dSSebastien Roy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30*45a4b79dSSebastien Roy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
31*45a4b79dSSebastien Roy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32*45a4b79dSSebastien Roy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33*45a4b79dSSebastien Roy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34*45a4b79dSSebastien Roy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35*45a4b79dSSebastien Roy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36*45a4b79dSSebastien Roy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37*45a4b79dSSebastien Roy * SUCH DAMAGE.
38*45a4b79dSSebastien Roy */
39*45a4b79dSSebastien Roy
40*45a4b79dSSebastien Roy /*
41*45a4b79dSSebastien Roy * This software was first released in 2007 by James Healy and Lawrence Stewart
42*45a4b79dSSebastien Roy * whilst working on the NewTCP research project at Swinburne University of
43*45a4b79dSSebastien Roy * Technology's Centre for Advanced Internet Architectures, Melbourne,
44*45a4b79dSSebastien Roy * Australia, which was made possible in part by a grant from the Cisco
45*45a4b79dSSebastien Roy * University Research Program Fund at Community Foundation Silicon Valley.
46*45a4b79dSSebastien Roy * More details are available at:
47*45a4b79dSSebastien Roy * http://caia.swin.edu.au/urp/newtcp/
48*45a4b79dSSebastien Roy */
49*45a4b79dSSebastien Roy
50*45a4b79dSSebastien Roy #include <sys/param.h>
51*45a4b79dSSebastien Roy #include <sys/errno.h>
52*45a4b79dSSebastien Roy #include <sys/systm.h>
53*45a4b79dSSebastien Roy #include <sys/queue.h>
54*45a4b79dSSebastien Roy #include <inet/cc.h>
55*45a4b79dSSebastien Roy #include <inet/tcp.h>
56*45a4b79dSSebastien Roy #include <sys/sdt.h>
57*45a4b79dSSebastien Roy
58*45a4b79dSSebastien Roy #define CC_KMODDIR "cc"
59*45a4b79dSSebastien Roy
60*45a4b79dSSebastien Roy /*
61*45a4b79dSSebastien Roy * List of available cc algorithms on the current system. Access is
62*45a4b79dSSebastien Roy * synchronized using cc_list_lock.
63*45a4b79dSSebastien Roy */
64*45a4b79dSSebastien Roy static STAILQ_HEAD(cc_head, cc_algo) cc_list = STAILQ_HEAD_INITIALIZER(cc_list);
65*45a4b79dSSebastien Roy static kmutex_t cc_list_lock;
66*45a4b79dSSebastien Roy
67*45a4b79dSSebastien Roy static struct modlmisc cc_modlmisc = {
68*45a4b79dSSebastien Roy &mod_miscops,
69*45a4b79dSSebastien Roy "Pluggable Congestion Control Framework"
70*45a4b79dSSebastien Roy };
71*45a4b79dSSebastien Roy
72*45a4b79dSSebastien Roy static struct modlinkage cc_modlinkage = {
73*45a4b79dSSebastien Roy MODREV_1,
74*45a4b79dSSebastien Roy &cc_modlmisc,
75*45a4b79dSSebastien Roy NULL
76*45a4b79dSSebastien Roy };
77*45a4b79dSSebastien Roy
78*45a4b79dSSebastien Roy /*
79*45a4b79dSSebastien Roy * Initialise CC subsystem on system boot.
80*45a4b79dSSebastien Roy */
81*45a4b79dSSebastien Roy int
_init(void)82*45a4b79dSSebastien Roy _init(void)
83*45a4b79dSSebastien Roy {
84*45a4b79dSSebastien Roy STAILQ_INIT(&cc_list);
85*45a4b79dSSebastien Roy
86*45a4b79dSSebastien Roy return (mod_install(&cc_modlinkage));
87*45a4b79dSSebastien Roy }
88*45a4b79dSSebastien Roy
89*45a4b79dSSebastien Roy int
_fini(void)90*45a4b79dSSebastien Roy _fini(void)
91*45a4b79dSSebastien Roy {
92*45a4b79dSSebastien Roy return (EBUSY);
93*45a4b79dSSebastien Roy }
94*45a4b79dSSebastien Roy
95*45a4b79dSSebastien Roy int
_info(struct modinfo * modinfop)96*45a4b79dSSebastien Roy _info(struct modinfo *modinfop)
97*45a4b79dSSebastien Roy {
98*45a4b79dSSebastien Roy return (mod_info(&cc_modlinkage, modinfop));
99*45a4b79dSSebastien Roy }
100*45a4b79dSSebastien Roy
101*45a4b79dSSebastien Roy int
cc_walk_algos(cc_walk_func_t * func,void * cd)102*45a4b79dSSebastien Roy cc_walk_algos(cc_walk_func_t *func, void *cd)
103*45a4b79dSSebastien Roy {
104*45a4b79dSSebastien Roy struct cc_algo *algo;
105*45a4b79dSSebastien Roy int ret = 0;
106*45a4b79dSSebastien Roy
107*45a4b79dSSebastien Roy mutex_enter(&cc_list_lock);
108*45a4b79dSSebastien Roy STAILQ_FOREACH(algo, &cc_list, entries) {
109*45a4b79dSSebastien Roy if ((ret = func(cd, algo)) != 0) {
110*45a4b79dSSebastien Roy break;
111*45a4b79dSSebastien Roy }
112*45a4b79dSSebastien Roy }
113*45a4b79dSSebastien Roy mutex_exit(&cc_list_lock);
114*45a4b79dSSebastien Roy
115*45a4b79dSSebastien Roy return (ret);
116*45a4b79dSSebastien Roy }
117*45a4b79dSSebastien Roy
118*45a4b79dSSebastien Roy /*
119*45a4b79dSSebastien Roy * Search for an algorithm of a given name, and return the corresponding set of
120*45a4b79dSSebastien Roy * operations. If there is no algorithm with the given name present, then this
121*45a4b79dSSebastien Roy * function returns NULL.
122*45a4b79dSSebastien Roy *
123*45a4b79dSSebastien Roy * Since this function is passed names from userland, it needs to be paranoid
124*45a4b79dSSebastien Roy * about the string, in case it's missing a terminating NUL character.
125*45a4b79dSSebastien Roy */
126*45a4b79dSSebastien Roy struct cc_algo *
cc_load_algo(const char * name)127*45a4b79dSSebastien Roy cc_load_algo(const char *name)
128*45a4b79dSSebastien Roy {
129*45a4b79dSSebastien Roy struct cc_algo *algo;
130*45a4b79dSSebastien Roy boolean_t found = B_FALSE;
131*45a4b79dSSebastien Roy
132*45a4b79dSSebastien Roy if (strnlen(name, CC_ALGO_NAME_MAX) >= CC_ALGO_NAME_MAX) {
133*45a4b79dSSebastien Roy return (NULL);
134*45a4b79dSSebastien Roy }
135*45a4b79dSSebastien Roy
136*45a4b79dSSebastien Roy mutex_enter(&cc_list_lock);
137*45a4b79dSSebastien Roy STAILQ_FOREACH(algo, &cc_list, entries) {
138*45a4b79dSSebastien Roy if (strncmp(algo->name, name, CC_ALGO_NAME_MAX) == 0) {
139*45a4b79dSSebastien Roy found = B_TRUE;
140*45a4b79dSSebastien Roy break;
141*45a4b79dSSebastien Roy }
142*45a4b79dSSebastien Roy }
143*45a4b79dSSebastien Roy mutex_exit(&cc_list_lock);
144*45a4b79dSSebastien Roy
145*45a4b79dSSebastien Roy return (found ? algo : NULL);
146*45a4b79dSSebastien Roy }
147*45a4b79dSSebastien Roy
148*45a4b79dSSebastien Roy /*
149*45a4b79dSSebastien Roy * Returns non-zero on success, 0 on failure.
150*45a4b79dSSebastien Roy */
151*45a4b79dSSebastien Roy int
cc_deregister_algo(struct cc_algo * remove_cc)152*45a4b79dSSebastien Roy cc_deregister_algo(struct cc_algo *remove_cc)
153*45a4b79dSSebastien Roy {
154*45a4b79dSSebastien Roy struct cc_algo *funcs, *tmpfuncs;
155*45a4b79dSSebastien Roy int err = ENOENT;
156*45a4b79dSSebastien Roy
157*45a4b79dSSebastien Roy mutex_enter(&cc_list_lock);
158*45a4b79dSSebastien Roy STAILQ_FOREACH_SAFE(funcs, &cc_list, entries, tmpfuncs) {
159*45a4b79dSSebastien Roy if (funcs == remove_cc) {
160*45a4b79dSSebastien Roy STAILQ_REMOVE(&cc_list, funcs, cc_algo, entries);
161*45a4b79dSSebastien Roy err = 0;
162*45a4b79dSSebastien Roy break;
163*45a4b79dSSebastien Roy }
164*45a4b79dSSebastien Roy }
165*45a4b79dSSebastien Roy mutex_exit(&cc_list_lock);
166*45a4b79dSSebastien Roy return (err);
167*45a4b79dSSebastien Roy }
168*45a4b79dSSebastien Roy
169*45a4b79dSSebastien Roy /*
170*45a4b79dSSebastien Roy * Returns 0 on success, non-zero on failure.
171*45a4b79dSSebastien Roy */
172*45a4b79dSSebastien Roy int
cc_register_algo(struct cc_algo * add_cc)173*45a4b79dSSebastien Roy cc_register_algo(struct cc_algo *add_cc)
174*45a4b79dSSebastien Roy {
175*45a4b79dSSebastien Roy struct cc_algo *funcs;
176*45a4b79dSSebastien Roy size_t nlen;
177*45a4b79dSSebastien Roy int err = 0;
178*45a4b79dSSebastien Roy
179*45a4b79dSSebastien Roy nlen = strnlen(add_cc->name, CC_ALGO_NAME_MAX);
180*45a4b79dSSebastien Roy if (nlen == 0 || nlen >= CC_ALGO_NAME_MAX) {
181*45a4b79dSSebastien Roy return (EINVAL);
182*45a4b79dSSebastien Roy }
183*45a4b79dSSebastien Roy
184*45a4b79dSSebastien Roy /*
185*45a4b79dSSebastien Roy * Iterate over list of registered CC algorithms and make sure
186*45a4b79dSSebastien Roy * we're not trying to add a duplicate.
187*45a4b79dSSebastien Roy */
188*45a4b79dSSebastien Roy mutex_enter(&cc_list_lock);
189*45a4b79dSSebastien Roy STAILQ_FOREACH(funcs, &cc_list, entries) {
190*45a4b79dSSebastien Roy if (strncmp(funcs->name, add_cc->name, CC_ALGO_NAME_MAX) == 0)
191*45a4b79dSSebastien Roy err = EEXIST;
192*45a4b79dSSebastien Roy }
193*45a4b79dSSebastien Roy
194*45a4b79dSSebastien Roy if (err == 0)
195*45a4b79dSSebastien Roy STAILQ_INSERT_TAIL(&cc_list, add_cc, entries);
196*45a4b79dSSebastien Roy
197*45a4b79dSSebastien Roy mutex_exit(&cc_list_lock);
198*45a4b79dSSebastien Roy
199*45a4b79dSSebastien Roy return (err);
200*45a4b79dSSebastien Roy }
201