196 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* 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 11struct mtk_flow_addr_info12{13 void *src, *dest;14 u16 *src_port, *dest_port;15 bool ipv6;16};17 18static 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 33static 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 50static void51mtk_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 64static void65mtk_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 76static int77mtk_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 170static int171mtk_ppe_debugfs_foe_all_show(struct seq_file *m, void *private)172{173 return mtk_ppe_debugfs_foe_show(m, private, false);174}175DEFINE_SHOW_ATTRIBUTE(mtk_ppe_debugfs_foe_all);176 177static int178mtk_ppe_debugfs_foe_bind_show(struct seq_file *m, void *private)179{180 return mtk_ppe_debugfs_foe_show(m, private, true);181}182DEFINE_SHOW_ATTRIBUTE(mtk_ppe_debugfs_foe_bind);183 184int 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