/* * Description: PP session manager debugfs interface * * SPDX-License-Identifier: GPL-2.0-only * Copyright (C) 2018-2020 Intel Corporation */ #define pr_fmt(fmt) "[PP_SESS_MGR_DBG]:%s:%d: " fmt, __func__, __LINE__ #include #include #include #include #include #include #include #include #include #include #include #include "classifier.h" #include "pp_common.h" #include "pp_debugfs_common.h" #include "pp_si.h" #include "checker.h" #include "modifier.h" #include "uc.h" #include "pp_session_mgr.h" #include "pp_session_mgr_internal.h" /** * @brief Session manager debugfs dir */ static struct dentry *dbgfs; static u32 dbg_sess_id; static unsigned long req_id; static void __smgr_dbg_inactive_cb(struct pp_inactive_list_cb_args *args) { u32 i, sz, n; char *buf; ulong scan_time; scan_time = get_jiffies_64() - args->base.req_id; sz = 100; /* 100 chars for misc stuff */ sz += args->n_sessions * 10; /* need 10 char to print session id */ sz += args->n_sessions * 1; /* space or new line after each session */ buf = kzalloc(sz, GFP_KERNEL); if (unlikely(!buf)) { pr_err("failed to allocate %u memory\n", sz); goto free_inact; } if (args->n_sessions == 0) { pr_buf(buf, sz, n, "No inactive Sessions - Scan time %u ms\n", jiffies_to_msecs(scan_time)); goto done; } pr_buf(buf, sz, n, "\n"); pr_buf_cat(buf, sz, n, " %u PP Inactive Sessions Found - Scan time %u ms\n", args->n_sessions, jiffies_to_msecs(scan_time)); pr_buf_cat(buf, sz, n, "===================================================\n"); for (i = 1; i <= args->n_sessions; i++) { pr_buf_cat(buf, sz, n, "%u ", args->inact_sess[i - 1]); if (!(i % 10)) pr_buf_cat(buf, sz, n, "\n"); } done: pr_info("%s", buf); kfree(buf); free_inact: kfree(args->inact_sess); } /** * @brief Debug callback for accepting session manager events * @param args event arguments */ static void __smgr_dbg_cb(struct pp_cb_args *args) { if (unlikely(ptr_is_null(args))) return; if (unlikely(!__pp_is_event_valid(args->ev))) return; pr_info("PP event %s(%u): args %p, req_id %lu, ret %d\n", PP_EVENT_STR(args->ev), args->ev, args, args->req_id, args->ret); switch (args->ev) { case PP_SESS_CREATE: { struct pp_sess_create_cb_args *cr_args; cr_args = container_of(args, struct pp_sess_create_cb_args, base); if (cr_args->base.ret == -EEXIST) { pr_info("Session exist, id %u\n", cr_args->sess_id); } else if (!cr_args->base.ret) { pr_info("Session %u created\n", cr_args->sess_id); dbg_sess_id = cr_args->sess_id; } else { pr_info("Failed to create session\n"); } break; } case PP_SESS_DELETE: { struct pp_sess_delete_cb_args *del_args; del_args = container_of(args, struct pp_sess_delete_cb_args, base); if (del_args->base.ret == -ENOENT) pr_info("Session %u not exist\n", del_args->sess_id); else if (!del_args->base.ret) pr_info("Session %u deleted\n", del_args->sess_id); else pr_info("Failed to delete session %u\n", del_args->sess_id); break; } case PP_INACTIVE_LIST: { struct pp_inactive_list_cb_args *inact_args; inact_args = container_of(args, struct pp_inactive_list_cb_args, base); if (inact_args->base.ret) pr_err("failed to get inactive sessions list\n"); else __smgr_dbg_inactive_cb(inact_args); break; } default: pr_err("Event %s not supported\n", PP_EVENT_STR(args->ev)); break; } } /** * @brief Dump all PP opened sessions */ void __smgr_dbg_sessions_dump(struct seq_file *f) { unsigned long *bmap; u32 n_sessions; s32 ret; ret = smgr_sessions_bmap_alloc(&bmap, &n_sessions); if (unlikely(ret)) return; ret = smgr_open_sessions_bmap_get(bmap, n_sessions); if (unlikely(ret)) goto done; seq_printf(f, "%*pbl\n", n_sessions, bmap); done: kfree(bmap); } PP_DEFINE_DEBUGFS(sessions, __smgr_dbg_sessions_dump, NULL); /** * @brief Dump all PP inactive sessions */ void __smgr_dbg_inact_sessions_dump(struct seq_file *f) { struct pp_request req; u32 *sessions, n_sessions; s32 ret; ret = smgr_sessions_arr_alloc(&sessions, &n_sessions); if (unlikely(ret)) return; req.cb = __smgr_dbg_cb; req.req_prio = 0; req.req_id = get_jiffies_64(); ret = pp_inactive_sessions_get(&req, sessions, n_sessions); } PP_DEFINE_DEBUGFS(inact_sess_dump, __smgr_dbg_inact_sessions_dump, NULL); /** * @brief Set session ID to use for dumping the session info */ void __smgr_dbg_session_set(char *cmd_buf, void *data) { if (kstrtou32(cmd_buf, 10, &dbg_sess_id)) pr_info("failed to parse '%s'\n", cmd_buf); } /** * @brief Dump specific session si top data, uses session ID * that was set by xsession file */ void __smgr_dbg_si_top_dump(struct seq_file *f, struct pp_si *si) { s32 i; seq_printf(f, "\n Session %u SI Info\n", dbg_sess_id); seq_puts(f, " ==============================\n"); seq_printf(f, " %-20s: %u\n", "sess_id ", si->sess_id); seq_printf(f, " %-20s: %u\n", "recipe_idx ", si->recipe_idx); seq_printf(f, " %-20s: %#x\n", "dpu_start ", si->dpu_start); seq_printf(f, " %-20s: %#x\n", "sce_start ", si->sce_start); seq_printf(f, " %-20s: %u\n", "fv_sz ", si->fv_sz); seq_printf(f, " %-20s: %#x\n", "bce_start ", si->bce_start); seq_printf(f, " %-20s: %u\n", "bce_sz ", si->bce_sz); seq_printf(f, " %-20s: %u\n", "bce_ext ", si->bce_ext); seq_printf(f, " %-20s: %u\n", "si_ps_sz ", si->si_ps_sz); seq_printf(f, " %-20s: %u\n", "si_ud_sz ", si->si_ud_sz); seq_printf(f, " %-20s: %u\n", "ext_reassembly", si->ext_reassembly); seq_printf(f, " %-20s: %u\n", "int_reassembly", si->int_reassembly); seq_printf(f, " %-20s: %u\n", "ps_off ", si->ps_off); seq_printf(f, " %-20s: %u\n", "base_policy ", si->base_policy); seq_printf(f, " %-20s: %u\n", "color ", si->color); seq_printf(f, " %-20s: %u\n", "tdox_flow ", si->tdox_flow); seq_printf(f, " %-20s: %u\n", "dst_q ", si->dst_q); seq_printf(f, " %-20s: %u\n", "eg_port ", si->eg_port); seq_printf(f, " %-20s: %u\n", "trim_l3_id ", si->trim_l3_id); seq_printf(f, " %-20s: %#x\n", "chck_flags ", si->chck_flags); seq_printf(f, " %-20s: %u\n", "pl2p ", si->pl2p); seq_printf(f, " %-20s: %u\n", "tmpl_ud_sz ", si->tmpl_ud_sz); seq_printf(f, " %-20s: %u\n", "ps_copy ", si->ps_copy); seq_printf(f, " %-20s: %d\n", "pkt_len_diff", si->pkt_len_diff); seq_printf(f, " %-20s: %#lx\n", "sgc_en_map ", si->sgc_en_map); for_each_set_bit (i, &si->sgc_en_map, PP_SI_SGC_MAX) seq_printf(f, " sgc[%u]%-14s: %u\n", i, " ", si->sgc[i]); seq_printf(f, " %-20s: %#lx\n", "tbm_en_map ", si->tbm_en_map); for_each_set_bit (i, &si->tbm_en_map, PP_SI_TBM_MAX) seq_printf(f, " tbm[%u]%-14s: %u\n", i, " ", si->tbm[i]); seq_printf(f, " %-20s: %#x\n", "policies_map ", si->policies_map); seq_printf(f, " %-20s: %s\n", "ext_df_mask", BOOL2STR(si->ext_df_mask)); seq_printf(f, " %-20s: %s\n", "int_df_mask", BOOL2STR(si->int_df_mask)); seq_printf(f, " %-20s: %s\n", "seg_en ", BOOL2STR(si->seg_en)); seq_printf(f, " %-20s: %u\n", "fsqm_prio ", si->fsqm_prio); } /** * @brief Dump specific session si data, uses session ID * that was set by xsession file */ void __smgr_dbg_session_si_dump(struct seq_file *f) { struct pp_dsi dsi; struct pp_si si; char buf[256]; s32 ret, i; struct sess_db_info info; struct si_ud_frag_info *frag_info; memset(&si, 0, sizeof(si)); ret = smgr_session_si_get(dbg_sess_id, &si); if (ret) return; /* Dump SI */ __smgr_dbg_si_top_dump(f, &si); if (SI_IS_DPU_EXIST(&si)) { seq_printf(f, " %-20s: %u\n", pp_si_fld2str(SI_FLD_DPU_NAT_SZ), si.dpu.nat_sz); seq_printf(f, " %-20s: %u\n", pp_si_fld2str(SI_FLD_DPU_NHDR_SZ), si.dpu.nhdr_sz); seq_printf(f, " %-20s: %u\n", pp_si_fld2str(SI_FLD_DPU_NHDR_L3_OFF), si.dpu.nhdr_l3_off); seq_printf(f, " %-20s: %u\n", pp_si_fld2str(SI_FLD_DPU_LYR_FLD_OFF), si.dpu.lyr_fld_off); seq_printf(f, " %-20s: %u\n", pp_si_fld2str(SI_FLD_DPU_PPPOE_OFF), si.dpu.pppoe_off); } if (SI_IS_SCE_EXIST(&si)) { seq_printf(f, " %-20s: %#x\n", pp_si_fld2str(SI_FLD_SCE_L3_CSUM), si.sce.l3_csum_delta); seq_printf(f, " %-20s: %#x\n", pp_si_fld2str(SI_FLD_SCE_L4_CSUM), si.sce.l4_csum_delta); seq_printf(f, " %-20s: %#x\n", pp_si_fld2str(SI_FLD_SCE_L4_CSUM_ZERO), si.sce.l4_csum_zero); seq_printf(f, " %-20s: %#x\n", pp_si_fld2str(SI_FLD_SCE_NHDR_CSUM), si.sce.nhdr_csum); seq_printf(f, " %-20s: %#x\n", pp_si_fld2str(SI_FLD_SCE_DSCP), si.sce.dscp); seq_printf(f, " %-20s: %u\n", pp_si_fld2str(SI_FLD_SCE_IP_LEN_DIFF), si.sce.tot_len_diff); seq_printf(f, " %-20s: %u(%#x)\n", pp_si_fld2str(SI_FLD_SCE_DST_PORT), si.sce.new_dst_port, si.sce.new_dst_port); seq_printf(f, " %-20s: %u(%#x)\n", pp_si_fld2str(SI_FLD_SCE_SRC_PORT), si.sce.new_src_port, si.sce.new_src_port); seq_printf(f, " %-20s: %u(%#x)\n", pp_si_fld2str(SI_FLD_SCE_TTL_DIFF), si.sce.ttl_diff, si.sce.ttl_diff); seq_printf(f, " %-20s: %u(%#x)\n", pp_si_fld2str(SI_FLD_SCE_PPPOE_DIFF), si.sce.pppoe_diff, si.sce.pppoe_diff); seq_printf(f, " %-20s: %u(%#x)\n", pp_si_fld2str(SI_FLD_SCE_L2_ORG_VAL), si.sce.l2_org_val, si.sce.l2_org_val); } if (SI_IS_BCE_EXIST(&si)) { if (si.dpu.nat_sz == sizeof(si.bce.nat.v4)) { seq_printf(f, " %-20s: %pI4b\n", "bce.nat.saddr", &si.bce.nat.v4.saddr); seq_printf(f, " %-20s: %pI4b\n", "bce.nat.daddr", &si.bce.nat.v4.daddr); } else if (si.dpu.nat_sz == sizeof(si.bce.nat.v6)) { seq_printf(f, " %-20s: %pI6\n", "bce.nat.saddr", &si.bce.nat.v6.saddr); seq_printf(f, " %-20s: %pI6\n", "bce.nat.daddr", &si.bce.nat.v6.daddr); } hex_dump_to_buffer(si.bce.nhdr, si.dpu.nhdr_sz, 32, 1, buf, sizeof(buf), false); (void)strreplace(buf, '\n', ' '); seq_printf(f, " %-20s: %s\n", "New Header", buf); } if (si.si_ud_sz || si.si_ps_sz) { hex_dump_to_buffer(si.ud, max_t(u8, si.si_ud_sz, si.si_ps_sz), 16, 1, buf, sizeof(buf), false); (void)strreplace(buf, '\n', ' '); seq_printf(f, " %-20s: %s\n", "UD", buf); ret = smgr_session_info_get(dbg_sess_id, &info); if (ret) return; if (test_bit(SESS_FLAG_MTU_CHCK, &info.flags)) { frag_info = (struct si_ud_frag_info *)&si.ud[PP_PS_REGION_SZ]; seq_printf(f, " %-20s: %u (INT_DF %d (IGNORE %d), EXT_DF %d (IGNORE %d), FRAG_EXT %d, IPV4 %d, PPPOE %d)\n", "frag.flags", frag_info->flags, !!(frag_info->flags & FRAG_INFO_FLAG_INT_DF), !!(frag_info->flags & FRAG_INFO_FLAG_IGNORE_INT_DF), !!(frag_info->flags & FRAG_INFO_FLAG_EXT_DF), !!(frag_info->flags & FRAG_INFO_FLAG_IGNORE_EXT_DF), !!(frag_info->flags & FRAG_INFO_FLAG_FRAG_EXT), !!(frag_info->flags & FRAG_INFO_FLAG_IPV4), !!(frag_info->flags & FRAG_INFO_FLAG_PPPOE)); seq_printf(f, " %-20s: %u\n", "frag.l3_off", frag_info->l3_off); seq_printf(f, " %-20s: %u\n", "frag.dst_q", frag_info->dst_q); seq_printf(f, " %-20s: %u\n", "frag.max_pkt_size", frag_info->max_pkt_size); } } for (i = 0; i < (sizeof(si.fv) / sizeof(u32)); i++) seq_printf(f, " FV WORD%-13u: %#010x\n", i, ((u32 *)(&si.fv))[i]); ret = smgr_session_dsi_get(dbg_sess_id, &dsi); if (ret) return; seq_printf(f, "\n Session %u DSI Info\n", dbg_sess_id); seq_puts(f, " ==============================\n"); seq_printf(f, " %-20s: %s\n", "valid", BOOL2STR(dsi.valid)); seq_printf(f, " %-20s: %s\n", "active", BOOL2STR(dsi.active)); seq_printf(f, " %-20s: %s\n", "stale", BOOL2STR(dsi.stale)); seq_printf(f, " %-20s: %s\n", "divert", BOOL2STR(dsi.divert)); seq_printf(f, " %-20s: %u\n", "dst_q", dsi.dst_q); seq_printf(f, " %-20s: %llu\n", "bytes", dsi.bytes_cnt); seq_printf(f, " %-20s: %llu\n", "packets", dsi.pkts_cnt); seq_puts(f, "\n"); } PP_DEFINE_DEBUGFS(session_si, __smgr_dbg_session_si_dump, NULL); /** * @brief Dump specific exception session si data, uses session * ID that was set by xsession file */ void __smgr_dbg_exception_session_si_dump(struct seq_file *f) { struct pp_si si; s32 ret; memset(&si, 0, sizeof(si)); ret = chk_exception_session_si_get(dbg_sess_id, &si); if (unlikely(ret)) { pr_err("Failed fetching SI for exception %u\n", dbg_sess_id); return; } /* Dump SI */ __smgr_dbg_si_top_dump(f, &si); } PP_DEFINE_DEBUGFS(exception_session_si, __smgr_dbg_exception_session_si_dump, NULL); /** * @brief Dump fragmentation stats */ void __smgr_dbg_frag_stats(struct seq_file *f) { struct frag_stats stats[UC_CPUS_MAX], *it; s32 ret; u32 cid, i; char **str; static const char *const cntrs_str[] = { "rx_pkt", "tx_pkt", "total_drops", "bmgr_drops", "df_drops", "max_frags_drops", "reserved1", "reserved2", }; for (cid = 0; cid < UC_CPUS_MAX; cid++) { ret = uc_egr_mbox_cmd_send(UC_CMD_FRAG_STATS, cid, NULL, 0, &stats[cid], sizeof(stats[cid])); if (unlikely(ret)) { pr_err("failed to get frag uc cpu %u counters\n", cid); return; } } seq_puts(f, "\n"); seq_puts(f, "|=====================================================================|\n"); seq_puts(f, "| Fragmentation UC Statistics |\n"); seq_puts(f, "|=====================================================================|\n"); seq_printf(f, "| %-15s ", "Counter"); for (cid = 0; cid < UC_CPUS_MAX; cid++) seq_printf(f, "| CPU%u ", cid); seq_puts(f, "|\n"); seq_puts(f, "|-----------------+------------+------------+------------+------------|\n"); i = 0; for_each_arr_entry(str, cntrs_str, ARRAY_SIZE(cntrs_str), i++) { seq_printf(f, "| %-15s ", *str); for_each_arr_entry(it, stats, ARRAY_SIZE(stats)) { seq_printf(f, "| %10u ", *(((u32 *)it) + i)); } seq_puts(f, "|\n"); } seq_puts(f, "|---------------------------------------------------------------------|\n\n"); } PP_DEFINE_DEBUGFS(frag_stats, __smgr_dbg_frag_stats, NULL); /** * @brief Dump fragmentation stats */ void __smgr_dbg_tdox_stats(struct seq_file *f) { struct smgr_tdox_stats tdox_stats; s32 ret; ret = smgr_tdox_stats_get(&tdox_stats); if (ret) return; seq_puts(f, "\n"); seq_puts(f, "|==============================|\n"); seq_puts(f, "| Tdox Statistics |\n"); seq_puts(f, "|==============================|\n"); seq_printf(f, "| %-15s ", "uC Stats"); seq_puts(f, "|\n"); seq_puts(f, "|-----------------|------------|\n"); seq_printf(f, "| %-15s ", " uC Rx "); seq_printf(f, "| %10u |\n", tdox_stats.uc_rx_pkt); seq_printf(f, "| %-15s ", " uC Tx "); seq_printf(f, "| %10u |\n", tdox_stats.uc_tx_pkt); seq_puts(f, "|------------------------------|\n"); seq_printf(f, "| %-15s ", "Entry Stats"); seq_puts(f, "|\n"); seq_puts(f, "|-----------------|------------|\n"); seq_printf(f, "| %-15s ", " Free Entries "); seq_printf(f, "| %10u |\n", tdox_stats.tdox_sess_free); seq_printf(f, "| %-15s ", " Free Cand "); seq_printf(f, "| %10u |\n", tdox_stats.tdox_free_candidates); seq_puts(f, "|------------------------------|\n"); seq_printf(f, "| %-15s ", "Session Stats"); seq_puts(f, "|\n"); seq_puts(f, "|-----------------|------------|\n"); seq_printf(f, "| %-15s ", " Tdox Full "); seq_printf(f, "| %10u |\n", tdox_stats.tdox_sess_full_fail); seq_printf(f, "| %-15s ", " TdoxCand Full "); seq_printf(f, "| %10u |\n", tdox_stats.tdox_candidate_full_fail); seq_printf(f, "| %-15s ", " Create Fail "); seq_printf(f, "| %10u |\n", tdox_stats.tdox_create_args_err); seq_puts(f, "|-----------------|------------|\n"); seq_printf(f, "| %-15s ", "Lists Stats"); seq_puts(f, "|\n"); seq_puts(f, "|-----------------|------------|\n"); seq_printf(f, "| %-15s ", " free "); seq_printf(f, "| %10u |\n", tdox_stats.free_list_cnt); seq_printf(f, "| %-15s ", " busy "); seq_printf(f, "| %10u |\n", tdox_stats.busy_list_cnt); seq_printf(f, "| %-15s ", " obsolete "); seq_printf(f, "| %10u |\n", tdox_stats.obsolete_list_cnt); seq_printf(f, "| %-15s ", " cand_free "); seq_printf(f, "| %10u |\n", tdox_stats.cand_free_list_cnt); seq_printf(f, "| %-15s ", " cand_busy "); seq_printf(f, "| %10u |\n", tdox_stats.cand_busy_list_cnt); seq_printf(f, "| %-15s ", " update_free "); seq_printf(f, "| %10u |\n", tdox_stats.sess_update_free_list_cnt); seq_printf(f, "| %-15s ", " update_busy "); seq_printf(f, "| %10u |\n", tdox_stats.sess_update_busy_list_cnt); seq_puts(f, "|------------------------------|\n"); } PP_DEFINE_DEBUGFS(tdox_stats, __smgr_dbg_tdox_stats, NULL); static int __smgr_dbg_tdox_en_set(void *data, u64 val) { smgr_tdox_enable_set(val); return 0; } static int __smgr_dbg_tdox_en_get(void *data, u64 *val) { u32 tout; tout = smgr_tdox_enable_get(); *val = (u64)tout; return 0; } PP_DEFINE_DBGFS_ATT(tdox_en_fops, __smgr_dbg_tdox_en_get, __smgr_dbg_tdox_en_set); /** * @brief Dump specific session si and dsi raw data, uses session ID * that was set by xsession file */ void __smgr_dbg_session_si_raw_dump(struct seq_file *f) { struct pp_hw_dsi hw_dsi; struct pp_hw_si hw_si; u32 sess_id; s32 ret, i; memset(&hw_si, 0, sizeof(hw_si)); memset(&hw_dsi, 0, sizeof(hw_dsi)); ret = cls_session_si_get(dbg_sess_id, &hw_si); if (ret) return; ret = chk_session_dsi_get(dbg_sess_id, &hw_dsi); if (ret) return; ret = pp_si_fld_get(&hw_si, SI_FLD_SESS_ID, (s32 *)&sess_id); if (ret) return; seq_printf(f, "\n Session %u SI Info\n", sess_id); seq_puts(f, " =========================\n"); for (i = 0; i < ARRAY_SIZE(hw_si.word); i++) seq_printf(f, " SI WORD%-4u(%#4x): %#010x\n", i, i * (u32)sizeof(u32), hw_si.word[i]); for (i = 0; i < ARRAY_SIZE(hw_dsi.word); i++) seq_printf(f, " DSI WORD%-3u(%#4x): %#010x\n", i, i * (u32)sizeof(u32), hw_dsi.word[i]); seq_puts(f, "\n"); } PP_DEFINE_DEBUGFS(session_si_raw, __smgr_dbg_session_si_raw_dump, NULL); static void __smgr_pr_session_flags(struct seq_file *f, ulong flags) { const char *flags_str[SMGR_FLAGS_NUM] = { "ROUTED", "SYNCQ", "MTU_CHECK", "MCAST_GRP", "MCAST_DST", "SESS_FLAG_TDOX", "SESS_FLAG_TDOX_SUPP", }; u32 flag; if (!flags) return; seq_printf(f, " %-20s = %#lx ", "Flags", flags); for_each_set_bit (flag, &flags, SMGR_FLAGS_NUM) seq_printf(f, "[%s]", flags_str[flag]); seq_puts(f, "\n"); } static void __smgr_pr_si_chck_flags(struct seq_file *f, ulong flags) { u32 flag; if (!flags) return; seq_printf(f, " %-20s = %#lx ", "Checker Flags", flags); for_each_set_bit (flag, &flags, SI_CHCK_FLAGS_NUM) seq_printf(f, "[%s]", pp_si_chck_flag_to_str(flag)); seq_puts(f, "\n"); } static void __smgr_pr_learn_mac(struct seq_file *f, struct fv_l2 *l2, u32 flags) { if (unlikely(!l2)) return; if (FV_L2_BASE & flags) { seq_printf(f, " %-20s = %pM\n", "Source MAC", l2->h_source); seq_printf(f, " %-20s = %pM\n", "Dest MAC", l2->h_dest); seq_printf(f, " %-20s = %s %u[%#x]\n", "Ether Type", PP_FV_L2_ETHERTYPE_STR(l2->h_proto), ntohs(l2->h_proto), ntohs(l2->h_proto)); } if (FV_L2_EXT_VLAN & flags) seq_printf(f, " %-20s = %u[%#x]\n", "External VLAN", ntohs(l2->ext_vlan), ntohs(l2->ext_vlan)); if (FV_L2_INT_VLAN & flags) seq_printf(f, " %-20s = %u[%#x]\n", "Internal VLAN", ntohs(l2->int_vlan), ntohs(l2->int_vlan)); if (FV_L2_PPPOE & flags) seq_printf(f, " %-20s = %u[%#x]\n", "PPPoE ID", ntohs(l2->pppoe_id), ntohs(l2->pppoe_id)); } static void __smgr_pr_learn_ipv4(struct seq_file *f, struct fv_ipv4 *v4, u32 flags) { if (unlikely(!v4)) return; seq_printf(f, " %-20s = %pI4b[%#x]\n", "Source IP", &v4->saddr, ntohl(v4->saddr)); seq_printf(f, " %-20s = %pI4b[%#x]\n", "Dest IP", &v4->daddr, ntohl(v4->daddr)); seq_printf(f, " %-20s = %s %u[%#x]\n", "L4 Protocol", PP_FV_L3_PROTOCOL_STR(v4->protocol), v4->protocol, v4->protocol); seq_printf(f, " %-20s = %u[%#x]\n", "TOS", v4->tos, v4->tos); if (FV_L3_FRAG_1ST & flags) seq_printf(f, " %-20s = %s\n", "Frag", "First"); if (FV_L3_FRAG_2ND & flags) seq_printf(f, " %-20s = %s\n", "Frag", "Second"); } static void __smgr_pr_learn_ipv6(struct seq_file *f, struct fv_ipv6 *v6, u32 flags) { u32 flow = 0; u8 tc = 0; if (unlikely(!v6)) return; tc = PP_FIELD_GET(GENMASK(7, 4), v6->flow_lbl[0]); tc = PP_FIELD_MOD(GENMASK(7, 4), v6->priority, tc); flow = PP_FIELD_MOD(GENMASK(19, 16), v6->flow_lbl[0] & 0x0f, flow); flow = PP_FIELD_MOD(GENMASK(15, 8), v6->flow_lbl[1], flow); flow = PP_FIELD_MOD(GENMASK(7, 0), v6->flow_lbl[2], flow); if (flags > FV_L4_TCP) seq_printf(f, " %-20s = ", "Next Header"); if (FV_L4_TCP & flags) seq_puts(f, "TCP\n"); if (FV_L4_UDP & flags) seq_puts(f, "UDP\n"); if (FV_L4_ESP & flags) seq_puts(f, "ESP\n"); if (FV_L4_SCTP & flags) seq_puts(f, "SCTP\n"); if (FV_L4_ICMP6 & flags) seq_puts(f, "ICMP\n"); seq_printf(f, " %-20s = %pI6\n", "Source IP", &v6->saddr); seq_printf(f, " %-20s = %pI6\n", "Dest IP", &v6->daddr); seq_printf(f, " %-20s = %u[%#x]\n", "TC", tc, tc); seq_printf(f, " %-20s = %u[%#x]\n", "Flow Label", flow, flow); if (FV_L3_FRAG_1ST & flags) seq_printf(f, " %-20s = %s\n", "Frag", "First"); if (FV_L3_FRAG_2ND & flags) seq_printf(f, " %-20s = %s\n", "Frag", "Second"); } static void __smgr_pr_learn_l3(struct seq_file *f, union fv_l3 *l3, __be16 h_proto, u32 flags) { if (unlikely(!l3)) return; if (FV_L3_IPV4 & flags) __smgr_pr_learn_ipv4(f, &l3->v4, flags); else if (FV_L3_IPV6 & flags) __smgr_pr_learn_ipv6(f, &l3->v6, flags); } static void __smgr_pr_learn_l4(struct seq_file *f, union fv_l4 *l4, u32 flags) { if (unlikely(!l4)) return; if ((FV_L4_TCP | FV_L4_UDP | FV_L4_SCTP) & flags) { seq_printf(f, " %-20s = %u[%#x]\n", "Source Port", ntohs(l4->tcp.source), ntohs(l4->tcp.source)); seq_printf(f, " %-20s = %u[%#x]\n", "Dest Port", ntohs(l4->tcp.dest), ntohs(l4->tcp.dest)); } else if ((FV_L4_ICMP4 | FV_L4_ICMP6) & flags) { seq_printf(f, " %-20s = %u[%#x]\n", "ICMP ID", l4->icmp.id, l4->icmp.id); seq_printf(f, " %-20s = %u[%#x]\n", "ICMP Type", l4->icmp.type, l4->icmp.type); } else if (FV_L4_ESP & flags) { seq_printf(f, " %-20s = %u[%#x]\n", "ESP SPI", l4->esp.spi, l4->esp.spi); } } static void __smgr_pr_learn_tunn(struct seq_file *f, union fv_tunnel *tunn, union fv_l4 *l4, u32 flags, u32 tunn_flags) { if (!tunn_flags) return; seq_printf(f, " %-20s = ", "Tunnel Type"); if (FV_L2_PPPOE & flags) seq_puts(f, "[PPPoE]"); if (FV_TUNNEL_L2TPV2_UDP & tunn_flags) seq_puts(f, "[UDP][L2TPV2]"); if (FV_TUNNEL_L2TPV3_UDP & tunn_flags) seq_puts(f, "[UDP][L2TPV3]"); if (FV_TUNNEL_VXLAN & tunn_flags) seq_puts(f, "[UDP][VXLAN]"); if (FV_TUNNEL_GNV & tunn_flags) seq_puts(f, "[UDP][GENEVE]"); if (FV_L4_SCTP & flags) seq_puts(f, "[SCTP]"); if (FV_TUNNEL_L2TPV3_IP & tunn_flags) seq_puts(f, "[L2TPIP]"); if (FV_TUNNEL_GRE_IP & tunn_flags) seq_puts(f, "[IPoGRE]"); if (FV_TUNNEL_GRE_ETH & tunn_flags) seq_puts(f, "[EoGRE]"); if (FV_TUNNEL_DSLITE & tunn_flags) seq_puts(f, "[DsLITE]"); if (FV_TUNNEL_6RD & tunn_flags) seq_puts(f, "[6rd]"); if (FV_TUNNEL_IPSEC & tunn_flags) seq_puts(f, "[IPSec]"); seq_puts(f, "\n"); if (FV_TUNNEL_VXLAN & tunn_flags) seq_printf(f, " %-20s = %u[%#x]\n", "VNI", ntohl(tunn->vxlan.vni), ntohl(tunn->vxlan.vni)); if (FV_TUNNEL_GNV & tunn_flags) seq_printf(f, " %-20s = %#02x%02x%02x\n", "VNI", tunn->geneve.vni[2], tunn->geneve.vni[1], tunn->geneve.vni[0]); if (FV_TUNNEL_L2TPV3_IP & tunn_flags) seq_printf(f, " %-20s = %u[%#x]\n", "Session ID", ntohl(l4->l2tpoip.session_id), ntohl(l4->l2tpoip.session_id)); if ((FV_TUNNEL_L2TPV2_UDP | FV_TUNNEL_L2TPV3_UDP) & tunn_flags) { seq_printf(f, " %-20s = %u[%#x]\n", "Session ID", tunn->l2tpoudp.session_id, tunn->l2tpoudp.session_id); seq_printf(f, " %-20s = %u[%#x]\n", "Tunnel ID", tunn->l2tpoudp.tunnel_id, tunn->l2tpoudp.tunnel_id); } if (FV_L4_SCTP & flags) seq_printf(f, " %-20s = %u[%#x]\n", "VTAG", ntohl(tunn->sctp.vtag), ntohl(tunn->sctp.vtag)); } static void __smgr_pr_learn_pkt(struct seq_file *f, struct fv_pkt_info *pkt) { if (unlikely(!pkt)) return; #if 0 { struct fv_pkt_off *offs; offs = &pkt->fv_offsets; seq_printf(f, " %-20s = %u\n", "Header Length", offs->pkt_hdr_len); seq_printf(f, " %-20s = %u\n", "Outer L2 Off ", offs->outer_offsets.l2); seq_printf(f, " %-20s = %u\n", "Outer L3 Off ", offs->outer_offsets.l3); seq_printf(f, " %-20s = %u\n", "Outer L4 Off ", offs->outer_offsets.l4); seq_printf(f, " %-20s = %u\n", "Tunnel Off ", offs->tunnel_offset); seq_printf(f, " %-20s = %u\n", "Inner L2 Off ", offs->inner_offsets.l2); seq_printf(f, " %-20s = %u\n", "Inner L3 Off ", offs->inner_offsets.l3); seq_printf(f, " %-20s = %u\n", "Inner L4 Off ", offs->inner_offsets.l4); } #endif __smgr_pr_learn_mac(f, &pkt->fv.outer.l2, pkt->fv_outer_bitmap); __smgr_pr_learn_l3(f, &pkt->fv.outer.l3, pkt->fv.outer.l2.h_proto, pkt->fv_outer_bitmap); __smgr_pr_learn_l4(f, &pkt->fv.outer.l4, pkt->fv_outer_bitmap); __smgr_pr_learn_tunn(f, &pkt->fv.tunnel, &pkt->fv.outer.l4, pkt->fv_outer_bitmap, pkt->fv_tunnel_bitmap); __smgr_pr_learn_mac(f, &pkt->fv.inner.l2, pkt->fv_inner_bitmap); __smgr_pr_learn_l3(f, &pkt->fv.inner.l3, pkt->fv.inner.l2.h_proto, pkt->fv_inner_bitmap); __smgr_pr_learn_l4(f, &pkt->fv.inner.l4, pkt->fv_inner_bitmap); } static void __smgr_pr_sess_mod(struct seq_file *f, ulong mod_flags, struct pp_si *si) { char buf[256]; u32 flag; if (unlikely(!si)) return; if (!(SI_IS_SCE_EXIST(si) || SI_IS_DPU_EXIST(si))) return; seq_puts(f, " Modification Record\n"); seq_puts(f, "=====================\n"); seq_printf(f, " %-20s = %#lx ", "Modification Flags", mod_flags); for_each_set_bit (flag, &mod_flags, MOD_FLAG_NUM) seq_printf(f, "[%s]", mod_flag_to_str(flag)); seq_puts(f, "\n"); if (SI_IS_DPU_EXIST(si)) { seq_printf(f, " %-20s = %u[%#x]\n", "NAT Size", si->dpu.nat_sz, si->dpu.nat_sz); seq_printf(f, " %-20s = %u[%#x]\n", "New Header Size", si->dpu.nhdr_sz, si->dpu.nhdr_sz); seq_printf(f, " %-20s = %u[%#x]\n", "New Header L3 Offset", si->dpu.nhdr_l3_off, si->dpu.nhdr_l3_off); seq_printf(f, " %-20s = %u[%#x]\n", "Layer Field Offset", si->dpu.lyr_fld_off, si->dpu.lyr_fld_off); seq_printf(f, " %-20s = %u[%#x]\n", "PPPoE Offset", si->dpu.pppoe_off, si->dpu.pppoe_off); } if (si->dpu.nhdr_sz) { hex_dump_to_buffer(si->bce.nhdr, si->dpu.nhdr_sz, 32, 4, buf, sizeof(buf), false); (void)strreplace(buf, '\n', ' '); seq_printf(f, " %-20s = %s\n", "New Header", buf); } if (si->dpu.nat_sz == sizeof(si->bce.nat.v4)) { seq_printf(f, " %-20s = %pI4b[%#x]\n", "Source IP", &si->bce.nat.v4.saddr, si->bce.nat.v4.saddr); seq_printf(f, " %-20s = %pI4b[%#x]\n", "Dest IP", &si->bce.nat.v4.daddr, si->bce.nat.v4.daddr); } else if (si->dpu.nat_sz == sizeof(si->bce.nat.v6)) { seq_printf(f, " %-20s = %pI6\n", "Source IP", &si->bce.nat.v6.saddr); seq_printf(f, " %-20s = %pI6\n", "Dest IP", &si->bce.nat.v6.daddr); } if (SI_IS_SCE_EXIST(si)) { seq_printf(f, " %-20s = %u[%#x]\n", "Source Port", si->sce.new_src_port, si->sce.new_src_port); seq_printf(f, " %-20s = %u[%#x]\n", "Dest Port", si->sce.new_dst_port, si->sce.new_dst_port); seq_printf(f, " %-20s = %#x\n", "L3 Checksum Delta", si->sce.l3_csum_delta); seq_printf(f, " %-20s = %#x\n", "L4 Checksum Delta", si->sce.l4_csum_delta); seq_printf(f, " %-20s = %#x\n", "New Header Checksum", si->sce.nhdr_csum); seq_printf(f, " %-20s = %#x\n", "TOS", si->sce.dscp); seq_printf(f, " %-20s = %d\n", "Packet Length Diff", si->pkt_len_diff); seq_printf(f, " %-20s = %d\n", "IP Length Diff", si->sce.tot_len_diff); seq_printf(f, " %-20s = %u\n", "TTL/Hop Limit Diff", si->sce.ttl_diff); seq_printf(f, " %-20s = %u\n", "PPPoE Diff", si->sce.pppoe_diff); } } /** * @brief Dump specific session info including packets and bytes * counters */ void __smgr_dbg_session_dump(struct seq_file *f) { struct sess_db_info info; struct pp_dsi dsi; struct pp_si si; char buf[128]; s32 ret, n; memset(&info, 0, sizeof(info)); memset(&si, 0, sizeof(si)); memset(&dsi, 0, sizeof(dsi)); ret = smgr_session_info_get(dbg_sess_id, &info); if (ret) return; ret = smgr_session_si_get(dbg_sess_id, &si); if (ret) return; ret = smgr_session_dsi_get(dbg_sess_id, &dsi); if (ret) return; pr_buf(buf, sizeof(buf), n, "Session %u Info", info.sess_id); seq_puts(f, "##############################\n"); seq_printf(f, "## %-22s ##\n", buf); seq_puts(f, "##############################\n"); seq_printf(f, " %-20s = %s\n", "Valid", BOOL2STR(dsi.valid)); seq_printf(f, " %-20s = %s\n", "Active", BOOL2STR(dsi.active)); seq_printf(f, " %-20s = %s\n", "Stale", BOOL2STR(dsi.stale)); seq_printf(f, " %-20s = %s\n", "Type", smgr_is_sess_routed(&info) ? "Routed" : "Bridge"); seq_printf(f, " %-20s = %s\n", "Divert", BOOL2STR(dsi.divert)); __smgr_pr_session_flags(f, info.flags); seq_printf(f, " %-20s = %u - %s\n", "Recipe", si.recipe_idx, mod_rcp_to_str(si.recipe_idx)); seq_printf(f, " %-20s = %u - %s\n", "Color", si.color, PP_COLOR_TO_STR(si.color)); seq_printf(f, " %-20s = %u\n", "FV Size", si.fv_sz); seq_printf(f, " %-20s = %u\n", "TDOX Flow/LRO Info", si.tdox_flow); __smgr_pr_si_chck_flags(f, si.chck_flags); seq_puts(f, "\n"); seq_puts(f, " Stats\n"); seq_puts(f, "=======\n"); seq_printf(f, " %-20s = %llu\n", "Packets", dsi.pkts_cnt); seq_printf(f, " %-20s = %llu\n", "Bytes", dsi.bytes_cnt); seq_puts(f, "\n"); seq_puts(f, " Ingress Packet\n"); seq_puts(f, "================\n"); seq_printf(f, " %-20s = %u\n", "Port", info.in_port); __smgr_pr_learn_pkt(f, &info.ingress); seq_puts(f, "\n"); seq_puts(f, " Egress Packet\n"); seq_puts(f, "===============\n"); seq_printf(f, " %-20s = %u\n", "Port", si.eg_port); seq_printf(f, " %-20s = %u\n", "Dest Q", si.dst_q); seq_printf(f, " %-20s = %u\n", "Dynamic Dest Q", dsi.dst_q); __smgr_pr_learn_pkt(f, &info.egress); seq_puts(f, "\n"); __smgr_pr_sess_mod(f, info.mod_flags, &si); seq_puts(f, "\n"); seq_puts(f, " Hash\n"); seq_puts(f, "======\n"); seq_printf(f, " %-20s = %#x\n", "H1", info.hash.h1); seq_printf(f, " %-20s = %#x\n", "H2", info.hash.h2); seq_printf(f, " %-20s = %#x\n", "Signature", info.hash.sig); seq_puts(f, "\n"); if (smgr_is_sess_mcast_dst(&info) || smgr_is_sess_mcast_grp(&info)) { seq_puts(f, " Multicast\n"); seq_puts(f, "==========\n"); seq_printf(f, " %-20s = %#x\n", "Group-ID", info.mcast.grp_idx); if (smgr_is_sess_mcast_dst(&info)) { seq_printf(f, " %-20s = %#x\n", "Dest-ID", info.mcast.dst_idx); } seq_puts(f, "\n"); } } PP_DEFINE_DEBUGFS(session, __smgr_dbg_session_dump, __smgr_dbg_session_set); void __smgr_dbg_stats_dump(struct seq_file *f) { struct smgr_stats stats; u32 n_sessions; s32 ret; ret = pp_max_sessions_get(&n_sessions); if (ret) return; memset(&stats, 0, sizeof(stats)); ret = pp_smgr_stats_get(&stats); if (ret) return; seq_puts(f, " +---------------------------------------------------------------------------------------+\n"); seq_puts(f, " | Session Manager Statistics |\n"); seq_puts(f, " +------------------------------+------------+------------------------------+------------+\n"); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Max Supported Sessions", n_sessions, "Free Sessions", atomic_read(&stats.sess_free)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Open Sessions", atomic_read(&stats.sess_open), "Open Sessions High Watermark", atomic_read(&stats.sess_open_hi_wm)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Session Create Requests", atomic_read(&stats.sess_create_req), "Sessions Created", atomic_read(&stats.sess_created)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Session Delete Requests", atomic_read(&stats.sess_delete_req), "Deleted Sessions", atomic_read(&stats.sess_deleted)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Port Flush Requests", atomic_read(&stats.port_flush_req), "Ports Flushed", atomic_read(&stats.port_flushed)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Flush All Requests", atomic_read(&stats.flush_all_req), "Flush All Done", atomic_read(&stats.flush_all_done)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Inactive Sessions Request", atomic_read(&stats.inactive_req), "Inactive Sessions Req Done", atomic_read(&stats.inactive_done)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Lookup Success", atomic_read(&stats.sess_lu_succ), "Lookup Fail", atomic_read(&stats.sess_lu_fail)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10s |\n", "Wait for Crawler Idle", atomic_read(&stats.crwlr_idle_wait), "", ""); seq_puts(f, " +------------------------------+------------+------------------------------+------------+\n"); seq_puts(f, " | Errors |\n"); seq_puts(f, " +------------------------------+------------+------------------------------+------------+\n"); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Session Create Fail", atomic_read(&stats.sess_create_fail), "Session Delete Fail", atomic_read(&stats.sess_delete_fail)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Port Flush Fail", atomic_read(&stats.port_flush_fail), "Flush All Fail", atomic_read(&stats.flush_all_fail)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10s |\n", "Inactive Sessions Req Fail", atomic_read(&stats.inactive_fail), "", ""); seq_puts(f, " +------------------------------+------------+------------------------------+------------+\n"); seq_puts(f, " | Error Cause |\n"); seq_puts(f, " +------------------------------+------------+------------------------------+------------+\n"); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Invalid Arguments", atomic_read(&stats.invalid_args), "Lookup Error", atomic_read(&stats.sess_lookup_err)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Unsupported Protocols", atomic_read(&stats.sess_not_supported), "SI Error", atomic_read(&stats.sess_si_create_err)); seq_printf(f, " | %-28s | %-10u | %-28s | %-10u |\n", "Cache Error", atomic_read(&stats.work_args_cache_err), "HW Error", atomic_read(&stats.hw_err)); seq_puts(f, " +------------------------------+------------+------------------------------+------------+\n"); seq_puts(f, "\n"); } void __smgr_dbg_stats_reset(char *cmd_buf, void *data) { if (!strncmp(cmd_buf, "0", strlen("0"))) pp_smgr_stats_reset(); } PP_DEFINE_DEBUGFS(stats, __smgr_dbg_stats_dump, __smgr_dbg_stats_reset); enum sess_del_opts { sess_del_opt_help = 1, sess_del_opt_id, sess_del_opt_prio, sess_del_opt_async, }; static const match_table_t sess_del_tokens = { { sess_del_opt_help, "help" }, { sess_del_opt_id, "id=%u" }, { sess_del_opt_prio, "prio=%u" }, { sess_del_opt_async, "async" }, }; /** * @brief Session delete help */ static void __smgr_dbg_sess_del_help(void) { pr_info("\n"); pr_info(" Usage: echo