On 1/23/18, 9:30 AM, "Yuchung Cheng" <ych...@google.com> wrote:

    The original patch that changes TCP's congestion control via eBPF only
    re-initializes the new congestion control, if the BPF op is set to an
    (invalid) value beyond BPF_SOCK_OPS_NEEDS_ECN. Consequently TCP will

What do you mean by “(invalid) value”?

    run the new congestion control from random states. 

This has always been possible with setsockopt, no?

   This patch fixes
    the issue by always re-init the congestion control like other means
    such as setsockopt and sysctl changes.

The current code re-inits the congestion control when calling 
tcp_set_congestion_control except when it is called early on (i.e. op <= 
BPF_SOCK_OPS_NEEDS_ECN). In that case there is no need to re-initialize
since it will be initialized later by TCP when the connection is established.

Otherwise, if we always call tcp_reinit_congestion_control we would call 
tcp_cleanup_congestion_control when the congestion control has not been
initialized yet.


    Fixes: 91b5b21c7c16 ("bpf: Add support for changing congestion control")
    Signed-off-by: Yuchung Cheng <ych...@google.com>
    Signed-off-by: Eric Dumazet <eduma...@google.com>
    Signed-off-by: Neal Cardwell <ncardw...@google.com>
    Signed-off-by: Soheil Hassas Yeganeh <soh...@google.com>
    ---
     include/net/tcp.h   |  2 +-
     net/core/filter.c   |  3 +--
     net/ipv4/tcp.c      |  2 +-
     net/ipv4/tcp_cong.c | 11 ++---------
     4 files changed, 5 insertions(+), 13 deletions(-)
    
    diff --git a/include/net/tcp.h b/include/net/tcp.h
    index 6da880d2f022..f94a71b62ba5 100644
    --- a/include/net/tcp.h
    +++ b/include/net/tcp.h
    @@ -1006,7 +1006,7 @@ void tcp_get_default_congestion_control(struct net 
*net, char *name);
     void tcp_get_available_congestion_control(char *buf, size_t len);
     void tcp_get_allowed_congestion_control(char *buf, size_t len);
     int tcp_set_allowed_congestion_control(char *allowed);
    -int tcp_set_congestion_control(struct sock *sk, const char *name, bool 
load, bool reinit);
    +int tcp_set_congestion_control(struct sock *sk, const char *name, bool 
load);
     u32 tcp_slow_start(struct tcp_sock *tp, u32 acked);
     void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w, u32 acked);
     
    diff --git a/net/core/filter.c b/net/core/filter.c
    index 6a85e67fafce..757d52adccfc 100644
    --- a/net/core/filter.c
    +++ b/net/core/filter.c
    @@ -3233,12 +3233,11 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern 
*, bpf_sock,
                   sk->sk_prot->setsockopt == tcp_setsockopt) {
                if (optname == TCP_CONGESTION) {
                        char name[TCP_CA_NAME_MAX];
    -                   bool reinit = bpf_sock->op > BPF_SOCK_OPS_NEEDS_ECN;
     
                        strncpy(name, optval, min_t(long, optlen,
                                                    TCP_CA_NAME_MAX-1));
                        name[TCP_CA_NAME_MAX-1] = 0;
    -                   ret = tcp_set_congestion_control(sk, name, false, 
reinit);
    +                   ret = tcp_set_congestion_control(sk, name, false);
                } else {
                        struct tcp_sock *tp = tcp_sk(sk);
     
    diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
    index f08eebe60446..21e2a07e857e 100644
    --- a/net/ipv4/tcp.c
    +++ b/net/ipv4/tcp.c
    @@ -2550,7 +2550,7 @@ static int do_tcp_setsockopt(struct sock *sk, int 
level,
                name[val] = 0;
     
                lock_sock(sk);
    -           err = tcp_set_congestion_control(sk, name, true, true);
    +           err = tcp_set_congestion_control(sk, name, true);
                release_sock(sk);
                return err;
        }
    diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
    index bc6c02f16243..70895bee3026 100644
    --- a/net/ipv4/tcp_cong.c
    +++ b/net/ipv4/tcp_cong.c
    @@ -332,7 +332,7 @@ int tcp_set_allowed_congestion_control(char *val)
      * tcp_reinit_congestion_control (if the current congestion control was
      * already initialized.
      */
    -int tcp_set_congestion_control(struct sock *sk, const char *name, bool 
load, bool reinit)
    +int tcp_set_congestion_control(struct sock *sk, const char *name, bool 
load)
     {
        struct inet_connection_sock *icsk = inet_csk(sk);
        const struct tcp_congestion_ops *ca;
    @@ -356,15 +356,8 @@ int tcp_set_congestion_control(struct sock *sk, const 
char *name, bool load, boo
        if (!ca) {
                err = -ENOENT;
        } else if (!load) {
    -           const struct tcp_congestion_ops *old_ca = icsk->icsk_ca_ops;
    -
                if (try_module_get(ca->owner)) {
    -                   if (reinit) {
    -                           tcp_reinit_congestion_control(sk, ca);
    -                   } else {
    -                           icsk->icsk_ca_ops = ca;
    -                           module_put(old_ca->owner);
    -                   }
    +                   tcp_reinit_congestion_control(sk, ca);
                } else {
                        err = -EBUSY;
                }
    -- 
    2.16.0.rc1.238.g530d649a79-goog
    
    

Reply via email to