Skip to content

Commit a108177

Browse files
committed
Merge branch 'netcons-add-udp-send-fail-statistics-to-netconsole'
Maksym Kutsevol says: ==================== netcons: Add udp send fail statistics to netconsole Enhance observability of netconsole. Packet sends can fail. Start tracking at least two failure possibilities: ENOMEM and NET_XMIT_DROP for every target. Stats are exposed via an additional attribute in CONFIGFS. The exposed statistics allows easier debugging of cases when netconsole messages were not seen by receivers, eliminating the guesswork if the sender thinks that messages in question were sent out. Stats are not reset on enable/disable/change remote ip/etc, they belong to the netcons target itself. ==================== Link: https://patch.msgid.link/20241202-netcons-add-udp-send-fail-statistics-to-netconsole-v5-0-70e82239f922@kutsevol.com Signed-off-by: Jakub Kicinski <[email protected]>
2 parents a9ab02e + 36de47b commit a108177

File tree

4 files changed

+64
-9
lines changed

4 files changed

+64
-9
lines changed

Documentation/networking/netconsole.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ To remove a target::
124124

125125
The interface exposes these parameters of a netconsole target to userspace:
126126

127-
============== ================================= ============
127+
=============== ================================= ============
128128
enabled Is this target currently enabled? (read-write)
129129
extended Extended mode enabled (read-write)
130130
release Prepend kernel release to message (read-write)
@@ -135,7 +135,8 @@ The interface exposes these parameters of a netconsole target to userspace:
135135
remote_ip Remote agent's IP address (read-write)
136136
local_mac Local interface's MAC address (read-only)
137137
remote_mac Remote agent's MAC address (read-write)
138-
============== ================================= ============
138+
transmit_errors Number of packet send errors (read-only)
139+
=============== ================================= ============
139140

140141
The "enabled" attribute is also used to control whether the parameters of
141142
a target can be updated or not -- you can modify the parameters of only

drivers/net/netconsole.c

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <linux/inet.h>
3737
#include <linux/configfs.h>
3838
#include <linux/etherdevice.h>
39+
#include <linux/u64_stats_sync.h>
3940
#include <linux/utsname.h>
4041
#include <linux/rtnetlink.h>
4142

@@ -90,13 +91,20 @@ static DEFINE_MUTEX(target_cleanup_list_lock);
9091
*/
9192
static struct console netconsole_ext;
9293

94+
struct netconsole_target_stats {
95+
u64_stats_t xmit_drop_count;
96+
u64_stats_t enomem_count;
97+
struct u64_stats_sync syncp;
98+
};
99+
93100
/**
94101
* struct netconsole_target - Represents a configured netconsole target.
95102
* @list: Links this target into the target_list.
96103
* @group: Links us into the configfs subsystem hierarchy.
97104
* @userdata_group: Links to the userdata configfs hierarchy
98105
* @userdata_complete: Cached, formatted string of append
99106
* @userdata_length: String length of userdata_complete
107+
* @stats: Packet send stats for the target. Used for debugging.
100108
* @enabled: On / off knob to enable / disable target.
101109
* Visible from userspace (read-write).
102110
* We maintain a strict 1:1 correspondence between this and
@@ -124,6 +132,7 @@ struct netconsole_target {
124132
char userdata_complete[MAX_USERDATA_ENTRY_LENGTH * MAX_USERDATA_ITEMS];
125133
size_t userdata_length;
126134
#endif
135+
struct netconsole_target_stats stats;
127136
bool enabled;
128137
bool extended;
129138
bool release;
@@ -262,6 +271,7 @@ static void netconsole_process_cleanups_core(void)
262271
* | remote_ip
263272
* | local_mac
264273
* | remote_mac
274+
* | transmit_errors
265275
* | userdata/
266276
* | <key>/
267277
* | value
@@ -371,6 +381,21 @@ static ssize_t remote_mac_show(struct config_item *item, char *buf)
371381
return sysfs_emit(buf, "%pM\n", to_target(item)->np.remote_mac);
372382
}
373383

384+
static ssize_t transmit_errors_show(struct config_item *item, char *buf)
385+
{
386+
struct netconsole_target *nt = to_target(item);
387+
u64 xmit_drop_count, enomem_count;
388+
unsigned int start;
389+
390+
do {
391+
start = u64_stats_fetch_begin(&nt->stats.syncp);
392+
xmit_drop_count = u64_stats_read(&nt->stats.xmit_drop_count);
393+
enomem_count = u64_stats_read(&nt->stats.enomem_count);
394+
} while (u64_stats_fetch_retry(&nt->stats.syncp, start));
395+
396+
return sysfs_emit(buf, "%llu\n", xmit_drop_count + enomem_count);
397+
}
398+
374399
/*
375400
* This one is special -- targets created through the configfs interface
376401
* are not enabled (and the corresponding netpoll activated) by default.
@@ -842,6 +867,7 @@ CONFIGFS_ATTR(, remote_ip);
842867
CONFIGFS_ATTR_RO(, local_mac);
843868
CONFIGFS_ATTR(, remote_mac);
844869
CONFIGFS_ATTR(, release);
870+
CONFIGFS_ATTR_RO(, transmit_errors);
845871

846872
static struct configfs_attribute *netconsole_target_attrs[] = {
847873
&attr_enabled,
@@ -854,6 +880,7 @@ static struct configfs_attribute *netconsole_target_attrs[] = {
854880
&attr_remote_ip,
855881
&attr_local_mac,
856882
&attr_remote_mac,
883+
&attr_transmit_errors,
857884
NULL,
858885
};
859886

@@ -1058,6 +1085,33 @@ static struct notifier_block netconsole_netdev_notifier = {
10581085
.notifier_call = netconsole_netdev_event,
10591086
};
10601087

1088+
/**
1089+
* send_udp - Wrapper for netpoll_send_udp that counts errors
1090+
* @nt: target to send message to
1091+
* @msg: message to send
1092+
* @len: length of message
1093+
*
1094+
* Calls netpoll_send_udp and classifies the return value. If an error
1095+
* occurred it increments statistics in nt->stats accordingly.
1096+
* Only calls netpoll_send_udp if CONFIG_NETCONSOLE_DYNAMIC is disabled.
1097+
*/
1098+
static void send_udp(struct netconsole_target *nt, const char *msg, int len)
1099+
{
1100+
int result = netpoll_send_udp(&nt->np, msg, len);
1101+
1102+
if (IS_ENABLED(CONFIG_NETCONSOLE_DYNAMIC)) {
1103+
if (result == NET_XMIT_DROP) {
1104+
u64_stats_update_begin(&nt->stats.syncp);
1105+
u64_stats_inc(&nt->stats.xmit_drop_count);
1106+
u64_stats_update_end(&nt->stats.syncp);
1107+
} else if (result == -ENOMEM) {
1108+
u64_stats_update_begin(&nt->stats.syncp);
1109+
u64_stats_inc(&nt->stats.enomem_count);
1110+
u64_stats_update_end(&nt->stats.syncp);
1111+
}
1112+
}
1113+
}
1114+
10611115
static void send_msg_no_fragmentation(struct netconsole_target *nt,
10621116
const char *msg,
10631117
int msg_len,
@@ -1085,7 +1139,7 @@ static void send_msg_no_fragmentation(struct netconsole_target *nt,
10851139
MAX_PRINT_CHUNK - msg_len,
10861140
"%s", userdata);
10871141

1088-
netpoll_send_udp(&nt->np, buf, msg_len);
1142+
send_udp(nt, buf, msg_len);
10891143
}
10901144

10911145
static void append_release(char *buf)
@@ -1178,7 +1232,7 @@ static void send_fragmented_body(struct netconsole_target *nt, char *buf,
11781232
this_offset += this_chunk;
11791233
}
11801234

1181-
netpoll_send_udp(&nt->np, buf, this_header + this_offset);
1235+
send_udp(nt, buf, this_header + this_offset);
11821236
offset += this_offset;
11831237
}
11841238
}
@@ -1288,7 +1342,7 @@ static void write_msg(struct console *con, const char *msg, unsigned int len)
12881342
tmp = msg;
12891343
for (left = len; left;) {
12901344
frag = min(left, MAX_PRINT_CHUNK);
1291-
netpoll_send_udp(&nt->np, tmp, frag);
1345+
send_udp(nt, tmp, frag);
12921346
tmp += frag;
12931347
left -= frag;
12941348
}

include/linux/netpoll.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ static inline void netpoll_poll_disable(struct net_device *dev) { return; }
5757
static inline void netpoll_poll_enable(struct net_device *dev) { return; }
5858
#endif
5959

60-
void netpoll_send_udp(struct netpoll *np, const char *msg, int len);
60+
int netpoll_send_udp(struct netpoll *np, const char *msg, int len);
6161
void netpoll_print_options(struct netpoll *np);
6262
int netpoll_parse_options(struct netpoll *np, char *opt);
6363
int __netpoll_setup(struct netpoll *np, struct net_device *ndev);

net/core/netpoll.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ netdev_tx_t netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
390390
}
391391
EXPORT_SYMBOL(netpoll_send_skb);
392392

393-
void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
393+
int netpoll_send_udp(struct netpoll *np, const char *msg, int len)
394394
{
395395
int total_len, ip_len, udp_len;
396396
struct sk_buff *skb;
@@ -414,7 +414,7 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
414414
skb = find_skb(np, total_len + np->dev->needed_tailroom,
415415
total_len - len);
416416
if (!skb)
417-
return;
417+
return -ENOMEM;
418418

419419
skb_copy_to_linear_data(skb, msg, len);
420420
skb_put(skb, len);
@@ -490,7 +490,7 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
490490

491491
skb->dev = np->dev;
492492

493-
netpoll_send_skb(np, skb);
493+
return (int)netpoll_send_skb(np, skb);
494494
}
495495
EXPORT_SYMBOL(netpoll_send_udp);
496496

0 commit comments

Comments
 (0)