1 /*
2 * Copyright (c) 2025 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_DECLARE(net_shell);
9
10 #include <zephyr/net/net_pkt_filter.h>
11
12 #include "net_shell_private.h"
13
14
15 #if defined(CONFIG_NET_PKT_FILTER)
rule_type2str(enum npf_rule_type type)16 static const char *rule_type2str(enum npf_rule_type type)
17 {
18 switch (type) {
19 case NPF_RULE_TYPE_SEND:
20 return "send";
21 case NPF_RULE_TYPE_RECV:
22 return "recv";
23 case NPF_RULE_TYPE_LOCAL_IN_RECV:
24 return "local recv";
25 case NPF_RULE_TYPE_IPV4_RECV:
26 return "IPv4 recv";
27 case NPF_RULE_TYPE_IPV6_RECV:
28 return "IPv6 recv";
29 case NPF_RULE_TYPE_UNKNOWN:
30 __fallthrough;
31 default:
32 break;
33 }
34
35 return "<UNKNOWN>";
36 }
37
verdict2str(enum net_verdict verdict)38 static const char *verdict2str(enum net_verdict verdict)
39 {
40 switch (verdict) {
41 case NET_OK:
42 return "OK";
43 case NET_DROP:
44 return "DROP";
45 case NET_CONTINUE:
46 return "CONTINUE";
47 default:
48 break;
49 }
50
51 return "<UNK>";
52 }
53
rule_cb(struct npf_rule * rule,enum npf_rule_type type,void * user_data)54 static void rule_cb(struct npf_rule *rule, enum npf_rule_type type, void *user_data)
55 {
56 struct net_shell_user_data *data = user_data;
57 const struct shell *sh = data->sh;
58 int *count = data->user_data;
59 uint8_t tc;
60 int thread_prio;
61
62 PR("[%2d] %-10s %-8s ",
63 (*count) + 1, rule_type2str(type), verdict2str(rule->result));
64
65 if (rule->result == NET_CONTINUE && type == NPF_RULE_TYPE_SEND) {
66 tc = net_tx_priority2tc(rule->priority);
67 if (net_tc_tx_is_immediate(tc, rule->priority)) {
68 PR("%8d %5d SKIP ", rule->priority, tc);
69 } else {
70 thread_prio = net_tc_tx_thread_priority(tc);
71 PR("%8d %5d %11d ", rule->priority, tc, thread_prio);
72 }
73 } else if (rule->result == NET_CONTINUE) {
74 tc = net_rx_priority2tc(rule->priority);
75 if (net_tc_rx_is_immediate(tc, rule->priority)) {
76 PR("%8d %5d SKIP ", rule->priority, tc);
77 } else {
78 thread_prio = net_tc_rx_thread_priority(tc);
79 PR("%8d %5d %11d ", rule->priority, tc, thread_prio);
80 }
81 } else {
82 PR(" N/A N/A N/A ");
83 }
84
85 PR("%-5d", rule->nb_tests);
86
87 for (int i = 0; i < rule->nb_tests; i++) {
88 /* Allocate room for storing two full IPv4/6 addresses */
89 #define MAX_BUF_LEN ((IS_ENABLED(CONFIG_NET_IPV6) ? \
90 NET_INET6_ADDRSTRLEN : NET_INET_ADDRSTRLEN) * 2)
91 char buf[MAX_BUF_LEN] = { 0 };
92 struct npf_test *test;
93 const char *str;
94
95 test = rule->tests[i];
96
97 str = npf_test_get_str(test, buf, sizeof(buf) - 1);
98 PR("%s%s%s", str, buf[0] != '\0' ? buf : "",
99 i == rule->nb_tests - 1 ? "" : ",");
100 }
101
102 PR("\n");
103 (*count)++;
104 }
105 #endif /* CONFIG_NET_PKT_FILTER */
106
cmd_net_filter(const struct shell * sh,size_t argc,char * argv[])107 static int cmd_net_filter(const struct shell *sh, size_t argc, char *argv[])
108 {
109 ARG_UNUSED(argc);
110 ARG_UNUSED(argv);
111
112 #if defined(CONFIG_NET_PKT_FILTER)
113 struct net_shell_user_data user_data;
114 int count = 0;
115
116 PR("Rule %-10s Verdict Pkt-Prio Queue Thread-Prio Tests\n", "Type");
117
118 user_data.sh = sh;
119 user_data.user_data = &count;
120
121 npf_rules_foreach(rule_cb, &user_data);
122
123 if (count == 0) {
124 PR("No network packet filter rules\n");
125 }
126 #else
127 PR_INFO("Set %s to enable %s support.\n",
128 "CONFIG_NET_PKT_FILTER",
129 "packet filter information");
130
131 #endif /* CONFIG_NET_PKT_FILTER */
132
133 return 0;
134 }
135
136
137 SHELL_SUBCMD_ADD((net), filter, NULL, "Print information about network packet filters.",
138 cmd_net_filter, 1, 0);
139