Move protocol specific implementation detail out of the core CC framework.
Sponsored by: FreeBSD Foundation Tested by: Mikolaj Golub <to.my.trociny at gmail com> MFC after: 11 weeks X-MFC with: r215166
This commit is contained in:
parent
4e805854ed
commit
99065ae6a8
@ -190,10 +190,7 @@ int
|
||||
cc_deregister_algo(struct cc_algo *remove_cc)
|
||||
{
|
||||
struct cc_algo *funcs, *tmpfuncs;
|
||||
struct tcpcb *tp;
|
||||
struct inpcb *inp;
|
||||
int err;
|
||||
VNET_ITERATOR_DECL(vnet_iter);
|
||||
|
||||
err = ENOENT;
|
||||
|
||||
@ -220,53 +217,14 @@ cc_deregister_algo(struct cc_algo *remove_cc)
|
||||
}
|
||||
CC_LIST_WUNLOCK();
|
||||
|
||||
if (!err) {
|
||||
if (!err)
|
||||
/*
|
||||
* Check all active control blocks across all network stacks and
|
||||
* change any that are using this algorithm back to newreno. If
|
||||
* the algorithm that was in use requires cleanup code to be
|
||||
* run, call it.
|
||||
*
|
||||
* New connections already part way through being initialised
|
||||
* with the CC algo we're removing will not race with this code
|
||||
* because the INP_INFO_WLOCK is held during initialisation.
|
||||
* We therefore don't enter the loop below until the connection
|
||||
* list has stabilised.
|
||||
* XXXLAS:
|
||||
* - We may need to handle non-zero return values in future.
|
||||
* - If we add CC framework support for protocols other than
|
||||
* TCP, we may want a more generic way to handle this step.
|
||||
*/
|
||||
VNET_LIST_RLOCK();
|
||||
VNET_FOREACH(vnet_iter) {
|
||||
CURVNET_SET(vnet_iter);
|
||||
INP_INFO_RLOCK(&V_tcbinfo);
|
||||
LIST_FOREACH(inp, &V_tcb, inp_list) {
|
||||
INP_WLOCK(inp);
|
||||
/* Important to skip tcptw structs. */
|
||||
if (!(inp->inp_flags & INP_TIMEWAIT) &&
|
||||
(tp = intotcpcb(inp)) != NULL) {
|
||||
/*
|
||||
* By holding INP_WLOCK here, we are
|
||||
* assured that the connection is not
|
||||
* currently executing inside the CC
|
||||
* module's functions i.e. it is safe
|
||||
* to make the switch back to newreno.
|
||||
*/
|
||||
if (CC_ALGO(tp) == remove_cc) {
|
||||
tmpfuncs = CC_ALGO(tp);
|
||||
/*
|
||||
* Newreno does not
|
||||
* require any init.
|
||||
*/
|
||||
CC_ALGO(tp) = &newreno_cc_algo;
|
||||
if (tmpfuncs->cb_destroy != NULL)
|
||||
tmpfuncs->cb_destroy(tp->ccv);
|
||||
}
|
||||
}
|
||||
INP_WUNLOCK(inp);
|
||||
}
|
||||
INP_INFO_RUNLOCK(&V_tcbinfo);
|
||||
CURVNET_RESTORE();
|
||||
}
|
||||
VNET_LIST_RUNLOCK();
|
||||
}
|
||||
tcp_ccalgounload(remove_cc);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
@ -707,6 +707,69 @@ tcp_newtcpcb(struct inpcb *inp)
|
||||
return (tp); /* XXX */
|
||||
}
|
||||
|
||||
/*
|
||||
* Switch the congestion control algorithm back to NewReno for any active
|
||||
* control blocks using an algorithm which is about to go away.
|
||||
* This ensures the CC framework can allow the unload to proceed without leaving
|
||||
* any dangling pointers which would trigger a panic.
|
||||
* Returning non-zero would inform the CC framework that something went wrong
|
||||
* and it would be unsafe to allow the unload to proceed. However, there is no
|
||||
* way for this to occur with this implementation so we always return zero.
|
||||
*/
|
||||
int
|
||||
tcp_ccalgounload(struct cc_algo *unload_algo)
|
||||
{
|
||||
struct cc_algo *tmpalgo;
|
||||
struct inpcb *inp;
|
||||
struct tcpcb *tp;
|
||||
VNET_ITERATOR_DECL(vnet_iter);
|
||||
|
||||
/*
|
||||
* Check all active control blocks across all network stacks and change
|
||||
* any that are using "unload_algo" back to NewReno. If "unload_algo"
|
||||
* requires cleanup code to be run, call it.
|
||||
*/
|
||||
VNET_LIST_RLOCK();
|
||||
VNET_FOREACH(vnet_iter) {
|
||||
CURVNET_SET(vnet_iter);
|
||||
INP_INFO_RLOCK(&V_tcbinfo);
|
||||
/*
|
||||
* New connections already part way through being initialised
|
||||
* with the CC algo we're removing will not race with this code
|
||||
* because the INP_INFO_WLOCK is held during initialisation. We
|
||||
* therefore don't enter the loop below until the connection
|
||||
* list has stabilised.
|
||||
*/
|
||||
LIST_FOREACH(inp, &V_tcb, inp_list) {
|
||||
INP_WLOCK(inp);
|
||||
/* Important to skip tcptw structs. */
|
||||
if (!(inp->inp_flags & INP_TIMEWAIT) &&
|
||||
(tp = intotcpcb(inp)) != NULL) {
|
||||
/*
|
||||
* By holding INP_WLOCK here, we are assured
|
||||
* that the connection is not currently
|
||||
* executing inside the CC module's functions
|
||||
* i.e. it is safe to make the switch back to
|
||||
* NewReno.
|
||||
*/
|
||||
if (CC_ALGO(tp) == unload_algo) {
|
||||
tmpalgo = CC_ALGO(tp);
|
||||
/* NewReno does not require any init. */
|
||||
CC_ALGO(tp) = &newreno_cc_algo;
|
||||
if (tmpalgo->cb_destroy != NULL)
|
||||
tmpalgo->cb_destroy(tp->ccv);
|
||||
}
|
||||
}
|
||||
INP_WUNLOCK(inp);
|
||||
}
|
||||
INP_INFO_RUNLOCK(&V_tcbinfo);
|
||||
CURVNET_RESTORE();
|
||||
}
|
||||
VNET_LIST_RUNLOCK();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Drop a TCP connection, reporting
|
||||
* the specified error. If connection is synchronized,
|
||||
|
@ -605,6 +605,7 @@ VNET_DECLARE(int, tcp_ecn_maxretries);
|
||||
#define V_tcp_ecn_maxretries VNET(tcp_ecn_maxretries)
|
||||
|
||||
int tcp_addoptions(struct tcpopt *, u_char *);
|
||||
int tcp_ccalgounload(struct cc_algo *unload_algo);
|
||||
struct tcpcb *
|
||||
tcp_close(struct tcpcb *);
|
||||
void tcp_discardcb(struct tcpcb *);
|
||||
|
Loading…
x
Reference in New Issue
Block a user