On an FRR router, the configuration you type into vtysh is the running configuration, held in the daemons’ memory. FRR 8.1 on Ubuntu 22.04, with a static route added interactively:

What happened next Route still there?
systemctl restart frr no
Added again, then write memory, then restart yes
Then ansible-playbook site.yml no

The first row is the familiar lesson: unsaved changes do not survive a restart. write memory is the fix, and it writes the running configuration to /etc/frr/frr.conf.

The third row is the one that bites in an automated lab or estate. In mine, frr.conf is a template that Ansible renders. write memory replaced that file with FRR’s own rendering of the running config: reordered, a version line added, and the new route included. The next playbook run saw a file that did not match the template, reported changed, put the template back and restarted FRR. The route was gone, and nothing pointed at why: from Ansible’s side, it had simply corrected drift.

Neither tool did anything wrong. There were two sources of truth, and the one that runs on a schedule wins.

Pick one per device:

  • If Ansible owns frr.conf, make every change in the template. Use vtysh to look, or to experiment you intend to throw away, and expect the next run to undo anything else.
  • If the device owns its config, don’t template the whole file. Manage only what has to be consistent, and let write memory be the record.

A quick check for which one you have: run the playbook in check mode (--check --diff) after an interactive change. In my lab it showed the line it would remove, -ip route 192.0.2.0/24 Null0, and left the router alone. If the diff wants to change frr.conf, your change will not last.