1 From 408eccce32044ee3285a7f6a812723ba3540c3e7 Mon Sep 17 00:00:00 2001
2 From: Daniel Borkmann <dborkman@redhat.com>
3 Date: Tue, 1 Apr 2014 16:20:23 +0200
4 Subject: [PATCH] net: ptp: move PTP classifier in its own file
6 This commit fixes a build error reported by Fengguang, that is
7 triggered when CONFIG_NETWORK_PHY_TIMESTAMPING is not set:
9 ERROR: "ptp_classify_raw" [drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.ko] undefined!
11 The fix is to introduce its own file for the PTP BPF classifier,
12 so that PTP_1588_CLOCK and/or NETWORK_PHY_TIMESTAMPING can select
13 it independently from each other. IXP4xx driver on ARM needs to
14 select it as well since it does not seem to select PTP_1588_CLOCK
15 or similar that would pull it in automatically.
17 This also allows for hiding all of the internals of the BPF PTP
18 program inside that file, and only exporting relevant API bits
21 This patch also adds a kdoc documentation of ptp_classify_raw()
22 API to make it clear that it can return PTP_CLASS_* defines. Also,
23 the BPF program has been translated into bpf_asm code, so that it
24 can be more easily read and altered (extensively documented in [1]).
26 In the kernel tree under tools/net/ we have bpf_asm and bpf_dbg
27 tools, so the commented program can simply be translated via
28 `./bpf_asm -c prog` where prog is a file that contains the
29 commented code. This makes it easily readable/verifiable and when
30 there's a need to change something, jump offsets etc do not need
31 to be replaced manually which can be very error prone. Instead,
32 a newly translated version via bpf_asm can simply replace the old
33 code. I have checked opcode diffs before/after and it's the very
36 [1] Documentation/networking/filter.txt
38 Fixes: 164d8c666521 ("net: ptp: do not reimplement PTP/BPF classifier")
39 Reported-by: Fengguang Wu <fengguang.wu@intel.com>
40 Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
41 Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
42 Cc: Richard Cochran <richardcochran@gmail.com>
43 Cc: Jiri Benc <jbenc@redhat.com>
44 Acked-by: Richard Cochran <richardcochran@gmail.com>
45 Signed-off-by: David S. Miller <davem@davemloft.net>
47 drivers/net/ethernet/xscale/Kconfig | 1 +
48 drivers/net/phy/dp83640.c | 1 +
49 drivers/ptp/Kconfig | 1 +
50 include/linux/ptp_classify.h | 95 ++++++------------------
51 include/linux/skbuff.h | 2 -
53 net/core/Makefile | 1 +
54 net/core/ptp_classifier.c | 141 ++++++++++++++++++++++++++++++++++++
55 net/core/timestamping.c | 18 -----
57 10 files changed, 173 insertions(+), 96 deletions(-)
58 create mode 100644 net/core/ptp_classifier.c
60 diff --git a/drivers/net/ethernet/xscale/Kconfig b/drivers/net/ethernet/xscale/Kconfig
61 index 3f43101..b81bc9f 100644
62 --- a/drivers/net/ethernet/xscale/Kconfig
63 +++ b/drivers/net/ethernet/xscale/Kconfig
64 @@ -23,6 +23,7 @@ config IXP4XX_ETH
65 tristate "Intel IXP4xx Ethernet support"
66 depends on ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR
68 + select NET_PTP_CLASSIFY
70 Say Y here if you want to use built-in Ethernet ports
72 diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
73 index 352c5e4..6a999e6 100644
74 --- a/drivers/net/phy/dp83640.c
75 +++ b/drivers/net/phy/dp83640.c
77 #include <linux/module.h>
78 #include <linux/net_tstamp.h>
79 #include <linux/netdevice.h>
80 +#include <linux/if_vlan.h>
81 #include <linux/phy.h>
82 #include <linux/ptp_classify.h>
83 #include <linux/ptp_clock_kernel.h>
84 diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
85 index 5a7910e..6963bdf 100644
86 --- a/drivers/ptp/Kconfig
87 +++ b/drivers/ptp/Kconfig
88 @@ -7,6 +7,7 @@ menu "PTP clock support"
90 tristate "PTP clock support"
92 + select NET_PTP_CLASSIFY
94 The IEEE 1588 standard defines a method to precisely
95 synchronize distributed clocks over Ethernet networks. The
96 diff --git a/include/linux/ptp_classify.h b/include/linux/ptp_classify.h
97 index 6d3b0a2..7dfed71 100644
98 --- a/include/linux/ptp_classify.h
99 +++ b/include/linux/ptp_classify.h
101 #ifndef _PTP_CLASSIFY_H_
102 #define _PTP_CLASSIFY_H_
104 -#include <linux/if_ether.h>
105 -#include <linux/if_vlan.h>
106 #include <linux/ip.h>
107 -#include <linux/filter.h>
108 -#include <linux/in.h>
109 +#include <linux/skbuff.h>
111 #define PTP_CLASS_NONE 0x00 /* not a PTP event message */
112 #define PTP_CLASS_V1 0x01 /* protocol version 1 */
114 #define PTP_CLASS_PMASK 0xf0 /* mask for the packet type field */
116 #define PTP_CLASS_V1_IPV4 (PTP_CLASS_V1 | PTP_CLASS_IPV4)
117 -#define PTP_CLASS_V1_IPV6 (PTP_CLASS_V1 | PTP_CLASS_IPV6) /*probably DNE*/
118 +#define PTP_CLASS_V1_IPV6 (PTP_CLASS_V1 | PTP_CLASS_IPV6) /* probably DNE */
119 #define PTP_CLASS_V2_IPV4 (PTP_CLASS_V2 | PTP_CLASS_IPV4)
120 #define PTP_CLASS_V2_IPV6 (PTP_CLASS_V2 | PTP_CLASS_IPV6)
121 #define PTP_CLASS_V2_L2 (PTP_CLASS_V2 | PTP_CLASS_L2)
123 #define PTP_EV_PORT 319
124 #define PTP_GEN_BIT 0x08 /* indicates general message, if set in message type */
126 -#define OFF_ETYPE 12
129 -#define OFF_PROTO4 23
131 -#define OFF_UDP_DST 2
133 #define OFF_PTP_SOURCE_UUID 22 /* PTPv1 only */
134 #define OFF_PTP_SEQUENCE_ID 30
135 #define OFF_PTP_CONTROL 32 /* PTPv1 only */
137 -#define IPV4_HLEN(data) (((struct iphdr *)(data + OFF_IHL))->ihl << 2)
139 +/* Below defines should actually be removed at some point in time. */
143 -#define RELOFF_DST4 (ETH_HLEN + OFF_UDP_DST)
144 -#define OFF_DST6 (ETH_HLEN + IP6_HLEN + OFF_UDP_DST)
146 #define OFF_PTP6 (ETH_HLEN + IP6_HLEN + UDP_HLEN)
147 +#define IPV4_HLEN(data) (((struct iphdr *)(data + OFF_IHL))->ihl << 2)
149 -#define OP_AND (BPF_ALU | BPF_AND | BPF_K)
150 -#define OP_JEQ (BPF_JMP | BPF_JEQ | BPF_K)
151 -#define OP_JSET (BPF_JMP | BPF_JSET | BPF_K)
152 -#define OP_LDB (BPF_LD | BPF_B | BPF_ABS)
153 -#define OP_LDH (BPF_LD | BPF_H | BPF_ABS)
154 -#define OP_LDHI (BPF_LD | BPF_H | BPF_IND)
155 -#define OP_LDX (BPF_LDX | BPF_B | BPF_MSH)
156 -#define OP_OR (BPF_ALU | BPF_OR | BPF_K)
157 -#define OP_RETA (BPF_RET | BPF_A)
158 -#define OP_RETK (BPF_RET | BPF_K)
160 -#define PTP_FILTER \
161 - {OP_LDH, 0, 0, OFF_ETYPE }, /* */ \
162 - {OP_JEQ, 0, 12, ETH_P_IP }, /* f goto L20 */ \
163 - {OP_LDB, 0, 0, OFF_PROTO4 }, /* */ \
164 - {OP_JEQ, 0, 9, IPPROTO_UDP }, /* f goto L10 */ \
165 - {OP_LDH, 0, 0, OFF_FRAG }, /* */ \
166 - {OP_JSET, 7, 0, 0x1fff }, /* t goto L11 */ \
167 - {OP_LDX, 0, 0, OFF_IHL }, /* */ \
168 - {OP_LDHI, 0, 0, RELOFF_DST4 }, /* */ \
169 - {OP_JEQ, 0, 4, PTP_EV_PORT }, /* f goto L12 */ \
170 - {OP_LDHI, 0, 0, ETH_HLEN + UDP_HLEN }, /* */ \
171 - {OP_AND, 0, 0, PTP_CLASS_VMASK }, /* */ \
172 - {OP_OR, 0, 0, PTP_CLASS_IPV4 }, /* */ \
173 - {OP_RETA, 0, 0, 0 }, /* */ \
174 -/*L1x*/ {OP_RETK, 0, 0, PTP_CLASS_NONE }, /* */ \
175 -/*L20*/ {OP_JEQ, 0, 9, ETH_P_IPV6 }, /* f goto L40 */ \
176 - {OP_LDB, 0, 0, ETH_HLEN + OFF_NEXT }, /* */ \
177 - {OP_JEQ, 0, 6, IPPROTO_UDP }, /* f goto L30 */ \
178 - {OP_LDH, 0, 0, OFF_DST6 }, /* */ \
179 - {OP_JEQ, 0, 4, PTP_EV_PORT }, /* f goto L31 */ \
180 - {OP_LDH, 0, 0, OFF_PTP6 }, /* */ \
181 - {OP_AND, 0, 0, PTP_CLASS_VMASK }, /* */ \
182 - {OP_OR, 0, 0, PTP_CLASS_IPV6 }, /* */ \
183 - {OP_RETA, 0, 0, 0 }, /* */ \
184 -/*L3x*/ {OP_RETK, 0, 0, PTP_CLASS_NONE }, /* */ \
185 -/*L40*/ {OP_JEQ, 0, 9, ETH_P_8021Q }, /* f goto L50 */ \
186 - {OP_LDH, 0, 0, OFF_ETYPE + 4 }, /* */ \
187 - {OP_JEQ, 0, 15, ETH_P_1588 }, /* f goto L60 */ \
188 - {OP_LDB, 0, 0, ETH_HLEN + VLAN_HLEN }, /* */ \
189 - {OP_AND, 0, 0, PTP_GEN_BIT }, /* */ \
190 - {OP_JEQ, 0, 12, 0 }, /* f goto L6x */ \
191 - {OP_LDH, 0, 0, ETH_HLEN + VLAN_HLEN }, /* */ \
192 - {OP_AND, 0, 0, PTP_CLASS_VMASK }, /* */ \
193 - {OP_OR, 0, 0, PTP_CLASS_VLAN }, /* */ \
194 - {OP_RETA, 0, 0, 0 }, /* */ \
195 -/*L50*/ {OP_JEQ, 0, 7, ETH_P_1588 }, /* f goto L61 */ \
196 - {OP_LDB, 0, 0, ETH_HLEN }, /* */ \
197 - {OP_AND, 0, 0, PTP_GEN_BIT }, /* */ \
198 - {OP_JEQ, 0, 4, 0 }, /* f goto L6x */ \
199 - {OP_LDH, 0, 0, ETH_HLEN }, /* */ \
200 - {OP_AND, 0, 0, PTP_CLASS_VMASK }, /* */ \
201 - {OP_OR, 0, 0, PTP_CLASS_L2 }, /* */ \
202 - {OP_RETA, 0, 0, 0 }, /* */ \
203 -/*L6x*/ {OP_RETK, 0, 0, PTP_CLASS_NONE },
205 +#if defined(CONFIG_NET_PTP_CLASSIFY)
207 + * ptp_classify_raw - classify a PTP packet
210 + * Runs a minimal BPF dissector to classify a network packet to
211 + * determine the PTP class. In case the skb does not contain any
212 + * PTP protocol data, PTP_CLASS_NONE will be returned, otherwise
213 + * PTP_CLASS_V1_IPV{4,6}, PTP_CLASS_V2_IPV{4,6} or
214 + * PTP_CLASS_V2_{L2,VLAN}, depending on the packet content.
216 unsigned int ptp_classify_raw(const struct sk_buff *skb);
218 +void __init ptp_classifier_init(void);
220 +static inline void ptp_classifier_init(void)
224 +#endif /* _PTP_CLASSIFY_H_ */
225 diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
226 index 18ef022..31edf63 100644
227 --- a/include/linux/skbuff.h
228 +++ b/include/linux/skbuff.h
229 @@ -2630,8 +2630,6 @@ static inline ktime_t net_invalid_timestamp(void)
230 return ktime_set(0, 0);
233 -void skb_timestamping_init(void);
235 #ifdef CONFIG_NETWORK_PHY_TIMESTAMPING
237 void skb_clone_tx_timestamp(struct sk_buff *skb);
238 diff --git a/net/Kconfig b/net/Kconfig
239 index e411046..d1f6f96 100644
242 @@ -89,8 +89,12 @@ config NETWORK_SECMARK
243 to nfmark, but designated for security purposes.
244 If you are unsure how to answer this question, answer N.
246 +config NET_PTP_CLASSIFY
249 config NETWORK_PHY_TIMESTAMPING
250 bool "Timestamping in PHY devices"
251 + select NET_PTP_CLASSIFY
253 This allows timestamping of network packets by PHYs with
254 hardware timestamping capabilities. This option adds some
255 diff --git a/net/core/Makefile b/net/core/Makefile
256 index 9628c20..826b925 100644
257 --- a/net/core/Makefile
258 +++ b/net/core/Makefile
259 @@ -21,5 +21,6 @@ obj-$(CONFIG_FIB_RULES) += fib_rules.o
260 obj-$(CONFIG_TRACEPOINTS) += net-traces.o
261 obj-$(CONFIG_NET_DROP_MONITOR) += drop_monitor.o
262 obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += timestamping.o
263 +obj-$(CONFIG_NET_PTP_CLASSIFY) += ptp_classifier.o
264 obj-$(CONFIG_CGROUP_NET_PRIO) += netprio_cgroup.o
265 obj-$(CONFIG_CGROUP_NET_CLASSID) += netclassid_cgroup.o
266 diff --git a/net/core/ptp_classifier.c b/net/core/ptp_classifier.c
268 index 0000000..eaba0f6
270 +++ b/net/core/ptp_classifier.c
274 + * This program is free software; you can redistribute it and/or
275 + * modify it under the terms of version 2 of the GNU General Public
276 + * License as published by the Free Software Foundation.
278 + * This program is distributed in the hope that it will be useful, but
279 + * WITHOUT ANY WARRANTY; without even the implied warranty of
280 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
281 + * General Public License for more details.
284 +/* The below program is the bpf_asm (tools/net/) representation of
285 + * the opcode array in the ptp_filter structure.
287 + * For convenience, this can easily be altered and reviewed with
288 + * bpf_asm and bpf_dbg, e.g. `./bpf_asm -c prog` where prog is a
289 + * simple file containing the below program:
291 + * ldh [12] ; load ethertype
293 + * ; PTP over UDP over IPv4 over Ethernet
295 + * jneq #0x800, test_ipv6 ; ETH_P_IP ?
296 + * ldb [23] ; load proto
297 + * jneq #17, drop_ipv4 ; IPPROTO_UDP ?
298 + * ldh [20] ; load frag offset field
299 + * jset #0x1fff, drop_ipv4 ; don't allow fragments
300 + * ldxb 4*([14]&0xf) ; load IP header len
301 + * ldh [x + 16] ; load UDP dst port
302 + * jneq #319, drop_ipv4 ; is port PTP_EV_PORT ?
303 + * ldh [x + 22] ; load payload
304 + * and #0xf ; mask PTP_CLASS_VMASK
305 + * or #0x10 ; PTP_CLASS_IPV4
306 + * ret a ; return PTP class
307 + * drop_ipv4: ret #0x0 ; PTP_CLASS_NONE
309 + * ; PTP over UDP over IPv6 over Ethernet
311 + * jneq #0x86dd, test_8021q ; ETH_P_IPV6 ?
312 + * ldb [20] ; load proto
313 + * jneq #17, drop_ipv6 ; IPPROTO_UDP ?
314 + * ldh [56] ; load UDP dst port
315 + * jneq #319, drop_ipv6 ; is port PTP_EV_PORT ?
316 + * ldh [62] ; load payload
317 + * and #0xf ; mask PTP_CLASS_VMASK
318 + * or #0x20 ; PTP_CLASS_IPV6
319 + * ret a ; return PTP class
320 + * drop_ipv6: ret #0x0 ; PTP_CLASS_NONE
322 + * ; PTP over 802.1Q over Ethernet
324 + * jneq #0x8100, test_ieee1588 ; ETH_P_8021Q ?
325 + * ldh [16] ; load inner type
326 + * jneq #0x88f7, drop_ieee1588 ; ETH_P_1588 ?
327 + * ldb [18] ; load payload
328 + * and #0x8 ; as we don't have ports here, test
329 + * jneq #0x0, drop_ieee1588 ; for PTP_GEN_BIT and drop these
330 + * ldh [18] ; reload payload
331 + * and #0xf ; mask PTP_CLASS_VMASK
332 + * or #0x40 ; PTP_CLASS_V2_VLAN
333 + * ret a ; return PTP class
335 + * ; PTP over Ethernet
337 + * jneq #0x88f7, drop_ieee1588 ; ETH_P_1588 ?
338 + * ldb [14] ; load payload
339 + * and #0x8 ; as we don't have ports here, test
340 + * jneq #0x0, drop_ieee1588 ; for PTP_GEN_BIT and drop these
341 + * ldh [14] ; reload payload
342 + * and #0xf ; mask PTP_CLASS_VMASK
343 + * or #0x30 ; PTP_CLASS_L2
344 + * ret a ; return PTP class
345 + * drop_ieee1588: ret #0x0 ; PTP_CLASS_NONE
348 +#include <linux/skbuff.h>
349 +#include <linux/filter.h>
350 +#include <linux/ptp_classify.h>
352 +static struct sk_filter *ptp_insns __read_mostly;
354 +unsigned int ptp_classify_raw(const struct sk_buff *skb)
356 + return SK_RUN_FILTER(ptp_insns, skb);
358 +EXPORT_SYMBOL_GPL(ptp_classify_raw);
360 +void __init ptp_classifier_init(void)
362 + static struct sock_filter ptp_filter[] = {
363 + { 0x28, 0, 0, 0x0000000c },
364 + { 0x15, 0, 12, 0x00000800 },
365 + { 0x30, 0, 0, 0x00000017 },
366 + { 0x15, 0, 9, 0x00000011 },
367 + { 0x28, 0, 0, 0x00000014 },
368 + { 0x45, 7, 0, 0x00001fff },
369 + { 0xb1, 0, 0, 0x0000000e },
370 + { 0x48, 0, 0, 0x00000010 },
371 + { 0x15, 0, 4, 0x0000013f },
372 + { 0x48, 0, 0, 0x00000016 },
373 + { 0x54, 0, 0, 0x0000000f },
374 + { 0x44, 0, 0, 0x00000010 },
375 + { 0x16, 0, 0, 0x00000000 },
376 + { 0x06, 0, 0, 0x00000000 },
377 + { 0x15, 0, 9, 0x000086dd },
378 + { 0x30, 0, 0, 0x00000014 },
379 + { 0x15, 0, 6, 0x00000011 },
380 + { 0x28, 0, 0, 0x00000038 },
381 + { 0x15, 0, 4, 0x0000013f },
382 + { 0x28, 0, 0, 0x0000003e },
383 + { 0x54, 0, 0, 0x0000000f },
384 + { 0x44, 0, 0, 0x00000020 },
385 + { 0x16, 0, 0, 0x00000000 },
386 + { 0x06, 0, 0, 0x00000000 },
387 + { 0x15, 0, 9, 0x00008100 },
388 + { 0x28, 0, 0, 0x00000010 },
389 + { 0x15, 0, 15, 0x000088f7 },
390 + { 0x30, 0, 0, 0x00000012 },
391 + { 0x54, 0, 0, 0x00000008 },
392 + { 0x15, 0, 12, 0x00000000 },
393 + { 0x28, 0, 0, 0x00000012 },
394 + { 0x54, 0, 0, 0x0000000f },
395 + { 0x44, 0, 0, 0x00000040 },
396 + { 0x16, 0, 0, 0x00000000 },
397 + { 0x15, 0, 7, 0x000088f7 },
398 + { 0x30, 0, 0, 0x0000000e },
399 + { 0x54, 0, 0, 0x00000008 },
400 + { 0x15, 0, 4, 0x00000000 },
401 + { 0x28, 0, 0, 0x0000000e },
402 + { 0x54, 0, 0, 0x0000000f },
403 + { 0x44, 0, 0, 0x00000030 },
404 + { 0x16, 0, 0, 0x00000000 },
405 + { 0x06, 0, 0, 0x00000000 },
407 + struct sock_fprog ptp_prog = {
408 + .len = ARRAY_SIZE(ptp_filter), .filter = ptp_filter,
411 + BUG_ON(sk_unattached_filter_create(&ptp_insns, &ptp_prog));
413 diff --git a/net/core/timestamping.c b/net/core/timestamping.c
414 index 9ff26b3..6521dfd 100644
415 --- a/net/core/timestamping.c
416 +++ b/net/core/timestamping.c
418 #include <linux/skbuff.h>
419 #include <linux/export.h>
421 -static struct sk_filter *ptp_insns __read_mostly;
423 -unsigned int ptp_classify_raw(const struct sk_buff *skb)
425 - return SK_RUN_FILTER(ptp_insns, skb);
427 -EXPORT_SYMBOL_GPL(ptp_classify_raw);
429 static unsigned int classify(const struct sk_buff *skb)
431 if (likely(skb->dev && skb->dev->phydev &&
432 @@ -140,13 +132,3 @@ bool skb_defer_rx_timestamp(struct sk_buff *skb)
435 EXPORT_SYMBOL_GPL(skb_defer_rx_timestamp);
437 -void __init skb_timestamping_init(void)
439 - static struct sock_filter ptp_filter[] = { PTP_FILTER };
440 - struct sock_fprog ptp_prog = {
441 - .len = ARRAY_SIZE(ptp_filter), .filter = ptp_filter,
444 - BUG_ON(sk_unattached_filter_create(&ptp_insns, &ptp_prog));
446 diff --git a/net/socket.c b/net/socket.c
447 index f25eaa3..1b1e7e6 100644
451 #include <linux/if_bridge.h>
452 #include <linux/if_frad.h>
453 #include <linux/if_vlan.h>
454 +#include <linux/ptp_classify.h>
455 #include <linux/init.h>
456 #include <linux/poll.h>
457 #include <linux/cache.h>
458 @@ -2685,9 +2686,7 @@ static int __init sock_init(void)
462 -#ifdef CONFIG_NETWORK_PHY_TIMESTAMPING
463 - skb_timestamping_init();
465 + ptp_classifier_init();