From b71d1d426d263b0b6cb5760322efebbfc89d4463 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 22 Apr 2011 04:53:02 +0000 Subject: inet: constify ip headers and in6_addr Add const qualifiers to structs iphdr, ipv6hdr and in6_addr pointers where possible, to make code intention more obvious. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sctp/ipv6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/sctp/ipv6.c') diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 865ce7ba4e14..321f175055bf 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -531,7 +531,7 @@ static int sctp_v6_is_any(const union sctp_addr *addr) static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp) { int type; - struct in6_addr *in6 = (struct in6_addr *)&addr->v6.sin6_addr; + const struct in6_addr *in6 = (const struct in6_addr *)&addr->v6.sin6_addr; type = ipv6_addr_type(in6); if (IPV6_ADDR_ANY == type) -- cgit v1.2.3 From 625034113bd45c71fb9e329f52f25fef9e6993a3 Mon Sep 17 00:00:00 2001 From: Weixing Shi Date: Tue, 26 Apr 2011 21:36:32 +0000 Subject: sctp: fix sctp to work with ipv6 source address routing In the below test case, using the source address routing, sctp can not work. Node-A 1)ifconfig eth0 inet6 add 2001:1::1/64 2)ip -6 rule add from 2001:1::1 table 100 pref 100 3)ip -6 route add 2001:2::1 dev eth0 table 100 4)sctp_darn -H 2001:1::1 -P 250 -l & Node-B 1)ifconfig eth0 inet6 add 2001:2::1/64 2)ip -6 rule add from 2001:2::1 table 100 pref 100 3)ip -6 route add 2001:1::1 dev eth0 table 100 4)sctp_darn -H 2001:2::1 -P 250 -h 2001:1::1 -p 250 -s root cause: Node-A and Node-B use the source address routing, and at begining, source address will be NULL,sctp will search the routing table by the destination address, because using the source address routing table, and the result dst_entry will be NULL. solution: walk through the bind address list to get the source address and then lookup the routing table again to get the correct dst_entry. Signed-off-by: Weixing Shi Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/sctp/ipv6.c | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'net/sctp/ipv6.c') diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 321f175055bf..3a571d6614f9 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -80,6 +80,9 @@ #include +static inline int sctp_v6_addr_match_len(union sctp_addr *s1, + union sctp_addr *s2); + /* Event handler for inet6 address addition/deletion events. * The sctp_local_addr_list needs to be protocted by a spin lock since * multiple notifiers (say IPv4 and IPv6) may be running at the same @@ -244,8 +247,14 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, union sctp_addr *daddr, union sctp_addr *saddr) { - struct dst_entry *dst; + struct dst_entry *dst = NULL; struct flowi6 fl6; + struct sctp_bind_addr *bp; + struct sctp_sockaddr_entry *laddr; + union sctp_addr *baddr = NULL; + __u8 matchlen = 0; + __u8 bmatchlen; + sctp_scope_t scope; memset(&fl6, 0, sizeof(fl6)); ipv6_addr_copy(&fl6.daddr, &daddr->v6.sin6_addr); @@ -261,6 +270,39 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, } dst = ip6_route_output(&init_net, NULL, &fl6); + if (!asoc || saddr) + goto out; + + if (dst->error) { + dst_release(dst); + dst = NULL; + bp = &asoc->base.bind_addr; + scope = sctp_scope(daddr); + /* Walk through the bind address list and try to get a dst that + * matches a bind address as the source address. + */ + rcu_read_lock(); + list_for_each_entry_rcu(laddr, &bp->address_list, list) { + if (!laddr->valid) + continue; + if ((laddr->state == SCTP_ADDR_SRC) && + (laddr->a.sa.sa_family == AF_INET6) && + (scope <= sctp_scope(&laddr->a))) { + bmatchlen = sctp_v6_addr_match_len(daddr, + &laddr->a); + if (!baddr || (matchlen < bmatchlen)) { + baddr = &laddr->a; + matchlen = bmatchlen; + } + } + } + rcu_read_unlock(); + if (baddr) { + ipv6_addr_copy(&fl6.saddr, &baddr->v6.sin6_addr); + dst = ip6_route_output(&init_net, NULL, &fl6); + } + } +out: if (!dst->error) { struct rt6_info *rt; rt = (struct rt6_info *)dst; -- cgit v1.2.3 From 9914ae3ca770389a3bec3114d0a07532a7f235dd Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 26 Apr 2011 21:51:31 +0000 Subject: sctp: cache the ipv6 source after route lookup The ipv6 routing lookup does give us a source address, but instead of filling it into the dst, it's stored in the flowi. We can use that instead of going through the entire source address selection again. Also the useless ->dst_saddr member of sctp_pf is removed. And sctp_v6_dst_saddr() is removed, instead by introduce sctp_v6_to_addr(), which can be reused to cleanup some dup code. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- include/net/sctp/structs.h | 14 ++-- net/sctp/ipv6.c | 161 ++++++++++++++++++++------------------------- net/sctp/protocol.c | 47 +++++++------ net/sctp/socket.c | 2 +- net/sctp/transport.c | 15 +++-- 5 files changed, 112 insertions(+), 127 deletions(-) (limited to 'net/sctp/ipv6.c') diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 5c9bada51d2d..1d465d62f34f 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -566,17 +566,15 @@ struct sctp_af { int __user *optlen); struct dst_entry *(*get_dst) (struct sctp_association *asoc, union sctp_addr *daddr, - union sctp_addr *saddr); + union sctp_addr *saddr, + struct flowi *fl, + struct sock *sk); void (*get_saddr) (struct sctp_sock *sk, - struct sctp_association *asoc, - struct dst_entry *dst, + struct sctp_transport *t, union sctp_addr *daddr, - union sctp_addr *saddr); + struct flowi *fl); void (*copy_addrlist) (struct list_head *, struct net_device *); - void (*dst_saddr) (union sctp_addr *saddr, - struct dst_entry *dst, - __be16 port); int (*cmp_addr) (const union sctp_addr *addr1, const union sctp_addr *addr2); void (*addr_copy) (union sctp_addr *dst, @@ -1061,7 +1059,7 @@ void sctp_transport_set_owner(struct sctp_transport *, struct sctp_association *); void sctp_transport_route(struct sctp_transport *, union sctp_addr *, struct sctp_sock *); -void sctp_transport_pmtu(struct sctp_transport *); +void sctp_transport_pmtu(struct sctp_transport *, struct sock *sk); void sctp_transport_free(struct sctp_transport *); void sctp_transport_reset_timers(struct sctp_transport *); void sctp_transport_hold(struct sctp_transport *); diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 3a571d6614f9..51c048d256f5 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -82,6 +82,10 @@ static inline int sctp_v6_addr_match_len(union sctp_addr *s1, union sctp_addr *s2); +static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr, + __be16 port); +static int sctp_v6_cmp_addr(const union sctp_addr *addr1, + const union sctp_addr *addr2); /* Event handler for inet6 address addition/deletion events. * The sctp_local_addr_list needs to be protocted by a spin lock since @@ -245,73 +249,99 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport) */ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, union sctp_addr *daddr, - union sctp_addr *saddr) + union sctp_addr *saddr, + struct flowi *fl, + struct sock *sk) { struct dst_entry *dst = NULL; - struct flowi6 fl6; + struct flowi6 *fl6 = &fl->u.ip6; struct sctp_bind_addr *bp; struct sctp_sockaddr_entry *laddr; union sctp_addr *baddr = NULL; + union sctp_addr dst_saddr; __u8 matchlen = 0; __u8 bmatchlen; sctp_scope_t scope; + int err = 0; - memset(&fl6, 0, sizeof(fl6)); - ipv6_addr_copy(&fl6.daddr, &daddr->v6.sin6_addr); + memset(fl6, 0, sizeof(struct flowi6)); + ipv6_addr_copy(&fl6->daddr, &daddr->v6.sin6_addr); if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) - fl6.flowi6_oif = daddr->v6.sin6_scope_id; + fl6->flowi6_oif = daddr->v6.sin6_scope_id; - SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6.daddr); + SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6->daddr); if (saddr) { - ipv6_addr_copy(&fl6.saddr, &saddr->v6.sin6_addr); - SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6.saddr); + ipv6_addr_copy(&fl6->saddr, &saddr->v6.sin6_addr); + SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6->saddr); } - dst = ip6_route_output(&init_net, NULL, &fl6); + err = ip6_dst_lookup(sk, &dst, fl6); if (!asoc || saddr) goto out; - if (dst->error) { - dst_release(dst); - dst = NULL; - bp = &asoc->base.bind_addr; - scope = sctp_scope(daddr); - /* Walk through the bind address list and try to get a dst that - * matches a bind address as the source address. + bp = &asoc->base.bind_addr; + scope = sctp_scope(daddr); + /* ip6_dst_lookup has filled in the fl6->saddr for us. Check + * to see if we can use it. + */ + if (!err) { + /* Walk through the bind address list and look for a bind + * address that matches the source address of the returned dst. */ + sctp_v6_to_addr(&dst_saddr, &fl6->saddr, htons(bp->port)); rcu_read_lock(); list_for_each_entry_rcu(laddr, &bp->address_list, list) { - if (!laddr->valid) + if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC)) continue; - if ((laddr->state == SCTP_ADDR_SRC) && - (laddr->a.sa.sa_family == AF_INET6) && - (scope <= sctp_scope(&laddr->a))) { - bmatchlen = sctp_v6_addr_match_len(daddr, - &laddr->a); - if (!baddr || (matchlen < bmatchlen)) { - baddr = &laddr->a; - matchlen = bmatchlen; - } + + /* Do not compare against v4 addrs */ + if ((laddr->a.sa.sa_family == AF_INET6) && + (sctp_v6_cmp_addr(&dst_saddr, &laddr->a))) { + rcu_read_unlock(); + goto out; } } rcu_read_unlock(); - if (baddr) { - ipv6_addr_copy(&fl6.saddr, &baddr->v6.sin6_addr); - dst = ip6_route_output(&init_net, NULL, &fl6); + /* None of the bound addresses match the source address of the + * dst. So release it. + */ + dst_release(dst); + dst = NULL; + } + + /* Walk through the bind address list and try to get the + * best source address for a given destination. + */ + rcu_read_lock(); + list_for_each_entry_rcu(laddr, &bp->address_list, list) { + if (!laddr->valid && laddr->state != SCTP_ADDR_SRC) + continue; + if ((laddr->a.sa.sa_family == AF_INET6) && + (scope <= sctp_scope(&laddr->a))) { + bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); + if (!baddr || (matchlen < bmatchlen)) { + baddr = &laddr->a; + matchlen = bmatchlen; + } } } + rcu_read_unlock(); + if (baddr) { + ipv6_addr_copy(&fl6->saddr, &baddr->v6.sin6_addr); + err = ip6_dst_lookup(sk, &dst, fl6); + } + out: - if (!dst->error) { + if (!err) { struct rt6_info *rt; rt = (struct rt6_info *)dst; SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n", - &rt->rt6i_dst.addr, &rt->rt6i_src.addr); + &rt->rt6i_dst.addr, &fl6->saddr); return dst; } SCTP_DEBUG_PRINTK("NO ROUTE\n"); - dst_release(dst); return NULL; } @@ -328,64 +358,21 @@ static inline int sctp_v6_addr_match_len(union sctp_addr *s1, * and asoc's bind address list. */ static void sctp_v6_get_saddr(struct sctp_sock *sk, - struct sctp_association *asoc, - struct dst_entry *dst, + struct sctp_transport *t, union sctp_addr *daddr, - union sctp_addr *saddr) + struct flowi *fl) { - struct sctp_bind_addr *bp; - struct sctp_sockaddr_entry *laddr; - sctp_scope_t scope; - union sctp_addr *baddr = NULL; - __u8 matchlen = 0; - __u8 bmatchlen; + struct flowi6 *fl6 = &fl->u.ip6; + union sctp_addr *saddr = &t->saddr; SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p daddr:%pI6 ", - __func__, asoc, dst, &daddr->v6.sin6_addr); - - if (!asoc) { - ipv6_dev_get_saddr(sock_net(sctp_opt2sk(sk)), - dst ? ip6_dst_idev(dst)->dev : NULL, - &daddr->v6.sin6_addr, - inet6_sk(&sk->inet.sk)->srcprefs, - &saddr->v6.sin6_addr); - SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: %pI6\n", - &saddr->v6.sin6_addr); - return; - } - - scope = sctp_scope(daddr); + __func__, t->asoc, t->dst, &daddr->v6.sin6_addr); - bp = &asoc->base.bind_addr; - - /* Go through the bind address list and find the best source address - * that matches the scope of the destination address. - */ - rcu_read_lock(); - list_for_each_entry_rcu(laddr, &bp->address_list, list) { - if (!laddr->valid) - continue; - if ((laddr->state == SCTP_ADDR_SRC) && - (laddr->a.sa.sa_family == AF_INET6) && - (scope <= sctp_scope(&laddr->a))) { - bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); - if (!baddr || (matchlen < bmatchlen)) { - baddr = &laddr->a; - matchlen = bmatchlen; - } - } - } - if (baddr) { - memcpy(saddr, baddr, sizeof(union sctp_addr)); - SCTP_DEBUG_PRINTK("saddr: %pI6\n", &saddr->v6.sin6_addr); - } else { - pr_err("%s: asoc:%p Could not find a valid source " - "address for the dest:%pI6\n", - __func__, asoc, &daddr->v6.sin6_addr); + if (t->dst) { + saddr->v6.sin6_family = AF_INET6; + ipv6_addr_copy(&saddr->v6.sin6_addr, &fl6->saddr); } - - rcu_read_unlock(); } /* Make a copy of all potential local addresses. */ @@ -507,14 +494,13 @@ static int sctp_v6_to_addr_param(const union sctp_addr *addr, return length; } -/* Initialize a sctp_addr from a dst_entry. */ -static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst, +/* Initialize a sctp_addr from struct in6_addr. */ +static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr, __be16 port) { - struct rt6_info *rt = (struct rt6_info *)dst; addr->sa.sa_family = AF_INET6; addr->v6.sin6_port = port; - ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr); + ipv6_addr_copy(&addr->v6.sin6_addr, saddr); } /* Compare addresses exactly. @@ -1001,7 +987,6 @@ static struct sctp_af sctp_af_inet6 = { .to_sk_daddr = sctp_v6_to_sk_daddr, .from_addr_param = sctp_v6_from_addr_param, .to_addr_param = sctp_v6_to_addr_param, - .dst_saddr = sctp_v6_dst_saddr, .cmp_addr = sctp_v6_cmp_addr, .scope = sctp_v6_scope, .addr_valid = sctp_v6_addr_valid, diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index d5bf91d04f63..34216458ded1 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -465,33 +465,35 @@ static sctp_scope_t sctp_v4_scope(union sctp_addr *addr) */ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, union sctp_addr *daddr, - union sctp_addr *saddr) + union sctp_addr *saddr, + struct flowi *fl, + struct sock *sk) { struct rtable *rt; - struct flowi4 fl4; + struct flowi4 *fl4 = &fl->u.ip4; struct sctp_bind_addr *bp; struct sctp_sockaddr_entry *laddr; struct dst_entry *dst = NULL; union sctp_addr dst_saddr; - memset(&fl4, 0x0, sizeof(struct flowi4)); - fl4.daddr = daddr->v4.sin_addr.s_addr; - fl4.fl4_dport = daddr->v4.sin_port; - fl4.flowi4_proto = IPPROTO_SCTP; + memset(fl4, 0x0, sizeof(struct flowi4)); + fl4->daddr = daddr->v4.sin_addr.s_addr; + fl4->fl4_dport = daddr->v4.sin_port; + fl4->flowi4_proto = IPPROTO_SCTP; if (asoc) { - fl4.flowi4_tos = RT_CONN_FLAGS(asoc->base.sk); - fl4.flowi4_oif = asoc->base.sk->sk_bound_dev_if; - fl4.fl4_sport = htons(asoc->base.bind_addr.port); + fl4->flowi4_tos = RT_CONN_FLAGS(asoc->base.sk); + fl4->flowi4_oif = asoc->base.sk->sk_bound_dev_if; + fl4->fl4_sport = htons(asoc->base.bind_addr.port); } if (saddr) { - fl4.saddr = saddr->v4.sin_addr.s_addr; - fl4.fl4_sport = saddr->v4.sin_port; + fl4->saddr = saddr->v4.sin_addr.s_addr; + fl4->fl4_sport = saddr->v4.sin_port; } SCTP_DEBUG_PRINTK("%s: DST:%pI4, SRC:%pI4 - ", - __func__, &fl4.daddr, &fl4.saddr); + __func__, &fl4->daddr, &fl4->saddr); - rt = ip_route_output_key(&init_net, &fl4); + rt = ip_route_output_key(&init_net, fl4); if (!IS_ERR(rt)) dst = &rt->dst; @@ -533,9 +535,9 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, continue; if ((laddr->state == SCTP_ADDR_SRC) && (AF_INET == laddr->a.sa.sa_family)) { - fl4.saddr = laddr->a.v4.sin_addr.s_addr; - fl4.fl4_sport = laddr->a.v4.sin_port; - rt = ip_route_output_key(&init_net, &fl4); + fl4->saddr = laddr->a.v4.sin_addr.s_addr; + fl4->fl4_sport = laddr->a.v4.sin_port; + rt = ip_route_output_key(&init_net, fl4); if (!IS_ERR(rt)) { dst = &rt->dst; goto out_unlock; @@ -559,19 +561,15 @@ out: * to cache it separately and hence this is an empty routine. */ static void sctp_v4_get_saddr(struct sctp_sock *sk, - struct sctp_association *asoc, - struct dst_entry *dst, + struct sctp_transport *t, union sctp_addr *daddr, - union sctp_addr *saddr) + struct flowi *fl) { - struct rtable *rt = (struct rtable *)dst; - - if (!asoc) - return; + union sctp_addr *saddr = &t->saddr; + struct rtable *rt = (struct rtable *)t->dst; if (rt) { saddr->v4.sin_family = AF_INET; - saddr->v4.sin_port = htons(asoc->base.bind_addr.port); saddr->v4.sin_addr.s_addr = rt->rt_src; } } @@ -950,7 +948,6 @@ static struct sctp_af sctp_af_inet = { .to_sk_daddr = sctp_v4_to_sk_daddr, .from_addr_param = sctp_v4_from_addr_param, .to_addr_param = sctp_v4_to_addr_param, - .dst_saddr = sctp_v4_dst_saddr, .cmp_addr = sctp_v4_cmp_addr, .addr_valid = sctp_v4_addr_valid, .inaddr_any = sctp_v4_inaddr_any, diff --git a/net/sctp/socket.c b/net/sctp/socket.c index f694ee116746..33d9ee629b4e 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2287,7 +2287,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, trans->param_flags = (trans->param_flags & ~SPP_PMTUD) | pmtud_change; if (update) { - sctp_transport_pmtu(trans); + sctp_transport_pmtu(trans, sctp_opt2sk(sp)); sctp_assoc_sync_pmtu(asoc); } } else if (asoc) { diff --git a/net/sctp/transport.c b/net/sctp/transport.c index d3ae493d234a..2544b9b21f86 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -211,11 +211,15 @@ void sctp_transport_set_owner(struct sctp_transport *transport, } /* Initialize the pmtu of a transport. */ -void sctp_transport_pmtu(struct sctp_transport *transport) +void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk) { struct dst_entry *dst; + struct flowi fl; - dst = transport->af_specific->get_dst(NULL, &transport->ipaddr, NULL); + dst = transport->af_specific->get_dst(transport->asoc, + &transport->ipaddr, + &transport->saddr, + &fl, sk); if (dst) { transport->pathmtu = dst_mtu(dst); @@ -272,15 +276,16 @@ void sctp_transport_route(struct sctp_transport *transport, struct sctp_af *af = transport->af_specific; union sctp_addr *daddr = &transport->ipaddr; struct dst_entry *dst; + struct flowi fl; - dst = af->get_dst(asoc, daddr, saddr); + dst = af->get_dst(asoc, daddr, saddr, &fl, sctp_opt2sk(opt)); + transport->dst = dst; if (saddr) memcpy(&transport->saddr, saddr, sizeof(union sctp_addr)); else - af->get_saddr(opt, asoc, dst, daddr, &transport->saddr); + af->get_saddr(opt, transport, daddr, &fl); - transport->dst = dst; if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) { return; } -- cgit v1.2.3 From 9c6a02f41d10dc9fbf5dd42058e8846f38dd2d9a Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 26 Apr 2011 21:52:27 +0000 Subject: sctp: make sctp over IPv6 work with IPsec SCTP never called xfrm_output after it's v6 route lookups so that never really worked with ipsec. Additioanlly, we never passed port nubmers and protocol in the flowi, so any port based policies were never applied as well. Now that we can fixed ipv6 routing lookup code, using ip6_dst_lookup_flow() and pass port numbers. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- net/sctp/ipv6.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'net/sctp/ipv6.c') diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 51c048d256f5..593c80162913 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -262,22 +262,27 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, __u8 matchlen = 0; __u8 bmatchlen; sctp_scope_t scope; - int err = 0; memset(fl6, 0, sizeof(struct flowi6)); ipv6_addr_copy(&fl6->daddr, &daddr->v6.sin6_addr); + fl6->fl6_dport = daddr->v6.sin6_port; + fl6->flowi6_proto = IPPROTO_SCTP; if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) fl6->flowi6_oif = daddr->v6.sin6_scope_id; SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6->daddr); + if (asoc) + fl6->fl6_sport = htons(asoc->base.bind_addr.port); + if (saddr) { ipv6_addr_copy(&fl6->saddr, &saddr->v6.sin6_addr); + fl6->fl6_sport = saddr->v6.sin6_port; SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6->saddr); } - err = ip6_dst_lookup(sk, &dst, fl6); + dst = ip6_dst_lookup_flow(sk, fl6, NULL, false); if (!asoc || saddr) goto out; @@ -286,7 +291,7 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, /* ip6_dst_lookup has filled in the fl6->saddr for us. Check * to see if we can use it. */ - if (!err) { + if (!IS_ERR(dst)) { /* Walk through the bind address list and look for a bind * address that matches the source address of the returned dst. */ @@ -330,11 +335,12 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, rcu_read_unlock(); if (baddr) { ipv6_addr_copy(&fl6->saddr, &baddr->v6.sin6_addr); - err = ip6_dst_lookup(sk, &dst, fl6); + fl6->fl6_sport = baddr->v6.sin6_port; + dst = ip6_dst_lookup_flow(sk, fl6, NULL, false); } out: - if (!err) { + if (!IS_ERR(dst)) { struct rt6_info *rt; rt = (struct rt6_info *)dst; SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n", -- cgit v1.2.3 From af1384703f8a4ff3d245925d6596ef1c5c6e469e Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 26 Apr 2011 21:53:20 +0000 Subject: sctp: remove useless arguments from get_saddr() call There is no point in passing a destination address to a get_saddr() call. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- include/net/sctp/structs.h | 1 - net/sctp/ipv6.c | 5 +---- net/sctp/protocol.c | 1 - net/sctp/transport.c | 2 +- 4 files changed, 2 insertions(+), 7 deletions(-) (limited to 'net/sctp/ipv6.c') diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 1d465d62f34f..bb2f43b7e9a8 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -571,7 +571,6 @@ struct sctp_af { struct sock *sk); void (*get_saddr) (struct sctp_sock *sk, struct sctp_transport *t, - union sctp_addr *daddr, struct flowi *fl); void (*copy_addrlist) (struct list_head *, struct net_device *); diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 593c80162913..a1913a4b6f3a 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -365,15 +365,12 @@ static inline int sctp_v6_addr_match_len(union sctp_addr *s1, */ static void sctp_v6_get_saddr(struct sctp_sock *sk, struct sctp_transport *t, - union sctp_addr *daddr, struct flowi *fl) { struct flowi6 *fl6 = &fl->u.ip6; union sctp_addr *saddr = &t->saddr; - SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p daddr:%pI6 ", - __func__, t->asoc, t->dst, &daddr->v6.sin6_addr); - + SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p\n", __func__, t->asoc, t->dst); if (t->dst) { saddr->v6.sin6_family = AF_INET6; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 34216458ded1..68b4c4317d61 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -562,7 +562,6 @@ out: */ static void sctp_v4_get_saddr(struct sctp_sock *sk, struct sctp_transport *t, - union sctp_addr *daddr, struct flowi *fl) { union sctp_addr *saddr = &t->saddr; diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 2544b9b21f86..1fbb920f8dfb 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -284,7 +284,7 @@ void sctp_transport_route(struct sctp_transport *transport, if (saddr) memcpy(&transport->saddr, saddr, sizeof(union sctp_addr)); else - af->get_saddr(opt, transport, daddr, &fl); + af->get_saddr(opt, transport, &fl); if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) { return; -- cgit v1.2.3 From da0420bee24a1ba54e55a61e95b1a53205d7e62d Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 26 Apr 2011 21:54:17 +0000 Subject: sctp: clean up route lookup calls Change the call to take the transport parameter and set the cached 'dst' appropriately inside the get_dst() function calls. This will allow us in the future to clean up source address storage as well. Signed-off-by: Vlad Yasevich Signed-off-by: Wei Yongjun Signed-off-by: David S. Miller --- include/net/sctp/structs.h | 3 +-- net/sctp/ipv6.c | 17 ++++++++--------- net/sctp/protocol.c | 12 +++++------- net/sctp/transport.c | 23 ++++++++++------------- 4 files changed, 24 insertions(+), 31 deletions(-) (limited to 'net/sctp/ipv6.c') diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index bb2f43b7e9a8..ff3e8cce7d66 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -564,8 +564,7 @@ struct sctp_af { int optname, char __user *optval, int __user *optlen); - struct dst_entry *(*get_dst) (struct sctp_association *asoc, - union sctp_addr *daddr, + void (*get_dst) (struct sctp_transport *t, union sctp_addr *saddr, struct flowi *fl, struct sock *sk); diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index a1913a4b6f3a..500875f4dc41 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -247,17 +247,16 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport) /* Returns the dst cache entry for the given source and destination ip * addresses. */ -static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, - union sctp_addr *daddr, - union sctp_addr *saddr, - struct flowi *fl, - struct sock *sk) +static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, + struct flowi *fl, struct sock *sk) { + struct sctp_association *asoc = t->asoc; struct dst_entry *dst = NULL; struct flowi6 *fl6 = &fl->u.ip6; struct sctp_bind_addr *bp; struct sctp_sockaddr_entry *laddr; union sctp_addr *baddr = NULL; + union sctp_addr *daddr = &t->ipaddr; union sctp_addr dst_saddr; __u8 matchlen = 0; __u8 bmatchlen; @@ -270,7 +269,6 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) fl6->flowi6_oif = daddr->v6.sin6_scope_id; - SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6->daddr); if (asoc) @@ -343,12 +341,13 @@ out: if (!IS_ERR(dst)) { struct rt6_info *rt; rt = (struct rt6_info *)dst; + t->dst = dst; SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n", &rt->rt6i_dst.addr, &fl6->saddr); - return dst; + } else { + t->dst = NULL; + SCTP_DEBUG_PRINTK("NO ROUTE\n"); } - SCTP_DEBUG_PRINTK("NO ROUTE\n"); - return NULL; } /* Returns the number of consecutive initial bits that match in the 2 ipv6 diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 68b4c4317d61..9d3f15957d12 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -463,17 +463,16 @@ static sctp_scope_t sctp_v4_scope(union sctp_addr *addr) * addresses. If an association is passed, trys to get a dst entry with a * source address that matches an address in the bind address list. */ -static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, - union sctp_addr *daddr, - union sctp_addr *saddr, - struct flowi *fl, - struct sock *sk) +static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, + struct flowi *fl, struct sock *sk) { + struct sctp_association *asoc = t->asoc; struct rtable *rt; struct flowi4 *fl4 = &fl->u.ip4; struct sctp_bind_addr *bp; struct sctp_sockaddr_entry *laddr; struct dst_entry *dst = NULL; + union sctp_addr *daddr = &t->ipaddr; union sctp_addr dst_saddr; memset(fl4, 0x0, sizeof(struct flowi4)); @@ -548,13 +547,12 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, out_unlock: rcu_read_unlock(); out: + t->dst = dst; if (dst) SCTP_DEBUG_PRINTK("rt_dst:%pI4, rt_src:%pI4\n", &rt->rt_dst, &rt->rt_src); else SCTP_DEBUG_PRINTK("NO ROUTE\n"); - - return dst; } /* For v4, the source address is cached in the route entry(dst). So no need diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 1fbb920f8dfb..d8595dd1a8a7 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -213,17 +213,17 @@ void sctp_transport_set_owner(struct sctp_transport *transport, /* Initialize the pmtu of a transport. */ void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk) { - struct dst_entry *dst; struct flowi fl; - dst = transport->af_specific->get_dst(transport->asoc, - &transport->ipaddr, - &transport->saddr, + /* If we don't have a fresh route, look one up */ + if (!transport->dst || transport->dst->obsolete > 1) { + dst_release(transport->dst); + transport->af_specific->get_dst(transport, &transport->saddr, &fl, sk); + } - if (dst) { - transport->pathmtu = dst_mtu(dst); - dst_release(dst); + if (transport->dst) { + transport->pathmtu = dst_mtu(transport->dst); } else transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT; } @@ -274,12 +274,9 @@ void sctp_transport_route(struct sctp_transport *transport, { struct sctp_association *asoc = transport->asoc; struct sctp_af *af = transport->af_specific; - union sctp_addr *daddr = &transport->ipaddr; - struct dst_entry *dst; struct flowi fl; - dst = af->get_dst(asoc, daddr, saddr, &fl, sctp_opt2sk(opt)); - transport->dst = dst; + af->get_dst(transport, saddr, &fl, sctp_opt2sk(opt)); if (saddr) memcpy(&transport->saddr, saddr, sizeof(union sctp_addr)); @@ -289,8 +286,8 @@ void sctp_transport_route(struct sctp_transport *transport, if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) { return; } - if (dst) { - transport->pathmtu = dst_mtu(dst); + if (transport->dst) { + transport->pathmtu = dst_mtu(transport->dst); /* Initialize sk->sk_rcv_saddr, if the transport is the * association's active path for getsockname(). -- cgit v1.2.3