]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
sctp: add dst_pending_confirm flag
authorJulian Anastasov <ja@ssi.bg>
Fri, 8 Sep 2017 07:01:00 +0000 (09:01 +0200)
committerStefan Bader <stefan.bader@canonical.com>
Fri, 15 Sep 2017 13:53:27 +0000 (15:53 +0200)
BugLink: https://bugs.launchpad.net/bugs/1715812
Add new transport flag to allow sockets to confirm neighbour.
When same struct dst_entry can be used for many different
neighbours we can not use it for pending confirmations.
The flag is propagated from transport to every packet.
It is reset when cached dst is reset.

Reported-by: YueHaibing <yuehaibing@huawei.com>
Fixes: 5110effee8fd ("net: Do delayed neigh confirmation.")
Fixes: f2bb4bedf35d ("ipv4: Cache output routes in fib_info nexthops.")
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Acked-by: Eric Dumazet <edumazet@google.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(backported from commit c86a773c78025f5b825bacd7b846f4fa60dc0317)
Signed-off-by: Daniel Axtens <daniel.axtens@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Acked-by: Colin King <colin.king@canonical.com>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
include/net/sctp/sctp.h
include/net/sctp/structs.h
net/sctp/associola.c
net/sctp/output.c
net/sctp/outqueue.c
net/sctp/sm_make_chunk.c
net/sctp/sm_sideeffect.c
net/sctp/socket.c
net/sctp/transport.c

index d33b17ba51d2ccfdc777ea1e79fc8bd19357b752..12a96f315ff4e116f6658ac31b4ec37d81cbc14d 100644 (file)
@@ -596,10 +596,8 @@ 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, t->dst_cookie)) {
-               dst_release(t->dst);
-               t->dst = NULL;
-       }
+       if (t->dst && !dst_check(t->dst, t->dst_cookie))
+               sctp_transport_dst_release(t);
 
        return t->dst;
 }
index eea9bdeecba27f0ecff39e9d821fc029028f8e5b..422785b7a255dc9ddaff5d014c7d5299581802f8 100644 (file)
@@ -830,6 +830,8 @@ struct sctp_transport {
 
        __u32 burst_limited;    /* Holds old cwnd when max.burst is applied */
 
+       __u32 dst_pending_confirm;      /* need to confirm neighbour */
+
        /* Destination */
        struct dst_entry *dst;
        /* Source address. */
@@ -966,6 +968,8 @@ unsigned long sctp_transport_timeout(struct sctp_transport *);
 void sctp_transport_reset(struct sctp_transport *);
 void sctp_transport_update_pmtu(struct sock *, struct sctp_transport *, u32);
 void sctp_transport_immediate_rtx(struct sctp_transport *);
+void sctp_transport_dst_release(struct sctp_transport *t);
+void sctp_transport_dst_confirm(struct sctp_transport *t);
 
 
 /* This is the structure we use to queue packets as they come into
index 559afd0ee7de099ba013c8921045fedb4e7e5488..7a0e32607c75d08572bcdd4d12a3974c3286c573 100644 (file)
@@ -810,8 +810,7 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
                if (transport->state != SCTP_UNCONFIRMED)
                        transport->state = SCTP_INACTIVE;
                else {
-                       dst_release(transport->dst);
-                       transport->dst = NULL;
+                       sctp_transport_dst_release(transport);
                        ulp_notify = false;
                }
 
index 9d610eddd19ef2320fc34ae9d91e7426ae5f50f9..5d06aaa270ff45cb56d7a9b03ce127844e86683b 100644 (file)
@@ -380,6 +380,7 @@ int sctp_packet_transmit(struct sctp_packet *packet)
 {
        struct sctp_transport *tp = packet->transport;
        struct sctp_association *asoc = tp->asoc;
+       int confirm;
        struct sctphdr *sh;
        struct sk_buff *nskb;
        struct sctp_chunk *chunk, *tmp;
@@ -592,7 +593,14 @@ int sctp_packet_transmit(struct sctp_packet *packet)
        pr_debug("***sctp_transmit_packet*** skb->len:%d\n", nskb->len);
 
        nskb->ignore_df = packet->ipfragok;
-       tp->af_specific->sctp_xmit(nskb, tp);
+       confirm = tp->dst_pending_confirm;
+       if (confirm)
+               skb_set_dst_pending_confirm(nskb, 1);
+       /* neighbour should be confirmed on successful transmission or
+        * positive error
+        */
+       if (tp->af_specific->sctp_xmit(nskb, tp) >= 0 && confirm)
+               tp->dst_pending_confirm = 0;
 
 out:
        sctp_packet_reset(packet);
index c0380cfb16ae4eb77bdab457e8310c0cb15a1c4a..250159d28570e0c7a6a6cc71ee0a6042f6f8b001 100644 (file)
@@ -1563,7 +1563,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
 
                if (forward_progress) {
                        if (transport->dst)
-                               dst_confirm(transport->dst);
+                               sctp_transport_dst_confirm(transport);
                }
        }
 
index 5d6a03fad3789a12290f5f14c5a7efa69c98f41a..1d79c1e48c5e7d2a426e7695b62f7246b347136c 100644 (file)
@@ -3308,8 +3308,7 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,
                local_bh_enable();
                list_for_each_entry(transport, &asoc->peer.transport_addr_list,
                                transports) {
-                       dst_release(transport->dst);
-                       transport->dst = NULL;
+                       sctp_transport_dst_release(transport);
                }
                break;
        case SCTP_PARAM_DEL_IP:
@@ -3323,8 +3322,7 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,
                local_bh_enable();
                list_for_each_entry(transport, &asoc->peer.transport_addr_list,
                                transports) {
-                       dst_release(transport->dst);
-                       transport->dst = NULL;
+                       sctp_transport_dst_release(transport);
                }
                break;
        default:
index 6098d4c42fa91287d3cde36ac05d860f76d4fe32..388307b5e139424ab8ba0146a2e8db6ed9c5429a 100644 (file)
@@ -731,7 +731,7 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
         * forward progress.
         */
        if (t->dst)
-               dst_confirm(t->dst);
+               sctp_transport_dst_confirm(t);
 
        /* The receiver of the HEARTBEAT ACK should also perform an
         * RTT measurement for that destination transport address
index 3ebf3b652d600d75719468018ee8fbfc25114b27..88a67d2401a0a94a3e07c8fe4afad26f6d1af6d2 100644 (file)
@@ -590,7 +590,7 @@ static int sctp_send_asconf_add_ip(struct sock              *sk,
                        list_for_each_entry(trans,
                            &asoc->peer.transport_addr_list, transports) {
                                /* Clear the source and route cache */
-                               dst_release(trans->dst);
+                               sctp_transport_dst_release(trans);
                                trans->cwnd = min(4*asoc->pathmtu, max_t(__u32,
                                    2*asoc->pathmtu, 4380));
                                trans->ssthresh = asoc->peer.i.a_rwnd;
@@ -841,7 +841,7 @@ skip_mkasconf:
                 */
                list_for_each_entry(transport, &asoc->peer.transport_addr_list,
                                        transports) {
-                       dst_release(transport->dst);
+                       sctp_transport_dst_release(transport);
                        sctp_transport_route(transport, NULL,
                                             sctp_sk(asoc->base.sk));
                }
index aab9e3f29755a58eb7584aa763b4b1a46d2e6608..238dd57911fe2f5e0931759615487cc0d032d042 100644 (file)
@@ -222,7 +222,7 @@ void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk)
 {
        /* If we don't have a fresh route, look one up */
        if (!transport->dst || transport->dst->obsolete) {
-               dst_release(transport->dst);
+               sctp_transport_dst_release(transport);
                transport->af_specific->get_dst(transport, &transport->saddr,
                                                &transport->fl, sk);
        }
@@ -654,3 +654,17 @@ void sctp_transport_immediate_rtx(struct sctp_transport *t)
                        sctp_transport_hold(t);
        }
 }
+
+/* Drop dst */
+void sctp_transport_dst_release(struct sctp_transport *t)
+{
+       dst_release(t->dst);
+       t->dst = NULL;
+       t->dst_pending_confirm = 0;
+}
+
+/* Schedule neighbour confirm */
+void sctp_transport_dst_confirm(struct sctp_transport *t)
+{
+       t->dst_pending_confirm = 1;
+}