Skip to content

Commit d7074aa

Browse files
ps-ushankargregkh
authored andcommitted
netconsole: allow selection of egress interface via MAC address
[ Upstream commit f8a10be ] Currently, netconsole has two methods of configuration - module parameter and configfs. The former interface allows for netconsole activation earlier during boot (by specifying the module parameter on the kernel command line), so it is preferred for debugging issues which arise before userspace is up/the configfs interface can be used. The module parameter syntax requires specifying the egress interface name. This requirement makes it hard to use for a couple reasons: - The egress interface name can be hard or impossible to predict. For example, installing a new network card in a system can change the interface names assigned by the kernel. - When constructing the module parameter, one may have trouble determining the original (kernel-assigned) name of the interface (which is the name that should be given to netconsole) if some stable interface naming scheme is in effect. A human can usually look at kernel logs to determine the original name, but this is very painful if automation is constructing the parameter. For these reasons, allow selection of the egress interface via MAC address when configuring netconsole using the module parameter. Update the netconsole documentation with an example of the new syntax. Selection of egress interface by MAC address via configfs is far less interesting (since when this interface can be used, one should be able to easily convert between MAC address and interface name), so it is left unimplemented. Signed-off-by: Uday Shankar <ushankar@purestorage.com> Reviewed-by: Breno Leitao <leitao@debian.org> Tested-by: Breno Leitao <leitao@debian.org> Reviewed-by: Simon Horman <horms@kernel.org> Link: https://patch.msgid.link/20250312-netconsole-v6-2-3437933e79b8@purestorage.com Signed-off-by: Paolo Abeni <pabeni@redhat.com> Stable-dep-of: 3bc179b ("netpoll: fix IPv6 local-address corruption") Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent a5bc748 commit d7074aa

3 files changed

Lines changed: 50 additions & 13 deletions

File tree

Documentation/networking/netconsole.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ following format::
4545
r if present, prepend kernel version (release) to the message
4646
src-port source for UDP packets (defaults to 6665)
4747
src-ip source IP to use (interface address)
48-
dev network interface (eth0)
48+
dev network interface name (eth0) or MAC address
4949
tgt-port port for logging agent (6666)
5050
tgt-ip IP address for logging agent
5151
tgt-macaddr ethernet MAC address for logging agent (broadcast)
@@ -62,6 +62,10 @@ or using IPv6::
6262

6363
insmod netconsole netconsole=@/,@fd00:1:2:3::1/
6464

65+
or using a MAC address to select the egress interface::
66+
67+
linux netconsole=4444@10.0.0.1/22:33:44:55:66:77,9353@10.0.0.2/12:34:56:78:9a:bc
68+
6569
It also supports logging to multiple remote agents by specifying
6670
parameters for the multiple agents separated by semicolons and the
6771
complete string enclosed in "quotes", thusly::

include/linux/netpoll.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,13 @@ union inet_addr {
2525
struct netpoll {
2626
struct net_device *dev;
2727
netdevice_tracker dev_tracker;
28+
/*
29+
* Either dev_name or dev_mac can be used to specify the local
30+
* interface - dev_name is used if it is a nonempty string, else
31+
* dev_mac is used.
32+
*/
2833
char dev_name[IFNAMSIZ];
34+
u8 dev_mac[ETH_ALEN];
2935
const char *name;
3036

3137
union inet_addr local_ip, remote_ip;

net/core/netpoll.c

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,8 @@ void netpoll_print_options(struct netpoll *np)
506506
np_info(np, "local IPv6 address %pI6c\n", &np->local_ip.in6);
507507
else
508508
np_info(np, "local IPv4 address %pI4\n", &np->local_ip.ip);
509-
np_info(np, "interface '%s'\n", np->dev_name);
509+
np_info(np, "interface name '%s'\n", np->dev_name);
510+
np_info(np, "local ethernet address '%pM'\n", np->dev_mac);
510511
np_info(np, "remote port %d\n", np->remote_port);
511512
if (np->ipv6)
512513
np_info(np, "remote IPv6 address %pI6c\n", &np->remote_ip.in6);
@@ -575,11 +576,18 @@ int netpoll_parse_options(struct netpoll *np, char *opt)
575576
cur++;
576577

577578
if (*cur != ',') {
578-
/* parse out dev name */
579+
/* parse out dev_name or dev_mac */
579580
if ((delim = strchr(cur, ',')) == NULL)
580581
goto parse_failed;
581582
*delim = 0;
582-
strscpy(np->dev_name, cur, sizeof(np->dev_name));
583+
584+
np->dev_name[0] = '\0';
585+
eth_broadcast_addr(np->dev_mac);
586+
if (!strchr(cur, ':'))
587+
strscpy(np->dev_name, cur, sizeof(np->dev_name));
588+
else if (!mac_pton(cur, np->dev_mac))
589+
goto parse_failed;
590+
583591
cur = delim;
584592
}
585593
cur++;
@@ -684,35 +692,54 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
684692
}
685693
EXPORT_SYMBOL_GPL(__netpoll_setup);
686694

695+
/*
696+
* Returns a pointer to a string representation of the identifier used
697+
* to select the egress interface for the given netpoll instance. buf
698+
* must be a buffer of length at least MAC_ADDR_STR_LEN + 1.
699+
*/
700+
static char *egress_dev(struct netpoll *np, char *buf)
701+
{
702+
if (np->dev_name[0])
703+
return np->dev_name;
704+
705+
snprintf(buf, MAC_ADDR_STR_LEN, "%pM", np->dev_mac);
706+
return buf;
707+
}
708+
687709
int netpoll_setup(struct netpoll *np)
688710
{
711+
struct net *net = current->nsproxy->net_ns;
712+
char buf[MAC_ADDR_STR_LEN + 1];
689713
struct net_device *ndev = NULL;
690714
bool ip_overwritten = false;
691715
struct in_device *in_dev;
692716
int err;
693717

694718
rtnl_lock();
695-
if (np->dev_name[0]) {
696-
struct net *net = current->nsproxy->net_ns;
719+
if (np->dev_name[0])
697720
ndev = __dev_get_by_name(net, np->dev_name);
698-
}
721+
else if (is_valid_ether_addr(np->dev_mac))
722+
ndev = dev_getbyhwaddr(net, ARPHRD_ETHER, np->dev_mac);
723+
699724
if (!ndev) {
700-
np_err(np, "%s doesn't exist, aborting\n", np->dev_name);
725+
np_err(np, "%s doesn't exist, aborting\n", egress_dev(np, buf));
701726
err = -ENODEV;
702727
goto unlock;
703728
}
704729
netdev_hold(ndev, &np->dev_tracker, GFP_KERNEL);
705730

706731
if (netdev_master_upper_dev_get(ndev)) {
707-
np_err(np, "%s is a slave device, aborting\n", np->dev_name);
732+
np_err(np, "%s is a slave device, aborting\n",
733+
egress_dev(np, buf));
708734
err = -EBUSY;
709735
goto put;
710736
}
711737

712738
if (!netif_running(ndev)) {
713739
unsigned long atmost;
714740

715-
np_info(np, "device %s not up yet, forcing it\n", np->dev_name);
741+
np_info(np, "device %s not up yet, forcing it\n",
742+
egress_dev(np, buf));
716743

717744
err = dev_open(ndev, NULL);
718745

@@ -746,7 +773,7 @@ int netpoll_setup(struct netpoll *np)
746773
if (!ifa) {
747774
put_noaddr:
748775
np_err(np, "no IP address for %s, aborting\n",
749-
np->dev_name);
776+
egress_dev(np, buf));
750777
err = -EDESTADDRREQ;
751778
goto put;
752779
}
@@ -777,13 +804,13 @@ int netpoll_setup(struct netpoll *np)
777804
}
778805
if (err) {
779806
np_err(np, "no IPv6 address for %s, aborting\n",
780-
np->dev_name);
807+
egress_dev(np, buf));
781808
goto put;
782809
} else
783810
np_info(np, "local IPv6 %pI6c\n", &np->local_ip.in6);
784811
#else
785812
np_err(np, "IPv6 is not supported %s, aborting\n",
786-
np->dev_name);
813+
egress_dev(np, buf));
787814
err = -EINVAL;
788815
goto put;
789816
#endif

0 commit comments

Comments
 (0)