Skip to content

Commit 8092a12

Browse files
jsitnickiKernel Patches Daemon
authored andcommitted
net: Track skb metadata end separately from MAC offset
Currently skb metadata location is derived from the MAC header offset. This breaks when L2 tunnel/tagging devices (VLAN, GRE, etc.) reset the MAC offset after pulling the encapsulation header, making the metadata inaccessible. A naive fix would be to move metadata on every skb_pull() path. However, we can avoid a memmove on L2 decapsulation if we can locate metadata independently of the MAC offset. Introduce a meta_end field in skb_shared_info to track where metadata ends, decoupling it from mac_header. The new field takes 2 bytes out of the existing 4 byte hole, with structure size unchanged if we reorder the gso_type field. Update skb_metadata_set() to record meta_end at the time of the call, and adjust skb_data_move() and pskb_expand_head() to keep meta_end in sync with head buffer layout. Remove the now-unneeded metadata adjustment in skb_reorder_vlan_header(). Note that this breaks BPF skb metadata access through skb->data_meta when there is a gap between meta_end and skb->data. Following BPF verifier changes address this. Also, we still need to relocate the metadata on encapsulation on forward path. VLAN and QinQ have already been patched when fixing TC BPF helpers [1], but other tagging/tunnel code still requires similar changes. This will be done as a follow up. Signed-off-by: Jakub Sitnicki <[email protected]>
1 parent 9df90a8 commit 8092a12

File tree

2 files changed

+14
-10
lines changed

2 files changed

+14
-10
lines changed

include/linux/skbuff.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -595,15 +595,16 @@ struct skb_shared_info {
595595
__u8 meta_len;
596596
__u8 nr_frags;
597597
__u8 tx_flags;
598+
u16 meta_end;
598599
unsigned short gso_size;
599600
/* Warning: this field is not always filled in (UFO)! */
600601
unsigned short gso_segs;
602+
unsigned int gso_type;
601603
struct sk_buff *frag_list;
602604
union {
603605
struct skb_shared_hwtstamps hwtstamps;
604606
struct xsk_tx_metadata_compl xsk_meta;
605607
};
606-
unsigned int gso_type;
607608
u32 tskey;
608609

609610
/*
@@ -4499,7 +4500,7 @@ static inline u8 skb_metadata_len(const struct sk_buff *skb)
44994500

45004501
static inline void *skb_metadata_end(const struct sk_buff *skb)
45014502
{
4502-
return skb_mac_header(skb);
4503+
return skb->head + skb_shinfo(skb)->meta_end;
45034504
}
45044505

45054506
static inline bool __skb_metadata_differs(const struct sk_buff *skb_a,
@@ -4554,8 +4555,16 @@ static inline bool skb_metadata_differs(const struct sk_buff *skb_a,
45544555
true : __skb_metadata_differs(skb_a, skb_b, len_a);
45554556
}
45564557

4558+
/**
4559+
* skb_metadata_set - Record packet metadata length and location.
4560+
* @skb: packet carrying the metadata
4561+
* @meta_len: number of bytes of metadata preceding skb->data
4562+
*
4563+
* Must be called when skb->data already points past the metadata area.
4564+
*/
45574565
static inline void skb_metadata_set(struct sk_buff *skb, u8 meta_len)
45584566
{
4567+
skb_shinfo(skb)->meta_end = skb_headroom(skb);
45594568
skb_shinfo(skb)->meta_len = meta_len;
45604569
}
45614570

@@ -4601,6 +4610,7 @@ static inline void skb_data_move(struct sk_buff *skb, const int len,
46014610
}
46024611

46034612
memmove(meta + len, meta, meta_len + n);
4613+
skb_shinfo(skb)->meta_end += len;
46044614
return;
46054615

46064616
no_metadata:

net/core/skbuff.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2306,6 +2306,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
23062306
#endif
23072307
skb->tail += off;
23082308
skb_headers_offset_update(skb, nhead);
2309+
skb_shinfo(skb)->meta_end += nhead;
23092310
skb->cloned = 0;
23102311
skb->hdr_len = 0;
23112312
skb->nohdr = 0;
@@ -6219,8 +6220,7 @@ EXPORT_SYMBOL_GPL(skb_scrub_packet);
62196220

62206221
static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb)
62216222
{
6222-
int mac_len, meta_len;
6223-
void *meta;
6223+
int mac_len;
62246224

62256225
if (skb_cow(skb, skb_headroom(skb)) < 0) {
62266226
kfree_skb(skb);
@@ -6233,12 +6233,6 @@ static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb)
62336233
mac_len - VLAN_HLEN - ETH_TLEN);
62346234
}
62356235

6236-
meta_len = skb_metadata_len(skb);
6237-
if (meta_len) {
6238-
meta = skb_metadata_end(skb) - meta_len;
6239-
memmove(meta + VLAN_HLEN, meta, meta_len);
6240-
}
6241-
62426236
skb->mac_header += VLAN_HLEN;
62436237
return skb;
62446238
}

0 commit comments

Comments
 (0)