Commit 1efddc06 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'net-netconsole-configfs-entries-for-boot-target'

Breno Leitao says:

====================
net: netconsole: configfs entries for boot target

There is a limitation in netconsole, where it is impossible to
disable or modify the target created from the command line parameter.
(netconsole=...).

"netconsole" cmdline parameter sets the remote IP, and if the remote IP
changes, the machine needs to be rebooted (with the new remote IP set in
the command line parameter).

This allows the user to modify a target without the need to restart the
machine.

This functionality sits on top of the dynamic target reconfiguration that is
already implemented in netconsole.

The way to modify a boot time target is creating special named configfs
directories, that will be associated with the targets coming from
`netconsole=...`.

Example:

Let's suppose you have two netconsole targets defined at boot time::

 netconsole=4444@10.0.0.1/eth1,9353@10.0.0.2/12:34:56:78:9a:bc;4444@10.0.0.1/eth1,9353@10.0.0.3/12:34:56:78:9a:bc

You can modify these targets in runtime by creating the following targets::

 $ mkdir cmdline1
 $ cat cmdline1/remote_ip
 10.0.0.3
 $ echo 0 > cmdline1/enabled
 $ echo 10.0.0.4 > cmdline1/remote_ip
 $ echo 1 > cmdline1/enabled
====================

Link: https://lore.kernel.org/r/20231012111401.333798-1-leitao@debian.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 220dd227 7eeb84d8
...@@ -99,9 +99,6 @@ Dynamic reconfiguration: ...@@ -99,9 +99,6 @@ Dynamic reconfiguration:
Dynamic reconfigurability is a useful addition to netconsole that enables Dynamic reconfigurability is a useful addition to netconsole that enables
remote logging targets to be dynamically added, removed, or have their remote logging targets to be dynamically added, removed, or have their
parameters reconfigured at runtime from a configfs-based userspace interface. parameters reconfigured at runtime from a configfs-based userspace interface.
[ Note that the parameters of netconsole targets that were specified/created
from the boot/module option are not exposed via this interface, and hence
cannot be modified dynamically. ]
To include this feature, select CONFIG_NETCONSOLE_DYNAMIC when building the To include this feature, select CONFIG_NETCONSOLE_DYNAMIC when building the
netconsole module (or kernel, if netconsole is built-in). netconsole module (or kernel, if netconsole is built-in).
...@@ -155,6 +152,25 @@ You can also update the local interface dynamically. This is especially ...@@ -155,6 +152,25 @@ You can also update the local interface dynamically. This is especially
useful if you want to use interfaces that have newly come up (and may not useful if you want to use interfaces that have newly come up (and may not
have existed when netconsole was loaded / initialized). have existed when netconsole was loaded / initialized).
Netconsole targets defined at boot time (or module load time) with the
`netconsole=` param are assigned the name `cmdline<index>`. For example, the
first target in the parameter is named `cmdline0`. You can control and modify
these targets by creating configfs directories with the matching name.
Let's suppose you have two netconsole targets defined at boot time::
netconsole=4444@10.0.0.1/eth1,9353@10.0.0.2/12:34:56:78:9a:bc;4444@10.0.0.1/eth1,9353@10.0.0.3/12:34:56:78:9a:bc
You can modify these targets in runtime by creating the following targets::
mkdir cmdline0
cat cmdline0/remote_ip
10.0.0.2
mkdir cmdline1
cat cmdline1/remote_ip
10.0.0.3
Extended console: Extended console:
================= =================
......
...@@ -53,6 +53,8 @@ static bool oops_only = false; ...@@ -53,6 +53,8 @@ static bool oops_only = false;
module_param(oops_only, bool, 0600); module_param(oops_only, bool, 0600);
MODULE_PARM_DESC(oops_only, "Only log oops messages"); MODULE_PARM_DESC(oops_only, "Only log oops messages");
#define NETCONSOLE_PARAM_TARGET_PREFIX "cmdline"
#ifndef MODULE #ifndef MODULE
static int __init option_setup(char *opt) static int __init option_setup(char *opt)
{ {
...@@ -165,6 +167,10 @@ static void netconsole_target_put(struct netconsole_target *nt) ...@@ -165,6 +167,10 @@ static void netconsole_target_put(struct netconsole_target *nt)
{ {
} }
static void populate_configfs_item(struct netconsole_target *nt,
int cmdline_count)
{
}
#endif /* CONFIG_NETCONSOLE_DYNAMIC */ #endif /* CONFIG_NETCONSOLE_DYNAMIC */
/* Allocate and initialize with defaults. /* Allocate and initialize with defaults.
...@@ -192,58 +198,6 @@ static struct netconsole_target *alloc_and_init(void) ...@@ -192,58 +198,6 @@ static struct netconsole_target *alloc_and_init(void)
return nt; return nt;
} }
/* Allocate new target (from boot/module param) and setup netpoll for it */
static struct netconsole_target *alloc_param_target(char *target_config)
{
struct netconsole_target *nt;
int err;
nt = alloc_and_init();
if (!nt) {
err = -ENOMEM;
goto fail;
}
if (*target_config == '+') {
nt->extended = true;
target_config++;
}
if (*target_config == 'r') {
if (!nt->extended) {
pr_err("Netconsole configuration error. Release feature requires extended log message");
err = -EINVAL;
goto fail;
}
nt->release = true;
target_config++;
}
/* Parse parameters and setup netpoll */
err = netpoll_parse_options(&nt->np, target_config);
if (err)
goto fail;
err = netpoll_setup(&nt->np);
if (err)
goto fail;
nt->enabled = true;
return nt;
fail:
kfree(nt);
return ERR_PTR(err);
}
/* Cleanup netpoll for given target (from boot/module param) and free it */
static void free_param_target(struct netconsole_target *nt)
{
netpoll_cleanup(&nt->np);
kfree(nt);
}
#ifdef CONFIG_NETCONSOLE_DYNAMIC #ifdef CONFIG_NETCONSOLE_DYNAMIC
/* /*
...@@ -675,6 +629,23 @@ static const struct config_item_type netconsole_target_type = { ...@@ -675,6 +629,23 @@ static const struct config_item_type netconsole_target_type = {
.ct_owner = THIS_MODULE, .ct_owner = THIS_MODULE,
}; };
static struct netconsole_target *find_cmdline_target(const char *name)
{
struct netconsole_target *nt, *ret = NULL;
unsigned long flags;
spin_lock_irqsave(&target_list_lock, flags);
list_for_each_entry(nt, &target_list, list) {
if (!strcmp(nt->item.ci_name, name)) {
ret = nt;
break;
}
}
spin_unlock_irqrestore(&target_list_lock, flags);
return ret;
}
/* /*
* Group operations and type for netconsole_subsys. * Group operations and type for netconsole_subsys.
*/ */
...@@ -685,6 +656,17 @@ static struct config_item *make_netconsole_target(struct config_group *group, ...@@ -685,6 +656,17 @@ static struct config_item *make_netconsole_target(struct config_group *group,
struct netconsole_target *nt; struct netconsole_target *nt;
unsigned long flags; unsigned long flags;
/* Checking if a target by this name was created at boot time. If so,
* attach a configfs entry to that target. This enables dynamic
* control.
*/
if (!strncmp(name, NETCONSOLE_PARAM_TARGET_PREFIX,
strlen(NETCONSOLE_PARAM_TARGET_PREFIX))) {
nt = find_cmdline_target(name);
if (nt)
return &nt->item;
}
nt = alloc_and_init(); nt = alloc_and_init();
if (!nt) if (!nt)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -740,6 +722,17 @@ static struct configfs_subsystem netconsole_subsys = { ...@@ -740,6 +722,17 @@ static struct configfs_subsystem netconsole_subsys = {
}, },
}; };
static void populate_configfs_item(struct netconsole_target *nt,
int cmdline_count)
{
char target_name[16];
snprintf(target_name, sizeof(target_name), "%s%d",
NETCONSOLE_PARAM_TARGET_PREFIX, cmdline_count);
config_item_init_type_name(&nt->item, target_name,
&netconsole_target_type);
}
#endif /* CONFIG_NETCONSOLE_DYNAMIC */ #endif /* CONFIG_NETCONSOLE_DYNAMIC */
/* Handle network interface device notifications */ /* Handle network interface device notifications */
...@@ -938,6 +931,60 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) ...@@ -938,6 +931,60 @@ static void write_msg(struct console *con, const char *msg, unsigned int len)
spin_unlock_irqrestore(&target_list_lock, flags); spin_unlock_irqrestore(&target_list_lock, flags);
} }
/* Allocate new target (from boot/module param) and setup netpoll for it */
static struct netconsole_target *alloc_param_target(char *target_config,
int cmdline_count)
{
struct netconsole_target *nt;
int err;
nt = alloc_and_init();
if (!nt) {
err = -ENOMEM;
goto fail;
}
if (*target_config == '+') {
nt->extended = true;
target_config++;
}
if (*target_config == 'r') {
if (!nt->extended) {
pr_err("Netconsole configuration error. Release feature requires extended log message");
err = -EINVAL;
goto fail;
}
nt->release = true;
target_config++;
}
/* Parse parameters and setup netpoll */
err = netpoll_parse_options(&nt->np, target_config);
if (err)
goto fail;
err = netpoll_setup(&nt->np);
if (err)
goto fail;
populate_configfs_item(nt, cmdline_count);
nt->enabled = true;
return nt;
fail:
kfree(nt);
return ERR_PTR(err);
}
/* Cleanup netpoll for given target (from boot/module param) and free it */
static void free_param_target(struct netconsole_target *nt)
{
netpoll_cleanup(&nt->np);
kfree(nt);
}
static struct console netconsole_ext = { static struct console netconsole_ext = {
.name = "netcon_ext", .name = "netcon_ext",
.flags = CON_ENABLED | CON_EXTENDED, .flags = CON_ENABLED | CON_EXTENDED,
...@@ -954,6 +1001,7 @@ static int __init init_netconsole(void) ...@@ -954,6 +1001,7 @@ static int __init init_netconsole(void)
{ {
int err; int err;
struct netconsole_target *nt, *tmp; struct netconsole_target *nt, *tmp;
unsigned int count = 0;
bool extended = false; bool extended = false;
unsigned long flags; unsigned long flags;
char *target_config; char *target_config;
...@@ -961,7 +1009,7 @@ static int __init init_netconsole(void) ...@@ -961,7 +1009,7 @@ static int __init init_netconsole(void)
if (strnlen(input, MAX_PARAM_LENGTH)) { if (strnlen(input, MAX_PARAM_LENGTH)) {
while ((target_config = strsep(&input, ";"))) { while ((target_config = strsep(&input, ";"))) {
nt = alloc_param_target(target_config); nt = alloc_param_target(target_config, count);
if (IS_ERR(nt)) { if (IS_ERR(nt)) {
err = PTR_ERR(nt); err = PTR_ERR(nt);
goto fail; goto fail;
...@@ -977,6 +1025,7 @@ static int __init init_netconsole(void) ...@@ -977,6 +1025,7 @@ static int __init init_netconsole(void)
spin_lock_irqsave(&target_list_lock, flags); spin_lock_irqsave(&target_list_lock, flags);
list_add(&nt->list, &target_list); list_add(&nt->list, &target_list);
spin_unlock_irqrestore(&target_list_lock, flags); spin_unlock_irqrestore(&target_list_lock, flags);
count++;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment