Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: ptp: move PTP classifier in its own file

This commit fixes a build error reported by Fengguang, that is
triggered when CONFIG_NETWORK_PHY_TIMESTAMPING is not set:

ERROR: "ptp_classify_raw" [drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.ko] undefined!

The fix is to introduce its own file for the PTP BPF classifier,
so that PTP_1588_CLOCK and/or NETWORK_PHY_TIMESTAMPING can select
it independently from each other. IXP4xx driver on ARM needs to
select it as well since it does not seem to select PTP_1588_CLOCK
or similar that would pull it in automatically.

This also allows for hiding all of the internals of the BPF PTP
program inside that file, and only exporting relevant API bits
to drivers.

This patch also adds a kdoc documentation of ptp_classify_raw()
API to make it clear that it can return PTP_CLASS_* defines. Also,
the BPF program has been translated into bpf_asm code, so that it
can be more easily read and altered (extensively documented in [1]).

In the kernel tree under tools/net/ we have bpf_asm and bpf_dbg
tools, so the commented program can simply be translated via
`./bpf_asm -c prog` where prog is a file that contains the
commented code. This makes it easily readable/verifiable and when
there's a need to change something, jump offsets etc do not need
to be replaced manually which can be very error prone. Instead,
a newly translated version via bpf_asm can simply replace the old
code. I have checked opcode diffs before/after and it's the very
same filter.

[1] Documentation/networking/filter.txt

Fixes: 164d8c666521 ("net: ptp: do not reimplement PTP/BPF classifier")
Reported-by: Fengguang Wu <fengguang.wu@intel.com>
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
Cc: Richard Cochran <richardcochran@gmail.com>
Cc: Jiri Benc <jbenc@redhat.com>
Acked-by: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Daniel Borkmann and committed by
David S. Miller
408eccce 7baea6ef

+173 -96
+1
drivers/net/ethernet/xscale/Kconfig
··· 23 23 tristate "Intel IXP4xx Ethernet support" 24 24 depends on ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR 25 25 select PHYLIB 26 + select NET_PTP_CLASSIFY 26 27 ---help--- 27 28 Say Y here if you want to use built-in Ethernet ports 28 29 on IXP4xx processor.
+1
drivers/net/phy/dp83640.c
··· 27 27 #include <linux/module.h> 28 28 #include <linux/net_tstamp.h> 29 29 #include <linux/netdevice.h> 30 + #include <linux/if_vlan.h> 30 31 #include <linux/phy.h> 31 32 #include <linux/ptp_classify.h> 32 33 #include <linux/ptp_clock_kernel.h>
+1
drivers/ptp/Kconfig
··· 7 7 config PTP_1588_CLOCK 8 8 tristate "PTP clock support" 9 9 select PPS 10 + select NET_PTP_CLASSIFY 10 11 help 11 12 The IEEE 1588 standard defines a method to precisely 12 13 synchronize distributed clocks over Ethernet networks. The
+22 -73
include/linux/ptp_classify.h
··· 23 23 #ifndef _PTP_CLASSIFY_H_ 24 24 #define _PTP_CLASSIFY_H_ 25 25 26 - #include <linux/if_ether.h> 27 - #include <linux/if_vlan.h> 28 26 #include <linux/ip.h> 29 - #include <linux/filter.h> 30 - #include <linux/in.h> 27 + #include <linux/skbuff.h> 31 28 32 29 #define PTP_CLASS_NONE 0x00 /* not a PTP event message */ 33 30 #define PTP_CLASS_V1 0x01 /* protocol version 1 */ ··· 37 40 #define PTP_CLASS_PMASK 0xf0 /* mask for the packet type field */ 38 41 39 42 #define PTP_CLASS_V1_IPV4 (PTP_CLASS_V1 | PTP_CLASS_IPV4) 40 - #define PTP_CLASS_V1_IPV6 (PTP_CLASS_V1 | PTP_CLASS_IPV6) /*probably DNE*/ 43 + #define PTP_CLASS_V1_IPV6 (PTP_CLASS_V1 | PTP_CLASS_IPV6) /* probably DNE */ 41 44 #define PTP_CLASS_V2_IPV4 (PTP_CLASS_V2 | PTP_CLASS_IPV4) 42 45 #define PTP_CLASS_V2_IPV6 (PTP_CLASS_V2 | PTP_CLASS_IPV6) 43 46 #define PTP_CLASS_V2_L2 (PTP_CLASS_V2 | PTP_CLASS_L2) ··· 46 49 #define PTP_EV_PORT 319 47 50 #define PTP_GEN_BIT 0x08 /* indicates general message, if set in message type */ 48 51 49 - #define OFF_ETYPE 12 50 - #define OFF_IHL 14 51 - #define OFF_FRAG 20 52 - #define OFF_PROTO4 23 53 - #define OFF_NEXT 6 54 - #define OFF_UDP_DST 2 55 - 56 52 #define OFF_PTP_SOURCE_UUID 22 /* PTPv1 only */ 57 53 #define OFF_PTP_SEQUENCE_ID 30 58 54 #define OFF_PTP_CONTROL 32 /* PTPv1 only */ 59 55 60 - #define IPV4_HLEN(data) (((struct iphdr *)(data + OFF_IHL))->ihl << 2) 61 - 56 + /* Below defines should actually be removed at some point in time. */ 62 57 #define IP6_HLEN 40 63 58 #define UDP_HLEN 8 64 - 65 - #define RELOFF_DST4 (ETH_HLEN + OFF_UDP_DST) 66 - #define OFF_DST6 (ETH_HLEN + IP6_HLEN + OFF_UDP_DST) 59 + #define OFF_IHL 14 67 60 #define OFF_PTP6 (ETH_HLEN + IP6_HLEN + UDP_HLEN) 61 + #define IPV4_HLEN(data) (((struct iphdr *)(data + OFF_IHL))->ihl << 2) 68 62 69 - #define OP_AND (BPF_ALU | BPF_AND | BPF_K) 70 - #define OP_JEQ (BPF_JMP | BPF_JEQ | BPF_K) 71 - #define OP_JSET (BPF_JMP | BPF_JSET | BPF_K) 72 - #define OP_LDB (BPF_LD | BPF_B | BPF_ABS) 73 - #define OP_LDH (BPF_LD | BPF_H | BPF_ABS) 74 - #define OP_LDHI (BPF_LD | BPF_H | BPF_IND) 75 - #define OP_LDX (BPF_LDX | BPF_B | BPF_MSH) 76 - #define OP_OR (BPF_ALU | BPF_OR | BPF_K) 77 - #define OP_RETA (BPF_RET | BPF_A) 78 - #define OP_RETK (BPF_RET | BPF_K) 79 - 80 - #define PTP_FILTER \ 81 - {OP_LDH, 0, 0, OFF_ETYPE }, /* */ \ 82 - {OP_JEQ, 0, 12, ETH_P_IP }, /* f goto L20 */ \ 83 - {OP_LDB, 0, 0, OFF_PROTO4 }, /* */ \ 84 - {OP_JEQ, 0, 9, IPPROTO_UDP }, /* f goto L10 */ \ 85 - {OP_LDH, 0, 0, OFF_FRAG }, /* */ \ 86 - {OP_JSET, 7, 0, 0x1fff }, /* t goto L11 */ \ 87 - {OP_LDX, 0, 0, OFF_IHL }, /* */ \ 88 - {OP_LDHI, 0, 0, RELOFF_DST4 }, /* */ \ 89 - {OP_JEQ, 0, 4, PTP_EV_PORT }, /* f goto L12 */ \ 90 - {OP_LDHI, 0, 0, ETH_HLEN + UDP_HLEN }, /* */ \ 91 - {OP_AND, 0, 0, PTP_CLASS_VMASK }, /* */ \ 92 - {OP_OR, 0, 0, PTP_CLASS_IPV4 }, /* */ \ 93 - {OP_RETA, 0, 0, 0 }, /* */ \ 94 - /*L1x*/ {OP_RETK, 0, 0, PTP_CLASS_NONE }, /* */ \ 95 - /*L20*/ {OP_JEQ, 0, 9, ETH_P_IPV6 }, /* f goto L40 */ \ 96 - {OP_LDB, 0, 0, ETH_HLEN + OFF_NEXT }, /* */ \ 97 - {OP_JEQ, 0, 6, IPPROTO_UDP }, /* f goto L30 */ \ 98 - {OP_LDH, 0, 0, OFF_DST6 }, /* */ \ 99 - {OP_JEQ, 0, 4, PTP_EV_PORT }, /* f goto L31 */ \ 100 - {OP_LDH, 0, 0, OFF_PTP6 }, /* */ \ 101 - {OP_AND, 0, 0, PTP_CLASS_VMASK }, /* */ \ 102 - {OP_OR, 0, 0, PTP_CLASS_IPV6 }, /* */ \ 103 - {OP_RETA, 0, 0, 0 }, /* */ \ 104 - /*L3x*/ {OP_RETK, 0, 0, PTP_CLASS_NONE }, /* */ \ 105 - /*L40*/ {OP_JEQ, 0, 9, ETH_P_8021Q }, /* f goto L50 */ \ 106 - {OP_LDH, 0, 0, OFF_ETYPE + 4 }, /* */ \ 107 - {OP_JEQ, 0, 15, ETH_P_1588 }, /* f goto L60 */ \ 108 - {OP_LDB, 0, 0, ETH_HLEN + VLAN_HLEN }, /* */ \ 109 - {OP_AND, 0, 0, PTP_GEN_BIT }, /* */ \ 110 - {OP_JEQ, 0, 12, 0 }, /* f goto L6x */ \ 111 - {OP_LDH, 0, 0, ETH_HLEN + VLAN_HLEN }, /* */ \ 112 - {OP_AND, 0, 0, PTP_CLASS_VMASK }, /* */ \ 113 - {OP_OR, 0, 0, PTP_CLASS_VLAN }, /* */ \ 114 - {OP_RETA, 0, 0, 0 }, /* */ \ 115 - /*L50*/ {OP_JEQ, 0, 7, ETH_P_1588 }, /* f goto L61 */ \ 116 - {OP_LDB, 0, 0, ETH_HLEN }, /* */ \ 117 - {OP_AND, 0, 0, PTP_GEN_BIT }, /* */ \ 118 - {OP_JEQ, 0, 4, 0 }, /* f goto L6x */ \ 119 - {OP_LDH, 0, 0, ETH_HLEN }, /* */ \ 120 - {OP_AND, 0, 0, PTP_CLASS_VMASK }, /* */ \ 121 - {OP_OR, 0, 0, PTP_CLASS_L2 }, /* */ \ 122 - {OP_RETA, 0, 0, 0 }, /* */ \ 123 - /*L6x*/ {OP_RETK, 0, 0, PTP_CLASS_NONE }, 124 - 63 + #if defined(CONFIG_NET_PTP_CLASSIFY) 64 + /** 65 + * ptp_classify_raw - classify a PTP packet 66 + * @skb: buffer 67 + * 68 + * Runs a minimal BPF dissector to classify a network packet to 69 + * determine the PTP class. In case the skb does not contain any 70 + * PTP protocol data, PTP_CLASS_NONE will be returned, otherwise 71 + * PTP_CLASS_V1_IPV{4,6}, PTP_CLASS_V2_IPV{4,6} or 72 + * PTP_CLASS_V2_{L2,VLAN}, depending on the packet content. 73 + */ 125 74 unsigned int ptp_classify_raw(const struct sk_buff *skb); 126 75 76 + void __init ptp_classifier_init(void); 77 + #else 78 + static inline void ptp_classifier_init(void) 79 + { 80 + } 127 81 #endif 82 + #endif /* _PTP_CLASSIFY_H_ */
-2
include/linux/skbuff.h
··· 2630 2630 return ktime_set(0, 0); 2631 2631 } 2632 2632 2633 - void skb_timestamping_init(void); 2634 - 2635 2633 #ifdef CONFIG_NETWORK_PHY_TIMESTAMPING 2636 2634 2637 2635 void skb_clone_tx_timestamp(struct sk_buff *skb);
+4
net/Kconfig
··· 89 89 to nfmark, but designated for security purposes. 90 90 If you are unsure how to answer this question, answer N. 91 91 92 + config NET_PTP_CLASSIFY 93 + def_bool n 94 + 92 95 config NETWORK_PHY_TIMESTAMPING 93 96 bool "Timestamping in PHY devices" 97 + select NET_PTP_CLASSIFY 94 98 help 95 99 This allows timestamping of network packets by PHYs with 96 100 hardware timestamping capabilities. This option adds some
+1
net/core/Makefile
··· 21 21 obj-$(CONFIG_TRACEPOINTS) += net-traces.o 22 22 obj-$(CONFIG_NET_DROP_MONITOR) += drop_monitor.o 23 23 obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += timestamping.o 24 + obj-$(CONFIG_NET_PTP_CLASSIFY) += ptp_classifier.o 24 25 obj-$(CONFIG_CGROUP_NET_PRIO) += netprio_cgroup.o 25 26 obj-$(CONFIG_CGROUP_NET_CLASSID) += netclassid_cgroup.o
+141
net/core/ptp_classifier.c
··· 1 + /* PTP classifier 2 + * 3 + * This program is free software; you can redistribute it and/or 4 + * modify it under the terms of version 2 of the GNU General Public 5 + * License as published by the Free Software Foundation. 6 + * 7 + * This program is distributed in the hope that it will be useful, but 8 + * WITHOUT ANY WARRANTY; without even the implied warranty of 9 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 + * General Public License for more details. 11 + */ 12 + 13 + /* The below program is the bpf_asm (tools/net/) representation of 14 + * the opcode array in the ptp_filter structure. 15 + * 16 + * For convenience, this can easily be altered and reviewed with 17 + * bpf_asm and bpf_dbg, e.g. `./bpf_asm -c prog` where prog is a 18 + * simple file containing the below program: 19 + * 20 + * ldh [12] ; load ethertype 21 + * 22 + * ; PTP over UDP over IPv4 over Ethernet 23 + * test_ipv4: 24 + * jneq #0x800, test_ipv6 ; ETH_P_IP ? 25 + * ldb [23] ; load proto 26 + * jneq #17, drop_ipv4 ; IPPROTO_UDP ? 27 + * ldh [20] ; load frag offset field 28 + * jset #0x1fff, drop_ipv4 ; don't allow fragments 29 + * ldxb 4*([14]&0xf) ; load IP header len 30 + * ldh [x + 16] ; load UDP dst port 31 + * jneq #319, drop_ipv4 ; is port PTP_EV_PORT ? 32 + * ldh [x + 22] ; load payload 33 + * and #0xf ; mask PTP_CLASS_VMASK 34 + * or #0x10 ; PTP_CLASS_IPV4 35 + * ret a ; return PTP class 36 + * drop_ipv4: ret #0x0 ; PTP_CLASS_NONE 37 + * 38 + * ; PTP over UDP over IPv6 over Ethernet 39 + * test_ipv6: 40 + * jneq #0x86dd, test_8021q ; ETH_P_IPV6 ? 41 + * ldb [20] ; load proto 42 + * jneq #17, drop_ipv6 ; IPPROTO_UDP ? 43 + * ldh [56] ; load UDP dst port 44 + * jneq #319, drop_ipv6 ; is port PTP_EV_PORT ? 45 + * ldh [62] ; load payload 46 + * and #0xf ; mask PTP_CLASS_VMASK 47 + * or #0x20 ; PTP_CLASS_IPV6 48 + * ret a ; return PTP class 49 + * drop_ipv6: ret #0x0 ; PTP_CLASS_NONE 50 + * 51 + * ; PTP over 802.1Q over Ethernet 52 + * test_8021q: 53 + * jneq #0x8100, test_ieee1588 ; ETH_P_8021Q ? 54 + * ldh [16] ; load inner type 55 + * jneq #0x88f7, drop_ieee1588 ; ETH_P_1588 ? 56 + * ldb [18] ; load payload 57 + * and #0x8 ; as we don't have ports here, test 58 + * jneq #0x0, drop_ieee1588 ; for PTP_GEN_BIT and drop these 59 + * ldh [18] ; reload payload 60 + * and #0xf ; mask PTP_CLASS_VMASK 61 + * or #0x40 ; PTP_CLASS_V2_VLAN 62 + * ret a ; return PTP class 63 + * 64 + * ; PTP over Ethernet 65 + * test_ieee1588: 66 + * jneq #0x88f7, drop_ieee1588 ; ETH_P_1588 ? 67 + * ldb [14] ; load payload 68 + * and #0x8 ; as we don't have ports here, test 69 + * jneq #0x0, drop_ieee1588 ; for PTP_GEN_BIT and drop these 70 + * ldh [14] ; reload payload 71 + * and #0xf ; mask PTP_CLASS_VMASK 72 + * or #0x30 ; PTP_CLASS_L2 73 + * ret a ; return PTP class 74 + * drop_ieee1588: ret #0x0 ; PTP_CLASS_NONE 75 + */ 76 + 77 + #include <linux/skbuff.h> 78 + #include <linux/filter.h> 79 + #include <linux/ptp_classify.h> 80 + 81 + static struct sk_filter *ptp_insns __read_mostly; 82 + 83 + unsigned int ptp_classify_raw(const struct sk_buff *skb) 84 + { 85 + return SK_RUN_FILTER(ptp_insns, skb); 86 + } 87 + EXPORT_SYMBOL_GPL(ptp_classify_raw); 88 + 89 + void __init ptp_classifier_init(void) 90 + { 91 + static struct sock_filter ptp_filter[] = { 92 + { 0x28, 0, 0, 0x0000000c }, 93 + { 0x15, 0, 12, 0x00000800 }, 94 + { 0x30, 0, 0, 0x00000017 }, 95 + { 0x15, 0, 9, 0x00000011 }, 96 + { 0x28, 0, 0, 0x00000014 }, 97 + { 0x45, 7, 0, 0x00001fff }, 98 + { 0xb1, 0, 0, 0x0000000e }, 99 + { 0x48, 0, 0, 0x00000010 }, 100 + { 0x15, 0, 4, 0x0000013f }, 101 + { 0x48, 0, 0, 0x00000016 }, 102 + { 0x54, 0, 0, 0x0000000f }, 103 + { 0x44, 0, 0, 0x00000010 }, 104 + { 0x16, 0, 0, 0x00000000 }, 105 + { 0x06, 0, 0, 0x00000000 }, 106 + { 0x15, 0, 9, 0x000086dd }, 107 + { 0x30, 0, 0, 0x00000014 }, 108 + { 0x15, 0, 6, 0x00000011 }, 109 + { 0x28, 0, 0, 0x00000038 }, 110 + { 0x15, 0, 4, 0x0000013f }, 111 + { 0x28, 0, 0, 0x0000003e }, 112 + { 0x54, 0, 0, 0x0000000f }, 113 + { 0x44, 0, 0, 0x00000020 }, 114 + { 0x16, 0, 0, 0x00000000 }, 115 + { 0x06, 0, 0, 0x00000000 }, 116 + { 0x15, 0, 9, 0x00008100 }, 117 + { 0x28, 0, 0, 0x00000010 }, 118 + { 0x15, 0, 15, 0x000088f7 }, 119 + { 0x30, 0, 0, 0x00000012 }, 120 + { 0x54, 0, 0, 0x00000008 }, 121 + { 0x15, 0, 12, 0x00000000 }, 122 + { 0x28, 0, 0, 0x00000012 }, 123 + { 0x54, 0, 0, 0x0000000f }, 124 + { 0x44, 0, 0, 0x00000040 }, 125 + { 0x16, 0, 0, 0x00000000 }, 126 + { 0x15, 0, 7, 0x000088f7 }, 127 + { 0x30, 0, 0, 0x0000000e }, 128 + { 0x54, 0, 0, 0x00000008 }, 129 + { 0x15, 0, 4, 0x00000000 }, 130 + { 0x28, 0, 0, 0x0000000e }, 131 + { 0x54, 0, 0, 0x0000000f }, 132 + { 0x44, 0, 0, 0x00000030 }, 133 + { 0x16, 0, 0, 0x00000000 }, 134 + { 0x06, 0, 0, 0x00000000 }, 135 + }; 136 + struct sock_fprog ptp_prog = { 137 + .len = ARRAY_SIZE(ptp_filter), .filter = ptp_filter, 138 + }; 139 + 140 + BUG_ON(sk_unattached_filter_create(&ptp_insns, &ptp_prog)); 141 + }
-18
net/core/timestamping.c
··· 23 23 #include <linux/skbuff.h> 24 24 #include <linux/export.h> 25 25 26 - static struct sk_filter *ptp_insns __read_mostly; 27 - 28 - unsigned int ptp_classify_raw(const struct sk_buff *skb) 29 - { 30 - return SK_RUN_FILTER(ptp_insns, skb); 31 - } 32 - EXPORT_SYMBOL_GPL(ptp_classify_raw); 33 - 34 26 static unsigned int classify(const struct sk_buff *skb) 35 27 { 36 28 if (likely(skb->dev && skb->dev->phydev && ··· 132 140 return false; 133 141 } 134 142 EXPORT_SYMBOL_GPL(skb_defer_rx_timestamp); 135 - 136 - void __init skb_timestamping_init(void) 137 - { 138 - static struct sock_filter ptp_filter[] = { PTP_FILTER }; 139 - struct sock_fprog ptp_prog = { 140 - .len = ARRAY_SIZE(ptp_filter), .filter = ptp_filter, 141 - }; 142 - 143 - BUG_ON(sk_unattached_filter_create(&ptp_insns, &ptp_prog)); 144 - }
+2 -3
net/socket.c
··· 72 72 #include <linux/if_bridge.h> 73 73 #include <linux/if_frad.h> 74 74 #include <linux/if_vlan.h> 75 + #include <linux/ptp_classify.h> 75 76 #include <linux/init.h> 76 77 #include <linux/poll.h> 77 78 #include <linux/cache.h> ··· 2686 2685 goto out; 2687 2686 #endif 2688 2687 2689 - #ifdef CONFIG_NETWORK_PHY_TIMESTAMPING 2690 - skb_timestamping_init(); 2691 - #endif 2688 + ptp_classifier_init(); 2692 2689 2693 2690 out: 2694 2691 return err;