aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-08-23 15:13:41 -0400
committerDavid S. Miller <davem@davemloft.net>2014-08-23 15:13:41 -0400
commit690e36e726d00d2528bc569809048adf61550d80 (patch)
treee28c0ca1fce29a077415235ec3b90db4527de6c9 /net/core
parent1ad676a6bc4b284b68e4d24c0eac366438a32af6 (diff)
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>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/flow_dissector.c40
1 files changed, 26 insertions, 14 deletions
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index 5f362c1d0332..660c6492fb78 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -34,29 +34,40 @@ static void iph_to_flow_copy_addrs(struct flow_keys *flow, const struct iphdr *i
34 * The function will try to retrieve the ports at offset thoff + poff where poff 34 * The function will try to retrieve the ports at offset thoff + poff where poff
35 * is the protocol port offset returned from proto_ports_offset 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 int poff = proto_ports_offset(ip_proto); 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 if (poff >= 0) { 47 if (poff >= 0) {
42 __be32 *ports, _ports; 48 __be32 *ports, _ports;
43 49
44 ports = skb_header_pointer(skb, thoff + poff, 50 ports = __skb_header_pointer(skb, thoff + poff,
45 sizeof(_ports), &_ports); 51 sizeof(_ports), data, hlen, &_ports);
46 if (ports) 52 if (ports)
47 return *ports; 53 return *ports;
48 } 54 }
49 55
50 return 0; 56 return 0;
51} 57}
52EXPORT_SYMBOL(skb_flow_get_ports); 58EXPORT_SYMBOL(__skb_flow_get_ports);
53 59
54bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow) 60bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow, void *data, int hlen)
55{ 61{
56 int nhoff = skb_network_offset(skb); 62 int nhoff = skb_network_offset(skb);
57 u8 ip_proto; 63 u8 ip_proto;
58 __be16 proto = skb->protocol; 64 __be16 proto = skb->protocol;
59 65
66 if (!data) {
67 data = skb->data;
68 hlen = skb_headlen(skb);
69 }
70
60 memset(flow, 0, sizeof(*flow)); 71 memset(flow, 0, sizeof(*flow));
61 72
62again: 73again:
@@ -65,7 +76,7 @@ again:
65 const struct iphdr *iph; 76 const struct iphdr *iph;
66 struct iphdr _iph; 77 struct iphdr _iph;
67ip: 78ip:
68 iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph); 79 iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph);
69 if (!iph || iph->ihl < 5) 80 if (!iph || iph->ihl < 5)
70 return false; 81 return false;
71 nhoff += iph->ihl * 4; 82 nhoff += iph->ihl * 4;
@@ -83,7 +94,7 @@ ip:
83 __be32 flow_label; 94 __be32 flow_label;
84 95
85ipv6: 96ipv6:
86 iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph); 97 iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph);
87 if (!iph) 98 if (!iph)
88 return false; 99 return false;
89 100
@@ -113,7 +124,7 @@ ipv6:
113 const struct vlan_hdr *vlan; 124 const struct vlan_hdr *vlan;
114 struct vlan_hdr _vlan; 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 if (!vlan) 128 if (!vlan)
118 return false; 129 return false;
119 130
@@ -126,7 +137,7 @@ ipv6:
126 struct pppoe_hdr hdr; 137 struct pppoe_hdr hdr;
127 __be16 proto; 138 __be16 proto;
128 } *hdr, _hdr; 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 if (!hdr) 141 if (!hdr)
131 return false; 142 return false;
132 proto = hdr->proto; 143 proto = hdr->proto;
@@ -151,7 +162,7 @@ ipv6:
151 __be16 proto; 162 __be16 proto;
152 } *hdr, _hdr; 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 if (!hdr) 166 if (!hdr)
156 return false; 167 return false;
157 /* 168 /*
@@ -171,8 +182,9 @@ ipv6:
171 const struct ethhdr *eth; 182 const struct ethhdr *eth;
172 struct ethhdr _eth; 183 struct ethhdr _eth;
173 184
174 eth = skb_header_pointer(skb, nhoff, 185 eth = __skb_header_pointer(skb, nhoff,
175 sizeof(_eth), &_eth); 186 sizeof(_eth),
187 data, hlen, &_eth);
176 if (!eth) 188 if (!eth)
177 return false; 189 return false;
178 proto = eth->h_proto; 190 proto = eth->h_proto;
@@ -194,12 +206,12 @@ ipv6:
194 206
195 flow->n_proto = proto; 207 flow->n_proto = proto;
196 flow->ip_proto = ip_proto; 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 flow->thoff = (u16) nhoff; 210 flow->thoff = (u16) nhoff;
199 211
200 return true; 212 return true;
201} 213}
202EXPORT_SYMBOL(skb_flow_dissect); 214EXPORT_SYMBOL(__skb_flow_dissect);
203 215
204static u32 hashrnd __read_mostly; 216static u32 hashrnd __read_mostly;
205static __always_inline void __flow_hash_secret_init(void) 217static __always_inline void __flow_hash_secret_init(void)