Skip to content

Commit

Permalink
mptcp: remove addr and subflow in PM netlink
Browse files Browse the repository at this point in the history
This patch implements the remove announced addr and subflow logic in PM
netlink.

When the PM netlink removes an address, we traverse all the existing msk
sockets to find the relevant sockets.

In the traversing, we check if this address is in conn_list. If it is,
we trigger the RM_ADDR signal to remove the remote subflow and remove the
local subflow which using this local address.

Suggested-by: Matthieu Baerts <matthieu.baerts@tessares.net>
Suggested-by: Paolo Abeni <pabeni@redhat.com>
Suggested-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Acked-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Geliang Tang <geliangtang@gmail.com>
  • Loading branch information
geliangtang authored and jenkins-tessares committed Sep 17, 2020
1 parent 9669e16 commit a4b885e
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 11 deletions.
7 changes: 6 additions & 1 deletion net/mptcp/pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ int mptcp_pm_announce_addr(struct mptcp_sock *msk,

int mptcp_pm_remove_addr(struct mptcp_sock *msk, u8 local_id)
{
return -ENOTSUPP;
pr_debug("msk=%p, local_id=%d", msk, local_id);

msk->pm.rm_id = local_id;
WRITE_ONCE(msk->pm.rm_addr_signal, true);
return 0;
}

int mptcp_pm_remove_subflow(struct mptcp_sock *msk, u8 remote_id)
Expand Down Expand Up @@ -231,6 +235,7 @@ void mptcp_pm_data_init(struct mptcp_sock *msk)
msk->pm.status = 0;

spin_lock_init(&msk->pm.lock);
INIT_LIST_HEAD(&msk->pm.anno_list);

mptcp_pm_nl_data_init(msk);
}
Expand Down
122 changes: 116 additions & 6 deletions net/mptcp/pm_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,50 @@ static void check_work_pending(struct mptcp_sock *msk)
WRITE_ONCE(msk->pm.work_pending, false);
}

static bool lookup_anno_list_by_saddr(struct mptcp_sock *msk,
struct mptcp_addr_info *addr)
{
struct mptcp_pm_addr_entry *entry;

list_for_each_entry(entry, &msk->pm.anno_list, list) {
if (addresses_equal(&entry->addr, addr, false))
return true;
}

return false;
}

static bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk,
struct mptcp_pm_addr_entry *entry)
{
struct mptcp_pm_addr_entry *clone = NULL;

if (lookup_anno_list_by_saddr(msk, &entry->addr))
return false;

clone = kmemdup(entry, sizeof(*entry), GFP_ATOMIC);
if (!clone)
return false;

list_add(&clone->list, &msk->pm.anno_list);

return true;
}

void mptcp_pm_free_anno_list(struct mptcp_sock *msk)
{
struct mptcp_pm_addr_entry *entry, *tmp;

pr_debug("msk=%p\n", msk);

spin_lock_bh(&msk->pm.lock);
list_for_each_entry_safe(entry, tmp, &msk->pm.anno_list, list) {
list_del(&entry->list);
kfree(entry);
}
spin_unlock_bh(&msk->pm.lock);
}

static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
{
struct mptcp_addr_info remote = { 0 };
Expand All @@ -197,8 +241,10 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
msk->pm.add_addr_signaled);

if (local) {
msk->pm.add_addr_signaled++;
mptcp_pm_announce_addr(msk, &local->addr, false);
if (mptcp_pm_alloc_anno_list(msk, local)) {
msk->pm.add_addr_signaled++;
mptcp_pm_announce_addr(msk, &local->addr, false);
}
} else {
/* pick failed, avoid fourther attempts later */
msk->pm.local_addr_used = msk->pm.add_addr_signal_max;
Expand Down Expand Up @@ -567,6 +613,68 @@ __lookup_addr_by_id(struct pm_nl_pernet *pernet, unsigned int id)
return NULL;
}

static bool remove_anno_list_by_saddr(struct mptcp_sock *msk,
struct mptcp_addr_info *addr)
{
struct mptcp_pm_addr_entry *entry, *tmp;

list_for_each_entry_safe(entry, tmp, &msk->pm.anno_list, list) {
if (addresses_equal(&entry->addr, addr, false)) {
list_del(&entry->list);
kfree(entry);
return true;
}
}

return false;
}

static bool mptcp_pm_remove_anno_addr(struct mptcp_sock *msk,
struct mptcp_addr_info *addr,
bool force)
{
bool ret;

spin_lock_bh(&msk->pm.lock);
ret = remove_anno_list_by_saddr(msk, addr);
if (ret || force)
mptcp_pm_remove_addr(msk, addr->id);
spin_unlock_bh(&msk->pm.lock);
return ret;
}

static int mptcp_nl_remove_subflow_and_signal_addr(struct net *net,
struct mptcp_addr_info *addr)
{
struct mptcp_sock *msk;
long s_slot = 0, s_num = 0;

pr_debug("remove_id=%d\n", addr->id);

while ((msk = mptcp_token_iter_next(net, &s_slot, &s_num)) != NULL) {
struct sock *sk = (struct sock *)msk;
bool remove_subflow;

if (list_empty(&msk->conn_list)) {
mptcp_pm_remove_anno_addr(msk, addr, false);
goto next;
}

lock_sock(sk);
remove_subflow = lookup_subflow_by_saddr(&msk->conn_list, addr);
mptcp_pm_remove_anno_addr(msk, addr, remove_subflow);
if (remove_subflow)
mptcp_pm_remove_subflow(msk, addr->id);
release_sock(sk);

next:
sock_put(sk);
cond_resched();
}

return 0;
}

static int mptcp_nl_cmd_del_addr(struct sk_buff *skb, struct genl_info *info)
{
struct nlattr *attr = info->attrs[MPTCP_PM_ATTR_ADDR];
Expand All @@ -582,8 +690,8 @@ static int mptcp_nl_cmd_del_addr(struct sk_buff *skb, struct genl_info *info)
entry = __lookup_addr_by_id(pernet, addr.addr.id);
if (!entry) {
GENL_SET_ERR_MSG(info, "address not found");
ret = -EINVAL;
goto out;
spin_unlock_bh(&pernet->lock);
return -EINVAL;
}
if (entry->addr.flags & MPTCP_PM_ADDR_FLAG_SIGNAL)
pernet->add_addr_signal_max--;
Expand All @@ -592,9 +700,11 @@ static int mptcp_nl_cmd_del_addr(struct sk_buff *skb, struct genl_info *info)

pernet->addrs--;
list_del_rcu(&entry->list);
kfree_rcu(entry, rcu);
out:
spin_unlock_bh(&pernet->lock);

mptcp_nl_remove_subflow_and_signal_addr(sock_net(skb->sk), &entry->addr);
kfree_rcu(entry, rcu);

return ret;
}

Expand Down
9 changes: 5 additions & 4 deletions net/mptcp/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -1809,16 +1809,16 @@ static int mptcp_init_sock(struct sock *sk)
struct net *net = sock_net(sk);
int ret;

ret = __mptcp_init_sock(sk);
if (ret)
return ret;

if (!mptcp_is_enabled(net))
return -ENOPROTOOPT;

if (unlikely(!net->mib.mptcp_statistics) && !mptcp_mib_alloc(net))
return -ENOMEM;

ret = __mptcp_init_sock(sk);
if (ret)
return ret;

ret = __mptcp_socket_create(mptcp_sk(sk));
if (ret)
return ret;
Expand Down Expand Up @@ -2136,6 +2136,7 @@ static void mptcp_destroy(struct sock *sk)
if (msk->cached_ext)
__skb_ext_put(msk->cached_ext);

mptcp_pm_free_anno_list(msk);
sk_sockets_allocated_dec(sk);
}

Expand Down
2 changes: 2 additions & 0 deletions net/mptcp/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ enum mptcp_pm_status {
struct mptcp_pm_data {
struct mptcp_addr_info local;
struct mptcp_addr_info remote;
struct list_head anno_list;

spinlock_t lock; /*protects the whole PM data */

Expand Down Expand Up @@ -441,6 +442,7 @@ void mptcp_pm_subflow_closed(struct mptcp_sock *msk, u8 id);
void mptcp_pm_add_addr_received(struct mptcp_sock *msk,
const struct mptcp_addr_info *addr);
void mptcp_pm_rm_addr_received(struct mptcp_sock *msk, u8 rm_id);
void mptcp_pm_free_anno_list(struct mptcp_sock *msk);

int mptcp_pm_announce_addr(struct mptcp_sock *msk,
const struct mptcp_addr_info *addr,
Expand Down
1 change: 1 addition & 0 deletions net/mptcp/subflow.c
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@ static void mptcp_sock_destruct(struct sock *sk)

skb_rbtree_purge(&mptcp_sk(sk)->out_of_order_queue);
mptcp_token_destroy(mptcp_sk(sk));
mptcp_pm_free_anno_list(mptcp_sk(sk));
inet_sock_destruct(sk);
}

Expand Down

0 comments on commit a4b885e

Please sign in to comment.