public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 iproute2-next] utils: add fflush_monitor() helper
@ 2026-04-27  8:19 Eric Dumazet
  2026-04-27 16:31 ` Stephen Hemminger
  0 siblings, 1 reply; 3+ messages in thread
From: Eric Dumazet @ 2026-04-27  8:19 UTC (permalink / raw)
  To: David Ahern, Stephen Hemminger
  Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, netdev,
	eric.dumazet, Eric Dumazet

Some fflush() calls only make sense for monitor programs.

For other cases, forcing a flush is expensive.

After this patch, ip, tc and ss are correctly buffering most of their
output when redirected to a file.

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 include/utils.h  |  7 +++++++
 ip/ipaddress.c   | 12 +++++++-----
 ip/iplink.c      |  4 ++--
 ip/ipmonitor.c   |  1 +
 ip/ipmptcp.c     | 10 +++++-----
 ip/ipneigh.c     |  4 ++--
 ip/ipnetconf.c   |  2 +-
 ip/ipnetns.c     |  2 +-
 ip/ipnexthop.c   | 12 ++++++------
 ip/iproute.c     |  4 ++--
 ip/iprule.c      |  2 +-
 ip/iptoken.c     |  2 +-
 ip/tcp_metrics.c |  2 +-
 lib/utils.c      |  1 +
 misc/ss.c        |  3 ++-
 tc/tc_class.c    |  2 +-
 tc/tc_filter.c   |  2 +-
 tc/tc_monitor.c  |  1 +
 tc/tc_qdisc.c    |  2 +-
 19 files changed, 44 insertions(+), 31 deletions(-)

diff --git a/include/utils.h b/include/utils.h
index b68d6bc4edcf9ca335148f731cd240871b6c809b..2ed3b75ebb45e0f0e4aedd9bdf21375f74c2bbef 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -38,6 +38,7 @@ extern int numeric;
 extern bool do_all;
 extern int echo_request;
 extern int use_iec;
+extern int monitor_mode;
 
 #define SPRINT_BSIZE 64
 #define SPRINT_BUF(x)	char x[SPRINT_BSIZE]
@@ -399,4 +400,10 @@ FILE *generic_proc_open(const char *env, const char *name);
 int open_fds_add(int fd);
 void open_fds_close(void);
 
+static inline void fflush_monitor(FILE *fp)
+{
+	if (monitor_mode)
+		fflush(fp);
+}
+
 #endif /* __UTILS_H__ */
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index 4d93a04a8555e141ae30a4aaeb42ac607a181c9b..14aa98e77452c9681c9d3660f6a882df56b44f1c 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -894,7 +894,7 @@ static int print_linkinfo_brief(FILE *fp, const char *name,
 		print_string(PRINT_FP, NULL, "%s", "\n");
 	}
 
-	fflush(fp);
+	fflush_monitor(fp);
 	return 0;
 }
 
@@ -1346,10 +1346,12 @@ int print_linkinfo(struct nlmsghdr *n, void *arg)
 	}
 
 	print_string(PRINT_FP, NULL, "%s", "\n");
-	fflush(fp);
+	fflush_monitor(fp);
 	/* prettier here if stderr and stdout go to the same place */
-	if (truncated_vfs)
+	if (truncated_vfs) {
+		fflush(fp);
 		fprintf(stderr, "Truncated VF list: %s\n", name);
+	}
 	return 1;
 }
 
@@ -1732,7 +1734,7 @@ int print_addrinfo(struct nlmsghdr *n, void *arg)
 	}
 	print_string(PRINT_FP, NULL, "%s", "\n");
 brief_exit:
-	fflush(fp);
+	fflush_monitor(fp);
 	return 0;
 }
 
@@ -1768,7 +1770,7 @@ static int print_selected_addrinfo(struct ifinfomsg *ifi,
 
 	if (brief) {
 		print_string(PRINT_FP, NULL, "%s", "\n");
-		fflush(fp);
+		fflush_monitor(fp);
 	}
 	return 0;
 }
diff --git a/ip/iplink.c b/ip/iplink.c
index fce6631d2d821a8739d28805e13d98f6804bda30..806f86987ed7c8af5ddd40f04a44fb8ce8debfaf 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -1296,7 +1296,7 @@ static void print_mpls_stats(FILE *fp, struct rtattr *attr)
 	print_nl();
 	print_mpls_link_stats(fp, stats, "        ");
 	print_string(PRINT_FP, NULL, "%s", "\n");
-	fflush(fp);
+	fflush_monitor(fp);
 }
 
 static void print_af_stats_attr(FILE *fp, int ifindex, struct rtattr *attr)
@@ -1359,7 +1359,7 @@ static int print_af_stats(struct nlmsghdr *n, void *arg)
 	if (tb[IFLA_STATS_AF_SPEC])
 		print_af_stats_attr(fp, ifsm->ifindex, tb[IFLA_STATS_AF_SPEC]);
 
-	fflush(fp);
+	fflush_monitor(fp);
 	return 0;
 }
 
diff --git a/ip/ipmonitor.c b/ip/ipmonitor.c
index 1f4e860f8d6726edffcf9bf81636c6555757dd09..23bd667a2f7a27e620d0f6dd13a16476c1ac0d08 100644
--- a/ip/ipmonitor.c
+++ b/ip/ipmonitor.c
@@ -324,6 +324,7 @@ int do_ipmonitor(int argc, char **argv)
 		return err;
 	}
 
+	monitor_mode = 1;
 	if (rtnl_open(&rth, groups) < 0)
 		exit(1);
 
diff --git a/ip/ipmptcp.c b/ip/ipmptcp.c
index 3df89db54b4e00f8fe2d18828621999512622d59..37df15ba9b5f2d6974f5fdd2360025ce9a017316 100644
--- a/ip/ipmptcp.c
+++ b/ip/ipmptcp.c
@@ -276,7 +276,7 @@ static int print_mptcp_addrinfo(struct rtattr *addrinfo)
 
 	print_nl();
 	close_json_object();
-	fflush(stdout);
+	fflush_monitor(stdout);
 
 	return 0;
 }
@@ -325,7 +325,7 @@ static int mptcp_addr_dump(void)
 	}
 
 	delete_json_obj();
-	fflush(stdout);
+	fflush_monitor(stdout);
 	return 0;
 }
 
@@ -349,7 +349,7 @@ static int mptcp_addr_show(int argc, char **argv)
 	ret = print_mptcp_addr(answer, stdout);
 	delete_json_obj();
 	free(answer);
-	fflush(stdout);
+	fflush_monitor(stdout);
 	return ret;
 }
 
@@ -430,7 +430,7 @@ static int print_mptcp_limit(struct nlmsghdr *n, void *arg)
 
 	print_nl();
 	close_json_object();
-	fflush(stdout);
+	fflush_monitor(stdout);
 
 	return 0;
 }
@@ -592,7 +592,7 @@ static int mptcp_monitor_msg(struct rtnl_ctrl_data *ctrl,
 out:
 	print_nl();
 	close_json_object();
-	fflush(stdout);
+	fflush_monitor(stdout);
 
 	return 0;
 }
diff --git a/ip/ipneigh.c b/ip/ipneigh.c
index e678545ad535ad83722d1daef51f08c569df8236..2b74fccdfd9c5e39d675b8d1419e23bf9f6b6e3d 100644
--- a/ip/ipneigh.c
+++ b/ip/ipneigh.c
@@ -298,7 +298,7 @@ static int print_neigh_brief(FILE *fp, struct ndmsg *r, struct rtattr *tb[])
 
 	print_string(PRINT_FP, NULL, "%s", "\n");
 	close_json_object();
-	fflush(fp);
+	fflush_monitor(fp);
 
 	return 0;
 }
@@ -472,7 +472,7 @@ int print_neigh(struct nlmsghdr *n, void *arg)
 
 	print_string(PRINT_FP, NULL, "\n", "");
 	close_json_object();
-	fflush(fp);
+	fflush_monitor(fp);
 
 	return 0;
 }
diff --git a/ip/ipnetconf.c b/ip/ipnetconf.c
index 020eff786d0b82f3033a71c2f4fc3d5b1af5f099..efb4da963d463481fa27f41fcb8e65db844381cf 100644
--- a/ip/ipnetconf.c
+++ b/ip/ipnetconf.c
@@ -140,7 +140,7 @@ int print_netconf(struct rtnl_ctrl_data *ctrl, struct nlmsghdr *n, void *arg)
 
 	close_json_object();
 	print_string(PRINT_FP, NULL, "\n", NULL);
-	fflush(fp);
+	fflush_monitor(fp);
 	return 0;
 }
 
diff --git a/ip/ipnetns.c b/ip/ipnetns.c
index 3a33a3adacee31080c3ea9d0a52e455243423a75..abe5746415176c137c9755a6211cc4b7cbabe4e2 100644
--- a/ip/ipnetns.c
+++ b/ip/ipnetns.c
@@ -327,7 +327,7 @@ int print_nsid(struct nlmsghdr *n, void *arg)
 
 	print_string(PRINT_FP, NULL, "\n", NULL);
 	close_json_object();
-	fflush(fp);
+	fflush_monitor(fp);
 	return 0;
 }
 
diff --git a/ip/ipnexthop.c b/ip/ipnexthop.c
index d5c429369d10f629823639fa7e6bfb70be5226d6..a9ebffc8e50101c5c4b2480fd4d8e1bb1a3c7588 100644
--- a/ip/ipnexthop.c
+++ b/ip/ipnexthop.c
@@ -826,7 +826,7 @@ int print_cache_nexthop(struct nlmsghdr *n, void *arg, bool process_cache)
 
 	__print_nexthop_entry(fp, NULL, &nhe, n->nlmsg_type == RTM_DELNEXTHOP);
 	print_string(PRINT_FP, NULL, "%s", "\n");
-	fflush(fp);
+	fflush_monitor(fp);
 
 	if (process_cache)
 		ipnh_cache_process_nlmsg(n, &nhe);
@@ -882,7 +882,7 @@ int print_nexthop_bucket(struct nlmsghdr *n, void *arg)
 
 	print_string(PRINT_FP, NULL, "%s", "\n");
 	close_json_object();
-	fflush(fp);
+	fflush_monitor(fp);
 
 	return 0;
 }
@@ -1178,7 +1178,7 @@ static int ipnh_get_id(__u32 id)
 	}
 
 	delete_json_obj();
-	fflush(stdout);
+	fflush_monitor(stdout);
 
 	free(answer);
 
@@ -1266,7 +1266,7 @@ static int ipnh_list_flush(int argc, char **argv, int action)
 	}
 
 	delete_json_obj();
-	fflush(stdout);
+	fflush_monitor(stdout);
 
 	return 0;
 }
@@ -1342,7 +1342,7 @@ static int ipnh_bucket_list(int argc, char **argv)
 	}
 
 	delete_json_obj();
-	fflush(stdout);
+	fflush_monitor(stdout);
 
 	return 0;
 }
@@ -1383,7 +1383,7 @@ static int ipnh_bucket_get_id(__u32 id, __u16 bucket_index)
 	}
 
 	delete_json_obj();
-	fflush(stdout);
+	fflush_monitor(stdout);
 
 	free(answer);
 
diff --git a/ip/iproute.c b/ip/iproute.c
index c2538894da633b56f5b926ecafda4960a48e9fbd..c6a6ba9dd37076acfceb9b259874a50e7cd3c3d0 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -1012,7 +1012,7 @@ int print_route(struct nlmsghdr *n, void *arg)
 
 	print_string(PRINT_FP, NULL, "\n", NULL);
 	close_json_object();
-	fflush(fp);
+	fflush_monitor(fp);
 	return 0;
 }
 
@@ -2035,7 +2035,7 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
 	}
 
 	delete_json_obj();
-	fflush(stdout);
+	fflush_monitor(stdout);
 	return 0;
 }
 
diff --git a/ip/iprule.c b/ip/iprule.c
index 3af02da24950ae224614e8e45e3de400675eee57..5bcafe11986f84f4b1946d758647d909456aeb61 100644
--- a/ip/iprule.c
+++ b/ip/iprule.c
@@ -599,7 +599,7 @@ int print_rule(struct nlmsghdr *n, void *arg)
 
 	print_string(PRINT_FP, NULL, "\n", "");
 	close_json_object();
-	fflush(fp);
+	fflush_monitor(fp);
 	return 0;
 }
 
diff --git a/ip/iptoken.c b/ip/iptoken.c
index f25a7c8b21f57c941d975a0255b0613f8a38f999..c19f9e0b4fdb282d1835959b025adf5bdf5a14e8 100644
--- a/ip/iptoken.c
+++ b/ip/iptoken.c
@@ -85,7 +85,7 @@ static int print_token(struct nlmsghdr *n, void *arg)
 			   "ifname", "%s\n",
 			   ll_index_to_name(ifi->ifi_index));
 	close_json_object();
-	fflush(fp);
+	fflush_monitor(fp);
 
 	return 0;
 }
diff --git a/ip/tcp_metrics.c b/ip/tcp_metrics.c
index 9c8fb07240bf01511aa2fc8cc2e80603db3252c9..b69bb282e1f30f53843e2cd9e51bfc3debf4310b 100644
--- a/ip/tcp_metrics.c
+++ b/ip/tcp_metrics.c
@@ -334,7 +334,7 @@ static int process_msg(struct nlmsghdr *n, void *arg)
 
 	print_string(PRINT_FP, NULL, "\n", "");
 	close_json_object();
-	fflush(fp);
+	fflush_monitor(fp);
 	return 0;
 }
 
diff --git a/lib/utils.c b/lib/utils.c
index 1215fe31cb3f63c0fa768fef60da77a641c51581..7017b0e6afacd8e770fb9f8b26aa5a319c1279e7 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -41,6 +41,7 @@ int timestamp_short;
 int pretty;
 int use_iec;
 int human_readable;
+int monitor_mode;
 const char *_SL_ = "\n";
 
 static int open_fds[5];
diff --git a/misc/ss.c b/misc/ss.c
index 14e9f27a75321556240a5f290b8bcf51c605a4c2..0f9b37177d375ddf70cb34674992723b5c4883be 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -5544,7 +5544,7 @@ static int generic_show_sock(struct nlmsghdr *nlh, void *arg)
 
 	render();
 
-	fflush(stdout);
+	fflush_monitor(stdout);
 	return ret;
 }
 
@@ -5580,6 +5580,7 @@ static int handle_follow_request(struct filter *f)
 		f->rth_for_killing = &rth2;
 	}
 
+	monitor_mode = 1;
 	if (rtnl_dump_filter(&rth, generic_show_sock, f))
 		ret = -1;
 
diff --git a/tc/tc_class.c b/tc/tc_class.c
index 6d707d8c924f4b5e90201d4de8e9779f82ce17f3..8197566281fad47d4efcf4768ed406ab809dd08a 100644
--- a/tc/tc_class.c
+++ b/tc/tc_class.c
@@ -380,7 +380,7 @@ int print_class(struct nlmsghdr *n, void *arg)
 		close_json_object();
 	}
 	close_json_object();
-	fflush(fp);
+	fflush_monitor(fp);
 	return 0;
 }
 
diff --git a/tc/tc_filter.c b/tc/tc_filter.c
index 7db850bda11a3408ec66b457c9fc590f3a734f65..633f027d79865d98ba1ccba48af71d247dfc7a48 100644
--- a/tc/tc_filter.c
+++ b/tc/tc_filter.c
@@ -374,7 +374,7 @@ int print_filter(struct nlmsghdr *n, void *arg)
 
 	print_ext_msg(tb);
 	close_json_object();
-	fflush(fp);
+	fflush_monitor(fp);
 	return 0;
 }
 
diff --git a/tc/tc_monitor.c b/tc/tc_monitor.c
index 5b9bccbed4140241a4d7a5cffc50865106224867..49bd4b6a460fbfe41a35e06f92f07dbe56a6be2d 100644
--- a/tc/tc_monitor.c
+++ b/tc/tc_monitor.c
@@ -100,6 +100,7 @@ int do_tcmonitor(int argc, char **argv)
 		return ret;
 	}
 
+	monitor_mode = 1;
 	if (rtnl_open(&rth, groups) < 0)
 		exit(1);
 
diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c
index 7eb9a31baa31fb91a8141c9eca1135e76a52fa8b..a8ef8fc9f70d91609d6ed61c2a46b29120512fd2 100644
--- a/tc/tc_qdisc.c
+++ b/tc/tc_qdisc.c
@@ -344,7 +344,7 @@ int print_qdisc(struct nlmsghdr *n, void *arg)
 
 	print_ext_msg(tb);
 	close_json_object();
-	fflush(fp);
+	fflush_monitor(fp);
 	return 0;
 }
 
-- 
2.54.0.545.g6539524ca2-goog


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-04-27 16:47 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-27  8:19 [PATCH v2 iproute2-next] utils: add fflush_monitor() helper Eric Dumazet
2026-04-27 16:31 ` Stephen Hemminger
2026-04-27 16:47   ` Eric Dumazet

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox