Skip to content

Commit

Permalink
mptcp: add netlink event support
Browse files Browse the repository at this point in the history
Allow userspace (mptcpd) to subscribe to mptcp genl multicast events.
This implementation reuses the same event API as the mptcp kernel fork
to ease integration of existing tools, e.g. mptcpd.

Supported events include:
1. start and close of an mptcp connection
2. start and close of subflows (joins)
3. announce and withdrawals of addresses
4. subflow priority (backup/non-backup) change.

Reviewed-by: Matthieu Baerts <[email protected]>
Reviewed-by: Mat Martineau <[email protected]>
Signed-off-by: Florian Westphal <[email protected]>
  • Loading branch information
Florian Westphal authored and jenkins-tessares committed Feb 2, 2021
1 parent cf6cac4 commit 6399d64
Show file tree
Hide file tree
Showing 5 changed files with 363 additions and 7 deletions.
74 changes: 74 additions & 0 deletions include/uapi/linux/mptcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ enum {
/* netlink interface */
#define MPTCP_PM_NAME "mptcp_pm"
#define MPTCP_PM_CMD_GRP_NAME "mptcp_pm_cmds"
#define MPTCP_PM_EV_GRP_NAME "mptcp_pm_events"
#define MPTCP_PM_VER 0x1

/*
Expand Down Expand Up @@ -104,4 +105,77 @@ struct mptcp_info {
__u64 mptcpi_rcv_nxt;
};

/*
* MPTCP_EVENT_CREATED: token, family, saddr4 | saddr6, daddr4 | daddr6,
* sport, dport
* A new MPTCP connection has been created. It is the good time to allocate
* memory and send ADD_ADDR if needed. Depending on the traffic-patterns
* it can take a long time until the MPTCP_EVENT_ESTABLISHED is sent.
*
* MPTCP_EVENT_ESTABLISHED: token, family, saddr4 | saddr6, daddr4 | daddr6,
* sport, dport
* A MPTCP connection is established (can start new subflows).
*
* MPTCP_EVENT_CLOSED: token
* A MPTCP connection has stopped.
*
* MPTCP_EVENT_ANNOUNCED: token, rem_id, family, daddr4 | daddr6 [, dport]
* A new address has been announced by the peer.
*
* MPTCP_EVENT_REMOVED: token, rem_id
* An address has been lost by the peer.
*
* MPTCP_EVENT_SUB_ESTABLISHED: token, family, saddr4 | saddr6,
* daddr4 | daddr6, sport, dport, backup,
* if_idx [, error]
* A new subflow has been established. 'error' should not be set.
*
* MPTCP_EVENT_SUB_CLOSED: token, family, saddr4 | saddr6, daddr4 | daddr6,
* sport, dport, backup, if_idx [, error]
* A subflow has been closed. An error (copy of sk_err) could be set if an
* error has been detected for this subflow.
*
* MPTCP_EVENT_SUB_PRIORITY: token, family, saddr4 | saddr6, daddr4 | daddr6,
* sport, dport, backup, if_idx [, error]
* The priority of a subflow has changed. 'error' should not be set.
*/
enum mptcp_event_type {
MPTCP_EVENT_UNSPEC = 0,
MPTCP_EVENT_CREATED = 1,
MPTCP_EVENT_ESTABLISHED = 2,
MPTCP_EVENT_CLOSED = 3,

MPTCP_EVENT_ANNOUNCED = 6,
MPTCP_EVENT_REMOVED = 7,

MPTCP_EVENT_SUB_ESTABLISHED = 10,
MPTCP_EVENT_SUB_CLOSED = 11,

MPTCP_EVENT_SUB_PRIORITY = 13,
};

enum mptcp_event_attr {
MPTCP_ATTR_UNSPEC = 0,

MPTCP_ATTR_TOKEN, /* u32 */
MPTCP_ATTR_FAMILY, /* u16 */
MPTCP_ATTR_LOC_ID, /* u8 */
MPTCP_ATTR_REM_ID, /* u8 */
MPTCP_ATTR_SADDR4, /* be32 */
MPTCP_ATTR_SADDR6, /* struct in6_addr */
MPTCP_ATTR_DADDR4, /* be32 */
MPTCP_ATTR_DADDR6, /* struct in6_addr */
MPTCP_ATTR_SPORT, /* be16 */
MPTCP_ATTR_DPORT, /* be16 */
MPTCP_ATTR_BACKUP, /* u8 */
MPTCP_ATTR_ERROR, /* u8 */
MPTCP_ATTR_FLAGS, /* u16 */
MPTCP_ATTR_TIMEOUT, /* u32 */
MPTCP_ATTR_IF_IDX, /* s32 */

__MPTCP_ATTR_AFTER_LAST
};

#define MPTCP_ATTR_MAX (__MPTCP_ATTR_AFTER_LAST - 1)

#endif /* _UAPI_MPTCP_H */
20 changes: 15 additions & 5 deletions net/mptcp/pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ void mptcp_pm_new_connection(struct mptcp_sock *msk, const struct sock *ssk, int
pr_debug("msk=%p, token=%u side=%d", msk, msk->token, server_side);

WRITE_ONCE(pm->server_side, server_side);
mptcp_event(MPTCP_EVENT_CREATED, msk, ssk, GFP_ATOMIC);
}

bool mptcp_pm_allow_new_subflow(struct mptcp_sock *msk)
Expand Down Expand Up @@ -122,13 +123,10 @@ static bool mptcp_pm_schedule_work(struct mptcp_sock *msk,
void mptcp_pm_fully_established(struct mptcp_sock *msk, const struct sock *ssk, gfp_t gfp)
{
struct mptcp_pm_data *pm = &msk->pm;
bool announce = false;

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

/* try to avoid acquiring the lock below */
if (!READ_ONCE(pm->work_pending))
return;

spin_lock_bh(&pm->lock);

/* mptcp_pm_fully_established() can be invoked by multiple
Expand All @@ -138,9 +136,15 @@ void mptcp_pm_fully_established(struct mptcp_sock *msk, const struct sock *ssk,
if (READ_ONCE(pm->work_pending) &&
!(msk->pm.status & BIT(MPTCP_PM_ALREADY_ESTABLISHED)))
mptcp_pm_schedule_work(msk, MPTCP_PM_ESTABLISHED);
msk->pm.status |= BIT(MPTCP_PM_ALREADY_ESTABLISHED);

if ((msk->pm.status & BIT(MPTCP_PM_ALREADY_ESTABLISHED)) == 0)
announce = true;

msk->pm.status |= BIT(MPTCP_PM_ALREADY_ESTABLISHED);
spin_unlock_bh(&pm->lock);

if (announce)
mptcp_event(MPTCP_EVENT_ESTABLISHED, msk, ssk, gfp);
}

void mptcp_pm_connection_closed(struct mptcp_sock *msk)
Expand Down Expand Up @@ -179,6 +183,8 @@ void mptcp_pm_add_addr_received(struct mptcp_sock *msk,
pr_debug("msk=%p remote_id=%d accept=%d", msk, addr->id,
READ_ONCE(pm->accept_addr));

mptcp_event_addr_announced(msk, addr);

spin_lock_bh(&pm->lock);

if (!READ_ONCE(pm->accept_addr)) {
Expand All @@ -205,6 +211,8 @@ void mptcp_pm_rm_addr_received(struct mptcp_sock *msk, u8 rm_id)

pr_debug("msk=%p remote_id=%d", msk, rm_id);

mptcp_event_addr_removed(msk, rm_id);

spin_lock_bh(&pm->lock);
mptcp_pm_schedule_work(msk, MPTCP_PM_RM_ADDR_RECEIVED);
pm->rm_id = rm_id;
Expand All @@ -217,6 +225,8 @@ void mptcp_pm_mp_prio_received(struct sock *sk, u8 bkup)

pr_debug("subflow->backup=%d, bkup=%d\n", subflow->backup, bkup);
subflow->backup = bkup;

mptcp_event(MPTCP_EVENT_SUB_PRIORITY, mptcp_sk(subflow->conn), sk, GFP_ATOMIC);
}

/* path manager helpers */
Expand Down
Loading

0 comments on commit 6399d64

Please sign in to comment.