diff -pruN 1.1.2-7/debian/changelog 1.1.2-7ubuntu3/debian/changelog
--- 1.1.2-7/debian/changelog	2025-04-16 11:32:34.000000000 +0000
+++ 1.1.2-7ubuntu3/debian/changelog	2025-09-06 14:17:29.000000000 +0000
@@ -1,3 +1,25 @@
+netplan.io (1.1.2-7ubuntu3) questing; urgency=medium
+
+  * Rebuild to include updated RISC-V base ISA RVA23
+
+ -- Heinrich Schuchardt <heinrich.schuchardt@canonical.com>  Sat, 06 Sep 2025 14:17:29 +0000
+
+netplan.io (1.1.2-7ubuntu2) questing; urgency=medium
+
+  * Support non-standard OVS setups, e.g. inside snap environments.
+    - d/p/0012-Allows-non-standard-OVS-setups.patch
+
+ -- Lukas Märdian <slyon@ubuntu.com>  Thu, 31 Jul 2025 12:08:33 +0200
+
+netplan.io (1.1.2-7ubuntu1) questing; urgency=medium
+
+  * Merge with Debian unstable (LP: #2110448). Remaining changes:
+    - d/p/wait-online-dns: Enable waiting for DNS servers.
+      This builds upon systemd#34640, as backported in systemd 257.2-3ubuntu1
+    - d/control: update dependency on systemd 257.2-3ubuntu1
+
+ -- Lukas Märdian <slyon@ubuntu.com>  Mon, 19 May 2025 10:35:14 +0200
+
 netplan.io (1.1.2-7) unstable; urgency=medium
 
   [ Wesley Hershberger ]
@@ -41,11 +63,23 @@ netplan.io (1.1.2-3) unstable; urgency=m
 
   * d/tests: Fix 00test.yaml permissions warnings.
   * d/p/python-limited-stable-api.patch: Gbp refresh.
-  * Do not re-execute generator during daemon-reload (LP: #2090848)
+  * Do not re-execute generator during daemon-reload (LP: 2090848)
     - d/p/lp2090848-0005-generator-Do-not-re-execute-during-daemon-reload.patch
 
  -- Lukas Märdian <slyon@debian.org>  Mon, 03 Mar 2025 11:14:28 +0100
 
+netplan.io (1.1.2-2ubuntu1) plucky; urgency=medium
+
+  * Merge with Debian unstable. Remaining changes:
+    - d/p/wait-online-dns: Enable waiting for DNS servers.
+      This builds upon systemd#34640, as backported in systemd 257.2-3ubuntu
+    - d/control: update dependency on systemd 257.2-3ubuntu1
+  * Drop Changes:
+    - d/gbp.conf: update for Plucky
+      [Not needed for git-ubuntu]
+
+ -- Lukas Märdian <slyon@ubuntu.com>  Wed, 05 Feb 2025 17:54:40 +0100
+
 netplan.io (1.1.2-2) unstable; urgency=medium
 
   * d/t/control: Avoid flaky 'wifi' DEP8 test, instead SKIP if
@@ -59,6 +93,15 @@ netplan.io (1.1.2-2) unstable; urgency=m
 
  -- Lukas Märdian <slyon@debian.org>  Wed, 05 Feb 2025 16:51:55 +0100
 
+netplan.io (1.1.2-1ubuntu1) plucky; urgency=medium
+
+  * d/p/wait-online-dns: Enable waiting for DNS servers.
+    This builds upon systemd#34640, as backported in systemd 257.2-3ubuntu1
+  * d/control: update dependency on systemd 257.2-3ubuntu1
+  * d/gbp.conf: update for Plucky
+
+ -- Lukas Märdian <slyon@ubuntu.com>  Tue, 04 Feb 2025 12:23:09 +0100
+
 netplan.io (1.1.2-1) unstable; urgency=medium
 
   * New upstream release: 1.1.2
diff -pruN 1.1.2-7/debian/control 1.1.2-7ubuntu3/debian/control
--- 1.1.2-7/debian/control	2025-04-10 13:12:05.000000000 +0000
+++ 1.1.2-7ubuntu3/debian/control	2025-07-31 10:02:25.000000000 +0000
@@ -1,5 +1,6 @@
 Source: netplan.io
-Maintainer: Debian Networking Team <team+networking@tracker.debian.org>
+Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
+XSBC-Original-Maintainer: Debian Networking Team <team+networking@tracker.debian.org>
 Uploaders:
  Andrej Shadura <andrewsh@debian.org>,
  Lukas Märdian <slyon@debian.org>,
@@ -52,7 +53,7 @@ Depends:
  netplan-generator,
  python3-netplan,
  python3-yaml,
- systemd (>= 248~),
+ systemd (>= 257.2-3ubuntu1~),
  udev,
 Recommends:
  python3-rich,
@@ -77,7 +78,7 @@ Depends:
  ${shlibs:Depends},
  ${misc:Depends},
  libnetplan1 (= ${binary:Version}),
- systemd (>= 248~),
+ systemd (>= 257.2-3ubuntu1~),
 Suggests:
  network-manager | wpasupplicant,
  openvswitch-switch,
diff -pruN 1.1.2-7/debian/patches/0012-Allows-non-standard-OVS-setups.patch 1.1.2-7ubuntu3/debian/patches/0012-Allows-non-standard-OVS-setups.patch
--- 1.1.2-7/debian/patches/0012-Allows-non-standard-OVS-setups.patch	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.2-7ubuntu3/debian/patches/0012-Allows-non-standard-OVS-setups.patch	2025-07-31 10:05:11.000000000 +0000
@@ -0,0 +1,1257 @@
+From: MJ Ponsonby <mj.ponsonby@canonical.com>
+Date: Mon, 17 Mar 2025 14:57:09 +0000
+Subject: Allows non standard OVS setups
+
+Changes the checks to be based around the availability of the command
+line OVS tools instead of the availability of the service installed
+under apt. This allows netplan to consume OVS when it is provided as part
+of another package such as in snap environments.
+
+This involves minor changes to lots of the OVS code and also modifies
+the unit tests as to handle OVS from both standard and nonstandard setups.
+
+Signed-off-by: MJ Ponsonby <mj.ponsonby@canonical.com>
+
+Origin: upstream, https://github.com/canonical/netplan/commit/4abe2e7dcb8da8994796e702eae4d32ad893c844
+Last-Update: 2025-07-31
+---
+ meson.build                 |   2 +
+ netplan_cli/cli/ovs.py      | 128 +++++++++++++------------
+ src/openvswitch.c           |  98 +++++++++++++++----
+ src/openvswitch.h           |   3 +
+ src/util-internal.h         |  14 ++-
+ src/validation.c            |   3 +-
+ tests/cli/test_get_set.py   |   4 +-
+ tests/generator/base.py     |  16 ++--
+ tests/generator/test_ovs.py | 229 ++++++++++++++++++++++----------------------
+ tests/integration/ovs.py    |   2 +-
+ tests/test_configmanager.py |   4 +-
+ tests/test_libnetplan.py    |   8 +-
+ tests/test_ovs.py           |  42 ++++----
+ 13 files changed, 320 insertions(+), 233 deletions(-)
+
+diff --git a/meson.build b/meson.build
+index 16f8166..41879a7 100644
+--- a/meson.build
++++ b/meson.build
+@@ -32,6 +32,8 @@ find = find_program('find')
+ 
+ add_project_arguments(
+     '-DSBINDIR="' + join_paths(get_option('prefix'), get_option('sbindir')) + '"',
++    '-DPREFIX="' + get_option('prefix') + '"',
++    '-DBINDIR="' + get_option('bindir') + '"',
+     '-D_GNU_SOURCE',
+     '-Wconversion',
+     language: 'c')
+diff --git a/netplan_cli/cli/ovs.py b/netplan_cli/cli/ovs.py
+index a3ada29..ff93a73 100644
+--- a/netplan_cli/cli/ovs.py
++++ b/netplan_cli/cli/ovs.py
+@@ -19,10 +19,7 @@ import logging
+ import os
+ import subprocess
+ 
+-from .utils import systemctl_is_active, systemctl_is_installed
+-
+-OPENVSWITCH_OVS_VSCTL = '/usr/bin/ovs-vsctl'
+-OPENVSWITCH_OVSDB_SERVER_UNIT = 'ovsdb-server.service'
++OPENVSWITCH_OVS_VSCTL = 'ovs-vsctl'
+ # Defaults for non-optional settings, as defined here:
+ # http://www.openvswitch.org/ovs-vswitchd.conf.db.5.pdf
+ DEFAULTS = {
+@@ -46,17 +43,35 @@ class OvsDbServerNotInstalled(Exception):
+     pass
+ 
+ 
++def _ovs_vsctl_path():  # pragma: nocover
++    if os.path.exists('/snap/bin/'+OPENVSWITCH_OVS_VSCTL):
++        return '/snap/bin/'+OPENVSWITCH_OVS_VSCTL
++    else:
++        return '/usr/bin/'+OPENVSWITCH_OVS_VSCTL
++
++
++OVS_VSCTL_PATH = _ovs_vsctl_path()
++
++
++def _ovs_installed():  # pragma: nocover
++    return os.path.exists(OVS_VSCTL_PATH)
++
++
++def _ovs_active():  # pragma: nocover
++    return subprocess.call([OVS_VSCTL_PATH, 'show'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) == 0
++
++
+ def _del_col(type, iface, column, value):
+     """Cleanup values from a column (i.e. "column=value")"""
+     default = DEFAULTS.get(column)
+     if default is None:
+         # removes the exact value only if it was set by netplan
+-        cmd = [OPENVSWITCH_OVS_VSCTL, 'remove', type, iface, column, value]
++        cmd = [OVS_VSCTL_PATH, 'remove', type, iface, column, value]
+         logging.debug('Running: %s' % ' '.join(cmd))
+         subprocess.check_call(cmd)
+     elif default and default != value:
+         # reset to default, if its not the default already
+-        cmd = [OPENVSWITCH_OVS_VSCTL, 'set', type, iface, '%s=%s' % (column, default)]
++        cmd = [OVS_VSCTL_PATH, 'set', type, iface, '%s=%s' % (column, default)]
+         logging.debug('Running: %s' % ' '.join(cmd))
+         subprocess.check_call(cmd)
+ 
+@@ -64,7 +79,7 @@ def _del_col(type, iface, column, value):
+ def _del_dict(type, iface, column, key, value):
+     """Cleanup values from a dictionary (i.e. "column:key=value")"""
+     # removes the exact value only if it was set by netplan
+-    cmd = [OPENVSWITCH_OVS_VSCTL, 'remove', type, iface, column, '%s=\"%s\"' % (key, value)]
++    cmd = [OVS_VSCTL_PATH, 'remove', type, iface, column, '%s=\"%s\"' % (key, value)]
+     logging.debug('Running: %s' % ' '.join(cmd))
+     subprocess.check_call(cmd)
+ 
+@@ -76,8 +91,8 @@ def _del_global(type, iface, key, value):
+         iface = None
+ 
+     if del_cmd:
+-        args_get = [OPENVSWITCH_OVS_VSCTL, get_cmd]
+-        args_del = [OPENVSWITCH_OVS_VSCTL, del_cmd]
++        args_get = [OVS_VSCTL_PATH, get_cmd]
++        args_del = [OVS_VSCTL_PATH, del_cmd]
+         if iface:
+             args_get.append(iface)
+             args_del.append(iface)
+@@ -112,7 +127,7 @@ def clear_setting(type, iface, setting, value):
+     else:
+         _del_col(type, iface, split[1], value)
+     # Cleanup the tag itself (i.e. "netplan/column[/key]")
+-    subprocess.check_call([OPENVSWITCH_OVS_VSCTL, 'remove', type, iface, 'external-ids', setting])
++    subprocess.check_call([OVS_VSCTL_PATH, 'remove', type, iface, 'external-ids', setting])
+ 
+ 
+ def is_ovs_interface(iface, np_interface_dict):
+@@ -129,11 +144,11 @@ def apply_ovs_cleanup(config_manager, ovs_old, ovs_current):  # pragma: nocover
+     Also filter for individual settings tagged netplan/<column>[/<key]=value
+     in external-ids and clear them if they have been set by netplan.
+     """
+-    if not systemctl_is_installed(OPENVSWITCH_OVSDB_SERVER_UNIT):
+-        raise OvsDbServerNotInstalled("Cannot apply OVS cleanup: %s is 'not-found'" %
+-                                      OPENVSWITCH_OVSDB_SERVER_UNIT)
+-    if not systemctl_is_active(OPENVSWITCH_OVSDB_SERVER_UNIT):
+-        raise OvsDbServerNotRunning('{} is not running'.format(OPENVSWITCH_OVSDB_SERVER_UNIT))
++    if not _ovs_installed():
++        raise OvsDbServerNotInstalled("Cannot apply OpenvSwitch cleanup: ovs-vsctl is 'not-found'")
++
++    if not _ovs_active():
++        raise OvsDbServerNotRunning('OpenvSwitch database is not running')
+ 
+     config_manager.parse()
+     ovs_ifaces = set()
+@@ -144,47 +159,42 @@ def apply_ovs_cleanup(config_manager, ovs_old, ovs_current):  # pragma: nocover
+     # Tear down old OVS interfaces, not defined in the current config.
+     # Use 'del-br' on the Interface table, to delete any netplan created VLAN fake bridges.
+     # Use 'del-bond-iface' on the Interface table, to delete netplan created patch port interfaces
+-    if os.path.isfile(OPENVSWITCH_OVS_VSCTL):
+-        # Step 1: Delete all interfaces, which are not part of the current OVS config
+-        for t in (('Port', 'del-port'), ('Bridge', 'del-br'), ('Interface', 'del-br')):
+-            out = subprocess.check_output([OPENVSWITCH_OVS_VSCTL, '--columns=name,external-ids',
+-                                           '-f', 'csv', '-d', 'bare', '--no-headings', 'list', t[0]],
+-                                          text=True)
+-            for line in out.splitlines():
+-                if 'netplan=true' in line:
+-                    iface = line.split(',')[0]
+-                    # Skip cleanup if this OVS interface is part of the current netplan OVS config
+-                    if iface in ovs_ifaces:
+-                        continue
+-                    if t[0] == 'Interface' and subprocess.run([OPENVSWITCH_OVS_VSCTL, 'br-exists', iface]).returncode > 0:
+-                        subprocess.check_call([OPENVSWITCH_OVS_VSCTL, '--if-exists', 'del-bond-iface', iface])
+-                    else:
+-                        subprocess.check_call([OPENVSWITCH_OVS_VSCTL, '--if-exists', t[1], iface])
+-
+-        # Step 2: Clean up the settings of the remaining interfaces
+-        for t in ('Port', 'Bridge', 'Interface', 'Open_vSwitch', 'Controller'):
+-            cols = 'name,external-ids'
+-            if t == 'Open_vSwitch':
+-                cols = 'external-ids'
+-            elif t == 'Controller':
+-                cols = '_uuid,external-ids'  # handle _uuid as if it would be the iface 'name'
+-            out = subprocess.check_output([OPENVSWITCH_OVS_VSCTL, '--columns=%s' % cols,
+-                                           '-f', 'csv', '-d', 'bare', '--no-headings', 'list', t],
+-                                          text=True)
+-            for line in out.splitlines():
+-                if 'netplan/' in line:
+-                    iface = '.'
+-                    extids = line
+-                    if t != 'Open_vSwitch':
+-                        iface, extids = line.split(',', 1)
+-                    # Check each line (interface) if it contains any netplan tagged settings, e.g.:
+-                    # ovs0,"iface-id=myhostname netplan=true netplan/external-ids/iface-id=myhostname"
+-                    # ovs1,"netplan=true netplan/global/set-fail-mode=standalone netplan/mcast_snooping_enable=false"
+-                    for entry in extids.strip('"').split(' '):
+-                        if entry.startswith('netplan/') and '=' in entry:
+-                            setting, val = entry.split('=', 1)
+-                            clear_setting(t, iface, setting, val)
+-
+-    # Show the warning only if we are or have been working with OVS definitions
+-    elif ovs_old or ovs_current:
+-        logging.warning('ovs-vsctl is missing, cannot tear down old OpenVSwitch interfaces')
++    # Step 1: Delete all interfaces, which are not part of the current OVS config
++    for t in (('Port', 'del-port'), ('Bridge', 'del-br'), ('Interface', 'del-br')):
++        out = subprocess.check_output([OVS_VSCTL_PATH, '--columns=name,external-ids',
++                                       '-f', 'csv', '-d', 'bare', '--no-headings', 'list', t[0]],
++                                      text=True)
++        for line in out.splitlines():
++            if 'netplan=true' in line:
++                iface = line.split(',')[0]
++                # Skip cleanup if this OVS interface is part of the current netplan OVS config
++                if iface in ovs_ifaces:
++                    continue
++                if t[0] == 'Interface' and subprocess.run([OVS_VSCTL_PATH, 'br-exists', iface]).returncode > 0:
++                    subprocess.check_call([OVS_VSCTL_PATH, '--if-exists', 'del-bond-iface', iface])
++                else:
++                    subprocess.check_call([OVS_VSCTL_PATH, '--if-exists', t[1], iface])
++
++    # Step 2: Clean up the settings of the remaining interfaces
++    for t in ('Port', 'Bridge', 'Interface', 'Open_vSwitch', 'Controller'):
++        cols = 'name,external-ids'
++        if t == 'Open_vSwitch':
++            cols = 'external-ids'
++        elif t == 'Controller':
++            cols = '_uuid,external-ids'  # handle _uuid as if it would be the iface 'name'
++        out = subprocess.check_output([OVS_VSCTL_PATH, '--columns=%s' % cols,
++                                       '-f', 'csv', '-d', 'bare', '--no-headings', 'list', t],
++                                      text=True)
++        for line in out.splitlines():
++            if 'netplan/' in line:
++                iface = '.'
++                extids = line
++                if t != 'Open_vSwitch':
++                    iface, extids = line.split(',', 1)
++                # Check each line (interface) if it contains any netplan tagged settings, e.g.:
++                # ovs0,"iface-id=myhostname netplan=true netplan/external-ids/iface-id=myhostname"
++                # ovs1,"netplan=true netplan/global/set-fail-mode=standalone netplan/mcast_snooping_enable=false"
++                for entry in extids.strip('"').split(' '):
++                    if entry.startswith('netplan/') and '=' in entry:
++                        setting, val = entry.split('=', 1)
++                        clear_setting(t, iface, setting, val)
+diff --git a/src/openvswitch.c b/src/openvswitch.c
+index 0567252..db45394 100644
+--- a/src/openvswitch.c
++++ b/src/openvswitch.c
+@@ -29,6 +29,35 @@
+ #include "util.h"
+ #include "util-internal.h"
+ 
++#define OPENVSWITCH_OVS_VSCTL "ovs-vsctl"
++
++static GString *netplan_openvswitch_ovs_vsctl_path = NULL;
++
++// LCOV_EXCL_START
++void _prepare_netplan_openvswitch_ovs_vsctl_path__(void)
++{
++    g_assert(netplan_openvswitch_ovs_vsctl_path == NULL);
++    netplan_openvswitch_ovs_vsctl_path = g_string_new(NULL);
++
++    if (g_file_test(SNAPBINDIR "/" OPENVSWITCH_OVS_VSCTL, G_FILE_TEST_EXISTS)) {
++        g_debug("using ovs-vsctl at %s/%s", SNAPBINDIR, OPENVSWITCH_OVS_VSCTL);
++        g_string_printf(netplan_openvswitch_ovs_vsctl_path, "%s/%s", SNAPBINDIR, OPENVSWITCH_OVS_VSCTL);
++    } else {
++        g_debug("using ovs-vsctl at %s/%s/%s", PREFIX, BINDIR, OPENVSWITCH_OVS_VSCTL);
++        g_string_printf(netplan_openvswitch_ovs_vsctl_path, "%s/%s/%s", PREFIX, BINDIR, OPENVSWITCH_OVS_VSCTL);
++    }
++}
++
++const char *_get_netplan_openvswitch_ovs_vsctl_path()
++{
++    if (!netplan_openvswitch_ovs_vsctl_path) {
++        _prepare_netplan_openvswitch_ovs_vsctl_path__();
++    }
++    return netplan_openvswitch_ovs_vsctl_path->str;
++}
++// LCOV_EXCL_STOP
++
++
+ STATIC gboolean
+ write_ovs_systemd_unit(const char* id, const GString* cmds, const char* rootdir, gboolean physical, gboolean cleanup, const char* dependency, GError** error)
+ {
+@@ -51,7 +80,8 @@ write_ovs_systemd_unit(const char* id, const GString* cmds, const char* rootdir,
+         g_string_append_printf(s, "After=netplan-ovs-cleanup.service\n");
+     } else {
+         /* The netplan-ovs-cleanup unit shall not run on systems where Open vSwitch is not installed. */
+-        g_string_append(s, "ConditionFileIsExecutable=" OPENVSWITCH_OVS_VSCTL "\n");
++        g_string_append_printf(s, "ConditionFileIsExecutable=%s\n",
++                               _get_netplan_openvswitch_ovs_vsctl_path());
+     }
+     g_string_append(s, "Before=network.target\nWants=network.target\n");
+     if (dependency) {
+@@ -138,7 +168,8 @@ write_ovs_tag_setting(const gchar* id, const char* type, const char* col, const
+     if (key)
+         g_string_append_printf(s, "/%s", key);
+     g_string_append_printf(s, "=\"%s\"", clean_value);
+-    append_systemd_cmd(cmds, OPENVSWITCH_OVS_VSCTL " set %s %s %s", type, id, s->str);
++    append_systemd_cmd(cmds, "%s set %s %s %s",
++                       _get_netplan_openvswitch_ovs_vsctl_path(), type, id, s->str);
+     g_string_free(s, TRUE);
+ }
+ 
+@@ -153,8 +184,9 @@ write_ovs_additional_data(GHashTable *data, const char* type, const gchar* id, G
+     while (g_hash_table_iter_next(&iter, (gpointer) &key, (gpointer) &value)) {
+         /* XXX: we need to check what happens when an invalid key=value pair
+             gets supplied here. We might want to handle this somehow. */
+-        append_systemd_cmd(cmds, OPENVSWITCH_OVS_VSCTL " set %s %s %s:%s=\"%s\"",
+-                           type, id, setting, key, value);
++        append_systemd_cmd(cmds, "%s set %s %s %s:%s=\"%s\"",
++                           _get_netplan_openvswitch_ovs_vsctl_path(), type, id, setting,
++                           key, value);
+         write_ovs_tag_setting(id, type, setting, key, value, cmds);
+     }
+ }
+@@ -186,8 +218,10 @@ write_ovs_bond_interfaces(const NetplanState* np_state, const NetplanNetDefiniti
+         return NULL;
+     }
+ 
+-    s = g_string_new(OPENVSWITCH_OVS_VSCTL " --may-exist add-bond");
+-    g_string_append_printf(s, " %s %s", def->bridge, def->id);
++
++    s = g_string_new(NULL);
++    g_string_printf(s, "%s --may-exist add-bond %s %s",
++                    _get_netplan_openvswitch_ovs_vsctl_path(), def->bridge, def->id);
+ 
+     g_hash_table_iter_init(&iter, np_state->netdefs);
+     while (g_hash_table_iter_next(&iter, (gpointer) &key, (gpointer) &tmp_nd)) {
+@@ -213,8 +247,8 @@ STATIC void
+ write_ovs_tag_netplan(const gchar* id, const char* type, GString* cmds)
+ {
+     /* Mark this bridge/port/interface as created by netplan */
+-    append_systemd_cmd(cmds, OPENVSWITCH_OVS_VSCTL " set %s %s external-ids:netplan=\"true\"",
+-                       type, id);
++    append_systemd_cmd(cmds, "%s set %s %s external-ids:netplan=\"true\"",
++                       _get_netplan_openvswitch_ovs_vsctl_path(), type, id);
+ }
+ 
+ STATIC gboolean
+@@ -227,7 +261,8 @@ write_ovs_bond_mode(const NetplanNetDefinition* def, GString* cmds, GError** err
+         !strcmp(def->bond_params.mode, "balance-tcp") ||
+         !strcmp(def->bond_params.mode, "balance-slb")) {
+         value = def->bond_params.mode;
+-        append_systemd_cmd(cmds, OPENVSWITCH_OVS_VSCTL " set Port %s bond_mode=%s", def->id, value);
++        append_systemd_cmd(cmds, "%s set Port %s bond_mode=%s",
++                           _get_netplan_openvswitch_ovs_vsctl_path(), def->id, value);
+         write_ovs_tag_setting(def->id, "Port", "bond_mode", NULL, value, cmds);
+     } else {
+         g_set_error(error, NETPLAN_BACKEND_ERROR, NETPLAN_ERROR_VALIDATION, "%s: bond mode '%s' not supported by Open vSwitch\n",
+@@ -244,7 +279,8 @@ write_ovs_bridge_interfaces(const NetplanState* np_state, const NetplanNetDefini
+     GHashTableIter iter;
+     gchar* key;
+ 
+-    append_systemd_cmd(cmds, OPENVSWITCH_OVS_VSCTL " --may-exist add-br %s", def->id);
++    append_systemd_cmd(cmds, "%s --may-exist add-br %s",
++                       _get_netplan_openvswitch_ovs_vsctl_path(), def->id);
+ 
+     g_hash_table_iter_init(&iter, np_state->netdefs);
+     while (g_hash_table_iter_next(&iter, (gpointer) &key, (gpointer) &tmp_nd)) {
+@@ -254,8 +290,9 @@ write_ovs_bridge_interfaces(const NetplanState* np_state, const NetplanNetDefini
+             GString * patch_ports = g_string_new("");
+             if (tmp_nd->type == NETPLAN_DEF_TYPE_PORT)
+                 setup_patch_port(patch_ports, tmp_nd);
+-            append_systemd_cmd(cmds, OPENVSWITCH_OVS_VSCTL " --may-exist add-port %s %s%s",
+-                               def->id, tmp_nd->id, patch_ports->str);
++            append_systemd_cmd(cmds, "%s --may-exist add-port %s %s%s",
++                                _get_netplan_openvswitch_ovs_vsctl_path(), def->id,
++                                tmp_nd->id, patch_ports->str);
+             g_string_free(patch_ports, TRUE);
+         }
+     }
+@@ -270,7 +307,8 @@ write_ovs_protocols(const NetplanOVSSettings* ovs_settings, const gchar* bridge,
+     for (unsigned i = 1; i < ovs_settings->protocols->len; ++i)
+         g_string_append_printf(s, ",%s", g_array_index(ovs_settings->protocols, char*, i));
+ 
+-    append_systemd_cmd(cmds, OPENVSWITCH_OVS_VSCTL " set Bridge %s protocols=%s", bridge, s->str);
++    append_systemd_cmd(cmds, "%s set Bridge %s protocols=%s",
++                       _get_netplan_openvswitch_ovs_vsctl_path(), bridge, s->str);
+     write_ovs_tag_setting(bridge, "Bridge", "protocols", NULL, s->str, cmds);
+     g_string_free(s, TRUE);
+ }
+@@ -313,7 +351,8 @@ write_ovs_bridge_controller_targets(const NetplanOVSSettings* settings, const Ne
+     g_assert(s->len < G_MAXSSIZE);
+     g_string_erase(s, (gssize)s->len-1, 1);
+ 
+-    append_systemd_cmd(cmds, OPENVSWITCH_OVS_VSCTL " set-controller %s %s", bridge, s->str);
++    append_systemd_cmd(cmds, "%s set-controller %s %s",
++                       _get_netplan_openvswitch_ovs_vsctl_path(), bridge, s->str);
+     write_ovs_tag_setting(bridge, "Bridge", "global", "set-controller", s->str, cmds);
+ 
+ cleanup:
+@@ -353,7 +392,9 @@ _netplan_netdef_write_ovs(const NetplanState* np_state, const NetplanNetDefiniti
+                 write_ovs_tag_netplan(def->id, type, cmds);
+                 /* Set LACP mode, default to "off" */
+                 value = def->ovs_settings.lacp? def->ovs_settings.lacp : "off";
+-                append_systemd_cmd(cmds, OPENVSWITCH_OVS_VSCTL " set Port %s lacp=%s", def->id, value);
++                append_systemd_cmd(cmds, "%s set Port %s lacp=%s",
++                                   _get_netplan_openvswitch_ovs_vsctl_path(),
++                                   def->id, value);
+                 write_ovs_tag_setting(def->id, type, "lacp", NULL, value, cmds);
+                 if (def->bond_params.mode && !write_ovs_bond_mode(def, cmds, error))
+                     return FALSE;
+@@ -364,15 +405,23 @@ _netplan_netdef_write_ovs(const NetplanState* np_state, const NetplanNetDefiniti
+                 write_ovs_tag_netplan(def->id, type, cmds);
+                 /* Set fail-mode, default to "standalone" */
+                 value = def->ovs_settings.fail_mode? def->ovs_settings.fail_mode : "standalone";
+-                append_systemd_cmd(cmds, OPENVSWITCH_OVS_VSCTL " set-fail-mode %s %s", def->id, value);
++                append_systemd_cmd(cmds, "%s set-fail-mode %s %s",
++                                   _get_netplan_openvswitch_ovs_vsctl_path(),
++                                   def->id, value);
+                 write_ovs_tag_setting(def->id, type, "global", "set-fail-mode", value, cmds);
+                 /* Enable/disable mcast-snooping */ 
+                 value = def->ovs_settings.mcast_snooping? "true" : "false";
+-                append_systemd_cmd(cmds, OPENVSWITCH_OVS_VSCTL " set Bridge %s mcast_snooping_enable=%s", def->id, value);
++                append_systemd_cmd(cmds,
++                                   "%s set Bridge %s mcast_snooping_enable=%s",
++                                   _get_netplan_openvswitch_ovs_vsctl_path(),
++                                   def->id, value);
+                 write_ovs_tag_setting(def->id, type, "mcast_snooping_enable", NULL, value, cmds);
+                 /* Enable/disable rstp */
+                 value = def->ovs_settings.rstp? "true" : "false";
+-                append_systemd_cmd(cmds, OPENVSWITCH_OVS_VSCTL " set Bridge %s rstp_enable=%s", def->id, value);
++                append_systemd_cmd(cmds,
++                                   "%s set Bridge %s rstp_enable=%s",
++                                   _get_netplan_openvswitch_ovs_vsctl_path(),
++                                   def->id, value);
+                 write_ovs_tag_setting(def->id, type, "rstp_enable", NULL, value, cmds);
+                 /* Set protocols */
+                 if (def->ovs_settings.protocols && def->ovs_settings.protocols->len > 0)
+@@ -387,7 +436,11 @@ _netplan_netdef_write_ovs(const NetplanState* np_state, const NetplanNetDefiniti
+                     /* Set controller connection mode, only applicable if at least one controller target address was set */
+                     if (def->ovs_settings.controller.connection_mode) {
+                         value = def->ovs_settings.controller.connection_mode;
+-                        append_systemd_cmd(cmds, OPENVSWITCH_OVS_VSCTL " set Controller %s connection-mode=%s", def->id, value);
++                        append_systemd_cmd(cmds,
++                                           "%s set Controller %s "
++                                           "connection-mode=%s",
++                                           _get_netplan_openvswitch_ovs_vsctl_path(),
++                                           def->id, value);
+                         write_ovs_tag_setting(def->id, "Controller", "connection-mode", NULL, value, cmds);
+                     }
+                 }
+@@ -413,7 +466,9 @@ _netplan_netdef_write_ovs(const NetplanState* np_state, const NetplanNetDefiniti
+                 g_assert(def->vlan_link != NULL);
+                 dependency = def->vlan_link->id;
+                 /* Create a fake VLAN bridge */
+-                append_systemd_cmd(cmds, OPENVSWITCH_OVS_VSCTL " --may-exist add-br %s %s %i", def->id, def->vlan_link->id, def->vlan_id)
++                append_systemd_cmd(cmds, "%s --may-exist add-br %s %s %i",
++                                   _get_netplan_openvswitch_ovs_vsctl_path(),
++                                   def->id, def->vlan_link->id, def->vlan_id)
+                 write_ovs_tag_netplan(def->id, type, cmds);
+                 break;
+ 
+@@ -490,7 +545,8 @@ netplan_state_finish_ovs_write(const NetplanState* np_state, const char* rootdir
+                         settings->ssl.client_key,
+                         settings->ssl.client_certificate,
+                         settings->ssl.ca_certificate);
+-        append_systemd_cmd(cmds, OPENVSWITCH_OVS_VSCTL " set-ssl %s", value->str);
++        append_systemd_cmd(cmds, "%s set-ssl %s",
++                           _get_netplan_openvswitch_ovs_vsctl_path(), value->str);
+         write_ovs_tag_setting(".", "open_vswitch", "global", "set-ssl", value->str, cmds);
+         g_string_free(value, TRUE);
+     }
+diff --git a/src/openvswitch.h b/src/openvswitch.h
+index 4d53ac3..2d2ae02 100644
+--- a/src/openvswitch.h
++++ b/src/openvswitch.h
+@@ -29,3 +29,6 @@ _netplan_netdef_write_ovs(
+ 
+ NETPLAN_INTERNAL gboolean
+ _netplan_ovs_cleanup(const char* rootdir);
++
++const char *
++_get_netplan_openvswitch_ovs_vsctl_path(void);
+diff --git a/src/util-internal.h b/src/util-internal.h
+index bfc4dbe..d3e230a 100644
+--- a/src/util-internal.h
++++ b/src/util-internal.h
+@@ -24,6 +24,18 @@
+ #include <glib.h>
+ #include "netplan.h"
+ 
++#ifndef PREFIX
++#define PREFIX "/usr"
++#endif
++
++#ifndef BINDIR
++#define BINDIR "bin"
++#endif
++
++#ifndef SNAPBINDIR
++#define SNAPBINDIR "/snap/bin"
++#endif
++
+ #define SET_OPT_OUT_PTR(ptr,val) { if (ptr) *ptr = val; }
+ 
+ #define __unused __attribute__((unused))
+@@ -64,8 +76,6 @@ wifi_get_freq5(guint channel);
+ gchar*
+ systemd_escape(char* string);
+ 
+-#define OPENVSWITCH_OVS_VSCTL "/usr/bin/ovs-vsctl"
+-
+ void
+ mark_data_as_dirty(NetplanParser* npp, const void* data_ptr);
+ 
+diff --git a/src/validation.c b/src/validation.c
+index 78e0bf9..14f906b 100644
+--- a/src/validation.c
++++ b/src/validation.c
+@@ -30,6 +30,7 @@
+ #include "error.h"
+ #include "util-internal.h"
+ #include "validation.h"
++#include "openvswitch.h"
+ 
+ /* Check coherence for address types */
+ 
+@@ -441,7 +442,7 @@ validate_netdef_grammar(const NetplanParser* npp, NetplanNetDefinition* nd, GErr
+ 
+     if (nd->backend == NETPLAN_BACKEND_OVS) {
+         // LCOV_EXCL_START
+-        if (!g_file_test(OPENVSWITCH_OVS_VSCTL, G_FILE_TEST_EXISTS)) {
++        if (!g_file_test(_get_netplan_openvswitch_ovs_vsctl_path(), G_FILE_TEST_EXISTS)) {
+             /* Tested via integration test */
+             return yaml_error(npp, NULL, error, "%s: The 'ovs-vsctl' tool is required to setup OpenVSwitch interfaces.", nd->id);
+         }
+diff --git a/tests/cli/test_get_set.py b/tests/cli/test_get_set.py
+index 6d8b93a..a878c61 100644
+--- a/tests/cli/test_get_set.py
++++ b/tests/cli/test_get_set.py
+@@ -26,7 +26,7 @@ import glob
+ import yaml
+ 
+ from netplan_cli.cli.commands.set import FALLBACK_FILENAME
+-from netplan_cli.cli.ovs import OPENVSWITCH_OVS_VSCTL
++from netplan_cli.cli.ovs import OVS_VSCTL_PATH
+ 
+ from netplan import NetplanException
+ from tests.test_utils import call_cli
+@@ -520,7 +520,7 @@ class TestSet(unittest.TestCase):
+         self.assertNotIn('eno2', out['network']['bridges']['br0']['parameters']['port-priority'])
+         self.assertEqual(14, out['network']['bridges']['br0']['parameters']['port-priority']['eno1'])
+ 
+-    @unittest.skipIf(not os.path.exists(OPENVSWITCH_OVS_VSCTL),
++    @unittest.skipIf(not os.path.exists(OVS_VSCTL_PATH),
+                      'OpenVSwitch not installed')
+     def test_set_delete_ovs_other_config(self):
+         with open(self.path, 'w') as f:
+diff --git a/tests/generator/base.py b/tests/generator/base.py
+index 424e168..9bd4760 100644
+--- a/tests/generator/base.py
++++ b/tests/generator/base.py
+@@ -35,6 +35,7 @@ import re
+ from io import StringIO
+ 
+ import netplan
++from netplan_cli.cli.ovs import OVS_VSCTL_PATH
+ 
+ exe_generate = os.environ.get('NETPLAN_GENERATE_PATH',
+                               os.path.join(os.path.dirname(os.path.dirname(
+@@ -65,14 +66,15 @@ Wants=ovsdb-server.service\nAfter=ovsdb-server.service\n'
+ OVS_PHYSICAL = _OVS_BASE + 'Requires=sys-subsystem-net-devices-%(iface)s.device\nAfter=sys-subsystem-net-devices-%(iface)s\
+ .device\nAfter=netplan-ovs-cleanup.service\nBefore=network.target\nWants=network.target\n%(extra)s'
+ OVS_VIRTUAL = _OVS_BASE + 'After=netplan-ovs-cleanup.service\nBefore=network.target\nWants=network.target\n%(extra)s'
+-OVS_BR_DEFAULT = 'ExecStart=/usr/bin/ovs-vsctl set Bridge %(iface)s external-ids:netplan=\"true\"\nExecStart=/usr/bin/ovs-vsctl \
+-set-fail-mode %(iface)s standalone\nExecStart=/usr/bin/ovs-vsctl set Bridge %(iface)s external-ids:netplan/global/set-fail-mode=\
+-\"standalone\"\nExecStart=/usr/bin/ovs-vsctl set Bridge %(iface)s mcast_snooping_enable=false\nExecStart=/usr/bin/ovs-vsctl set \
+-Bridge %(iface)s external-ids:netplan/mcast_snooping_enable="false"\nExecStart=/usr/bin/ovs-vsctl set Bridge %(iface)s \
+-rstp_enable=false\nExecStart=/usr/bin/ovs-vsctl set Bridge %(iface)s external-ids:netplan/rstp_enable=\"false\"\n'
++OVS_BR_DEFAULT = 'ExecStart=' + OVS_VSCTL_PATH + ' set Bridge %(iface)s external-ids:netplan=\"true\"\n\
++ExecStart=' + OVS_VSCTL_PATH + ' set-fail-mode %(iface)s standalone\nExecStart=' + OVS_VSCTL_PATH + ' set Bridge %(iface)s \
++external-ids:netplan/global/set-fail-mode=\"standalone\"\nExecStart=' + OVS_VSCTL_PATH + ' set Bridge %(iface)s \
++mcast_snooping_enable=false\nExecStart=' + OVS_VSCTL_PATH + ' set Bridge %(iface)s external-ids:netplan/mcast_snooping_enable=\
++"false"\nExecStart=' + OVS_VSCTL_PATH + ' set Bridge %(iface)s rstp_enable=false\nExecStart=' + OVS_VSCTL_PATH + ' \
++set Bridge %(iface)s external-ids:netplan/rstp_enable=\"false\"\n'
+ OVS_BR_EMPTY = _OVS_BASE + 'After=netplan-ovs-cleanup.service\nBefore=network.target\nWants=network.target\n\n[Service]\n\
+-Type=oneshot\nTimeoutStartSec=10s\nExecStart=/usr/bin/ovs-vsctl --may-exist add-br %(iface)s\n' + OVS_BR_DEFAULT
+-OVS_CLEANUP = _OVS_BASE + 'ConditionFileIsExecutable=/usr/bin/ovs-vsctl\nBefore=network.target\nWants=network.target\n\n\
++Type=oneshot\nTimeoutStartSec=10s\nExecStart=' + OVS_VSCTL_PATH + ' --may-exist add-br %(iface)s\n' + OVS_BR_DEFAULT
++OVS_CLEANUP = _OVS_BASE + 'ConditionFileIsExecutable=' + OVS_VSCTL_PATH + '\nBefore=network.target\nWants=network.target\n\n\
+ [Service]\nType=oneshot\nTimeoutStartSec=10s\nStartLimitBurst=0\nExecStart=/usr/sbin/netplan apply --only-ovs-cleanup\n'
+ UDEV_MAC_RULE = 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="%s", ATTR{address}=="%s", NAME="%s"\n'
+ UDEV_NO_MAC_RULE = 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="%s", NAME="%s"\n'
+diff --git a/tests/generator/test_ovs.py b/tests/generator/test_ovs.py
+index a3a422e..98f99c7 100644
+--- a/tests/generator/test_ovs.py
++++ b/tests/generator/test_ovs.py
+@@ -20,14 +20,14 @@
+ import os
+ import unittest
+ 
+-from netplan_cli.cli.ovs import OPENVSWITCH_OVS_VSCTL
++from netplan_cli.cli.ovs import OVS_VSCTL_PATH
+ from .base import TestBase, ND_EMPTY, ND_WITHIP, ND_DHCP4, ND_DHCP6, \
+                             OVS_PHYSICAL, OVS_VIRTUAL, \
+                             OVS_BR_EMPTY, OVS_BR_DEFAULT, \
+                             OVS_CLEANUP
+ 
+ 
+-@unittest.skipIf(not os.path.exists(OPENVSWITCH_OVS_VSCTL),
++@unittest.skipIf(not os.path.exists(OVS_VSCTL_PATH),
+                  'OpenVSwitch not installed')
+ class TestOpenVSwitch(TestBase):
+     '''OVS output'''
+@@ -56,9 +56,9 @@ class TestOpenVSwitch(TestBase):
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-br ovs0
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-port ovs0 eth1
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-port ovs0 eth0
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-br ovs0
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-port ovs0 eth1
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-port ovs0 eth0
+ ''' + OVS_BR_DEFAULT % {'iface': 'ovs0'}},
+                          'eth0.service': OVS_PHYSICAL % {'iface': 'eth0', 'extra': '''\
+ Requires=netplan-ovs-ovs0.service
+@@ -67,10 +67,10 @@ After=netplan-ovs-ovs0.service
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl set Interface eth0 external-ids:iface-id="myhostname"
+-ExecStart=/usr/bin/ovs-vsctl set Interface eth0 external-ids:netplan/external-ids/iface-id="myhostname"
+-ExecStart=/usr/bin/ovs-vsctl set Interface eth0 other-config:disable-in-band="true"
+-ExecStart=/usr/bin/ovs-vsctl set Interface eth0 external-ids:netplan/other-config/disable-in-band="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Interface eth0 external-ids:iface-id="myhostname"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Interface eth0 external-ids:netplan/external-ids/iface-id="myhostname"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Interface eth0 other-config:disable-in-band="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Interface eth0 external-ids:netplan/other-config/disable-in-band="true"
+ '''},
+                          'eth1.service': OVS_PHYSICAL % {'iface': 'eth1', 'extra': '''\
+ Requires=netplan-ovs-ovs0.service
+@@ -79,8 +79,8 @@ After=netplan-ovs-ovs0.service
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl set Interface eth1 other-config:disable-in-band="false"
+-ExecStart=/usr/bin/ovs-vsctl set Interface eth1 external-ids:netplan/other-config/disable-in-band="false"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Interface eth1 other-config:disable-in-band="false"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Interface eth1 external-ids:netplan/other-config/disable-in-band="false"
+ '''},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+         # Confirm that the networkd config is still sane
+@@ -118,10 +118,10 @@ ExecStart=/usr/bin/ovs-vsctl set Interface eth1 external-ids:netplan/other-confi
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl set open_vswitch . external-ids:iface-id="myhostname"
+-ExecStart=/usr/bin/ovs-vsctl set open_vswitch . external-ids:netplan/external-ids/iface-id="myhostname"
+-ExecStart=/usr/bin/ovs-vsctl set open_vswitch . other-config:disable-in-band="true"
+-ExecStart=/usr/bin/ovs-vsctl set open_vswitch . external-ids:netplan/other-config/disable-in-band="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set open_vswitch . external-ids:iface-id="myhostname"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set open_vswitch . external-ids:netplan/external-ids/iface-id="myhostname"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set open_vswitch . other-config:disable-in-band="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set open_vswitch . external-ids:netplan/other-config/disable-in-band="true"
+ '''},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+         # Confirm that the networkd config is still sane
+@@ -140,10 +140,10 @@ ExecStart=/usr/bin/ovs-vsctl set open_vswitch . external-ids:netplan/other-confi
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-br ovs0
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-br ovs0
+ ''' + OVS_BR_DEFAULT % {'iface': 'ovs0'} + '''\
+-ExecStart=/usr/bin/ovs-vsctl set Bridge ovs0 protocols=OpenFlow10,OpenFlow11,OpenFlow12
+-ExecStart=/usr/bin/ovs-vsctl set Bridge ovs0 external-ids:netplan/protocols="OpenFlow10,OpenFlow11,OpenFlow12"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Bridge ovs0 protocols=OpenFlow10,OpenFlow11,OpenFlow12
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Bridge ovs0 external-ids:netplan/protocols="OpenFlow10,OpenFlow11,OpenFlow12"
+ '''},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+         # Confirm that the networkd config is still sane
+@@ -197,12 +197,12 @@ After=netplan-ovs-br0.service
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-bond br0 bond0 eth1 eth2
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 external-ids:netplan="true"
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 lacp=off
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 external-ids:netplan/lacp="off"
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 external-ids:iface-id="myhostname"
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 external-ids:netplan/external-ids/iface-id="myhostname"
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-bond br0 bond0 eth1 eth2
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 external-ids:netplan="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 lacp=off
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 external-ids:netplan/lacp="off"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 external-ids:iface-id="myhostname"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 external-ids:netplan/external-ids/iface-id="myhostname"
+ '''},
+                          'br0.service': OVS_BR_EMPTY % {'iface': 'br0'},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+@@ -266,10 +266,10 @@ After=netplan-ovs-br0.service
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-bond br0 bond0 eth1 eth2
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 external-ids:netplan="true"
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 lacp=active
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 external-ids:netplan/lacp="active"
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-bond br0 bond0 eth1 eth2
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 external-ids:netplan="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 lacp=active
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 external-ids:netplan/lacp="active"
+ '''},
+                          'br0.service': OVS_BR_EMPTY % {'iface': 'br0'},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+@@ -332,12 +332,12 @@ After=netplan-ovs-br0.service
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-bond br0 bond0 eth1 eth2
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 external-ids:netplan="true"
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 lacp=off
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 external-ids:netplan/lacp="off"
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 bond_mode=balance-tcp
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 external-ids:netplan/bond_mode="balance-tcp"
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-bond br0 bond0 eth1 eth2
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 external-ids:netplan="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 lacp=off
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 external-ids:netplan/lacp="off"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 bond_mode=balance-tcp
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 external-ids:netplan/bond_mode="balance-tcp"
+ '''},
+                          'br0.service': OVS_BR_EMPTY % {'iface': 'br0'},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+@@ -372,12 +372,12 @@ After=netplan-ovs-br0.service
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-bond br0 bond0 eth1 eth2
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 external-ids:netplan="true"
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 lacp=off
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 external-ids:netplan/lacp="off"
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 bond_mode=active-backup
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 external-ids:netplan/bond_mode="active-backup"
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-bond br0 bond0 eth1 eth2
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 external-ids:netplan="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 lacp=off
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 external-ids:netplan/lacp="off"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 bond_mode=active-backup
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 external-ids:netplan/bond_mode="active-backup"
+ '''},
+                          'br0.service': OVS_BR_EMPTY % {'iface': 'br0'},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+@@ -424,9 +424,9 @@ ExecStart=/usr/bin/ovs-vsctl set Port bond0 external-ids:netplan/bond_mode="acti
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-br br0
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-port br0 eth1
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-port br0 eth2
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-br br0
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-port br0 eth1
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-port br0 eth2
+ ''' + OVS_BR_DEFAULT % {'iface': 'br0'}},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+         # Confirm that the networkd config is still sane
+@@ -449,12 +449,12 @@ ExecStart=/usr/bin/ovs-vsctl --may-exist add-port br0 eth2
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-br br0
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-br br0
+ ''' + OVS_BR_DEFAULT % {'iface': 'br0'} + '''\
+-ExecStart=/usr/bin/ovs-vsctl set Bridge br0 external-ids:iface-id="myhostname"
+-ExecStart=/usr/bin/ovs-vsctl set Bridge br0 external-ids:netplan/external-ids/iface-id="myhostname"
+-ExecStart=/usr/bin/ovs-vsctl set Bridge br0 other-config:disable-in-band="true"
+-ExecStart=/usr/bin/ovs-vsctl set Bridge br0 external-ids:netplan/other-config/disable-in-band="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Bridge br0 external-ids:iface-id="myhostname"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Bridge br0 external-ids:netplan/external-ids/iface-id="myhostname"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Bridge br0 other-config:disable-in-band="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Bridge br0 external-ids:netplan/other-config/disable-in-band="true"
+ '''},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+         # Confirm that the bridge has been only configured for OVS
+@@ -480,16 +480,16 @@ ExecStart=/usr/bin/ovs-vsctl set Bridge br0 external-ids:netplan/other-config/di
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-br br0
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-port br0 eth1
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-port br0 eth2
+-ExecStart=/usr/bin/ovs-vsctl set Bridge br0 external-ids:netplan="true"
+-ExecStart=/usr/bin/ovs-vsctl set-fail-mode br0 secure
+-ExecStart=/usr/bin/ovs-vsctl set Bridge br0 external-ids:netplan/global/set-fail-mode="secure"
+-ExecStart=/usr/bin/ovs-vsctl set Bridge br0 mcast_snooping_enable=true
+-ExecStart=/usr/bin/ovs-vsctl set Bridge br0 external-ids:netplan/mcast_snooping_enable="true"
+-ExecStart=/usr/bin/ovs-vsctl set Bridge br0 rstp_enable=true
+-ExecStart=/usr/bin/ovs-vsctl set Bridge br0 external-ids:netplan/rstp_enable="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-br br0
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-port br0 eth1
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-port br0 eth2
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Bridge br0 external-ids:netplan="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set-fail-mode br0 secure
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Bridge br0 external-ids:netplan/global/set-fail-mode="secure"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Bridge br0 mcast_snooping_enable=true
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Bridge br0 external-ids:netplan/mcast_snooping_enable="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Bridge br0 rstp_enable=true
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Bridge br0 external-ids:netplan/rstp_enable="true"
+ '''},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+         # Confirm that the networkd config is still sane
+@@ -540,10 +540,10 @@ ExecStart=/usr/bin/ovs-vsctl set Bridge br0 external-ids:netplan/rstp_enable="tr
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-br br0
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-br br0
+ ''' + OVS_BR_DEFAULT % {'iface': 'br0'} + '''\
+-ExecStart=/usr/bin/ovs-vsctl set Bridge br0 protocols=OpenFlow10,OpenFlow11,OpenFlow15
+-ExecStart=/usr/bin/ovs-vsctl set Bridge br0 external-ids:netplan/protocols="OpenFlow10,OpenFlow11,OpenFlow15"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Bridge br0 protocols=OpenFlow10,OpenFlow11,OpenFlow15
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Bridge br0 external-ids:netplan/protocols="OpenFlow10,OpenFlow11,OpenFlow15"
+ '''},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+         # Confirm that the networkd config is still sane
+@@ -590,22 +590,22 @@ ExecStart=/usr/bin/ovs-vsctl set Bridge br0 external-ids:netplan/protocols="Open
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-br br0
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-br br0
+ ''' + OVS_BR_DEFAULT % {'iface': 'br0'} + '''\
+-ExecStart=/usr/bin/ovs-vsctl set-controller br0 ptcp: ptcp:1337 ptcp:1337:[fe80::1234%eth0] pssl:1337:[fe80::1] ssl:10.10.10.1 \
+-tcp:127.0.0.1:1337 tcp:[fe80::1234%eth0] tcp:[fe80::1]:1337 unix:/some/path punix:other/path
+-ExecStart=/usr/bin/ovs-vsctl set Bridge br0 external-ids:netplan/global/set-controller="ptcp:,ptcp:1337,\
++ExecStart=''' + OVS_VSCTL_PATH + ''' set-controller br0 ptcp: ptcp:1337 ptcp:1337:[fe80::1234%eth0] pssl:1337:[fe80::1] \
++ssl:10.10.10.1 tcp:127.0.0.1:1337 tcp:[fe80::1234%eth0] tcp:[fe80::1]:1337 unix:/some/path punix:other/path
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Bridge br0 external-ids:netplan/global/set-controller="ptcp:,ptcp:1337,\
+ ptcp:1337:[fe80::1234%eth0],pssl:1337:[fe80::1],ssl:10.10.10.1,tcp:127.0.0.1:1337,tcp:[fe80::1234%eth0],tcp:[fe80::1]:1337,\
+ unix:/some/path,punix:other/path"
+-ExecStart=/usr/bin/ovs-vsctl set Controller br0 connection-mode=out-of-band
+-ExecStart=/usr/bin/ovs-vsctl set Controller br0 external-ids:netplan/connection-mode="out-of-band"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Controller br0 connection-mode=out-of-band
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Controller br0 external-ids:netplan/connection-mode="out-of-band"
+ '''},
+                          'global.service': OVS_VIRTUAL % {'iface': 'global', 'extra': '''
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl set-ssl /key/path /some/path /another/path
+-ExecStart=/usr/bin/ovs-vsctl set open_vswitch . external-ids:netplan/global/set-ssl="/key/path,/some/path,/another/path"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set-ssl /key/path /some/path /another/path
++ExecStart=''' + OVS_VSCTL_PATH + ''' set open_vswitch . external-ids:netplan/global/set-ssl="/key/path,/some/path,/another/path"
+ '''},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+         # Confirm that the networkd config is still sane
+@@ -702,8 +702,8 @@ ExecStart=/usr/bin/ovs-vsctl set open_vswitch . external-ids:netplan/global/set-
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl set-ssl /key/path /some/path /another/path
+-ExecStart=/usr/bin/ovs-vsctl set open_vswitch . external-ids:netplan/global/set-ssl="/key/path,/some/path,/another/path"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set-ssl /key/path /some/path /another/path
++ExecStart=''' + OVS_VSCTL_PATH + ''' set open_vswitch . external-ids:netplan/global/set-ssl="/key/path,/some/path,/another/path"
+ '''},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+         # Confirm that the networkd config is still sane
+@@ -807,10 +807,10 @@ After=netplan-ovs-br0.service
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-bond br0 bond0 eth1 eth2
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 external-ids:netplan="true"
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 lacp=off
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 external-ids:netplan/lacp="off"
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-bond br0 bond0 eth1 eth2
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 external-ids:netplan="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 lacp=off
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 external-ids:netplan/lacp="off"
+ '''},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+         self.assert_networkd({'br0.network': ND_WITHIP % ('br0', '192.170.1.1/24'),
+@@ -856,8 +856,8 @@ Bond=bond0
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-br br1
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-port br1 patchx -- set Interface patchx type=patch options:peer=patchy
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-br br1
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-port br1 patchx -- set Interface patchx type=patch options:peer=patchy
+ ''' + OVS_BR_DEFAULT % {'iface': 'br1'}},
+                          'bond0.service': OVS_VIRTUAL % {'iface': 'bond0', 'extra':
+                                                          '''Requires=netplan-ovs-br0.service
+@@ -866,10 +866,11 @@ After=netplan-ovs-br0.service
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-bond br0 bond0 patchy eth0 -- set Interface patchy type=patch options:peer=patchx
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 external-ids:netplan="true"
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 lacp=off
+-ExecStart=/usr/bin/ovs-vsctl set Port bond0 external-ids:netplan/lacp="off"
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-bond br0 bond0 patchy eth0 -- set Interface patchy type=patch \
++options:peer=patchx
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 external-ids:netplan="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 lacp=off
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port bond0 external-ids:netplan/lacp="off"
+ '''},
+                          'patchx.service': OVS_VIRTUAL % {'iface': 'patchx', 'extra':
+                                                           '''Requires=netplan-ovs-br1.service
+@@ -878,7 +879,7 @@ After=netplan-ovs-br1.service
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl set Port patchx external-ids:netplan="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port patchx external-ids:netplan="true"
+ '''},
+                          'patchy.service': OVS_VIRTUAL % {'iface': 'patchy', 'extra':
+                                                           '''Requires=netplan-ovs-bond0.service
+@@ -887,7 +888,7 @@ After=netplan-ovs-bond0.service
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl set Interface patchy external-ids:netplan="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Interface patchy external-ids:netplan="true"
+ '''},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+         self.assert_networkd({'br0.network': ND_WITHIP % ('br0', '192.170.1.1/24'),
+@@ -915,15 +916,15 @@ ExecStart=/usr/bin/ovs-vsctl set Interface patchy external-ids:netplan="true"
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-br br0
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-port br0 patch0-1 -- set Interface patch0-1 type=patch options:peer=patch1-0
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-br br0
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-port br0 patch0-1 -- set Interface patch0-1 type=patch options:peer=patch1-0
+ ''' + OVS_BR_DEFAULT % {'iface': 'br0'}},
+                          'br1.service': OVS_VIRTUAL % {'iface': 'br1', 'extra': '''
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-br br1
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-port br1 patch1-0 -- set Interface patch1-0 type=patch options:peer=patch0-1
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-br br1
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-port br1 patch1-0 -- set Interface patch1-0 type=patch options:peer=patch0-1
+ ''' + OVS_BR_DEFAULT % {'iface': 'br1'}},
+                          'patch0-1.service': OVS_VIRTUAL % {'iface': 'patch0-1', 'extra':
+                                                             '''Requires=netplan-ovs-br0.service
+@@ -932,7 +933,7 @@ After=netplan-ovs-br0.service
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl set Port patch0-1 external-ids:netplan="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port patch0-1 external-ids:netplan="true"
+ '''},
+                          'patch1-0.service': OVS_VIRTUAL % {'iface': 'patch1-0', 'extra':
+                                                             '''Requires=netplan-ovs-br1.service
+@@ -941,7 +942,7 @@ After=netplan-ovs-br1.service
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl set Port patch1-0 external-ids:netplan="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Port patch1-0 external-ids:netplan="true"
+ '''},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+         self.assert_networkd({'br0.network': ND_WITHIP % ('br0', '192.168.1.1/24'),
+@@ -966,7 +967,7 @@ ExecStart=/usr/bin/ovs-vsctl set Port patch1-0 external-ids:netplan="true"
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-br br0
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-br br0
+ ''' + OVS_BR_DEFAULT % {'iface': 'br0'}},
+                          'br0.100.service': OVS_VIRTUAL % {'iface': 'br0.100', 'extra':
+                                                            '''Requires=netplan-ovs-br0.service
+@@ -975,8 +976,8 @@ After=netplan-ovs-br0.service
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-br br0.100 br0 100
+-ExecStart=/usr/bin/ovs-vsctl set Interface br0.100 external-ids:netplan="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-br br0.100 br0 100
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Interface br0.100 external-ids:netplan="true"
+ '''},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+         # Confirm that the networkd config is still sane
+@@ -1005,8 +1006,8 @@ After=netplan-ovs-br0.service
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-br br0.100 br0 100
+-ExecStart=/usr/bin/ovs-vsctl set Interface br0.100 external-ids:netplan="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-br br0.100 br0 100
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Interface br0.100 external-ids:netplan="true"
+ '''},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+         # Confirm that the networkd config is still sane
+@@ -1042,8 +1043,8 @@ ExecStart=/usr/bin/ovs-vsctl set Interface br0.100 external-ids:netplan="true"
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-br ovs-br
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-port ovs-br non-ovs-bond
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-br ovs-br
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-port ovs-br non-ovs-bond
+ ''' + OVS_BR_DEFAULT % {'iface': 'ovs-br'}},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+         # Confirm that the networkd config is still sane
+@@ -1097,13 +1098,13 @@ ExecStart=/usr/bin/ovs-vsctl --may-exist add-port ovs-br non-ovs-bond
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-br br123
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-port br123 nic1
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-br br123
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-port br123 nic1
+ ''' + OVS_BR_DEFAULT % {'iface': 'br123'} + ('\
+-ExecStart=/usr/bin/ovs-vsctl set Bridge br123 protocols=OpenFlow10,OpenFlow11,OpenFlow12\n\
+-ExecStart=/usr/bin/ovs-vsctl set Bridge br123 external-ids:netplan/protocols="OpenFlow10,OpenFlow11,OpenFlow12"\n\
+-ExecStart=/usr/bin/ovs-vsctl set-controller br123 tcp:127.0.0.1:6653\n\
+-ExecStart=/usr/bin/ovs-vsctl set Bridge br123 external-ids:netplan/global/set-controller="tcp:127.0.0.1:6653"\n\
++ExecStart=' + OVS_VSCTL_PATH + ' set Bridge br123 protocols=OpenFlow10,OpenFlow11,OpenFlow12\n\
++ExecStart=' + OVS_VSCTL_PATH + ' set Bridge br123 external-ids:netplan/protocols="OpenFlow10,OpenFlow11,OpenFlow12"\n\
++ExecStart=' + OVS_VSCTL_PATH + ' set-controller br123 tcp:127.0.0.1:6653\n\
++ExecStart=' + OVS_VSCTL_PATH + ' set Bridge br123 external-ids:netplan/global/set-controller="tcp:127.0.0.1:6653"\n\
+ ')},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+ 
+@@ -1135,8 +1136,8 @@ After=netplan-ovs-abc%2F..%2F..%2F123.service
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-br abc/../../123.100 abc/../../123 100
+-ExecStart=/usr/bin/ovs-vsctl set Interface abc/../../123.100 external-ids:netplan="true"
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-br abc/../../123.100 abc/../../123 100
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Interface abc/../../123.100 external-ids:netplan="true"
+ '''},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+ 
+@@ -1164,9 +1165,9 @@ ExecStart=/usr/bin/ovs-vsctl set Interface abc/../../123.100 external-ids:netpla
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-br ovs0
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-port ovs0 eth1
+-ExecStart=/usr/bin/ovs-vsctl --may-exist add-port ovs0 eth0
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-br ovs0
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-port ovs0 eth1
++ExecStart=''' + OVS_VSCTL_PATH + ''' --may-exist add-port ovs0 eth0
+ ''' + OVS_BR_DEFAULT % {'iface': 'ovs0'}},
+                          'eth0.service': OVS_PHYSICAL % {'iface': 'eth0', 'extra': '''\
+ Requires=netplan-ovs-ovs0.service
+@@ -1175,10 +1176,12 @@ After=netplan-ovs-ovs0.service
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl set Interface eth0 external-ids:a\\n1\\ra=" \\; a \\; 1 ;a; ;b\\t;\\t3 ;\\ta\\t; 1"
+-ExecStart=/usr/bin/ovs-vsctl set Interface eth0 external-ids:netplan/external-ids/a\\n1\\ra=",;,a,;,1,;a;,;b\\t;\\t3,;\\ta\\t;,1"
+-ExecStart=/usr/bin/ovs-vsctl set Interface eth0 other-config:a\\n1\\ra=" \\; a \\; 1 ;a; ;b\\t;\\t3 ;\\ta\\t; 1"
+-ExecStart=/usr/bin/ovs-vsctl set Interface eth0 external-ids:netplan/other-config/a\\n1\\ra=",;,a,;,1,;a;,;b\\t;\\t3,;\\ta\\t;,1"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Interface eth0 external-ids:a\\n1\\ra=" \\; a \\; 1 ;a; ;b\\t;\\t3 ;\\ta\\t; 1"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Interface eth0 \
++external-ids:netplan/external-ids/a\\n1\\ra=",;,a,;,1,;a;,;b\\t;\\t3,;\\ta\\t;,1"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Interface eth0 other-config:a\\n1\\ra=" \\; a \\; 1 ;a; ;b\\t;\\t3 ;\\ta\\t; 1"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Interface eth0 \
++external-ids:netplan/other-config/a\\n1\\ra=",;,a,;,1,;a;,;b\\t;\\t3,;\\ta\\t;,1"
+ '''},
+                          'eth1.service': OVS_PHYSICAL % {'iface': 'eth1', 'extra': '''\
+ Requires=netplan-ovs-ovs0.service
+@@ -1187,8 +1190,8 @@ After=netplan-ovs-ovs0.service
+ [Service]
+ Type=oneshot
+ TimeoutStartSec=10s
+-ExecStart=/usr/bin/ovs-vsctl set Interface eth1 other-config:disable-in-band="false"
+-ExecStart=/usr/bin/ovs-vsctl set Interface eth1 external-ids:netplan/other-config/disable-in-band="false"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Interface eth1 other-config:disable-in-band="false"
++ExecStart=''' + OVS_VSCTL_PATH + ''' set Interface eth1 external-ids:netplan/other-config/disable-in-band="false"
+ '''},
+                          'cleanup.service': OVS_CLEANUP % {'iface': 'cleanup'}})
+         # Confirm that the networkd config is still sane
+diff --git a/tests/integration/ovs.py b/tests/integration/ovs.py
+index bfcfc64..ac5156f 100644
+--- a/tests/integration/ovs.py
++++ b/tests/integration/ovs.py
+@@ -474,7 +474,7 @@ class _CommonTests():
+         p = subprocess.Popen(['netplan', 'apply'], stdout=subprocess.PIPE,
+                              stderr=subprocess.PIPE, text=True)
+         (_, err) = p.communicate()
+-        self.assertIn('Cannot call Open vSwitch: ovsdb-server.service is not running.', err)
++        self.assertIn("OpenvSwitch database is not running", err)
+         self.assertEqual(p.returncode, 0)
+ 
+     def test_settings_tag_cleanup(self):
+diff --git a/tests/test_configmanager.py b/tests/test_configmanager.py
+index 5f2e926..ca766c9 100644
+--- a/tests/test_configmanager.py
++++ b/tests/test_configmanager.py
+@@ -22,7 +22,7 @@ import tempfile
+ import unittest
+ 
+ from netplan_cli.configmanager import ConfigManager, ConfigurationError
+-from netplan_cli.cli.ovs import OPENVSWITCH_OVS_VSCTL
++from netplan_cli.cli.ovs import OVS_VSCTL_PATH
+ 
+ 
+ class TestConfigManager(unittest.TestCase):
+@@ -230,7 +230,7 @@ class TestConfigManager(unittest.TestCase):
+         self.assertIn('eth0',    state.ethernets)
+         self.assertIn('eth42',   state.ethernets)
+ 
+-    @unittest.skipIf(not os.path.exists(OPENVSWITCH_OVS_VSCTL),
++    @unittest.skipIf(not os.path.exists(OVS_VSCTL_PATH),
+                      'OpenVSwitch not installed')
+     def test_parse_merging_ovs(self):
+         state = self.configmanager.parse(extra_config=[os.path.join(self.workdir.name, "ovs_merging.yaml")])
+diff --git a/tests/test_libnetplan.py b/tests/test_libnetplan.py
+index 33a07f4..5c5d80f 100644
+--- a/tests/test_libnetplan.py
++++ b/tests/test_libnetplan.py
+@@ -30,7 +30,7 @@ from parser.base import capture_stderr
+ 
+ from utils import state_from_yaml
+ from netplan_cli.cli.commands.set import FALLBACK_FILENAME
+-from netplan_cli.cli.ovs import OPENVSWITCH_OVS_VSCTL
++from netplan_cli.cli.ovs import OVS_VSCTL_PATH
+ 
+ import netplan
+ from netplan.netdef import NetplanRoute
+@@ -642,7 +642,7 @@ class TestNetDefinition(TestBase):
+         netdef = state['eth0']
+         self.assertEqual(os.path.join(self.confdir, "a.yaml"), netdef.filepath)
+ 
+-    @unittest.skipIf(not os.path.exists(OPENVSWITCH_OVS_VSCTL),
++    @unittest.skipIf(not os.path.exists(OVS_VSCTL_PATH),
+                      'OpenVSwitch not installed')
+     def test_filepath_for_ovs_ports(self):
+         state = state_from_yaml(self.confdir, '''network:
+@@ -663,7 +663,7 @@ class TestNetDefinition(TestBase):
+         self.assertEqual(os.path.join(self.confdir, "a.yaml"), netdef_port1.filepath)
+         self.assertEqual(os.path.join(self.confdir, "a.yaml"), netdef_port2.filepath)
+ 
+-    @unittest.skipIf(not os.path.exists(OPENVSWITCH_OVS_VSCTL),
++    @unittest.skipIf(not os.path.exists(OVS_VSCTL_PATH),
+                      'OpenVSwitch not installed')
+     def test_filepath_for_ovs_ports_when_conf_is_redefined(self):
+         state = netplan.State()
+@@ -847,7 +847,7 @@ class TestNetDefinition(TestBase):
+ 
+         self.assertIsNone(state['eth0'].links.get('vrf'))
+ 
+-    @unittest.skipIf(not os.path.exists(OPENVSWITCH_OVS_VSCTL),
++    @unittest.skipIf(not os.path.exists(OVS_VSCTL_PATH),
+                      'OpenVSwitch not installed')
+     def test_interface_has_pointer_to_peer(self):
+         state = state_from_yaml(self.confdir, '''network:
+diff --git a/tests/test_ovs.py b/tests/test_ovs.py
+index e238c67..9232c09 100644
+--- a/tests/test_ovs.py
++++ b/tests/test_ovs.py
+@@ -19,7 +19,7 @@ import os
+ import unittest
+ 
+ from unittest.mock import patch, call
+-from netplan_cli.cli.ovs import OPENVSWITCH_OVS_VSCTL as OVS
++from netplan_cli.cli.ovs import OVS_VSCTL_PATH as OVS_PATH
+ 
+ import netplan_cli.cli.ovs as ovs
+ 
+@@ -27,14 +27,14 @@ from utils import state_from_yaml
+ import tempfile
+ 
+ 
+-@unittest.skipIf(not os.path.exists(OVS),
++@unittest.skipIf(not os.path.exists(OVS_PATH),
+                  'OpenVSwitch not installed')
+ class TestOVS(unittest.TestCase):
+ 
+     @patch('subprocess.check_call')
+     def test_clear_settings_tag(self, mock):
+         ovs.clear_setting('Bridge', 'ovs0', 'netplan/external-ids/key', 'value')
+-        mock.assert_called_with([OVS, 'remove', 'Bridge', 'ovs0', 'external-ids', 'netplan/external-ids/key'])
++        mock.assert_called_with([OVS_PATH, 'remove', 'Bridge', 'ovs0', 'external-ids', 'netplan/external-ids/key'])
+ 
+     @patch('subprocess.check_output')
+     @patch('subprocess.check_call')
+@@ -45,10 +45,10 @@ Certificate: /another/cert.pem
+ CA Certificate: /some/ca-cert.pem
+ Bootstrap: false'''
+         ovs.clear_setting('Open_vSwitch', '.', 'netplan/global/set-ssl', '/private/key.pem,/another/cert.pem,/some/ca-cert.pem')
+-        mock_out.assert_called_once_with([OVS, 'get-ssl'], text=True)
++        mock_out.assert_called_once_with([OVS_PATH, 'get-ssl'], text=True)
+         mock.assert_has_calls([
+-            call([OVS, 'del-ssl']),
+-            call([OVS, 'remove', 'Open_vSwitch', '.', 'external-ids', 'netplan/global/set-ssl'])
++            call([OVS_PATH, 'del-ssl']),
++            call([OVS_PATH, 'remove', 'Open_vSwitch', '.', 'external-ids', 'netplan/global/set-ssl'])
+         ])
+ 
+     @patch('subprocess.check_output')
+@@ -60,9 +60,9 @@ Certificate: /another/cert.pem
+ CA Certificate: /some/ca-cert.pem
+ Bootstrap: false'''
+         ovs.clear_setting('Open_vSwitch', '.', 'netplan/global/set-ssl', '/some/key.pem,/other/cert.pem,/some/cert.pem')
+-        mock_out.assert_called_once_with([OVS, 'get-ssl'], text=True)
++        mock_out.assert_called_once_with([OVS_PATH, 'get-ssl'], text=True)
+         mock.assert_has_calls([
+-            call([OVS, 'remove', 'Open_vSwitch', '.', 'external-ids', 'netplan/global/set-ssl'])
++            call([OVS_PATH, 'remove', 'Open_vSwitch', '.', 'external-ids', 'netplan/global/set-ssl'])
+         ])
+ 
+     def test_clear_global_unknown(self):
+@@ -74,10 +74,10 @@ Bootstrap: false'''
+     def test_clear_global(self, mock, mock_out):
+         mock_out.return_value = 'tcp:127.0.0.1:1337\nunix:/some/socket'
+         ovs.clear_setting('Bridge', 'ovs0', 'netplan/global/set-controller', 'tcp:127.0.0.1:1337,unix:/some/socket')
+-        mock_out.assert_called_once_with([OVS, 'get-controller', 'ovs0'], text=True)
++        mock_out.assert_called_once_with([OVS_PATH, 'get-controller', 'ovs0'], text=True)
+         mock.assert_has_calls([
+-            call([OVS, 'del-controller', 'ovs0']),
+-            call([OVS, 'remove', 'Bridge', 'ovs0', 'external-ids', 'netplan/global/set-controller'])
++            call([OVS_PATH, 'del-controller', 'ovs0']),
++            call([OVS_PATH, 'remove', 'Bridge', 'ovs0', 'external-ids', 'netplan/global/set-controller'])
+         ])
+ 
+     @patch('subprocess.check_output')
+@@ -85,41 +85,41 @@ Bootstrap: false'''
+     def test_no_clear_global_different(self, mock, mock_out):
+         mock_out.return_value = 'unix:/var/run/openvswitch/ovs0.mgmt'
+         ovs.clear_setting('Bridge', 'ovs0', 'netplan/global/set-controller', 'tcp:127.0.0.1:1337,unix:/some/socket')
+-        mock_out.assert_called_once_with([OVS, 'get-controller', 'ovs0'], text=True)
++        mock_out.assert_called_once_with([OVS_PATH, 'get-controller', 'ovs0'], text=True)
+         mock.assert_has_calls([
+-            call([OVS, 'remove', 'Bridge', 'ovs0', 'external-ids', 'netplan/global/set-controller'])
++            call([OVS_PATH, 'remove', 'Bridge', 'ovs0', 'external-ids', 'netplan/global/set-controller'])
+         ])
+ 
+     @patch('subprocess.check_call')
+     def test_clear_dict(self, mock):
+         ovs.clear_setting('Bridge', 'ovs0', 'netplan/other-config/key', 'value')
+         mock.assert_has_calls([
+-            call([OVS, 'remove', 'Bridge', 'ovs0', 'other-config', 'key=\"value\"']),
+-            call([OVS, 'remove', 'Bridge', 'ovs0', 'external-ids', 'netplan/other-config/key'])
++            call([OVS_PATH, 'remove', 'Bridge', 'ovs0', 'other-config', 'key=\"value\"']),
++            call([OVS_PATH, 'remove', 'Bridge', 'ovs0', 'external-ids', 'netplan/other-config/key'])
+         ])
+ 
+     @patch('subprocess.check_call')
+     def test_clear_col(self, mock):
+         ovs.clear_setting('Port', 'bond0', 'netplan/bond_mode', 'balance-tcp')
+         mock.assert_has_calls([
+-            call([OVS, 'remove', 'Port', 'bond0', 'bond_mode', 'balance-tcp']),
+-            call([OVS, 'remove', 'Port', 'bond0', 'external-ids', 'netplan/bond_mode'])
++            call([OVS_PATH, 'remove', 'Port', 'bond0', 'bond_mode', 'balance-tcp']),
++            call([OVS_PATH, 'remove', 'Port', 'bond0', 'external-ids', 'netplan/bond_mode'])
+         ])
+ 
+     @patch('subprocess.check_call')
+     def test_clear_col_default(self, mock):
+         ovs.clear_setting('Bridge', 'ovs0', 'netplan/rstp_enable', 'true')
+         mock.assert_has_calls([
+-            call([OVS, 'set', 'Bridge', 'ovs0', 'rstp_enable=false']),
+-            call([OVS, 'remove', 'Bridge', 'ovs0', 'external-ids', 'netplan/rstp_enable'])
++            call([OVS_PATH, 'set', 'Bridge', 'ovs0', 'rstp_enable=false']),
++            call([OVS_PATH, 'remove', 'Bridge', 'ovs0', 'external-ids', 'netplan/rstp_enable'])
+         ])
+ 
+     @patch('subprocess.check_call')
+     def test_clear_dict_colon(self, mock):
+         ovs.clear_setting('Bridge', 'ovs0', 'netplan/other-config/key', 'fa:16:3e:4b:19:3a')
+         mock.assert_has_calls([
+-            call([OVS, 'remove', 'Bridge', 'ovs0', 'other-config', 'key=\"fa:16:3e:4b:19:3a\"']),
+-            call([OVS, 'remove', 'Bridge', 'ovs0', 'external-ids', 'netplan/other-config/key'])
++            call([OVS_PATH, 'remove', 'Bridge', 'ovs0', 'other-config', 'key=\"fa:16:3e:4b:19:3a\"']),
++            call([OVS_PATH, 'remove', 'Bridge', 'ovs0', 'external-ids', 'netplan/other-config/key'])
+         ])
+         mock.mock_calls
+ 
diff -pruN 1.1.2-7/debian/patches/series 1.1.2-7ubuntu3/debian/patches/series
--- 1.1.2-7/debian/patches/series	2025-04-16 11:31:36.000000000 +0000
+++ 1.1.2-7ubuntu3/debian/patches/series	2025-07-31 10:05:11.000000000 +0000
@@ -6,3 +6,7 @@ lp2095203-0004-cli-apply-Ignore-udevadm-
 0006-tests-regressions-Give-more-time-for-slow-architectu.patch
 0007-tests-integration-Avoid-race-condition-with-veth-MAC.patch
 lp2083029-fix-try.patch
+wait-online-dns-pr535/0002-networkd-wait-online-wait-for-DNS-servers-to-be-assi.patch
+wait-online-dns-pr535/0003-test-generator-wait-online-DNS-testing.patch
+wait-online-dns-pr535/0004-tests-ethernets-wait-online-DNS-testing.patch
+0012-Allows-non-standard-OVS-setups.patch
diff -pruN 1.1.2-7/debian/patches/wait-online-dns-pr535/0002-networkd-wait-online-wait-for-DNS-servers-to-be-assi.patch 1.1.2-7ubuntu3/debian/patches/wait-online-dns-pr535/0002-networkd-wait-online-wait-for-DNS-servers-to-be-assi.patch
--- 1.1.2-7/debian/patches/wait-online-dns-pr535/0002-networkd-wait-online-wait-for-DNS-servers-to-be-assi.patch	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.2-7ubuntu3/debian/patches/wait-online-dns-pr535/0002-networkd-wait-online-wait-for-DNS-servers-to-be-assi.patch	2025-07-31 10:05:11.000000000 +0000
@@ -0,0 +1,47 @@
+From: =?utf-8?q?Lukas_M=C3=A4rdian?= <slyon@ubuntu.com>
+Date: Tue, 14 Jan 2025 10:11:37 +0100
+Subject: networkd: wait-online wait for DNS servers to be assigned
+
+As implemented in systemd (v258):
+https://github.com/systemd/systemd/pull/34640
+
+Forwarded: https://github.com/canonical/netplan/pull/535
+---
+ src/networkd.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/src/networkd.c b/src/networkd.c
+index 982d18c..d0d8205 100644
+--- a/src/networkd.c
++++ b/src/networkd.c
+@@ -1631,7 +1631,6 @@ _netplan_networkd_write_wait_online(const NetplanState* np_state, const char* ro
+     // ELSE:
+     GString* linklocal_str = g_string_new("");
+     GString* routable_str  = g_string_new("");
+-    g_string_append(content, "\n[Service]\nExecStart=\n"); // clear old s-n-wait-online command
+ 
+     GHashTableIter giter;
+     gpointer key, value;
+@@ -1655,6 +1654,13 @@ _netplan_networkd_write_wait_online(const NetplanState* np_state, const char* ro
+         }
+     }
+ 
++    // allow waiting for "--dns"
++    if (routable_str->len > 0) {
++        g_string_append(content, "After=systemd-resolved.service\n");
++    }
++    // clear old s-n-wait-online command
++    g_string_append(content, "\n[Service]\nExecStart=\n");
++
+     // wait for all link-local (degraded/carrier) interface
+     if (linklocal_str->len > 0) {
+         g_string_append_printf(content, "ExecStart=/lib/systemd/systemd-networkd-wait-online%s\n", linklocal_str->str);
+@@ -1662,7 +1668,7 @@ _netplan_networkd_write_wait_online(const NetplanState* np_state, const char* ro
+     g_string_free(linklocal_str, TRUE);
+     // wait for any routable interface
+     if (routable_str->len > 0) {
+-        g_string_append_printf(content, "ExecStart=/lib/systemd/systemd-networkd-wait-online --any -o routable%s\n", routable_str->str);
++        g_string_append_printf(content, "ExecStart=/lib/systemd/systemd-networkd-wait-online --any --dns -o routable%s\n", routable_str->str);
+     }
+     g_string_free(routable_str, TRUE);
+ 
diff -pruN 1.1.2-7/debian/patches/wait-online-dns-pr535/0003-test-generator-wait-online-DNS-testing.patch 1.1.2-7ubuntu3/debian/patches/wait-online-dns-pr535/0003-test-generator-wait-online-DNS-testing.patch
--- 1.1.2-7/debian/patches/wait-online-dns-pr535/0003-test-generator-wait-online-DNS-testing.patch	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.2-7ubuntu3/debian/patches/wait-online-dns-pr535/0003-test-generator-wait-online-DNS-testing.patch	2025-07-31 10:05:39.000000000 +0000
@@ -0,0 +1,56 @@
+From: =?utf-8?q?Lukas_M=C3=A4rdian?= <slyon@ubuntu.com>
+Date: Tue, 14 Jan 2025 10:12:27 +0100
+Subject: test:generator: wait-online DNS testing
+
+Forwarded: https://github.com/canonical/netplan/pull/535
+---
+ tests/generator/test_args.py | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/tests/generator/test_args.py b/tests/generator/test_args.py
+index bb79c40..b8a7f95 100644
+--- a/tests/generator/test_args.py
++++ b/tests/generator/test_args.py
+@@ -207,12 +207,13 @@ class TestConfigArgs(TestBase):
+             # eth99 does not exist on the system, so will not be listed
+             self.assertEqual(f.read(), '''[Unit]
+ ConditionPathIsSymbolicLink=/run/systemd/generator/network-online.target.wants/systemd-networkd-wait-online.service
++After=systemd-resolved.service
+ 
+ [Service]
+ ExecStart=
+ ExecStart=/lib/systemd/systemd-networkd-wait-online -i eth99.43:carrier -i lo:carrier \
+ -i eth99.42:carrier -i eth99.44:degraded -i bond0:degraded
+-ExecStart=/lib/systemd/systemd-networkd-wait-online --any -o routable -i eth99.43 -i eth99.45 -i bond0\n''')
++ExecStart=/lib/systemd/systemd-networkd-wait-online --any --dns -o routable -i eth99.43 -i eth99.45 -i bond0\n''')
+ 
+         # should be a no-op the second time while the stamp exists
+         out = subprocess.check_output([generator, '--root-dir', self.workdir.name, outdir, outdir, outdir],
+@@ -323,11 +324,12 @@ ExecStart=/lib/systemd/systemd-networkd-wait-online -i eth99.44:degraded
+         with open(override, 'r') as f:
+             self.assertEqual(f.read(), '''[Unit]
+ ConditionPathIsSymbolicLink=/run/systemd/generator/network-online.target.wants/systemd-networkd-wait-online.service
++After=systemd-resolved.service
+ 
+ [Service]
+ ExecStart=
+ ExecStart=/lib/systemd/systemd-networkd-wait-online -i br0:degraded
+-ExecStart=/lib/systemd/systemd-networkd-wait-online --any -o routable -i br0
++ExecStart=/lib/systemd/systemd-networkd-wait-online --any --dns -o routable -i br0
+ ''')
+ 
+     def test_systemd_generator_noconf(self):
+@@ -395,11 +397,12 @@ ExecStart=/lib/systemd/systemd-networkd-wait-online --any -o routable -i br0
+             # eth99 does not exist on the system, so will not be listed
+             self.assertEqual(f.read(), '''[Unit]
+ ConditionPathIsSymbolicLink=/run/systemd/generator/network-online.target.wants/systemd-networkd-wait-online.service
++After=systemd-resolved.service
+ 
+ [Service]
+ ExecStart=
+ ExecStart=/lib/systemd/systemd-networkd-wait-online -i a \\; b\\t; c\\t; d \\n 123 \\; echo :degraded
+-ExecStart=/lib/systemd/systemd-networkd-wait-online --any -o routable -i a \\; b\\t; c\\t; d \\n 123 \\; echo \n''')
++ExecStart=/lib/systemd/systemd-networkd-wait-online --any --dns -o routable -i a \\; b\\t; c\\t; d \\n 123 \\; echo \n''')
+ 
+         # should be a no-op the second time while the stamp exists
+         out = subprocess.check_output([generator, '--root-dir', self.workdir.name, outdir, outdir, outdir],
diff -pruN 1.1.2-7/debian/patches/wait-online-dns-pr535/0004-tests-ethernets-wait-online-DNS-testing.patch 1.1.2-7ubuntu3/debian/patches/wait-online-dns-pr535/0004-tests-ethernets-wait-online-DNS-testing.patch
--- 1.1.2-7/debian/patches/wait-online-dns-pr535/0004-tests-ethernets-wait-online-DNS-testing.patch	1970-01-01 00:00:00.000000000 +0000
+++ 1.1.2-7ubuntu3/debian/patches/wait-online-dns-pr535/0004-tests-ethernets-wait-online-DNS-testing.patch	2025-07-31 10:05:39.000000000 +0000
@@ -0,0 +1,65 @@
+From: =?utf-8?q?Lukas_M=C3=A4rdian?= <slyon@ubuntu.com>
+Date: Tue, 14 Jan 2025 10:12:46 +0100
+Subject: tests:ethernets: wait-online DNS testing
+
+Forward-ported to enable the 'systemctl restart systemd-networkd-wait-online.service'
+autopkgtest as part of ethernets.py:test_systemd_networkd_wait_online()
+
+Forwarded: https://github.com/canonical/netplan/pull/535
+---
+ tests/integration/ethernets.py | 23 ++++++++++++++++++-----
+ 1 file changed, 18 insertions(+), 5 deletions(-)
+
+diff --git a/tests/integration/ethernets.py b/tests/integration/ethernets.py
+index 2196d54..09186a6 100644
+--- a/tests/integration/ethernets.py
++++ b/tests/integration/ethernets.py
+@@ -427,7 +427,9 @@ class TestNetworkd(IntegrationTestsBase, _CommonTests):
+ 
+     def test_systemd_networkd_wait_online(self):
+         self.addCleanup(subprocess.call, ['ip', 'link', 'del', 'br0'])
+-        self.setup_eth(None, False)
++        # Start dnsmasq DNS server to validate s-d-wait-online --dns option,
++        # which needs to reach the DNS server at UDP/53 on self.dev_e2_ap
++        self.setup_eth(None, True)
+         with open(self.config, 'w') as f:
+             f.write('''network:
+   renderer: %(r)s
+@@ -446,9 +448,17 @@ class TestNetworkd(IntegrationTestsBase, _CommonTests):
+       addresses: ["10.0.0.1/24"]
+   bridges:
+     br0:
+-      addresses: ["10.0.0.2/24"]
+-      interfaces: [%(e2c)s]
+-''' % {'r': self.backend, 'ec_mac': self.dev_e_client_mac, 'e2c': self.dev_e2_client})
++      addresses: ["192.168.6.7/24"]  # from self.dev_e2_ap range
++      nameservers:
++        addresses: [%(dnsip)s]
++      interfaces: [%(e2c)s]''' % {'r': self.backend,
++                                  'ec_mac': self.dev_e_client_mac,
++                                  'e2c': self.dev_e2_client,
++                                  'dnsip': self.dev_e2_ap_ip4.split('/')[0]})
++        # make sure 'findme' still gets found after the rename (we cannot match
++        # PermanentMacAddress on veth), so it does not get into unmanaged and
++        # 'no-carrier' state.
++        self.match_veth_by_non_permanent_mac_quirk('findme', self.dev_e_client_mac)
+         self.generate_and_settle([self.dev_e2_client, 'br0'])
+         override = os.path.join('/run', 'systemd', 'system', 'systemd-networkd-wait-online.service.d', '10-netplan.conf')
+         self.assertTrue(os.path.isfile(override))
+@@ -460,12 +470,15 @@ class TestNetworkd(IntegrationTestsBase, _CommonTests):
+             # <dev_e2_client> should be listed normally
+             self.assertEqual(f.read(), '''[Unit]
+ ConditionPathIsSymbolicLink=/run/systemd/generator/network-online.target.wants/systemd-networkd-wait-online.service
++After=systemd-resolved.service
+ 
+ [Service]
+ ExecStart=
+ ExecStart=/lib/systemd/systemd-networkd-wait-online -i %(e2c)s:carrier -i br0:degraded -i findme:carrier
+-ExecStart=/lib/systemd/systemd-networkd-wait-online --any -o routable -i %(e2c)s -i br0
++ExecStart=/lib/systemd/systemd-networkd-wait-online --any --dns -o routable -i %(e2c)s -i br0
+ ''' % {'e2c': self.dev_e2_client})
++        # Restart sd-nd-wait-online.service and check that it was launched correctly.
++        subprocess.check_call(['systemctl', 'restart', 'systemd-networkd-wait-online.service'])
+ 
+ 
+ @unittest.skipIf("NetworkManager" not in test_backends,
