mptcp: remove addr and subflow in PM netlink

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.

We add a new list named anno_list in mptcp_pm_data, to record all the
announced addrs. In the traversing, we check if it has been recorded.
If it has been, we trigger the RM_ADDR signal.

We also check if this address is in conn_list. If it is, we remove the
subflow which using this local address.

Since we call mptcp_pm_free_anno_list in mptcp_destroy, we need to move
__mptcp_init_sock before the mptcp_is_enabled check in mptcp_init_sock.

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>
Reviewed-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Geliang Tang 2020-09-24 08:29:54 +08:00 коммит произвёл David S. Miller
Родитель f58f065aa1
Коммит b6c0838086
5 изменённых файлов: 130 добавлений и 11 удалений

Просмотреть файл

@ -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)
@ -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);
}

Просмотреть файл

@ -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", 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 };
@ -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;
@ -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", 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];
@ -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--;
@ -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;
}

Просмотреть файл

@ -1810,16 +1810,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;
@ -2137,6 +2137,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);
}

Просмотреть файл

@ -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 */
@ -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,

Просмотреть файл

@ -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);
}