Skip to content

Commit 690e36e

Browse files
committed
net: Allow raw buffers to be passed into the flow dissector.
Drivers, and perhaps other entities we have not yet considered, sometimes want to know how deep the protocol headers go before deciding how large of an SKB to allocate and how much of the packet to place into the linear SKB area. For example, consider a driver which has a device which DMAs into pools of pages and then tells the driver where the data went in the DMA descriptor(s). The driver can then build an SKB and reference most of the data via SKB fragments (which are page/offset/length triplets). However at least some of the front of the packet should be placed into the linear SKB area, which comes before the fragments, so that packet processing can get at the headers efficiently. The first thing each protocol layer is going to do is a "pskb_may_pull()" so we might as well aggregate as much of this as possible while we're building the SKB in the driver. Part of supporting this is that we don't have an SKB yet, so we want to be able to let the flow dissector operate on a raw buffer in order to compute the offset of the end of the headers. So now we have a __skb_flow_dissect() which takes an explicit data pointer and length. Signed-off-by: David S. Miller <[email protected]>
1 parent 1ad676a commit 690e36e

File tree

3 files changed

+50
-22
lines changed

3 files changed

+50
-22
lines changed

include/linux/skbuff.h

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2567,20 +2567,26 @@ __wsum __skb_checksum(const struct sk_buff *skb, int offset, int len,
25672567
__wsum skb_checksum(const struct sk_buff *skb, int offset, int len,
25682568
__wsum csum);
25692569

2570-
static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
2571-
int len, void *buffer)
2570+
static inline void *__skb_header_pointer(const struct sk_buff *skb, int offset,
2571+
int len, void *data, int hlen, void *buffer)
25722572
{
2573-
int hlen = skb_headlen(skb);
2574-
25752573
if (hlen - offset >= len)
2576-
return skb->data + offset;
2574+
return data + offset;
25772575

2578-
if (skb_copy_bits(skb, offset, buffer, len) < 0)
2576+
if (!skb ||
2577+
skb_copy_bits(skb, offset, buffer, len) < 0)
25792578
return NULL;
25802579

25812580
return buffer;
25822581
}
25832582

2583+
static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
2584+
int len, void *buffer)
2585+
{
2586+
return __skb_header_pointer(skb, offset, len, skb->data,
2587+
skb_headlen(skb), buffer);
2588+
}
2589+
25842590
/**
25852591
* skb_needs_linearize - check if we need to linearize a given skb
25862592
* depending on the given device features.

include/net/flow_keys.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,17 @@ struct flow_keys {
2727
u8 ip_proto;
2828
};
2929

30-
bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow);
31-
__be32 skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto);
30+
bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow,
31+
void *data, int hlen);
32+
static inline bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow)
33+
{
34+
return __skb_flow_dissect(skb, flow, NULL, 0);
35+
}
36+
__be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto,
37+
void *data, int hlen_proto);
38+
static inline __be32 skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto)
39+
{
40+
return __skb_flow_get_ports(skb, thoff, ip_proto, NULL, 0);
41+
}
3242
u32 flow_hash_from_keys(struct flow_keys *keys);
3343
#endif

net/core/flow_dissector.c

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,29 +34,40 @@ static void iph_to_flow_copy_addrs(struct flow_keys *flow, const struct iphdr *i
3434
* The function will try to retrieve the ports at offset thoff + poff where poff
3535
* is the protocol port offset returned from proto_ports_offset
3636
*/
37-
__be32 skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto)
37+
__be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto,
38+
void *data, int hlen)
3839
{
3940
int poff = proto_ports_offset(ip_proto);
4041

42+
if (!data) {
43+
data = skb->data;
44+
hlen = skb_headlen(skb);
45+
}
46+
4147
if (poff >= 0) {
4248
__be32 *ports, _ports;
4349

44-
ports = skb_header_pointer(skb, thoff + poff,
45-
sizeof(_ports), &_ports);
50+
ports = __skb_header_pointer(skb, thoff + poff,
51+
sizeof(_ports), data, hlen, &_ports);
4652
if (ports)
4753
return *ports;
4854
}
4955

5056
return 0;
5157
}
52-
EXPORT_SYMBOL(skb_flow_get_ports);
58+
EXPORT_SYMBOL(__skb_flow_get_ports);
5359

54-
bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow)
60+
bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow, void *data, int hlen)
5561
{
5662
int nhoff = skb_network_offset(skb);
5763
u8 ip_proto;
5864
__be16 proto = skb->protocol;
5965

66+
if (!data) {
67+
data = skb->data;
68+
hlen = skb_headlen(skb);
69+
}
70+
6071
memset(flow, 0, sizeof(*flow));
6172

6273
again:
@@ -65,7 +76,7 @@ bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow)
6576
const struct iphdr *iph;
6677
struct iphdr _iph;
6778
ip:
68-
iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
79+
iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph);
6980
if (!iph || iph->ihl < 5)
7081
return false;
7182
nhoff += iph->ihl * 4;
@@ -83,7 +94,7 @@ bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow)
8394
__be32 flow_label;
8495

8596
ipv6:
86-
iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
97+
iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph);
8798
if (!iph)
8899
return false;
89100

@@ -113,7 +124,7 @@ bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow)
113124
const struct vlan_hdr *vlan;
114125
struct vlan_hdr _vlan;
115126

116-
vlan = skb_header_pointer(skb, nhoff, sizeof(_vlan), &_vlan);
127+
vlan = __skb_header_pointer(skb, nhoff, sizeof(_vlan), data, hlen, &_vlan);
117128
if (!vlan)
118129
return false;
119130

@@ -126,7 +137,7 @@ bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow)
126137
struct pppoe_hdr hdr;
127138
__be16 proto;
128139
} *hdr, _hdr;
129-
hdr = skb_header_pointer(skb, nhoff, sizeof(_hdr), &_hdr);
140+
hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr);
130141
if (!hdr)
131142
return false;
132143
proto = hdr->proto;
@@ -151,7 +162,7 @@ bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow)
151162
__be16 proto;
152163
} *hdr, _hdr;
153164

154-
hdr = skb_header_pointer(skb, nhoff, sizeof(_hdr), &_hdr);
165+
hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr);
155166
if (!hdr)
156167
return false;
157168
/*
@@ -171,8 +182,9 @@ bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow)
171182
const struct ethhdr *eth;
172183
struct ethhdr _eth;
173184

174-
eth = skb_header_pointer(skb, nhoff,
175-
sizeof(_eth), &_eth);
185+
eth = __skb_header_pointer(skb, nhoff,
186+
sizeof(_eth),
187+
data, hlen, &_eth);
176188
if (!eth)
177189
return false;
178190
proto = eth->h_proto;
@@ -194,12 +206,12 @@ bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow)
194206

195207
flow->n_proto = proto;
196208
flow->ip_proto = ip_proto;
197-
flow->ports = skb_flow_get_ports(skb, nhoff, ip_proto);
209+
flow->ports = __skb_flow_get_ports(skb, nhoff, ip_proto, data, hlen);
198210
flow->thoff = (u16) nhoff;
199211

200212
return true;
201213
}
202-
EXPORT_SYMBOL(skb_flow_dissect);
214+
EXPORT_SYMBOL(__skb_flow_dissect);
203215

204216
static u32 hashrnd __read_mostly;
205217
static __always_inline void __flow_hash_secret_init(void)

0 commit comments

Comments
 (0)