diff --git a/include/net/tcp.h b/include/net/tcp.h index f858278..4550c25 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -968,8 +968,9 @@ static inline int tcp_win_from_space(int space) /* Note: caller must be prepared to deal with negative returns */ static inline int tcp_space(const struct sock *sk) { - return tcp_win_from_space(sk->sk_rcvbuf - - atomic_read(&sk->sk_rmem_alloc)); + int ub_tcp_rcvbuf = (int) sock_bc(sk)->ub_tcp_rcvbuf; + return tcp_win_from_space(min(sk->sk_rcvbuf, ub_tcp_rcvbuf) + - atomic_read(&sk->sk_rmem_alloc)); } static inline int tcp_full_space(const struct sock *sk) diff --git a/include/ub/beancounter.h b/include/ub/beancounter.h index d984883..c204e15 100644 --- a/include/ub/beancounter.h +++ b/include/ub/beancounter.h @@ -151,6 +151,8 @@ struct sock_private { unsigned long ubp_rmem_thres; unsigned long ubp_wmem_pressure; unsigned long ubp_maxadvmss; + /* Total size of all advertised receive windows for all tcp sockets */ + unsigned long ubp_rcv_wnd; unsigned long ubp_rmem_pressure; int ubp_tw_count; #define UB_RMEM_EXPAND 0 @@ -218,6 +220,7 @@ struct user_beancounter struct sock_private spriv; #define ub_rmem_thres spriv.ubp_rmem_thres #define ub_maxadvmss spriv.ubp_maxadvmss +#define ub_rcv_wnd spriv.ubp_rcv_wnd #define ub_rmem_pressure spriv.ubp_rmem_pressure #define ub_wmem_pressure spriv.ubp_wmem_pressure #define ub_tcp_sk_list spriv.ubp_tcp_socks diff --git a/include/ub/ub_sk.h b/include/ub/ub_sk.h index 45f29be..1969593 100644 --- a/include/ub/ub_sk.h +++ b/include/ub/ub_sk.h @@ -34,6 +34,8 @@ struct sock_beancounter { */ unsigned long poll_reserv; unsigned long forw_space; + unsigned long ub_tcp_rcvbuf; + unsigned long ub_rcv_wnd_old; /* fields below are protected by bc spinlock */ unsigned long ub_waitspc; /* space waiting for */ unsigned long ub_wcharged; diff --git a/kernel/ub/ub_net.c b/kernel/ub/ub_net.c index fb2ac24..bfe925e 100644 --- a/kernel/ub/ub_net.c +++ b/kernel/ub/ub_net.c @@ -424,6 +424,7 @@ static int __sock_charge(struct sock *sk, int res) added_reserv = 0; added_forw = 0; + skbc->ub_rcv_wnd_old = 0; if (res == UB_NUMTCPSOCK) { added_reserv = skb_charge_size(MAX_TCP_HEADER + 1500 - sizeof(struct iphdr) - @@ -443,6 +444,7 @@ static int __sock_charge(struct sock *sk, int res) added_forw = 0; } skbc->forw_space = added_forw; + skbc->ub_tcp_rcvbuf = added_forw + SK_STREAM_MEM_QUANTUM; } spin_unlock_irqrestore(&ub->ub_lock, flags); @@ -533,6 +535,7 @@ void ub_sock_uncharge(struct sock *sk) skbc->ub_wcharged, skbc->ub, skbc->ub->ub_uid); skbc->poll_reserv = 0; skbc->forw_space = 0; + ub->ub_rcv_wnd -= is_tcp_sock ? tcp_sk(sk)->rcv_wnd : 0; spin_unlock_irqrestore(&ub->ub_lock, flags); uncharge_beancounter_notop(skbc->ub, @@ -793,6 +796,44 @@ static void ub_sockrcvbuf_uncharge(struct sk_buff *skb) * UB_TCPRCVBUF */ +/* + * UBC TCP window management mechanism. + * Every socket may consume no more than sock_quantum. + * sock_quantum depends on space available and ub_parms[UB_NUMTCPSOCK].held. + */ +static void ub_sock_tcp_update_rcvbuf(struct user_beancounter *ub, + struct sock *sk) +{ + unsigned long allowed; + unsigned long reserved; + unsigned long available; + unsigned long sock_quantum; + struct tcp_sock *tp = tcp_sk(sk); + struct sock_beancounter *skbc; + skbc = sock_bc(sk); + + if( ub->ub_parms[UB_NUMTCPSOCK].limit * ub->ub_maxadvmss + > ub->ub_parms[UB_TCPRCVBUF].limit) { + /* this is defenitly shouldn't happend */ + return; + } + allowed = ub->ub_parms[UB_TCPRCVBUF].barrier; + ub->ub_rcv_wnd += (tp->rcv_wnd - skbc->ub_rcv_wnd_old); + skbc->ub_rcv_wnd_old = tp->rcv_wnd; + reserved = ub->ub_parms[UB_TCPRCVBUF].held + ub->ub_rcv_wnd; + available = (allowed < reserved)? + 0:allowed - reserved; + sock_quantum = max(allowed / ub->ub_parms[UB_NUMTCPSOCK].held, + ub->ub_maxadvmss); + if ( skbc->ub_tcp_rcvbuf > sock_quantum) { + skbc->ub_tcp_rcvbuf = sock_quantum; + } else { + skbc->ub_tcp_rcvbuf += min(sock_quantum - skbc->ub_tcp_rcvbuf, + available); + } + +} + int ub_sock_tcp_chargerecv(struct sock *sk, struct sk_buff *skb, enum ub_severity strict) { @@ -829,7 +870,9 @@ int ub_sock_tcp_chargerecv(struct sock *sk, struct sk_buff *skb, retval = 0; ub = top_beancounter(sock_bc(sk)->ub); spin_lock_irqsave(&ub->ub_lock, flags); + ub_sock_tcp_update_rcvbuf(ub, sk); ub->ub_parms[UB_TCPRCVBUF].held += chargesize; + ub_sock_tcp_update_rcvbuf(ub, sk); if (ub->ub_parms[UB_TCPRCVBUF].held > ub->ub_parms[UB_TCPRCVBUF].barrier && strict != UB_FORCE)