mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-06 10:57:46 +00:00
Merge branch 'mptcp-add_addr-enhancements'
Mat Martineau says: ==================== mptcp: ADD_ADDR enhancements This patch series from the MPTCP tree contains enhancements and associated tests for the ADD_ADDR ("add address") MPTCP option. This option allows already-connected MPTCP peers to share additional IP addresses with each other, which can then be used to create additional subflows within those MPTCP connections. Patches 1 & 2 remove duplicated data in the per-connection path manager structure. Patches 3-6 initiate additional subflows when an address is added using the netlink path manager interface and improve ADD_ADDR signaling reliability, subject to configured limits. Self tests are also updated. Patches 7-15 add new support for optional port numbers in ADD_ADDR. This includes creating an additional in-kernel TCP listening socket for the requested port number, validating the port number when processing incoming subflow connections, including the port number in netlink interfaces, and adding some new MIBs. New self test cases are added for subflows connecting with alternate port numbers. ==================== Link: https://lore.kernel.org/r/20210201230920.66027-1-mathew.j.martineau@linux.intel.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
a1a809c489
11 changed files with 609 additions and 94 deletions
|
@ -29,6 +29,12 @@ static const struct snmp_mib mptcp_snmp_list[] = {
|
||||||
SNMP_MIB_ITEM("DuplicateData", MPTCP_MIB_DUPDATA),
|
SNMP_MIB_ITEM("DuplicateData", MPTCP_MIB_DUPDATA),
|
||||||
SNMP_MIB_ITEM("AddAddr", MPTCP_MIB_ADDADDR),
|
SNMP_MIB_ITEM("AddAddr", MPTCP_MIB_ADDADDR),
|
||||||
SNMP_MIB_ITEM("EchoAdd", MPTCP_MIB_ECHOADD),
|
SNMP_MIB_ITEM("EchoAdd", MPTCP_MIB_ECHOADD),
|
||||||
|
SNMP_MIB_ITEM("PortAdd", MPTCP_MIB_PORTADD),
|
||||||
|
SNMP_MIB_ITEM("MPJoinPortSynRx", MPTCP_MIB_JOINPORTSYNRX),
|
||||||
|
SNMP_MIB_ITEM("MPJoinPortSynAckRx", MPTCP_MIB_JOINPORTSYNACKRX),
|
||||||
|
SNMP_MIB_ITEM("MPJoinPortAckRx", MPTCP_MIB_JOINPORTACKRX),
|
||||||
|
SNMP_MIB_ITEM("MismatchPortSynRx", MPTCP_MIB_MISMATCHPORTSYNRX),
|
||||||
|
SNMP_MIB_ITEM("MismatchPortAckRx", MPTCP_MIB_MISMATCHPORTACKRX),
|
||||||
SNMP_MIB_ITEM("RmAddr", MPTCP_MIB_RMADDR),
|
SNMP_MIB_ITEM("RmAddr", MPTCP_MIB_RMADDR),
|
||||||
SNMP_MIB_ITEM("RmSubflow", MPTCP_MIB_RMSUBFLOW),
|
SNMP_MIB_ITEM("RmSubflow", MPTCP_MIB_RMSUBFLOW),
|
||||||
SNMP_MIB_ITEM("MPPrioTx", MPTCP_MIB_MPPRIOTX),
|
SNMP_MIB_ITEM("MPPrioTx", MPTCP_MIB_MPPRIOTX),
|
||||||
|
|
|
@ -22,6 +22,12 @@ enum linux_mptcp_mib_field {
|
||||||
MPTCP_MIB_DUPDATA, /* Segments discarded due to duplicate DSS */
|
MPTCP_MIB_DUPDATA, /* Segments discarded due to duplicate DSS */
|
||||||
MPTCP_MIB_ADDADDR, /* Received ADD_ADDR with echo-flag=0 */
|
MPTCP_MIB_ADDADDR, /* Received ADD_ADDR with echo-flag=0 */
|
||||||
MPTCP_MIB_ECHOADD, /* Received ADD_ADDR with echo-flag=1 */
|
MPTCP_MIB_ECHOADD, /* Received ADD_ADDR with echo-flag=1 */
|
||||||
|
MPTCP_MIB_PORTADD, /* Received ADD_ADDR with a port-number */
|
||||||
|
MPTCP_MIB_JOINPORTSYNRX, /* Received a SYN MP_JOIN with a different port-number */
|
||||||
|
MPTCP_MIB_JOINPORTSYNACKRX, /* Received a SYNACK MP_JOIN with a different port-number */
|
||||||
|
MPTCP_MIB_JOINPORTACKRX, /* Received an ACK MP_JOIN with a different port-number */
|
||||||
|
MPTCP_MIB_MISMATCHPORTSYNRX, /* Received a SYN MP_JOIN with a mismatched port-number */
|
||||||
|
MPTCP_MIB_MISMATCHPORTACKRX, /* Received an ACK MP_JOIN with a mismatched port-number */
|
||||||
MPTCP_MIB_RMADDR, /* Received RM_ADDR */
|
MPTCP_MIB_RMADDR, /* Received RM_ADDR */
|
||||||
MPTCP_MIB_RMSUBFLOW, /* Remove a subflow */
|
MPTCP_MIB_RMSUBFLOW, /* Remove a subflow */
|
||||||
MPTCP_MIB_MPPRIOTX, /* Transmit a MP_PRIO */
|
MPTCP_MIB_MPPRIOTX, /* Transmit a MP_PRIO */
|
||||||
|
|
|
@ -128,10 +128,10 @@ static void mptcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
|
||||||
info->mptcpi_subflows = READ_ONCE(msk->pm.subflows);
|
info->mptcpi_subflows = READ_ONCE(msk->pm.subflows);
|
||||||
info->mptcpi_add_addr_signal = READ_ONCE(msk->pm.add_addr_signaled);
|
info->mptcpi_add_addr_signal = READ_ONCE(msk->pm.add_addr_signaled);
|
||||||
info->mptcpi_add_addr_accepted = READ_ONCE(msk->pm.add_addr_accepted);
|
info->mptcpi_add_addr_accepted = READ_ONCE(msk->pm.add_addr_accepted);
|
||||||
info->mptcpi_subflows_max = READ_ONCE(msk->pm.subflows_max);
|
info->mptcpi_subflows_max = mptcp_pm_get_subflows_max(msk);
|
||||||
val = READ_ONCE(msk->pm.add_addr_signal_max);
|
val = mptcp_pm_get_add_addr_signal_max(msk);
|
||||||
info->mptcpi_add_addr_signal_max = val;
|
info->mptcpi_add_addr_signal_max = val;
|
||||||
val = READ_ONCE(msk->pm.add_addr_accept_max);
|
val = mptcp_pm_get_add_addr_accept_max(msk);
|
||||||
info->mptcpi_add_addr_accepted_max = val;
|
info->mptcpi_add_addr_accepted_max = val;
|
||||||
if (test_bit(MPTCP_FALLBACK_DONE, &msk->flags))
|
if (test_bit(MPTCP_FALLBACK_DONE, &msk->flags))
|
||||||
flags |= MPTCP_INFO_FLAG_FALLBACK;
|
flags |= MPTCP_INFO_FLAG_FALLBACK;
|
||||||
|
|
|
@ -1025,6 +1025,10 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
|
||||||
mptcp_pm_del_add_timer(msk, &addr);
|
mptcp_pm_del_add_timer(msk, &addr);
|
||||||
MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ECHOADD);
|
MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ECHOADD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mp_opt.port)
|
||||||
|
MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_PORTADD);
|
||||||
|
|
||||||
mp_opt.add_addr = 0;
|
mp_opt.add_addr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,10 +78,13 @@ void mptcp_pm_new_connection(struct mptcp_sock *msk, int server_side)
|
||||||
bool mptcp_pm_allow_new_subflow(struct mptcp_sock *msk)
|
bool mptcp_pm_allow_new_subflow(struct mptcp_sock *msk)
|
||||||
{
|
{
|
||||||
struct mptcp_pm_data *pm = &msk->pm;
|
struct mptcp_pm_data *pm = &msk->pm;
|
||||||
|
unsigned int subflows_max;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
subflows_max = mptcp_pm_get_subflows_max(msk);
|
||||||
|
|
||||||
pr_debug("msk=%p subflows=%d max=%d allow=%d", msk, pm->subflows,
|
pr_debug("msk=%p subflows=%d max=%d allow=%d", msk, pm->subflows,
|
||||||
pm->subflows_max, READ_ONCE(pm->accept_subflow));
|
subflows_max, READ_ONCE(pm->accept_subflow));
|
||||||
|
|
||||||
/* try to avoid acquiring the lock below */
|
/* try to avoid acquiring the lock below */
|
||||||
if (!READ_ONCE(pm->accept_subflow))
|
if (!READ_ONCE(pm->accept_subflow))
|
||||||
|
@ -89,8 +92,8 @@ bool mptcp_pm_allow_new_subflow(struct mptcp_sock *msk)
|
||||||
|
|
||||||
spin_lock_bh(&pm->lock);
|
spin_lock_bh(&pm->lock);
|
||||||
if (READ_ONCE(pm->accept_subflow)) {
|
if (READ_ONCE(pm->accept_subflow)) {
|
||||||
ret = pm->subflows < pm->subflows_max;
|
ret = pm->subflows < subflows_max;
|
||||||
if (ret && ++pm->subflows == pm->subflows_max)
|
if (ret && ++pm->subflows == subflows_max)
|
||||||
WRITE_ONCE(pm->accept_subflow, false);
|
WRITE_ONCE(pm->accept_subflow, false);
|
||||||
}
|
}
|
||||||
spin_unlock_bh(&pm->lock);
|
spin_unlock_bh(&pm->lock);
|
||||||
|
@ -188,8 +191,7 @@ void mptcp_pm_add_addr_received(struct mptcp_sock *msk,
|
||||||
|
|
||||||
void mptcp_pm_add_addr_send_ack(struct mptcp_sock *msk)
|
void mptcp_pm_add_addr_send_ack(struct mptcp_sock *msk)
|
||||||
{
|
{
|
||||||
if (!mptcp_pm_should_add_signal_ipv6(msk) &&
|
if (!mptcp_pm_should_add_signal(msk))
|
||||||
!mptcp_pm_should_add_signal_port(msk))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mptcp_pm_schedule_work(msk, MPTCP_PM_ADD_ADDR_SEND_ACK);
|
mptcp_pm_schedule_work(msk, MPTCP_PM_ADD_ADDR_SEND_ACK);
|
||||||
|
|
|
@ -26,6 +26,7 @@ struct mptcp_pm_addr_entry {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct mptcp_addr_info addr;
|
struct mptcp_addr_info addr;
|
||||||
struct rcu_head rcu;
|
struct rcu_head rcu;
|
||||||
|
struct socket *lsk;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mptcp_pm_add_entry {
|
struct mptcp_pm_add_entry {
|
||||||
|
@ -90,14 +91,14 @@ static bool address_zero(const struct mptcp_addr_info *addr)
|
||||||
memset(&zero, 0, sizeof(zero));
|
memset(&zero, 0, sizeof(zero));
|
||||||
zero.family = addr->family;
|
zero.family = addr->family;
|
||||||
|
|
||||||
return addresses_equal(addr, &zero, false);
|
return addresses_equal(addr, &zero, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void local_address(const struct sock_common *skc,
|
static void local_address(const struct sock_common *skc,
|
||||||
struct mptcp_addr_info *addr)
|
struct mptcp_addr_info *addr)
|
||||||
{
|
{
|
||||||
addr->port = 0;
|
|
||||||
addr->family = skc->skc_family;
|
addr->family = skc->skc_family;
|
||||||
|
addr->port = htons(skc->skc_num);
|
||||||
if (addr->family == AF_INET)
|
if (addr->family == AF_INET)
|
||||||
addr->addr.s_addr = skc->skc_rcv_saddr;
|
addr->addr.s_addr = skc->skc_rcv_saddr;
|
||||||
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
|
||||||
|
@ -130,7 +131,7 @@ static bool lookup_subflow_by_saddr(const struct list_head *list,
|
||||||
skc = (struct sock_common *)mptcp_subflow_tcp_sock(subflow);
|
skc = (struct sock_common *)mptcp_subflow_tcp_sock(subflow);
|
||||||
|
|
||||||
local_address(skc, &cur);
|
local_address(skc, &cur);
|
||||||
if (addresses_equal(&cur, saddr, false))
|
if (addresses_equal(&cur, saddr, saddr->port))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,11 +197,46 @@ select_signal_address(struct pm_nl_pernet *pernet, unsigned int pos)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int mptcp_pm_get_add_addr_signal_max(struct mptcp_sock *msk)
|
||||||
|
{
|
||||||
|
struct pm_nl_pernet *pernet;
|
||||||
|
|
||||||
|
pernet = net_generic(sock_net((struct sock *)msk), pm_nl_pernet_id);
|
||||||
|
return READ_ONCE(pernet->add_addr_signal_max);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mptcp_pm_get_add_addr_signal_max);
|
||||||
|
|
||||||
|
unsigned int mptcp_pm_get_add_addr_accept_max(struct mptcp_sock *msk)
|
||||||
|
{
|
||||||
|
struct pm_nl_pernet *pernet;
|
||||||
|
|
||||||
|
pernet = net_generic(sock_net((struct sock *)msk), pm_nl_pernet_id);
|
||||||
|
return READ_ONCE(pernet->add_addr_accept_max);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mptcp_pm_get_add_addr_accept_max);
|
||||||
|
|
||||||
|
unsigned int mptcp_pm_get_subflows_max(struct mptcp_sock *msk)
|
||||||
|
{
|
||||||
|
struct pm_nl_pernet *pernet;
|
||||||
|
|
||||||
|
pernet = net_generic(sock_net((struct sock *)msk), pm_nl_pernet_id);
|
||||||
|
return READ_ONCE(pernet->subflows_max);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mptcp_pm_get_subflows_max);
|
||||||
|
|
||||||
|
static unsigned int mptcp_pm_get_local_addr_max(struct mptcp_sock *msk)
|
||||||
|
{
|
||||||
|
struct pm_nl_pernet *pernet;
|
||||||
|
|
||||||
|
pernet = net_generic(sock_net((struct sock *)msk), pm_nl_pernet_id);
|
||||||
|
return READ_ONCE(pernet->local_addr_max);
|
||||||
|
}
|
||||||
|
|
||||||
static void check_work_pending(struct mptcp_sock *msk)
|
static void check_work_pending(struct mptcp_sock *msk)
|
||||||
{
|
{
|
||||||
if (msk->pm.add_addr_signaled == msk->pm.add_addr_signal_max &&
|
if (msk->pm.add_addr_signaled == mptcp_pm_get_add_addr_signal_max(msk) &&
|
||||||
(msk->pm.local_addr_used == msk->pm.local_addr_max ||
|
(msk->pm.local_addr_used == mptcp_pm_get_local_addr_max(msk) ||
|
||||||
msk->pm.subflows == msk->pm.subflows_max))
|
msk->pm.subflows == mptcp_pm_get_subflows_max(msk)))
|
||||||
WRITE_ONCE(msk->pm.work_pending, false);
|
WRITE_ONCE(msk->pm.work_pending, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,13 +247,34 @@ lookup_anno_list_by_saddr(struct mptcp_sock *msk,
|
||||||
struct mptcp_pm_add_entry *entry;
|
struct mptcp_pm_add_entry *entry;
|
||||||
|
|
||||||
list_for_each_entry(entry, &msk->pm.anno_list, list) {
|
list_for_each_entry(entry, &msk->pm.anno_list, list) {
|
||||||
if (addresses_equal(&entry->addr, addr, false))
|
if (addresses_equal(&entry->addr, addr, true))
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool mptcp_pm_sport_in_anno_list(struct mptcp_sock *msk, const struct sock *sk)
|
||||||
|
{
|
||||||
|
struct mptcp_pm_add_entry *entry;
|
||||||
|
struct mptcp_addr_info saddr;
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
local_address((struct sock_common *)sk, &saddr);
|
||||||
|
|
||||||
|
spin_lock_bh(&msk->pm.lock);
|
||||||
|
list_for_each_entry(entry, &msk->pm.anno_list, list) {
|
||||||
|
if (addresses_equal(&entry->addr, &saddr, true)) {
|
||||||
|
ret = true;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
spin_unlock_bh(&msk->pm.lock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void mptcp_pm_add_timer(struct timer_list *timer)
|
static void mptcp_pm_add_timer(struct timer_list *timer)
|
||||||
{
|
{
|
||||||
struct mptcp_pm_add_entry *entry = from_timer(entry, timer, add_timer);
|
struct mptcp_pm_add_entry *entry = from_timer(entry, timer, add_timer);
|
||||||
|
@ -327,17 +384,24 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
|
||||||
{
|
{
|
||||||
struct sock *sk = (struct sock *)msk;
|
struct sock *sk = (struct sock *)msk;
|
||||||
struct mptcp_pm_addr_entry *local;
|
struct mptcp_pm_addr_entry *local;
|
||||||
|
unsigned int add_addr_signal_max;
|
||||||
|
unsigned int local_addr_max;
|
||||||
struct pm_nl_pernet *pernet;
|
struct pm_nl_pernet *pernet;
|
||||||
|
unsigned int subflows_max;
|
||||||
|
|
||||||
pernet = net_generic(sock_net(sk), pm_nl_pernet_id);
|
pernet = net_generic(sock_net(sk), pm_nl_pernet_id);
|
||||||
|
|
||||||
|
add_addr_signal_max = mptcp_pm_get_add_addr_signal_max(msk);
|
||||||
|
local_addr_max = mptcp_pm_get_local_addr_max(msk);
|
||||||
|
subflows_max = mptcp_pm_get_subflows_max(msk);
|
||||||
|
|
||||||
pr_debug("local %d:%d signal %d:%d subflows %d:%d\n",
|
pr_debug("local %d:%d signal %d:%d subflows %d:%d\n",
|
||||||
msk->pm.local_addr_used, msk->pm.local_addr_max,
|
msk->pm.local_addr_used, local_addr_max,
|
||||||
msk->pm.add_addr_signaled, msk->pm.add_addr_signal_max,
|
msk->pm.add_addr_signaled, add_addr_signal_max,
|
||||||
msk->pm.subflows, msk->pm.subflows_max);
|
msk->pm.subflows, subflows_max);
|
||||||
|
|
||||||
/* check first for announce */
|
/* check first for announce */
|
||||||
if (msk->pm.add_addr_signaled < msk->pm.add_addr_signal_max) {
|
if (msk->pm.add_addr_signaled < add_addr_signal_max) {
|
||||||
local = select_signal_address(pernet,
|
local = select_signal_address(pernet,
|
||||||
msk->pm.add_addr_signaled);
|
msk->pm.add_addr_signaled);
|
||||||
|
|
||||||
|
@ -349,15 +413,15 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* pick failed, avoid fourther attempts later */
|
/* pick failed, avoid fourther attempts later */
|
||||||
msk->pm.local_addr_used = msk->pm.add_addr_signal_max;
|
msk->pm.local_addr_used = add_addr_signal_max;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_work_pending(msk);
|
check_work_pending(msk);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if should create a new subflow */
|
/* check if should create a new subflow */
|
||||||
if (msk->pm.local_addr_used < msk->pm.local_addr_max &&
|
if (msk->pm.local_addr_used < local_addr_max &&
|
||||||
msk->pm.subflows < msk->pm.subflows_max) {
|
msk->pm.subflows < subflows_max) {
|
||||||
local = select_local_address(pernet, msk);
|
local = select_local_address(pernet, msk);
|
||||||
if (local) {
|
if (local) {
|
||||||
struct mptcp_addr_info remote = { 0 };
|
struct mptcp_addr_info remote = { 0 };
|
||||||
|
@ -373,7 +437,7 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* lookup failed, avoid fourther attempts later */
|
/* lookup failed, avoid fourther attempts later */
|
||||||
msk->pm.local_addr_used = msk->pm.local_addr_max;
|
msk->pm.local_addr_used = local_addr_max;
|
||||||
check_work_pending(msk);
|
check_work_pending(msk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -391,17 +455,22 @@ void mptcp_pm_nl_subflow_established(struct mptcp_sock *msk)
|
||||||
void mptcp_pm_nl_add_addr_received(struct mptcp_sock *msk)
|
void mptcp_pm_nl_add_addr_received(struct mptcp_sock *msk)
|
||||||
{
|
{
|
||||||
struct sock *sk = (struct sock *)msk;
|
struct sock *sk = (struct sock *)msk;
|
||||||
|
unsigned int add_addr_accept_max;
|
||||||
struct mptcp_addr_info remote;
|
struct mptcp_addr_info remote;
|
||||||
struct mptcp_addr_info local;
|
struct mptcp_addr_info local;
|
||||||
|
unsigned int subflows_max;
|
||||||
bool use_port = false;
|
bool use_port = false;
|
||||||
|
|
||||||
|
add_addr_accept_max = mptcp_pm_get_add_addr_accept_max(msk);
|
||||||
|
subflows_max = mptcp_pm_get_subflows_max(msk);
|
||||||
|
|
||||||
pr_debug("accepted %d:%d remote family %d",
|
pr_debug("accepted %d:%d remote family %d",
|
||||||
msk->pm.add_addr_accepted, msk->pm.add_addr_accept_max,
|
msk->pm.add_addr_accepted, add_addr_accept_max,
|
||||||
msk->pm.remote.family);
|
msk->pm.remote.family);
|
||||||
msk->pm.add_addr_accepted++;
|
msk->pm.add_addr_accepted++;
|
||||||
msk->pm.subflows++;
|
msk->pm.subflows++;
|
||||||
if (msk->pm.add_addr_accepted >= msk->pm.add_addr_accept_max ||
|
if (msk->pm.add_addr_accepted >= add_addr_accept_max ||
|
||||||
msk->pm.subflows >= msk->pm.subflows_max)
|
msk->pm.subflows >= subflows_max)
|
||||||
WRITE_ONCE(msk->pm.accept_addr, false);
|
WRITE_ONCE(msk->pm.accept_addr, false);
|
||||||
|
|
||||||
/* connect to the specified remote address, using whatever
|
/* connect to the specified remote address, using whatever
|
||||||
|
@ -427,8 +496,7 @@ void mptcp_pm_nl_add_addr_send_ack(struct mptcp_sock *msk)
|
||||||
{
|
{
|
||||||
struct mptcp_subflow_context *subflow;
|
struct mptcp_subflow_context *subflow;
|
||||||
|
|
||||||
if (!mptcp_pm_should_add_signal_ipv6(msk) &&
|
if (!mptcp_pm_should_add_signal(msk))
|
||||||
!mptcp_pm_should_add_signal_port(msk))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
__mptcp_flush_join_list(msk);
|
__mptcp_flush_join_list(msk);
|
||||||
|
@ -438,10 +506,9 @@ void mptcp_pm_nl_add_addr_send_ack(struct mptcp_sock *msk)
|
||||||
u8 add_addr;
|
u8 add_addr;
|
||||||
|
|
||||||
spin_unlock_bh(&msk->pm.lock);
|
spin_unlock_bh(&msk->pm.lock);
|
||||||
if (mptcp_pm_should_add_signal_ipv6(msk))
|
pr_debug("send ack for add_addr%s%s",
|
||||||
pr_debug("send ack for add_addr6");
|
mptcp_pm_should_add_signal_ipv6(msk) ? " [ipv6]" : "",
|
||||||
if (mptcp_pm_should_add_signal_port(msk))
|
mptcp_pm_should_add_signal_port(msk) ? " [port]" : "");
|
||||||
pr_debug("send ack for add_addr_port");
|
|
||||||
|
|
||||||
lock_sock(ssk);
|
lock_sock(ssk);
|
||||||
tcp_send_ack(ssk);
|
tcp_send_ack(ssk);
|
||||||
|
@ -572,6 +639,7 @@ static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet,
|
||||||
struct mptcp_pm_addr_entry *entry)
|
struct mptcp_pm_addr_entry *entry)
|
||||||
{
|
{
|
||||||
struct mptcp_pm_addr_entry *cur;
|
struct mptcp_pm_addr_entry *cur;
|
||||||
|
unsigned int addr_max;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
spin_lock_bh(&pernet->lock);
|
spin_lock_bh(&pernet->lock);
|
||||||
|
@ -614,10 +682,14 @@ static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet,
|
||||||
if (entry->addr.id > pernet->next_id)
|
if (entry->addr.id > pernet->next_id)
|
||||||
pernet->next_id = entry->addr.id;
|
pernet->next_id = entry->addr.id;
|
||||||
|
|
||||||
if (entry->addr.flags & MPTCP_PM_ADDR_FLAG_SIGNAL)
|
if (entry->addr.flags & MPTCP_PM_ADDR_FLAG_SIGNAL) {
|
||||||
pernet->add_addr_signal_max++;
|
addr_max = pernet->add_addr_signal_max;
|
||||||
if (entry->addr.flags & MPTCP_PM_ADDR_FLAG_SUBFLOW)
|
WRITE_ONCE(pernet->add_addr_signal_max, addr_max + 1);
|
||||||
pernet->local_addr_max++;
|
}
|
||||||
|
if (entry->addr.flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) {
|
||||||
|
addr_max = pernet->local_addr_max;
|
||||||
|
WRITE_ONCE(pernet->local_addr_max, addr_max + 1);
|
||||||
|
}
|
||||||
|
|
||||||
pernet->addrs++;
|
pernet->addrs++;
|
||||||
list_add_tail_rcu(&entry->list, &pernet->local_addr_list);
|
list_add_tail_rcu(&entry->list, &pernet->local_addr_list);
|
||||||
|
@ -628,6 +700,53 @@ static int mptcp_pm_nl_append_new_local_addr(struct pm_nl_pernet *pernet,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mptcp_pm_nl_create_listen_socket(struct sock *sk,
|
||||||
|
struct mptcp_pm_addr_entry *entry)
|
||||||
|
{
|
||||||
|
struct sockaddr_storage addr;
|
||||||
|
struct mptcp_sock *msk;
|
||||||
|
struct socket *ssock;
|
||||||
|
int backlog = 1024;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = sock_create_kern(sock_net(sk), entry->addr.family,
|
||||||
|
SOCK_STREAM, IPPROTO_MPTCP, &entry->lsk);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
msk = mptcp_sk(entry->lsk->sk);
|
||||||
|
if (!msk) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssock = __mptcp_nmpc_socket(msk);
|
||||||
|
if (!ssock) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
mptcp_info2sockaddr(&entry->addr, &addr, entry->addr.family);
|
||||||
|
err = kernel_bind(ssock, (struct sockaddr *)&addr,
|
||||||
|
sizeof(struct sockaddr_in));
|
||||||
|
if (err) {
|
||||||
|
pr_warn("kernel_bind error, err=%d", err);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = kernel_listen(ssock, backlog);
|
||||||
|
if (err) {
|
||||||
|
pr_warn("kernel_listen error, err=%d", err);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
sock_release(entry->lsk);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct sock_common *skc)
|
int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct sock_common *skc)
|
||||||
{
|
{
|
||||||
struct mptcp_pm_addr_entry *entry;
|
struct mptcp_pm_addr_entry *entry;
|
||||||
|
@ -654,7 +773,7 @@ int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct sock_common *skc)
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
list_for_each_entry_rcu(entry, &pernet->local_addr_list, list) {
|
list_for_each_entry_rcu(entry, &pernet->local_addr_list, list) {
|
||||||
if (addresses_equal(&entry->addr, &skc_local, false)) {
|
if (addresses_equal(&entry->addr, &skc_local, entry->addr.port)) {
|
||||||
ret = entry->addr.id;
|
ret = entry->addr.id;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -672,6 +791,8 @@ int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct sock_common *skc)
|
||||||
entry->addr.ifindex = 0;
|
entry->addr.ifindex = 0;
|
||||||
entry->addr.flags = 0;
|
entry->addr.flags = 0;
|
||||||
entry->addr.id = 0;
|
entry->addr.id = 0;
|
||||||
|
entry->addr.port = 0;
|
||||||
|
entry->lsk = NULL;
|
||||||
ret = mptcp_pm_nl_append_new_local_addr(pernet, entry);
|
ret = mptcp_pm_nl_append_new_local_addr(pernet, entry);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
kfree(entry);
|
kfree(entry);
|
||||||
|
@ -682,19 +803,12 @@ int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct sock_common *skc)
|
||||||
void mptcp_pm_nl_data_init(struct mptcp_sock *msk)
|
void mptcp_pm_nl_data_init(struct mptcp_sock *msk)
|
||||||
{
|
{
|
||||||
struct mptcp_pm_data *pm = &msk->pm;
|
struct mptcp_pm_data *pm = &msk->pm;
|
||||||
struct pm_nl_pernet *pernet;
|
|
||||||
bool subflows;
|
bool subflows;
|
||||||
|
|
||||||
pernet = net_generic(sock_net((struct sock *)msk), pm_nl_pernet_id);
|
subflows = !!mptcp_pm_get_subflows_max(msk);
|
||||||
|
WRITE_ONCE(pm->work_pending, (!!mptcp_pm_get_local_addr_max(msk) && subflows) ||
|
||||||
pm->add_addr_signal_max = READ_ONCE(pernet->add_addr_signal_max);
|
!!mptcp_pm_get_add_addr_signal_max(msk));
|
||||||
pm->add_addr_accept_max = READ_ONCE(pernet->add_addr_accept_max);
|
WRITE_ONCE(pm->accept_addr, !!mptcp_pm_get_add_addr_accept_max(msk) && subflows);
|
||||||
pm->local_addr_max = READ_ONCE(pernet->local_addr_max);
|
|
||||||
pm->subflows_max = READ_ONCE(pernet->subflows_max);
|
|
||||||
subflows = !!pm->subflows_max;
|
|
||||||
WRITE_ONCE(pm->work_pending, (!!pm->local_addr_max && subflows) ||
|
|
||||||
!!pm->add_addr_signal_max);
|
|
||||||
WRITE_ONCE(pm->accept_addr, !!pm->add_addr_accept_max && subflows);
|
|
||||||
WRITE_ONCE(pm->accept_subflow, subflows);
|
WRITE_ONCE(pm->accept_subflow, subflows);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -797,6 +911,9 @@ static int mptcp_pm_parse_addr(struct nlattr *attr, struct genl_info *info,
|
||||||
if (tb[MPTCP_PM_ADDR_ATTR_FLAGS])
|
if (tb[MPTCP_PM_ADDR_ATTR_FLAGS])
|
||||||
entry->addr.flags = nla_get_u32(tb[MPTCP_PM_ADDR_ATTR_FLAGS]);
|
entry->addr.flags = nla_get_u32(tb[MPTCP_PM_ADDR_ATTR_FLAGS]);
|
||||||
|
|
||||||
|
if (tb[MPTCP_PM_ADDR_ATTR_PORT])
|
||||||
|
entry->addr.port = htons(nla_get_u16(tb[MPTCP_PM_ADDR_ATTR_PORT]));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -805,6 +922,31 @@ static struct pm_nl_pernet *genl_info_pm_nl(struct genl_info *info)
|
||||||
return net_generic(genl_info_net(info), pm_nl_pernet_id);
|
return net_generic(genl_info_net(info), pm_nl_pernet_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mptcp_nl_add_subflow_or_signal_addr(struct net *net)
|
||||||
|
{
|
||||||
|
struct mptcp_sock *msk;
|
||||||
|
long s_slot = 0, s_num = 0;
|
||||||
|
|
||||||
|
while ((msk = mptcp_token_iter_next(net, &s_slot, &s_num)) != NULL) {
|
||||||
|
struct sock *sk = (struct sock *)msk;
|
||||||
|
|
||||||
|
if (!READ_ONCE(msk->fully_established))
|
||||||
|
goto next;
|
||||||
|
|
||||||
|
lock_sock(sk);
|
||||||
|
spin_lock_bh(&msk->pm.lock);
|
||||||
|
mptcp_pm_create_subflow_or_signal_addr(msk);
|
||||||
|
spin_unlock_bh(&msk->pm.lock);
|
||||||
|
release_sock(sk);
|
||||||
|
|
||||||
|
next:
|
||||||
|
sock_put(sk);
|
||||||
|
cond_resched();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int mptcp_nl_cmd_add_addr(struct sk_buff *skb, struct genl_info *info)
|
static int mptcp_nl_cmd_add_addr(struct sk_buff *skb, struct genl_info *info)
|
||||||
{
|
{
|
||||||
struct nlattr *attr = info->attrs[MPTCP_PM_ATTR_ADDR];
|
struct nlattr *attr = info->attrs[MPTCP_PM_ATTR_ADDR];
|
||||||
|
@ -823,13 +965,25 @@ static int mptcp_nl_cmd_add_addr(struct sk_buff *skb, struct genl_info *info)
|
||||||
}
|
}
|
||||||
|
|
||||||
*entry = addr;
|
*entry = addr;
|
||||||
|
if (entry->addr.port) {
|
||||||
|
ret = mptcp_pm_nl_create_listen_socket(skb->sk, entry);
|
||||||
|
if (ret) {
|
||||||
|
GENL_SET_ERR_MSG(info, "create listen socket error");
|
||||||
|
kfree(entry);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
ret = mptcp_pm_nl_append_new_local_addr(pernet, entry);
|
ret = mptcp_pm_nl_append_new_local_addr(pernet, entry);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
GENL_SET_ERR_MSG(info, "too many addresses or duplicate one");
|
GENL_SET_ERR_MSG(info, "too many addresses or duplicate one");
|
||||||
|
if (entry->lsk)
|
||||||
|
sock_release(entry->lsk);
|
||||||
kfree(entry);
|
kfree(entry);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mptcp_nl_add_subflow_or_signal_addr(sock_net(skb->sk));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -907,11 +1061,44 @@ static int mptcp_nl_remove_subflow_and_signal_addr(struct net *net,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct addr_entry_release_work {
|
||||||
|
struct rcu_work rwork;
|
||||||
|
struct mptcp_pm_addr_entry *entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void mptcp_pm_release_addr_entry(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct addr_entry_release_work *w;
|
||||||
|
struct mptcp_pm_addr_entry *entry;
|
||||||
|
|
||||||
|
w = container_of(to_rcu_work(work), struct addr_entry_release_work, rwork);
|
||||||
|
entry = w->entry;
|
||||||
|
if (entry) {
|
||||||
|
if (entry->lsk)
|
||||||
|
sock_release(entry->lsk);
|
||||||
|
kfree(entry);
|
||||||
|
}
|
||||||
|
kfree(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mptcp_pm_free_addr_entry(struct mptcp_pm_addr_entry *entry)
|
||||||
|
{
|
||||||
|
struct addr_entry_release_work *w;
|
||||||
|
|
||||||
|
w = kmalloc(sizeof(*w), GFP_ATOMIC);
|
||||||
|
if (w) {
|
||||||
|
INIT_RCU_WORK(&w->rwork, mptcp_pm_release_addr_entry);
|
||||||
|
w->entry = entry;
|
||||||
|
queue_rcu_work(system_wq, &w->rwork);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int mptcp_nl_cmd_del_addr(struct sk_buff *skb, struct genl_info *info)
|
static int mptcp_nl_cmd_del_addr(struct sk_buff *skb, struct genl_info *info)
|
||||||
{
|
{
|
||||||
struct nlattr *attr = info->attrs[MPTCP_PM_ATTR_ADDR];
|
struct nlattr *attr = info->attrs[MPTCP_PM_ATTR_ADDR];
|
||||||
struct pm_nl_pernet *pernet = genl_info_pm_nl(info);
|
struct pm_nl_pernet *pernet = genl_info_pm_nl(info);
|
||||||
struct mptcp_pm_addr_entry addr, *entry;
|
struct mptcp_pm_addr_entry addr, *entry;
|
||||||
|
unsigned int addr_max;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = mptcp_pm_parse_addr(attr, info, false, &addr);
|
ret = mptcp_pm_parse_addr(attr, info, false, &addr);
|
||||||
|
@ -925,10 +1112,14 @@ static int mptcp_nl_cmd_del_addr(struct sk_buff *skb, struct genl_info *info)
|
||||||
spin_unlock_bh(&pernet->lock);
|
spin_unlock_bh(&pernet->lock);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (entry->addr.flags & MPTCP_PM_ADDR_FLAG_SIGNAL)
|
if (entry->addr.flags & MPTCP_PM_ADDR_FLAG_SIGNAL) {
|
||||||
pernet->add_addr_signal_max--;
|
addr_max = pernet->add_addr_signal_max;
|
||||||
if (entry->addr.flags & MPTCP_PM_ADDR_FLAG_SUBFLOW)
|
WRITE_ONCE(pernet->add_addr_signal_max, addr_max - 1);
|
||||||
pernet->local_addr_max--;
|
}
|
||||||
|
if (entry->addr.flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) {
|
||||||
|
addr_max = pernet->local_addr_max;
|
||||||
|
WRITE_ONCE(pernet->local_addr_max, addr_max - 1);
|
||||||
|
}
|
||||||
|
|
||||||
pernet->addrs--;
|
pernet->addrs--;
|
||||||
list_del_rcu(&entry->list);
|
list_del_rcu(&entry->list);
|
||||||
|
@ -936,7 +1127,7 @@ static int mptcp_nl_cmd_del_addr(struct sk_buff *skb, struct genl_info *info)
|
||||||
spin_unlock_bh(&pernet->lock);
|
spin_unlock_bh(&pernet->lock);
|
||||||
|
|
||||||
mptcp_nl_remove_subflow_and_signal_addr(sock_net(skb->sk), &entry->addr);
|
mptcp_nl_remove_subflow_and_signal_addr(sock_net(skb->sk), &entry->addr);
|
||||||
kfree_rcu(entry, rcu);
|
mptcp_pm_free_addr_entry(entry);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -950,15 +1141,15 @@ static void __flush_addrs(struct net *net, struct list_head *list)
|
||||||
struct mptcp_pm_addr_entry, list);
|
struct mptcp_pm_addr_entry, list);
|
||||||
mptcp_nl_remove_subflow_and_signal_addr(net, &cur->addr);
|
mptcp_nl_remove_subflow_and_signal_addr(net, &cur->addr);
|
||||||
list_del_rcu(&cur->list);
|
list_del_rcu(&cur->list);
|
||||||
kfree_rcu(cur, rcu);
|
mptcp_pm_free_addr_entry(cur);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __reset_counters(struct pm_nl_pernet *pernet)
|
static void __reset_counters(struct pm_nl_pernet *pernet)
|
||||||
{
|
{
|
||||||
pernet->add_addr_signal_max = 0;
|
WRITE_ONCE(pernet->add_addr_signal_max, 0);
|
||||||
pernet->add_addr_accept_max = 0;
|
WRITE_ONCE(pernet->add_addr_accept_max, 0);
|
||||||
pernet->local_addr_max = 0;
|
WRITE_ONCE(pernet->local_addr_max, 0);
|
||||||
pernet->addrs = 0;
|
pernet->addrs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -989,6 +1180,8 @@ static int mptcp_nl_fill_addr(struct sk_buff *skb,
|
||||||
|
|
||||||
if (nla_put_u16(skb, MPTCP_PM_ADDR_ATTR_FAMILY, addr->family))
|
if (nla_put_u16(skb, MPTCP_PM_ADDR_ATTR_FAMILY, addr->family))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
|
if (nla_put_u16(skb, MPTCP_PM_ADDR_ATTR_PORT, ntohs(addr->port)))
|
||||||
|
goto nla_put_failure;
|
||||||
if (nla_put_u8(skb, MPTCP_PM_ADDR_ATTR_ID, addr->id))
|
if (nla_put_u8(skb, MPTCP_PM_ADDR_ATTR_ID, addr->id))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
if (nla_put_u32(skb, MPTCP_PM_ADDR_ATTR_FLAGS, entry->addr.flags))
|
if (nla_put_u32(skb, MPTCP_PM_ADDR_ATTR_FLAGS, entry->addr.flags))
|
||||||
|
|
|
@ -52,7 +52,7 @@ static struct net_device mptcp_napi_dev;
|
||||||
* completed yet or has failed, return the subflow socket.
|
* completed yet or has failed, return the subflow socket.
|
||||||
* Otherwise return NULL.
|
* Otherwise return NULL.
|
||||||
*/
|
*/
|
||||||
static struct socket *__mptcp_nmpc_socket(const struct mptcp_sock *msk)
|
struct socket *__mptcp_nmpc_socket(const struct mptcp_sock *msk)
|
||||||
{
|
{
|
||||||
if (!msk->subflow || READ_ONCE(msk->can_ack))
|
if (!msk->subflow || READ_ONCE(msk->can_ack))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -203,10 +203,6 @@ struct mptcp_pm_data {
|
||||||
u8 add_addr_accepted;
|
u8 add_addr_accepted;
|
||||||
u8 local_addr_used;
|
u8 local_addr_used;
|
||||||
u8 subflows;
|
u8 subflows;
|
||||||
u8 add_addr_signal_max;
|
|
||||||
u8 add_addr_accept_max;
|
|
||||||
u8 local_addr_max;
|
|
||||||
u8 subflows_max;
|
|
||||||
u8 status;
|
u8 status;
|
||||||
u8 rm_id;
|
u8 rm_id;
|
||||||
};
|
};
|
||||||
|
@ -542,11 +538,15 @@ void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
|
||||||
struct mptcp_subflow_context *subflow);
|
struct mptcp_subflow_context *subflow);
|
||||||
void mptcp_subflow_reset(struct sock *ssk);
|
void mptcp_subflow_reset(struct sock *ssk);
|
||||||
void mptcp_sock_graft(struct sock *sk, struct socket *parent);
|
void mptcp_sock_graft(struct sock *sk, struct socket *parent);
|
||||||
|
struct socket *__mptcp_nmpc_socket(const struct mptcp_sock *msk);
|
||||||
|
|
||||||
/* called with sk socket lock held */
|
/* called with sk socket lock held */
|
||||||
int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
|
int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
|
||||||
const struct mptcp_addr_info *remote);
|
const struct mptcp_addr_info *remote);
|
||||||
int mptcp_subflow_create_socket(struct sock *sk, struct socket **new_sock);
|
int mptcp_subflow_create_socket(struct sock *sk, struct socket **new_sock);
|
||||||
|
void mptcp_info2sockaddr(const struct mptcp_addr_info *info,
|
||||||
|
struct sockaddr_storage *addr,
|
||||||
|
unsigned short family);
|
||||||
|
|
||||||
static inline void mptcp_subflow_tcp_fallback(struct sock *sk,
|
static inline void mptcp_subflow_tcp_fallback(struct sock *sk,
|
||||||
struct mptcp_subflow_context *ctx)
|
struct mptcp_subflow_context *ctx)
|
||||||
|
@ -650,6 +650,7 @@ int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk,
|
||||||
struct mptcp_addr_info *addr,
|
struct mptcp_addr_info *addr,
|
||||||
u8 bkup);
|
u8 bkup);
|
||||||
void mptcp_pm_free_anno_list(struct mptcp_sock *msk);
|
void mptcp_pm_free_anno_list(struct mptcp_sock *msk);
|
||||||
|
bool mptcp_pm_sport_in_anno_list(struct mptcp_sock *msk, const struct sock *sk);
|
||||||
struct mptcp_pm_add_entry *
|
struct mptcp_pm_add_entry *
|
||||||
mptcp_pm_del_add_timer(struct mptcp_sock *msk,
|
mptcp_pm_del_add_timer(struct mptcp_sock *msk,
|
||||||
struct mptcp_addr_info *addr);
|
struct mptcp_addr_info *addr);
|
||||||
|
@ -714,6 +715,9 @@ void mptcp_pm_nl_add_addr_send_ack(struct mptcp_sock *msk);
|
||||||
void mptcp_pm_nl_rm_addr_received(struct mptcp_sock *msk);
|
void mptcp_pm_nl_rm_addr_received(struct mptcp_sock *msk);
|
||||||
void mptcp_pm_nl_rm_subflow_received(struct mptcp_sock *msk, u8 rm_id);
|
void mptcp_pm_nl_rm_subflow_received(struct mptcp_sock *msk, u8 rm_id);
|
||||||
int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct sock_common *skc);
|
int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct sock_common *skc);
|
||||||
|
unsigned int mptcp_pm_get_add_addr_signal_max(struct mptcp_sock *msk);
|
||||||
|
unsigned int mptcp_pm_get_add_addr_accept_max(struct mptcp_sock *msk);
|
||||||
|
unsigned int mptcp_pm_get_subflows_max(struct mptcp_sock *msk);
|
||||||
|
|
||||||
static inline struct mptcp_ext *mptcp_get_ext(struct sk_buff *skb)
|
static inline struct mptcp_ext *mptcp_get_ext(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
|
|
|
@ -64,11 +64,23 @@ static bool mptcp_can_accept_new_subflow(const struct mptcp_sock *msk)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* validate received token and create truncated hmac and nonce for SYN-ACK */
|
/* validate received token and create truncated hmac and nonce for SYN-ACK */
|
||||||
static struct mptcp_sock *subflow_token_join_request(struct request_sock *req,
|
static void subflow_req_create_thmac(struct mptcp_subflow_request_sock *subflow_req)
|
||||||
const struct sk_buff *skb)
|
{
|
||||||
|
struct mptcp_sock *msk = subflow_req->msk;
|
||||||
|
u8 hmac[SHA256_DIGEST_SIZE];
|
||||||
|
|
||||||
|
get_random_bytes(&subflow_req->local_nonce, sizeof(u32));
|
||||||
|
|
||||||
|
subflow_generate_hmac(msk->local_key, msk->remote_key,
|
||||||
|
subflow_req->local_nonce,
|
||||||
|
subflow_req->remote_nonce, hmac);
|
||||||
|
|
||||||
|
subflow_req->thmac = get_unaligned_be64(hmac);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct mptcp_sock *subflow_token_join_request(struct request_sock *req)
|
||||||
{
|
{
|
||||||
struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
|
struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
|
||||||
u8 hmac[SHA256_DIGEST_SIZE];
|
|
||||||
struct mptcp_sock *msk;
|
struct mptcp_sock *msk;
|
||||||
int local_id;
|
int local_id;
|
||||||
|
|
||||||
|
@ -85,13 +97,6 @@ static struct mptcp_sock *subflow_token_join_request(struct request_sock *req,
|
||||||
}
|
}
|
||||||
subflow_req->local_id = local_id;
|
subflow_req->local_id = local_id;
|
||||||
|
|
||||||
get_random_bytes(&subflow_req->local_nonce, sizeof(u32));
|
|
||||||
|
|
||||||
subflow_generate_hmac(msk->local_key, msk->remote_key,
|
|
||||||
subflow_req->local_nonce,
|
|
||||||
subflow_req->remote_nonce, hmac);
|
|
||||||
|
|
||||||
subflow_req->thmac = get_unaligned_be64(hmac);
|
|
||||||
return msk;
|
return msk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,6 +120,11 @@ static int __subflow_init_req(struct request_sock *req, const struct sock *sk_li
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool subflow_use_different_sport(struct mptcp_sock *msk, const struct sock *sk)
|
||||||
|
{
|
||||||
|
return inet_sk(sk)->inet_sport != inet_sk((struct sock *)msk)->inet_sport;
|
||||||
|
}
|
||||||
|
|
||||||
/* Init mptcp request socket.
|
/* Init mptcp request socket.
|
||||||
*
|
*
|
||||||
* Returns an error code if a JOIN has failed and a TCP reset
|
* Returns an error code if a JOIN has failed and a TCP reset
|
||||||
|
@ -181,12 +191,30 @@ static int subflow_init_req(struct request_sock *req,
|
||||||
subflow_req->remote_id = mp_opt.join_id;
|
subflow_req->remote_id = mp_opt.join_id;
|
||||||
subflow_req->token = mp_opt.token;
|
subflow_req->token = mp_opt.token;
|
||||||
subflow_req->remote_nonce = mp_opt.nonce;
|
subflow_req->remote_nonce = mp_opt.nonce;
|
||||||
subflow_req->msk = subflow_token_join_request(req, skb);
|
subflow_req->msk = subflow_token_join_request(req);
|
||||||
|
|
||||||
/* Can't fall back to TCP in this case. */
|
/* Can't fall back to TCP in this case. */
|
||||||
if (!subflow_req->msk)
|
if (!subflow_req->msk)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
|
if (subflow_use_different_sport(subflow_req->msk, sk_listener)) {
|
||||||
|
pr_debug("syn inet_sport=%d %d",
|
||||||
|
ntohs(inet_sk(sk_listener)->inet_sport),
|
||||||
|
ntohs(inet_sk((struct sock *)subflow_req->msk)->inet_sport));
|
||||||
|
if (!mptcp_pm_sport_in_anno_list(subflow_req->msk, sk_listener)) {
|
||||||
|
sock_put((struct sock *)subflow_req->msk);
|
||||||
|
mptcp_token_destroy_request(req);
|
||||||
|
tcp_request_sock_ops.destructor(req);
|
||||||
|
subflow_req->msk = NULL;
|
||||||
|
subflow_req->mp_join = 0;
|
||||||
|
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MISMATCHPORTSYNRX);
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINPORTSYNRX);
|
||||||
|
}
|
||||||
|
|
||||||
|
subflow_req_create_thmac(subflow_req);
|
||||||
|
|
||||||
if (unlikely(req->syncookie)) {
|
if (unlikely(req->syncookie)) {
|
||||||
if (mptcp_can_accept_new_subflow(subflow_req->msk))
|
if (mptcp_can_accept_new_subflow(subflow_req->msk))
|
||||||
subflow_init_req_cookie_join_save(subflow_req, skb);
|
subflow_init_req_cookie_join_save(subflow_req, skb);
|
||||||
|
@ -329,6 +357,11 @@ void mptcp_subflow_reset(struct sock *ssk)
|
||||||
sock_put(sk);
|
sock_put(sk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool subflow_use_different_dport(struct mptcp_sock *msk, const struct sock *sk)
|
||||||
|
{
|
||||||
|
return inet_sk(sk)->inet_dport != inet_sk((struct sock *)msk)->inet_dport;
|
||||||
|
}
|
||||||
|
|
||||||
static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
|
static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
|
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
|
||||||
|
@ -395,6 +428,13 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
|
||||||
|
|
||||||
subflow->mp_join = 1;
|
subflow->mp_join = 1;
|
||||||
MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINSYNACKRX);
|
MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINSYNACKRX);
|
||||||
|
|
||||||
|
if (subflow_use_different_dport(mptcp_sk(parent), sk)) {
|
||||||
|
pr_debug("synack inet_dport=%d %d",
|
||||||
|
ntohs(inet_sk(sk)->inet_dport),
|
||||||
|
ntohs(inet_sk(parent)->inet_dport));
|
||||||
|
MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINPORTSYNACKRX);
|
||||||
|
}
|
||||||
} else if (mptcp_check_fallback(sk)) {
|
} else if (mptcp_check_fallback(sk)) {
|
||||||
fallback:
|
fallback:
|
||||||
mptcp_rcv_space_init(mptcp_sk(parent), sk);
|
mptcp_rcv_space_init(mptcp_sk(parent), sk);
|
||||||
|
@ -660,6 +700,17 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
|
||||||
|
|
||||||
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINACKRX);
|
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINACKRX);
|
||||||
tcp_rsk(req)->drop_req = true;
|
tcp_rsk(req)->drop_req = true;
|
||||||
|
|
||||||
|
if (subflow_use_different_sport(owner, sk)) {
|
||||||
|
pr_debug("ack inet_sport=%d %d",
|
||||||
|
ntohs(inet_sk(sk)->inet_sport),
|
||||||
|
ntohs(inet_sk((struct sock *)owner)->inet_sport));
|
||||||
|
if (!mptcp_pm_sport_in_anno_list(owner, sk)) {
|
||||||
|
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MISMATCHPORTACKRX);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINPORTACKRX);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1084,9 +1135,9 @@ void mptcpv6_handle_mapped(struct sock *sk, bool mapped)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void mptcp_info2sockaddr(const struct mptcp_addr_info *info,
|
void mptcp_info2sockaddr(const struct mptcp_addr_info *info,
|
||||||
struct sockaddr_storage *addr,
|
struct sockaddr_storage *addr,
|
||||||
unsigned short family)
|
unsigned short family)
|
||||||
{
|
{
|
||||||
memset(addr, 0, sizeof(*addr));
|
memset(addr, 0, sizeof(*addr));
|
||||||
addr->ss_family = family;
|
addr->ss_family = family;
|
||||||
|
|
|
@ -209,8 +209,8 @@ do_transfer()
|
||||||
srv_proto="$4"
|
srv_proto="$4"
|
||||||
connect_addr="$5"
|
connect_addr="$5"
|
||||||
test_link_fail="$6"
|
test_link_fail="$6"
|
||||||
rm_nr_ns1="$7"
|
addr_nr_ns1="$7"
|
||||||
rm_nr_ns2="$8"
|
addr_nr_ns2="$8"
|
||||||
speed="$9"
|
speed="$9"
|
||||||
bkup="${10}"
|
bkup="${10}"
|
||||||
|
|
||||||
|
@ -264,7 +264,24 @@ do_transfer()
|
||||||
fi
|
fi
|
||||||
cpid=$!
|
cpid=$!
|
||||||
|
|
||||||
if [ $rm_nr_ns1 -gt 0 ]; then
|
if [ $addr_nr_ns1 -gt 0 ]; then
|
||||||
|
let add_nr_ns1=addr_nr_ns1
|
||||||
|
counter=2
|
||||||
|
sleep 1
|
||||||
|
while [ $add_nr_ns1 -gt 0 ]; do
|
||||||
|
local addr
|
||||||
|
if is_v6 "${connect_addr}"; then
|
||||||
|
addr="dead:beef:$counter::1"
|
||||||
|
else
|
||||||
|
addr="10.0.$counter.1"
|
||||||
|
fi
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl add $addr flags signal
|
||||||
|
let counter+=1
|
||||||
|
let add_nr_ns1-=1
|
||||||
|
done
|
||||||
|
sleep 1
|
||||||
|
elif [ $addr_nr_ns1 -lt 0 ]; then
|
||||||
|
let rm_nr_ns1=-addr_nr_ns1
|
||||||
if [ $rm_nr_ns1 -lt 8 ]; then
|
if [ $rm_nr_ns1 -lt 8 ]; then
|
||||||
counter=1
|
counter=1
|
||||||
sleep 1
|
sleep 1
|
||||||
|
@ -281,7 +298,24 @@ do_transfer()
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $rm_nr_ns2 -gt 0 ]; then
|
if [ $addr_nr_ns2 -gt 0 ]; then
|
||||||
|
let add_nr_ns2=addr_nr_ns2
|
||||||
|
counter=3
|
||||||
|
sleep 1
|
||||||
|
while [ $add_nr_ns2 -gt 0 ]; do
|
||||||
|
local addr
|
||||||
|
if is_v6 "${connect_addr}"; then
|
||||||
|
addr="dead:beef:$counter::2"
|
||||||
|
else
|
||||||
|
addr="10.0.$counter.2"
|
||||||
|
fi
|
||||||
|
ip netns exec $ns2 ./pm_nl_ctl add $addr flags subflow
|
||||||
|
let counter+=1
|
||||||
|
let add_nr_ns2-=1
|
||||||
|
done
|
||||||
|
sleep 1
|
||||||
|
elif [ $addr_nr_ns2 -lt 0 ]; then
|
||||||
|
let rm_nr_ns2=-addr_nr_ns2
|
||||||
if [ $rm_nr_ns2 -lt 8 ]; then
|
if [ $rm_nr_ns2 -lt 8 ]; then
|
||||||
counter=1
|
counter=1
|
||||||
sleep 1
|
sleep 1
|
||||||
|
@ -368,8 +402,8 @@ run_tests()
|
||||||
connector_ns="$2"
|
connector_ns="$2"
|
||||||
connect_addr="$3"
|
connect_addr="$3"
|
||||||
test_linkfail="${4:-0}"
|
test_linkfail="${4:-0}"
|
||||||
rm_nr_ns1="${5:-0}"
|
addr_nr_ns1="${5:-0}"
|
||||||
rm_nr_ns2="${6:-0}"
|
addr_nr_ns2="${6:-0}"
|
||||||
speed="${7:-fast}"
|
speed="${7:-fast}"
|
||||||
bkup="${8:-""}"
|
bkup="${8:-""}"
|
||||||
lret=0
|
lret=0
|
||||||
|
@ -386,7 +420,7 @@ run_tests()
|
||||||
fi
|
fi
|
||||||
|
|
||||||
do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr} \
|
do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr} \
|
||||||
${test_linkfail} ${rm_nr_ns1} ${rm_nr_ns2} ${speed} ${bkup}
|
${test_linkfail} ${addr_nr_ns1} ${addr_nr_ns2} ${speed} ${bkup}
|
||||||
lret=$?
|
lret=$?
|
||||||
|
|
||||||
if [ "$test_linkfail" -eq 1 ];then
|
if [ "$test_linkfail" -eq 1 ];then
|
||||||
|
@ -453,6 +487,12 @@ chk_add_nr()
|
||||||
{
|
{
|
||||||
local add_nr=$1
|
local add_nr=$1
|
||||||
local echo_nr=$2
|
local echo_nr=$2
|
||||||
|
local port_nr=${3:-0}
|
||||||
|
local syn_nr=${4:-$port_nr}
|
||||||
|
local syn_ack_nr=${5:-$port_nr}
|
||||||
|
local ack_nr=${6:-$port_nr}
|
||||||
|
local mis_syn_nr=${7:-0}
|
||||||
|
local mis_ack_nr=${8:-0}
|
||||||
local count
|
local count
|
||||||
local dump_stats
|
local dump_stats
|
||||||
|
|
||||||
|
@ -475,7 +515,87 @@ chk_add_nr()
|
||||||
ret=1
|
ret=1
|
||||||
dump_stats=1
|
dump_stats=1
|
||||||
else
|
else
|
||||||
echo "[ ok ]"
|
echo -n "[ ok ]"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $port_nr -gt 0 ]; then
|
||||||
|
echo -n " - pt "
|
||||||
|
count=`ip netns exec $ns2 nstat -as | grep MPTcpExtPortAdd | awk '{print $2}'`
|
||||||
|
[ -z "$count" ] && count=0
|
||||||
|
if [ "$count" != "$port_nr" ]; then
|
||||||
|
echo "[fail] got $count ADD_ADDR[s] with a port-number expected $port_nr"
|
||||||
|
ret=1
|
||||||
|
dump_stats=1
|
||||||
|
else
|
||||||
|
echo "[ ok ]"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "%-39s %s" " " "syn"
|
||||||
|
count=`ip netns exec $ns1 nstat -as | grep MPTcpExtMPJoinPortSynRx |
|
||||||
|
awk '{print $2}'`
|
||||||
|
[ -z "$count" ] && count=0
|
||||||
|
if [ "$count" != "$syn_nr" ]; then
|
||||||
|
echo "[fail] got $count JOIN[s] syn with a different \
|
||||||
|
port-number expected $syn_nr"
|
||||||
|
ret=1
|
||||||
|
dump_stats=1
|
||||||
|
else
|
||||||
|
echo -n "[ ok ]"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n " - synack"
|
||||||
|
count=`ip netns exec $ns2 nstat -as | grep MPTcpExtMPJoinPortSynAckRx |
|
||||||
|
awk '{print $2}'`
|
||||||
|
[ -z "$count" ] && count=0
|
||||||
|
if [ "$count" != "$syn_ack_nr" ]; then
|
||||||
|
echo "[fail] got $count JOIN[s] synack with a different \
|
||||||
|
port-number expected $syn_ack_nr"
|
||||||
|
ret=1
|
||||||
|
dump_stats=1
|
||||||
|
else
|
||||||
|
echo -n "[ ok ]"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n " - ack"
|
||||||
|
count=`ip netns exec $ns1 nstat -as | grep MPTcpExtMPJoinPortAckRx |
|
||||||
|
awk '{print $2}'`
|
||||||
|
[ -z "$count" ] && count=0
|
||||||
|
if [ "$count" != "$ack_nr" ]; then
|
||||||
|
echo "[fail] got $count JOIN[s] ack with a different \
|
||||||
|
port-number expected $ack_nr"
|
||||||
|
ret=1
|
||||||
|
dump_stats=1
|
||||||
|
else
|
||||||
|
echo "[ ok ]"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "%-39s %s" " " "syn"
|
||||||
|
count=`ip netns exec $ns1 nstat -as | grep MPTcpExtMismatchPortSynRx |
|
||||||
|
awk '{print $2}'`
|
||||||
|
[ -z "$count" ] && count=0
|
||||||
|
if [ "$count" != "$mis_syn_nr" ]; then
|
||||||
|
echo "[fail] got $count JOIN[s] syn with a mismatched \
|
||||||
|
port-number expected $mis_syn_nr"
|
||||||
|
ret=1
|
||||||
|
dump_stats=1
|
||||||
|
else
|
||||||
|
echo -n "[ ok ]"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n " - ack "
|
||||||
|
count=`ip netns exec $ns1 nstat -as | grep MPTcpExtMismatchPortAckRx |
|
||||||
|
awk '{print $2}'`
|
||||||
|
[ -z "$count" ] && count=0
|
||||||
|
if [ "$count" != "$mis_ack_nr" ]; then
|
||||||
|
echo "[fail] got $count JOIN[s] ack with a mismatched \
|
||||||
|
port-number expected $mis_ack_nr"
|
||||||
|
ret=1
|
||||||
|
dump_stats=1
|
||||||
|
else
|
||||||
|
echo "[ ok ]"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "${dump_stats}" = 1 ]; then
|
if [ "${dump_stats}" = 1 ]; then
|
||||||
|
@ -677,7 +797,7 @@ reset
|
||||||
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
||||||
ip netns exec $ns2 ./pm_nl_ctl limits 0 1
|
ip netns exec $ns2 ./pm_nl_ctl limits 0 1
|
||||||
ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
|
ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
|
||||||
run_tests $ns1 $ns2 10.0.1.1 0 0 1 slow
|
run_tests $ns1 $ns2 10.0.1.1 0 0 -1 slow
|
||||||
chk_join_nr "remove single subflow" 1 1 1
|
chk_join_nr "remove single subflow" 1 1 1
|
||||||
chk_rm_nr 1 1
|
chk_rm_nr 1 1
|
||||||
|
|
||||||
|
@ -687,7 +807,7 @@ ip netns exec $ns1 ./pm_nl_ctl limits 0 2
|
||||||
ip netns exec $ns2 ./pm_nl_ctl limits 0 2
|
ip netns exec $ns2 ./pm_nl_ctl limits 0 2
|
||||||
ip netns exec $ns2 ./pm_nl_ctl add 10.0.2.2 flags subflow
|
ip netns exec $ns2 ./pm_nl_ctl add 10.0.2.2 flags subflow
|
||||||
ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
|
ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
|
||||||
run_tests $ns1 $ns2 10.0.1.1 0 0 2 slow
|
run_tests $ns1 $ns2 10.0.1.1 0 0 -2 slow
|
||||||
chk_join_nr "remove multiple subflows" 2 2 2
|
chk_join_nr "remove multiple subflows" 2 2 2
|
||||||
chk_rm_nr 2 2
|
chk_rm_nr 2 2
|
||||||
|
|
||||||
|
@ -696,7 +816,7 @@ reset
|
||||||
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
||||||
ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
|
ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
|
||||||
ip netns exec $ns2 ./pm_nl_ctl limits 1 1
|
ip netns exec $ns2 ./pm_nl_ctl limits 1 1
|
||||||
run_tests $ns1 $ns2 10.0.1.1 0 1 0 slow
|
run_tests $ns1 $ns2 10.0.1.1 0 -1 0 slow
|
||||||
chk_join_nr "remove single address" 1 1 1
|
chk_join_nr "remove single address" 1 1 1
|
||||||
chk_add_nr 1 1
|
chk_add_nr 1 1
|
||||||
chk_rm_nr 0 0
|
chk_rm_nr 0 0
|
||||||
|
@ -707,7 +827,7 @@ ip netns exec $ns1 ./pm_nl_ctl limits 0 2
|
||||||
ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
|
ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
|
||||||
ip netns exec $ns2 ./pm_nl_ctl limits 1 2
|
ip netns exec $ns2 ./pm_nl_ctl limits 1 2
|
||||||
ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
|
ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
|
||||||
run_tests $ns1 $ns2 10.0.1.1 0 1 1 slow
|
run_tests $ns1 $ns2 10.0.1.1 0 -1 -1 slow
|
||||||
chk_join_nr "remove subflow and signal" 2 2 2
|
chk_join_nr "remove subflow and signal" 2 2 2
|
||||||
chk_add_nr 1 1
|
chk_add_nr 1 1
|
||||||
chk_rm_nr 1 1
|
chk_rm_nr 1 1
|
||||||
|
@ -719,7 +839,7 @@ ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
|
||||||
ip netns exec $ns2 ./pm_nl_ctl limits 1 3
|
ip netns exec $ns2 ./pm_nl_ctl limits 1 3
|
||||||
ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
|
ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
|
||||||
ip netns exec $ns2 ./pm_nl_ctl add 10.0.4.2 flags subflow
|
ip netns exec $ns2 ./pm_nl_ctl add 10.0.4.2 flags subflow
|
||||||
run_tests $ns1 $ns2 10.0.1.1 0 1 2 slow
|
run_tests $ns1 $ns2 10.0.1.1 0 -1 -2 slow
|
||||||
chk_join_nr "remove subflows and signal" 3 3 3
|
chk_join_nr "remove subflows and signal" 3 3 3
|
||||||
chk_add_nr 1 1
|
chk_add_nr 1 1
|
||||||
chk_rm_nr 2 2
|
chk_rm_nr 2 2
|
||||||
|
@ -731,11 +851,48 @@ ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal
|
||||||
ip netns exec $ns2 ./pm_nl_ctl limits 1 3
|
ip netns exec $ns2 ./pm_nl_ctl limits 1 3
|
||||||
ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
|
ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
|
||||||
ip netns exec $ns2 ./pm_nl_ctl add 10.0.4.2 flags subflow
|
ip netns exec $ns2 ./pm_nl_ctl add 10.0.4.2 flags subflow
|
||||||
run_tests $ns1 $ns2 10.0.1.1 0 8 8 slow
|
run_tests $ns1 $ns2 10.0.1.1 0 -8 -8 slow
|
||||||
chk_join_nr "flush subflows and signal" 3 3 3
|
chk_join_nr "flush subflows and signal" 3 3 3
|
||||||
chk_add_nr 1 1
|
chk_add_nr 1 1
|
||||||
chk_rm_nr 2 2
|
chk_rm_nr 2 2
|
||||||
|
|
||||||
|
# add single subflow
|
||||||
|
reset
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
||||||
|
ip netns exec $ns2 ./pm_nl_ctl limits 0 1
|
||||||
|
run_tests $ns1 $ns2 10.0.1.1 0 0 1 slow
|
||||||
|
chk_join_nr "add single subflow" 1 1 1
|
||||||
|
|
||||||
|
# add signal address
|
||||||
|
reset
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
||||||
|
ip netns exec $ns2 ./pm_nl_ctl limits 1 1
|
||||||
|
run_tests $ns1 $ns2 10.0.1.1 0 1 0 slow
|
||||||
|
chk_join_nr "add signal address" 1 1 1
|
||||||
|
chk_add_nr 1 1
|
||||||
|
|
||||||
|
# add multiple subflows
|
||||||
|
reset
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl limits 0 2
|
||||||
|
ip netns exec $ns2 ./pm_nl_ctl limits 0 2
|
||||||
|
run_tests $ns1 $ns2 10.0.1.1 0 0 2 slow
|
||||||
|
chk_join_nr "add multiple subflows" 2 2 2
|
||||||
|
|
||||||
|
# add multiple subflows IPv6
|
||||||
|
reset
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl limits 0 2
|
||||||
|
ip netns exec $ns2 ./pm_nl_ctl limits 0 2
|
||||||
|
run_tests $ns1 $ns2 dead:beef:1::1 0 0 2 slow
|
||||||
|
chk_join_nr "add multiple subflows IPv6" 2 2 2
|
||||||
|
|
||||||
|
# add multiple addresses IPv6
|
||||||
|
reset
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl limits 0 2
|
||||||
|
ip netns exec $ns2 ./pm_nl_ctl limits 2 2
|
||||||
|
run_tests $ns1 $ns2 dead:beef:1::1 0 2 0 slow
|
||||||
|
chk_join_nr "add multiple addresses IPv6" 2 2 2
|
||||||
|
chk_add_nr 2 2
|
||||||
|
|
||||||
# subflow IPv6
|
# subflow IPv6
|
||||||
reset
|
reset
|
||||||
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
||||||
|
@ -774,7 +931,7 @@ reset
|
||||||
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
||||||
ip netns exec $ns1 ./pm_nl_ctl add dead:beef:2::1 flags signal
|
ip netns exec $ns1 ./pm_nl_ctl add dead:beef:2::1 flags signal
|
||||||
ip netns exec $ns2 ./pm_nl_ctl limits 1 1
|
ip netns exec $ns2 ./pm_nl_ctl limits 1 1
|
||||||
run_tests $ns1 $ns2 dead:beef:1::1 0 1 0 slow
|
run_tests $ns1 $ns2 dead:beef:1::1 0 -1 0 slow
|
||||||
chk_join_nr "remove single address IPv6" 1 1 1
|
chk_join_nr "remove single address IPv6" 1 1 1
|
||||||
chk_add_nr 1 1
|
chk_add_nr 1 1
|
||||||
chk_rm_nr 0 0
|
chk_rm_nr 0 0
|
||||||
|
@ -785,7 +942,7 @@ ip netns exec $ns1 ./pm_nl_ctl limits 0 2
|
||||||
ip netns exec $ns1 ./pm_nl_ctl add dead:beef:2::1 flags signal
|
ip netns exec $ns1 ./pm_nl_ctl add dead:beef:2::1 flags signal
|
||||||
ip netns exec $ns2 ./pm_nl_ctl limits 1 2
|
ip netns exec $ns2 ./pm_nl_ctl limits 1 2
|
||||||
ip netns exec $ns2 ./pm_nl_ctl add dead:beef:3::2 flags subflow
|
ip netns exec $ns2 ./pm_nl_ctl add dead:beef:3::2 flags subflow
|
||||||
run_tests $ns1 $ns2 dead:beef:1::1 0 1 1 slow
|
run_tests $ns1 $ns2 dead:beef:1::1 0 -1 -1 slow
|
||||||
chk_join_nr "remove subflow and signal IPv6" 2 2 2
|
chk_join_nr "remove subflow and signal IPv6" 2 2 2
|
||||||
chk_add_nr 1 1
|
chk_add_nr 1 1
|
||||||
chk_rm_nr 1 1
|
chk_rm_nr 1 1
|
||||||
|
@ -884,6 +1041,78 @@ chk_join_nr "single address, backup" 1 1 1
|
||||||
chk_add_nr 1 1
|
chk_add_nr 1 1
|
||||||
chk_prio_nr 1 0
|
chk_prio_nr 1 0
|
||||||
|
|
||||||
|
# signal address with port
|
||||||
|
reset
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
||||||
|
ip netns exec $ns2 ./pm_nl_ctl limits 1 1
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal port 10100
|
||||||
|
run_tests $ns1 $ns2 10.0.1.1
|
||||||
|
chk_join_nr "signal address with port" 1 1 1
|
||||||
|
chk_add_nr 1 1 1
|
||||||
|
|
||||||
|
# subflow and signal with port
|
||||||
|
reset
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal port 10100
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl limits 0 2
|
||||||
|
ip netns exec $ns2 ./pm_nl_ctl limits 1 2
|
||||||
|
ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
|
||||||
|
run_tests $ns1 $ns2 10.0.1.1
|
||||||
|
chk_join_nr "subflow and signal with port" 2 2 2
|
||||||
|
chk_add_nr 1 1 1
|
||||||
|
|
||||||
|
# single address with port, remove
|
||||||
|
reset
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal port 10100
|
||||||
|
ip netns exec $ns2 ./pm_nl_ctl limits 1 1
|
||||||
|
run_tests $ns1 $ns2 10.0.1.1 0 -1 0 slow
|
||||||
|
chk_join_nr "remove single address with port" 1 1 1
|
||||||
|
chk_add_nr 1 1 1
|
||||||
|
chk_rm_nr 0 0
|
||||||
|
|
||||||
|
# subflow and signal with port, remove
|
||||||
|
reset
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl limits 0 2
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal port 10100
|
||||||
|
ip netns exec $ns2 ./pm_nl_ctl limits 1 2
|
||||||
|
ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
|
||||||
|
run_tests $ns1 $ns2 10.0.1.1 0 -1 -1 slow
|
||||||
|
chk_join_nr "remove subflow and signal with port" 2 2 2
|
||||||
|
chk_add_nr 1 1 1
|
||||||
|
chk_rm_nr 1 1
|
||||||
|
|
||||||
|
# subflows and signal with port, flush
|
||||||
|
reset
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl limits 0 3
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal port 10100
|
||||||
|
ip netns exec $ns2 ./pm_nl_ctl limits 1 3
|
||||||
|
ip netns exec $ns2 ./pm_nl_ctl add 10.0.3.2 flags subflow
|
||||||
|
ip netns exec $ns2 ./pm_nl_ctl add 10.0.4.2 flags subflow
|
||||||
|
run_tests $ns1 $ns2 10.0.1.1 0 -8 -8 slow
|
||||||
|
chk_join_nr "flush subflows and signal with port" 3 3 3
|
||||||
|
chk_add_nr 1 1
|
||||||
|
chk_rm_nr 2 2
|
||||||
|
|
||||||
|
# multiple addresses with port
|
||||||
|
reset
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl limits 2 2
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal port 10100
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl add 10.0.3.1 flags signal port 10100
|
||||||
|
ip netns exec $ns2 ./pm_nl_ctl limits 2 2
|
||||||
|
run_tests $ns1 $ns2 10.0.1.1
|
||||||
|
chk_join_nr "multiple addresses with port" 2 2 2
|
||||||
|
chk_add_nr 2 2 2
|
||||||
|
|
||||||
|
# multiple addresses with ports
|
||||||
|
reset
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl limits 2 2
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl add 10.0.2.1 flags signal port 10100
|
||||||
|
ip netns exec $ns1 ./pm_nl_ctl add 10.0.3.1 flags signal port 10101
|
||||||
|
ip netns exec $ns2 ./pm_nl_ctl limits 2 2
|
||||||
|
run_tests $ns1 $ns2 10.0.1.1
|
||||||
|
chk_join_nr "multiple addresses with ports" 2 2 2
|
||||||
|
chk_add_nr 2 2 2
|
||||||
|
|
||||||
# single subflow, syncookies
|
# single subflow, syncookies
|
||||||
reset_with_cookies
|
reset_with_cookies
|
||||||
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
ip netns exec $ns1 ./pm_nl_ctl limits 0 1
|
||||||
|
|
|
@ -177,8 +177,8 @@ int add_addr(int fd, int pm_family, int argc, char *argv[])
|
||||||
1024];
|
1024];
|
||||||
struct rtattr *rta, *nest;
|
struct rtattr *rta, *nest;
|
||||||
struct nlmsghdr *nh;
|
struct nlmsghdr *nh;
|
||||||
|
u_int32_t flags = 0;
|
||||||
u_int16_t family;
|
u_int16_t family;
|
||||||
u_int32_t flags;
|
|
||||||
int nest_start;
|
int nest_start;
|
||||||
u_int8_t id;
|
u_int8_t id;
|
||||||
int off = 0;
|
int off = 0;
|
||||||
|
@ -224,7 +224,6 @@ int add_addr(int fd, int pm_family, int argc, char *argv[])
|
||||||
char *tok, *str;
|
char *tok, *str;
|
||||||
|
|
||||||
/* flags */
|
/* flags */
|
||||||
flags = 0;
|
|
||||||
if (++arg >= argc)
|
if (++arg >= argc)
|
||||||
error(1, 0, " missing flags value");
|
error(1, 0, " missing flags value");
|
||||||
|
|
||||||
|
@ -272,6 +271,20 @@ int add_addr(int fd, int pm_family, int argc, char *argv[])
|
||||||
rta->rta_len = RTA_LENGTH(4);
|
rta->rta_len = RTA_LENGTH(4);
|
||||||
memcpy(RTA_DATA(rta), &ifindex, 4);
|
memcpy(RTA_DATA(rta), &ifindex, 4);
|
||||||
off += NLMSG_ALIGN(rta->rta_len);
|
off += NLMSG_ALIGN(rta->rta_len);
|
||||||
|
} else if (!strcmp(argv[arg], "port")) {
|
||||||
|
u_int16_t port;
|
||||||
|
|
||||||
|
if (++arg >= argc)
|
||||||
|
error(1, 0, " missing port value");
|
||||||
|
if (!(flags & MPTCP_PM_ADDR_FLAG_SIGNAL))
|
||||||
|
error(1, 0, " flags must be signal when using port");
|
||||||
|
|
||||||
|
port = atoi(argv[arg]);
|
||||||
|
rta = (void *)(data + off);
|
||||||
|
rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT;
|
||||||
|
rta->rta_len = RTA_LENGTH(2);
|
||||||
|
memcpy(RTA_DATA(rta), &port, 2);
|
||||||
|
off += NLMSG_ALIGN(rta->rta_len);
|
||||||
} else
|
} else
|
||||||
error(1, 0, "unknown keyword %s", argv[arg]);
|
error(1, 0, "unknown keyword %s", argv[arg]);
|
||||||
}
|
}
|
||||||
|
@ -324,6 +337,7 @@ int del_addr(int fd, int pm_family, int argc, char *argv[])
|
||||||
static void print_addr(struct rtattr *attrs, int len)
|
static void print_addr(struct rtattr *attrs, int len)
|
||||||
{
|
{
|
||||||
uint16_t family = 0;
|
uint16_t family = 0;
|
||||||
|
uint16_t port = 0;
|
||||||
char str[1024];
|
char str[1024];
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
uint8_t id;
|
uint8_t id;
|
||||||
|
@ -331,12 +345,16 @@ static void print_addr(struct rtattr *attrs, int len)
|
||||||
while (RTA_OK(attrs, len)) {
|
while (RTA_OK(attrs, len)) {
|
||||||
if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_FAMILY)
|
if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_FAMILY)
|
||||||
memcpy(&family, RTA_DATA(attrs), 2);
|
memcpy(&family, RTA_DATA(attrs), 2);
|
||||||
|
if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_PORT)
|
||||||
|
memcpy(&port, RTA_DATA(attrs), 2);
|
||||||
if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR4) {
|
if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR4) {
|
||||||
if (family != AF_INET)
|
if (family != AF_INET)
|
||||||
error(1, errno, "wrong IP (v4) for family %d",
|
error(1, errno, "wrong IP (v4) for family %d",
|
||||||
family);
|
family);
|
||||||
inet_ntop(AF_INET, RTA_DATA(attrs), str, sizeof(str));
|
inet_ntop(AF_INET, RTA_DATA(attrs), str, sizeof(str));
|
||||||
printf("%s", str);
|
printf("%s", str);
|
||||||
|
if (port)
|
||||||
|
printf(" %d", port);
|
||||||
}
|
}
|
||||||
if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR6) {
|
if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ADDR6) {
|
||||||
if (family != AF_INET6)
|
if (family != AF_INET6)
|
||||||
|
@ -344,6 +362,8 @@ static void print_addr(struct rtattr *attrs, int len)
|
||||||
family);
|
family);
|
||||||
inet_ntop(AF_INET6, RTA_DATA(attrs), str, sizeof(str));
|
inet_ntop(AF_INET6, RTA_DATA(attrs), str, sizeof(str));
|
||||||
printf("%s", str);
|
printf("%s", str);
|
||||||
|
if (port)
|
||||||
|
printf(" %d", port);
|
||||||
}
|
}
|
||||||
if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ID) {
|
if (attrs->rta_type == MPTCP_PM_ADDR_ATTR_ID) {
|
||||||
memcpy(&id, RTA_DATA(attrs), 1);
|
memcpy(&id, RTA_DATA(attrs), 1);
|
||||||
|
|
Loading…
Reference in a new issue