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