This commit change a method of printing multicast routes by showing all interfaces per entry instead of aggregating them by interface. Signed-off-by: Konrad Derda <konrad.derda@nordicsemi.no>
248 lines
6.2 KiB
C
248 lines
6.2 KiB
C
/*
|
|
* Copyright (c) 2016 Intel Corporation
|
|
* Copyright (c) 2023 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_DECLARE(net_shell);
|
|
|
|
#include "net_shell_private.h"
|
|
|
|
#include "../ip/route.h"
|
|
|
|
#if defined(CONFIG_NET_ROUTE) && defined(CONFIG_NET_NATIVE)
|
|
static void route_cb(struct net_route_entry *entry, void *user_data)
|
|
{
|
|
struct net_shell_user_data *data = user_data;
|
|
const struct shell *sh = data->sh;
|
|
struct net_if *iface = data->user_data;
|
|
struct net_route_nexthop *nexthop_route;
|
|
int count;
|
|
uint32_t now = k_uptime_get_32();
|
|
|
|
if (entry->iface != iface) {
|
|
return;
|
|
}
|
|
|
|
PR("IPv6 prefix : %s/%d\n", net_sprint_ipv6_addr(&entry->addr),
|
|
entry->prefix_len);
|
|
|
|
count = 0;
|
|
|
|
SYS_SLIST_FOR_EACH_CONTAINER(&entry->nexthop, nexthop_route, node) {
|
|
struct net_linkaddr_storage *lladdr;
|
|
char remaining_str[sizeof("01234567890 sec")];
|
|
uint32_t remaining;
|
|
|
|
if (!nexthop_route->nbr) {
|
|
continue;
|
|
}
|
|
|
|
PR("\tneighbor : %p\t", nexthop_route->nbr);
|
|
|
|
if (nexthop_route->nbr->idx == NET_NBR_LLADDR_UNKNOWN) {
|
|
PR("addr : <unknown>\t");
|
|
} else {
|
|
lladdr = net_nbr_get_lladdr(nexthop_route->nbr->idx);
|
|
|
|
PR("addr : %s\t", net_sprint_ll_addr(lladdr->addr,
|
|
lladdr->len));
|
|
}
|
|
|
|
if (entry->is_infinite) {
|
|
snprintk(remaining_str, sizeof(remaining_str) - 1,
|
|
"infinite");
|
|
} else {
|
|
remaining = net_timeout_remaining(&entry->lifetime, now);
|
|
snprintk(remaining_str, sizeof(remaining_str) - 1,
|
|
"%u sec", remaining);
|
|
}
|
|
|
|
PR("lifetime : %s\n", remaining_str);
|
|
|
|
count++;
|
|
}
|
|
|
|
if (count == 0) {
|
|
PR("\t<none>\n");
|
|
}
|
|
}
|
|
|
|
static void iface_per_route_cb(struct net_if *iface, void *user_data)
|
|
{
|
|
struct net_shell_user_data *data = user_data;
|
|
const struct shell *sh = data->sh;
|
|
const char *extra;
|
|
|
|
PR("\nIPv6 routes for interface %d (%p) (%s)\n",
|
|
net_if_get_by_iface(iface), iface,
|
|
iface2str(iface, &extra));
|
|
PR("=========================================%s\n", extra);
|
|
|
|
data->user_data = iface;
|
|
|
|
net_route_foreach(route_cb, data);
|
|
}
|
|
#endif /* CONFIG_NET_ROUTE */
|
|
|
|
#if defined(CONFIG_NET_ROUTE_MCAST) && defined(CONFIG_NET_NATIVE)
|
|
static void route_mcast_cb(struct net_route_entry_mcast *entry,
|
|
void *user_data)
|
|
{
|
|
struct net_shell_user_data *data = user_data;
|
|
const struct shell *sh = data->sh;
|
|
|
|
PR("IPv6 multicast route (%p)\n", entry);
|
|
PR("=================================\n");
|
|
|
|
PR("IPv6 group : %s\n", net_sprint_ipv6_addr(&entry->group));
|
|
PR("IPv6 group len : %d\n", entry->prefix_len);
|
|
PR("Lifetime : %u\n", entry->lifetime);
|
|
|
|
for (int i = 0; i < CONFIG_NET_MCAST_ROUTE_MAX_IFACES; ++i) {
|
|
if (entry->ifaces[i]) {
|
|
PR("Interface : %d (%p) %s\n", net_if_get_by_iface(entry->ifaces[i]),
|
|
entry->ifaces[i], iface2str(entry->ifaces[i], NULL));
|
|
}
|
|
}
|
|
}
|
|
#endif /* CONFIG_NET_ROUTE_MCAST */
|
|
|
|
static int cmd_net_ip6_route_add(const struct shell *sh, size_t argc, char *argv[])
|
|
{
|
|
#if defined(CONFIG_NET_NATIVE_IPV6) && (CONFIG_NET_ROUTE)
|
|
struct net_if *iface = NULL;
|
|
int idx;
|
|
struct net_route_entry *route;
|
|
struct in6_addr gw = {0};
|
|
struct in6_addr prefix = {0};
|
|
|
|
if (argc != 4) {
|
|
PR_ERROR("Correct usage: net route add <index> "
|
|
"<destination> <gateway>\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
idx = get_iface_idx(sh, argv[1]);
|
|
if (idx < 0) {
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
iface = net_if_get_by_index(idx);
|
|
if (!iface) {
|
|
PR_WARNING("No such interface in index %d\n", idx);
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
if (net_addr_pton(AF_INET6, argv[2], &prefix)) {
|
|
PR_ERROR("Invalid address: %s\n", argv[2]);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (net_addr_pton(AF_INET6, argv[3], &gw)) {
|
|
PR_ERROR("Invalid gateway: %s\n", argv[3]);
|
|
return -EINVAL;
|
|
}
|
|
|
|
route = net_route_add(iface, &prefix, NET_IPV6_DEFAULT_PREFIX_LEN,
|
|
&gw, NET_IPV6_ND_INFINITE_LIFETIME,
|
|
NET_ROUTE_PREFERENCE_MEDIUM);
|
|
if (route == NULL) {
|
|
PR_ERROR("Failed to add route\n");
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
#else /* CONFIG_NET_NATIVE_IPV6 && CONFIG_NET_ROUTE */
|
|
PR_INFO("Set %s and %s to enable native %s support."
|
|
" And enable CONFIG_NET_ROUTE.\n",
|
|
"CONFIG_NET_NATIVE", "CONFIG_NET_IPV6", "IPv6");
|
|
#endif /* CONFIG_NET_NATIVE_IPV6 && CONFIG_NET_ROUTE */
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_net_ip6_route_del(const struct shell *sh, size_t argc, char *argv[])
|
|
{
|
|
#if defined(CONFIG_NET_NATIVE_IPV6) && (CONFIG_NET_ROUTE)
|
|
struct net_if *iface = NULL;
|
|
int idx;
|
|
struct net_route_entry *route;
|
|
struct in6_addr prefix = { 0 };
|
|
|
|
if (argc != 3) {
|
|
PR_ERROR("Correct usage: net route del <index> <destination>\n");
|
|
return -EINVAL;
|
|
}
|
|
idx = get_iface_idx(sh, argv[1]);
|
|
if (idx < 0) {
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
iface = net_if_get_by_index(idx);
|
|
if (!iface) {
|
|
PR_WARNING("No such interface in index %d\n", idx);
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
if (net_addr_pton(AF_INET6, argv[2], &prefix)) {
|
|
PR_ERROR("Invalid address: %s\n", argv[2]);
|
|
return -EINVAL;
|
|
}
|
|
|
|
route = net_route_lookup(iface, &prefix);
|
|
if (route) {
|
|
net_route_del(route);
|
|
}
|
|
#else /* CONFIG_NET_NATIVE_IPV6 && CONFIG_NET_ROUTE */
|
|
PR_INFO("Set %s and %s to enable native %s support."
|
|
" And enable CONFIG_NET_ROUTE\n",
|
|
"CONFIG_NET_NATIVE", "CONFIG_NET_IPV6", "IPv6");
|
|
#endif /* CONFIG_NET_NATIVE_IPV6 && CONFIG_NET_ROUTE */
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_net_route(const struct shell *sh, size_t argc, char *argv[])
|
|
{
|
|
ARG_UNUSED(argc);
|
|
ARG_UNUSED(argv);
|
|
|
|
#if defined(CONFIG_NET_NATIVE)
|
|
#if defined(CONFIG_NET_ROUTE) || defined(CONFIG_NET_ROUTE_MCAST)
|
|
struct net_shell_user_data user_data;
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_ROUTE) || defined(CONFIG_NET_ROUTE_MCAST)
|
|
user_data.sh = sh;
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_ROUTE)
|
|
net_if_foreach(iface_per_route_cb, &user_data);
|
|
#else
|
|
PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_ROUTE",
|
|
"network route");
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_ROUTE_MCAST)
|
|
net_route_mcast_foreach(route_mcast_cb, NULL, &user_data);
|
|
#endif
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_route,
|
|
SHELL_CMD(add, NULL,
|
|
"'net route add <index> <destination> <gateway>'"
|
|
" adds the route to the destination.",
|
|
cmd_net_ip6_route_add),
|
|
SHELL_CMD(del, NULL,
|
|
"'net route del <index> <destination>'"
|
|
" deletes the route to the destination.",
|
|
cmd_net_ip6_route_del),
|
|
SHELL_SUBCMD_SET_END
|
|
);
|
|
|
|
SHELL_SUBCMD_ADD((net), route, &net_cmd_route,
|
|
"Show network route.",
|
|
cmd_net_route, 1, 0);
|