All of lore.kernel.org
 help / color / mirror / Atom feed
From: Stephen Hemminger <stephen@networkplumber.org>
To: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>
Cc: David Ahern <dsahern@kernel.org>,
	netdev@vger.kernel.org, mptcp@lists.linux.dev
Subject: Re: [PATCH iproute2-next 0/3] ip mptcp monitor: add JSON support
Date: Fri, 20 Feb 2026 21:35:31 -0800	[thread overview]
Message-ID: <20260220213531.2d930e5d@phoenix.local> (raw)
In-Reply-To: <20260220-ipr-monitor-json-v1-0-eb4b0d5f7820@kernel.org>

On Fri, 20 Feb 2026 19:54:00 +0100
"Matthieu Baerts (NGI0)" <matttbe@kernel.org> wrote:

> With this series, the command 'ip [-t[s]] mptcp monitor' produces an
> output with the JSON format.
> 
> - Patch 1: a small refactoring to uniform the code.
> 
> - Patch 2: add JSON support in print_timestamp() helper.
> 
> - Patch 3: add JSON support to 'ip mptcp monitor' as requested by
>   Stephen.
> 
> Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
> ---
> Matthieu Baerts (NGI0) (3):
>       mptcp: uniform stream closure
>       utils: timestamp: add JSON support
>       mptcp: monitor: add JSON support
> 
>  ip/ipmptcp.c | 96 +++++++++++++++++++++++++++++++++++++++++-------------------
>  lib/utils.c  | 19 ++++++++----
>  2 files changed, 80 insertions(+), 35 deletions(-)
> ---
> base-commit: f120cdb35da76ca99932d0428a0917bd01a843da
> change-id: 20260220-ipr-monitor-json-1573371524c1
> 
> Best regards,

I used recent review-prompt to do a more deep dive AI analysis.
And it found:

Here's the deep dive review. The series is solid work from Matthieu —
clean, well-structured, and follows iproute2 conventions. The main
items worth raising:

token printed via print_uint() with %08x format — text will show hex
but JSON will emit decimal. Probably fine (JSON consumers prefer raw
numbers), but worth a conscious decision.

Signal handler calls delete_json_obj() and rtnl_close() — these aren't
async-signal-safe. Pragmatically OK for a Ctrl-C'd monitor tool, but
rtnl_close() could be dropped since exit() cleans up the socket anyway.

Missing delete_json_obj() on the normal/error exit path after
rtnl_listen() returns — if it fails rather than being signaled, the
JSON ] never gets written.

Patch 1 quietly fixes a real bug (fflush before close_json_object) —
the commit message could call that out more explicitly.

--------
# Review: [PATCH iproute2-next 0/3] ip mptcp monitor: add JSON support

**Author**: Matthieu Baerts (NGI0) \<matttbe@kernel.org\>
**Date**: Fri, 20 Feb 2026
**Series**: 3 patches

## Overview

This series adds JSON output support to `ip mptcp monitor`, converting raw `printf()` calls to the standard `print_XXX()` helpers. It's well-structured as three incremental patches: a cleanup, a utility enhancement, and the main feature. Overall this is solid work — the conversion is thorough and follows iproute2 conventions well. I have a few comments below, mostly minor.

---

## Patch 1/3: mptcp: uniform stream closure

**Verdict: Looks good.**

This is a clean refactoring. Two changes:

1. Replaces `print_string(PRINT_FP, NULL, "\n", NULL)` and `print_string(PRINT_FP, NULL, "%s", "\n")` with `print_nl()` — correct and cleaner.

2. Reorders `close_json_object()` to come *after* `print_nl()` but *before* `fflush()`. This is the right ordering: newline belongs inside the object's text representation, and flushing should happen after the JSON object is fully closed so the complete JSON is written out.

In `print_mptcp_limit()`, the original code called `fflush(stdout)` before `close_json_object()` — that's a bug in the existing code (would flush incomplete JSON). This patch fixes it. Worth noting in the commit message that this is a bugfix, not just cosmetic.

No issues.

---

## Patch 2/3: utils: timestamp: add JSON support

**Verdict: Acceptable, with comments.**

Adds JSON-aware output to `print_timestamp()` by using `print_string()` when `fp == stdout`, falling back to `fprintf()` otherwise.

### Comments

**1. The `fp == stdout` conditional pattern is unusual but justified here.**

The commit message explains this: the `print_XXX()` helpers only write to stdout, so when `fp` is something else (e.g. stderr), it must fall back to `fprintf()`. This is a reasonable pragmatic choice given the existing API. A brief inline comment in the code would help future readers understand *why* the check exists:

```c
/* print_string() only outputs to stdout; fall back to fprintf() for other streams */
if (fp == stdout)
```

**2. JSON key naming: `timestamp_short` vs `timestamp`.**

The short timestamp gets key `"timestamp_short"` while the long one gets `"timestamp"`. This means JSON consumers need to know which format was requested to know which key to look for. Consider using a single key name (e.g. `"timestamp"`) for both, since only one can ever be present at a time and consumers shouldn't need to care about the format variant. Up to the maintainer though — there may be value in distinguishing them.

**3. The `snprintf` composition is clean.**

Building the timestamp string first with `strftime` + `snprintf` for the microseconds, then passing the complete string to `print_string()`, is the right approach. It avoids needing two separate JSON fields for the time and microsecond components.

**4. Minor: `strftime()` return value.**

`strftime()` returns 0 on failure (buffer too small). The code uses the return value in `ts + len` without checking for 0. The buffer is 40 bytes and the format `"%Y-%m-%dT%H:%M:%S"` is ~19 chars, so this is safe in practice, but a pedantic reviewer might want a check. Not a blocker.

---

## Patch 3/3: mptcp: monitor: add JSON support

**Verdict: Good overall, a few points to discuss.**

This is the main patch. It converts all `printf()` / `color_fprintf()` calls in `mptcp_monitor_msg()` to `print_XXX()` helpers and adds JSON object framing and signal handling.

### What's done well

- Consistent use of `print_uint(PRINT_ANY, ...)`, `print_string(PRINT_ANY, ...)`, `print_0xhex(PRINT_ANY, ...)` throughout — no fprintf-to-stdout for display output.
- Error output isn't affected (no stdout corruption risk).
- `open_json_object(NULL)` / `close_json_object()` properly paired in `mptcp_monitor_msg()`.
- The boolean flags (`server_side`, `deny_join_id0`) correctly use separate `print_string(PRINT_FP, ...)` / `print_bool(PRINT_JSON, ...)` paths — this is one of the legitimate cases for separate JSON/text output, since the text format is a bare keyword while JSON needs a proper boolean value.
- Merging the two identical `UNKNOWN` cases into one `||` condition is a nice cleanup.

### Comments

**1. `token` format: `%08x` in `print_uint()` — JSON will emit decimal, not hex.**

```c
print_uint(PRINT_ANY, "token"," token=%08x",
           rta_getattr_u32(tb[MPTCP_ATTR_TOKEN]));
```

The text format string `%08x` will show hex in text mode, but `print_uint()` emits the raw numeric value in JSON mode — which will be decimal. This changes the JSON representation from what a user might expect for a token (usually seen as hex). Two options:

- Use `print_0xhex()` if you want hex in both modes.
- Accept decimal in JSON (it's a valid uint32) and document it. JSON consumers typically prefer raw numeric values anyway.

Either way, this deserves a conscious decision. The same applies to `reset_flags` but that one already uses `print_0xhex()` which is correct.

**2. Missing space before `"token"` format string.**

```c
print_uint(PRINT_ANY, "token"," token=%08x",
```

There's a missing space after `"token",` — purely cosmetic, but the rest of the file has consistent spacing after commas. Very minor.

**3. Signal handler safety: `sig_exit_json()` calls non-async-signal-safe functions.**

```c
static void sig_exit_json(int signo)
{
    delete_json_obj();
    rtnl_close(&genl_rth);
    exit(0);
}
```

`delete_json_obj()` ultimately calls `fwrite()`/`fflush()` to emit the closing `]`, and `rtnl_close()` calls `close()`. Strictly speaking, `fwrite`/`fflush` are not async-signal-safe (POSIX). If the signal arrives while inside `printf()` or another stdio call in `mptcp_monitor_msg()`, this could deadlock or corrupt the stream.

In practice, for a simple monitoring tool that's being Ctrl-C'd by a user, this is unlikely to cause real problems. But the technically correct approach would be to set a volatile flag in the signal handler and check it in the main loop, or use `sigaction` with `SA_RESTART` and handle cleanup after `rtnl_listen()` returns.

This pattern does exist in other iproute2 monitor commands, so it may be acceptable as-is. Worth noting for awareness.

**4. `rtnl_close(&genl_rth)` in signal handler — is this necessary?**

Other monitor commands (e.g. `ip monitor`) don't close the rtnl handle in signal handlers. The process is about to `exit(0)` anyway, so the kernel will clean up the socket. Removing it would reduce the signal-safety concern.

**5. `new_json_obj(json)` placement.**

```c
new_json_obj(json);

if (is_json_context()) {
    struct sigaction sa = { .sa_handler = sig_exit_json };

    sigaction(SIGINT, &sa, NULL);
    sigaction(SIGTERM, &sa, NULL);
}
```

This looks correct — `new_json_obj()` initializes the JSON context, and then the signal handlers are only installed when actually in JSON mode. Good.

However, there's no corresponding `delete_json_obj()` on the normal exit path (after `rtnl_listen()` returns). If `rtnl_listen()` returns due to an error rather than a signal, the JSON output won't be properly closed. Consider adding cleanup after the `rtnl_listen()` call:

```c
if (rtnl_listen(&genl_rth, mptcp_monitor_msg, stdout) < 0) {
    delete_json_obj();
    return 2;
}

delete_json_obj();
return 0;
```

**6. `sigaction` struct initialization.**

```c
struct sigaction sa = { .sa_handler = sig_exit_json };
```

This zero-initializes the rest of the struct via designated initializer, so `sa_mask` is empty and `sa_flags` is 0. That's fine. The `SA_RESTART` flag is intentionally not set, which means `rtnl_listen()` will be interrupted by the signal and return `EINTR` — but the signal handler calls `exit(0)` so it never actually returns. Acceptable.

---

## Commit Message Quality

All three patches have proper `Signed-off-by`, correct `[PATCH iproute2-next]` prefix, and reasonable descriptions. Patch 2's message is the most detailed, which is appropriate since it has the most subtle design decision (the `fp == stdout` check).

One suggestion: Patch 1's message could mention that the reordering of `close_json_object()` vs `fflush()` in `print_mptcp_limit()` fixes incorrect flush ordering, not just "uniform" the code.

---

## Summary

| Check | Status |
|---|---|
| `strcmp()` not `matches()` | N/A (no arg parsing changes) |
| `print_XXX()` helpers used | ✅ All printf→print_XXX conversions correct |
| Errors to stderr | ✅ No error output changes |
| JSON open/close paired | ✅ Balanced in mptcp_monitor_msg |
| `PRINT_ANY` preferred | ✅ Used throughout; separate paths only where justified |
| Signed-off-by present | ✅ All three patches |
| Subject format | ✅ `[PATCH iproute2-next N/3]` |
| No string breaking | ✅ |
| Coding style | ✅ Tabs, braces, naming all correct |

**Key items for author attention:**

1. **`token` hex format** — confirm whether decimal in JSON is intentional (probably fine, but worth a note)
2. **Signal handler safety** — pragmatically OK, but consider removing `rtnl_close()` from the handler
3. **Missing `delete_json_obj()`** on `rtnl_listen()` error path
4. Consider single `"timestamp"` key name in patch 2


      parent reply	other threads:[~2026-02-21  5:35 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-20 18:54 [PATCH iproute2-next 0/3] ip mptcp monitor: add JSON support Matthieu Baerts (NGI0)
2026-02-20 18:54 ` [PATCH iproute2-next 1/3] mptcp: uniform stream closure Matthieu Baerts (NGI0)
2026-02-20 18:54 ` [PATCH iproute2-next 2/3] utils: timestamp: add JSON support Matthieu Baerts (NGI0)
2026-02-21  5:39   ` Stephen Hemminger
2026-02-23 13:20     ` Matthieu Baerts
2026-02-23 15:31       ` Matthieu Baerts
2026-02-20 18:54 ` [PATCH iproute2-next 3/3] mptcp: monitor: " Matthieu Baerts (NGI0)
2026-02-21  5:23   ` Stephen Hemminger
2026-02-21  5:35 ` Stephen Hemminger [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260220213531.2d930e5d@phoenix.local \
    --to=stephen@networkplumber.org \
    --cc=dsahern@kernel.org \
    --cc=matttbe@kernel.org \
    --cc=mptcp@lists.linux.dev \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.