We would like that optional info provided by Congestion Control modules using netlink can also be read using getsockopt() This patch changes get_info() to put this information in a buffer, instead of skb, like tcp_get_info(), so that following patch can reuse this common infrastructure.
Unified · Split
| @@ -804,6 +804,8 @@ enum tcp_ca_ack_event_flags { · 803 unmodified lines | ||
| 804 | 804 | /* Requires ECN/ECT set on all packets */ |
| 805 | 805 | #define TCP_CONG_NEEDS_ECN 0x2 |
| 806 | 806 | |
| 807 | +union tcp_cc_info; | |
| 808 | + | |
| 807 | 809 | struct tcp_congestion_ops { |
| 808 | 810 | struct list_head list; |
| 809 | 811 | u32 key; |
| @@ -829,7 +831,8 @@ struct tcp_congestion_ops { · 19 unmodified lines | ||
| 829 | 831 | /* hook for packet ack accounting (optional) */ |
| 830 | 832 | void (*pkts_acked)(struct sock *sk, u32 num_acked, s32 rtt_us); |
| 831 | 833 | /* get info for inet_diag (optional) */ |
| 832 | − int (*get_info)(struct sock *sk, u32 ext, struct sk_buff *skb); | |
| 834 | + size_t (*get_info)(struct sock *sk, u32 ext, int *attr, | |
| 835 | + union tcp_cc_info *info); | |
| 833 | 836 | |
| 834 | 837 | char name[TCP_CA_NAME_MAX]; |
| 835 | 838 | struct module *owner; |
| @@ -143,4 +143,8 @@ struct tcp_dctcp_info { · 142 unmodified lines | ||
| 143 | 143 | __u32 dctcp_ab_tot; |
| 144 | 144 | }; |
| 145 | 145 | |
| 146 | +union tcp_cc_info { | |
| 147 | + struct tcpvegas_info vegas; | |
| 148 | + struct tcp_dctcp_info dctcp; | |
| 149 | +}; | |
| 146 | 150 | #endif /* _UAPI_INET_DIAG_H_ */ |
| @@ -224,14 +224,16 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, · 223 unmodified lines | ||
| 224 | 224 | handler->idiag_get_info(sk, r, info); |
| 225 | 225 | |
| 226 | 226 | if (sk->sk_state < TCP_TIME_WAIT) { |
| 227 | − int err = 0; | |
| 227 | + union tcp_cc_info info; | |
| 228 | + size_t sz = 0; | |
| 229 | + int attr; | |
| 228 | 230 | |
| 229 | 231 | rcu_read_lock(); |
| 230 | 232 | ca_ops = READ_ONCE(icsk->icsk_ca_ops); |
| 231 | 233 | if (ca_ops && ca_ops->get_info) |
| 232 | − err = ca_ops->get_info(sk, ext, skb); | |
| 234 | + sz = ca_ops->get_info(sk, ext, &attr, &info); | |
| 233 | 235 | rcu_read_unlock(); |
| 234 | − if (err < 0) | |
| 236 | + if (sz && nla_put(skb, attr, sz, &info) < 0) | |
| 235 | 237 | goto errout; |
| 236 | 238 | } |
| 237 | 239 | |
| @@ -277,7 +277,8 @@ static void dctcp_cwnd_event(struct sock *sk, enum tcp_ca_event ev) · 276 unmodified lines | ||
| 277 | 277 | } |
| 278 | 278 | } |
| 279 | 279 | |
| 280 | −static int dctcp_get_info(struct sock *sk, u32 ext, struct sk_buff *skb) | |
| 280 | +static size_t dctcp_get_info(struct sock *sk, u32 ext, int *attr, | |
| 281 | + union tcp_cc_info *info) | |
| 281 | 282 | { |
| 282 | 283 | const struct dctcp *ca = inet_csk_ca(sk); |
| 283 | 284 | |
| @@ -286,18 +287,17 @@ static int dctcp_get_info(struct sock *sk, u32 ext, struct sk_buff *skb) · 2 unmodified lines | ||
| 286 | 287 | */ |
| 287 | 288 | if (ext & (1 << (INET_DIAG_DCTCPINFO - 1)) || |
| 288 | 289 | ext & (1 << (INET_DIAG_VEGASINFO - 1))) { |
| 289 | − struct tcp_dctcp_info info; | |
| 290 | − | |
| 291 | − memset(&info, 0, sizeof(info)); | |
| 290 | + memset(info, 0, sizeof(struct tcp_dctcp_info)); | |
| 292 | 291 | if (inet_csk(sk)->icsk_ca_ops != &dctcp_reno) { |
| 293 | − info.dctcp_enabled = 1; | |
| 294 | − info.dctcp_ce_state = (u16) ca->ce_state; | |
| 295 | − info.dctcp_alpha = ca->dctcp_alpha; | |
| 296 | − info.dctcp_ab_ecn = ca->acked_bytes_ecn; | |
| 297 | − info.dctcp_ab_tot = ca->acked_bytes_total; | |
| 292 | + info->dctcp.dctcp_enabled = 1; | |
| 293 | + info->dctcp.dctcp_ce_state = (u16) ca->ce_state; | |
| 294 | + info->dctcp.dctcp_alpha = ca->dctcp_alpha; | |
| 295 | + info->dctcp.dctcp_ab_ecn = ca->acked_bytes_ecn; | |
| 296 | + info->dctcp.dctcp_ab_tot = ca->acked_bytes_total; | |
| 298 | 297 | } |
| 299 | 298 | |
| 300 | − return nla_put(skb, INET_DIAG_DCTCPINFO, sizeof(info), &info); | |
| 299 | + *attr = INET_DIAG_DCTCPINFO; | |
| 300 | + return sizeof(*info); | |
| 301 | 301 | } |
| 302 | 302 | return 0; |
| 303 | 303 | } |
| @@ -300,24 +300,25 @@ static u32 tcp_illinois_ssthresh(struct sock *sk) · 299 unmodified lines | ||
| 300 | 300 | } |
| 301 | 301 | |
| 302 | 302 | /* Extract info for Tcp socket info provided via netlink. */ |
| 303 | −static int tcp_illinois_info(struct sock *sk, u32 ext, struct sk_buff *skb) | |
| 303 | +static size_t tcp_illinois_info(struct sock *sk, u32 ext, int *attr, | |
| 304 | + union tcp_cc_info *info) | |
| 304 | 305 | { |
| 305 | 306 | const struct illinois *ca = inet_csk_ca(sk); |
| 306 | 307 | |
| 307 | 308 | if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) { |
| 308 | − struct tcpvegas_info info = { | |
| 309 | − .tcpv_enabled = 1, | |
| 310 | − .tcpv_rttcnt = ca->cnt_rtt, | |
| 311 | − .tcpv_minrtt = ca->base_rtt, | |
| 312 | − }; | |
| 309 | + info->vegas.tcpv_enabled = 1; | |
| 310 | + info->vegas.tcpv_rttcnt = ca->cnt_rtt; | |
| 311 | + info->vegas.tcpv_minrtt = ca->base_rtt; | |
| 312 | + info->vegas.tcpv_rtt = 0; | |
| 313 | 313 | |
| 314 | − if (info.tcpv_rttcnt > 0) { | |
| 314 | + if (info->vegas.tcpv_rttcnt > 0) { | |
| 315 | 315 | u64 t = ca->sum_rtt; |
| 316 | 316 | |
| 317 | − do_div(t, info.tcpv_rttcnt); | |
| 318 | − info.tcpv_rtt = t; | |
| 317 | + do_div(t, info->vegas.tcpv_rttcnt); | |
| 318 | + info->vegas.tcpv_rtt = t; | |
| 319 | 319 | } |
| 320 | − return nla_put(skb, INET_DIAG_VEGASINFO, sizeof(info), &info); | |
| 320 | + *attr = INET_DIAG_VEGASINFO; | |
| 321 | + return sizeof(struct tcpvegas_info); | |
| 321 | 322 | } |
| 322 | 323 | return 0; |
| 323 | 324 | } |
| @@ -286,18 +286,19 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) · 285 unmodified lines | ||
| 286 | 286 | } |
| 287 | 287 | |
| 288 | 288 | /* Extract info for Tcp socket info provided via netlink. */ |
| 289 | −int tcp_vegas_get_info(struct sock *sk, u32 ext, struct sk_buff *skb) | |
| 289 | +size_t tcp_vegas_get_info(struct sock *sk, u32 ext, int *attr, | |
| 290 | + union tcp_cc_info *info) | |
| 290 | 291 | { |
| 291 | 292 | const struct vegas *ca = inet_csk_ca(sk); |
| 293 | + | |
| 292 | 294 | if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) { |
| 293 | − struct tcpvegas_info info = { | |
| 294 | − .tcpv_enabled = ca->doing_vegas_now, | |
| 295 | − .tcpv_rttcnt = ca->cntRTT, | |
| 296 | − .tcpv_rtt = ca->baseRTT, | |
| 297 | − .tcpv_minrtt = ca->minRTT, | |
| 298 | − }; | |
| 299 | − | |
| 300 | − return nla_put(skb, INET_DIAG_VEGASINFO, sizeof(info), &info); | |
| 295 | + info->vegas.tcpv_enabled = ca->doing_vegas_now, | |
| 296 | + info->vegas.tcpv_rttcnt = ca->cntRTT, | |
| 297 | + info->vegas.tcpv_rtt = ca->baseRTT, | |
| 298 | + info->vegas.tcpv_minrtt = ca->minRTT, | |
| 299 | + | |
| 300 | + *attr = INET_DIAG_VEGASINFO; | |
| 301 | + return sizeof(struct tcpvegas_info); | |
| 301 | 302 | } |
| 302 | 303 | return 0; |
| 303 | 304 | } |
| @@ -19,6 +19,7 @@ void tcp_vegas_init(struct sock *sk); · 18 unmodified lines | ||
| 19 | 19 | void tcp_vegas_state(struct sock *sk, u8 ca_state); |
| 20 | 20 | void tcp_vegas_pkts_acked(struct sock *sk, u32 cnt, s32 rtt_us); |
| 21 | 21 | void tcp_vegas_cwnd_event(struct sock *sk, enum tcp_ca_event event); |
| 22 | −int tcp_vegas_get_info(struct sock *sk, u32 ext, struct sk_buff *skb); | |
| 22 | +size_t tcp_vegas_get_info(struct sock *sk, u32 ext, int *attr, | |
| 23 | + union tcp_cc_info *info); | |
| 23 | 24 | |
| 24 | 25 | #endif /* __TCP_VEGAS_H */ |