Message ID | 51DF74BE.6000001@windriver.com |
---|---|
State | RFC, archived |
Delegated to: | David Miller |
Headers | show |
From: Fan Du <fan.du@windriver.com> Date: Fri, 12 Jul 2013 11:15:10 +0800 > But problem still arise when we attempt to delete address > in multi-home mode, deleting an IPv6 address does not invalidate > any dst which source address is the same at the deleted one. > Which means sctp cannot rely on ip6_dst_check in this scenario. I still cannot understand why this is an SCTP specific issue. Specifically, I cannot see why address addition/deletion doesn't cause problems for cached ipv6 routes in UDP and TCP sockets too. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 07/12/2013 06:58 PM, David Miller wrote: > From: Fan Du <fan.du@windriver.com> > Date: Fri, 12 Jul 2013 11:15:10 +0800 > >> But problem still arise when we attempt to delete address >> in multi-home mode, deleting an IPv6 address does not invalidate >> any dst which source address is the same at the deleted one. >> Which means sctp cannot rely on ip6_dst_check in this scenario. > > I still cannot understand why this is an SCTP specific issue. > > Specifically, I cannot see why address addition/deletion doesn't > cause problems for cached ipv6 routes in UDP and TCP sockets too. > Trying to figure this out. -vlad -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 2013年07月13日 06:58, David Miller wrote: > From: Fan Du<fan.du@windriver.com> > Date: Fri, 12 Jul 2013 11:15:10 +0800 > >> But problem still arise when we attempt to delete address >> in multi-home mode, deleting an IPv6 address does not invalidate >> any dst which source address is the same at the deleted one. >> Which means sctp cannot rely on ip6_dst_check in this scenario. > > I still cannot understand why this is an SCTP specific issue. It's not SCTP specific, it's shared by all all layer 4 protocol IMHO. The issue of SCTP IPv6 doesn't check IPv6 dst validness has been addressed using *only* dst_cookie as other layer 4 protocol does for its sock. But this scheme cannot cover scenario when delete primary address to support SCTP multi-home feature, this is where the concern is. Use netsend to send a large file using DCCP, considering the sender host has two IPv6 address, while sending, delete the one netsend currently using. Wireshark could catch the sender is still transmit packet out using the deleted address in a slowly manner. All of those boils down to one question that I cannot resist to ask: If delete an IPv6 address(*1*), whether the original rt/dst destinate for a remote address(*2*) using the deleted address as source address is still legal for subsequent usage in current kernel IPv6 routing implementation??? btw, (*1*) and (*2*) are on quite different node in the binary tree as well as different leaf. > Specifically, I cannot see why address addition/deletion doesn't > cause problems for cached ipv6 routes in UDP and TCP sockets too. >
diff --git a/include/net/netns/sctp.h b/include/net/netns/sctp.h index 3573a81..83204db 100644 --- a/include/net/netns/sctp.h +++ b/include/net/netns/sctp.h @@ -129,6 +129,11 @@ struct netns_sctp { /* Threshold for autoclose timeout, in seconds. */ unsigned long max_autoclose; + +#if IS_ENABLED(CONFIG_IPV6) + /* sctp IPv6 specific */ + atomic_t addr_genid; +#endif }; #endif /* __NETNS_SCTP_H__ */ diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index d8e37ec..c344ea8 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -613,11 +613,18 @@ static inline void sctp_v4_map_v6(union sctp_addr *addr) */ static inline struct dst_entry *sctp_transport_dst_check(struct sctp_transport *t) { - if (t->dst && !dst_check(t->dst, 0)) { + struct sctp_af *af = t->af_specific; + + /* We handle two sceanario here: + * One: using dst_cookie to check against any routing information change + * Two: using sctp_cookie to check against address deletion + * Either of them force a new dst lookup for transport + */ + if ((t->dst && !dst_check(t->dst, t->dst_cookie)) || + af->check_addr_change(t)) { dst_release(t->dst); t->dst = NULL; } - return t->dst; } diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index e745c92..9849915 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -492,6 +492,7 @@ struct sctp_af { void (*seq_dump_addr)(struct seq_file *seq, union sctp_addr *addr); void (*ecn_capable)(struct sock *sk); + int (*check_addr_change)(struct sctp_transport *t); __u16 net_header_len; int sockaddr_len; sa_family_t sa_family; @@ -946,6 +947,8 @@ struct sctp_transport { __u64 hb_nonce; struct rcu_head rcu; + u32 dst_cookie; + u32 addr_cookie; }; struct sctp_transport *sctp_transport_new(struct net *, const union sctp_addr *, diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 09ffcc9..343cd10 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -137,6 +137,8 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev, break; } + /* force a lookup on all transport->dst for stcp IPv6 ONLY */ + atomic_inc(&net->sctp.addr_genid); return NOTIFY_DONE; } @@ -348,12 +350,20 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, out: if (!IS_ERR_OR_NULL(dst)) { struct rt6_info *rt; + struct net *net; rt = (struct rt6_info *)dst; t->dst = dst; - + net = dev_net(rt->rt6i_idev->dev); + pr_debug("rt6_dst:%pI6 rt6_src:%pI6\n", &rt->rt6i_dst.addr, - &fl6->saddr); + &fl6->saddr); + + /* use fn_sernum to detect routing change */ + t->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; + + /* record addr_genid to check against address delete */ + t->addr_cookie = atomic_read(&net->sctp.addr_genid); } else { t->dst = NULL; @@ -724,6 +734,14 @@ static void sctp_v6_ecn_capable(struct sock *sk) inet6_sk(sk)->tclass |= INET_ECN_ECT_0; } +static int sctp_v6_check_addr_change(struct sctp_transport *t) +{ + struct rt6_info *rt = (struct rt6_info *)t->dst; + struct net *net = dev_net(rt->rt6i_idev->dev); + + return (t->addr_cookie != atomic_read(&net->sctp.addr_genid) ? 1 : 0); +} + /* Initialize a PF_INET6 socket msg_name. */ static void sctp_inet6_msgname(char *msgname, int *addr_len) { @@ -1008,6 +1026,7 @@ static struct sctp_af sctp_af_inet6 = { .is_ce = sctp_v6_is_ce, .seq_dump_addr = sctp_v6_seq_dump_addr, .ecn_capable = sctp_v6_ecn_capable, + .check_addr_change = sctp_v6_check_addr_change, .net_header_len = sizeof(struct ipv6hdr), .sockaddr_len = sizeof(struct sockaddr_in6), #ifdef CONFIG_COMPAT @@ -1076,7 +1095,6 @@ int sctp_v6_add_protocol(void) if (inet6_add_protocol(&sctpv6_protocol, IPPROTO_SCTP) < 0) return -EAGAIN; - return 0; } diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 4a17494d..b9335d7 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -595,6 +595,12 @@ static void sctp_v4_ecn_capable(struct sock *sk) INET_ECN_xmit(sk); } +static int sctp_v4_check_addr_change(struct sctp_transport *t) +{ + /* Always return 0, as IPv4 bump rt genid when address changes */ + return 0; +} + static void sctp_addr_wq_timeout_handler(unsigned long arg) { struct net *net = (struct net *)arg; @@ -1064,6 +1070,7 @@ static struct sctp_af sctp_af_inet = { .is_ce = sctp_v4_is_ce, .seq_dump_addr = sctp_v4_seq_dump_addr, .ecn_capable = sctp_v4_ecn_capable, + .check_addr_change = sctp_v4_check_addr_change, .net_header_len = sizeof(struct iphdr), .sockaddr_len = sizeof(struct sockaddr_in), #ifdef CONFIG_COMPAT