162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Multipath TCP 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2019, Tessares SA. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#ifdef CONFIG_SYSCTL 862306a36Sopenharmony_ci#include <linux/sysctl.h> 962306a36Sopenharmony_ci#endif 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <net/net_namespace.h> 1262306a36Sopenharmony_ci#include <net/netns/generic.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "protocol.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define MPTCP_SYSCTL_PATH "net/mptcp" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic int mptcp_pernet_id; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#ifdef CONFIG_SYSCTL 2162306a36Sopenharmony_cistatic int mptcp_pm_type_max = __MPTCP_PM_TYPE_MAX; 2262306a36Sopenharmony_ci#endif 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistruct mptcp_pernet { 2562306a36Sopenharmony_ci#ifdef CONFIG_SYSCTL 2662306a36Sopenharmony_ci struct ctl_table_header *ctl_table_hdr; 2762306a36Sopenharmony_ci#endif 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci unsigned int add_addr_timeout; 3062306a36Sopenharmony_ci unsigned int stale_loss_cnt; 3162306a36Sopenharmony_ci u8 mptcp_enabled; 3262306a36Sopenharmony_ci u8 checksum_enabled; 3362306a36Sopenharmony_ci u8 allow_join_initial_addr_port; 3462306a36Sopenharmony_ci u8 pm_type; 3562306a36Sopenharmony_ci char scheduler[MPTCP_SCHED_NAME_MAX]; 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic struct mptcp_pernet *mptcp_get_pernet(const struct net *net) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci return net_generic(net, mptcp_pernet_id); 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ciint mptcp_is_enabled(const struct net *net) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci return mptcp_get_pernet(net)->mptcp_enabled; 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ciunsigned int mptcp_get_add_addr_timeout(const struct net *net) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci return mptcp_get_pernet(net)->add_addr_timeout; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ciint mptcp_is_checksum_enabled(const struct net *net) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci return mptcp_get_pernet(net)->checksum_enabled; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ciint mptcp_allow_join_id0(const struct net *net) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci return mptcp_get_pernet(net)->allow_join_initial_addr_port; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ciunsigned int mptcp_stale_loss_cnt(const struct net *net) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci return mptcp_get_pernet(net)->stale_loss_cnt; 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ciint mptcp_get_pm_type(const struct net *net) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci return mptcp_get_pernet(net)->pm_type; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ciconst char *mptcp_get_scheduler(const struct net *net) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci return mptcp_get_pernet(net)->scheduler; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic void mptcp_pernet_set_defaults(struct mptcp_pernet *pernet) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci pernet->mptcp_enabled = 1; 8162306a36Sopenharmony_ci pernet->add_addr_timeout = TCP_RTO_MAX; 8262306a36Sopenharmony_ci pernet->checksum_enabled = 0; 8362306a36Sopenharmony_ci pernet->allow_join_initial_addr_port = 1; 8462306a36Sopenharmony_ci pernet->stale_loss_cnt = 4; 8562306a36Sopenharmony_ci pernet->pm_type = MPTCP_PM_TYPE_KERNEL; 8662306a36Sopenharmony_ci strcpy(pernet->scheduler, "default"); 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci#ifdef CONFIG_SYSCTL 9062306a36Sopenharmony_cistatic struct ctl_table mptcp_sysctl_table[] = { 9162306a36Sopenharmony_ci { 9262306a36Sopenharmony_ci .procname = "enabled", 9362306a36Sopenharmony_ci .maxlen = sizeof(u8), 9462306a36Sopenharmony_ci .mode = 0644, 9562306a36Sopenharmony_ci /* users with CAP_NET_ADMIN or root (not and) can change this 9662306a36Sopenharmony_ci * value, same as other sysctl or the 'net' tree. 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_ci .proc_handler = proc_dou8vec_minmax, 9962306a36Sopenharmony_ci .extra1 = SYSCTL_ZERO, 10062306a36Sopenharmony_ci .extra2 = SYSCTL_ONE 10162306a36Sopenharmony_ci }, 10262306a36Sopenharmony_ci { 10362306a36Sopenharmony_ci .procname = "add_addr_timeout", 10462306a36Sopenharmony_ci .maxlen = sizeof(unsigned int), 10562306a36Sopenharmony_ci .mode = 0644, 10662306a36Sopenharmony_ci .proc_handler = proc_dointvec_jiffies, 10762306a36Sopenharmony_ci }, 10862306a36Sopenharmony_ci { 10962306a36Sopenharmony_ci .procname = "checksum_enabled", 11062306a36Sopenharmony_ci .maxlen = sizeof(u8), 11162306a36Sopenharmony_ci .mode = 0644, 11262306a36Sopenharmony_ci .proc_handler = proc_dou8vec_minmax, 11362306a36Sopenharmony_ci .extra1 = SYSCTL_ZERO, 11462306a36Sopenharmony_ci .extra2 = SYSCTL_ONE 11562306a36Sopenharmony_ci }, 11662306a36Sopenharmony_ci { 11762306a36Sopenharmony_ci .procname = "allow_join_initial_addr_port", 11862306a36Sopenharmony_ci .maxlen = sizeof(u8), 11962306a36Sopenharmony_ci .mode = 0644, 12062306a36Sopenharmony_ci .proc_handler = proc_dou8vec_minmax, 12162306a36Sopenharmony_ci .extra1 = SYSCTL_ZERO, 12262306a36Sopenharmony_ci .extra2 = SYSCTL_ONE 12362306a36Sopenharmony_ci }, 12462306a36Sopenharmony_ci { 12562306a36Sopenharmony_ci .procname = "stale_loss_cnt", 12662306a36Sopenharmony_ci .maxlen = sizeof(unsigned int), 12762306a36Sopenharmony_ci .mode = 0644, 12862306a36Sopenharmony_ci .proc_handler = proc_douintvec_minmax, 12962306a36Sopenharmony_ci }, 13062306a36Sopenharmony_ci { 13162306a36Sopenharmony_ci .procname = "pm_type", 13262306a36Sopenharmony_ci .maxlen = sizeof(u8), 13362306a36Sopenharmony_ci .mode = 0644, 13462306a36Sopenharmony_ci .proc_handler = proc_dou8vec_minmax, 13562306a36Sopenharmony_ci .extra1 = SYSCTL_ZERO, 13662306a36Sopenharmony_ci .extra2 = &mptcp_pm_type_max 13762306a36Sopenharmony_ci }, 13862306a36Sopenharmony_ci { 13962306a36Sopenharmony_ci .procname = "scheduler", 14062306a36Sopenharmony_ci .maxlen = MPTCP_SCHED_NAME_MAX, 14162306a36Sopenharmony_ci .mode = 0644, 14262306a36Sopenharmony_ci .proc_handler = proc_dostring, 14362306a36Sopenharmony_ci }, 14462306a36Sopenharmony_ci {} 14562306a36Sopenharmony_ci}; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct ctl_table_header *hdr; 15062306a36Sopenharmony_ci struct ctl_table *table; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci table = mptcp_sysctl_table; 15362306a36Sopenharmony_ci if (!net_eq(net, &init_net)) { 15462306a36Sopenharmony_ci table = kmemdup(table, sizeof(mptcp_sysctl_table), GFP_KERNEL); 15562306a36Sopenharmony_ci if (!table) 15662306a36Sopenharmony_ci goto err_alloc; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci table[0].data = &pernet->mptcp_enabled; 16062306a36Sopenharmony_ci table[1].data = &pernet->add_addr_timeout; 16162306a36Sopenharmony_ci table[2].data = &pernet->checksum_enabled; 16262306a36Sopenharmony_ci table[3].data = &pernet->allow_join_initial_addr_port; 16362306a36Sopenharmony_ci table[4].data = &pernet->stale_loss_cnt; 16462306a36Sopenharmony_ci table[5].data = &pernet->pm_type; 16562306a36Sopenharmony_ci table[6].data = &pernet->scheduler; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci hdr = register_net_sysctl_sz(net, MPTCP_SYSCTL_PATH, table, 16862306a36Sopenharmony_ci ARRAY_SIZE(mptcp_sysctl_table)); 16962306a36Sopenharmony_ci if (!hdr) 17062306a36Sopenharmony_ci goto err_reg; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci pernet->ctl_table_hdr = hdr; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return 0; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cierr_reg: 17762306a36Sopenharmony_ci if (!net_eq(net, &init_net)) 17862306a36Sopenharmony_ci kfree(table); 17962306a36Sopenharmony_cierr_alloc: 18062306a36Sopenharmony_ci return -ENOMEM; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic void mptcp_pernet_del_table(struct mptcp_pernet *pernet) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct ctl_table *table = pernet->ctl_table_hdr->ctl_table_arg; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci unregister_net_sysctl_table(pernet->ctl_table_hdr); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci kfree(table); 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci#else 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic int mptcp_pernet_new_table(struct net *net, struct mptcp_pernet *pernet) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci return 0; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic void mptcp_pernet_del_table(struct mptcp_pernet *pernet) {} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci#endif /* CONFIG_SYSCTL */ 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic int __net_init mptcp_net_init(struct net *net) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci struct mptcp_pernet *pernet = mptcp_get_pernet(net); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci mptcp_pernet_set_defaults(pernet); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci return mptcp_pernet_new_table(net, pernet); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci/* Note: the callback will only be called per extra netns */ 21362306a36Sopenharmony_cistatic void __net_exit mptcp_net_exit(struct net *net) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci struct mptcp_pernet *pernet = mptcp_get_pernet(net); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci mptcp_pernet_del_table(pernet); 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic struct pernet_operations mptcp_pernet_ops = { 22162306a36Sopenharmony_ci .init = mptcp_net_init, 22262306a36Sopenharmony_ci .exit = mptcp_net_exit, 22362306a36Sopenharmony_ci .id = &mptcp_pernet_id, 22462306a36Sopenharmony_ci .size = sizeof(struct mptcp_pernet), 22562306a36Sopenharmony_ci}; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_civoid __init mptcp_init(void) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci mptcp_join_cookie_init(); 23062306a36Sopenharmony_ci mptcp_proto_init(); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (register_pernet_subsys(&mptcp_pernet_ops) < 0) 23362306a36Sopenharmony_ci panic("Failed to register MPTCP pernet subsystem.\n"); 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPTCP_IPV6) 23762306a36Sopenharmony_ciint __init mptcpv6_init(void) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci int err; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci err = mptcp_proto_v6_init(); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci return err; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci#endif 246