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

Commit 52ccb8e9 authored by Frank Filz's avatar Frank Filz Committed by David S. Miller
Browse files

[SCTP]: Update SCTP_PEER_ADDR_PARAMS socket option to the latest api draft.



This patch adds support to set/get heartbeat interval, maximum number of
retransmissions, pathmtu, sackdelay time for a particular transport/
association/socket as per the latest SCTP sockets api draft11.

Signed-off-by: default avatarFrank Filz <ffilz@us.ibm.com>
Signed-off-by: default avatarSridhar Samudrala <sri@us.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fd966255
Loading
Loading
Loading
Loading
+56 −20
Original line number Diff line number Diff line
@@ -277,6 +277,24 @@ struct sctp_sock {
	__u32 default_context;
	__u32 default_timetolive;

	/* Heartbeat interval: The endpoint sends out a Heartbeat chunk to
	 * the destination address every heartbeat interval. This value
	 * will be inherited by all new associations.
	 */
	__u32 hbinterval;

	/* This is the max_retrans value for new associations. */
	__u16 pathmaxrxt;

	/* The initial Path MTU to use for new associations. */
	__u32 pathmtu;

	/* The default SACK delay timeout for new associations. */
	__u32 sackdelay;

	/* Flags controling Heartbeat, SACK delay, and Path MTU Discovery. */
	__u32 param_flags;

	struct sctp_initmsg initmsg;
	struct sctp_rtoinfo rtoinfo;
	struct sctp_paddrparams paddrparam;
@@ -845,9 +863,6 @@ struct sctp_transport {
	/* Data that has been sent, but not acknowledged. */
	__u32 flight_size;

	/* PMTU	      : The current known path MTU.  */
	__u32 pmtu;

	/* Destination */
	struct dst_entry *dst;
	/* Source address. */
@@ -862,7 +877,22 @@ struct sctp_transport {
	/* Heartbeat interval: The endpoint sends out a Heartbeat chunk to
	 * the destination address every heartbeat interval.
	 */
	int hb_interval;
	__u32 hbinterval;

	/* This is the max_retrans value for the transport and will
	 * be initialized from the assocs value.  This can be changed
	 * using SCTP_SET_PEER_ADDR_PARAMS socket option.
	 */
	__u16 pathmaxrxt;

	/* PMTU	      : The current known path MTU.  */
	__u32 pathmtu;

	/* SACK delay timeout */
	__u32 sackdelay;

	/* Flags controling Heartbeat, SACK delay, and Path MTU Discovery. */
	__u32 param_flags;

	/* When was the last time (in jiffies) that we heard from this
	 * transport?  We use this to pick new active and retran paths.
@@ -882,22 +912,11 @@ struct sctp_transport {
	 */
	int state;

	/* hb_allowed  : The current heartbeat state of this destination,
	 *	       :  i.e. ALLOW-HB, NO-HEARTBEAT, etc.
	 */
	int hb_allowed;

	/* These are the error stats for this destination.  */

	/* Error count : The current error count for this destination.	*/
	unsigned short error_count;

	/* This is the max_retrans value for the transport and will
	 * be initialized to proto.max_retrans.path.  This can be changed
	 * using SCTP_SET_PEER_ADDR_PARAMS socket option.
	 */
	int max_retrans;

	/* Per	       : A timer used by each destination.
	 * Destination :
	 * Timer       :
@@ -1502,6 +1521,28 @@ struct sctp_association {
	/* The largest timeout or RTO value to use in attempting an INIT */
	__u16 max_init_timeo;

	/* Heartbeat interval: The endpoint sends out a Heartbeat chunk to
	 * the destination address every heartbeat interval. This value
	 * will be inherited by all new transports.
	 */
	__u32 hbinterval;

	/* This is the max_retrans value for new transports in the
	 * association.
	 */
	__u16 pathmaxrxt;

	/* Association : The smallest PMTU discovered for all of the
	 * PMTU	       : peer's transport addresses.
	 */
	__u32 pathmtu;

	/* SACK delay timeout */
	__u32 sackdelay;

	/* Flags controling Heartbeat, SACK delay, and Path MTU Discovery. */
	__u32 param_flags;

	int timeouts[SCTP_NUM_TIMEOUT_TYPES];
	struct timer_list timers[SCTP_NUM_TIMEOUT_TYPES];

@@ -1571,11 +1612,6 @@ struct sctp_association {
	 */
	wait_queue_head_t	wait;

	/* Association : The smallest PMTU discovered for all of the
	 * PMTU	       : peer's transport addresses.
	 */
	__u32 pmtu;

	/* The message size at which SCTP fragmentation will occur. */
	__u32 frag_point;

+16 −0
Original line number Diff line number Diff line
@@ -503,11 +503,27 @@ struct sctp_setadaption {
 *   unreachable. The following structure is used to access and modify an
 *   address's parameters:
 */
enum  sctp_spp_flags {
	SPP_HB_ENABLE = 1,		/*Enable heartbeats*/
	SPP_HB_DISABLE = 2,		/*Disable heartbeats*/
	SPP_HB = SPP_HB_ENABLE | SPP_HB_DISABLE,
	SPP_HB_DEMAND = 4,		/*Send heartbeat immediately*/
	SPP_PMTUD_ENABLE = 8,		/*Enable PMTU discovery*/
	SPP_PMTUD_DISABLE = 16,		/*Disable PMTU discovery*/
	SPP_PMTUD = SPP_PMTUD_ENABLE | SPP_PMTUD_DISABLE,
	SPP_SACKDELAY_ENABLE = 32,	/*Enable SACK*/
	SPP_SACKDELAY_DISABLE = 64,	/*Disable SACK*/
	SPP_SACKDELAY = SPP_SACKDELAY_ENABLE | SPP_SACKDELAY_DISABLE,
};

struct sctp_paddrparams {
	sctp_assoc_t		spp_assoc_id;
	struct sockaddr_storage	spp_address;
	__u32			spp_hbinterval;
	__u16			spp_pathmaxrxt;
	__u32			spp_pathmtu;
	__u32			spp_sackdelay;
	__u32			spp_flags;
} __attribute__((packed, aligned(4)));

/*
+55 −26
Original line number Diff line number Diff line
@@ -110,7 +110,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
	asoc->cookie_life.tv_sec = sp->assocparams.sasoc_cookie_life / 1000;
	asoc->cookie_life.tv_usec = (sp->assocparams.sasoc_cookie_life % 1000)
					* 1000;
	asoc->pmtu = 0;
	asoc->frag_point = 0;

	/* Set the association max_retrans and RTO values from the
@@ -123,6 +122,25 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a

	asoc->overall_error_count = 0;

	/* Initialize the association's heartbeat interval based on the
	 * sock configured value.
	 */
	asoc->hbinterval = msecs_to_jiffies(sp->hbinterval);

	/* Initialize path max retrans value. */
	asoc->pathmaxrxt = sp->pathmaxrxt;

	/* Initialize default path MTU. */
	asoc->pathmtu = sp->pathmtu;

	/* Set association default SACK delay */
	asoc->sackdelay = msecs_to_jiffies(sp->sackdelay);

	/* Set the association default flags controlling
	 * Heartbeat, SACK delay, and Path MTU Discovery.
	 */
	asoc->param_flags = sp->param_flags;

	/* Initialize the maximum mumber of new data packets that can be sent
	 * in a burst.
	 */
@@ -144,8 +162,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
		= 5 * asoc->rto_max;

	asoc->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = 0;
	asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] =
		SCTP_DEFAULT_TIMEOUT_SACK;
	asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = asoc->sackdelay;
	asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] =
		sp->autoclose * HZ;
	
@@ -540,23 +557,46 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,

	sctp_transport_set_owner(peer, asoc);

	/* Initialize the peer's heartbeat interval based on the
	 * association configured value.
	 */
	peer->hbinterval = asoc->hbinterval;

	/* Set the path max_retrans.  */
	peer->pathmaxrxt = asoc->pathmaxrxt;

	/* Initialize the peer's SACK delay timeout based on the
	 * association configured value.
	 */
	peer->sackdelay = asoc->sackdelay;

	/* Enable/disable heartbeat, SACK delay, and path MTU discovery
	 * based on association setting.
	 */
	peer->param_flags = asoc->param_flags;

	/* Initialize the pmtu of the transport. */
	if (peer->param_flags & SPP_PMTUD_ENABLE)
		sctp_transport_pmtu(peer);
	else if (asoc->pathmtu)
		peer->pathmtu = asoc->pathmtu;
	else
		peer->pathmtu = SCTP_DEFAULT_MAXSEGMENT;

	/* 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->pmtu)
		asoc->pmtu = min_t(int, peer->pmtu, asoc->pmtu);
	if (asoc->pathmtu)
		asoc->pathmtu = min_t(int, peer->pathmtu, asoc->pathmtu);
	else
		asoc->pmtu = peer->pmtu;
		asoc->pathmtu = peer->pathmtu;

	SCTP_DEBUG_PRINTK("sctp_assoc_add_peer:association %p PMTU set to "
			  "%d\n", asoc, asoc->pmtu);
			  "%d\n", asoc, asoc->pathmtu);

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

	/* The asoc->peer.port might not be meaningful yet, but
	 * initialize the packet structure anyway.
@@ -574,7 +614,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
	 *   (for example, implementations MAY use the size of the
	 *   receiver advertised window).
	 */
	peer->cwnd = min(4*asoc->pmtu, max_t(__u32, 2*asoc->pmtu, 4380));
	peer->cwnd = min(4*asoc->pathmtu, max_t(__u32, 2*asoc->pathmtu, 4380));

	/* At this point, we may not have the receiver's advertised window,
	 * so initialize ssthresh to the default value and it will be set
@@ -585,17 +625,6 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
	peer->partial_bytes_acked = 0;
	peer->flight_size = 0;

	/* By default, enable heartbeat for peer address. */
	peer->hb_allowed = 1;

	/* Initialize the peer's heartbeat interval based on the
	 * sock configured value.
	 */
	peer->hb_interval = msecs_to_jiffies(sp->paddrparam.spp_hbinterval);

	/* Set the path max_retrans.  */
	peer->max_retrans = sp->paddrparam.spp_pathmaxrxt;

	/* Set the transport's RTO.initial value */
	peer->rto = asoc->rto_initial;

@@ -1155,18 +1184,18 @@ void sctp_assoc_sync_pmtu(struct sctp_association *asoc)
	/* Get the lowest pmtu of all the transports. */
	list_for_each(pos, &asoc->peer.transport_addr_list) {
		t = list_entry(pos, struct sctp_transport, transports);
		if (!pmtu || (t->pmtu < pmtu))
			pmtu = t->pmtu;
		if (!pmtu || (t->pathmtu < pmtu))
			pmtu = t->pathmtu;
	}

	if (pmtu) {
		struct sctp_sock *sp = sctp_sk(asoc->base.sk);
		asoc->pmtu = pmtu;
		asoc->pathmtu = pmtu;
		asoc->frag_point = sctp_frag_point(sp, pmtu);
	}

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

/* Should we send a SACK to update our peer? */
@@ -1179,7 +1208,7 @@ static inline int sctp_peer_needs_update(struct sctp_association *asoc)
	case SCTP_STATE_SHUTDOWN_SENT:
		if ((asoc->rwnd > asoc->a_rwnd) &&
		    ((asoc->rwnd - asoc->a_rwnd) >=
		     min_t(__u32, (asoc->base.sk->sk_rcvbuf >> 1), asoc->pmtu)))
		     min_t(__u32, (asoc->base.sk->sk_rcvbuf >> 1), asoc->pathmtu)))
			return 1;
		break;
	default:
+27 −9
Original line number Diff line number Diff line
@@ -305,18 +305,36 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,
			   struct sctp_transport *t, __u32 pmtu)
{
	if (sock_owned_by_user(sk) || !t || (t->pathmtu == pmtu))
		return;

	if (t->param_flags & SPP_PMTUD_ENABLE) {
		if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) {
			printk(KERN_WARNING "%s: Reported pmtu %d too low, "
		       "using default minimum of %d\n", __FUNCTION__, pmtu,
			       "using default minimum of %d\n",
			       __FUNCTION__, pmtu,
			       SCTP_DEFAULT_MINSEGMENT);
		pmtu = SCTP_DEFAULT_MINSEGMENT;
			/* Use default minimum segment size and disable
			 * pmtu discovery on this transport.
			 */
			t->pathmtu = SCTP_DEFAULT_MINSEGMENT;
			t->param_flags = (t->param_flags & ~SPP_HB) |
				SPP_PMTUD_DISABLE;
		} else {
			t->pathmtu = pmtu;
		}

	if (!sock_owned_by_user(sk) && t && (t->pmtu != pmtu)) {
		t->pmtu = pmtu;
		/* Update association pmtu. */
		sctp_assoc_sync_pmtu(asoc);
		sctp_retransmit(&asoc->outqueue, t, SCTP_RTXR_PMTUD);
	}

	/* Retransmit with the new pmtu setting.
	 * Normally, if PMTU discovery is disabled, an ICMP Fragmentation
	 * Needed will never be sent, but if a message was sent before
	 * PMTU discovery was disabled that was larger than the PMTU, it
	 * would not be fragmented, so it must be re-transmitted fragmented.	 
	 */
	sctp_retransmit(&asoc->outqueue, t, SCTP_RTXR_PMTUD);
}

/*
+11 −6
Original line number Diff line number Diff line
@@ -234,8 +234,8 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
		goto finish;

	pmtu  = ((packet->transport->asoc) ?
		 (packet->transport->asoc->pmtu) :
		 (packet->transport->pmtu));
		 (packet->transport->asoc->pathmtu) :
		 (packet->transport->pathmtu));

	too_big = (psize + chunk_len > pmtu);

@@ -482,8 +482,10 @@ int sctp_packet_transmit(struct sctp_packet *packet)
	if (!dst || (dst->obsolete > 1)) {
		dst_release(dst);
		sctp_transport_route(tp, NULL, sctp_sk(sk));
		if (asoc->param_flags & SPP_PMTUD_ENABLE) {
			sctp_assoc_sync_pmtu(asoc);
		}
	}

	nskb->dst = dst_clone(tp->dst);
	if (!nskb->dst)
@@ -492,7 +494,10 @@ int sctp_packet_transmit(struct sctp_packet *packet)
	SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb len %d\n",
			  nskb->len);

	if (tp->param_flags & SPP_PMTUD_ENABLE)
		(*tp->af_specific->sctp_xmit)(nskb, tp, packet->ipfragok);
	else
		(*tp->af_specific->sctp_xmit)(nskb, tp, 1);

out:
	packet->size = packet->overhead;
@@ -577,7 +582,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
	 * 	if ((flightsize + Max.Burst * MTU) < cwnd)
	 *		cwnd = flightsize + Max.Burst * MTU
	 */
	max_burst_bytes = asoc->max_burst * asoc->pmtu;
	max_burst_bytes = asoc->max_burst * asoc->pathmtu;
	if ((transport->flight_size + max_burst_bytes) < transport->cwnd) {
		transport->cwnd = transport->flight_size + max_burst_bytes;
		SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: "
@@ -622,7 +627,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
		 * data will fit or delay in hopes of bundling a full
		 * sized packet.
		 */
		if (len < asoc->pmtu - packet->overhead) {
		if (len < asoc->pathmtu - packet->overhead) {
			retval = SCTP_XMIT_NAGLE_DELAY;
			goto finish;
		}
Loading