about summary refs log tree commit diff
path: root/examples
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2021-02-11 18:11:46 +0100
committerMichael Biebl <biebl@debian.org>2021-02-11 18:11:46 +0100
commit80ec1decc49c72efec2a8b87c06245c92c0ab807 (patch)
treee3b229aa94e8dcf0590f2317664176e7b8f7607b /examples
parent65f86e8f56267192d42f2b629fc6b0c99fb9cd0c (diff)
New upstream version 1.29.90 upstream/1.29.90
Diffstat (limited to 'examples')
-rw-r--r--examples/C/glib/add-connection-gdbus.c2
-rw-r--r--examples/C/glib/add-connection-libnm.c2
-rw-r--r--examples/C/glib/get-active-connections-gdbus.c2
-rw-r--r--examples/C/glib/get-ap-info-libnm.c2
-rw-r--r--examples/C/glib/list-connections-gdbus.c2
-rw-r--r--examples/C/glib/list-connections-libnm.c2
-rw-r--r--examples/C/glib/meson.build2
-rw-r--r--examples/C/glib/monitor-nm-running-gdbus.c2
-rw-r--r--examples/C/glib/monitor-nm-state-gdbus.c2
-rw-r--r--examples/C/qt/add-connection-wired.cpp2
-rw-r--r--examples/C/qt/change-ipv4-addresses.cpp2
-rw-r--r--examples/C/qt/list-connections.cpp2
-rw-r--r--examples/C/qt/meson.build2
-rw-r--r--examples/C/qt/monitor-nm-running.cpp2
-rwxr-xr-xexamples/js/get_ips.js2
-rwxr-xr-xexamples/lua/lgi/add-connection.lua2
-rwxr-xr-xexamples/lua/lgi/change-vpn-username.lua2
-rwxr-xr-xexamples/lua/lgi/deactivate-all.lua2
-rwxr-xr-xexamples/lua/lgi/get-basic-nm-info.lua2
-rwxr-xr-xexamples/lua/lgi/get-ips.lua2
-rwxr-xr-xexamples/lua/lgi/list-connections.lua2
-rwxr-xr-xexamples/lua/lgi/list-devices.lua2
-rwxr-xr-xexamples/lua/lgi/show-wifi-networks.lua2
-rwxr-xr-xexamples/python/dbus/add-connection-compat.py2
-rwxr-xr-xexamples/python/dbus/add-connection.py2
-rwxr-xr-xexamples/python/dbus/add-wifi-eap-connection.py2
-rwxr-xr-xexamples/python/dbus/add-wifi-psk-connection.py6
-rwxr-xr-xexamples/python/dbus/create-bond.py2
-rwxr-xr-xexamples/python/dbus/disconnect-device.py2
-rwxr-xr-xexamples/python/dbus/get-active-connection-uuids.py2
-rwxr-xr-xexamples/python/dbus/is-wwan-default.py2
-rwxr-xr-xexamples/python/dbus/list-connections.py2
-rwxr-xr-xexamples/python/dbus/list-devices.py2
-rwxr-xr-xexamples/python/dbus/nm-state.py2
-rwxr-xr-xexamples/python/dbus/show-bssids.py9
-rwxr-xr-xexamples/python/dbus/update-ip4-method.py2
-rwxr-xr-xexamples/python/dbus/update-secrets.py2
-rwxr-xr-xexamples/python/dbus/vpn.py2
-rwxr-xr-xexamples/python/dbus/wifi-active-ap.py2
-rwxr-xr-xexamples/python/dbus/wifi-hotspot.py2
-rwxr-xr-xexamples/python/gi/add_connection.py2
-rwxr-xr-xexamples/python/gi/deactivate-all.py2
-rwxr-xr-xexamples/python/gi/device-state-ip4config.py2
-rwxr-xr-xexamples/python/gi/firewall-zone.py2
-rwxr-xr-xexamples/python/gi/get-active-connections.py2
-rwxr-xr-xexamples/python/gi/get_ips.py2
-rwxr-xr-xexamples/python/gi/list-connections.py2
-rwxr-xr-xexamples/python/gi/nm-add-connection2.py2
-rwxr-xr-xexamples/python/gi/nm-connection-update-stable-id.py2
-rwxr-xr-xexamples/python/gi/nm-keyfile.py139
-rwxr-xr-xexamples/python/gi/nm-update2.py2
-rwxr-xr-xexamples/python/gi/nm-wg-set2
-rwxr-xr-xexamples/python/gi/ovs-external-ids.py663
-rwxr-xr-xexamples/python/gi/setting-user-data.py2
-rwxr-xr-xexamples/python/gi/show-wifi-networks.py3
-rwxr-xr-xexamples/python/gi/update-ip4-method.py2
-rwxr-xr-xexamples/ruby/add-connection.rb2
-rwxr-xr-xexamples/ruby/get-basic-nm-info.rb2
-rwxr-xr-xexamples/ruby/list-devices.rb2
-rwxr-xr-xexamples/shell/active-wifi.sh2
-rwxr-xr-xexamples/shell/disconnect-device.sh2
-rwxr-xr-xexamples/shell/get-hostname.sh2
-rwxr-xr-xexamples/shell/list-devices.sh2
-rwxr-xr-xexamples/shell/nm-logging.sh2
64 files changed, 872 insertions, 66 deletions
diff --git a/examples/C/glib/add-connection-gdbus.c b/examples/C/glib/add-connection-gdbus.c
index 3e3f67ce..6dc3b8d4 100644
--- a/examples/C/glib/add-connection-gdbus.c
+++ b/examples/C/glib/add-connection-gdbus.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
  * Copyright (C) 2011, 2014 Red Hat, Inc.
  */
diff --git a/examples/C/glib/add-connection-libnm.c b/examples/C/glib/add-connection-libnm.c
index 510ea4a2..6e4cd6b8 100644
--- a/examples/C/glib/add-connection-libnm.c
+++ b/examples/C/glib/add-connection-libnm.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
  * Copyright (C) 2011 Red Hat, Inc.
  */
diff --git a/examples/C/glib/get-active-connections-gdbus.c b/examples/C/glib/get-active-connections-gdbus.c
index e3edb429..c07b0f15 100644
--- a/examples/C/glib/get-active-connections-gdbus.c
+++ b/examples/C/glib/get-active-connections-gdbus.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
  * Copyright (C) 2010 - 2014 Red Hat, Inc.
  */
diff --git a/examples/C/glib/get-ap-info-libnm.c b/examples/C/glib/get-ap-info-libnm.c
index f2bcdf9d..247ab8f1 100644
--- a/examples/C/glib/get-ap-info-libnm.c
+++ b/examples/C/glib/get-ap-info-libnm.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
  * Copyright (C) 2010 Red Hat, Inc.
  */
diff --git a/examples/C/glib/list-connections-gdbus.c b/examples/C/glib/list-connections-gdbus.c
index 84fcf0bd..babf6f14 100644
--- a/examples/C/glib/list-connections-gdbus.c
+++ b/examples/C/glib/list-connections-gdbus.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
  * Copyright (C) 2011, 2014 Red Hat, Inc.
  */
diff --git a/examples/C/glib/list-connections-libnm.c b/examples/C/glib/list-connections-libnm.c
index 39affb4c..0cee2f7b 100644
--- a/examples/C/glib/list-connections-libnm.c
+++ b/examples/C/glib/list-connections-libnm.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
  * Copyright (C) 2011 Red Hat, Inc.
  */
diff --git a/examples/C/glib/meson.build b/examples/C/glib/meson.build
index 8eac711c..41c46ca8 100644
--- a/examples/C/glib/meson.build
+++ b/examples/C/glib/meson.build
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: LGPL-2.1+
+# SPDX-License-Identifier: LGPL-2.1-or-later
 
 examples = [
   ['add-connection-gdbus', [libnm_enum_sources[1]], [uuid_dep]],
diff --git a/examples/C/glib/monitor-nm-running-gdbus.c b/examples/C/glib/monitor-nm-running-gdbus.c
index e38fb533..11eddce8 100644
--- a/examples/C/glib/monitor-nm-running-gdbus.c
+++ b/examples/C/glib/monitor-nm-running-gdbus.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
  * Copyright (C) 2012 Red Hat, Inc.
  */
diff --git a/examples/C/glib/monitor-nm-state-gdbus.c b/examples/C/glib/monitor-nm-state-gdbus.c
index 43259dd0..5e938f2b 100644
--- a/examples/C/glib/monitor-nm-state-gdbus.c
+++ b/examples/C/glib/monitor-nm-state-gdbus.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
  * Copyright (C) 2012 Red Hat, Inc.
  */
diff --git a/examples/C/qt/add-connection-wired.cpp b/examples/C/qt/add-connection-wired.cpp
index f9df13bc..85d796d4 100644
--- a/examples/C/qt/add-connection-wired.cpp
+++ b/examples/C/qt/add-connection-wired.cpp
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
  * Copyright (C) 2011 Eckhart Wörner
  */
diff --git a/examples/C/qt/change-ipv4-addresses.cpp b/examples/C/qt/change-ipv4-addresses.cpp
index 059e2b4a..43fc9d65 100644
--- a/examples/C/qt/change-ipv4-addresses.cpp
+++ b/examples/C/qt/change-ipv4-addresses.cpp
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
  * Copyright (C) 2011 Red Hat, Inc.
  */
diff --git a/examples/C/qt/list-connections.cpp b/examples/C/qt/list-connections.cpp
index 39293ebc..0a3697cf 100644
--- a/examples/C/qt/list-connections.cpp
+++ b/examples/C/qt/list-connections.cpp
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
  * Copyright (C) 2011 Eckhart Wörner
  */
diff --git a/examples/C/qt/meson.build b/examples/C/qt/meson.build
index 87f60f5f..7e4e1274 100644
--- a/examples/C/qt/meson.build
+++ b/examples/C/qt/meson.build
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: LGPL-2.1+
+# SPDX-License-Identifier: LGPL-2.1-or-later
 
 examples = [
   ['add-connection-wired', []],
diff --git a/examples/C/qt/monitor-nm-running.cpp b/examples/C/qt/monitor-nm-running.cpp
index db3ec07b..15bf3edf 100644
--- a/examples/C/qt/monitor-nm-running.cpp
+++ b/examples/C/qt/monitor-nm-running.cpp
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*
  * Copyright (C) 2012 Red Hat, Inc.
  */
diff --git a/examples/js/get_ips.js b/examples/js/get_ips.js
index 7d3c436e..4e64eefc 100755
--- a/examples/js/get_ips.js
+++ b/examples/js/get_ips.js
@@ -1,5 +1,5 @@
 #!/usr/bin/env gjs
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * Copyright (C) 2014, 2017 Red Hat, Inc.
  */
diff --git a/examples/lua/lgi/add-connection.lua b/examples/lua/lgi/add-connection.lua
index 14871aa4..11be01dd 100755
--- a/examples/lua/lgi/add-connection.lua
+++ b/examples/lua/lgi/add-connection.lua
@@ -1,5 +1,5 @@
 #!/usr/bin/env lua
--- SPDX-License-Identifier: GPL-2.0+
+-- SPDX-License-Identifier: GPL-2.0-or-later
 --
 -- Copyright (C) 2015 Red Hat, Inc.
 --
diff --git a/examples/lua/lgi/change-vpn-username.lua b/examples/lua/lgi/change-vpn-username.lua
index 3b607c05..538658d8 100755
--- a/examples/lua/lgi/change-vpn-username.lua
+++ b/examples/lua/lgi/change-vpn-username.lua
@@ -1,5 +1,5 @@
 #!/usr/bin/env lua
--- SPDX-License-Identifier: GPL-2.0+
+-- SPDX-License-Identifier: GPL-2.0-or-later
 --
 -- Copyright (C) 2015 Red Hat, Inc.
 --
diff --git a/examples/lua/lgi/deactivate-all.lua b/examples/lua/lgi/deactivate-all.lua
index 6d53956d..b535f121 100755
--- a/examples/lua/lgi/deactivate-all.lua
+++ b/examples/lua/lgi/deactivate-all.lua
@@ -1,5 +1,5 @@
 #!/usr/bin/env lua
--- SPDX-License-Identifier: GPL-2.0+
+-- SPDX-License-Identifier: GPL-2.0-or-later
 --
 -- Copyright (C) 2015 Red Hat, Inc.
 --
diff --git a/examples/lua/lgi/get-basic-nm-info.lua b/examples/lua/lgi/get-basic-nm-info.lua
index 5c99461d..8d9ae755 100755
--- a/examples/lua/lgi/get-basic-nm-info.lua
+++ b/examples/lua/lgi/get-basic-nm-info.lua
@@ -1,5 +1,5 @@
 #!/usr/bin/env lua
--- SPDX-License-Identifier: GPL-2.0+
+-- SPDX-License-Identifier: GPL-2.0-or-later
 --
 -- Copyright (C) 2015 Red Hat, Inc.
 --
diff --git a/examples/lua/lgi/get-ips.lua b/examples/lua/lgi/get-ips.lua
index 916dcea0..7e174c4d 100755
--- a/examples/lua/lgi/get-ips.lua
+++ b/examples/lua/lgi/get-ips.lua
@@ -1,5 +1,5 @@
 #!/usr/bin/env lua
--- SPDX-License-Identifier: GPL-2.0+
+-- SPDX-License-Identifier: GPL-2.0-or-later
 --
 -- Copyright (C) 2015 Red Hat, Inc.
 --
diff --git a/examples/lua/lgi/list-connections.lua b/examples/lua/lgi/list-connections.lua
index fc62e12d..b011641f 100755
--- a/examples/lua/lgi/list-connections.lua
+++ b/examples/lua/lgi/list-connections.lua
@@ -1,5 +1,5 @@
 #!/usr/bin/env lua
--- SPDX-License-Identifier: GPL-2.0+
+-- SPDX-License-Identifier: GPL-2.0-or-later
 --
 -- Copyright (C) 2015 Red Hat, Inc.
 --
diff --git a/examples/lua/lgi/list-devices.lua b/examples/lua/lgi/list-devices.lua
index 35023453..aca5de64 100755
--- a/examples/lua/lgi/list-devices.lua
+++ b/examples/lua/lgi/list-devices.lua
@@ -1,5 +1,5 @@
 #!/usr/bin/env lua
--- SPDX-License-Identifier: GPL-2.0+
+-- SPDX-License-Identifier: GPL-2.0-or-later
 --
 -- Copyright (C) 2015 Red Hat, Inc.
 --
diff --git a/examples/lua/lgi/show-wifi-networks.lua b/examples/lua/lgi/show-wifi-networks.lua
index 8fecc741..9438a4d9 100755
--- a/examples/lua/lgi/show-wifi-networks.lua
+++ b/examples/lua/lgi/show-wifi-networks.lua
@@ -1,5 +1,5 @@
 #!/usr/bin/env lua
--- SPDX-License-Identifier: GPL-2.0+
+-- SPDX-License-Identifier: GPL-2.0-or-later
 --
 -- Copyright (C) 2015 Red Hat, Inc.
 --
diff --git a/examples/python/dbus/add-connection-compat.py b/examples/python/dbus/add-connection-compat.py
index 2661eccb..d5218514 100755
--- a/examples/python/dbus/add-connection-compat.py
+++ b/examples/python/dbus/add-connection-compat.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2010 - 2012 Red Hat, Inc.
 #
diff --git a/examples/python/dbus/add-connection.py b/examples/python/dbus/add-connection.py
index a7c8947c..cfb46de2 100755
--- a/examples/python/dbus/add-connection.py
+++ b/examples/python/dbus/add-connection.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2010 - 2012 Red Hat, Inc.
 #
diff --git a/examples/python/dbus/add-wifi-eap-connection.py b/examples/python/dbus/add-wifi-eap-connection.py
index 23962e76..8ed80f72 100755
--- a/examples/python/dbus/add-wifi-eap-connection.py
+++ b/examples/python/dbus/add-wifi-eap-connection.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2011 Red Hat, Inc.
 #
diff --git a/examples/python/dbus/add-wifi-psk-connection.py b/examples/python/dbus/add-wifi-psk-connection.py
index 66d42e82..c9a4ceed 100755
--- a/examples/python/dbus/add-wifi-psk-connection.py
+++ b/examples/python/dbus/add-wifi-psk-connection.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2015 Red Hat, Inc.
 #
@@ -11,11 +11,11 @@ s_con = dbus.Dictionary(
 )
 
 s_wifi = dbus.Dictionary(
-    {"ssid": dbus.ByteArray("best-wifi".encode("utf-8")), "mode": "infrastructure",}
+    {"ssid": dbus.ByteArray("best-wifi".encode("utf-8")), "mode": "infrastructure"}
 )
 
 s_wsec = dbus.Dictionary(
-    {"key-mgmt": "wpa-psk", "auth-alg": "open", "psk": "super-secret-password",}
+    {"key-mgmt": "wpa-psk", "auth-alg": "open", "psk": "super-secret-password"}
 )
 
 s_ip4 = dbus.Dictionary({"method": "auto"})
diff --git a/examples/python/dbus/create-bond.py b/examples/python/dbus/create-bond.py
index 77c2ece4..4ebec24a 100755
--- a/examples/python/dbus/create-bond.py
+++ b/examples/python/dbus/create-bond.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2015 Red Hat, Inc.
 #
diff --git a/examples/python/dbus/disconnect-device.py b/examples/python/dbus/disconnect-device.py
index 1b257025..d44eb1bd 100755
--- a/examples/python/dbus/disconnect-device.py
+++ b/examples/python/dbus/disconnect-device.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2010 Red Hat, Inc.
 #
diff --git a/examples/python/dbus/get-active-connection-uuids.py b/examples/python/dbus/get-active-connection-uuids.py
index 3e80b603..1ba156b6 100755
--- a/examples/python/dbus/get-active-connection-uuids.py
+++ b/examples/python/dbus/get-active-connection-uuids.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2010 Red Hat, Inc.
 #
diff --git a/examples/python/dbus/is-wwan-default.py b/examples/python/dbus/is-wwan-default.py
index 18279db0..749b71b3 100755
--- a/examples/python/dbus/is-wwan-default.py
+++ b/examples/python/dbus/is-wwan-default.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2011 - 2012 Red Hat, Inc.
 #
diff --git a/examples/python/dbus/list-connections.py b/examples/python/dbus/list-connections.py
index 81b32896..c5381b69 100755
--- a/examples/python/dbus/list-connections.py
+++ b/examples/python/dbus/list-connections.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2010 - 2011 Red Hat, Inc.
 #
diff --git a/examples/python/dbus/list-devices.py b/examples/python/dbus/list-devices.py
index 910bc461..17654f38 100755
--- a/examples/python/dbus/list-devices.py
+++ b/examples/python/dbus/list-devices.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2011 - 2012 Red Hat, Inc.
 #
diff --git a/examples/python/dbus/nm-state.py b/examples/python/dbus/nm-state.py
index 4bc9285e..27e99e27 100755
--- a/examples/python/dbus/nm-state.py
+++ b/examples/python/dbus/nm-state.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2010 - 2012 Red Hat, Inc.
 #
diff --git a/examples/python/dbus/show-bssids.py b/examples/python/dbus/show-bssids.py
index b56822fb..17364e49 100755
--- a/examples/python/dbus/show-bssids.py
+++ b/examples/python/dbus/show-bssids.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2010 Red Hat, Inc.
 #
@@ -7,6 +7,11 @@
 # This example prints out all the AP BSSIDs that all Wi-Fi devices on the
 # machine can see.  Useful for location-based services like Skyhook that
 # can geolocate you based on the APs you can see.
+#
+# Note that with NetworkManager clients are required to request scanning.
+# If you don't do that, the scan list may be outdated. That means, you would
+# check the LastScan property, and if necessary call RequestScan() first.
+# After RequestScan(), you wait until the LastScan property gets bumped again.
 
 import dbus
 
@@ -30,7 +35,7 @@ for d in devices:
 
     # Make sure the device is enabled before we try to use it
     state = prop_iface.Get("org.freedesktop.NetworkManager.Device", "State")
-    if state <= 2:
+    if state <= 20:  # NM_DEVICE_STATE_UNAVAILABLE
         continue
 
     # Get device's type; we only want wifi devices
diff --git a/examples/python/dbus/update-ip4-method.py b/examples/python/dbus/update-ip4-method.py
index 98927903..d84e01b2 100755
--- a/examples/python/dbus/update-ip4-method.py
+++ b/examples/python/dbus/update-ip4-method.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2014 Red Hat, Inc.
 #
diff --git a/examples/python/dbus/update-secrets.py b/examples/python/dbus/update-secrets.py
index 5df25e5c..ce69cb9a 100755
--- a/examples/python/dbus/update-secrets.py
+++ b/examples/python/dbus/update-secrets.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2011 - 2012 Red Hat, Inc.
 #
diff --git a/examples/python/dbus/vpn.py b/examples/python/dbus/vpn.py
index 814e4415..f86bf1ad 100755
--- a/examples/python/dbus/vpn.py
+++ b/examples/python/dbus/vpn.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2009 Novell, Inc.
 # Copyright (C) 2009 Red Hat, Inc.
diff --git a/examples/python/dbus/wifi-active-ap.py b/examples/python/dbus/wifi-active-ap.py
index 33fae0b2..bc8f1ea5 100755
--- a/examples/python/dbus/wifi-active-ap.py
+++ b/examples/python/dbus/wifi-active-ap.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2015 Red Hat, Inc.
 #
diff --git a/examples/python/dbus/wifi-hotspot.py b/examples/python/dbus/wifi-hotspot.py
index 77582b6a..a441e7e9 100755
--- a/examples/python/dbus/wifi-hotspot.py
+++ b/examples/python/dbus/wifi-hotspot.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2010 - 2012 Red Hat, Inc.
 #
diff --git a/examples/python/gi/add_connection.py b/examples/python/gi/add_connection.py
index ac537ead..e6e1d5a6 100755
--- a/examples/python/gi/add_connection.py
+++ b/examples/python/gi/add_connection.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2014 Red Hat, Inc.
 #
diff --git a/examples/python/gi/deactivate-all.py b/examples/python/gi/deactivate-all.py
index cc181dd9..bb590b23 100755
--- a/examples/python/gi/deactivate-all.py
+++ b/examples/python/gi/deactivate-all.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2015 Red Hat, Inc.
 #
diff --git a/examples/python/gi/device-state-ip4config.py b/examples/python/gi/device-state-ip4config.py
index 038b8a72..6ad882c1 100755
--- a/examples/python/gi/device-state-ip4config.py
+++ b/examples/python/gi/device-state-ip4config.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2012 Red Hat, Inc.
 #
diff --git a/examples/python/gi/firewall-zone.py b/examples/python/gi/firewall-zone.py
index 3de06f52..e3ee2511 100755
--- a/examples/python/gi/firewall-zone.py
+++ b/examples/python/gi/firewall-zone.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2013 - 2014 Red Hat, Inc.
 #
diff --git a/examples/python/gi/get-active-connections.py b/examples/python/gi/get-active-connections.py
index c2f261ab..aedfad6f 100755
--- a/examples/python/gi/get-active-connections.py
+++ b/examples/python/gi/get-active-connections.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2014 Red Hat, Inc.
 #
diff --git a/examples/python/gi/get_ips.py b/examples/python/gi/get_ips.py
index 07d6f0cc..e4276ab9 100755
--- a/examples/python/gi/get_ips.py
+++ b/examples/python/gi/get_ips.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2014 Red Hat, Inc.
 #
diff --git a/examples/python/gi/list-connections.py b/examples/python/gi/list-connections.py
index ba4f50e2..d3a74d5a 100755
--- a/examples/python/gi/list-connections.py
+++ b/examples/python/gi/list-connections.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2012 - 2014 Red Hat, Inc.
 #
diff --git a/examples/python/gi/nm-add-connection2.py b/examples/python/gi/nm-add-connection2.py
index f487e0bb..2cd760a2 100755
--- a/examples/python/gi/nm-add-connection2.py
+++ b/examples/python/gi/nm-add-connection2.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2019 Red Hat, Inc.
 #
diff --git a/examples/python/gi/nm-connection-update-stable-id.py b/examples/python/gi/nm-connection-update-stable-id.py
index 091a67d6..05926f40 100755
--- a/examples/python/gi/nm-connection-update-stable-id.py
+++ b/examples/python/gi/nm-connection-update-stable-id.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2017 Red Hat, Inc.
 #
diff --git a/examples/python/gi/nm-keyfile.py b/examples/python/gi/nm-keyfile.py
new file mode 100755
index 00000000..3a467d43
--- /dev/null
+++ b/examples/python/gi/nm-keyfile.py
@@ -0,0 +1,139 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+import sys
+import os
+
+import gi
+
+gi.require_version("NM", "1.0")
+from gi.repository import NM, GLib
+
+###############################################################################
+
+
+def kf_load_from_file(filename):
+    kf = GLib.KeyFile.new()
+    kf.load_from_file(filename, GLib.KeyFileFlags.NONE)
+    return kf
+
+
+def kf_to_string(kf):
+    d, l = kf.to_data()
+    return d
+
+
+def debug(message):
+    if os.getenv("DEBUG") == "1":
+        print(">>> %s" % (message))
+
+
+###############################################################################
+
+filename = sys.argv[1]
+base_dir = os.path.dirname(os.path.realpath(filename))
+
+kf = kf_load_from_file(filename)
+
+print('> keyfile "%s":' % (filename))
+print(">>\n%s\n<<" % (kf_to_string(kf)))
+
+###############################################################################
+
+
+def kf_handler_read(keyfile, connection, handler_type, handler_data, user_data):
+    kf_handler_read_cnt = globals().get("kf_handler_read_cnt", 0) + 1
+    globals()["kf_handler_read_cnt"] = kf_handler_read_cnt
+
+    [kf_group, kf_key, cur_setting, cur_property] = handler_data.get_context()
+
+    debug("kf_handler_read(%s): keyfile=%r" % (kf_handler_read_cnt, keyfile))
+    debug("kf_handler_read(%s): connection=%r" % (kf_handler_read_cnt, connection))
+    debug("kf_handler_read(%s): handler-type=%r" % (kf_handler_read_cnt, handler_type))
+    debug("kf_handler_read(%s): handler-data=%r" % (kf_handler_read_cnt, handler_data))
+    debug("kf_handler_read(%s): user-data=%r" % (kf_handler_read_cnt, user_data))
+    debug("kf_handler_read(%s): kf-group=%r" % (kf_handler_read_cnt, kf_group))
+    debug("kf_handler_read(%s): kf-key=%r" % (kf_handler_read_cnt, kf_key))
+    debug("kf_handler_read(%s): kf-setting=%r" % (kf_handler_read_cnt, cur_setting))
+    debug("kf_handler_read(%s): kf-property=%r" % (kf_handler_read_cnt, cur_property))
+
+    if handler_type == NM.KeyfileHandlerType.WARN:
+        [message, severity] = handler_data.warn_get()
+        debug('parse-warning: <%s> = "%s"' % (severity, message))
+        print("> warning: %s" % (message))
+        return False
+
+    if handler_type == NM.KeyfileHandlerType.WRITE_CERT:
+        # just to show how to abort the parsing. This event won't happen
+        # for read.
+        handler_data.fail_with_error(
+            GLib.GError.new_literal(
+                NM.ConnectionError.quark(), "hallo1", NM.ConnectionError.MISSINGPROPERTY
+            )
+        )
+
+    # don't handle unknown handler types.
+    return False
+
+
+try:
+    print("parse keyfile...")
+    c = NM.keyfile_read(kf, base_dir, NM.KeyfileHandlerFlags.NONE, kf_handler_read, 42)
+except Exception as e:
+    print("parsing failed: %r" % (e))
+    raise
+
+verify_failure = None
+try:
+    c.verify()
+except Exception as e:
+    verify_failure = e.message
+
+print(
+    'parsing succeeded: "%s" (%s)%s'
+    % (
+        c.get_id(),
+        c.get_uuid(),
+        " (invalid: " + verify_failure + ")" if verify_failure is not None else "",
+    )
+)
+
+
+###############################################################################
+
+
+def kf_handler_write(connection, keyfile, handler_type, handler_data, user_data):
+    kf_handler_write_cnt = globals().get("kf_handler_write_cnt", 0) + 1
+    globals()["kf_handler_write_cnt"] = kf_handler_write_cnt
+
+    [kf_group, kf_key, cur_setting, cur_property] = handler_data.get_context()
+
+    debug("kf_handler_write(%s): keyfile=%r" % (kf_handler_write_cnt, keyfile))
+    debug("kf_handler_write(%s): connection=%r" % (kf_handler_write_cnt, connection))
+    debug(
+        "kf_handler_write(%s): handler-type=%r" % (kf_handler_write_cnt, handler_type)
+    )
+    debug(
+        "kf_handler_write(%s): handler-data=%r" % (kf_handler_write_cnt, handler_data)
+    )
+    debug("kf_handler_write(%s): user-data=%r" % (kf_handler_write_cnt, user_data))
+    debug("kf_handler_write(%s): kf-group=%r" % (kf_handler_write_cnt, kf_group))
+    debug("kf_handler_write(%s): kf-key=%r" % (kf_handler_write_cnt, kf_key))
+    debug("kf_handler_write(%s): kf-setting=%r" % (kf_handler_write_cnt, cur_setting))
+    debug("kf_handler_write(%s): kf-property=%r" % (kf_handler_write_cnt, cur_property))
+
+    if handler_type == NM.KeyfileHandlerType.WRITE_CERT:
+        return False
+    return False
+
+
+try:
+    print("")
+    print("write keyfile...")
+    kf2 = NM.keyfile_write(c, NM.KeyfileHandlerFlags.NONE, kf_handler_write, 43)
+except Exception as e:
+    print("write failed: %r" % (e))
+    raise
+
+print("persisted again:")
+print(">>\n%s\n<<" % (kf_to_string(kf2)))
diff --git a/examples/python/gi/nm-update2.py b/examples/python/gi/nm-update2.py
index 192768ee..9d272ead 100755
--- a/examples/python/gi/nm-update2.py
+++ b/examples/python/gi/nm-update2.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2019 Red Hat, Inc.
 #
diff --git a/examples/python/gi/nm-wg-set b/examples/python/gi/nm-wg-set
index 4f074605..4d162570 100755
--- a/examples/python/gi/nm-wg-set
+++ b/examples/python/gi/nm-wg-set
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2018 - 2019 Red Hat, Inc.
 #
diff --git a/examples/python/gi/ovs-external-ids.py b/examples/python/gi/ovs-external-ids.py
new file mode 100755
index 00000000..63f9695e
--- /dev/null
+++ b/examples/python/gi/ovs-external-ids.py
@@ -0,0 +1,663 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2017, 2020 Red Hat, Inc.
+#
+
+#
+# set and show OVS external-ids for a connection:
+#
+
+import sys
+import os
+import re
+import pprint
+import subprocess
+
+import gi
+
+gi.require_version("NM", "1.0")
+from gi.repository import GLib, NM
+
+###############################################################################
+
+MODE_GET = "get"
+MODE_SET = "set"
+MODE_APPLY = "apply"
+
+
+def memoize0(f):
+    result = []
+
+    def helper():
+        if len(result) == 0:
+            result.append(f())
+        return result[0]
+
+    return helper
+
+
+def memoize(f):
+    memo = {}
+
+    def helper(x):
+        if x not in memo:
+            memo[x] = f(x)
+        return memo[x]
+
+    return helper
+
+
+def pr(v):
+    pprint.pprint(v, indent=4, depth=5, width=60)
+
+
+@memoize0
+def is_libnm_debug():
+    return os.getenv("LIBNM_CLIENT_DEBUG") is not None
+
+
+@memoize0
+def can_sudo():
+    try:
+        return (
+            subprocess.run(
+                ["sudo", "-n", "true"],
+                stdout=subprocess.DEVNULL,
+                stderr=subprocess.DEVNULL,
+            ).returncode
+            == 0
+        )
+    except:
+        return False
+
+
+def _print(msg=""):
+    if is_libnm_debug():
+        # we want to use the same logging mechanism as libnm's debug
+        # logging with "LIBNM_CLIENT_DEBUG=trace,stdout".
+        NM.utils_print(0, msg + "\n")
+        return
+    print(msg)
+
+
+def mainloop_run(timeout_msec=0, mainloop=None):
+    if mainloop is None:
+        mainloop = GLib.MainLoop()
+
+    timeout_id = None
+    timeout_reached = []
+
+    if timeout_msec > 0:
+
+        def _timeout_cb(unused):
+            # it can happen that the caller already quit the mainloop
+            # otherwise. In that case, we don't want to signal a timeout.
+            if mainloop.is_running():
+                timeout_reached.append(1)
+                mainloop.quit()
+            return True
+
+        timeout_id = GLib.timeout_add(timeout_msec, _timeout_cb, None)
+
+    mainloop.run()
+    if timeout_id:
+        GLib.source_remove(timeout_id)
+    return not timeout_reached
+
+
+###############################################################################
+
+
+def connection_update2(remote_connection, connection):
+
+    mainloop = GLib.MainLoop()
+    result_error = []
+
+    def cb(c, result):
+        try:
+            c.update2_finish(result)
+        except Exception as e:
+            result_error.append(e)
+        mainloop.quit()
+
+    remote_connection.update2(
+        connection.to_dbus(NM.ConnectionSerializationFlags.ALL),
+        NM.SettingsUpdate2Flags.NO_REAPPLY,
+        None,
+        None,
+        cb,
+    )
+
+    mainloop_run(mainloop=mainloop)
+
+    if result_error:
+        raise result_error[0]
+
+
+def device_get_applied_connection(device):
+    mainloop = GLib.MainLoop()
+    rr = []
+
+    def cb(c, result):
+        try:
+            con, version_id = c.get_applied_connection_finish(result)
+        except Exception as e:
+            rr.append(e)
+        else:
+            rr.append(con)
+            rr.append(version_id)
+        mainloop.quit()
+
+    device.get_applied_connection_async(0, None, cb)
+
+    mainloop_run(mainloop=mainloop)
+
+    if len(rr) == 1:
+        raise rr[0]
+    return rr[0], rr[1]
+
+
+def device_reapply(device, connection, version_id):
+
+    mainloop = GLib.MainLoop()
+    result_error = []
+
+    def cb(d, result):
+        try:
+            d.reapply_finish(result)
+        except Exception as e:
+            result_error.append(e)
+        mainloop.quit()
+
+    device.reapply_async(connection, version_id, 0, None, cb)
+
+    mainloop_run(mainloop=mainloop)
+
+    if len(result_error) == 1:
+        raise result_error[0]
+
+
+def ovs_print_external_ids(prefix):
+    if not can_sudo():
+        _print(prefix + ": not running as root and cannot call ovs-vsctl")
+        return
+
+    cmds = [["ovs-vsctl", "show"]]
+    for typ in ["Bridge", "Port", "Interface"]:
+        cmds += [["ovs-vsctl", "--columns=name,external-ids", "list", typ]]
+
+    out = ""
+    for cmd in cmds:
+        p = subprocess.run(cmd, stdout=subprocess.PIPE, check=True)
+        out += p.stdout.decode("utf-8") + "\n"
+    out = "\n".join([prefix + s for s in out.split("\n")])
+    _print(out)
+
+
+###############################################################################
+
+
+def usage():
+    _print("%s g[et]   PROFILE [ GETTER ]" % (sys.argv[0]))
+    _print("%s s[et]   PROFILE   SETTER   [--test]" % (sys.argv[0]))
+    _print("%s a[pply] DEVICE    SETTER   [--test]" % (sys.argv[0]))
+    _print(
+        "   PROFILE :=  [id | uuid | type] STRING  |  [ ~id | ~type ] REGEX_STRING  |  STRING"
+    )
+    _print("   DEVICE :=  [iface] STRING")
+    _print("   GETTER  := ( KEY | ~REGEX_KEY )  [... GETTER]")
+    _print("   SETTER  := ( + | - | -KEY | [+]KEY VALUE ) [... SETTER]")
+
+
+def die(msg, show_usage=False):
+    _print("FAILED: %s" % (msg))
+    if show_usage:
+        usage()
+    sys.exit(1)
+
+
+def die_usage(msg):
+    die(msg, show_usage=True)
+
+
+def parse_args(argv):
+    had_dash_dash = False
+    args = {
+        "mode": MODE_GET,
+        "select_arg": None,
+        "ids_arg": [],
+        "do_test": False,
+    }
+    i = 1
+    while i < len(argv):
+        a = argv[i]
+
+        if i == 1:
+            if a in ["s", "set"]:
+                args["mode"] = MODE_SET
+            elif a in ["g", "get"]:
+                args["mode"] = MODE_GET
+            elif a in ["a", "apply"]:
+                args["mode"] = MODE_APPLY
+            else:
+                die_usage("unexpected mode argument '%s'" % (a))
+            i += 1
+            continue
+
+        if a == "--test":
+            args["do_test"] = True
+            i += 1
+            continue
+
+        if args["select_arg"] is None:
+            if args["mode"] == MODE_APPLY:
+                possible_selects = ["iface"]
+            else:
+                possible_selects = ["id", "~id", "uuid", "type", "~type"]
+
+            if a in possible_selects:
+                if i + 1 >= len(argv):
+                    die_usage("'%s' requires an argument'" % (a))
+                args["select_arg"] = (a, argv[i + 1])
+                i += 2
+                continue
+
+            if a == "*":
+                a = None
+            args["select_arg"] = ("*", a)
+            i += 1
+            continue
+
+        if args["mode"] == MODE_GET:
+            args["ids_arg"].append(a)
+            i += 1
+            continue
+
+        if not a:
+            die_usage("argument should specify a external-id but is empty string")
+
+        if a[0] == "-":
+            v = (a, None)
+            i += 1
+        elif a == "+":
+            v = (a, None)
+            i += 1
+        else:
+            if a[0] != "+":
+                a = "+" + a
+            if i + 1 >= len(argv):
+                die_usage("'%s' requires an argument'" % (a))
+            v = (a, argv[i + 1])
+            i += 2
+
+        args["ids_arg"].append(v)
+
+    if args["mode"] == MODE_SET:
+        if not args["ids_arg"]:
+            die_usage("Requires one or more external-ids to set or delete")
+
+    return args
+
+
+def device_to_str(device, show_type=False):
+    if show_type:
+        return "%s (%s)" % (device.get_iface(), device.get_type_desc())
+    return "%s" % (device.get_iface(),)
+
+
+def connection_to_str(connection, show_type=False):
+    if show_type:
+        return "%s (%s, %s)" % (
+            connection.get_id(),
+            connection.get_uuid(),
+            connection.get_connection_type(),
+        )
+    return "%s (%s)" % (connection.get_id(), connection.get_uuid())
+
+
+def devices_filter(devices, select_arg):
+    devices = list(sorted(devices, key=device_to_str))
+    if not select_arg:
+        return devices
+    # we preserve the order of the selected devices. And
+    # if devices are selected multiple times, we return
+    # them multiple times.
+    l = []
+    f = select_arg
+    for d in devices:
+        if f[0] == "iface":
+            if f[1] == d.get_iface():
+                l.append(d)
+        else:
+            assert f[0] == "*"
+            if f[1] is None:
+                l.append(d)
+            else:
+                if f[1] in [d.get_iface()]:
+                    l.append(d)
+    return l
+
+
+def connections_filter(connections, select_arg):
+    connections = list(sorted(connections, key=connection_to_str))
+    if not select_arg:
+        return connections
+    # we preserve the order of the selected connections. And
+    # if connections are selected multiple times, we return
+    # them multiple times.
+    l = []
+    f = select_arg
+    for c in connections:
+        if f[0] == "id":
+            if f[1] == c.get_id():
+                l.append(c)
+        elif f[0] == "~id":
+            if re.match(f[1], c.get_id()):
+                l.append(c)
+        elif f[0] == "uuid":
+            if f[1] == c.get_uuid():
+                l.append(c)
+        elif f[0] == "type":
+            if f[1] == c.get_connection_type():
+                l.append(c)
+        elif f[0] == "~type":
+            if re.match(f[1], c.get_connection_type()):
+                l.append(c)
+        else:
+            assert f[0] == "*"
+            if f[1] is None:
+                l.append(c)
+            else:
+                if f[1] in [c.get_uuid(), c.get_id()]:
+                    l.append(c)
+    return l
+
+
+def ids_select(ids, mode, ids_arg):
+    ids = list(ids)
+    if not ids_arg:
+        return (ids, [])
+
+    keys = set()
+    requested = []
+    for d in ids_arg:
+        if mode == MODE_GET:
+            if d[0] == "~":
+                r = re.compile(d[1:])
+                keys.update([k for k in ids if r.match(k)])
+            else:
+                keys.update([k for k in ids if k == d])
+                if d not in requested:
+                    requested.append(d)
+        else:
+            assert mode in [MODE_SET, MODE_APPLY]
+            d2 = d[0]
+            assert d2[0] in ["-", "+"]
+            d3 = d2[1:]
+            if d3 in ids:
+                keys.add(d3)
+    return (list([k for k in ids if k in keys]), requested)
+
+
+def connection_print(connection, mode, ids_arg, dbus_path, prefix=""):
+    sett = connection.get_setting(NM.SettingOvsExternalIDs)
+
+    if sett is not None:
+        all_ids = list(sett.get_data_keys())
+        keys, requested = ids_select(all_ids, mode, ids_arg)
+        num_str = "%s" % (len(all_ids))
+    else:
+        keys = []
+        requested = []
+        num_str = "none"
+
+    _print(
+        "%s%s [%s]" % (prefix, connection_to_str(connection, show_type=True), num_str)
+    )
+    if dbus_path:
+        _print("%s   %s" % (prefix, dbus_path))
+    if sett is not None:
+        dd = sett.get_property(NM.SETTING_OVS_EXTERNAL_IDS_DATA)
+    else:
+        dd = {}
+    for k in keys:
+        v = sett.get_data(k)
+        assert v is not None
+        assert v == dd.get(k, None)
+        _print('%s   "%s" = "%s"' % (prefix, k, v))
+    for k in requested:
+        _print('%s   "%s" = <unset>' % (prefix, k))
+
+
+def sett_update(connection, ids_arg):
+
+    sett = connection.get_setting(NM.SettingOvsExternalIDs)
+
+    for d in ids_arg:
+        op = d[0][0]
+        key = d[0][1:]
+        val = d[1]
+
+        oldval = None
+        if sett is not None:
+            oldval = sett.get_data(key)
+
+        if op == "-":
+            assert val is None
+            if key == "":
+                if sett is None:
+                    _print(" DEL: setting (ovs-external-ids group was not present)")
+                else:
+                    connection.remove_setting(NM.SettingOvsExternalIDs)
+                    sett = None
+                    _print(" DEL: setting")
+                continue
+
+            if sett is None:
+                _print(' DEL: "%s" (ovs-external-ids group was not present)' % (key))
+                continue
+            if oldval is None:
+                _print(' DEL: "%s" (id was unset)' % (key))
+                continue
+            _print(' DEL: "%s" (id was set to"%s")' % (key, oldval))
+            sett.set_data(key, None)
+            continue
+
+        if key == "":
+            assert val is None
+            if sett is None:
+                sett = NM.SettingOvsExternalIDs.new()
+                connection.add_setting(sett)
+                _print(" SET: setting (external-ids group was added)")
+                continue
+
+            _print(" SET: setting (external-ids group was present)")
+            continue
+
+        assert val is not None
+
+        if sett is None:
+            sett = NM.SettingOvsExternalIDs.new()
+            connection.add_setting(sett)
+            _print(
+                ' SET: "%s" = "%s" (external-ids group was not present)' % (key, val)
+            )
+        elif oldval is None:
+            _print(' SET: "%s" = "%s" (new)' % (key, val))
+        elif oldval != val:
+            _print(' SET: "%s" = "%s" (was "%s")' % (key, val, oldval))
+        else:
+            _print(' SET: "%s" = "%s" (unchanged)' % (key, val))
+        sett.set_data(key, val)
+
+
+def do_get(connections, ids_arg):
+    first_line = True
+    for c in connections:
+        if first_line:
+            first_line = False
+        else:
+            _print()
+        connection_print(c, MODE_GET, ids_arg, dbus_path=c.get_path())
+
+
+def do_set(nmc, connection, ids_arg, do_test):
+
+    remote_connection = connection
+    connection = NM.SimpleConnection.new_clone(remote_connection)
+
+    connection_print(
+        connection, MODE_SET, [], remote_connection.get_path(), prefix="BEFORE: "
+    )
+    _print()
+
+    sett_update(connection, ids_arg)
+
+    if do_test:
+        _print()
+        _print("Only show. Run without --test to set")
+        return
+
+    try:
+        connection_update2(remote_connection, connection)
+    except Exception as e:
+        _print()
+        _print("FAILURE to commit connection: %s" % (e))
+        return
+
+    # NMClient received the completion of Update2() call. It also received
+    # a property changed signal that the profile changed, and it is about
+    # to fetch the new value. However, that value is not yet here.
+    #
+    # libnm should provide a better API for this. For example, not signal
+    # completion of update2() until the profile was refetched. Or, indicate
+    # that the settings are dirty, so we would know how long to wait.
+    #
+    # Add an ugly workaround here and wait a bit.
+    _print()
+    _print("WORKAROUND: wait for connection to change")
+    mainloop_run(timeout_msec=500)
+
+    if remote_connection is not nmc.get_object_by_path(remote_connection.get_path()):
+        _print()
+        _print(
+            "Connection %s no longer exists after commit"
+            % (remote_connection.get_path())
+        )
+        return
+
+    _print()
+    connection_print(
+        remote_connection, MODE_SET, [], remote_connection.get_path(), prefix="AFTER:  "
+    )
+
+    _print()
+    if remote_connection.compare(connection, NM.SettingCompareFlags.EXACT):
+        _print("resulting connection is as expected")
+    else:
+        _print("WARNING: resulting connection is not as expected")
+
+
+def do_apply(nmc, device, ids_arg, do_test):
+
+    try:
+        connection_orig, version_id = device_get_applied_connection(device)
+    except Exception as e:
+        _print(
+            'failure to get applied connection for %s: %s"' % (device_to_str(device), e)
+        )
+        die("The device does not seem active? Nothing to reapply")
+
+    _print(
+        "REAPPLY device %s (%s) with connection %s (version-id = %s)"
+        % (
+            device_to_str(device),
+            NM.Object.get_path(device),
+            connection_to_str(connection_orig),
+            version_id,
+        )
+    )
+    _print()
+
+    ovs_print_external_ids("BEFORE-OVS-VSCTL: ")
+    _print()
+
+    connection = NM.SimpleConnection.new_clone(connection_orig)
+
+    connection_print(connection, MODE_APPLY, [], device.get_path(), prefix="BEFORE: ")
+    _print()
+
+    sett_update(connection, ids_arg)
+
+    if do_test:
+        _print()
+        _print("Only show. Run without --test to set")
+        return
+
+    _print()
+    _print("reapply...")
+
+    try:
+        device_reapply(device, connection, version_id)
+    except Exception as e:
+        _print()
+        _print("FAILURE to commit connection: %s" % (e))
+        return
+
+    try:
+        connection_after, version_id = device_get_applied_connection(device)
+    except Exception as e:
+        _print(
+            'failure to get applied connection after reapply for device %s: %s"'
+            % (device_to_str(device), e)
+        )
+        die("FAILURE to get applied connection after reapply")
+
+    _print()
+    connection_print(connection, MODE_APPLY, [], device.get_path(), prefix="AFTER: ")
+    _print()
+
+    ovs_print_external_ids("AFTER-OVS-VSCTL: ")
+
+
+###############################################################################
+
+if __name__ == "__main__":
+
+    args = parse_args(sys.argv)
+
+    nmc = NM.Client.new(None)
+
+    if args["mode"] == MODE_APPLY:
+
+        devices = devices_filter(nmc.get_devices(), args["select_arg"])
+
+        if len(devices) != 1:
+            _print(
+                "To apply the external-ids of a device, exactly one connection must be selected. Instead, %s devices matched ([%s])"
+                % (len(devices), ", ".join([device_to_str(c) for c in devices]))
+            )
+            die_usage("Select unique device to apply")
+        do_apply(nmc, devices[0], args["ids_arg"], do_test=args["do_test"])
+
+    else:
+
+        connections = connections_filter(nmc.get_connections(), args["select_arg"])
+
+        if args["mode"] == MODE_SET:
+            if len(connections) != 1:
+                _print(
+                    "To set the external-ids of a connection, exactly one connection must be selected via id|uuid. Instead, %s connection matched ([%s])"
+                    % (
+                        len(connections),
+                        ", ".join([connection_to_str(c) for c in connections]),
+                    )
+                )
+                die_usage("Select unique connection to set")
+            do_set(nmc, connections[0], args["ids_arg"], do_test=args["do_test"])
+        else:
+            if len(connections) < 1:
+                _print("No connection selected for printing the external ids")
+                die_usage("Select connection to get")
+            do_get(connections, args["ids_arg"])
diff --git a/examples/python/gi/setting-user-data.py b/examples/python/gi/setting-user-data.py
index e2194074..20c6a2e9 100755
--- a/examples/python/gi/setting-user-data.py
+++ b/examples/python/gi/setting-user-data.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2017 Red Hat, Inc.
 #
diff --git a/examples/python/gi/show-wifi-networks.py b/examples/python/gi/show-wifi-networks.py
index b865a85a..eb71c4c4 100755
--- a/examples/python/gi/show-wifi-networks.py
+++ b/examples/python/gi/show-wifi-networks.py
@@ -1,6 +1,5 @@
 #!/usr/bin/env python
-# coding=utf-8
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2013 Red Hat, Inc.
 #
diff --git a/examples/python/gi/update-ip4-method.py b/examples/python/gi/update-ip4-method.py
index 6fae2603..811d10b4 100755
--- a/examples/python/gi/update-ip4-method.py
+++ b/examples/python/gi/update-ip4-method.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2014 Red Hat, Inc.
 #
diff --git a/examples/ruby/add-connection.rb b/examples/ruby/add-connection.rb
index dae6ece3..5ff0ac36 100755
--- a/examples/ruby/add-connection.rb
+++ b/examples/ruby/add-connection.rb
@@ -1,5 +1,5 @@
 #!/usr/bin/env ruby
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2011 Red Hat, Inc.
 #
diff --git a/examples/ruby/get-basic-nm-info.rb b/examples/ruby/get-basic-nm-info.rb
index e696f353..82f96532 100755
--- a/examples/ruby/get-basic-nm-info.rb
+++ b/examples/ruby/get-basic-nm-info.rb
@@ -1,5 +1,5 @@
 #!/usr/bin/env ruby
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2011 Red Hat, Inc.
 #
diff --git a/examples/ruby/list-devices.rb b/examples/ruby/list-devices.rb
index e885d4a6..110d8307 100755
--- a/examples/ruby/list-devices.rb
+++ b/examples/ruby/list-devices.rb
@@ -1,5 +1,5 @@
 #!/usr/bin/env ruby
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2011 - 2012 Red Hat, Inc.
 #
diff --git a/examples/shell/active-wifi.sh b/examples/shell/active-wifi.sh
index 54e0527f..6213fc0c 100755
--- a/examples/shell/active-wifi.sh
+++ b/examples/shell/active-wifi.sh
@@ -1,5 +1,5 @@
 #!/bin/sh
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2012 Red Hat, Inc.
 #
diff --git a/examples/shell/disconnect-device.sh b/examples/shell/disconnect-device.sh
index ef2a129b..8dfadaec 100755
--- a/examples/shell/disconnect-device.sh
+++ b/examples/shell/disconnect-device.sh
@@ -1,5 +1,5 @@
 #!/bin/sh
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2012 Red Hat, Inc.
 #
diff --git a/examples/shell/get-hostname.sh b/examples/shell/get-hostname.sh
index ecefdcfd..976803aa 100755
--- a/examples/shell/get-hostname.sh
+++ b/examples/shell/get-hostname.sh
@@ -1,5 +1,5 @@
 #!/bin/sh
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2011 Red Hat, Inc.
 #
diff --git a/examples/shell/list-devices.sh b/examples/shell/list-devices.sh
index 74342d41..4d9555ac 100755
--- a/examples/shell/list-devices.sh
+++ b/examples/shell/list-devices.sh
@@ -1,5 +1,5 @@
 #!/bin/sh
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2011 - 2012 Red Hat, Inc.
 #
diff --git a/examples/shell/nm-logging.sh b/examples/shell/nm-logging.sh
index 2261f449..beb427f5 100755
--- a/examples/shell/nm-logging.sh
+++ b/examples/shell/nm-logging.sh
@@ -1,5 +1,5 @@
 #!/bin/sh
-# SPDX-License-Identifier: GPL-2.0+
+# SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Copyright (C) 2011 Red Hat, Inc.
 #