1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */ |
3 | |
4 | #include <linux/kernel.h> |
5 | #include <linux/debugfs.h> |
6 | #include "mtk_eth_soc.h" |
7 | |
8 | struct mtk_flow_addr_info |
9 | { |
10 | void *src, *dest; |
11 | u16 *src_port, *dest_port; |
12 | bool ipv6; |
13 | }; |
14 | |
15 | static const char *mtk_foe_entry_state_str(int state) |
16 | { |
17 | static const char * const state_str[] = { |
18 | [MTK_FOE_STATE_INVALID] = "INV" , |
19 | [MTK_FOE_STATE_UNBIND] = "UNB" , |
20 | [MTK_FOE_STATE_BIND] = "BND" , |
21 | [MTK_FOE_STATE_FIN] = "FIN" , |
22 | }; |
23 | |
24 | if (state >= ARRAY_SIZE(state_str) || !state_str[state]) |
25 | return "UNK" ; |
26 | |
27 | return state_str[state]; |
28 | } |
29 | |
30 | static const char *mtk_foe_pkt_type_str(int type) |
31 | { |
32 | static const char * const type_str[] = { |
33 | [MTK_PPE_PKT_TYPE_IPV4_HNAPT] = "IPv4 5T" , |
34 | [MTK_PPE_PKT_TYPE_IPV4_ROUTE] = "IPv4 3T" , |
35 | [MTK_PPE_PKT_TYPE_IPV4_DSLITE] = "DS-LITE" , |
36 | [MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T] = "IPv6 3T" , |
37 | [MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T] = "IPv6 5T" , |
38 | [MTK_PPE_PKT_TYPE_IPV6_6RD] = "6RD" , |
39 | }; |
40 | |
41 | if (type >= ARRAY_SIZE(type_str) || !type_str[type]) |
42 | return "UNKNOWN" ; |
43 | |
44 | return type_str[type]; |
45 | } |
46 | |
47 | static void |
48 | mtk_print_addr(struct seq_file *m, u32 *addr, bool ipv6) |
49 | { |
50 | __be32 n_addr[4]; |
51 | int i; |
52 | |
53 | if (!ipv6) { |
54 | seq_printf(m, fmt: "%pI4h" , addr); |
55 | return; |
56 | } |
57 | |
58 | for (i = 0; i < ARRAY_SIZE(n_addr); i++) |
59 | n_addr[i] = htonl(addr[i]); |
60 | seq_printf(m, fmt: "%pI6" , n_addr); |
61 | } |
62 | |
63 | static void |
64 | mtk_print_addr_info(struct seq_file *m, struct mtk_flow_addr_info *ai) |
65 | { |
66 | mtk_print_addr(m, addr: ai->src, ipv6: ai->ipv6); |
67 | if (ai->src_port) |
68 | seq_printf(m, fmt: ":%d" , *ai->src_port); |
69 | seq_printf(m, fmt: "->" ); |
70 | mtk_print_addr(m, addr: ai->dest, ipv6: ai->ipv6); |
71 | if (ai->dest_port) |
72 | seq_printf(m, fmt: ":%d" , *ai->dest_port); |
73 | } |
74 | |
75 | static int |
76 | mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind) |
77 | { |
78 | struct mtk_ppe *ppe = m->private; |
79 | int i; |
80 | |
81 | for (i = 0; i < MTK_PPE_ENTRIES; i++) { |
82 | struct mtk_foe_entry *entry = mtk_foe_get_entry(ppe, hash: i); |
83 | struct mtk_foe_mac_info *l2; |
84 | struct mtk_flow_addr_info ai = {}; |
85 | struct mtk_foe_accounting *acct; |
86 | unsigned char h_source[ETH_ALEN]; |
87 | unsigned char h_dest[ETH_ALEN]; |
88 | int type, state; |
89 | u32 ib2; |
90 | |
91 | |
92 | state = FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1); |
93 | if (!state) |
94 | continue; |
95 | |
96 | if (bind && state != MTK_FOE_STATE_BIND) |
97 | continue; |
98 | |
99 | acct = mtk_foe_entry_get_mib(ppe, index: i, NULL); |
100 | |
101 | type = mtk_get_ib1_pkt_type(eth: ppe->eth, val: entry->ib1); |
102 | seq_printf(m, fmt: "%05x %s %7s" , i, |
103 | mtk_foe_entry_state_str(state), |
104 | mtk_foe_pkt_type_str(type)); |
105 | |
106 | switch (type) { |
107 | case MTK_PPE_PKT_TYPE_IPV4_HNAPT: |
108 | case MTK_PPE_PKT_TYPE_IPV4_DSLITE: |
109 | ai.src_port = &entry->ipv4.orig.src_port; |
110 | ai.dest_port = &entry->ipv4.orig.dest_port; |
111 | fallthrough; |
112 | case MTK_PPE_PKT_TYPE_IPV4_ROUTE: |
113 | ai.src = &entry->ipv4.orig.src_ip; |
114 | ai.dest = &entry->ipv4.orig.dest_ip; |
115 | break; |
116 | case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T: |
117 | ai.src_port = &entry->ipv6.src_port; |
118 | ai.dest_port = &entry->ipv6.dest_port; |
119 | fallthrough; |
120 | case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T: |
121 | case MTK_PPE_PKT_TYPE_IPV6_6RD: |
122 | ai.src = &entry->ipv6.src_ip; |
123 | ai.dest = &entry->ipv6.dest_ip; |
124 | ai.ipv6 = true; |
125 | break; |
126 | } |
127 | |
128 | seq_printf(m, fmt: " orig=" ); |
129 | mtk_print_addr_info(m, ai: &ai); |
130 | |
131 | switch (type) { |
132 | case MTK_PPE_PKT_TYPE_IPV4_HNAPT: |
133 | case MTK_PPE_PKT_TYPE_IPV4_DSLITE: |
134 | ai.src_port = &entry->ipv4.new.src_port; |
135 | ai.dest_port = &entry->ipv4.new.dest_port; |
136 | fallthrough; |
137 | case MTK_PPE_PKT_TYPE_IPV4_ROUTE: |
138 | ai.src = &entry->ipv4.new.src_ip; |
139 | ai.dest = &entry->ipv4.new.dest_ip; |
140 | seq_printf(m, fmt: " new=" ); |
141 | mtk_print_addr_info(m, ai: &ai); |
142 | break; |
143 | } |
144 | |
145 | if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) { |
146 | l2 = &entry->ipv6.l2; |
147 | ib2 = entry->ipv6.ib2; |
148 | } else { |
149 | l2 = &entry->ipv4.l2; |
150 | ib2 = entry->ipv4.ib2; |
151 | } |
152 | |
153 | *((__be32 *)h_source) = htonl(l2->src_mac_hi); |
154 | *((__be16 *)&h_source[4]) = htons(l2->src_mac_lo); |
155 | *((__be32 *)h_dest) = htonl(l2->dest_mac_hi); |
156 | *((__be16 *)&h_dest[4]) = htons(l2->dest_mac_lo); |
157 | |
158 | seq_printf(m, fmt: " eth=%pM->%pM etype=%04x" |
159 | " vlan=%d,%d ib1=%08x ib2=%08x" |
160 | " packets=%llu bytes=%llu\n" , |
161 | h_source, h_dest, ntohs(l2->etype), |
162 | l2->vlan1, l2->vlan2, entry->ib1, ib2, |
163 | acct ? acct->packets : 0, acct ? acct->bytes : 0); |
164 | } |
165 | |
166 | return 0; |
167 | } |
168 | |
169 | static int |
170 | mtk_ppe_debugfs_foe_all_show(struct seq_file *m, void *private) |
171 | { |
172 | return mtk_ppe_debugfs_foe_show(m, private, bind: false); |
173 | } |
174 | DEFINE_SHOW_ATTRIBUTE(mtk_ppe_debugfs_foe_all); |
175 | |
176 | static int |
177 | mtk_ppe_debugfs_foe_bind_show(struct seq_file *m, void *private) |
178 | { |
179 | return mtk_ppe_debugfs_foe_show(m, private, bind: true); |
180 | } |
181 | DEFINE_SHOW_ATTRIBUTE(mtk_ppe_debugfs_foe_bind); |
182 | |
183 | int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index) |
184 | { |
185 | struct dentry *root; |
186 | |
187 | snprintf(buf: ppe->dirname, size: sizeof(ppe->dirname), fmt: "ppe%d" , index); |
188 | |
189 | root = debugfs_create_dir(name: ppe->dirname, NULL); |
190 | debugfs_create_file(name: "entries" , S_IRUGO, parent: root, data: ppe, fops: &mtk_ppe_debugfs_foe_all_fops); |
191 | debugfs_create_file(name: "bind" , S_IRUGO, parent: root, data: ppe, fops: &mtk_ppe_debugfs_foe_bind_fops); |
192 | |
193 | return 0; |
194 | } |
195 | |