summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2025-06-18 10:46:31 +0100
committerDavid S. Miller <davem@davemloft.net>2025-06-18 10:46:31 +0100
commitfc4842cd0f117042a648cf565da4db0c04a604be (patch)
treecde3af2d90beb3e866c5c4fbc301c91d284eb1dc
parentec315832f6f98f0fa5719b8b5dd2214ca44ef3f1 (diff)
parent8c587aa3fa5400467063f88a3a48f8e9480b2e33 (diff)
Merge branch 'netconsole-msgid' into main
Gustavo Luiz Duarte says: ==================== netconsole: Add support for msgid in sysdata This patch series introduces a new feature to netconsole which allows appending a message ID to the userdata dictionary. If the msgid feature is enabled, the message ID is built from a per-target 32 bit counter that is incremented and appended to every message sent to the target. Example:: echo 1 > "/sys/kernel/config/netconsole/cmdline0/userdata/msgid_enabled" echo "This is message #1" > /dev/kmsg echo "This is message #2" > /dev/kmsg 13,434,54928466,-;This is message #1 msgid=1 13,435,54934019,-;This is message #2 msgid=2 This feature can be used by the target to detect if messages were dropped or reordered before reaching the target. This allows system administrators to assess the reliability of their netconsole pipeline and detect loss of messages due to network contention or temporary unavailability. --- Changes in v3: - Add kdoc documentation for msgcounter. - Link to v2: https://lore.kernel.org/r/20250612-netconsole-msgid-v2-0-d4c1abc84bac@gmail.com Changes in v2: - Use wrapping_assign_add() to avoid warnings in UBSAN and friends. - Improve documentation to clarify wrapping and distinguish msgid from sequnum. - Rebase and fix conflict in prepare_extradata(). - Link to v1: https://lore.kernel.org/r/20250611-netconsole-msgid-v1-0-1784a51feb1e@gmail.com ==================== Suggested-by: Breno Leitao <leitao@debian.org> Signed-off-by: Gustavo Luiz Duarte <gustavold@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/networking/netconsole.rst32
-rw-r--r--drivers/net/netconsole.c66
-rwxr-xr-xtools/testing/selftests/drivers/net/netcons_sysdata.sh30
3 files changed, 128 insertions, 0 deletions
diff --git a/Documentation/networking/netconsole.rst b/Documentation/networking/netconsole.rst
index a0076b542e9c..59cb9982afe6 100644
--- a/Documentation/networking/netconsole.rst
+++ b/Documentation/networking/netconsole.rst
@@ -340,6 +340,38 @@ In this example, the message was sent by CPU 42.
cpu=42 # kernel-populated value
+Message ID auto population in userdata
+--------------------------------------
+
+Within the netconsole configfs hierarchy, there is a file named `msgid_enabled`
+located in the `userdata` directory. This file controls the message ID
+auto-population feature, which assigns a numeric id to each message sent to a
+given target and appends the ID to userdata dictionary in every message sent.
+
+The message ID is generated using a per-target 32 bit counter that is
+incremented for every message sent to the target. Note that this counter will
+eventually wrap around after reaching uint32_t max value, so the message ID is
+not globally unique over time. However, it can still be used by the target to
+detect if messages were dropped before reaching the target by identifying gaps
+in the sequence of IDs.
+
+It is important to distinguish message IDs from the message <sequnum> field.
+Some kernel messages may never reach netconsole (for example, due to printk
+rate limiting). Thus, a gap in <sequnum> cannot be solely relied upon to
+indicate that a message was dropped during transmission, as it may never have
+been sent via netconsole. The message ID, on the other hand, is only assigned
+to messages that are actually transmitted via netconsole.
+
+Example::
+
+ echo "This is message #1" > /dev/kmsg
+ echo "This is message #2" > /dev/kmsg
+ 13,434,54928466,-;This is message #1
+ msgid=1
+ 13,435,54934019,-;This is message #2
+ msgid=2
+
+
Extended console:
=================
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 89afe127b46c..e3722de08ea9 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -113,6 +113,8 @@ enum sysdata_feature {
SYSDATA_TASKNAME = BIT(1),
/* Kernel release/version as part of sysdata */
SYSDATA_RELEASE = BIT(2),
+ /* Include a per-target message ID as part of sysdata */
+ SYSDATA_MSGID = BIT(3),
};
/**
@@ -123,6 +125,7 @@ enum sysdata_feature {
* @extradata_complete: Cached, formatted string of append
* @userdata_length: String length of usedata in extradata_complete.
* @sysdata_fields: Sysdata features enabled.
+ * @msgcounter: Message sent counter.
* @stats: Packet send stats for the target. Used for debugging.
* @enabled: On / off knob to enable / disable target.
* Visible from userspace (read-write).
@@ -153,6 +156,8 @@ struct netconsole_target {
size_t userdata_length;
/* bit-wise with sysdata_feature bits */
u32 sysdata_fields;
+ /* protected by target_list_lock */
+ u32 msgcounter;
#endif
struct netconsole_target_stats stats;
bool enabled;
@@ -504,6 +509,19 @@ static void unregister_netcons_consoles(void)
unregister_console(&netconsole);
}
+static ssize_t sysdata_msgid_enabled_show(struct config_item *item,
+ char *buf)
+{
+ struct netconsole_target *nt = to_target(item->ci_parent);
+ bool msgid_enabled;
+
+ mutex_lock(&dynamic_netconsole_mutex);
+ msgid_enabled = !!(nt->sysdata_fields & SYSDATA_MSGID);
+ mutex_unlock(&dynamic_netconsole_mutex);
+
+ return sysfs_emit(buf, "%d\n", msgid_enabled);
+}
+
/*
* This one is special -- targets created through the configfs interface
* are not enabled (and the corresponding netpoll activated) by default.
@@ -799,6 +817,8 @@ static size_t count_extradata_entries(struct netconsole_target *nt)
entries += 1;
if (nt->sysdata_fields & SYSDATA_RELEASE)
entries += 1;
+ if (nt->sysdata_fields & SYSDATA_MSGID)
+ entries += 1;
return entries;
}
@@ -935,6 +955,40 @@ static void disable_sysdata_feature(struct netconsole_target *nt,
nt->extradata_complete[nt->userdata_length] = 0;
}
+static ssize_t sysdata_msgid_enabled_store(struct config_item *item,
+ const char *buf, size_t count)
+{
+ struct netconsole_target *nt = to_target(item->ci_parent);
+ bool msgid_enabled, curr;
+ ssize_t ret;
+
+ ret = kstrtobool(buf, &msgid_enabled);
+ if (ret)
+ return ret;
+
+ mutex_lock(&dynamic_netconsole_mutex);
+ curr = !!(nt->sysdata_fields & SYSDATA_MSGID);
+ if (msgid_enabled == curr)
+ goto unlock_ok;
+
+ if (msgid_enabled &&
+ count_extradata_entries(nt) >= MAX_EXTRADATA_ITEMS) {
+ ret = -ENOSPC;
+ goto unlock;
+ }
+
+ if (msgid_enabled)
+ nt->sysdata_fields |= SYSDATA_MSGID;
+ else
+ disable_sysdata_feature(nt, SYSDATA_MSGID);
+
+unlock_ok:
+ ret = strnlen(buf, count);
+unlock:
+ mutex_unlock(&dynamic_netconsole_mutex);
+ return ret;
+}
+
static ssize_t sysdata_release_enabled_store(struct config_item *item,
const char *buf, size_t count)
{
@@ -1050,6 +1104,7 @@ CONFIGFS_ATTR(userdatum_, value);
CONFIGFS_ATTR(sysdata_, cpu_nr_enabled);
CONFIGFS_ATTR(sysdata_, taskname_enabled);
CONFIGFS_ATTR(sysdata_, release_enabled);
+CONFIGFS_ATTR(sysdata_, msgid_enabled);
static struct configfs_attribute *userdatum_attrs[] = {
&userdatum_attr_value,
@@ -1112,6 +1167,7 @@ static struct configfs_attribute *userdata_attrs[] = {
&sysdata_attr_cpu_nr_enabled,
&sysdata_attr_taskname_enabled,
&sysdata_attr_release_enabled,
+ &sysdata_attr_msgid_enabled,
NULL,
};
@@ -1309,6 +1365,14 @@ static int sysdata_append_release(struct netconsole_target *nt, int offset)
init_utsname()->release);
}
+static int sysdata_append_msgid(struct netconsole_target *nt, int offset)
+{
+ wrapping_assign_add(nt->msgcounter, 1);
+ return scnprintf(&nt->extradata_complete[offset],
+ MAX_EXTRADATA_ENTRY_LEN, " msgid=%u\n",
+ nt->msgcounter);
+}
+
/*
* prepare_extradata - append sysdata at extradata_complete in runtime
* @nt: target to send message to
@@ -1331,6 +1395,8 @@ static int prepare_extradata(struct netconsole_target *nt)
extradata_len += sysdata_append_taskname(nt, extradata_len);
if (nt->sysdata_fields & SYSDATA_RELEASE)
extradata_len += sysdata_append_release(nt, extradata_len);
+ if (nt->sysdata_fields & SYSDATA_MSGID)
+ extradata_len += sysdata_append_msgid(nt, extradata_len);
WARN_ON_ONCE(extradata_len >
MAX_EXTRADATA_ENTRY_LEN * MAX_EXTRADATA_ITEMS);
diff --git a/tools/testing/selftests/drivers/net/netcons_sysdata.sh b/tools/testing/selftests/drivers/net/netcons_sysdata.sh
index a737e377bf08..baf69031089e 100755
--- a/tools/testing/selftests/drivers/net/netcons_sysdata.sh
+++ b/tools/testing/selftests/drivers/net/netcons_sysdata.sh
@@ -53,6 +53,17 @@ function set_release() {
echo 1 > "${NETCONS_PATH}/userdata/release_enabled"
}
+# Enable the msgid to be appended to sysdata
+function set_msgid() {
+ if [[ ! -f "${NETCONS_PATH}/userdata/msgid_enabled" ]]
+ then
+ echo "Not able to enable msgid sysdata append. Configfs not available in ${NETCONS_PATH}/userdata/msgid_enabled" >&2
+ exit "${ksft_skip}"
+ fi
+
+ echo 1 > "${NETCONS_PATH}/userdata/msgid_enabled"
+}
+
# Disable the sysdata cpu_nr feature
function unset_cpu_nr() {
echo 0 > "${NETCONS_PATH}/userdata/cpu_nr_enabled"
@@ -67,6 +78,10 @@ function unset_release() {
echo 0 > "${NETCONS_PATH}/userdata/release_enabled"
}
+function unset_msgid() {
+ echo 0 > "${NETCONS_PATH}/userdata/msgid_enabled"
+}
+
# Test if MSG contains sysdata
function validate_sysdata() {
# OUTPUT_FILE will contain something like:
@@ -74,6 +89,7 @@ function validate_sysdata() {
# userdatakey=userdatavalue
# cpu=X
# taskname=<taskname>
+ # msgid=<id>
# Echo is what this test uses to create the message. See runtest()
# function
@@ -104,6 +120,12 @@ function validate_sysdata() {
exit "${ksft_fail}"
fi
+ if ! grep -q "msgid=[0-9]\+$" "${OUTPUT_FILE}"; then
+ echo "FAIL: 'msgid=<id>' not found in ${OUTPUT_FILE}" >&2
+ cat "${OUTPUT_FILE}" >&2
+ exit "${ksft_fail}"
+ fi
+
rm "${OUTPUT_FILE}"
pkill_socat
}
@@ -155,6 +177,12 @@ function validate_no_sysdata() {
exit "${ksft_fail}"
fi
+ if grep -q "msgid=" "${OUTPUT_FILE}"; then
+ echo "FAIL: 'msgid= found in ${OUTPUT_FILE}" >&2
+ cat "${OUTPUT_FILE}" >&2
+ exit "${ksft_fail}"
+ fi
+
rm "${OUTPUT_FILE}"
}
@@ -206,6 +234,7 @@ set_cpu_nr
# Enable taskname to be appended to sysdata
set_taskname
set_release
+set_msgid
runtest
# Make sure the message was received in the dst part
# and exit
@@ -235,6 +264,7 @@ MSG="Test #3 from CPU${CPU}"
unset_cpu_nr
unset_taskname
unset_release
+unset_msgid
runtest
# At this time, cpu= shouldn't be present in the msg
validate_no_sysdata