Skip to content

Commit f970bd9

Browse files
Paolo Abenidavem330
authored andcommitted
udp: implement memory accounting helpers
Avoid using the generic helpers. Use the receive queue spin lock to protect the memory accounting operation, both on enqueue and on dequeue. On dequeue perform partial memory reclaiming, trying to leave a quantum of forward allocated memory. On enqueue use a custom helper, to allow some optimizations: - use a plain spin_lock() variant instead of the slightly costly spin_lock_irqsave(), - avoid dst_force check, since the calling code has already dropped the skb dst - avoid orphaning the skb, since skb_steal_sock() already did the work for us The above needs custom memory reclaiming on shutdown, provided by the udp_destruct_sock(). v5 -> v6: - don't orphan the skb on enqueue v4 -> v5: - replace the mem_lock with the receive queue spin lock - ensure that the bh is always allowed to enqueue at least a skb, even if sk_rcvbuf is exceeded v3 -> v4: - reworked memory accunting, simplifying the schema - provide an helper for both memory scheduling and enqueuing v1 -> v2: - use a udp specific destrctor to perform memory reclaiming - remove a couple of helpers, unneeded after the above cleanup - do not reclaim memory on dequeue if not under memory pressure - reworked the fwd accounting schema to avoid potential integer overflow Acked-by: Hannes Frederic Sowa <[email protected]> Signed-off-by: Paolo Abeni <[email protected]> Acked-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f8c3bf0 commit f970bd9

File tree

2 files changed

+110
-0
lines changed

2 files changed

+110
-0
lines changed

include/net/udp.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,9 @@ static inline __be16 udp_flow_src_port(struct net *net, struct sk_buff *skb,
246246
}
247247

248248
/* net/ipv4/udp.c */
249+
void skb_consume_udp(struct sock *sk, struct sk_buff *skb, int len);
250+
int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb);
251+
249252
void udp_v4_early_demux(struct sk_buff *skb);
250253
int udp_get_port(struct sock *sk, unsigned short snum,
251254
int (*saddr_cmp)(const struct sock *,
@@ -258,6 +261,7 @@ void udp_flush_pending_frames(struct sock *sk);
258261
void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst);
259262
int udp_rcv(struct sk_buff *skb);
260263
int udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
264+
int udp_init_sock(struct sock *sk);
261265
int udp_disconnect(struct sock *sk, int flags);
262266
unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait);
263267
struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,

net/ipv4/udp.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,6 +1172,112 @@ int udp_sendpage(struct sock *sk, struct page *page, int offset,
11721172
return ret;
11731173
}
11741174

1175+
static void udp_rmem_release(struct sock *sk, int size, int partial)
1176+
{
1177+
int amt;
1178+
1179+
atomic_sub(size, &sk->sk_rmem_alloc);
1180+
1181+
spin_lock_bh(&sk->sk_receive_queue.lock);
1182+
sk->sk_forward_alloc += size;
1183+
amt = (sk->sk_forward_alloc - partial) & ~(SK_MEM_QUANTUM - 1);
1184+
sk->sk_forward_alloc -= amt;
1185+
spin_unlock_bh(&sk->sk_receive_queue.lock);
1186+
1187+
if (amt)
1188+
__sk_mem_reduce_allocated(sk, amt >> SK_MEM_QUANTUM_SHIFT);
1189+
}
1190+
1191+
static void udp_rmem_free(struct sk_buff *skb)
1192+
{
1193+
udp_rmem_release(skb->sk, skb->truesize, 1);
1194+
}
1195+
1196+
int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb)
1197+
{
1198+
struct sk_buff_head *list = &sk->sk_receive_queue;
1199+
int rmem, delta, amt, err = -ENOMEM;
1200+
int size = skb->truesize;
1201+
1202+
/* try to avoid the costly atomic add/sub pair when the receive
1203+
* queue is full; always allow at least a packet
1204+
*/
1205+
rmem = atomic_read(&sk->sk_rmem_alloc);
1206+
if (rmem && (rmem + size > sk->sk_rcvbuf))
1207+
goto drop;
1208+
1209+
/* we drop only if the receive buf is full and the receive
1210+
* queue contains some other skb
1211+
*/
1212+
rmem = atomic_add_return(size, &sk->sk_rmem_alloc);
1213+
if ((rmem > sk->sk_rcvbuf) && (rmem > size))
1214+
goto uncharge_drop;
1215+
1216+
spin_lock(&list->lock);
1217+
if (size >= sk->sk_forward_alloc) {
1218+
amt = sk_mem_pages(size);
1219+
delta = amt << SK_MEM_QUANTUM_SHIFT;
1220+
if (!__sk_mem_raise_allocated(sk, delta, amt, SK_MEM_RECV)) {
1221+
err = -ENOBUFS;
1222+
spin_unlock(&list->lock);
1223+
goto uncharge_drop;
1224+
}
1225+
1226+
sk->sk_forward_alloc += delta;
1227+
}
1228+
1229+
sk->sk_forward_alloc -= size;
1230+
1231+
/* the skb owner in now the udp socket */
1232+
skb->sk = sk;
1233+
skb->destructor = udp_rmem_free;
1234+
skb->dev = NULL;
1235+
sock_skb_set_dropcount(sk, skb);
1236+
1237+
__skb_queue_tail(list, skb);
1238+
spin_unlock(&list->lock);
1239+
1240+
if (!sock_flag(sk, SOCK_DEAD))
1241+
sk->sk_data_ready(sk);
1242+
1243+
return 0;
1244+
1245+
uncharge_drop:
1246+
atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
1247+
1248+
drop:
1249+
atomic_inc(&sk->sk_drops);
1250+
return err;
1251+
}
1252+
EXPORT_SYMBOL_GPL(__udp_enqueue_schedule_skb);
1253+
1254+
static void udp_destruct_sock(struct sock *sk)
1255+
{
1256+
/* reclaim completely the forward allocated memory */
1257+
__skb_queue_purge(&sk->sk_receive_queue);
1258+
udp_rmem_release(sk, 0, 0);
1259+
inet_sock_destruct(sk);
1260+
}
1261+
1262+
int udp_init_sock(struct sock *sk)
1263+
{
1264+
sk->sk_destruct = udp_destruct_sock;
1265+
return 0;
1266+
}
1267+
EXPORT_SYMBOL_GPL(udp_init_sock);
1268+
1269+
void skb_consume_udp(struct sock *sk, struct sk_buff *skb, int len)
1270+
{
1271+
if (unlikely(READ_ONCE(sk->sk_peek_off) >= 0)) {
1272+
bool slow = lock_sock_fast(sk);
1273+
1274+
sk_peek_offset_bwd(sk, len);
1275+
unlock_sock_fast(sk, slow);
1276+
}
1277+
consume_skb(skb);
1278+
}
1279+
EXPORT_SYMBOL_GPL(skb_consume_udp);
1280+
11751281
/**
11761282
* first_packet_length - return length of first packet in receive queue
11771283
* @sk: socket

0 commit comments

Comments
 (0)