Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
44ddeb8
lib: allow oper callbacks with ignore_cfg_cbs
lamestllama May 23, 2026
a12f22b
ospfd,ospf6d: add RFC 9129 operational YANG state
lamestllama May 23, 2026
5b38986
lib: add per-node cfg_opt_in callback control
lamestllama May 24, 2026
00d6c41
lib: batch direct-daemon config loads in one NB transaction
lamestllama May 25, 2026
a9a370e
mgmtd: match backend xpaths with predicates
lamestllama May 25, 2026
da14860
ospfd,ospf6d: write explicit router IDs through mgmtd
lamestllama May 24, 2026
5c9ddcc
ospfd,ospf6d: write area lists and area types through mgmtd
lamestllama May 24, 2026
7e27bb9
ospfd,ospf6d: write area summaries and default costs via mgmtd
lamestllama May 24, 2026
13c78cd
ospfd: route area stub CLI through ietf-ospf YANG
lamestllama May 24, 2026
e60378e
ospfd,ospf6d: write interface area attachment and cost
lamestllama May 24, 2026
7b57d67
ospfd,ospf6d: write interface timer and priority leaves
lamestllama May 24, 2026
e72a454
ospfd,ospf6d: write area ranges through mgmtd
lamestllama May 24, 2026
c1ba426
ospfd,ospf6d: write interface type and passive mode
lamestllama May 24, 2026
a53d492
ospfd,ospf6d: write administrative preferences through mgmtd
lamestllama May 24, 2026
3aeaa40
ospfd,ospf6d: route interface CLI through ietf-ospf YANG
lamestllama May 24, 2026
1c6d7bb
tests: add negative ietf-ospf YANG topotests
lamestllama May 24, 2026
13c10f1
tests: clean up OSPF YANG state between topotests
lamestllama May 24, 2026
0bccc64
tests: cover OSPF YANG config file batching
lamestllama May 26, 2026
77aaf74
doc: document ietf-ospf config-write scope for OSPF
lamestllama May 24, 2026
d679632
ospfd,ospf6d: keep protocol parents in the NB candidate
lamestllama May 26, 2026
cc5b5cc
ospfd,ospf6d: write interface transmit delay through mgmtd
lamestllama May 29, 2026
1716f1a
ospfd: route interface timer CLI through ietf-ospf YANG
lamestllama May 29, 2026
173bbf1
tests: cover per-leaf OSPF CLI conversions
lamestllama May 29, 2026
fbd4ae7
ospfd,ospf6d: write SPF path limits through mgmtd
lamestllama May 30, 2026
7cbf51c
ospfd: write LDP IGP sync through mgmtd
lamestllama May 30, 2026
11fbfd3
ospfd: write stub-router always through mgmtd
lamestllama May 30, 2026
1c7451b
ospfd,ospf6d: write prefix suppression through mgmtd
lamestllama May 30, 2026
e8baae5
ospfd,ospf6d: write auto-cost through mgmtd
lamestllama May 30, 2026
145d4b2
ospfd: write MPLS TE router IDs through mgmtd
lamestllama May 30, 2026
691984c
ospfd,ospf6d: write graceful-restart restarter config
lamestllama May 30, 2026
05aaa72
ospfd,ospf6d: write graceful-restart helper config
lamestllama May 30, 2026
a05a920
doc: declare remaining ietf-ospf nodes out of scope
lamestllama May 30, 2026
bc197ae
ospf6d: harden ospf6_route_remove_all against hook re-entry
lamestllama May 30, 2026
7a76ee0
ospfd,ospf6d: write interface BFD config through mgmtd
lamestllama May 30, 2026
0c4e6ea
ospfd: write interface static-neighbors through mgmtd
lamestllama May 30, 2026
4643d3d
ospfd: write authentication key chains through mgmtd
lamestllama May 30, 2026
31de901
lib: publish ietf_bfd_types_info once for backends that share it
lamestllama May 30, 2026
bcd364f
doc: list ietf-ospf nodes without FRR implementation
lamestllama May 30, 2026
7cd5c5b
ospfd,ospf6d: tighten OSPF YANG callback handling
lamestllama Jun 3, 2026
0d2d63e
ospfd,ospf6d: add clear-neighbor and clear-database RPCs
lamestllama May 31, 2026
c703970
ospfd,ospf6d: add neighbor state change notifications
lamestllama May 31, 2026
78b66e5
ospfd,ospf6d: add interface state change notifications
lamestllama May 31, 2026
8e1535d
ospfd,ospf6d: add graceful restart status notifications
lamestllama May 31, 2026
5e2cc8b
ospfd,ospf6d: add bad packet and config error notifications
lamestllama May 31, 2026
303240d
ospfd,ospf6d: harden OSPF notification mappings
lamestllama May 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/developer/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ FRRouting Developer's Guide
fpm
grpc
ospf
ospf-yang-northbound-notes
zebra
vtysh
path
Expand Down
751 changes: 751 additions & 0 deletions doc/developer/ospf-yang-northbound-notes.rst

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions doc/user/grpc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ Northbound gRPC Features

There is currently no support for YANG notifications.

.. note::

Per-daemon gRPC ``Execute`` validates RPC input in the daemon-local
libyang context before dispatching to the northbound callback. RPCs whose
input contains a leafref into ``/ietf-routing:routing`` can therefore fail
with ``INVALID_ARGUMENT`` even when the referenced routing protocol exists
in mgmtd. The mgmtd-fronted ``vtysh`` RPC path does not have this
limitation.


.. note::

Expand Down
57 changes: 57 additions & 0 deletions doc/user/ospf6d.rst
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,63 @@ Showing OSPF6 information
This command shows the graceful-restart helper details including helper
configuration parameters.

YANG / NETCONF Support
----------------------

OSPFv3 operational state and a subset of OSPFv3 configuration are exposed
through the standard :rfc:`9129` ``ietf-ospf`` YANG model. The OSPFv3
instance itself remains owned by the legacy ``router ospf6`` CLI, but
per-area, per-interface and per-instance configuration leaves are routed
through the mgmtd northbound and can be read, set, and committed through
NETCONF / RESTCONF / ``vtysh``'s ``mgmt`` subcommands as well as the legacy
CLI.

The supported set mirrors the OSPFv2 side documented in :ref:`ospfv2`, with
two v3-specific gaps:

* ``areas/area/default-cost``: ospf6d has no per-area stub default-cost
knob, so this leaf is not implemented. Setting it via YANG is rejected
by mgmtd as ``no backend handles this path``. This matches FRR's existing
v3 CLI surface (which has no ``area X default-cost`` equivalent) and is a
pre-existing v2/v3 feature gap, not introduced by this conversion.
* ``interface-type``: RFC 9129 declares ``broadcast``, ``non-broadcast``,
``point-to-multipoint``, ``point-to-point`` and ``hybrid``. ospf6d only
accepts ``broadcast``, ``point-to-point`` and ``point-to-multipoint``;
the NB callback rejects ``non-broadcast`` and ``hybrid`` at VALIDATE
with a clear error.

Otherwise the supported set matches the shared OSPFv2 RFC 9129 surface:
router-id, preference, spf-control paths, auto-cost, graceful-restart
enabled, restart-interval, helper-enabled and helper-strict-lsa-checking,
area lifecycle, area-type, area summary, ranges, per-interface attachment,
cost, hello-interval, dead-interval, retransmit-interval, priority,
mtu-ignore, transmit-delay, interface-type, passive, per-interface BFD
``enabled``, ``local-multiplier``, ``desired-min-tx-interval`` and
``required-min-rx-interval``, and per-interface
``authentication/ospfv3-key-chain``.

For per-interface BFD, ``bfd/enabled`` controls activation. The multiplier
and interval leaves can be configured while BFD is disabled, but they do not
create or register BFD sessions until ``bfd/enabled=true`` is committed. The
legacy parameterised BFD CLI enqueues that enable leaf before it writes the
parameter leaves.

Examples
^^^^^^^^

Retrieve the OSPFv3 instance from the operational datastore:

.. code-block:: shell

vtysh -c 'show mgmt get-data /ietf-routing:routing/control-plane-protocols/control-plane-protocol[type="ietf-ospf:ospfv3"][name="default"] datastore operational'

Retrieve the merged operational datastore, including the OSPFv3 protocol
entry and the ``ietf-interfaces`` data used by OSPF interface leafrefs:

.. code-block:: shell

vtysh -c 'show mgmt get-data /* datastore operational'

.. clicmd:: show debugging ospf6

Show debugging status for OSPFv3.
Expand Down
110 changes: 110 additions & 0 deletions doc/user/ospfd.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1083,6 +1083,116 @@ Showing Information
Displays the Graceful Restart Helper details including helper
config changes.

YANG / NETCONF Support
----------------------

OSPF operational state and a subset of OSPF configuration are exposed through
the standard :rfc:`9129` ``ietf-ospf`` YANG model. The OSPF instance itself
remains owned by the legacy ``router ospf`` CLI, but per-area, per-interface
and per-instance configuration leaves are routed through the mgmtd northbound
so they can be read, set and committed via NETCONF / RESTCONF / ``vtysh``'s
``mgmt`` subcommands as well as the legacy CLI.

For the default or VRF-based daemon, the RFC 9129
``control-plane-protocol`` name is the OSPF VRF name, normally ``default``.
When ``ospfd`` is started in daemon-instance mode, the RFC 9129 name is the
decimal instance ID used by the legacy CLI; for example, ``router ospf 5`` is
addressed as ``control-plane-protocol[type='ietf-ospf:ospfv2'][name='5']``.
This keeps separate ``ospfd`` backend processes distinct in mgmtd.

Supported configuration leaves
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Under ``/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-ospf:ospfv2']/ietf-ospf:ospf``:

* ``explicit-router-id``
* ``preference/{all,intra-area,inter-area,internal,external}`` (admin distance)
* ``spf-control/paths``
* ``auto-cost/{enabled,reference-bandwidth}``
* ``mpls/ldp/igp-sync`` and ``mpls/te-rid/ipv4-router-id``
* ``graceful-restart/{enabled,restart-interval,helper-enabled,helper-strict-lsa-checking}``
* ``stub-router/always``
* ``areas/area`` (list create / destroy keyed by ``area-id``)
* ``areas/area/area-type`` (``normal-area``, ``stub-area``, ``nssa-area``)
* ``areas/area/summary`` (totally-stubby toggle; RFC 9129 inverts FRR's
``no-summary`` sense)
* ``areas/area/default-cost`` (stub / NSSA only)
* ``areas/area/ranges/range`` (list create / destroy), with ``advertise``
and ``cost`` leaves
* ``areas/area/interfaces/interface`` (list create / destroy: assigns an
interface to the area), plus the per-interface leaves
``cost``, ``hello-interval``, ``dead-interval``, ``retransmit-interval``,
``priority``, ``mtu-ignore``, ``transmit-delay``, ``interface-type``,
``passive`` and ``prefix-suppression``
* ``areas/area/interfaces/interface/bfd`` leaves: ``enabled``,
``local-multiplier``, ``desired-min-tx-interval`` and
``required-min-rx-interval``
* ``areas/area/interfaces/interface/static-neighbors/neighbor`` (list create
/ destroy), with ``poll-interval`` and ``priority`` leaves
* ``areas/area/interfaces/interface/authentication/ospfv2-key-chain``

For per-interface BFD, ``bfd/enabled`` controls activation. The multiplier
and interval leaves can be configured while BFD is disabled, but they do not
create or register BFD sessions until ``bfd/enabled=true`` is committed. The
legacy parameterised BFD CLI enqueues that enable leaf before it writes the
parameter leaves.

Out of scope for this slice
^^^^^^^^^^^^^^^^^^^^^^^^^^^

* ``redistribute`` and ``default-information-originate`` are FRR-specific
concepts that RFC 9129 / :rfc:`8349` leave to a separate import / export
mechanism. They stay reachable through the legacy CLI on the
direct-mutation path.
* Per-address overrides (e.g. ``ip ospf cost N A.B.C.D``) have no RFC 9129
counterpart; the YANG model is strictly per-interface. The legacy CLI
with an explicit address argument continues to use direct mutation.
* FRR-specific area NSSA augments (translator-role,
default-information-originate, suppress-fa) are not in the RFC 9129 area
grouping; they remain legacy-CLI-only.
* The ``router ospf [{(1-65535)|vrf NAME}]`` instance creation step is still
CLI-only; YANG operations that target a non-existent instance are
rejected at VALIDATE with a clear error pointing at ``router ospf``.

Examples
^^^^^^^^

Retrieve the OSPFv2 instance from the operational datastore:

.. code-block:: shell

vtysh -c 'show mgmt get-data /ietf-routing:routing/control-plane-protocols/control-plane-protocol[type="ietf-ospf:ospfv2"][name="default"] datastore operational'

Retrieve the merged operational datastore, including the OSPF protocol
entry and the ``ietf-interfaces`` data used by OSPF interface leafrefs:

.. code-block:: shell

vtysh -c 'show mgmt get-data /* datastore operational'

Set the router-id through mgmtd, then commit:

.. code-block:: shell

vtysh -c 'configure terminal file-lock' \
-c 'mgmt set-config /ietf-routing:routing/control-plane-protocols/control-plane-protocol[type="ietf-ospf:ospfv2"][name="default"]/ietf-ospf:ospf/explicit-router-id "10.0.0.1"' \
-c 'mgmt commit apply'

The corresponding ``ospf router-id 10.0.0.1`` legacy CLI command takes the
same path through the northbound; both surfaces converge on the same
committed running configuration.

Interface leafref relaxation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

RFC 9129's per-interface entry keys on a leafref into
``/ietf-interfaces:interfaces/interface/name``. The
``frr-deviations-ietf-routing-ospf`` deviation relaxes this so OSPF config
can be staged ahead of interface plumbing (useful when emitting config from
an external orchestrator). The relaxation removes libyang's referential
check; the NB callbacks restore it themselves, rejecting unknown interface
names at VALIDATE with a clear error.

.. _opaque-lsa:

Opaque LSA
Expand Down
21 changes: 21 additions & 0 deletions lib/bfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1347,3 +1347,24 @@ bool bfd_session_is_admin_down(const struct bfd_session_params *session)
{
return session->bss.state == BSS_ADMIN_DOWN;
}

/*
* Shared ietf-bfd-types loader. See the header comment in lib/bfd.h
* for why backend clients that inherit from `bfd-types:client-cfg-
* parms` need this in their `frr_yang_module_info` table. Wildcard
* features enabled so every if-feature in the module (including
* `client-base-cfg-parms` which gates the multiplier and tx/rx
* intervals) becomes visible in the compiled schema.
*/
static const char *const ietf_bfd_types_features[] = { "*", NULL };

const struct frr_yang_module_info ietf_bfd_types_info = {
.name = "ietf-bfd-types",
.features = (const char **)ietf_bfd_types_features,
.ignore_cfg_cbs = true,
.nodes = {
{
.xpath = NULL,
},
},
};
14 changes: 14 additions & 0 deletions lib/bfd.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,25 @@
#define _ZEBRA_BFD_H

#include "lib/zclient.h"
#include "lib/northbound.h"

#ifdef __cplusplus
extern "C" {
#endif

/*
* Module info for ietf-bfd-types. Backend clients that publish data
* nodes inheriting from `bfd-types:client-cfg-parms` (e.g. OSPFv2 and
* OSPFv3 via RFC 9129's ietf-ospf BFD container) must list this in
* their `frr_yang_module_info` table so libyang enables the foreign
* module's `client-base-cfg-parms` if-feature. Without it the
* inherited multiplier / tx-rx-interval leaves get elided from the
* compiled schema and mgmtd reports "unknown data path" for every
* write but `enabled`. Mirrors the existing `ietf_key_chain_info`
* pattern (lib/keychain.h).
*/
extern const struct frr_yang_module_info ietf_bfd_types_info;

#define BFD_DEF_MIN_RX 300
#define BFD_DEF_MIN_TX 300
#define BFD_DEF_DETECT_MULT 3
Expand Down
22 changes: 22 additions & 0 deletions lib/command.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ struct host host;
/* for vtysh, put together CLI trees only when switching into node */
static bool defer_cli_tree;

/* Direct daemon config-file loads normally preserve legacy per-line commit
* behavior. Daemons with cross-leaf YANG validation can opt in to batching
* their file loads into one northbound transaction.
*/
static bool batch_config_file;

/*
* Returns host.name if any, otherwise
* it returns the system hostname.
Expand Down Expand Up @@ -121,6 +127,11 @@ const char *cmd_release_get(void)
return host.release;
}

void cmd_config_file_batching_set(bool enabled)
{
batch_config_file = enabled;
}

const char *cmd_version_get(void)
{
return host.version;
Expand Down Expand Up @@ -1317,7 +1328,11 @@ int command_config_read_one_line(struct vty *vty,
int config_from_file(struct vty *vty, FILE *fp, unsigned int *line_num)
{
int ret, error_ret = 0;
bool saved_pending_allowed = vty->pending_allowed;

*line_num = 0;
if (batch_config_file)
vty->pending_allowed = true;

while (fgets(vty->buf, VTY_BUFSIZ, fp)) {
++(*line_num);
Expand All @@ -1337,6 +1352,13 @@ int config_from_file(struct vty *vty, FILE *fp, unsigned int *line_num)
error_ret = ret;
}

vty->pending_allowed = saved_pending_allowed;
if (batch_config_file && !saved_pending_allowed) {
ret = nb_cli_pending_commit_check(vty);
if (ret != CMD_SUCCESS)
error_ret = ret;
}

if (error_ret) {
return error_ret;
}
Expand Down
1 change: 1 addition & 0 deletions lib/command.h
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,7 @@ extern int command_config_read_one_line(struct vty *vty,
const struct cmd_element **cmd,
uint32_t line_num, int use_config_node);
extern int config_from_file(struct vty *vty, FILE *fp, unsigned int *line_num);
extern void cmd_config_file_batching_set(bool enabled);
extern enum node_type node_parent(enum node_type node);
/*
* Execute command under the given vty context.
Expand Down
5 changes: 5 additions & 0 deletions lib/libfrr.c
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,11 @@ const char *frr_get_progname(void)
return di ? di->progname : NULL;
}

unsigned short frr_get_instance(void)
{
return di ? di->instance : 0;
}

enum frr_cli_mode frr_get_cli_mode(void)
{
return di ? di->cli_mode : FRR_CLI_CLASSIC;
Expand Down
1 change: 1 addition & 0 deletions lib/libfrr.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ extern FRR_NORETURN void frr_help_exit(int status);

extern struct event_loop *frr_init(void);
extern const char *frr_get_progname(void);
extern unsigned short frr_get_instance(void);
extern enum frr_cli_mode frr_get_cli_mode(void);
extern uint32_t frr_get_fd_limit(void);
extern bool frr_is_startup_fd(int fd);
Expand Down
23 changes: 22 additions & 1 deletion lib/mgmt_be_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "libfrr.h"
#include "lib_errors.h"
#include "mgmt_be_client.h"
#include "mgmt_defines.h"
#include "mgmt_msg.h"
#include "mgmt_msg_native.h"
#include "network.h"
Expand Down Expand Up @@ -1386,6 +1387,9 @@ struct mgmt_be_client *mgmt_be_client_create(const char *client_name,
{
struct mgmt_be_client *client;
char server_path[MAXPATHLEN];
char client_name_inst[MAXPATHLEN];
int ret;
unsigned short instance = frr_get_instance();

if (__be_client)
return NULL;
Expand All @@ -1396,7 +1400,24 @@ struct mgmt_be_client *mgmt_be_client_create(const char *client_name,
/* Only call after frr_init() */
assert(running_config);

client->name = XSTRDUP(MTYPE_MGMTD_BE_CLIENT_NAME, client_name);
if (instance)
ret = snprintf(client_name_inst, sizeof(client_name_inst), "%s-%u", client_name,
instance);
else
ret = snprintf(client_name_inst, sizeof(client_name_inst), "%s", client_name);

if (ret < 0 || ret >= MGMTD_CLIENT_NAME_MAX_LEN) {
if (instance)
flog_err(EC_LIB_SYSTEM_CALL, "%s: backend client name '%s-%u' is too long",
__func__, client_name, instance);
else
flog_err(EC_LIB_SYSTEM_CALL, "%s: backend client name '%s' is too long",
__func__, client_name);
XFREE(MTYPE_MGMTD_BE_CLIENT, client);
__be_client = NULL;
return NULL;
}
client->name = XSTRDUP(MTYPE_MGMTD_BE_CLIENT_NAME, client_name_inst);
client->running_config = running_config;
// client->candidate_config = vty_shared_candidate_config;
if (cbs)
Expand Down
Loading
Loading