net: tcp: add flag for ca to indicate that ECN is required
[deliverable/linux.git] / include / net / tcp.h
index f99b0c072ee52d2d0da5b39d9892a8ad37d5d7fc..a12f145cfbc3d1b79de330269b3dbe53aeba8b2e 100644 (file)
@@ -733,23 +733,6 @@ struct tcp_skb_cb {
 
 #define TCP_SKB_CB(__skb)      ((struct tcp_skb_cb *)&((__skb)->cb[0]))
 
-/* RFC3168 : 6.1.1 SYN packets must not have ECT/ECN bits set
- *
- * If we receive a SYN packet with these bits set, it means a network is
- * playing bad games with TOS bits. In order to avoid possible false congestion
- * notifications, we disable TCP ECN negociation.
- */
-static inline void
-TCP_ECN_create_request(struct request_sock *req, const struct sk_buff *skb,
-               struct net *net)
-{
-       const struct tcphdr *th = tcp_hdr(skb);
-
-       if (net->ipv4.sysctl_tcp_ecn && th->ece && th->cwr &&
-           INET_ECN_is_not_ect(TCP_SKB_CB(skb)->ip_dsfield))
-               inet_rsk(req)->ecn_ok = 1;
-}
-
 /* Due to TSO, an SKB can be composed of multiple actual
  * packets.  To keep these tracked properly, we use this.
  */
@@ -791,7 +774,10 @@ enum tcp_ca_event {
 #define TCP_CA_MAX     128
 #define TCP_CA_BUF_MAX (TCP_CA_NAME_MAX*TCP_CA_MAX)
 
+/* Algorithm can be set on socket without CAP_NET_ADMIN privileges */
 #define TCP_CONG_NON_RESTRICTED 0x1
+/* Requires ECN/ECT set on all packets */
+#define TCP_CONG_NEEDS_ECN     0x2
 
 struct tcp_congestion_ops {
        struct list_head        list;
@@ -840,6 +826,13 @@ u32 tcp_reno_ssthresh(struct sock *sk);
 void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 acked);
 extern struct tcp_congestion_ops tcp_reno;
 
+static inline bool tcp_ca_needs_ecn(const struct sock *sk)
+{
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+
+       return icsk->icsk_ca_ops->flags & TCP_CONG_NEEDS_ECN;
+}
+
 static inline void tcp_set_ca_state(struct sock *sk, const u8 ca_state)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
@@ -857,6 +850,40 @@ static inline void tcp_ca_event(struct sock *sk, const enum tcp_ca_event event)
                icsk->icsk_ca_ops->cwnd_event(sk, event);
 }
 
+/* RFC3168 : 6.1.1 SYN packets must not have ECT/ECN bits set
+ *
+ * If we receive a SYN packet with these bits set, it means a
+ * network is playing bad games with TOS bits. In order to
+ * avoid possible false congestion notifications, we disable
+ * TCP ECN negociation.
+ *
+ * Exception: tcp_ca wants ECN. This is required for DCTCP
+ * congestion control; it requires setting ECT on all packets,
+ * including SYN. We inverse the test in this case: If our
+ * local socket wants ECN, but peer only set ece/cwr (but not
+ * ECT in IP header) its probably a non-DCTCP aware sender.
+ */
+static inline void
+TCP_ECN_create_request(struct request_sock *req, const struct sk_buff *skb,
+                      const struct sock *listen_sk)
+{
+       const struct tcphdr *th = tcp_hdr(skb);
+       const struct net *net = sock_net(listen_sk);
+       bool th_ecn = th->ece && th->cwr;
+       bool ect, need_ecn;
+
+       if (!th_ecn)
+               return;
+
+       ect = !INET_ECN_is_not_ect(TCP_SKB_CB(skb)->ip_dsfield);
+       need_ecn = tcp_ca_needs_ecn(listen_sk);
+
+       if (!ect && !need_ecn && net->ipv4.sysctl_tcp_ecn)
+               inet_rsk(req)->ecn_ok = 1;
+       else if (ect && need_ecn)
+               inet_rsk(req)->ecn_ok = 1;
+}
+
 /* These functions determine how the current flow behaves in respect of SACK
  * handling. SACK is negotiated with the peer, and therefore it can vary
  * between different flows.
This page took 0.046573 seconds and 5 git commands to generate.