about summary refs log tree commit diff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rwxr-xr-xtools/create-exports-NetworkManager.sh36
-rwxr-xr-xtools/generate-docs-nm-property-infos.py1
-rwxr-xr-xtools/generate-docs-nm-settings-docs-merge.py2
-rw-r--r--tools/nm-guest-data/bin-nm-deploy.sh.in7
-rw-r--r--tools/nm-guest-data/etc-bashrc.my.in1
-rw-r--r--tools/nm-guest-data/etc-motd-container.in56
-rw-r--r--tools/nm-guest-data/etc-motd-vm.in56
-rwxr-xr-xtools/nm-in-container3
-rwxr-xr-xtools/nm-in-vm2
-rwxr-xr-xtools/run-nm-test.sh22
-rwxr-xr-xtools/test-build.sh56
-rwxr-xr-xtools/test-cloud-meta-mock.py5
-rwxr-xr-xtools/test-networkmanager-service.py200
13 files changed, 174 insertions, 273 deletions
diff --git a/tools/create-exports-NetworkManager.sh b/tools/create-exports-NetworkManager.sh
index 855d8375..38bcdaf6 100755
--- a/tools/create-exports-NetworkManager.sh
+++ b/tools/create-exports-NetworkManager.sh
@@ -13,24 +13,6 @@ die() {
 # plugins. Note that this depends on how NetworkManager and
 # the plugins are build. For example, compiling without
 # --with-more-asserts will yield less symbols.
-#
-# _build re-builds NetworkManager with relevant compile time
-# options to yield the most symbols.
-_build() {
-    git clean -fdx
-    ./autogen.sh --enable-ld-gc \
-                 --enable-ifcfg-rh \
-                 --enable-ifupdown \
-                 --enable-teamdctl \
-                 --enable-wifi \
-                 --with-modem-manager-1 \
-                 --with-ofono \
-                 --with-more-asserts \
-                 --with-more-logging \
-                 --disable-autotools-deprecation
-    make -j20
-}
-
 _sort() {
     LANG=C sort -u
 }
@@ -75,16 +57,6 @@ pretty() {
     sed 's/.*/\t&;/'
 }
 
-do_build() {
-    do_update
-    make
-}
-
-do_rebuild() {
-    _build
-    do_build
-}
-
 do_update() {
     do_generate > ./src/core/NetworkManager.ver
 }
@@ -117,14 +89,6 @@ EOF
 test -f ./src/core/${libs}libNetworkManager.a || die "must be called from NetworkManager top build dir after building the tree"
 
 case "$1" in
-    rebuild)
-        [ -n "$from_meson" ] && die "can't do a build when called from meson"
-        do_rebuild
-        ;;
-    build)
-        [ -n "$from_meson" ] && die "can't do a build when called from meson"
-        do_build
-        ;;
     --called-from-build)
         if test -z "${NM_BUILD_NO_CREATE_EXPORTS+x}"; then
             do_update
diff --git a/tools/generate-docs-nm-property-infos.py b/tools/generate-docs-nm-property-infos.py
index 74dc9d1c..978cfa2e 100755
--- a/tools/generate-docs-nm-property-infos.py
+++ b/tools/generate-docs-nm-property-infos.py
@@ -164,6 +164,7 @@ KEYWORD_XML_TYPE_ATTR = "attr"
 keywords = collections.OrderedDict(
     [
         ("property", KEYWORD_XML_TYPE_ATTR),
+        ("rename", KEYWORD_XML_TYPE_ATTR),
         ("variable", KEYWORD_XML_TYPE_ATTR),
         ("format", KEYWORD_XML_TYPE_ATTR),
         ("values", KEYWORD_XML_TYPE_ATTR),
diff --git a/tools/generate-docs-nm-settings-docs-merge.py b/tools/generate-docs-nm-settings-docs-merge.py
index 853fb773..f59392d2 100755
--- a/tools/generate-docs-nm-settings-docs-merge.py
+++ b/tools/generate-docs-nm-settings-docs-merge.py
@@ -41,6 +41,7 @@ _setting_name_order = [
     "ipv4",
     "ipv6",
     "ip-tunnel",
+    "ipvlan",
     "macsec",
     "macvlan",
     "match",
@@ -299,6 +300,7 @@ for setting_name in iter_keys_of_dicts(settings_roots, key_fcn_setting_name):
         node_set_attr(property_node, "special-values", properties_attrs)
         node_set_attr(property_node, "default", properties_attrs)
         node_set_attr(property_node, "alias", properties_attrs)
+        node_set_attr(property_node, "rename", properties_attrs)
 
         if description_docbook is not None:
             property_node.insert(0, description_docbook)
diff --git a/tools/nm-guest-data/bin-nm-deploy.sh.in b/tools/nm-guest-data/bin-nm-deploy.sh.in
index 9b5385b1..77b51d0c 100644
--- a/tools/nm-guest-data/bin-nm-deploy.sh.in
+++ b/tools/nm-guest-data/bin-nm-deploy.sh.in
@@ -4,11 +4,6 @@ set -ex
 
 cd /NetworkManager
 
-if [ -f ./config.log ] ; then
-    make -j 5 install
-else
-    meson install -C build
-fi
-
+meson install -C build
 systemctl daemon-reload
 systemctl restart NetworkManager.service
diff --git a/tools/nm-guest-data/etc-bashrc.my.in b/tools/nm-guest-data/etc-bashrc.my.in
index 88f2f9aa..f6936c4d 100644
--- a/tools/nm-guest-data/etc-bashrc.my.in
+++ b/tools/nm-guest-data/etc-bashrc.my.in
@@ -1,4 +1,3 @@
-alias m="make -j 8"
 alias n="ninja -C build"
 
 alias l='ls -l --color=auto'
diff --git a/tools/nm-guest-data/etc-motd-container.in b/tools/nm-guest-data/etc-motd-container.in
index 131f815c..e0fb88d6 100644
--- a/tools/nm-guest-data/etc-motd-container.in
+++ b/tools/nm-guest-data/etc-motd-container.in
@@ -15,60 +15,8 @@ so that core dumps get written to file. Afterwards, restore with
 
 from /usr/lib/sysctl.d/50-coredump.conf.
 
-For example, configure NetworkManager with
-  $ ./configure \
-           --enable-address-sanitizer=no \
-           --enable-compile-warnings=yes \
-           --enable-concheck \
-           --enable-config-plugin-ibft=yes \
-           --enable-gtk-doc \
-           --enable-ifcfg-rh=yes \
-           --enable-ifcfg-suse \
-           --enable-ifnet \
-           --enable-ifupdown=yes \
-           --enable-introspection \
-           --enable-json-validation=yes \
-           --enable-maintainer-mode \
-           --enable-more-logging \
-           --enable-more-warnings=error \
-           --enable-ovs=yes \
-           --enable-polkit=yes \
-           --enable-teamdctl=yes \
-           --enable-undefined-sanitizer=no \
-           --enable-vala=yes \
-           --enable-wimax \
-           --localstatedir=/var \
-           --prefix=/opt/test \
-           --sysconfdir=/etc \
-           --with-config-dhcp-default=internal \
-           --with-config-dns-rc-manager-default=auto \
-           --with-consolekit=yes \
-           --with-consolekit=yes \
-           --with-crypto=nss \
-           --with-dhclient=yes \
-           --with-dhcpcanon=yes \
-           --with-dhcpcd=yes \
-           --with-iwd=yes \
-           --with-libnm-glib=yes \
-           --with-modem-manager-1 \
-           --with-netconfig=/bin/nowhere/netconfig \
-           --with-nm-cloud-setup=yes \
-           --with-nmcli=yes \
-           --with-nmtui=yes \
-           --with-ofono=yes \
-           --with-resolvconf=/bin/nowhere/resolvconf \
-           --with-session-tracking=systemd \
-           --with-suspend-resume=systemd \
-           --with-systemd-logind=yes \
-           --with-valgrind=yes \
-           --enable-tests="${NM_BUILD_TESTS:-yes}" \
-           --with-more-asserts="${NM_BUILD_MORE_ASSERTS:-1000}" \
-           "${NM_CONFIGURE_OTPS[@]}"
-Test with:
-  $ systemctl stop NetworkManager; /opt/test/sbin/NetworkManager --debug 2>&1 | tee -a /tmp/nm-log.txt
-
-Or better, configure with `contrib/fedora/rpm/configure-for-system.sh`,
-subsequent `make && make install` will overwrite your system's NetworkManager,
+Configure NetworkManager with `contrib/fedora/rpm/configure-for-system.sh`,
+subsequent `meson install` will overwrite your system's NetworkManager,
 and you can test it with `systemctl daemon-reload ; systemctl restart NetworkManager`.
 
 Run NM-ci tests after creating eth1 with
diff --git a/tools/nm-guest-data/etc-motd-vm.in b/tools/nm-guest-data/etc-motd-vm.in
index 10ae1f9f..feb6c7a3 100644
--- a/tools/nm-guest-data/etc-motd-vm.in
+++ b/tools/nm-guest-data/etc-motd-vm.in
@@ -3,60 +3,8 @@
 find NetworkManager bind mounted at {{BASEDIR_NM}}
 run `nm-env-prepare.sh setup --idx 1` to setup test interfaces
 
-For example, configure NetworkManager with
-  $ ./configure \
-           --enable-address-sanitizer=no \
-           --enable-compile-warnings=yes \
-           --enable-concheck \
-           --enable-config-plugin-ibft=yes \
-           --enable-gtk-doc \
-           --enable-ifcfg-rh=yes \
-           --enable-ifcfg-suse \
-           --enable-ifnet \
-           --enable-ifupdown=yes \
-           --enable-introspection \
-           --enable-json-validation=yes \
-           --enable-maintainer-mode \
-           --enable-more-logging \
-           --enable-more-warnings=error \
-           --enable-ovs=yes \
-           --enable-polkit=yes \
-           --enable-teamdctl=yes \
-           --enable-undefined-sanitizer=no \
-           --enable-vala=yes \
-           --enable-wimax \
-           --localstatedir=/var \
-           --prefix=/opt/test \
-           --sysconfdir=/etc \
-           --with-config-dhcp-default=internal \
-           --with-config-dns-rc-manager-default=auto \
-           --with-consolekit=yes \
-           --with-consolekit=yes \
-           --with-crypto=nss \
-           --with-dhclient=yes \
-           --with-dhcpcanon=yes \
-           --with-dhcpcd=yes \
-           --with-iwd=yes \
-           --with-libnm-glib=yes \
-           --with-modem-manager-1 \
-           --with-netconfig=/bin/nowhere/netconfig \
-           --with-nm-cloud-setup=yes \
-           --with-nmcli=yes \
-           --with-nmtui=yes \
-           --with-ofono=yes \
-           --with-resolvconf=/bin/nowhere/resolvconf \
-           --with-session-tracking=systemd \
-           --with-suspend-resume=systemd \
-           --with-systemd-logind=yes \
-           --with-valgrind=yes \
-           --enable-tests="${NM_BUILD_TESTS:-yes}" \
-           --with-more-asserts="${NM_BUILD_MORE_ASSERTS:-1000}" \
-           "${NM_CONFIGURE_OTPS[@]}"
-Test with:
-  $ systemctl stop NetworkManager; /opt/test/sbin/NetworkManager --debug 2>&1 | tee -a /tmp/nm-log.txt
-
-Or better, if using Fedora, configure with `contrib/fedora/rpm/configure-for-system.sh`,
-subsequent `make && make install` will overwrite your system's NetworkManager,
+Configure NetworkManager with `contrib/fedora/rpm/configure-for-system.sh`,
+subsequent `meson install` will overwrite your system's NetworkManager,
 and you can test it with `systemctl daemon-reload ; systemctl restart NetworkManager`.
 
 Run NM-ci tests after creating eth1 with
diff --git a/tools/nm-in-container b/tools/nm-in-container
index c6884cd5..0e3f31da 100755
--- a/tools/nm-in-container
+++ b/tools/nm-in-container
@@ -23,7 +23,7 @@ set -e
 #    - with command "journal", additional arguments that are passed to journalctl.
 #
 # It bind mounts the current working directory inside the container.
-# You can run `make install` and run tests.
+# You can run `meson install` and run tests.
 # There is a script nm-env-prepare.sh to generate a net1 interface for testing.
 #
 # This will bind-mount the NetworkManager working tree inside the container (and symlink
@@ -229,7 +229,6 @@ RUN dnf install -y \\
     libtool \\
     libubsan \\
     libuuid-devel \\
-    make \\
     meson \\
     mlocate \\
     mobile-broadband-provider-info-devel \\
diff --git a/tools/nm-in-vm b/tools/nm-in-vm
index 569c766c..4d2c7a15 100755
--- a/tools/nm-in-vm
+++ b/tools/nm-in-vm
@@ -23,7 +23,7 @@ set -e
 # NetworkManager directories:
 #
 #   The NetworkManager root directory is mounted in the VM as a filesystem share.
-#   You can run `make install` and run tests.
+#   You can run `meson install` and run tests.
 #
 #   Create a symlink ./.git/NetworkManager-ci, to share the CI directory too.
 #
diff --git a/tools/run-nm-test.sh b/tools/run-nm-test.sh
index 264fc48d..9f0a6531 100755
--- a/tools/run-nm-test.sh
+++ b/tools/run-nm-test.sh
@@ -35,9 +35,7 @@ usage() {
     echo "        the automatism to always launch a D-Bus session"
     echo "  --no-launch-dbus|-D: prevent launching a D-Bus session"
     echo "  --no-libtool: when running with valgrind, the script tries automatically to"
-    echo "        use libtool as necessary. This disables libtool usage" 
-    echo "  --make-first|-m: before running the test, make it (only works with autotools build)"
-    echo "  --no-make-first|-M: disable --make-first option"
+    echo "        use libtool as necessary. This disables libtool usage"
     echo "  --valgrind|-v: run under valgrind"
     echo "  --no-valgrind|-V: disable running under valgrind (overrides NMTST_USE_VALGRIND=1)"
     echo "  -d: set NMTST_DEBUG=d"
@@ -126,8 +124,6 @@ if [ "$CALLED_FROM_MAKE" == 1 ]; then
         NMTST_LAUNCH_DBUS=0
     fi
     TEST="$1"; shift
-    NMTST_MAKE_FIRST=0
-
     TEST_ARGV=("$@")
 else
     if [[ -z "${NMTST_USE_VALGRIND+x}" ]]; then
@@ -162,14 +158,6 @@ else
             NMTST_LIBTOOL=()
             shift
             ;;
-        --make-first|-m)
-            NMTST_MAKE_FIRST=1
-            shift
-            ;;
-        --no-make-first|-M)
-            NMTST_MAKE_FIRST=0
-            shift
-            ;;
         "--valgrind"|-v)
             NMTST_USE_VALGRIND=1
             shift;
@@ -235,14 +223,6 @@ fi
 
 [ -n "$TEST" ] || die "Missing test name. Specify it on the command line."
 
-if _is_true "$NMTST_MAKE_FIRST" 0; then
-    git_dir="$(readlink -f "$(git rev-parse --show-toplevel)")"
-    rel_path="$(realpath --relative-to="$git_dir" -m "$TEST" 2>/dev/null)" || die "cannot resolve test-name \"$TEST\". Did you call the script properly?"
-    cd "$git_dir"
-    make -j5 "$rel_path" || die "make of $TEST failed ($git_dir / $rel_path)"
-    cd - 1>/dev/null
-fi
-
 [ -x "$TEST" ] || die "Test \"$TEST\" does not exist"
 TEST_PATH="$(readlink -f "$(dirname "$TEST")")"
 TEST_NAME="${TEST##*/}"
diff --git a/tools/test-build.sh b/tools/test-build.sh
deleted file mode 100755
index 04d33b6a..00000000
--- a/tools/test-build.sh
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/bin/bash
-
-set -e
-
-die() {
-    echo "$@"
-    exit 1
-}
-
-if [[ "x$(LANG=C git clean -ndx)" != x ]]; then
-    die "The working directory is not clean. Refuse to run. Try \`git clean -dx -n\`"
-fi
-if [[ "x$(git status --porcelain)" != x ]]; then
-    die "The working directory has local changes. Refuse to run. Try \`git reset --hard\`"
-fi
-
-build_out_of_tree() {
-  local TARGET="$1"
-  local C="$2"
-  local M="$3"
-  (
-    git clean -fdx || return 1
-    NOCONFIGURE=x ./autogen.sh || return 1
-    mkdir -p x/y || return 1
-    cd x/y || return 1
-    ../../configure $C $NMTST_CONFIGURE || return 1
-     make $TARGET $M $NMTST_MAKE || return 1
-  )
-}
-
-TARGETS=("$@")
-if [ "${#TARGETS}" -lt 1 ]; then
-    TARGETS=(
-        dispatcher/nm-dispatcher
-        src/core/NetworkManager
-        src/core/dhcp/nm-dhcp-helper
-        src/core/ndisc/tests/test-ndisc-linux
-        src/core/platform/tests/monitor
-        src/nm-online/nm-online
-        src/nmcli/nmcli
-        src/nmtui/nmtui
-        $(git grep -h '\.l\?a\>' Makefile.am | sed 's/[a-zA-Z.0-9_-/]\+/\n\0\n/g' | sort -u | grep '\.l\?a$')
-    )
-fi
-
-set -x
-
-cd "$(dirname "$(readlink -f "$0")")/.."
-
-IDX=($(seq 0 $((${#TARGETS[@]} - 1))))
-IDX=($(printf '%s\n' "${IDX[@]}" | sort -R))
-for idx in "${IDX[@]}"; do
-    TARGET="${TARGETS[$idx]}"
-    echo "### $idx: TARGET=$TARGET"
-    build_out_of_tree "$TARGET" "--enable-gtk-doc" "-j 5"
-done
diff --git a/tools/test-cloud-meta-mock.py b/tools/test-cloud-meta-mock.py
index a396e0da..f7f48bc9 100755
--- a/tools/test-cloud-meta-mock.py
+++ b/tools/test-cloud-meta-mock.py
@@ -276,7 +276,10 @@ httpd = SocketHTTPServer(
     allow_default=allow_default,
 )
 
-print("Listening on http://%s:%d" % (httpd.server_address[0], httpd.server_address[1]))
+if fileno is None:
+    print(
+        "Listening on http://%s:%d" % (httpd.server_address[0], httpd.server_address[1])
+    )
 httpd.server_activate()
 
 httpd.serve_forever()
diff --git a/tools/test-networkmanager-service.py b/tools/test-networkmanager-service.py
index b4268721..8a426332 100755
--- a/tools/test-networkmanager-service.py
+++ b/tools/test-networkmanager-service.py
@@ -429,6 +429,7 @@ IFACE_AGENT = "org.freedesktop.NetworkManager.SecretAgent"
 IFACE_WIRED = "org.freedesktop.NetworkManager.Device.Wired"
 IFACE_MODEM = "org.freedesktop.NetworkManager.Device.Modem"
 IFACE_VLAN = "org.freedesktop.NetworkManager.Device.Vlan"
+IFACE_MACVLAN = "org.freedesktop.NetworkManager.Device.Macvlan"
 IFACE_WIFI_AP = "org.freedesktop.NetworkManager.AccessPoint"
 IFACE_ACTIVE_CONNECTION = "org.freedesktop.NetworkManager.Connection.Active"
 IFACE_VPN_CONNECTION = "org.freedesktop.NetworkManager.VPN.Connection"
@@ -611,6 +612,7 @@ class NmUtil:
         t = s_con[NM.SETTING_CONNECTION_TYPE]
         if t not in [
             NM.SETTING_GSM_SETTING_NAME,
+            NM.SETTING_MACVLAN_SETTING_NAME,
             NM.SETTING_VLAN_SETTING_NAME,
             NM.SETTING_VPN_SETTING_NAME,
             NM.SETTING_WIMAX_SETTING_NAME,
@@ -845,13 +847,14 @@ PRP_DEVICE_DEVICE_TYPE = "DeviceType"
 PRP_DEVICE_AVAILABLE_CONNECTIONS = "AvailableConnections"
 PRP_DEVICE_LLDP_NEIGHBORS = "LldpNeighbors"
 PRP_DEVICE_INTERFACE_FLAGS = "InterfaceFlags"
+PRP_DEVICE_HW_ADDRESS = "HwAddress"
 
 
 class Device(ExportedObj):
     path_counter_next = 1
     path_prefix = "/org/freedesktop/NetworkManager/Devices/"
 
-    def __init__(self, iface, devtype, ident=None):
+    def __init__(self, iface, devtype, ident=None, hwaddr=None):
         if ident is None:
             ident = iface
 
@@ -863,6 +866,7 @@ class Device(ExportedObj):
         self.dhcp4_config = None
         self.dhcp6_config = None
         self.activation_state_change_delay_ms = 50
+        self.hwaddr = hwaddr is None if "" else hwaddr
 
         self.prp_state = NM.DeviceState.UNAVAILABLE
 
@@ -890,6 +894,7 @@ class Device(ExportedObj):
             PRP_DEVICE_DEVICE_TYPE: dbus.UInt32(devtype),
             PRP_DEVICE_AVAILABLE_CONNECTIONS: ExportedObj.to_path_array([]),
             PRP_DEVICE_INTERFACE_FLAGS: dbus.UInt32(3),  # up,lower-up
+            PRP_DEVICE_HW_ADDRESS: dbus.String(self.hwaddr),
             PRP_DEVICE_LLDP_NEIGHBORS: dbus.Array(
                 [
                     dbus.Dictionary(
@@ -1166,10 +1171,11 @@ PRP_WIRED_S390_SUBCHANNELS = "S390Subchannels"
 
 class WiredDevice(Device):
     def __init__(self, iface, mac=None, subchannels=None, ident=None):
-        Device.__init__(self, iface, NM.DeviceType.ETHERNET, ident)
-
         if mac is None:
-            mac = Util.random_mac(self.ident)
+            mac = Util.random_mac(iface if ident is None else ident)
+
+        Device.__init__(self, iface, NM.DeviceType.ETHERNET, ident, hwaddr=mac)
+
         if subchannels is None:
             subchannels = dbus.Array(signature="s")
 
@@ -1206,14 +1212,23 @@ class ModemDevice(Device):
 
 ###############################################################################
 
+
+class MacvlanDevice(Device):
+    def __init__(self, iface, mac=None):
+        Device.__init__(self, iface, NM.DeviceType.MACVLAN, hwaddr=mac)
+        self.dbus_interface_add(IFACE_MACVLAN, {})
+
+
+###############################################################################
+
 PRP_VLAN_HW_ADDRESS = "HwAddress"
 PRP_VLAN_CARRIER = "Carrier"
 PRP_VLAN_VLAN_ID = "VlanId"
 
 
 class VlanDevice(Device):
-    def __init__(self, iface, ident=None):
-        Device.__init__(self, iface, NM.DeviceType.VLAN, ident)
+    def __init__(self, iface, mac=None, ident=None):
+        Device.__init__(self, iface, NM.DeviceType.VLAN, ident, hwaddr=mac)
 
         props = {
             PRP_VLAN_HW_ADDRESS: Util.random_mac(self.ident),
@@ -1313,10 +1328,10 @@ PRP_WIFI_LAST_SCAN = "LastScan"
 
 class WifiDevice(Device):
     def __init__(self, iface, mac=None, ident=None):
-        Device.__init__(self, iface, NM.DeviceType.WIFI, ident)
-
         if mac is None:
-            mac = Util.random_mac(self.ident)
+            mac = Util.random_mac(iface if ident is None else ident)
+
+        Device.__init__(self, iface, NM.DeviceType.WIFI, ident, hwaddr=mac)
 
         self.aps = []
         self.scan_cb_id = None
@@ -1651,30 +1666,16 @@ class NetworkManager(ExportedObj):
             raise BusErr.UnknownConnectionException("Connection not found")
 
         con_hash = con_inst.con_hash
-        con_type = NmUtil.con_hash_get_type(con_hash)
 
-        device = self.find_device_first(path=devpath)
-        if not device:
-            if con_type == NM.SETTING_WIRED_SETTING_NAME:
-                device = self.find_device_first(dev_type=WiredDevice)
-            elif con_type == NM.SETTING_WIRELESS_SETTING_NAME:
-                device = self.find_device_first(dev_type=WifiDevice)
-            elif con_type == NM.SETTING_VLAN_SETTING_NAME:
-                ifname = con_hash[NM.SETTING_CONNECTION_SETTING_NAME]["interface-name"]
-                device = VlanDevice(ifname)
+        device = self.find_device(devpath, con_hash)
+        if device is None:
+            device = self.create_device(con_hash)
+            if device:
+                # Just created the device, it can start activating right away
+                device.activation_state_change_delay_ms = 0
                 self.add_device(device)
-            elif con_type == NM.SETTING_VPN_SETTING_NAME:
-                for ac in self.active_connections:
-                    if ac.is_vpn:
-                        continue
-                    if ac.device:
-                        device = ac.device
-                        break
-
-        if not device:
-            raise BusErr.UnknownDeviceException(
-                "No device found for the requested iface."
-            )
+        if device is None:
+            raise BusErr.UnknownDeviceException("Device not found")
 
         # See if we need secrets. For the moment, we only support WPA
         if "802-11-wireless-security" in con_hash:
@@ -1733,11 +1734,16 @@ class NetworkManager(ExportedObj):
         out_signature="ooa{sv}",
     )
     def AddAndActivateConnection2(self, con_hash, devpath, specific_object, options):
-        device = self.find_device_first(
-            path=devpath, require=BusErr.UnknownDeviceException
-        )
-        conpath = gl.settings.AddConnection(con_hash)
-        return (conpath, self.ActivateConnection(conpath, devpath, specific_object), [])
+        conpath = gl.settings.add_connection(con_hash)
+        try:
+            return (
+                conpath,
+                self.ActivateConnection(conpath, devpath, specific_object),
+                [],
+            )
+        except:
+            gl.settings.delete_connection(conpath)
+            raise
 
     @dbus.service.method(dbus_interface=IFACE_NM, in_signature="o", out_signature="")
     def DeactivateConnection(self, active_connection):
@@ -1807,6 +1813,7 @@ class NetworkManager(ExportedObj):
         iface=_DEFAULT_ARG,
         ip_iface=_DEFAULT_ARG,
         dev_type=_DEFAULT_ARG,
+        hwaddr=_DEFAULT_ARG,
     ):
         r = None
         for d in self.devices:
@@ -1826,6 +1833,9 @@ class NetworkManager(ExportedObj):
             if dev_type is not _DEFAULT_ARG:
                 if not isinstance(d, dev_type):
                     continue
+            if hwaddr is not _DEFAULT_ARG:
+                if d.hwaddr.lower() != hwaddr.lower():
+                    continue
             yield d
 
     def find_device_first(
@@ -1835,11 +1845,17 @@ class NetworkManager(ExportedObj):
         iface=_DEFAULT_ARG,
         ip_iface=_DEFAULT_ARG,
         dev_type=_DEFAULT_ARG,
+        hwaddr=_DEFAULT_ARG,
         require=None,
     ):
         r = None
         for d in self.find_devices(
-            ident=ident, path=path, iface=iface, ip_iface=ip_iface, dev_type=dev_type
+            ident=ident,
+            path=path,
+            iface=iface,
+            ip_iface=ip_iface,
+            dev_type=dev_type,
+            hwaddr=hwaddr,
         ):
             r = d
             break
@@ -1849,6 +1865,107 @@ class NetworkManager(ExportedObj):
             raise BusErr.UnknownDeviceException("Device not found")
         return r
 
+    def find_device(self, devpath, con_hash):
+        device = self.find_device_first(path=devpath)
+        if device:
+            return device
+
+        con_type = NmUtil.con_hash_get_type(con_hash)
+
+        if con_type == NM.SETTING_WIRED_SETTING_NAME:
+            return self.find_device_first(dev_type=WiredDevice)
+
+        if con_type == NM.SETTING_WIRELESS_SETTING_NAME:
+            return self.find_device_first(dev_type=WifiDevice)
+
+        if con_type == NM.SETTING_VPN_SETTING_NAME:
+            for ac in self.active_connections:
+                if ac.is_vpn:
+                    continue
+                if ac.device:
+                    return ac.device
+
+        return None
+
+    def create_device(self, con_hash):
+        con_type = NmUtil.con_hash_get_type(con_hash)
+
+        if con_type == NM.SETTING_VLAN_SETTING_NAME:
+            iface = con_hash[NM.SETTING_CONNECTION_SETTING_NAME].get("interface-name")
+            parent_iface = con_hash[NM.SETTING_VLAN_SETTING_NAME].get("parent")
+
+            if NM.SETTING_WIRED_SETTING_NAME in con_hash:
+                mac = con_hash[NM.SETTING_WIRED_SETTING_NAME].get("mac-address")
+            else:
+                mac = None
+            if mac is not None:
+                parent_hwaddr = "%02X:%02X:%02X:%02X:%02X:%02X" % (
+                    mac[0],
+                    mac[1],
+                    mac[2],
+                    mac[3],
+                    mac[4],
+                    mac[5],
+                )
+            else:
+                parent_hwaddr = _DEFAULT_ARG
+
+            parent_ident = parent_iface if parent_iface is not None else _DEFAULT_ARG
+            parent_device = self.find_device_first(
+                dev_type=WiredDevice, hwaddr=parent_hwaddr, ident=parent_ident
+            )
+            if parent_device is None:
+                parent_device = self.find_device_first(
+                    dev_type=MacvlanDevice, hwaddr=parent_hwaddr, ident=parent_ident
+                )
+            if parent_device is None:
+                raise BusErr.UnknownDeviceException("Parent device not found")
+
+            if parent_hwaddr is None:
+                parent_hwaddr = parent_device.hwaddr
+
+            if NM.SETTING_WIRED_SETTING_NAME in con_hash:
+                mac = con_hash[NM.SETTING_WIRED_SETTING_NAME].get("cloned-mac-address")
+            else:
+                mac = None
+            if mac is not None:
+                hwaddr = "%02X:%02X:%02X:%02X:%02X:%02X" % (
+                    mac[0],
+                    mac[1],
+                    mac[2],
+                    mac[3],
+                    mac[4],
+                    mac[5],
+                )
+            else:
+                hwaddr = None
+
+            if parent_iface is None:
+                parent_iface = parent_device.ident
+
+            if iface is None:
+                iface = "%s.%d" % (
+                    parent_iface,
+                    con_hash[NM.SETTING_VLAN_SETTING_NAME]["id"],
+                )
+
+            return VlanDevice(iface, mac=hwaddr)
+
+        if con_type == NM.SETTING_MACVLAN_SETTING_NAME:
+            ifname = con_hash[NM.SETTING_CONNECTION_SETTING_NAME]["interface-name"]
+            mac = con_hash[NM.SETTING_WIRED_SETTING_NAME]["cloned-mac-address"]
+            hwaddr = "%02X:%02X:%02X:%02X:%02X:%02X" % (
+                mac[0],
+                mac[1],
+                mac[2],
+                mac[3],
+                mac[4],
+                mac[5],
+            )
+            return MacvlanDevice(ifname, hwaddr)
+
+        return None
+
     def add_device(self, device):
         if self.find_device_first(ident=device.ident, path=device.path) is not None:
             raise TestError(
@@ -2135,7 +2252,7 @@ class Connection(ExportedObj):
         dbus_interface=IFACE_CONNECTION, in_signature="", out_signature=""
     )
     def Delete(self):
-        gl.settings.delete_connection(self)
+        gl.settings.delete_connection(self.path)
 
     @dbus.service.method(
         dbus_interface=IFACE_CONNECTION, in_signature="a{sa{sv}}", out_signature=""
@@ -2267,7 +2384,7 @@ class Settings(ExportedObj):
             def cb():
                 if hasattr(con_inst, "_remove_next_connection_cb"):
                     del con_inst._remove_next_connection_cb
-                    self.delete_connection(con_inst)
+                    self.delete_connection(con_inst.path)
                 return False
 
             # We will delete the connection right away on an idle handler. However,
@@ -2284,8 +2401,9 @@ class Settings(ExportedObj):
             raise BusErr.UnknownConnectionException("Connection not found")
         self.connections[path].update_connection(con_hash, do_verify_strict)
 
-    def delete_connection(self, con_inst):
-        del self.connections[con_inst.path]
+    def delete_connection(self, path):
+        con_inst = self.get_connection(path)
+        del self.connections[path]
         self._dbus_property_set(
             IFACE_SETTINGS,
             PRP_SETTINGS_CONNECTIONS,