aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/skbuff.h18
-rw-r--r--include/net/flow_keys.h14
-rw-r--r--net/core/flow_dissector.c40
3 files changed, 50 insertions, 22 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index abde271c18ae..18ddf9684a27 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -2567,20 +2567,26 @@ __wsum __skb_checksum(const struct sk_buff *skb, int offset, int len,
2567__wsum skb_checksum(const struct sk_buff *skb, int offset, int len, 2567__wsum skb_checksum(const struct sk_buff *skb, int offset, int len,
2568 __wsum csum); 2568 __wsum csum);
2569 2569
2570static inline void *skb_header_pointer(const struct sk_buff *skb, int offset, 2570static inline void *__skb_header_pointer(const struct sk_buff *skb, int offset,
2571 int len, void *buffer) 2571 int len, void *data, int hlen, void *buffer)
2572{ 2572{
2573 int hlen = skb_headlen(skb);
2574
2575 if (hlen - offset >= len) 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 return NULL; 2578 return NULL;
2580 2579
2581 return buffer; 2580 return buffer;
2582} 2581}
2583 2582
2583static 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
2584/** 2590/**
2585 * skb_needs_linearize - check if we need to linearize a given skb 2591 * skb_needs_linearize - check if we need to linearize a given skb
2586 * depending on the given device features. 2592 * depending on the given device features.
diff --git a/include/net/flow_keys.h b/include/net/flow_keys.h
index 6667a054763a..4040f63932c5 100644
--- a/include/net/flow_keys.h
+++ b/include/net/flow_keys.h
@@ -27,7 +27,17 @@ struct flow_keys {
27 u8 ip_proto; 27 u8 ip_proto;
28}; 28};
29 29
30bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow); 30bool __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); 31 void *data, int hlen);
32static 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);
38static 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}
32u32 flow_hash_from_keys(struct flow_keys *keys); 42u32 flow_hash_from_keys(struct flow_keys *keys);
33#endif 43#endif
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)