2020-01-21 16:56:28 -08:00
// SPDX-License-Identifier: GPL-2.0
/* Multipath TCP
*
* Copyright ( c ) 2019 , Tessares SA .
*/
2021-05-27 16:54:29 -07:00
# ifdef CONFIG_SYSCTL
2020-01-21 16:56:28 -08:00
# include <linux/sysctl.h>
2021-05-27 16:54:29 -07:00
# endif
2020-01-21 16:56:28 -08:00
# include <net/net_namespace.h>
# include <net/netns/generic.h>
# include "protocol.h"
# define MPTCP_SYSCTL_PATH "net / mptcp"
static int mptcp_pernet_id ;
2022-04-27 15:50:01 -07:00
# ifdef CONFIG_SYSCTL
static int mptcp_pm_type_max = __MPTCP_PM_TYPE_MAX ;
# endif
2020-01-21 16:56:28 -08:00
struct mptcp_pernet {
2021-05-27 16:54:29 -07:00
# ifdef CONFIG_SYSCTL
2020-01-21 16:56:28 -08:00
struct ctl_table_header * ctl_table_hdr ;
2021-05-27 16:54:29 -07:00
# endif
2020-01-21 16:56:28 -08:00
2020-11-03 11:05:07 -08:00
unsigned int add_addr_timeout ;
2023-10-23 13:44:34 -07:00
unsigned int close_timeout ;
2021-08-13 15:15:45 -07:00
unsigned int stale_loss_cnt ;
2021-08-13 15:15:44 -07:00
u8 mptcp_enabled ;
2021-06-17 16:46:19 -07:00
u8 checksum_enabled ;
2021-06-22 12:25:18 -07:00
u8 allow_join_initial_addr_port ;
2022-04-27 15:50:01 -07:00
u8 pm_type ;
2023-08-21 15:25:15 -07:00
char scheduler [ MPTCP_SCHED_NAME_MAX ] ;
2020-01-21 16:56:28 -08:00
} ;
2021-08-13 15:15:44 -07:00
static struct mptcp_pernet * mptcp_get_pernet ( const struct net * net )
2020-01-21 16:56:28 -08:00
{
return net_generic ( net , mptcp_pernet_id ) ;
}
2021-08-13 15:15:44 -07:00
int mptcp_is_enabled ( const struct net * net )
2020-01-21 16:56:28 -08:00
{
return mptcp_get_pernet ( net ) - > mptcp_enabled ;
}
2021-08-13 15:15:44 -07:00
unsigned int mptcp_get_add_addr_timeout ( const struct net * net )
2020-11-03 11:05:07 -08:00
{
return mptcp_get_pernet ( net ) - > add_addr_timeout ;
}
2021-08-13 15:15:44 -07:00
int mptcp_is_checksum_enabled ( const struct net * net )
2021-06-17 16:46:19 -07:00
{
return mptcp_get_pernet ( net ) - > checksum_enabled ;
}
2021-08-13 15:15:44 -07:00
int mptcp_allow_join_id0 ( const struct net * net )
2021-06-22 12:25:18 -07:00
{
return mptcp_get_pernet ( net ) - > allow_join_initial_addr_port ;
}
2021-08-13 15:15:45 -07:00
unsigned int mptcp_stale_loss_cnt ( const struct net * net )
{
return mptcp_get_pernet ( net ) - > stale_loss_cnt ;
}
2023-10-23 13:44:34 -07:00
unsigned int mptcp_close_timeout ( const struct sock * sk )
{
if ( sock_flag ( sk , SOCK_DEAD ) )
return TCP_TIMEWAIT_LEN ;
return mptcp_get_pernet ( sock_net ( sk ) ) - > close_timeout ;
}
2022-04-27 15:50:01 -07:00
int mptcp_get_pm_type ( const struct net * net )
{
return mptcp_get_pernet ( net ) - > pm_type ;
}
2023-08-21 15:25:15 -07:00
const char * mptcp_get_scheduler ( const struct net * net )
{
return mptcp_get_pernet ( net ) - > scheduler ;
}
2021-05-27 16:54:29 -07:00
static void mptcp_pernet_set_defaults ( struct mptcp_pernet * pernet )
{
pernet - > mptcp_enabled = 1 ;
pernet - > add_addr_timeout = TCP_RTO_MAX ;
2023-10-23 13:44:34 -07:00
pernet - > close_timeout = TCP_TIMEWAIT_LEN ;
2021-06-17 16:46:19 -07:00
pernet - > checksum_enabled = 0 ;
2021-06-22 12:25:18 -07:00
pernet - > allow_join_initial_addr_port = 1 ;
2021-08-13 15:15:45 -07:00
pernet - > stale_loss_cnt = 4 ;
2022-04-27 15:50:01 -07:00
pernet - > pm_type = MPTCP_PM_TYPE_KERNEL ;
2024-05-13 18:13:29 -07:00
strscpy ( pernet - > scheduler , " default " , sizeof ( pernet - > scheduler ) ) ;
2021-05-27 16:54:29 -07:00
}
# ifdef CONFIG_SYSCTL
2024-05-06 17:35:28 +02:00
static int mptcp_set_scheduler ( const struct net * net , const char * name )
{
struct mptcp_pernet * pernet = mptcp_get_pernet ( net ) ;
struct mptcp_sched_ops * sched ;
int ret = 0 ;
rcu_read_lock ( ) ;
sched = mptcp_sched_find ( name ) ;
if ( sched )
strscpy ( pernet - > scheduler , name , MPTCP_SCHED_NAME_MAX ) ;
else
ret = - ENOENT ;
rcu_read_unlock ( ) ;
return ret ;
}
static int proc_scheduler ( struct ctl_table * ctl , int write ,
void * buffer , size_t * lenp , loff_t * ppos )
{
const struct net * net = current - > nsproxy - > net_ns ;
char val [ MPTCP_SCHED_NAME_MAX ] ;
struct ctl_table tbl = {
. data = val ,
. maxlen = MPTCP_SCHED_NAME_MAX ,
} ;
int ret ;
strscpy ( val , mptcp_get_scheduler ( net ) , MPTCP_SCHED_NAME_MAX ) ;
ret = proc_dostring ( & tbl , write , buffer , lenp , ppos ) ;
if ( write & & ret = = 0 )
ret = mptcp_set_scheduler ( net , val ) ;
return ret ;
}
2024-05-13 18:13:28 -07:00
static int proc_available_schedulers ( struct ctl_table * ctl ,
int write , void * buffer ,
size_t * lenp , loff_t * ppos )
{
struct ctl_table tbl = { . maxlen = MPTCP_SCHED_BUF_MAX , } ;
int ret ;
tbl . data = kmalloc ( tbl . maxlen , GFP_USER ) ;
if ( ! tbl . data )
return - ENOMEM ;
mptcp_get_available_schedulers ( tbl . data , MPTCP_SCHED_BUF_MAX ) ;
ret = proc_dostring ( & tbl , write , buffer , lenp , ppos ) ;
kfree ( tbl . data ) ;
return ret ;
}
2020-01-21 16:56:28 -08:00
static struct ctl_table mptcp_sysctl_table [ ] = {
{
. procname = " enabled " ,
2021-05-27 16:54:30 -07:00
. maxlen = sizeof ( u8 ) ,
2020-01-21 16:56:28 -08:00
. mode = 0644 ,
/* users with CAP_NET_ADMIN or root (not and) can change this
* value , same as other sysctl or the ' net ' tree .
*/
2021-05-27 16:54:30 -07:00
. proc_handler = proc_dou8vec_minmax ,
. extra1 = SYSCTL_ZERO ,
. extra2 = SYSCTL_ONE
2020-01-21 16:56:28 -08:00
} ,
2020-11-03 11:05:07 -08:00
{
. procname = " add_addr_timeout " ,
. maxlen = sizeof ( unsigned int ) ,
. mode = 0644 ,
. proc_handler = proc_dointvec_jiffies ,
} ,
2021-06-17 16:46:19 -07:00
{
. procname = " checksum_enabled " ,
. maxlen = sizeof ( u8 ) ,
. mode = 0644 ,
. proc_handler = proc_dou8vec_minmax ,
. extra1 = SYSCTL_ZERO ,
. extra2 = SYSCTL_ONE
} ,
2021-06-22 12:25:18 -07:00
{
. procname = " allow_join_initial_addr_port " ,
. maxlen = sizeof ( u8 ) ,
. mode = 0644 ,
. proc_handler = proc_dou8vec_minmax ,
. extra1 = SYSCTL_ZERO ,
. extra2 = SYSCTL_ONE
} ,
2021-08-13 15:15:45 -07:00
{
. procname = " stale_loss_cnt " ,
. maxlen = sizeof ( unsigned int ) ,
. mode = 0644 ,
. proc_handler = proc_douintvec_minmax ,
} ,
2022-04-27 15:50:01 -07:00
{
. procname = " pm_type " ,
. maxlen = sizeof ( u8 ) ,
. mode = 0644 ,
. proc_handler = proc_dou8vec_minmax ,
. extra1 = SYSCTL_ZERO ,
. extra2 = & mptcp_pm_type_max
} ,
2023-08-21 15:25:15 -07:00
{
. procname = " scheduler " ,
. maxlen = MPTCP_SCHED_NAME_MAX ,
. mode = 0644 ,
2024-05-06 17:35:28 +02:00
. proc_handler = proc_scheduler ,
2023-08-21 15:25:15 -07:00
} ,
2024-05-13 18:13:28 -07:00
{
. procname = " available_schedulers " ,
. maxlen = MPTCP_SCHED_BUF_MAX ,
. mode = 0644 ,
. proc_handler = proc_available_schedulers ,
} ,
2023-10-23 13:44:34 -07:00
{
. procname = " close_timeout " ,
. maxlen = sizeof ( unsigned int ) ,
. mode = 0644 ,
. proc_handler = proc_dointvec_jiffies ,
} ,
2020-01-21 16:56:28 -08:00
} ;
static int mptcp_pernet_new_table ( struct net * net , struct mptcp_pernet * pernet )
{
struct ctl_table_header * hdr ;
struct ctl_table * table ;
table = mptcp_sysctl_table ;
if ( ! net_eq ( net , & init_net ) ) {
table = kmemdup ( table , sizeof ( mptcp_sysctl_table ) , GFP_KERNEL ) ;
if ( ! table )
goto err_alloc ;
}
table [ 0 ] . data = & pernet - > mptcp_enabled ;
2020-11-03 11:05:07 -08:00
table [ 1 ] . data = & pernet - > add_addr_timeout ;
2021-06-17 16:46:19 -07:00
table [ 2 ] . data = & pernet - > checksum_enabled ;
2021-06-22 12:25:18 -07:00
table [ 3 ] . data = & pernet - > allow_join_initial_addr_port ;
2021-08-13 15:15:45 -07:00
table [ 4 ] . data = & pernet - > stale_loss_cnt ;
2022-04-27 15:50:01 -07:00
table [ 5 ] . data = & pernet - > pm_type ;
2023-08-21 15:25:15 -07:00
table [ 6 ] . data = & pernet - > scheduler ;
2024-05-13 18:13:28 -07:00
/* table[7] is for available_schedulers which is read-only info */
table [ 8 ] . data = & pernet - > close_timeout ;
2020-01-21 16:56:28 -08:00
2023-08-09 12:50:03 +02:00
hdr = register_net_sysctl_sz ( net , MPTCP_SYSCTL_PATH , table ,
ARRAY_SIZE ( mptcp_sysctl_table ) ) ;
2020-01-21 16:56:28 -08:00
if ( ! hdr )
goto err_reg ;
pernet - > ctl_table_hdr = hdr ;
return 0 ;
err_reg :
if ( ! net_eq ( net , & init_net ) )
kfree ( table ) ;
err_alloc :
return - ENOMEM ;
}
static void mptcp_pernet_del_table ( struct mptcp_pernet * pernet )
{
2024-04-18 11:40:08 +02:00
const struct ctl_table * table = pernet - > ctl_table_hdr - > ctl_table_arg ;
2020-01-21 16:56:28 -08:00
unregister_net_sysctl_table ( pernet - > ctl_table_hdr ) ;
kfree ( table ) ;
}
2021-05-27 16:54:29 -07:00
# else
static int mptcp_pernet_new_table ( struct net * net , struct mptcp_pernet * pernet )
{
return 0 ;
}
static void mptcp_pernet_del_table ( struct mptcp_pernet * pernet ) { }
# endif /* CONFIG_SYSCTL */
2020-01-21 16:56:28 -08:00
static int __net_init mptcp_net_init ( struct net * net )
{
struct mptcp_pernet * pernet = mptcp_get_pernet ( net ) ;
mptcp_pernet_set_defaults ( pernet ) ;
return mptcp_pernet_new_table ( net , pernet ) ;
}
/* Note: the callback will only be called per extra netns */
static void __net_exit mptcp_net_exit ( struct net * net )
{
struct mptcp_pernet * pernet = mptcp_get_pernet ( net ) ;
mptcp_pernet_del_table ( pernet ) ;
}
static struct pernet_operations mptcp_pernet_ops = {
. init = mptcp_net_init ,
. exit = mptcp_net_exit ,
. id = & mptcp_pernet_id ,
. size = sizeof ( struct mptcp_pernet ) ,
} ;
void __init mptcp_init ( void )
{
2020-07-30 21:25:56 +02:00
mptcp_join_cookie_init ( ) ;
2020-01-21 16:56:28 -08:00
mptcp_proto_init ( ) ;
if ( register_pernet_subsys ( & mptcp_pernet_ops ) < 0 )
panic ( " Failed to register MPTCP pernet subsystem. \n " ) ;
}
# if IS_ENABLED(CONFIG_MPTCP_IPV6)
int __init mptcpv6_init ( void )
{
int err ;
err = mptcp_proto_v6_init ( ) ;
return err ;
}
# endif