net: shell: Add network mgmt events monitor support
Add "net events [on|off]" command that can be used to monitor the generated network management events. The monitor output looks like this when enabled: EVENT: L2 [1] up EVENT: L3 [1] IPv6 mcast address add ff02::1:ff00:1 EVENT: L3 [1] IPv6 mcast join ff02::1:ff00:1 EVENT: L3 [1] IPv6 address add 2001:db8::1 EVENT: L4 [1] connected EVENT: L3 [1] IPv6 prefix add 2002:5b9b:41a0:: EVENT: L3 [1] IPv6 address add 2002:5b9b:41a0:0:fec2:3dff:fe11:c147 EVENT: L3 [1] IPv6 neighbor add fe80::9ec7:a6ff:fe5e:4735 EVENT: L3 [1] IPv6 router add fe80::9ec7:a6ff:fe5e:4735 EVENT: L3 [1] IPv6 DAD ok fe80::fec2:3dff:fe11:c147 EVENT: L3 [1] IPv6 DAD ok 2001:db8::1 EVENT: L3 [1] IPv6 DAD ok 2002:5b9b:41a0:0:fec2:3dff:fe11:c147 EVENT: L3 [1] IPv4 address add 192.168.1.69 EVENT: L3 [1] DHCPv4 bound 192.168.1.69 Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
parent
619dcef498
commit
accaab2112
|
@ -22,6 +22,8 @@ The following net-shell commands are implemented:
|
|||
"net conn", "Print information about network connections."
|
||||
"net dns", "Show how DNS is configured. The command can also be used to
|
||||
resolve a DNS name. Only available if :option:`CONFIG_DNS_RESOLVER` is set."
|
||||
"net events", "Enable network event monitoring. Only available if
|
||||
:option:`CONFIG_NET_MGMT_EVENT_MONITOR` is set."
|
||||
"net gptp", "Print information about gPTP support. Only available if
|
||||
:option:`CONFIG_NET_GPTP` is set."
|
||||
"net iface", "Print information about network interfaces."
|
||||
|
|
|
@ -36,6 +36,7 @@ config NET_MGMT_EVENT_THREAD_PRIO
|
|||
|
||||
config NET_MGMT_EVENT_QUEUE_SIZE
|
||||
int "Size of event queue"
|
||||
default 16 if NET_MGMT_EVENT_MONITOR
|
||||
default 2
|
||||
range 1 1024
|
||||
help
|
||||
|
@ -51,6 +52,24 @@ config NET_MGMT_EVENT_INFO
|
|||
and listeners will then be able to get it. Such information depends
|
||||
on the type of event.
|
||||
|
||||
config NET_MGMT_EVENT_MONITOR
|
||||
bool "Monitor network events from net shell"
|
||||
depends on NET_SHELL && NET_MGMT_EVENT_INFO
|
||||
help
|
||||
Allow user to monitor network events from net shell using
|
||||
"net events [on|off]" command. The monitoring is disabled by
|
||||
default. Note that you should probably increase the value of
|
||||
NET_MGMT_EVENT_QUEUE_SIZE from the default in order not to miss
|
||||
any events.
|
||||
|
||||
config NET_MGMT_EVENT_MONITOR_AUTO_START
|
||||
bool "Start the event monitor automatically at boot"
|
||||
depends on NET_MGMT_EVENT_MONITOR && SHELL_BACKEND_SERIAL
|
||||
help
|
||||
Allow user to start monitoring network events automatically
|
||||
when the system starts. The auto start is disabled by default.
|
||||
The default UART based shell is used to print data.
|
||||
|
||||
module = NET_MGMT_EVENT
|
||||
module-dep = NET_LOG
|
||||
module-str = Log level for network management event core
|
||||
|
|
|
@ -19,6 +19,7 @@ LOG_MODULE_REGISTER(net_shell, LOG_LEVEL_DBG);
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <shell/shell.h>
|
||||
#include <shell/shell_uart.h>
|
||||
|
||||
#include <net/net_if.h>
|
||||
#include <net/dns_resolve.h>
|
||||
|
@ -1887,6 +1888,401 @@ static int cmd_net_dns(const struct shell *shell, size_t argc, char *argv[])
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NET_MGMT_EVENT_MONITOR)
|
||||
#define EVENT_MON_STACK_SIZE 1024
|
||||
#define THREAD_PRIORITY K_PRIO_COOP(2)
|
||||
#define MAX_EVENT_INFO_SIZE NET_EVENT_INFO_MAX_SIZE
|
||||
#define MONITOR_L2_MASK (_NET_EVENT_IF_BASE)
|
||||
#define MONITOR_L3_IPV4_MASK (_NET_EVENT_IPV4_BASE)
|
||||
#define MONITOR_L3_IPV6_MASK (_NET_EVENT_IPV6_BASE)
|
||||
#define MONITOR_L4_MASK (_NET_EVENT_L4_BASE)
|
||||
|
||||
static bool net_event_monitoring;
|
||||
static bool net_event_shutting_down;
|
||||
static struct net_mgmt_event_callback l2_cb;
|
||||
static struct net_mgmt_event_callback l3_ipv4_cb;
|
||||
static struct net_mgmt_event_callback l3_ipv6_cb;
|
||||
static struct net_mgmt_event_callback l4_cb;
|
||||
static struct k_thread event_mon;
|
||||
static K_THREAD_STACK_DEFINE(event_mon_stack, EVENT_MON_STACK_SIZE);
|
||||
|
||||
struct event_msg {
|
||||
struct net_if *iface;
|
||||
size_t len;
|
||||
uint32_t event;
|
||||
uint8_t data[MAX_EVENT_INFO_SIZE];
|
||||
};
|
||||
|
||||
K_MSGQ_DEFINE(event_mon_msgq, sizeof(struct event_msg),
|
||||
CONFIG_NET_MGMT_EVENT_QUEUE_SIZE, sizeof(intptr_t));
|
||||
|
||||
static void event_handler(struct net_mgmt_event_callback *cb,
|
||||
uint32_t mgmt_event, struct net_if *iface)
|
||||
{
|
||||
struct event_msg msg;
|
||||
int ret;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
|
||||
msg.len = MIN(sizeof(msg.data), cb->info_length);
|
||||
msg.event = mgmt_event;
|
||||
msg.iface = iface;
|
||||
|
||||
if (cb->info_length > 0) {
|
||||
memcpy(msg.data, cb->info, msg.len);
|
||||
}
|
||||
|
||||
ret = k_msgq_put(&event_mon_msgq, (void *)&msg, K_MSEC(10));
|
||||
if (ret < 0) {
|
||||
NET_ERR("Cannot write to msgq (%d)\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *get_l2_desc(uint32_t event)
|
||||
{
|
||||
static const char *desc = "<unknown event>";
|
||||
|
||||
switch (event) {
|
||||
case NET_EVENT_IF_DOWN:
|
||||
desc = "down";
|
||||
break;
|
||||
case NET_EVENT_IF_UP:
|
||||
desc = "up";
|
||||
break;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
static char *get_l3_desc(struct event_msg *msg,
|
||||
const char **desc, const char **desc2,
|
||||
char *extra_info, size_t extra_info_len)
|
||||
{
|
||||
static const char *desc_unknown = "<unknown event>";
|
||||
char *info = NULL;
|
||||
|
||||
*desc = desc_unknown;
|
||||
|
||||
switch (msg->event) {
|
||||
case NET_EVENT_IPV6_ADDR_ADD:
|
||||
*desc = "IPv6 address";
|
||||
*desc2 = "add";
|
||||
info = net_addr_ntop(AF_INET6, msg->data, extra_info,
|
||||
extra_info_len);
|
||||
break;
|
||||
case NET_EVENT_IPV6_ADDR_DEL:
|
||||
*desc = "IPv6 address";
|
||||
*desc2 = "del";
|
||||
info = net_addr_ntop(AF_INET6, msg->data, extra_info,
|
||||
extra_info_len);
|
||||
break;
|
||||
case NET_EVENT_IPV6_MADDR_ADD:
|
||||
*desc = "IPv6 mcast address";
|
||||
*desc2 = "add";
|
||||
info = net_addr_ntop(AF_INET6, msg->data, extra_info,
|
||||
extra_info_len);
|
||||
break;
|
||||
case NET_EVENT_IPV6_MADDR_DEL:
|
||||
*desc = "IPv6 mcast address";
|
||||
*desc2 = "del";
|
||||
info = net_addr_ntop(AF_INET6, msg->data, extra_info,
|
||||
extra_info_len);
|
||||
break;
|
||||
case NET_EVENT_IPV6_PREFIX_ADD:
|
||||
*desc = "IPv6 prefix";
|
||||
*desc2 = "add";
|
||||
info = net_addr_ntop(AF_INET6, msg->data, extra_info,
|
||||
extra_info_len);
|
||||
break;
|
||||
case NET_EVENT_IPV6_PREFIX_DEL:
|
||||
*desc = "IPv6 prefix";
|
||||
*desc2 = "del";
|
||||
info = net_addr_ntop(AF_INET6, msg->data, extra_info,
|
||||
extra_info_len);
|
||||
break;
|
||||
case NET_EVENT_IPV6_MCAST_JOIN:
|
||||
*desc = "IPv6 mcast";
|
||||
*desc2 = "join";
|
||||
info = net_addr_ntop(AF_INET6, msg->data, extra_info,
|
||||
extra_info_len);
|
||||
break;
|
||||
case NET_EVENT_IPV6_MCAST_LEAVE:
|
||||
*desc = "IPv6 mcast";
|
||||
*desc2 = "leave";
|
||||
info = net_addr_ntop(AF_INET6, msg->data, extra_info,
|
||||
extra_info_len);
|
||||
break;
|
||||
case NET_EVENT_IPV6_ROUTER_ADD:
|
||||
*desc = "IPv6 router";
|
||||
*desc2 = "add";
|
||||
info = net_addr_ntop(AF_INET6, msg->data, extra_info,
|
||||
extra_info_len);
|
||||
break;
|
||||
case NET_EVENT_IPV6_ROUTER_DEL:
|
||||
*desc = "IPv6 router";
|
||||
*desc2 = "del";
|
||||
info = net_addr_ntop(AF_INET6, msg->data, extra_info,
|
||||
extra_info_len);
|
||||
break;
|
||||
case NET_EVENT_IPV6_ROUTE_ADD:
|
||||
*desc = "IPv6 route";
|
||||
*desc2 = "add";
|
||||
info = net_addr_ntop(AF_INET6, msg->data, extra_info,
|
||||
extra_info_len);
|
||||
break;
|
||||
case NET_EVENT_IPV6_ROUTE_DEL:
|
||||
*desc = "IPv6 route";
|
||||
*desc2 = "del";
|
||||
info = net_addr_ntop(AF_INET6, msg->data, extra_info,
|
||||
extra_info_len);
|
||||
break;
|
||||
case NET_EVENT_IPV6_DAD_SUCCEED:
|
||||
*desc = "IPv6 DAD";
|
||||
*desc2 = "ok";
|
||||
info = net_addr_ntop(AF_INET6, msg->data, extra_info,
|
||||
extra_info_len);
|
||||
break;
|
||||
case NET_EVENT_IPV6_DAD_FAILED:
|
||||
*desc = "IPv6 DAD";
|
||||
*desc2 = "fail";
|
||||
info = net_addr_ntop(AF_INET6, msg->data, extra_info,
|
||||
extra_info_len);
|
||||
break;
|
||||
case NET_EVENT_IPV6_NBR_ADD:
|
||||
*desc = "IPv6 neighbor";
|
||||
*desc2 = "add";
|
||||
info = net_addr_ntop(AF_INET6, msg->data, extra_info,
|
||||
extra_info_len);
|
||||
break;
|
||||
case NET_EVENT_IPV6_NBR_DEL:
|
||||
*desc = "IPv6 neighbor";
|
||||
*desc2 = "del";
|
||||
info = net_addr_ntop(AF_INET6, msg->data, extra_info,
|
||||
extra_info_len);
|
||||
break;
|
||||
case NET_EVENT_IPV4_ADDR_ADD:
|
||||
*desc = "IPv4 address";
|
||||
*desc2 = "add";
|
||||
info = net_addr_ntop(AF_INET, msg->data, extra_info,
|
||||
extra_info_len);
|
||||
break;
|
||||
case NET_EVENT_IPV4_ADDR_DEL:
|
||||
*desc = "IPv4 address";
|
||||
*desc2 = "del";
|
||||
info = net_addr_ntop(AF_INET, msg->data, extra_info,
|
||||
extra_info_len);
|
||||
break;
|
||||
case NET_EVENT_IPV4_ROUTER_ADD:
|
||||
*desc = "IPv4 router";
|
||||
*desc2 = "add";
|
||||
info = net_addr_ntop(AF_INET, msg->data, extra_info,
|
||||
extra_info_len);
|
||||
break;
|
||||
case NET_EVENT_IPV4_ROUTER_DEL:
|
||||
*desc = "IPv4 router";
|
||||
*desc2 = "del";
|
||||
info = net_addr_ntop(AF_INET, msg->data, extra_info,
|
||||
extra_info_len);
|
||||
break;
|
||||
case NET_EVENT_IPV4_DHCP_START:
|
||||
*desc = "DHCPv4";
|
||||
*desc2 = "start";
|
||||
break;
|
||||
case NET_EVENT_IPV4_DHCP_BOUND:
|
||||
*desc = "DHCPv4";
|
||||
*desc2 = "bound";
|
||||
#if defined(CONFIG_NET_DHCPV4)
|
||||
struct net_if_dhcpv4 *data = (struct net_if_dhcpv4 *)msg->data;
|
||||
|
||||
info = net_addr_ntop(AF_INET, &data->requested_ip, extra_info,
|
||||
extra_info_len);
|
||||
#endif
|
||||
break;
|
||||
case NET_EVENT_IPV4_DHCP_STOP:
|
||||
*desc = "DHCPv4";
|
||||
*desc2 = "stop";
|
||||
break;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static const char *get_l4_desc(uint32_t event)
|
||||
{
|
||||
static const char *desc = "<unknown event>";
|
||||
|
||||
switch (event) {
|
||||
case NET_EVENT_L4_CONNECTED:
|
||||
desc = "connected";
|
||||
break;
|
||||
case NET_EVENT_L4_DISCONNECTED:
|
||||
desc = "disconnected";
|
||||
break;
|
||||
case NET_EVENT_DNS_SERVER_ADD:
|
||||
desc = "DNS server add";
|
||||
break;
|
||||
case NET_EVENT_DNS_SERVER_DEL:
|
||||
desc = "DNS server del";
|
||||
break;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
/* We use a separate thread in order not to do any shell printing from
|
||||
* event handler callback (to avoid stack size issues).
|
||||
*/
|
||||
static void event_mon_handler(const struct shell *shell)
|
||||
{
|
||||
char extra_info[NET_IPV6_ADDR_LEN];
|
||||
struct event_msg msg;
|
||||
|
||||
net_mgmt_init_event_callback(&l2_cb, event_handler,
|
||||
MONITOR_L2_MASK);
|
||||
net_mgmt_add_event_callback(&l2_cb);
|
||||
|
||||
net_mgmt_init_event_callback(&l3_ipv4_cb, event_handler,
|
||||
MONITOR_L3_IPV4_MASK);
|
||||
net_mgmt_add_event_callback(&l3_ipv4_cb);
|
||||
|
||||
net_mgmt_init_event_callback(&l3_ipv6_cb, event_handler,
|
||||
MONITOR_L3_IPV6_MASK);
|
||||
net_mgmt_add_event_callback(&l3_ipv6_cb);
|
||||
|
||||
net_mgmt_init_event_callback(&l4_cb, event_handler,
|
||||
MONITOR_L4_MASK);
|
||||
net_mgmt_add_event_callback(&l4_cb);
|
||||
|
||||
while (net_event_shutting_down == false) {
|
||||
const char *layer_str = "<unknown layer>";
|
||||
const char *desc = "", *desc2 = "";
|
||||
char *info = NULL;
|
||||
uint32_t layer;
|
||||
|
||||
(void)k_msgq_get(&event_mon_msgq, &msg, K_FOREVER);
|
||||
|
||||
if (msg.iface == NULL && msg.event == 0 && msg.len == 0) {
|
||||
/* This is the stop message */
|
||||
continue;
|
||||
}
|
||||
|
||||
layer = NET_MGMT_GET_LAYER(msg.event);
|
||||
if (layer == NET_MGMT_LAYER_L2) {
|
||||
layer_str = "L2";
|
||||
desc = get_l2_desc(msg.event);
|
||||
} else if (layer == NET_MGMT_LAYER_L3) {
|
||||
layer_str = "L3";
|
||||
info = get_l3_desc(&msg, &desc, &desc2,
|
||||
extra_info, NET_IPV6_ADDR_LEN);
|
||||
} else if (layer == NET_MGMT_LAYER_L4) {
|
||||
layer_str = "L4";
|
||||
desc = get_l4_desc(msg.event);
|
||||
}
|
||||
|
||||
PR_INFO("EVENT: %s [%d] %s%s%s%s%s\n", layer_str,
|
||||
net_if_get_by_iface(msg.iface), desc,
|
||||
desc2 ? " " : "", desc2 ? desc2 : "",
|
||||
info ? " " : "", info ? info : "");
|
||||
}
|
||||
|
||||
net_mgmt_del_event_callback(&l2_cb);
|
||||
net_mgmt_del_event_callback(&l3_ipv4_cb);
|
||||
net_mgmt_del_event_callback(&l3_ipv6_cb);
|
||||
net_mgmt_del_event_callback(&l4_cb);
|
||||
|
||||
k_msgq_purge(&event_mon_msgq);
|
||||
|
||||
net_event_monitoring = false;
|
||||
net_event_shutting_down = false;
|
||||
|
||||
PR_INFO("Network event monitoring %s.\n", "disabled");
|
||||
}
|
||||
#endif
|
||||
|
||||
static int cmd_net_events_on(const struct shell *shell, size_t argc,
|
||||
char *argv[])
|
||||
{
|
||||
#if defined(CONFIG_NET_MGMT_EVENT_MONITOR)
|
||||
k_tid_t tid;
|
||||
|
||||
if (net_event_monitoring) {
|
||||
PR_INFO("Network event monitoring is already %s.\n",
|
||||
"enabled");
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
tid = k_thread_create(&event_mon, event_mon_stack,
|
||||
K_THREAD_STACK_SIZEOF(event_mon_stack),
|
||||
(k_thread_entry_t)event_mon_handler,
|
||||
(void *)shell, NULL, NULL, THREAD_PRIORITY, 0,
|
||||
K_FOREVER);
|
||||
if (!tid) {
|
||||
PR_ERROR("Cannot create network event monitor thread!");
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
k_thread_name_set(tid, "event_mon");
|
||||
|
||||
PR_INFO("Network event monitoring %s.\n", "enabled");
|
||||
|
||||
net_event_monitoring = true;
|
||||
net_event_shutting_down = false;
|
||||
|
||||
k_thread_start(tid);
|
||||
#else
|
||||
PR_INFO("Network management events are not supported. "
|
||||
"Set CONFIG_NET_MGMT_EVENT_MONITOR to enable it.\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_net_events_off(const struct shell *shell, size_t argc,
|
||||
char *argv[])
|
||||
{
|
||||
#if defined(CONFIG_NET_MGMT_EVENT_MONITOR)
|
||||
static const struct event_msg msg;
|
||||
int ret;
|
||||
|
||||
if (!net_event_monitoring) {
|
||||
PR_INFO("Network event monitoring is already %s.\n",
|
||||
"disabled");
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
net_event_shutting_down = true;
|
||||
|
||||
ret = k_msgq_put(&event_mon_msgq, (void *)&msg, K_MSEC(100));
|
||||
if (ret < 0) {
|
||||
PR_ERROR("Cannot write to msgq (%d)\n", ret);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
#else
|
||||
PR_INFO("Network management events are not supported. "
|
||||
"Set CONFIG_NET_MGMT_EVENT_MONITOR to enable it.\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_net_events(const struct shell *shell, size_t argc, char *argv[])
|
||||
{
|
||||
#if defined(CONFIG_NET_MGMT_EVENT_MONITOR)
|
||||
PR("Network event monitoring is %s.\n",
|
||||
net_event_monitoring ? "enabled" : "disabled");
|
||||
|
||||
if (!argv[1]) {
|
||||
PR_INFO("Give 'on' to enable event monitoring and "
|
||||
"'off' to disable it.\n");
|
||||
}
|
||||
#else
|
||||
PR_INFO("Network management events are not supported. "
|
||||
"Set CONFIG_NET_MGMT_EVENT_MONITOR to enable it.\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NET_GPTP)
|
||||
static const char *selected_role_str(int port);
|
||||
|
||||
|
@ -4481,6 +4877,14 @@ SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_dns,
|
|||
SHELL_SUBCMD_SET_END
|
||||
);
|
||||
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_events,
|
||||
SHELL_CMD(on, NULL, "Turn on network event monitoring.",
|
||||
cmd_net_events_on),
|
||||
SHELL_CMD(off, NULL, "Turn off network event monitoring.",
|
||||
cmd_net_events_off),
|
||||
SHELL_SUBCMD_SET_END
|
||||
);
|
||||
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_gptp,
|
||||
SHELL_CMD(port, NULL,
|
||||
"'net gptp [<port>]' prints detailed information about "
|
||||
|
@ -4768,6 +5172,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(net_commands,
|
|||
cmd_net_conn),
|
||||
SHELL_CMD(dns, &net_cmd_dns, "Show how DNS is configured.",
|
||||
cmd_net_dns),
|
||||
SHELL_CMD(events, &net_cmd_events, "Monitor network management events.",
|
||||
cmd_net_events),
|
||||
SHELL_CMD(gptp, &net_cmd_gptp, "Print information about gPTP support.",
|
||||
cmd_net_gptp),
|
||||
SHELL_CMD(iface, &net_cmd_iface,
|
||||
|
@ -4805,5 +5211,14 @@ SHELL_CMD_REGISTER(net, &net_commands, "Networking commands", NULL);
|
|||
|
||||
int net_shell_init(void)
|
||||
{
|
||||
#if defined(CONFIG_NET_MGMT_EVENT_MONITOR_AUTO_START)
|
||||
char *argv[] = {
|
||||
"on",
|
||||
NULL
|
||||
};
|
||||
|
||||
(void)cmd_net_events_on(shell_backend_uart_get_ptr(), 1, argv);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -212,6 +212,8 @@ CONFIG_NET_MGMT_EVENT_QUEUE_SIZE=2
|
|||
CONFIG_NET_MGMT_EVENT_LOG_LEVEL_DBG=y
|
||||
CONFIG_NET_DEBUG_MGMT_EVENT_STACK=y
|
||||
CONFIG_NET_MGMT_EVENT_INFO=y
|
||||
CONFIG_NET_MGMT_EVENT_MONITOR=y
|
||||
CONFIG_NET_MGMT_EVENT_MONITOR_AUTO_START=y
|
||||
|
||||
# IPv4
|
||||
CONFIG_NET_IPV4=y
|
||||
|
|
Loading…
Reference in a new issue