]> Pileus Git - ~andy/linux/blobdiff - net/sctp/ipv6.c
ipv6: make lookups simpler and faster
[~andy/linux] / net / sctp / ipv6.c
index da613ceae28cc95b38dc1a3d7366c2f38b348d9b..f6334aa19151c84cceebbb32c30670fc985f389c 100644 (file)
@@ -183,7 +183,7 @@ static void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                break;
        case NDISC_REDIRECT:
                sctp_icmp_redirect(sk, transport, skb);
-               break;
+               goto out_unlock;
        default:
                break;
        }
@@ -204,44 +204,23 @@ out:
                in6_dev_put(idev);
 }
 
-/* Based on tcp_v6_xmit() in tcp_ipv6.c. */
 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);
-       struct flowi6 fl6;
-
-       memset(&fl6, 0, sizeof(fl6));
-
-       fl6.flowi6_proto = sk->sk_protocol;
-
-       /* Fill in the dest address from the route entry passed with the skb
-        * and the source address from the transport.
-        */
-       fl6.daddr = transport->ipaddr.v6.sin6_addr;
-       fl6.saddr = transport->saddr.v6.sin6_addr;
-
-       fl6.flowlabel = np->flow_label;
-       IP6_ECN_flow_xmit(sk, fl6.flowlabel);
-       if (ipv6_addr_type(&fl6.saddr) & IPV6_ADDR_LINKLOCAL)
-               fl6.flowi6_oif = transport->saddr.v6.sin6_scope_id;
-       else
-               fl6.flowi6_oif = sk->sk_bound_dev_if;
-
-       if (np->opt && np->opt->srcrt) {
-               struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
-               fl6.daddr = *rt0->addr;
-       }
+       struct flowi6 *fl6 = &transport->fl.u.ip6;
 
        pr_debug("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", __func__, skb,
-                skb->len, &fl6.saddr, &fl6.daddr);
+                skb->len, &fl6->saddr, &fl6->daddr);
 
-       SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS);
+       IP6_ECN_flow_xmit(sk, fl6->flowlabel);
 
        if (!(transport->param_flags & SPP_PMTUD_ENABLE))
                skb->local_df = 1;
 
-       return ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
+       SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS);
+
+       return ip6_xmit(sk, skb, fl6, np->opt, np->tclass);
 }
 
 /* Returns the dst cache entry for the given source and destination ip
@@ -254,10 +233,12 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
        struct dst_entry *dst = NULL;
        struct flowi6 *fl6 = &fl->u.ip6;
        struct sctp_bind_addr *bp;
+       struct ipv6_pinfo *np = inet6_sk(sk);
        struct sctp_sockaddr_entry *laddr;
        union sctp_addr *baddr = NULL;
        union sctp_addr *daddr = &t->ipaddr;
        union sctp_addr dst_saddr;
+       struct in6_addr *final_p, final;
        __u8 matchlen = 0;
        __u8 bmatchlen;
        sctp_scope_t scope;
@@ -281,7 +262,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
                pr_debug("src=%pI6 - ", &fl6->saddr);
        }
 
-       dst = ip6_dst_lookup_flow(sk, fl6, NULL, false);
+       final_p = fl6_update_dst(fl6, np->opt, &final);
+       dst = ip6_dst_lookup_flow(sk, fl6, final_p, false);
        if (!asoc || saddr)
                goto out;
 
@@ -333,10 +315,12 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
                }
        }
        rcu_read_unlock();
+
        if (baddr) {
                fl6->saddr = baddr->v6.sin6_addr;
                fl6->fl6_sport = baddr->v6.sin6_port;
-               dst = ip6_dst_lookup_flow(sk, fl6, NULL, false);
+               final_p = fl6_update_dst(fl6, np->opt, &final);
+               dst = ip6_dst_lookup_flow(sk, fl6, final_p, false);
        }
 
 out:
@@ -442,20 +426,20 @@ static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk)
 {
        addr->v6.sin6_family = AF_INET6;
        addr->v6.sin6_port = 0;
-       addr->v6.sin6_addr = inet6_sk(sk)->rcv_saddr;
+       addr->v6.sin6_addr = sk->sk_v6_rcv_saddr;
 }
 
 /* Initialize sk->sk_rcv_saddr from sctp_addr. */
 static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
 {
        if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) {
-               inet6_sk(sk)->rcv_saddr.s6_addr32[0] = 0;
-               inet6_sk(sk)->rcv_saddr.s6_addr32[1] = 0;
-               inet6_sk(sk)->rcv_saddr.s6_addr32[2] = htonl(0x0000ffff);
-               inet6_sk(sk)->rcv_saddr.s6_addr32[3] =
+               sk->sk_v6_rcv_saddr.s6_addr32[0] = 0;
+               sk->sk_v6_rcv_saddr.s6_addr32[1] = 0;
+               sk->sk_v6_rcv_saddr.s6_addr32[2] = htonl(0x0000ffff);
+               sk->sk_v6_rcv_saddr.s6_addr32[3] =
                        addr->v4.sin_addr.s_addr;
        } else {
-               inet6_sk(sk)->rcv_saddr = addr->v6.sin6_addr;
+               sk->sk_v6_rcv_saddr = addr->v6.sin6_addr;
        }
 }
 
@@ -463,12 +447,12 @@ static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
 static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
 {
        if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) {
-               inet6_sk(sk)->daddr.s6_addr32[0] = 0;
-               inet6_sk(sk)->daddr.s6_addr32[1] = 0;
-               inet6_sk(sk)->daddr.s6_addr32[2] = htonl(0x0000ffff);
-               inet6_sk(sk)->daddr.s6_addr32[3] = addr->v4.sin_addr.s_addr;
+               sk->sk_v6_daddr.s6_addr32[0] = 0;
+               sk->sk_v6_daddr.s6_addr32[1] = 0;
+               sk->sk_v6_daddr.s6_addr32[2] = htonl(0x0000ffff);
+               sk->sk_v6_daddr.s6_addr32[3] = addr->v4.sin_addr.s_addr;
        } else {
-               inet6_sk(sk)->daddr = addr->v6.sin6_addr;
+               sk->sk_v6_daddr = addr->v6.sin6_addr;
        }
 }