Skip to content

Mgmt frontend problems in zebra - #21252

Merged
Jafaral merged 8 commits into
FRRouting:masterfrom
donaldsharp:mgmt_frontend_problems_in_zebra
Apr 8, 2026
Merged

Mgmt frontend problems in zebra#21252
Jafaral merged 8 commits into
FRRouting:masterfrom
donaldsharp:mgmt_frontend_problems_in_zebra

Conversation

@donaldsharp

Copy link
Copy Markdown
Member

See individual commits for more detail:

Move ip import-table, zebra work-queue, zebra zapi-packets, zebra dplane limit and allow-external-route-update to their appropriate place in the mgmt frontend.

Add tests to show things are working better.

@frrbot frrbot Bot added tests Topotests, make check, etc zebra labels Mar 18, 2026
@greptile-apps

greptile-apps Bot commented Mar 18, 2026

Copy link
Copy Markdown

Greptile Summary

This PR moves ip import-table, zebra work-queue, zebra zapi-packets, zebra dplane limit, and allow-external-route-update from legacy DEFUN handlers into the mgmt/northbound frontend, converting the import-kernel-table YANG node from a container to a list keyed on (afi-safi, table-id) to support both IPv4/IPv6 unicast and multicast import. It also extends the edit_notify callback with error/errstr parameters so VTY can surface mgmtd edit failures to the user. Previously-flagged issues (wrong msg_len in the error path, stale route-map data in route_map_destroy) have been addressed.

Confidence Score: 5/5

PR is safe to merge; all previously identified P0/P1 issues have been resolved and no new blocking issues were found.

The two P1 issues raised in earlier review rounds (wrong msg_len in the edit error path, stale route-map data in route_map_destroy) are both correctly addressed. The remaining findings are P2: a stale docstring copy-paste and test entries not cleaned up after the new bad-values test. Neither affects correctness or production behavior.

tests/topotests/zebra_rib/test_zebra_import.py β€” minor cleanup and docstring issues only

Vulnerabilities

No security concerns identified. The mgmt frontend changes are internal IPC, input validation is done through the northbound NB_EV_VALIDATE callback, and no new external-facing attack surfaces are introduced.

Important Files Changed

Filename Overview
lib/mgmt_fe_client.c Adds MGMT_MSG_CODE_EDIT error path handling using mgmt_msg_native_get_msg_len(edit_msg) (fixing the previous msg_len bug); success path passes error=0, errstr=NULL β€” both correct.
lib/mgmt_fe_client.h Extends edit_notify callback signature with int error, const char *errstr β€” clean, consistent with commit/lock pattern.
mgmtd/mgmt_vty_frontend.c Updated to new edit_notify signature; errors are surfaced to VTY with CMD_WARNING_CONFIG_FAILED and the errstr printed to the user β€” correct behavior.
zebra/zebra_nb_config.c Implements previously-stubbed northbound callbacks; route_map_destroy is now a no-op delegating to parent apply_finish, which reads committed dnode (fixes the stale-data issue).
zebra/zebra_cli.c Adds YANG-backed DEFPY commands for dplane-limit, zapi-packets, workqueue-timer, and import-table (IPv4 and IPv6); cli_show callbacks added.
zebra/zebra_vty.c Removes legacy DEFUN/DEFPY handlers for commands now owned by zebra_cli.c/northbound. zebra_ip_config simplified to return 0 since YANG handles serialization.
yang/frr-zebra.yang Converts import-kernel-table from container to list keyed on afi-safi+table-id; adds must expression restricting afi-safi to IPv4/IPv6 unicast/multicast; removes old range "1..252" from table-id (OS-agnostic, validated in C callbacks).
zebra/zebra_nb.c Updates northbound node registration from table-id leaf to import-kernel-table list with create/destroy/apply_finish callbacks β€” correct structural change.
tests/topotests/zebra_rib/test_zebra_import.py Adds check_show_running helper and new test cases verifying show-running output, route-map lifecycle, and test_zebra_import_bad_values for invalid/valid table ID validation via mgmt interface.
lib/northbound.c Comment-only update clarifying that deleted dnodes not found in candidate config fall through to a parent destroy iteration β€” no logic change.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[VTY: ip import-table N] --> B[zebra_cli.c DEFPY_YANG]
    B --> C[nb_cli_enqueue_change NB_OP_CREATE on list entry]
    C --> D[nb_cli_apply_changes]
    D --> E{NB_EV_VALIDATE zebra_import_kernel_table_create}
    E -- valid table_id --> F[NB_EV_APPLY: no-op]
    E -- invalid table_id --> G[NB_ERR_VALIDATION Error to VTY]
    F --> H[apply_finish zebra_import_kernel_table_apply_finish]
    H --> I[zebra_import_kernel_table_apply add=true reads committed dnode]
    I --> J[zebra_import_table AFI/SAFI/VRF/table_id/distance/rmap]
    K[VTY: no ip import-table N] --> L[no_ip_zebra_import_table_cmd]
    L --> M[nb_cli_enqueue_change NB_OP_DESTROY on list entry]
    M --> N[zebra_import_kernel_table_destroy NB_EV_APPLY]
    N --> O[zebra_import_kernel_table_apply add=false distance=0 rmap=NULL]
    O --> J
    P[mgmtd EDIT reply success] --> Q[edit_notify error=0 errstr=NULL]
    R[mgmtd EDIT reply error] --> S[edit_notify error!=0 errstr set]
    Q --> T[vty_mgmt_resume_response CMD_SUCCESS]
    S --> U[vty_out errstr / CMD_WARNING_CONFIG_FAILED]
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: tests/topotests/zebra_rib/test_zebra_import.py
Line: 545

Comment:
**Stale docstring copied from `test_zebra_mrib_import`**

The function docstring says `"Verify router starts with the initial MRIB"`, but this test actually validates rejection of invalid table IDs and acceptance of valid ones. The docstring was copied from an earlier test and not updated.

```suggestion
    "Verify invalid and valid import-table IDs are properly handled"
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: tests/topotests/zebra_rib/test_zebra_import.py
Line: 566-574

Comment:
**Valid table entries not cleaned up after test**

The loop creates three live import-table entries (table IDs 1, 253, 1000 with `ipv4-unicast`) but does not remove them. Since this test is currently last before `test_memory_leak`, the leaked config entries aren't a problem today, but they would pollute state if a new test is inserted after this one. Consider adding a teardown block that removes the created entries:

```python
    # Cleanup valid entries
    for tid in valids:
        r1.vtysh_cmd(f"conf term\n no ip import-table {tid}\n")
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (4): Last reviewed commit: "tests: update test description" | Re-trigger Greptile

Comment thread zebra/zebra_nb_config.c
Comment on lines 239 to 251
int zebra_import_kernel_table_route_map_destroy(struct nb_cb_destroy_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
/* TODO: implement me. */
break;
}
const struct lyd_node *dnode =
(const struct lyd_node *)args->dnode->parent;

if (args->event != NB_EV_APPLY)
return NB_OK;

if (zebra_import_kernel_table_apply(dnode, true) < 0)
return NB_ERR;

return NB_OK;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 route_map_destroy re-applies with stale route-map data

In FRR's northbound framework, args->dnode for a destroy callback points to the old (pre-deletion) diff node. Therefore args->dnode->parent is the list entry as it existed before the change, meaning the route-map leaf is still present as a child. As a result, yang_dnode_exists(dnode, "route-map") returns true and the old route-map name is read, so zebra_import_kernel_table_apply(dnode, true) re-applies the import table with the route-map still in effect instead of removing it.

This path is not exercised by the CLI (no ip import-table / no ipv6 import-table always destroys the entire list entry via NB_OP_DESTROY on the entry xpath, triggering zebra_import_kernel_table_destroy), but it is reachable via direct YANG/mgmtd operations that delete only the route-map leaf while keeping the list entry.

The callback needs to call zebra_import_table explicitly with rmap = NULL to apply the updated state without the route-map:

int zebra_import_kernel_table_route_map_destroy(struct nb_cb_destroy_args *args)
{
	const struct lyd_node *dnode =
		(const struct lyd_node *)args->dnode->parent;
	const char *afi_safi = yang_dnode_get_string(dnode, "afi-safi");
	uint32_t table_id = yang_dnode_get_uint32(dnode, "table-id");
	uint32_t distance = yang_dnode_get_uint32(dnode, "distance");
	afi_t afi;
	safi_t safi;

	if (args->event != NB_EV_APPLY)
		return NB_OK;

	yang_afi_safi_identity2value(afi_safi, &afi, &safi);

	/* Re-apply without the route-map since it is being removed */
	if (zebra_import_table(afi, safi, VRF_DEFAULT, table_id, distance,
			       NULL, true) < 0)
		return NB_ERR;

	return NB_OK;
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: zebra/zebra_nb_config.c
Line: 239-251

Comment:
**`route_map_destroy` re-applies with stale route-map data**

In FRR's northbound framework, `args->dnode` for a destroy callback points to the **old** (pre-deletion) diff node. Therefore `args->dnode->parent` is the list entry as it existed before the change, meaning the route-map leaf is still present as a child. As a result, `yang_dnode_exists(dnode, "route-map")` returns `true` and the old route-map name is read, so `zebra_import_kernel_table_apply(dnode, true)` re-applies the import table *with the route-map still in effect* instead of removing it.

This path is not exercised by the CLI (`no ip import-table` / `no ipv6 import-table` always destroys the entire list entry via `NB_OP_DESTROY` on the entry xpath, triggering `zebra_import_kernel_table_destroy`), but it is reachable via direct YANG/mgmtd operations that delete only the route-map leaf while keeping the list entry.

The callback needs to call `zebra_import_table` explicitly with `rmap = NULL` to apply the updated state without the route-map:

```c
int zebra_import_kernel_table_route_map_destroy(struct nb_cb_destroy_args *args)
{
	const struct lyd_node *dnode =
		(const struct lyd_node *)args->dnode->parent;
	const char *afi_safi = yang_dnode_get_string(dnode, "afi-safi");
	uint32_t table_id = yang_dnode_get_uint32(dnode, "table-id");
	uint32_t distance = yang_dnode_get_uint32(dnode, "distance");
	afi_t afi;
	safi_t safi;

	if (args->event != NB_EV_APPLY)
		return NB_OK;

	yang_afi_safi_identity2value(afi_safi, &afi, &safi);

	/* Re-apply without the route-map since it is being removed */
	if (zebra_import_table(afi, safi, VRF_DEFAULT, table_id, distance,
			       NULL, true) < 0)
		return NB_ERR;

	return NB_OK;
}
```

How can I resolve this? If you propose a fix, please make it concise.

@donaldsharp

Copy link
Copy Markdown
Member Author

@choppsv1 -> I need some advice here on what you think is best to do. For the ip import-table.. changes it's like 3-4 lines and the ai wants me to change the approach. When I do that to deduplicate it's several hundred lines of code. Searching the code base the only thing similiar to this problem is the router advertisement cli.

@choppsv1

Copy link
Copy Markdown
Contributor

@choppsv1 -> I need some advice here on what you think is best to do. For the ip import-table.. changes it's like 3-4 lines and the ai wants me to change the approach. When I do that to deduplicate it's several hundred lines of code. Searching the code base the only thing similiar to this problem is the router advertisement cli.

I'm going through the changes now, then I'll check out greptile's suggestions again.

@choppsv1
choppsv1 self-requested a review March 19, 2026 15:47
@choppsv1

choppsv1 commented Mar 19, 2026

Copy link
Copy Markdown
Contributor

I think the simple solution to the multiple calls to zebra_import_table (for list node create and for leaf-node modify), is to just have zebra_import_table check if it's already done the work and do-nothing if so. This seems to be easy enough to do since it tracks this info:

int zebra_import_table(afi_t afi, safi_t safi, vrf_id_t vrf_id, uint32_t table_id,
		       uint32_t distance, const char *rmap_name, bool add)
	...
                // ... add case
		zebra_import_table_used[afi][safi][table_id] = 1;
		zebra_import_table_distance[afi][safi][table_id] = distance;
	} else {
                // ... !add case
		zebra_import_table_used[afi][safi][table_id] = 0;
		zebra_import_table_distance[afi][safi][table_id] = ZEBRA_TABLE_DISTANCE_DEFAULT;

@github-actions

github-actions Bot commented Mar 20, 2026

Copy link
Copy Markdown

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@greptileai re-review

@donaldsharp
donaldsharp force-pushed the mgmt_frontend_problems_in_zebra branch from f60bc5b to 242e105 Compare March 20, 2026 18:12
@github-actions

Copy link
Copy Markdown

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@choppsv1
choppsv1 force-pushed the mgmt_frontend_problems_in_zebra branch from 242e105 to 88ff01a Compare April 7, 2026 14:35
@frrbot frrbot Bot added the libfrr label Apr 7, 2026
@github-actions github-actions Bot removed the conflicts label Apr 7, 2026
@choppsv1
choppsv1 force-pushed the mgmt_frontend_problems_in_zebra branch 2 times, most recently from e33c0c2 to 88ff01a Compare April 7, 2026 14:39
Route the `zebra dplane limit` CLI through the mgmt-fronted
zebra NB path and implement the existing dplane queue limit
NB apply callback so the command keeps its behavior after the move.

Signed-off-by: Donald Sharp <sharpd@nvidia.com>
Move the `zebra zapi-packets` command to fully use the mgmt
frontend.

Signed-off-by: Donald Sharp <sharpd@nvidia.com>
Reroute the `zebra work-queue` commands to actually be
on the mgmt frontend side instead of the zebra side.

Signed-off-by: Donald Sharp <sharpd@nvidia.com>
The `ip import-table ...` commands were not on the mgmt
front end side.  Move them to it.

Signed-off-by: Donald Sharp <sharpd@nvidia.com>
@choppsv1
choppsv1 force-pushed the mgmt_frontend_problems_in_zebra branch from 88ff01a to 9c58aa8 Compare April 7, 2026 17:49
@github-actions github-actions Bot added size/XXL and removed size/XL labels Apr 7, 2026

@choppsv1 choppsv1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, includes a few changes from me as well, in case @donaldsharp you want to review them.

@greptileai re-review

@donaldsharp

Copy link
Copy Markdown
Member Author

@greptile review

Comment thread yang/frr-zebra.yang
@choppsv1
choppsv1 force-pushed the mgmt_frontend_problems_in_zebra branch from 9c58aa8 to 0395396 Compare April 8, 2026 06:17
@frrbot frrbot Bot added the mgmt FRR Management Infra label Apr 8, 2026
@choppsv1

choppsv1 commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

@greptileai review and please pay attention to the comment I left regarding the YANG range restriction and why it was correctly removed -- that limited range only applied to early versions of linux kernels. Modern linux kernels support a much larger range. Furthermore, that range is totally incorrect for other, non-linux, operating systems that FRR also runs on.

@choppsv1
choppsv1 force-pushed the mgmt_frontend_problems_in_zebra branch from 0395396 to 4b28707 Compare April 8, 2026 06:39
@mjstapp

mjstapp commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

@greptileai review

@mjstapp

mjstapp commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

seems like the greptile didn't care for the extra info, maybe?

Comment thread lib/mgmt_fe_client.c Outdated
choppsv1 added 4 commits April 8, 2026 14:55
Improve handling of error in frontend client/mgmt vty. Use this to
return a more appropriate result (CMD_WARNING_CONFIG_FAILED) back to
vtysh mirroring the normal config change path. As a result vtysh will
correctly exit with status 1 when running one shot `mgmt edit` config
commands.

Signed-off-by: Christian Hopps <chopps@labn.net>
Signed-off-by: Christian Hopps <chopps@labn.net>
Better test:

a) ip import table
b) allow-external....
c) packet read in values for zebra

Signed-off-by: Donald Sharp <sharpd@nvidia.com>
Signed-off-by: Christian Hopps <chopps@labn.net>
This is a particular type of test we shouldn't mix in other generic
config tests. The previous name was too generic as well so update it
too.

Signed-off-by: Christian Hopps <chopps@labn.net>
@choppsv1
choppsv1 force-pushed the mgmt_frontend_problems_in_zebra branch from 4b28707 to 628dccb Compare April 8, 2026 14:56
@Jafaral

Jafaral commented Apr 8, 2026

Copy link
Copy Markdown
Member

@greptile review
also resolve existing feedback where applicable

@Jafaral
Jafaral merged commit 6ba3b5e into FRRouting:master Apr 8, 2026
22 checks passed
@donaldsharp
donaldsharp deleted the mgmt_frontend_problems_in_zebra branch April 29, 2026 12:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libfrr master mgmt FRR Management Infra size/XXL tests Topotests, make check, etc zebra

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants