Commit 690e36e726d00d2528bc569809048adf61550d80

Authored by David S. Miller
1 parent 1ad676a6bc

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 <davem@davemloft.net>

Showing 3 changed files with 50 additions and 22 deletions Side-by-side Diff

include/linux/skbuff.h
... ... @@ -2567,18 +2567,24 @@
2567 2567 __wsum skb_checksum(const struct sk_buff *skb, int offset, int len,
2568 2568 __wsum csum);
2569 2569  
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)
2572 2572 {
2573   - int hlen = skb_headlen(skb);
2574   -
2575 2573 if (hlen - offset >= len)
2576   - return skb->data + offset;
  2574 + return data + offset;
2577 2575  
2578   - if (skb_copy_bits(skb, offset, buffer, len) < 0)
  2576 + if (!skb ||
  2577 + skb_copy_bits(skb, offset, buffer, len) < 0)
2579 2578 return NULL;
2580 2579  
2581 2580 return buffer;
  2581 +}
  2582 +
  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);
2582 2588 }
2583 2589  
2584 2590 /**
include/net/flow_keys.h
... ... @@ -27,8 +27,18 @@
27 27 u8 ip_proto;
28 28 };
29 29  
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 +}
32 42 u32 flow_hash_from_keys(struct flow_keys *keys);
33 43 #endif
net/core/flow_dissector.c
... ... @@ -34,29 +34,40 @@
34 34 * The function will try to retrieve the ports at offset thoff + poff where poff
35 35 * is the protocol port offset returned from proto_ports_offset
36 36 */
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)
38 39 {
39 40 int poff = proto_ports_offset(ip_proto);
40 41  
  42 + if (!data) {
  43 + data = skb->data;
  44 + hlen = skb_headlen(skb);
  45 + }
  46 +
41 47 if (poff >= 0) {
42 48 __be32 *ports, _ports;
43 49  
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);
46 52 if (ports)
47 53 return *ports;
48 54 }
49 55  
50 56 return 0;
51 57 }
52   -EXPORT_SYMBOL(skb_flow_get_ports);
  58 +EXPORT_SYMBOL(__skb_flow_get_ports);
53 59  
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)
55 61 {
56 62 int nhoff = skb_network_offset(skb);
57 63 u8 ip_proto;
58 64 __be16 proto = skb->protocol;
59 65  
  66 + if (!data) {
  67 + data = skb->data;
  68 + hlen = skb_headlen(skb);
  69 + }
  70 +
60 71 memset(flow, 0, sizeof(*flow));
61 72  
62 73 again:
... ... @@ -65,7 +76,7 @@
65 76 const struct iphdr *iph;
66 77 struct iphdr _iph;
67 78 ip:
68   - iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
  79 + iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph);
69 80 if (!iph || iph->ihl < 5)
70 81 return false;
71 82 nhoff += iph->ihl * 4;
... ... @@ -83,7 +94,7 @@
83 94 __be32 flow_label;
84 95  
85 96 ipv6:
86   - iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
  97 + iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph);
87 98 if (!iph)
88 99 return false;
89 100  
... ... @@ -113,7 +124,7 @@
113 124 const struct vlan_hdr *vlan;
114 125 struct vlan_hdr _vlan;
115 126  
116   - vlan = skb_header_pointer(skb, nhoff, sizeof(_vlan), &_vlan);
  127 + vlan = __skb_header_pointer(skb, nhoff, sizeof(_vlan), data, hlen, &_vlan);
117 128 if (!vlan)
118 129 return false;
119 130  
... ... @@ -126,7 +137,7 @@
126 137 struct pppoe_hdr hdr;
127 138 __be16 proto;
128 139 } *hdr, _hdr;
129   - hdr = skb_header_pointer(skb, nhoff, sizeof(_hdr), &_hdr);
  140 + hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr);
130 141 if (!hdr)
131 142 return false;
132 143 proto = hdr->proto;
... ... @@ -151,7 +162,7 @@
151 162 __be16 proto;
152 163 } *hdr, _hdr;
153 164  
154   - hdr = skb_header_pointer(skb, nhoff, sizeof(_hdr), &_hdr);
  165 + hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr);
155 166 if (!hdr)
156 167 return false;
157 168 /*
... ... @@ -171,8 +182,9 @@
171 182 const struct ethhdr *eth;
172 183 struct ethhdr _eth;
173 184  
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);
176 188 if (!eth)
177 189 return false;
178 190 proto = eth->h_proto;
179 191  
... ... @@ -194,12 +206,12 @@
194 206  
195 207 flow->n_proto = proto;
196 208 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);
198 210 flow->thoff = (u16) nhoff;
199 211  
200 212 return true;
201 213 }
202   -EXPORT_SYMBOL(skb_flow_dissect);
  214 +EXPORT_SYMBOL(__skb_flow_dissect);
203 215  
204 216 static u32 hashrnd __read_mostly;
205 217 static __always_inline void __flow_hash_secret_init(void)