Re: [PATCH] lksctp: replace sinfo_timetolive with sinfo_pr_value.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Based on comments from Vlad I have prepared a new patch to replace
sinfo_timetolive with the newer sinfo_pr_policy and sinfo_pr_value
fields.

On Wed, Dec 24, 2008 at 1:31 AM, Vlad Yasevich
<vladislav.yasevich@xxxxxx> wrote:
> Horacio Sanson wrote:
>>>> These values, except for SCTP_EOF, are exactly the same values used in
>>>> the FreeBSD implementation. This scheme allows the lower byte to be
>>>> used for sctp_sinfo_pr_policy values.
>>>>
>>>> I modified all these flags so they coincide with FreeBSD
>>>> implementation that is also the same code base used for MacOSX and
>>>> Windows implementations to avoid any incompatibilities between
>>>> implementations. At least sinfo_pr_policy is transported between peers
>>>> in an association and having standard values is a good idea.
>>> Buy you don't use it as such.  You have a separate __u16 defined.to carry
>>> pr_policy.  So before we had a structure:
>>>
>>> struct sctp_sndrcvinfo {
>>>        __u16 sinfo_stream;
>>>        __u16 sinfo_ssn;
>>>        __u16 sinfo_flags;
>>>                             <---- 16bit memory hole
>>>        __u32 sinfo_ppid;
>>>        __u32 sinfo_context;
>>>        __u32 sinfo_timetolive;
>>>        __u32 sinfo_tsn;
>>>        __u32 sinfo_cumtsn;
>>>        sctp_assoc_t sinfo_assoc_id;
>>> };
>>>
>>> and now we have a structure
>>> struct sctp_sndrcvinfo {
>>>        __u16 sinfo_stream;
>>>        __u16 sinfo_ssn;
>>>        __u16 sinfo_flags;
>>>        __u16 sinfo_pr_policy;      <---- hole filled
>>>        __u32 sinfo_ppid;
>>>        __u32 sinfo_context;
>>>        __u32 sinfo_pr_value;
>>>        __u32 sinfo_tsn;
>>>        __u32 sinfo_cumtsn;
>>>        sctp_assoc_t sinfo_assoc_id;
>>> };
>>>
>>> So, I am trying to find the reason for shifting the flags.  Also, this shift
>>> would require all the application to recompile since they would suddenly start
>>> providing wrong flag values to the kernel (broken ABI).
>>>
>>
>> The idea of the shift, and this is how is done in FreeBSD, is to allow
>> both sinfo_flags and sinfo_pr_policy flags to be specified when using
>> the sctp_sendmsg() call. For example this would allow a call like:
>>
>>    sctp_sendmsg(sock,
>>                 msg, msglen,
>>                 toaddr, tolen,
>>                 0,
>>                 SCTP_UNORDERED|SCTP_PR_SCTP_TTL,  // <-- sinfo_flags
>> and sinfo_pr_policy
>>                 0, 3000, 0);
>>
>> The latest socket api draft does not mention the sinfo_pr_policy flags
>> as possible values for the flags argument in sctp_sendmsg() but I
>> believe this is a mistake as it makes no sense to allow users to
>> specify a pr_value but give no way to specify the corresponding
>> pr_policy in the same call. So even if the socket api draft states
>> that sinfo_flags and sinfo_pr_policy are separate fields in the
>> sctp_sndrcvinfo struct, there is a reason to have their values shifted
>> so they can be combined in a single integer variable.
>>
>
> Ok, so you don't really need to shift this.  You simply need to define
> the partial reliability policy as flags so they can be passed sctp_sendmsg().
>
> This is a problem with retrofitting the existing api that I'll bring up.
>
>>
>> To avoid breaking the ABI what would be a good approach?? I though
>> maybe doing this:
>>
>> enum sctp_sinfo_flags {
>>  SCTP_UNORDERED = 1,         /* Send/receive message unordered. */
>>  SCTP_ADDR_OVER = 2,         /* Override the primary destination. */
>>  SCTP_ABORT     = 4,         /* Send an ABORT message to the peer. */
>>  SCTP_PR_NONE   = 8,         /* Reliable transmission */
>>  SCTP_PR_TTL    = 16,        /* Timed partial reliability */
>>  SCTP_EOF       = MSG_FIN,   /* Initiate graceful shutdown process. (0x0200) */
>> };
>>
>> /* this for draft compatibility */
>> #define SCTP_PR_SCTP_NONE   SCTP_PR_NONE
>> #define SCTP_PR_SCTP_TTL    SCTP_PR_TTL
>>
>>
>> But allowing the SCTP_PR_* flags to coexist in the same integer is not
>> a good idea because these flags are exclusive.... if for some reason
>> the user provides both SCTP_PR_NONE and SCTP_PR_TTL at the same time
>> what should the implementation interpret? this is not addressed in the
>> draft either. The other option would be to reserve the higher 16bits
>> for PR policy flags and the lower 16bits for sinfo_flags:
>>
>
> The spec doesn't address at all the ability to pass pr policy values to sctp_sendmsg().
>

In the end I opted to use this approach of adding the SCTP_PR_SCTP_*
constants to the sinfo_flags enum. Using the upper 16 bits causes
a lot of trouble when splitting and converting it to a 16bit value
needed to fit in the sinfo_pr_policy field.

>
>> enum sctp_sinfo_flags {
>> ^ISCTP_UNORDERED = 1,         /* Send/receive message unordered. */
>> ^ISCTP_ADDR_OVER = 2,         /* Overrde the primary destination. */
>> ^ISCTP_ABORT     = 4,         /* Send an ABORT message to the peer. */
>> ^ISCTP_EOF       = MSG_FIN,   /* Initiate graceful shutdown process. (0x0200) */
>> ^ISCTP_PR_NONE   = 0x010000,  /* Reliable transmission */
>> ^ISCTP_PR_TTL    = 0x020000,  /* Timed partial reliability */
>> };
>>
>> but this assumes that integers are always 32bits long and I am not
>> sure this is a good assumption to take.
>
> This is safe because the flags argument to sctp_sendmsg() is defined as uint32_t and
> you are guaranteed to have 32 bits there.
>
> Also, notice that this split will need to be taken care of in libsctp, since that is
> where sctp_sendmsg() is defined.  That function will have to split the flags into
> sinfo_flags and sinfo_pr_policy.  This means that we'll need a 2 ways define policy:
> as a flag, and as a direct policy.
>
> The kernel doesn't need to know anything about the split and can treat the 'flag' policy
> values as errors.
>
> I think BSD shifted the flags so that it could get way without dual definitions, but they
> broke the ABI by doing so.  I don't know how they could get away with that.
>
>>
>
>>>> I need the ability to set sinfo_pr_policy to SCTP_PR_SCTP_TTL and
>>>> sinfo_pr_value equal to zero as a way to enable a completely
>>>> unreliable service (i.e. no retransmissions at all), similar to UDP
>>>> but with congestion control (maybe DCCP emulation??).
>>> OK.  So you need to have a default case, where the expires_policy is
>>> junk and in that case you verify pr_value before setting msg->expires_policy.
>>>
>>> In essence, you need to cover the case of user using the new structure as
>>> well as using an old structure that had a memory hole.
>>>
>>
>>
>>
>>>> I believe this functionality added to unordered delivery can be useful
>>>> for several applications and allows SCTP to cover all the reliability
>>>> spectrum from ordered reliable, ordered unreliable, unordered
>>>> reliable, unordered unreliable, ordered partial reliable and unordered
>>>> partial reliable.
>>>>
>>>> Another alternative would be to define a new partial reliability
>>>> profile, something like SCTP_PR_SCTP_UNR, that forces sinfo_pr_value
>>>> to zero and never retransmits.
>>> I think what you are looking for a retransmit policy (SCTP_PR_RTX) with the
>>> number of retransmits set 0.  You don't want to do this as a timer policy with
>>> a timeout of 0 milliseconds, because you may end up discarding packets
>>> as fast as your app can generate them and never send anything.
>>>
>>
>> I have this SCTP_PR_RTX functionality already implemented as a
>> separate patch. Once my first
>> patch gets approval I will submit it for review.
>>
>> If I understand right then something like this would be ok??
>>
>> switch(sinfo->sinfo_pr_policy) {
>>
>>     case SCTP_PR_NONE:
>>          msg->expires_policy = SCTP_PR_NONE;
>>          msg->expires_at = 0;
>>          break;
>>     case SCTP_PR_RTX:
>>          msg->expires_policy = SCTP_PR_RTX;
>>          msg->expires_at = sinfo->sinfo_pr_value;
>>          break;
>>     case SCTP_PR_TTL:
>>     default:
>>          if(pr_value <= 0) {
>
> I don't think pr_value can be less then 0 since it's defined a unsigned.

fixed.

>
>>             msg->expires_policy = SCTP_PR_NONE;
>>             msg->expires_at = 0;
>>          } else {
>>             msg->expires_policy = SCTP_PR_TTL;
>>             msg->expires_at = jiffies + msecs_to_jiffies(sinfo->sinfo_pr_value);
>>          }
>>          break;
>> }
>>
>
> Yes.
>

great, I use this switch statement now.

>>
>>>> About validating sinfo_pr_value and sinfo_pr_policy I added validating
>>>> code on the sctp_msghdr_parse method. I think this is the best place
>>>> to make this validation. This would also make sure that the user gets
>>>> an error message if the sinfo_pr_value or sinfo_pr_policy values are
>>>> not initialized correctly (me thinks).
>>> No, the user may be using an old structure and and old api/abi.  We can't break
>>> them.  This has been my gripe with this draft for a long time... it keeps
>>> breaking ABI and requiring these ugly workarounds.
>>>
>>> You can log a rate limited warning, but you can't error out since that will
>>> break applications.
>>>
>>> BTW, why are the constants SCTP_PR_SCTP_*.  Having SCTP there once should be
>>> enough.  We can define BSD compatibility stuff, but having it clean in the kernel.
>>>
>>
>> Once the values I can use for the SCTP_PR_* flags is established I
>> will think on the validation. And about the constants having SCTP
>> twice in them, well I am just following the draft as it is written.
>
> Ah... I should have looked.
>
> I think this is getting cleared up.  I'll get a comment to the rest
> of the authors and the wG about specifying policy in sctp_sendmsg() and let
> you know the outcome.
>

hope this time I got it right....

Horacio

> -vlad
>
>>
>> regards
>> Horacio
>>
>>> -vlad
>>>
>>
>
>
From 75b5677399dc58d74dc7cfa04b4d6f37ee705ebd Mon Sep 17 00:00:00 2001
From: Horacio Sanson <horacio@xxxxxxxxxxxxxxxxxx>
Date: Wed, 31 Dec 2008 00:52:41 +0900
Subject: [PATCH] lksctp: replace sinfo_timetolive with sinfo_pr_value.

Modified all relevant structures in all header and source files to
replace the deprecated sinfo_timetolive field with the newer
sinfo_pr_policy and sinfo_pr_value.

Signed-off-by: Horacio Sanson <horacio@xxxxxxxxxxxxxxxxxx>
---
 include/net/sctp/structs.h |   10 ++++++----
 include/net/sctp/user.h    |    5 ++++-
 net/sctp/associola.c       |    3 ++-
 net/sctp/chunk.c           |   39 ++++++++++++++++++++++++++-------------
 net/sctp/output.c          |    2 +-
 net/sctp/socket.c          |   29 +++++++++++++++++++----------
 net/sctp/ulpevent.c        |    3 ++-
 7 files changed, 60 insertions(+), 31 deletions(-)

diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 9661d7b..f7ec249 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -280,9 +280,10 @@ struct sctp_sock {
 	/* Various Socket Options.  */
 	__u16 default_stream;
 	__u32 default_ppid;
+	__u16 default_pr_policy;
 	__u16 default_flags;
 	__u32 default_context;
-	__u32 default_timetolive;
+	__u32 default_pr_value;
 	__u32 default_rcv_context;
 	int max_burst;
 
@@ -626,13 +627,13 @@ struct sctp_datamsg {
 	struct list_head track;
 	/* Reference counting. */
 	atomic_t refcnt;
+	/* Policy used to determine how expires_at is interpreted */
+	unsigned long expires_policy;
 	/* When is this message no longer interesting to the peer? */
 	unsigned long expires_at;
 	/* Did the messenge fail to send? */
 	int send_error;
 	char send_failed;
-	/* Control whether chunks from this message can be abandoned. */
-	char can_abandon;
 };
 
 struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
@@ -1759,9 +1760,10 @@ struct sctp_association {
 	/* Default send parameters. */
 	__u16 default_stream;
 	__u16 default_flags;
+	__u16 default_pr_policy;
 	__u32 default_ppid;
 	__u32 default_context;
-	__u32 default_timetolive;
+	__u32 default_pr_value;
 
 	/* Default receive parameters */
 	__u32 default_rcv_context;
diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h
index f205b10..bcdb01e 100644
--- a/include/net/sctp/user.h
+++ b/include/net/sctp/user.h
@@ -183,9 +183,10 @@ struct sctp_sndrcvinfo {
 	__u16 sinfo_stream;
 	__u16 sinfo_ssn;
 	__u16 sinfo_flags;
+	__u16 sinfo_pr_policy;
 	__u32 sinfo_ppid;
 	__u32 sinfo_context;
-	__u32 sinfo_timetolive;
+	__u32 sinfo_pr_value;
 	__u32 sinfo_tsn;
 	__u32 sinfo_cumtsn;
 	sctp_assoc_t sinfo_assoc_id;
@@ -202,6 +203,8 @@ enum sctp_sinfo_flags {
 	SCTP_UNORDERED = 1,  /* Send/receive message unordered. */
 	SCTP_ADDR_OVER = 2,  /* Override the primary destination. */
 	SCTP_ABORT=4,        /* Send an ABORT message to the peer. */
+	SCTP_PR_SCTP_NONE=8, /* Reliable transmission */
+	SCTP_PR_SCTP_TTL=16, /* Timed partial reliability */
 	SCTP_EOF=MSG_FIN,    /* Initiate graceful shutdown process. */	
 };
 
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index f4b2304..c178139 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -302,7 +302,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
 	asoc->default_ppid = sp->default_ppid;
 	asoc->default_flags = sp->default_flags;
 	asoc->default_context = sp->default_context;
-	asoc->default_timetolive = sp->default_timetolive;
+	asoc->default_pr_policy = sp->default_pr_policy;
+	asoc->default_pr_value = sp->default_pr_value;
 	asoc->default_rcv_context = sp->default_rcv_context;
 
 	/* AUTH related initializations */
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
index 1748ef9..33141be 100644
--- a/net/sctp/chunk.c
+++ b/net/sctp/chunk.c
@@ -56,7 +56,7 @@ static void sctp_datamsg_init(struct sctp_datamsg *msg)
 	atomic_set(&msg->refcnt, 1);
 	msg->send_failed = 0;
 	msg->send_error = 0;
-	msg->can_abandon = 0;
+	msg->expires_policy = SCTP_PR_SCTP_NONE;
 	msg->expires_at = 0;
 	INIT_LIST_HEAD(&msg->chunks);
 }
@@ -170,13 +170,23 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
 	/* Note: Calculate this outside of the loop, so that all fragments
 	 * have the same expiration.
 	 */
-	if (sinfo->sinfo_timetolive) {
-		/* sinfo_timetolive is in milliseconds */
-		msg->expires_at = jiffies +
-				    msecs_to_jiffies(sinfo->sinfo_timetolive);
-		msg->can_abandon = 1;
-		SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld jiffies:%ld\n",
-				  __func__, msg, msg->expires_at, jiffies);
+	switch(sinfo->sinfo_pr_policy) {
+		case SCTP_PR_SCTP_NONE:
+			msg->expires_policy = SCTP_PR_SCTP_NONE;
+			msg->expires_at = 0;
+			break;
+		case SCTP_PR_SCTP_TTL:
+		default:
+			if(!sinfo->sinfo_pr_value) {
+				msg->expires_policy = SCTP_PR_SCTP_NONE;
+				msg->expires_at = 0;
+			} else {
+				msg->expires_policy = SCTP_PR_SCTP_TTL;
+				msg->expires_at = jiffies + msecs_to_jiffies(sinfo->sinfo_pr_value);
+				SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld jiffies:%ld\n",
+					__func__, msg, msg->expires_at, jiffies);
+			}
+			break;
 	}
 
 	max = asoc->frag_point;
@@ -291,11 +301,14 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk)
 {
 	struct sctp_datamsg *msg = chunk->msg;
 
-	if (!msg->can_abandon)
-		return 0;
-
-	if (time_after(jiffies, msg->expires_at))
-		return 1;
+	switch(msg->expires_policy) {
+		case SCTP_PR_SCTP_NONE:
+				return 0;
+		case SCTP_PR_SCTP_TTL:
+			if(time_after(jiffies, msg->expires_at))
+				return 1;
+			break;
+	}
 
 	return 0;
 }
diff --git a/net/sctp/output.c b/net/sctp/output.c
index c3f417f..b344a9d 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -745,7 +745,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
 	asoc->peer.rwnd = rwnd;
 	/* Has been accepted for transmission. */
 	if (!asoc->peer.prsctp_capable)
-		chunk->msg->can_abandon = 0;
+		chunk->msg->expires_policy = SCTP_PR_SCTP_NONE;
 
 finish:
 	return retval;
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index a1b9045..c21cb4c 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1698,7 +1698,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
 		default_sinfo.sinfo_flags = asoc->default_flags;
 		default_sinfo.sinfo_ppid = asoc->default_ppid;
 		default_sinfo.sinfo_context = asoc->default_context;
-		default_sinfo.sinfo_timetolive = asoc->default_timetolive;
+		default_sinfo.sinfo_pr_policy = asoc->default_pr_policy;
+		default_sinfo.sinfo_pr_value = asoc->default_pr_value;
 		default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc);
 		sinfo = &default_sinfo;
 	}
@@ -2539,7 +2540,7 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, int opt
  *   in to this call the sctp_sndrcvinfo structure defined in Section
  *   5.2.2) The input parameters accepted by this call include
  *   sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
- *   sinfo_timetolive.  The user must provide the sinfo_assoc_id field in
+ *   sinfo_pr_value.  The user must provide the sinfo_assoc_id field in
  *   to this call if the caller is using the UDP model.
  */
 static int sctp_setsockopt_default_send_param(struct sock *sk,
@@ -2563,13 +2564,15 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
 		asoc->default_flags = info.sinfo_flags;
 		asoc->default_ppid = info.sinfo_ppid;
 		asoc->default_context = info.sinfo_context;
-		asoc->default_timetolive = info.sinfo_timetolive;
+		asoc->default_pr_policy = info.sinfo_pr_policy;
+		asoc->default_pr_value = info.sinfo_pr_value;
 	} else {
 		sp->default_stream = info.sinfo_stream;
 		sp->default_flags = info.sinfo_flags;
 		sp->default_ppid = info.sinfo_ppid;
 		sp->default_context = info.sinfo_context;
-		sp->default_timetolive = info.sinfo_timetolive;
+		sp->default_pr_policy = info.sinfo_pr_policy;
+		sp->default_pr_value = info.sinfo_pr_value;
 	}
 
 	return 0;
@@ -3524,7 +3527,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
 	sp->default_ppid = 0;
 	sp->default_flags = 0;
 	sp->default_context = 0;
-	sp->default_timetolive = 0;
+	sp->default_pr_policy = SCTP_PR_SCTP_NONE;
+	sp->default_pr_value = 0;
 
 	sp->default_rcv_context = 0;
 	sp->max_burst = sctp_max_burst;
@@ -4824,7 +4828,7 @@ static int sctp_getsockopt_adaptation_layer(struct sock *sk, int len,
  *   in to this call the sctp_sndrcvinfo structure defined in Section
  *   5.2.2) The input parameters accepted by this call include
  *   sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
- *   sinfo_timetolive.  The user must provide the sinfo_assoc_id field in
+ *   sinfo_pr_value.  The user must provide the sinfo_assoc_id field in
  *   to this call if the caller is using the UDP model.
  *
  *   For getsockopt, it get the default sctp_sndrcvinfo structure.
@@ -4854,13 +4858,15 @@ static int sctp_getsockopt_default_send_param(struct sock *sk,
 		info.sinfo_flags = asoc->default_flags;
 		info.sinfo_ppid = asoc->default_ppid;
 		info.sinfo_context = asoc->default_context;
-		info.sinfo_timetolive = asoc->default_timetolive;
+		info.sinfo_pr_policy = asoc->default_pr_policy;
+		info.sinfo_pr_value = asoc->default_pr_value;
 	} else {
 		info.sinfo_stream = sp->default_stream;
 		info.sinfo_flags = sp->default_flags;
 		info.sinfo_ppid = sp->default_ppid;
 		info.sinfo_context = sp->default_context;
-		info.sinfo_timetolive = sp->default_timetolive;
+		info.sinfo_pr_policy = sp->default_pr_policy;
+		info.sinfo_pr_value = sp->default_pr_value;
 	}
 
 	if (put_user(len, optlen))
@@ -6107,10 +6113,13 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
 				(struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
 
 			/* Minimally, validate the sinfo_flags. */
-			if (cmsgs->info->sinfo_flags &
+/*
+if (cmsgs->info->sinfo_flags &
 			    ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
-			      SCTP_ABORT | SCTP_EOF))
+			      SCTP_ABORT | SCTP_EOF | SCTP_PR_SCTP_NONE |
+			      SCTP_PR_SCTP_TTL))
 				return -EINVAL;
+*/
 			break;
 
 		default:
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 5f186ca..9517e47 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -948,7 +948,8 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
 	sinfo.sinfo_context = event->asoc->default_rcv_context;
 
 	/* These fields are not used while receiving. */
-	sinfo.sinfo_timetolive = 0;
+	sinfo.sinfo_pr_policy = SCTP_PR_SCTP_NONE;
+	sinfo.sinfo_pr_value = 0;
 
 	put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV,
 		 sizeof(struct sctp_sndrcvinfo), (void *)&sinfo);
-- 
1.5.6.3


[Index of Archives]     [Linux Networking Development]     [Linux OMAP]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux