xref: /illumos-gate/usr/src/uts/common/inet/cc/cc.c (revision 45a4b79d)
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