inet6: Fix paramater issue of inet6_csk_xmit
Subsystems (5)
PATCH 1/1 inet6: Fix paramater issue of inet6_csk_xmit
inet6_csk_xmit() has a paramater ipfragok, but never pass to ip6_xmit(), always call it with ipfragok = 0.
This patch fixed this problem by instead 0 of ipfragok.
Compiled test only.
---net/ipv6/inet6_connection_sock.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
net/ipv6/inet6_connection_sock.c +0 -0
@@ -233,7 +233,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
/* Restore final destination back after routing done */ ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
- return ip6_xmit(sk, skb, &fl, np->opt, 0);
+ return ip6_xmit(sk, skb, &fl, np->opt, ipfragok);
}
EXPORT_SYMBOL_GPL(inet6_csk_xmit);
Signature · 1 line
1.5.3.8
David Miller
maintainerFrom: Wei Yongjun <[email protected]>
Date: Thu, 31 Jul 2008 17:56:25 +0800
Quoted 8 lines
inet6_csk_xmit()has a paramater ipfragok, but never pass toip6_xmit(), always call it with ipfragok = 0.This patch fixed this problem by instead 0 of ipfragok.
Compiled test only.
Signed-off-by Wei Yongjun <[email protected]>
I would like to see someone do some testing of this patch before I apply it.
Quoted 9 lines · David Miller
From: Wei Yongjun <[email protected]>
Date: Thu, 31 Jul 2008 17:56:25 +0800Quoted 5 lines
inet6_csk_xmit()has a paramater ipfragok, but never pass toip6_xmit(), always call it with ipfragok = 0.This patch fixed this problem by instead 0 of ipfragok.
Quoted 8 lines
Quoted 4 lines
Compiled test only.
Signed-off-by Wei Yongjun <[email protected]>I would like to see someone do some testing of this patch before I apply it.
inet6_csk_xmit() just be used by tcp and dccp:
1042 net/dccp/ipv6.c .queue_xmit = inet6_csk_xmit
1853 net/ipv6/tcp_ipv6.c .queue_xmit = inet6_csk_xmit,
And used always with ipfragok = 0.
139 net/dccp/output.c err = icsk->icsk_af_ops->queue_xmit(skb, 0);
626 net/ipv4/tcp_output.c err = icsk->icsk_af_ops->queue_xmit(skb, 0);
I can not find any place used inet6_csk_xmit() with ipfragok = 1.
So I think it is safe to apply this patch. Or maybe this paramater is useless.
Quoted 5 lines · Wei Yongjun
inet6_csk_xmit()just be used by tcp and dccp:
1042net/dccp/ipv6.c.queue_xmit =inet6_csk_xmit
1853net/ipv6/tcp_ipv6.c.queue_xmit =inet6_csk_xmit,
Quoted 8 lines
And used always with ipfragok = 0.
139net/dccp/output.cerr =icsk->icsk_af_ops->queue_xmit(skb, 0);
626net/ipv4/tcp_output.cerr =icsk->icsk_af_ops->queue_xmit(skb, 0);I can not find any place used
inet6_csk_xmit()with ipfragok = 1.So I think it is safe to apply this patch. Or maybe this paramater is useless.
No we should get rid of the ipfragok argument if noone uses it.
Thanks,
Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txtDavid Miller
maintainerFrom: Herbert Xu <[email protected]>
Date: Fri, 01 Aug 2008 17:11:01 +0800
Quoted 10 lines
Quoted 9 lines · Wei Yongjun
inet6_csk_xmit()just be used by tcp and dccp:
1042net/dccp/ipv6.c.queue_xmit =inet6_csk_xmit
1853net/ipv6/tcp_ipv6.c.queue_xmit =inet6_csk_xmit,And used always with ipfragok = 0.
139net/dccp/output.cerr =icsk->icsk_af_ops->queue_xmit(skb, 0);
626net/ipv4/tcp_output.cerr =icsk->icsk_af_ops->queue_xmit(skb, 0);
Quoted 6 lines
Quoted 4 lines
I can not find any place used
inet6_csk_xmit()with ipfragok = 1.So I think it is safe to apply this patch. Or maybe this paramater is useless.
No we should get rid of the ipfragok argument if noone uses it.
SCTP calls ip_queue_xmit() and ip6_xmit() directly with it's ipfragok argument, so it is used for these functions.
As a result ->icsk_af_ops->queue_xmit() needs to have arguments at least matching those function's prototypes.
Quoted 6 lines · David Miller
SCTP calls
ip_queue_xmit()andip6_xmit()directly with it's ipfragok argument, so it is used for these functions.As a result ->icsk_af_ops->queue_xmit() needs to have arguments at least matching those function's prototypes.
Hmm, so SCTP is the only reason why ipfragok exists and yet it doesn't even use icsk_af_ops->queue_xmit. So unless SCTP has plans to use icsk_af_ops, perhaps we could provide it a copy of ip_queue_xmit/ip6_xmit that has the ipfragok argument and then put a wrapper around them without the argument for icsk_af_ops and everybody else.
Who knows, it might even save more memory than the ethtool hack :)
Cheers,
Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txtQuoted 7 lines · Herbert Xu
Hmm, so SCTP is the only reason why ipfragok exists and yet it doesn't even use
icsk_af_ops->queue_xmit. So unless SCTP has plans to useicsk_af_ops, perhaps we could provide it a copy of ip_queue_xmit/ip6_xmit that has the ipfragok argument and then put a wrapper around them without the argument foricsk_af_opsand everybody else.
I dug up this thread from the archives:
http://osdir.com/ml/network/2003-01/msg00065.html
SCTP is just a POS.
However, I think we can improve on what we have at the moment. Really we only need to clear the DF bit on packets which are above the PMTU on output. There is no need to clear the DF for packets which we don't need to fragment ourselves.
Yes, the RFC says we SHOULD do that, but it's braindead. In any case, this isn't allowed by IPv6 and it makes little sense for IPv4. If we are doing PMTU then we want to get that error back in all cases.
So we should be able to simply replace ipfragok with skb->local_df. The only trouble is that SCTP doesn't seem to keep its PMTU setting in the usual spot so we'll need to fix that before this can be done.
Cheers,
Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txtQuoted 4 lines · Herbert Xu
So we should be able to simply replace ipfragok with
skb->local_df. The only trouble is that SCTP doesn't seem to keep its PMTU setting in the usual spot so we'll need to fix that before this can be done.
OK I think this should work:
sctp: Drop ipfargok in sctp_xmit function
The ipfragok flag controls whether the packet may be fragmented either on the local host on beyond. The latter is only valid on IPv4.
In fact, we never want to do the latter even on IPv4 when PMTU is enabled. This is because even though we can't fragment packets within SCTP due to the prtocol's inherent faults, we can still fragment it at IP layer. By setting the DF bit we will improve the PMTU process.
RFC 2960 only says that we SHOULD clear the DF bit in this case, so we're compliant even if we set the DF bit.
Once we make this change, we only need to control the local fragmentation. There is already a bit in the skb which controls that, local_df. So this patch sets that instead of using the ipfragok argument.
The only complication is that there isn't a struct sock object per transport, so for IPv4 we have to resort to changing the pmtudisc field for every packet. This should be safe though as the protocol is single-threaded.
Note that after this patch we can remove ipfragok from the rest of the stack too.
include/net/sctp/structs.h +1 -2
@@ -524,8 +524,7 @@ static inline void sctp_ssn_skip(struct sctp_stream *stream, __u16 id,*/ struct sctp_af {int (*sctp_xmit) (struct sk_buff *skb, -struct sctp_transport *, -int ipfragok); +struct sctp_transport *); int (*setsockopt) (struct sock *sk, int level, int optname,
net/sctp/ipv6.c +5 -3
@@ -195,8 +195,7 @@ out: }/* Based on tcp_v6_xmit() in tcp_ipv6.c. */ -static int sctp_v6_xmit (struct sk_buff *skb,struct sctp_transport *transport, -int ipfragok) +static int sctp_v6_xmit (struct sk_buff *skb,struct sctp_transport *transport) {struct sock *sk = skb->sk;struct ipv6_pinfo *np =inet6_sk (sk);
@@ -231,7 +230,10 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport,SCTP_INC_STATS (SCTP_MIB_OUTSCTPPACKS ); -return ip6_xmit (sk, skb, &fl, np->opt, ipfragok); +if (!(tp->param_flags &SPP_PMTUD_ENABLE )) + skb->local_df =1 ; + +return ip6_xmit (sk, skb, &fl, np->opt,0 ); }/* Returns the dst cache entry for the given source and destination ip
net/sctp/output.c +2 -4
@@ -586,10 +586,8 @@ 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 ); + nskb->local_df = packet->ipfragok; + (*tp->af_specific->sctp_xmit)(nskb, tp); out: packet->size = packet->overhead;
net/sctp/protocol.c +11 -2
@@ -862,16 +862,25 @@ static int sctp_inet_supported_addrs(const struct sctp_sock *opt,/* Wrapper routine that calls the ip transmit routine. */ static inline int sctp_v4_xmit (struct sk_buff *skb, -struct sctp_transport *transport,int ipfragok) +struct sctp_transport *transport) { +struct inet_sock *inet =inet_sk (skb->sk); +SCTP_DEBUG_PRINTK ("%s: skb:%p, len:%d, " "src:%u.%u.%u.%u, dst:%u.%u.%u.%u\n" , __func__, skb, skb->len,NIPQUAD (skb->rtable->rt_src),NIPQUAD (skb->rtable->rt_dst)); +/* +* You'd think with a protocol this big they could afford +* a struct sock per transport. +*/ + inet->pmtudisc = transport->param_flags &SPP_PMTUD_ENABLE ? +IP_PMTUDISC_DO :IP_PMTUDISC_DONT ; +SCTP_INC_STATS (SCTP_MIB_OUTSCTPPACKS ); -return ip_queue_xmit (skb, ipfragok); +return ip_queue_xmit (skb,0 ); }static struct sctp_af sctp_af_inet;
Cheers,
Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txtQuoted 7 lines · Herbert Xu
Quoted 3 lines · Herbert Xu
So we should be able to simply replace ipfragok with
skb->local_df. The only trouble is that SCTP doesn't seem to keep its PMTU setting in the usual spot so we'll need to fix that before this can be done.OK I think this should work:
Quoted 8 lines
sctp: Drop ipfargok in
sctp_xmitfunctionThe ipfragok flag controls whether the packet may be fragmented either on the local host on beyond. The latter is only valid on IPv4.
In fact, we never want to do the latter even on IPv4 when PMTU is enabled. This is because even though we can't fragment packets
I think you mean that we can't "re-fragment packets". The reason for that is how SCTP handles sequence numbering, Instead of numbering bytes, it number messages. Thus once the number is assigned, you can't re-fragment it as that would result in different sequence numbers.
Quoted 6 lines
within SCTP due to the prtocol's inherent faults, we can still fragment it at IP layer. By setting the DF bit we will improve the PMTU process.
RFC 2960 only says that we SHOULD clear the DF bit in this case, so we're compliant even if we set the DF bit.
RFC 4960 doesn't mention DF bit anywhere, so that's not an issue.
Quoted 86 lines
Once we make this change, we only need to control the local fragmentation. There is already a bit in the skb which controls that,
local_df. So this patch sets that instead of using the ipfragok argument.The only complication is that there isn't a struct sock object per transport, so for IPv4 we have to resort to changing the pmtudisc field for every packet. This should be safe though as the protocol is single-threaded.
Note that after this patch we can remove ipfragok from the rest of the stack too.
Signed-off-by Herbert Xu <[email protected]>include/net/sctp/structs.h +1
-2@@ -524,8 +524,7 @@ static inline void sctp_ssn_skip(struct sctp_stream *stream, __u16 id,*/ struct sctp_af {int (*sctp_xmit) (struct sk_buff *skb, -struct sctp_transport *, -int ipfragok); +struct sctp_transport *); int (*setsockopt) (struct sock *sk, int level, int optname,net/sctp/ipv6.c +5
-3@@ -195,8 +195,7 @@ out: }/* Based on tcp_v6_xmit() in tcp_ipv6.c. */ -static int sctp_v6_xmit (struct sk_buff *skb,struct sctp_transport *transport, -int ipfragok) +static int sctp_v6_xmit (struct sk_buff *skb,struct sctp_transport *transport) {struct sock *sk = skb->sk;struct ipv6_pinfo *np =inet6_sk (sk);@@ -231,7 +230,10 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport,SCTP_INC_STATS (SCTP_MIB_OUTSCTPPACKS ); -return ip6_xmit (sk, skb, &fl, np->opt, ipfragok); +if (!(tp->param_flags &SPP_PMTUD_ENABLE )) + skb->local_df =1 ; + +return ip6_xmit (sk, skb, &fl, np->opt,0 ); }/* Returns the dst cache entry for the given source and destination ip net/sctp/output.c +2
-4@@ -586,10 +586,8 @@ 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 ); + nskb->local_df = packet->ipfragok; + (*tp->af_specific->sctp_xmit)(nskb, tp); out: packet->size = packet->overhead;net/sctp/protocol.c +3
-1@@ -862,16 +862,25 @@ static int sctp_inet_supported_addrs(const struct sctp_sock *opt,/* Wrapper routine that calls the ip transmit routine. */ static inline int sctp_v4_xmit (struct sk_buff *skb, -struct sctp_transport *transport,int ipfragok) +struct sctp_transport *transport) { +struct inet_sock *inet =inet_sk (skb->sk); +
net/sctp/protocol.c static int sctp_inet_supported_addrs(const struct sctp_sock *opt, · line 878
Quoted 10 lines
net/sctp/protocol.c +4
-0SCTP_DEBUG_PRINTK ("%s: skb:%p, len:%d, " "src:%u.%u.%u.%u, dst:%u.%u.%u.%u\n" , __func__, skb, skb->len,NIPQUAD (skb->rtable->rt_src),NIPQUAD (skb->rtable->rt_dst)); +/* +* You'd think with a protocol this big they could afford +* a struct sock per transport. +*/
Please don't add comments like this. It does not contribute anything.
net/sctp/protocol.c static int sctp_inet_supported_addrs(const struct sctp_sock *opt, · line 880
Quoted 2 lines
net/sctp/protocol.c +2
-0+ inet->pmtudisc = transport->param_flags &SPP_PMTUD_ENABLE ? +IP_PMTUDISC_DO :IP_PMTUDISC_DONT ;
If you insist on doing this, you need to save the old value and restore it after ip_queue_xmit().
The reason is that PMTU discovery change on a specific transport or association should not affect the socket, since there could be multiple associations on a given socket. Each association has it's own control.
Thanks
-vlad
Quoted 9 lines
net/sctp/protocol.c +2
-1+SCTP_INC_STATS (SCTP_MIB_OUTSCTPPACKS ); -return ip_queue_xmit (skb, ipfragok); +return ip_queue_xmit (skb,0 ); }static struct sctp_af sctp_af_inet;Cheers,
Quoted 10 lines · Vlad Yasevich
net/sctp/protocol.c static int sctp_inet_supported_addrs(const struct sctp_sock *opt, · line 880
Quoted 3 lines
net/sctp/protocol.c +2
-0+ inet->pmtudisc = transport->param_flags &SPP_PMTUD_ENABLE ? +IP_PMTUDISC_DO :IP_PMTUDISC_DONT ;If you insist on doing this, you need to save the old value and restore it after
ip_queue_xmit().The reason is that PMTU discovery change on a specific transport or association should not affect the socket, since there could be multiple associations on a given socket. Each association has it's own control.
Yes but they'll all pass through here so it'll get set to the appropriate value.
Cheers,
Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txtQuoted 6 lines · Herbert Xu
Quoted 5 lines · Vlad Yasevich
net/sctp/protocol.c static int sctp_inet_supported_addrs(const struct sctp_sock *opt, · line 880
Quoted 2 lines
net/sctp/protocol.c +2
-0+ inet->pmtudisc = transport->param_flags &SPP_PMTUD_ENABLE ? +IP_PMTUDISC_DO :IP_PMTUDISC_DONT ;If you insist on doing this, you need to save the old value and restore it after
ip_queue_xmit().
Quoted 8 lines
Quoted 3 lines
The reason is that PMTU discovery change on a specific transport or association should not affect the socket, since there could be multiple associations on a given socket. Each association has it's own control.
Yes but they'll all pass through here so it'll get set to the appropriate value.
Cheers,
OK, I see what you mean. Let me run some tests with this patch. I doesn't look like it will cause any issues, but I'd like to verify.
Thanks
-vlad
Quoted 3 lines · Vlad Yasevich
OK, I see what you mean. Let me run some tests with this patch. I doesn't look like it will cause any issues, but I'd like to verify.
Thanks Vlad!
Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txtDavid Miller
maintainerFrom: Vlad Yasevich <[email protected]>
Date: Sat, 02 Aug 2008 19:26:29 -0400
Quoted 11 lines
Quoted 10 lines · Herbert Xu
Quoted 8 lines · Vlad Yasevich
net/sctp/protocol.c static int sctp_inet_supported_addrs(const struct sctp_sock *opt, · line 880
Quoted 2 lines
net/sctp/protocol.c +2
-0+ inet->pmtudisc = transport->param_flags &SPP_PMTUD_ENABLE ? +IP_PMTUDISC_DO :IP_PMTUDISC_DONT ;If you insist on doing this, you need to save the old value and restore it after
ip_queue_xmit().The reason is that PMTU discovery change on a specific transport or association should not affect the socket, since there could be multiple associations on a given socket. Each association has it's own control.
Quoted 7 lines
Quoted 4 lines
Yes but they'll all pass through here so it'll get set to the appropriate value.
Cheers,
OK, I see what you mean. Let me run some tests with this patch. I doesn't look like it will cause any issues, but I'd like to verify.
Like Herbert said, thanks for doing this testing.
Let me know how it goes so I can apply the patch if everything is OK.
Hi Herbert
Quoted 29 lines · Herbert Xu
include/net/sctp/structs.h +1
-2@@ -524,8 +524,7 @@ static inline void sctp_ssn_skip(struct sctp_stream *stream, __u16 id,*/ struct sctp_af {int (*sctp_xmit) (struct sk_buff *skb, -struct sctp_transport *, -int ipfragok); +struct sctp_transport *); int (*setsockopt) (struct sock *sk, int level, int optname,net/sctp/ipv6.c +1
-2@@ -195,8 +195,7 @@ out: }/* Based on tcp_v6_xmit() in tcp_ipv6.c. */ -static int sctp_v6_xmit (struct sk_buff *skb,struct sctp_transport *transport, -int ipfragok) +static int sctp_v6_xmit (struct sk_buff *skb,struct sctp_transport *transport) {struct sock *sk = skb->sk;struct ipv6_pinfo *np =inet6_sk (sk);
net/sctp/ipv6.c static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport, · line 235
Quoted 7 lines
net/sctp/ipv6.c +3
-1@@ -231,7 +230,10 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport,SCTP_INC_STATS (SCTP_MIB_OUTSCTPPACKS ); -return ip6_xmit (sk, skb, &fl, np->opt, ipfragok); +if (!(tp->param_flags &SPP_PMTUD_ENABLE )) + skb->local_df =1 ; +
s/tp/transport. Otherwise, will not compile.
Quoted 34 lines
net/sctp/ipv6.c +1
-0+return ip6_xmit (sk, skb, &fl, np->opt,0 ); }/* Returns the dst cache entry for the given source and destination ip net/sctp/output.c +2
-4@@ -586,10 +586,8 @@ 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 ); + nskb->local_df = packet->ipfragok; + (*tp->af_specific->sctp_xmit)(nskb, tp); out: packet->size = packet->overhead;net/sctp/protocol.c +3
-1@@ -862,16 +862,25 @@ static int sctp_inet_supported_addrs(const struct sctp_sock *opt,/* Wrapper routine that calls the ip transmit routine. */ static inline int sctp_v4_xmit (struct sk_buff *skb, -struct sctp_transport *transport,int ipfragok) +struct sctp_transport *transport) { +struct inet_sock *inet =inet_sk (skb->sk); +
net/sctp/protocol.c static int sctp_inet_supported_addrs(const struct sctp_sock *opt, · line 878
Quoted 10 lines
net/sctp/protocol.c +4
-0SCTP_DEBUG_PRINTK ("%s: skb:%p, len:%d, " "src:%u.%u.%u.%u, dst:%u.%u.%u.%u\n" , __func__, skb, skb->len,NIPQUAD (skb->rtable->rt_src),NIPQUAD (skb->rtable->rt_dst)); +/* +* You'd think with a protocol this big they could afford +* a struct sock per transport. +*/
Please change this comment to be descriptive of the code, or just remove it.
Quoted 11 lines
net/sctp/protocol.c +4
-1+ inet->pmtudisc = transport->param_flags &SPP_PMTUD_ENABLE ? +IP_PMTUDISC_DO :IP_PMTUDISC_DONT ; +SCTP_INC_STATS (SCTP_MIB_OUTSCTPPACKS ); -return ip_queue_xmit (skb, ipfragok); +return ip_queue_xmit (skb,0 ); }static struct sctp_af sctp_af_inet;Cheers,
Otherwise, all of my tests have passed.
Thanks
-vlad
Quoted 2 lines · Vlad Yasevich
Otherwise, all of my tests have passed.
Thanks for testing, here is the corrected patch:
sctp: Drop ipfargok in sctp_xmit function
The ipfragok flag controls whether the packet may be fragmented either on the local host on beyond. The latter is only valid on IPv4.
In fact, we never want to do the latter even on IPv4 when PMTU is enabled. This is because even though we can't fragment packets within SCTP due to the prtocol's inherent faults, we can still fragment it at IP layer. By setting the DF bit we will improve the PMTU process.
RFC 2960 only says that we SHOULD clear the DF bit in this case, so we're compliant even if we set the DF bit. In fact RFC 4960 no longer has this statement.
Once we make this change, we only need to control the local fragmentation. There is already a bit in the skb which controls that, local_df. So this patch sets that instead of using the ipfragok argument.
The only complication is that there isn't a struct sock object per transport, so for IPv4 we have to resort to changing the pmtudisc field for every packet. This should be safe though as the protocol is single-threaded.
Note that after this patch we can remove ipfragok from the rest of the stack too.
include/net/sctp/structs.h +1 -2
@@ -524,8 +524,7 @@ static inline void sctp_ssn_skip(struct sctp_stream *stream, __u16 id,*/ struct sctp_af {int (*sctp_xmit) (struct sk_buff *skb, -struct sctp_transport *, -int ipfragok); +struct sctp_transport *); int (*setsockopt) (struct sock *sk, int level, int optname,
net/sctp/ipv6.c +5 -3
@@ -195,8 +195,7 @@ out: }/* Based on tcp_v6_xmit() in tcp_ipv6.c. */ -static int sctp_v6_xmit (struct sk_buff *skb,struct sctp_transport *transport, -int ipfragok) +static int sctp_v6_xmit (struct sk_buff *skb,struct sctp_transport *transport) {struct sock *sk = skb->sk;struct ipv6_pinfo *np =inet6_sk (sk);
@@ -231,7 +230,10 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport,SCTP_INC_STATS (SCTP_MIB_OUTSCTPPACKS ); -return ip6_xmit (sk, skb, &fl, np->opt, ipfragok); +if (!(transport->param_flags &SPP_PMTUD_ENABLE )) + skb->local_df =1 ; + +return ip6_xmit (sk, skb, &fl, np->opt,0 ); }/* Returns the dst cache entry for the given source and destination ip
net/sctp/output.c +2 -4
@@ -586,10 +586,8 @@ 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 ); + nskb->local_df = packet->ipfragok; + (*tp->af_specific->sctp_xmit)(nskb, tp); out: packet->size = packet->overhead;
net/sctp/protocol.c +7 -2
@@ -862,16 +862,21 @@ static int sctp_inet_supported_addrs(const struct sctp_sock *opt,/* Wrapper routine that calls the ip transmit routine. */ static inline int sctp_v4_xmit (struct sk_buff *skb, -struct sctp_transport *transport,int ipfragok) +struct sctp_transport *transport) { +struct inet_sock *inet =inet_sk (skb->sk); +SCTP_DEBUG_PRINTK ("%s: skb:%p, len:%d, " "src:%u.%u.%u.%u, dst:%u.%u.%u.%u\n" , __func__, skb, skb->len,NIPQUAD (skb->rtable->rt_src),NIPQUAD (skb->rtable->rt_dst)); + inet->pmtudisc = transport->param_flags &SPP_PMTUD_ENABLE ? +IP_PMTUDISC_DO :IP_PMTUDISC_DONT ; +SCTP_INC_STATS (SCTP_MIB_OUTSCTPPACKS ); -return ip_queue_xmit (skb, ipfragok); +return ip_queue_xmit (skb,0 ); }static struct sctp_af sctp_af_inet;
Cheers,
Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txtHi Herbert Xu:
Quoted 28 lines
Quoted 2 lines · Vlad Yasevich
Otherwise, all of my tests have passed.
Thanks for testing, here is the corrected patch:
sctp: Drop ipfargok in
sctp_xmitfunctionThe ipfragok flag controls whether the packet may be fragmented either on the local host on beyond. The latter is only valid on IPv4.
In fact, we never want to do the latter even on IPv4 when PMTU is enabled. This is because even though we can't fragment packets within SCTP due to the prtocol's inherent faults, we can still fragment it at IP layer. By setting the DF bit we will improve the PMTU process.
RFC 2960 only says that we SHOULD clear the DF bit in this case, so we're compliant even if we set the DF bit. In fact RFC 4960 no longer has this statement.
Once we make this change, we only need to control the local fragmentation. There is already a bit in the skb which controls that,
local_df. So this patch sets that instead of using the ipfragok argument.
Quoted 9 lines
The only complication is that there isn't a struct sock object per transport, so for IPv4 we have to resort to changing the pmtudisc field for every packet. This should be safe though as the protocol is single-threaded.
Note that after this patch we can remove ipfragok from the rest of the stack too.
You need this patch to let sctp under IPv6 do the correct thing.
ipv6: Do not drop packet if skb->local_df is set to true
The old code will drop IPv6 packet if ipfragok is not set, since ipfragok is obsoleted, will be instead by used skb->local_df, so this check must be changed to skb->local_df.
This patch fix this problem and not drop packet if skb->local_df is set to true.
---net/ipv6/ip6_output.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
net/ipv6/ip6_output.c +0 -0
@@ -269,7 +269,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
skb->mark = sk->sk_mark;
mtu = dst_mtu(dst);
- if ((skb->len <= mtu) || ipfragok || skb_is_gso(skb)) {
+ if ((skb->len <= mtu) || skb->local_df || skb_is_gso(skb)) {
IP6_INC_STATS(ip6_dst_idev(skb->dst),
IPSTATS_MIB_OUTREQUESTS);
return NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,Signature · 1 line
1.5.3.8
Herbert Xu
Acked-byQuoted 2 lines · Wei Yongjun
You need this patch to let sctp under IPv6 do the correct thing.
Good point.
Quoted 11 lines
ipv6: Do not drop packet if
skb->local_dfis set to trueThe old code will drop IPv6 packet if ipfragok is not set, since ipfragok is obsoleted, will be instead by used
skb->local_df, so this check must be changed
toskb->local_df.This patch fix this problem and not drop packet if
skb->local_dfis set to true.Signed-off-by Wei Yongjun <[email protected]>
Thanks,
Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txtDavid Miller
maintainerFrom: Herbert Xu <[email protected]>
Date: Mon, 4 Aug 2008 11:05:07 +0800
Quoted 13 lines · Wei Yongjun
Quoted 2 lines
You need this patch to let sctp under IPv6 do the correct thing.
Good point.
Quoted 7 lines
ipv6: Do not drop packet if
skb->local_dfis set to trueThe old code will drop IPv6 packet if ipfragok is not set, since ipfragok is obsoleted, will be instead by used
skb->local_df, so this check must be changed
toskb->local_df.
Quoted 6 lines
Quoted 4 lines
This patch fix this problem and not drop packet if
skb->local_dfis set to true.Signed-off-by Wei Yongjun <[email protected]>Acked-by Herbert Xu <[email protected]>
Also applied, thanks everyone.
From: Herbert Xu <[email protected]>
Date: Mon, 04 Aug 2008 09:55:19 +0800
Quoted 1 line
sctp: Drop ipfargok in
sctp_xmitfunction
...
Quoted 1 line
Signed-off-by Herbert Xu <[email protected]>
Applied, thanks.