Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4422cc0d authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'sctp-refactor-MTU-handling'



Marcelo Ricardo Leitner says:

====================
sctp: refactor MTU handling

Currently MTU handling is spread over SCTP stack. There are multiple
places doing same/similar calculations and updating them is error prone
as one spot can easily be left out.

This patchset converges it into a more concise and consistent code. In
general, it moves MTU handling from functions with bigger objectives,
such as sctp_assoc_add_peer(), to specific functions.

It's also a preparation for the next patchset, which removes the
duplication between sctp_make_op_error_space and
sctp_make_op_error_fixed and relies on sctp_mtu_payload introduced here.

More details on each patch.
====================

Reviewed-by: default avatarXin Long <lucien.xin@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5a643c86 38687b56
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -254,11 +254,10 @@ enum { SCTP_ARBITRARY_COOKIE_ECHO_LEN = 200 };
#define SCTP_TSN_MAP_SIZE 4096

/* We will not record more than this many duplicate TSNs between two
 * SACKs.  The minimum PMTU is 576.  Remove all the headers and there
 * is enough room for 131 duplicate reports.  Round down to the
 * SACKs.  The minimum PMTU is 512.  Remove all the headers and there
 * is enough room for 117 duplicate reports.  Round down to the
 * nearest power of 2.
 */
enum { SCTP_MIN_PMTU = 576 };
enum { SCTP_MAX_DUP_TSNS = 16 };
enum { SCTP_MAX_GABS = 16 };

+19 −33
Original line number Diff line number Diff line
@@ -428,32 +428,6 @@ static inline int sctp_list_single_entry(struct list_head *head)
	return (head->next != head) && (head->next == head->prev);
}

/* Break down data chunks at this point.  */
static inline int sctp_frag_point(const struct sctp_association *asoc, int pmtu)
{
	struct sctp_sock *sp = sctp_sk(asoc->base.sk);
	struct sctp_af *af = sp->pf->af;
	int frag = pmtu;

	frag -= af->ip_options_len(asoc->base.sk);
	frag -= af->net_header_len;
	frag -= sizeof(struct sctphdr) + sctp_datachk_len(&asoc->stream);

	if (asoc->user_frag)
		frag = min_t(int, frag, asoc->user_frag);

	frag = SCTP_TRUNC4(min_t(int, frag, SCTP_MAX_CHUNK_LEN -
					    sctp_datachk_len(&asoc->stream)));

	return frag;
}

static inline void sctp_assoc_pending_pmtu(struct sctp_association *asoc)
{
	sctp_assoc_sync_pmtu(asoc);
	asoc->pmtu_pending = 0;
}

static inline bool sctp_chunk_pending(const struct sctp_chunk *chunk)
{
	return !list_empty(&chunk->list);
@@ -607,17 +581,29 @@ static inline struct dst_entry *sctp_transport_dst_check(struct sctp_transport *
	return t->dst;
}

static inline bool sctp_transport_pmtu_check(struct sctp_transport *t)
/* Calculate max payload size given a MTU, or the total overhead if
 * given MTU is zero
 */
static inline __u32 sctp_mtu_payload(const struct sctp_sock *sp,
				     __u32 mtu, __u32 extra)
{
	__u32 pmtu = max_t(size_t, SCTP_TRUNC4(dst_mtu(t->dst)),
			   SCTP_DEFAULT_MINSEGMENT);
	__u32 overhead = sizeof(struct sctphdr) + extra;

	if (t->pathmtu == pmtu)
		return true;
	if (sp)
		overhead += sp->pf->af->net_header_len;
	else
		overhead += sizeof(struct ipv6hdr);

	t->pathmtu = pmtu;
	if (WARN_ON_ONCE(mtu && mtu <= overhead))
		mtu = overhead;

	return false;
	return mtu ? mtu - overhead : overhead;
}

static inline __u32 sctp_dst_mtu(const struct dst_entry *dst)
{
	return SCTP_TRUNC4(max_t(__u32, dst_mtu(dst),
				 SCTP_DEFAULT_MINSEGMENT));
}

#endif /* __net_sctp_h__ */
+2 −0
Original line number Diff line number Diff line
@@ -2097,6 +2097,8 @@ int sctp_assoc_update(struct sctp_association *old,

__u32 sctp_association_get_next_tsn(struct sctp_association *);

void sctp_assoc_update_frag_point(struct sctp_association *asoc);
void sctp_assoc_set_pmtu(struct sctp_association *asoc, __u32 pmtu);
void sctp_assoc_sync_pmtu(struct sctp_association *asoc);
void sctp_assoc_rwnd_increase(struct sctp_association *, unsigned int);
void sctp_assoc_rwnd_decrease(struct sctp_association *, unsigned int);
+32 −28
Original line number Diff line number Diff line
@@ -652,33 +652,20 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
	 */
	peer->param_flags = asoc->param_flags;

	sctp_transport_route(peer, NULL, sp);

	/* Initialize the pmtu of the transport. */
	if (peer->param_flags & SPP_PMTUD_DISABLE) {
		if (asoc->pathmtu)
			peer->pathmtu = asoc->pathmtu;
		else
			peer->pathmtu = SCTP_DEFAULT_MAXSEGMENT;
	}
	sctp_transport_route(peer, NULL, sp);

	/* If this is the first transport addr on this association,
	 * initialize the association PMTU to the peer's PMTU.
	 * If not and the current association PMTU is higher than the new
	 * peer's PMTU, reset the association PMTU to the new peer's PMTU.
	 */
	if (asoc->pathmtu)
		asoc->pathmtu = min_t(int, peer->pathmtu, asoc->pathmtu);
	else
		asoc->pathmtu = peer->pathmtu;

	pr_debug("%s: association:%p PMTU set to %d\n", __func__, asoc,
		 asoc->pathmtu);
	sctp_assoc_set_pmtu(asoc, asoc->pathmtu ?
				  min_t(int, peer->pathmtu, asoc->pathmtu) :
				  peer->pathmtu);

	peer->pmtu_pending = 0;

	asoc->frag_point = sctp_frag_point(asoc, asoc->pathmtu);

	/* The asoc->peer.port might not be meaningful yet, but
	 * initialize the packet structure anyway.
	 */
@@ -1381,6 +1368,31 @@ sctp_assoc_choose_alter_transport(struct sctp_association *asoc,
	}
}

void sctp_assoc_update_frag_point(struct sctp_association *asoc)
{
	int frag = sctp_mtu_payload(sctp_sk(asoc->base.sk), asoc->pathmtu,
				    sctp_datachk_len(&asoc->stream));

	if (asoc->user_frag)
		frag = min_t(int, frag, asoc->user_frag);

	frag = min_t(int, frag, SCTP_MAX_CHUNK_LEN -
				sctp_datachk_len(&asoc->stream));

	asoc->frag_point = SCTP_TRUNC4(frag);
}

void sctp_assoc_set_pmtu(struct sctp_association *asoc, __u32 pmtu)
{
	if (asoc->pathmtu != pmtu) {
		asoc->pathmtu = pmtu;
		sctp_assoc_update_frag_point(asoc);
	}

	pr_debug("%s: asoc:%p, pmtu:%d, frag_point:%d\n", __func__, asoc,
		 asoc->pathmtu, asoc->frag_point);
}

/* Update the association's pmtu and frag_point by going through all the
 * transports. This routine is called when a transport's PMTU has changed.
 */
@@ -1393,24 +1405,16 @@ void sctp_assoc_sync_pmtu(struct sctp_association *asoc)
		return;

	/* Get the lowest pmtu of all the transports. */
	list_for_each_entry(t, &asoc->peer.transport_addr_list,
				transports) {
	list_for_each_entry(t, &asoc->peer.transport_addr_list, transports) {
		if (t->pmtu_pending && t->dst) {
			sctp_transport_update_pmtu(
					t, SCTP_TRUNC4(dst_mtu(t->dst)));
			sctp_transport_update_pmtu(t, sctp_dst_mtu(t->dst));
			t->pmtu_pending = 0;
		}
		if (!pmtu || (t->pathmtu < pmtu))
			pmtu = t->pathmtu;
	}

	if (pmtu) {
		asoc->pathmtu = pmtu;
		asoc->frag_point = sctp_frag_point(asoc, pmtu);
	}

	pr_debug("%s: asoc:%p, pmtu:%d, frag_point:%d\n", __func__, asoc,
		 asoc->pathmtu, asoc->frag_point);
	sctp_assoc_set_pmtu(asoc, pmtu);
}

/* Should we send a SACK to update our peer? */
+1 −11
Original line number Diff line number Diff line
@@ -172,8 +172,6 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
	struct list_head *pos, *temp;
	struct sctp_chunk *chunk;
	struct sctp_datamsg *msg;
	struct sctp_sock *sp;
	struct sctp_af *af;
	int err;

	msg = sctp_datamsg_new(GFP_KERNEL);
@@ -192,12 +190,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
	/* This is the biggest possible DATA chunk that can fit into
	 * the packet
	 */
	sp = sctp_sk(asoc->base.sk);
	af = sp->pf->af;
	max_data = asoc->pathmtu - af->net_header_len -
		   sizeof(struct sctphdr) - sctp_datachk_len(&asoc->stream) -
		   af->ip_options_len(asoc->base.sk);
	max_data = SCTP_TRUNC4(max_data);
	max_data = asoc->frag_point;

	/* If the the peer requested that we authenticate DATA chunks
	 * we need to account for bundling of the AUTH chunks along with
@@ -222,9 +215,6 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
		}
	}

	/* Check what's our max considering the above */
	max_data = min_t(size_t, max_data, asoc->frag_point);

	/* Set first_len and then account for possible bundles on first frag */
	first_len = max_data;

Loading