Skip to content

Commit 8d39b4a

Browse files
wdebruijdavem330
authored andcommitted
packet: parse tpacket header before skb alloc
GSO packet headers must be stored in the linear skb segment. Move tpacket header parsing before sock_alloc_send_skb. The GSO follow-on patch will later increase the skb linear argument to sock_alloc_send_skb if needed for large packets. The header parsing code does not require an allocated skb, so is safe to move. Later pass to tpacket_fill_skb the computed data start and length. Signed-off-by: Willem de Bruijn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 58d19b1 commit 8d39b4a

File tree

1 file changed

+65
-46
lines changed

1 file changed

+65
-46
lines changed

net/packet/af_packet.c

Lines changed: 65 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2494,14 +2494,13 @@ static int packet_snd_vnet_gso(struct sk_buff *skb,
24942494
}
24952495

24962496
static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
2497-
void *frame, struct net_device *dev, int size_max,
2497+
void *frame, struct net_device *dev, void *data, int tp_len,
24982498
__be16 proto, unsigned char *addr, int hlen)
24992499
{
25002500
union tpacket_uhdr ph;
2501-
int to_write, offset, len, tp_len, nr_frags, len_max;
2501+
int to_write, offset, len, nr_frags, len_max;
25022502
struct socket *sock = po->sk.sk_socket;
25032503
struct page *page;
2504-
void *data;
25052504
int err;
25062505

25072506
ph.raw = frame;
@@ -2513,51 +2512,9 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
25132512
sock_tx_timestamp(&po->sk, &skb_shinfo(skb)->tx_flags);
25142513
skb_shinfo(skb)->destructor_arg = ph.raw;
25152514

2516-
switch (po->tp_version) {
2517-
case TPACKET_V2:
2518-
tp_len = ph.h2->tp_len;
2519-
break;
2520-
default:
2521-
tp_len = ph.h1->tp_len;
2522-
break;
2523-
}
2524-
if (unlikely(tp_len > size_max)) {
2525-
pr_err("packet size is too long (%d > %d)\n", tp_len, size_max);
2526-
return -EMSGSIZE;
2527-
}
2528-
25292515
skb_reserve(skb, hlen);
25302516
skb_reset_network_header(skb);
25312517

2532-
if (unlikely(po->tp_tx_has_off)) {
2533-
int off_min, off_max, off;
2534-
off_min = po->tp_hdrlen - sizeof(struct sockaddr_ll);
2535-
off_max = po->tx_ring.frame_size - tp_len;
2536-
if (sock->type == SOCK_DGRAM) {
2537-
switch (po->tp_version) {
2538-
case TPACKET_V2:
2539-
off = ph.h2->tp_net;
2540-
break;
2541-
default:
2542-
off = ph.h1->tp_net;
2543-
break;
2544-
}
2545-
} else {
2546-
switch (po->tp_version) {
2547-
case TPACKET_V2:
2548-
off = ph.h2->tp_mac;
2549-
break;
2550-
default:
2551-
off = ph.h1->tp_mac;
2552-
break;
2553-
}
2554-
}
2555-
if (unlikely((off < off_min) || (off_max < off)))
2556-
return -EINVAL;
2557-
data = ph.raw + off;
2558-
} else {
2559-
data = ph.raw + po->tp_hdrlen - sizeof(struct sockaddr_ll);
2560-
}
25612518
to_write = tp_len;
25622519

25632520
if (sock->type == SOCK_DGRAM) {
@@ -2615,6 +2572,61 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
26152572
return tp_len;
26162573
}
26172574

2575+
static int tpacket_parse_header(struct packet_sock *po, void *frame,
2576+
int size_max, void **data)
2577+
{
2578+
union tpacket_uhdr ph;
2579+
int tp_len, off;
2580+
2581+
ph.raw = frame;
2582+
2583+
switch (po->tp_version) {
2584+
case TPACKET_V2:
2585+
tp_len = ph.h2->tp_len;
2586+
break;
2587+
default:
2588+
tp_len = ph.h1->tp_len;
2589+
break;
2590+
}
2591+
if (unlikely(tp_len > size_max)) {
2592+
pr_err("packet size is too long (%d > %d)\n", tp_len, size_max);
2593+
return -EMSGSIZE;
2594+
}
2595+
2596+
if (unlikely(po->tp_tx_has_off)) {
2597+
int off_min, off_max;
2598+
2599+
off_min = po->tp_hdrlen - sizeof(struct sockaddr_ll);
2600+
off_max = po->tx_ring.frame_size - tp_len;
2601+
if (po->sk.sk_type == SOCK_DGRAM) {
2602+
switch (po->tp_version) {
2603+
case TPACKET_V2:
2604+
off = ph.h2->tp_net;
2605+
break;
2606+
default:
2607+
off = ph.h1->tp_net;
2608+
break;
2609+
}
2610+
} else {
2611+
switch (po->tp_version) {
2612+
case TPACKET_V2:
2613+
off = ph.h2->tp_mac;
2614+
break;
2615+
default:
2616+
off = ph.h1->tp_mac;
2617+
break;
2618+
}
2619+
}
2620+
if (unlikely((off < off_min) || (off_max < off)))
2621+
return -EINVAL;
2622+
} else {
2623+
off = po->tp_hdrlen - sizeof(struct sockaddr_ll);
2624+
}
2625+
2626+
*data = frame + off;
2627+
return tp_len;
2628+
}
2629+
26182630
static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
26192631
{
26202632
struct sk_buff *skb;
@@ -2626,6 +2638,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
26262638
bool need_wait = !(msg->msg_flags & MSG_DONTWAIT);
26272639
int tp_len, size_max;
26282640
unsigned char *addr;
2641+
void *data;
26292642
int len_sum = 0;
26302643
int status = TP_STATUS_AVAILABLE;
26312644
int hlen, tlen;
@@ -2673,6 +2686,11 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
26732686
continue;
26742687
}
26752688

2689+
skb = NULL;
2690+
tp_len = tpacket_parse_header(po, ph, size_max, &data);
2691+
if (tp_len < 0)
2692+
goto tpacket_error;
2693+
26762694
status = TP_STATUS_SEND_REQUEST;
26772695
hlen = LL_RESERVED_SPACE(dev);
26782696
tlen = dev->needed_tailroom;
@@ -2686,14 +2704,15 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
26862704
err = len_sum;
26872705
goto out_status;
26882706
}
2689-
tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto,
2707+
tp_len = tpacket_fill_skb(po, skb, ph, dev, data, tp_len, proto,
26902708
addr, hlen);
26912709
if (likely(tp_len >= 0) &&
26922710
tp_len > dev->mtu + reserve &&
26932711
!packet_extra_vlan_len_allowed(dev, skb))
26942712
tp_len = -EMSGSIZE;
26952713

26962714
if (unlikely(tp_len < 0)) {
2715+
tpacket_error:
26972716
if (po->tp_loss) {
26982717
__packet_set_status(po, ph,
26992718
TP_STATUS_AVAILABLE);

0 commit comments

Comments
 (0)