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 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 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 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 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 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 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 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 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