mctp: Implement message fragmentation & reassembly

This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.

The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment.  Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.

In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.

For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.

Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Jeremy Kerr
2021-07-29 10:20:50 +08:00
committed by David S. Miller
parent 833ef3b91d
commit 4a992bbd36
3 changed files with 363 additions and 46 deletions

View File

@@ -84,9 +84,21 @@ struct mctp_sock {
* updates to either list are performed under the netns_mctp->keys
* lock.
*
* - there is a single destruction path for a mctp_sk_key - through socket
* unhash (see mctp_sk_unhash). This performs the list removal under
* keys_lock.
* - a key may have a sk_buff attached as part of an in-progress message
* reassembly (->reasm_head). The reassembly context is protected by
* reasm_lock, which may be acquired with the keys lock (above) held, if
* necessary. Consequently, keys lock *cannot* be acquired with the
* reasm_lock held.
*
* - there are two destruction paths for a mctp_sk_key:
*
* - through socket unhash (see mctp_sk_unhash). This performs the list
* removal under keys_lock.
*
* - where a key is established to receive a reply message: after receiving
* the (complete) reply, or during reassembly errors. Here, we clean up
* the reassembly context (marking reasm_dead, to prevent another from
* starting), and remove the socket from the netns & socket lists.
*/
struct mctp_sk_key {
mctp_eid_t peer_addr;
@@ -102,6 +114,13 @@ struct mctp_sk_key {
/* per-socket list */
struct hlist_node sklist;
/* incoming fragment reassembly context */
spinlock_t reasm_lock;
struct sk_buff *reasm_head;
struct sk_buff **reasm_tailp;
bool reasm_dead;
u8 last_seq;
struct rcu_head rcu;
};