From c3080c79dc77b00d833109fc6d18e4b6b5e8b110 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 16 Oct 2017 23:27:04 +0200 Subject: [PATCH 01/36] ip-tunnel: fix a typo --- clients/common/settings-docs.c.in | 2 +- libnm-core/nm-setting-ip-tunnel.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clients/common/settings-docs.c.in b/clients/common/settings-docs.c.in index 4d1e94e817..8812255a48 100644 --- a/clients/common/settings-docs.c.in +++ b/clients/common/settings-docs.c.in @@ -197,7 +197,7 @@ #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_INPUT_KEY N_("The key used for tunnel input packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used.") #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_LOCAL N_("The local endpoint of the tunnel; the value can be empty, otherwise it must contain an IPv4 or IPv6 address.") #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_MODE N_("The tunneling mode, for example NM_IP_TUNNEL_MODE_IPIP (1) or NM_IP_TUNNEL_MODE_GRE (2).") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_MTU N_("None") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments.") #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_NAME N_("The setting's name, which uniquely identifies the setting within the connection. Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".") #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_OUTPUT_KEY N_("The key used for tunnel output packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used.") #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_PARENT N_("If given, specifies the parent interface name or parent connection UUID the new device will be bound to so that tunneled packets will only be routed via that interface.") diff --git a/libnm-core/nm-setting-ip-tunnel.c b/libnm-core/nm-setting-ip-tunnel.c index 7e1737fc3b..fa8d4a7a24 100644 --- a/libnm-core/nm-setting-ip-tunnel.c +++ b/libnm-core/nm-setting-ip-tunnel.c @@ -758,7 +758,7 @@ nm_setting_ip_tunnel_class_init (NMSettingIPTunnelClass *setting_class) G_PARAM_STATIC_STRINGS)); /** - * NMSettingIPTunel:mtu: + * NMSettingIPTunnel:mtu: * * If non-zero, only transmit packets of the specified size or smaller, * breaking larger packets up into multiple fragments. From acd814d50a993debb7a1cfb98c07e0e795942e12 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 16 Oct 2017 23:27:30 +0200 Subject: [PATCH 02/36] generate-setting-docs: error out on missing documentation --- libnm/generate-setting-docs.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libnm/generate-setting-docs.py b/libnm/generate-setting-docs.py index 9a8df4bfd1..aa0c96ebb2 100755 --- a/libnm/generate-setting-docs.py +++ b/libnm/generate-setting-docs.py @@ -257,6 +257,9 @@ for settingxml in settings: prop_upper = prop.upper().replace('-', '_') + if value_desc is None: + raise Exception("%s.%s needs a documentation description" % (setting.props.name, prop)) + if default_value is not None: outfile.write(" \n" % (prop, prop_upper, value_type, escape(default_value), escape(value_desc))) From 4391ba82dd535edd8651391dc05bb7c0d0a26c41 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 16 Oct 2017 21:31:17 +0200 Subject: [PATCH 03/36] cli/trivial: drop default branch from some cases This way not handling a known enum value will be caught by a compiler warning. --- clients/common/nm-client-utils.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/clients/common/nm-client-utils.c b/clients/common/nm-client-utils.c index 9423202ca7..fa7b720f46 100644 --- a/clients/common/nm-client-utils.c +++ b/clients/common/nm-client-utils.c @@ -243,9 +243,11 @@ nmc_device_state_to_string (NMDeviceState state) return _("deactivating"); case NM_DEVICE_STATE_FAILED: return _("connection failed"); - default: + case NM_DEVICE_STATE_UNKNOWN: return _("unknown"); } + + return _("unknown"); } const char * @@ -260,9 +262,11 @@ nmc_device_metered_to_string (NMMetered value) return _("yes (guessed)"); case NM_METERED_GUESS_NO: return _("no (guessed)"); - default: + case NM_METERED_UNKNOWN: return _("unknown"); } + + return _("unknown"); } const char * @@ -395,10 +399,10 @@ nmc_device_reason_to_string (NMDeviceStateReason reason) return _("The device's parent changed"); case NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED: return _("The device parent's management changed"); - default: - /* TRANSLATORS: Unknown reason for a device state change (NMDeviceStateReason) */ - return _("Unknown"); } + + /* TRANSLATORS: Unknown reason for a device state change (NMDeviceStateReason) */ + return _("Unknown"); } const char * From 67b265182f4173f1af321b4d0674dc540a2241a2 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 23 Oct 2017 11:47:25 +0200 Subject: [PATCH 04/36] utils: don't assume a device with master won't have IP configuration Whether the ip[46]-config exists is a better way, and we already check that. --- src/NetworkManagerUtils.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index b7a2faaa17..596c5bb362 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -175,32 +175,24 @@ nm_utils_get_ip_config_method (NMConnection *connection, if (ip_setting_type == NM_TYPE_SETTING_IP4_CONFIG) { g_return_val_if_fail (s_con != NULL, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - if (nm_setting_connection_get_master (s_con)) + s_ip4 = nm_connection_get_setting_ip4_config (connection); + if (!s_ip4) return NM_SETTING_IP4_CONFIG_METHOD_DISABLED; - else { - s_ip4 = nm_connection_get_setting_ip4_config (connection); - if (!s_ip4) - return NM_SETTING_IP4_CONFIG_METHOD_DISABLED; - method = nm_setting_ip_config_get_method (s_ip4); - g_return_val_if_fail (method != NULL, NM_SETTING_IP4_CONFIG_METHOD_AUTO); + method = nm_setting_ip_config_get_method (s_ip4); + g_return_val_if_fail (method != NULL, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - return method; - } + return method; } else if (ip_setting_type == NM_TYPE_SETTING_IP6_CONFIG) { g_return_val_if_fail (s_con != NULL, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - if (nm_setting_connection_get_master (s_con)) + s_ip6 = nm_connection_get_setting_ip6_config (connection); + if (!s_ip6) return NM_SETTING_IP6_CONFIG_METHOD_IGNORE; - else { - s_ip6 = nm_connection_get_setting_ip6_config (connection); - if (!s_ip6) - return NM_SETTING_IP6_CONFIG_METHOD_IGNORE; - method = nm_setting_ip_config_get_method (s_ip6); - g_return_val_if_fail (method != NULL, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + method = nm_setting_ip_config_get_method (s_ip6); + g_return_val_if_fail (method != NULL, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - return method; - } + return method; } else g_assert_not_reached (); From 097d41b8e6a10eee5a956aa3d8580991f246d913 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Thu, 12 Oct 2017 14:53:43 +0200 Subject: [PATCH 05/36] manager: match device type when removing an ip interface Otherwise we might end up removing a wrong device of a same name. --- src/nm-manager.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/nm-manager.c b/src/nm-manager.c index 46214130b3..7f854c3e3d 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -2031,6 +2031,7 @@ device_ip_iface_changed (NMDevice *device, NMManager *self) { const char *ip_iface = nm_device_get_ip_iface (device); + NMDeviceType device_type = nm_device_get_device_type (device); GSList *iter; /* Remove NMDevice objects that are actually child devices of others, @@ -2043,6 +2044,7 @@ device_ip_iface_changed (NMDevice *device, if ( candidate != device && g_strcmp0 (nm_device_get_iface (candidate), ip_iface) == 0 + && nm_device_get_device_type (candidate) == device_type && nm_device_is_real (candidate)) { remove_device (self, candidate, FALSE, FALSE); break; From abaa8528667f683eaedc7974eb834cefa174862c Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 10 Oct 2017 11:14:05 +0200 Subject: [PATCH 06/36] manager: don't assign a new link to a device of a different link type --- src/nm-manager.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/nm-manager.c b/src/nm-manager.c index 7f854c3e3d..647f0ddc2f 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -2341,6 +2341,9 @@ platform_link_added (NMManager *self, gboolean compatible = TRUE; gs_free_error GError *error = NULL; + if (nm_device_get_link_type (candidate) != plink->type) + continue; + if (strcmp (nm_device_get_iface (candidate), plink->name)) continue; From d7f7725ae8c965756902bd492bf2cf0834319548 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 16 Aug 2017 15:44:24 +0200 Subject: [PATCH 07/36] manager: always update the device when the plink comes and goes For some software devices, the platform link appears only after they've been realized. Update their properties and let them know that the link has changed so they can eventually proceed with activation. Also, reset the properties (udi, iface, driver) that are set from the platform link when the link goes away. At that point they don't reflect reality anymore. Removes some code duplication too. --- src/devices/nm-device.c | 79 +++++++++++++++++++---------------------- src/devices/nm-device.h | 3 ++ src/nm-manager.c | 3 ++ 3 files changed, 43 insertions(+), 42 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 52d7e3e3d3..0aac304cdd 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -2650,7 +2650,6 @@ device_link_changed (NMDevice *self) NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); gboolean ip_ifname_changed = FALSE; - const char *udi; NMPlatformLink info; const NMPlatformLink *pllink; int ifindex; @@ -2665,27 +2664,10 @@ device_link_changed (NMDevice *self) if (!pllink) return G_SOURCE_REMOVE; + nm_device_update_from_platform_link (self, pllink); + info = *pllink; - udi = nm_platform_link_get_udi (nm_device_get_platform (self), info.ifindex); - if (udi && !nm_streq0 (udi, priv->udi)) { - /* Update UDI to what udev gives us */ - g_free (priv->udi); - priv->udi = g_strdup (udi); - _notify (self, PROP_UDI); - } - - if (!nm_streq0 (info.driver, priv->driver)) { - g_free (priv->driver); - priv->driver = g_strdup (info.driver); - _notify (self, PROP_DRIVER); - } - - _set_mtu (self, info.mtu); - - if (ifindex == nm_device_get_ip_ifindex (self)) - _stats_update_counters_from_pllink (self, &info); - had_hw_addr = (priv->hw_addr != NULL); nm_device_update_hw_address (self); got_hw_addr = (!had_hw_addr && priv->hw_addr); @@ -3137,37 +3119,53 @@ nm_device_create_and_realize (NMDevice *self, return TRUE; } -static void -update_device_from_platform_link (NMDevice *self, const NMPlatformLink *plink) +void +nm_device_update_from_platform_link (NMDevice *self, const NMPlatformLink *plink) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const char *udi; + const char *str; + int ifindex; + guint32 mtu; - g_return_if_fail (plink != NULL); + g_return_if_fail (plink == NULL || link_type_compatible (self, plink->type, NULL, NULL)); - udi = nm_platform_link_get_udi (nm_device_get_platform (self), plink->ifindex); - if (udi && !nm_streq0 (udi, priv->udi)) { + str = plink ? nm_platform_link_get_udi (nm_device_get_platform (self), plink->ifindex) : NULL; + if (g_strcmp0 (str, priv->udi)) { g_free (priv->udi); - priv->udi = g_strdup (udi); + priv->udi = g_strdup (str); _notify (self, PROP_UDI); } - if (!g_strcmp0 (plink->name, priv->iface)) { + str = plink ? plink->name : NULL; + if (str && g_strcmp0 (str, priv->iface)) { g_free (priv->iface); - priv->iface = g_strdup (plink->name); + priv->iface = g_strdup (str); _notify (self, PROP_IFACE); } - if (priv->ifindex != plink->ifindex) { - priv->ifindex = plink->ifindex; - _notify (self, PROP_IFINDEX); + str = plink ? plink->driver : NULL; + if (g_strcmp0 (str, priv->driver) != 0) { + g_free (priv->driver); + priv->driver = g_strdup (str); + _notify (self, PROP_DRIVER); } - priv->up = NM_FLAGS_HAS (plink->n_ifi_flags, IFF_UP); - if (plink->driver && g_strcmp0 (plink->driver, priv->driver) != 0) { - g_free (priv->driver); - priv->driver = g_strdup (plink->driver); - _notify (self, PROP_DRIVER); + if (plink) { + priv->up = NM_FLAGS_HAS (plink->n_ifi_flags, IFF_UP); + if (plink->ifindex == nm_device_get_ip_ifindex (self)) + _stats_update_counters_from_pllink (self, plink); + } else { + priv->up = FALSE; + } + + mtu = plink ? plink->mtu : 0; + _set_mtu (self, mtu); + + ifindex = plink ? plink->ifindex : 0; + if (priv->ifindex != ifindex) { + priv->ifindex = ifindex; + _notify (self, PROP_IFINDEX); + NM_DEVICE_GET_CLASS (self)->link_changed (self, plink); } } @@ -3282,11 +3280,8 @@ realize_start_setup (NMDevice *self, nm_device_sys_iface_state_set (self, NM_DEVICE_SYS_IFACE_STATE_EXTERNAL); - if (plink) { - g_return_if_fail (link_type_compatible (self, plink->type, NULL, NULL)); - update_device_from_platform_link (self, plink); - _stats_update_counters_from_pllink (self, plink); - } + if (plink) + nm_device_update_from_platform_link (self, plink); if (priv->ifindex > 0) { priv->physical_port_id = nm_platform_link_get_physical_port_id (nm_device_get_platform (self), priv->ifindex); diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index ef83f1b53e..921db8aa5e 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -660,6 +660,9 @@ gboolean nm_device_unrealize (NMDevice *device, gboolean remove_resources, GError **error); +void nm_device_update_from_platform_link (NMDevice *self, + const NMPlatformLink *plink); + gboolean nm_device_get_autoconnect (NMDevice *device); void nm_device_set_autoconnect_intern (NMDevice *device, gboolean autoconnect); void nm_device_emit_recheck_auto_activate (NMDevice *device); diff --git a/src/nm-manager.c b/src/nm-manager.c index 647f0ddc2f..575a15e6c6 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -2351,6 +2351,7 @@ platform_link_added (NMManager *self, /* Ignore the link added event since there's already a realized * device with the link's name. */ + nm_device_update_from_platform_link (candidate, plink); return; } else if (nm_device_realize_start (candidate, plink, @@ -2481,6 +2482,8 @@ _platform_link_cb_idle (PlatformLinkCbData *data) _LOG2W (LOGD_DEVICE, device, "failed to unrealize: %s", error->message); g_clear_error (&error); remove_device (self, device, FALSE, TRUE); + } else { + nm_device_update_from_platform_link (device, NULL); } } else { /* Hardware and external devices always get removed when their kernel link is gone */ From 6af5030cf2374e8f2aff43df957ca2bbee5849dd Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 10 Oct 2017 15:00:59 +0200 Subject: [PATCH 08/36] manager: add a method to get a particular device of given type And also make the remove_device() method use it behind the scenes. --- src/devices/nm-device-ppp.c | 4 ++-- src/nm-manager.c | 30 +++++++++++++++++++++++------- src/nm-manager.h | 7 ++++++- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/devices/nm-device-ppp.c b/src/devices/nm-device-ppp.c index 09b25f50e2..8b3968d513 100644 --- a/src/devices/nm-device-ppp.c +++ b/src/devices/nm-device-ppp.c @@ -117,7 +117,7 @@ ppp_ip4_config (NMPPPManager *ppp_manager, return; } if (renamed) - nm_manager_remove_device (nm_manager_get (), iface); + nm_manager_remove_device (nm_manager_get (), iface, NM_DEVICE_TYPE_PPP); nm_device_activate_schedule_ip4_config_result (device, config); return; @@ -195,7 +195,7 @@ act_stage3_ip4_config_start (NMDevice *device, if (!nm_device_take_over_link (device, priv->pending_ifname, &renamed)) return NM_ACT_STAGE_RETURN_FAILURE; if (renamed) - nm_manager_remove_device (nm_manager_get (), priv->pending_ifname); + nm_manager_remove_device (nm_manager_get (), priv->pending_ifname, NM_DEVICE_TYPE_PPP); if (out_config) *out_config = g_steal_pointer (&priv->pending_ip4_config); else diff --git a/src/nm-manager.c b/src/nm-manager.c index 575a15e6c6..be64a868ba 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1270,22 +1270,38 @@ nm_manager_iface_for_uuid (NMManager *self, const char *uuid) return nm_connection_get_interface_name (NM_CONNECTION (connection)); } -gboolean -nm_manager_remove_device (NMManager *self, const char *ifname) +NMDevice * +nm_manager_get_device (NMManager *self, const char *ifname, NMDeviceType device_type) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); GSList *iter; NMDevice *d; + g_return_val_if_fail (ifname, NULL); + g_return_val_if_fail (device_type != NM_DEVICE_TYPE_UNKNOWN, NULL); + for (iter = priv->devices; iter; iter = iter->next) { d = iter->data; - if (nm_streq0 (nm_device_get_iface (d), ifname)) { - remove_device (self, d, FALSE, FALSE); - return TRUE; - } + + if ( nm_device_get_device_type (d) == device_type + && nm_streq0 (nm_device_get_iface (d), ifname)) + return d; } - return FALSE; + return NULL; +} + +gboolean +nm_manager_remove_device (NMManager *self, const char *ifname, NMDeviceType device_type) +{ + NMDevice *d; + + d = nm_manager_get_device (self, ifname, device_type); + if (!d) + return FALSE; + + remove_device (self, d, FALSE, FALSE); + return TRUE; } /** diff --git a/src/nm-manager.h b/src/nm-manager.h index fdcae121c5..622edb5b54 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -126,6 +126,11 @@ gboolean nm_manager_deactivate_connection (NMManager *manager, void nm_manager_set_capability (NMManager *self, NMCapability cap); -gboolean nm_manager_remove_device (NMManager *self, const char *ifname); +NMDevice * nm_manager_get_device (NMManager *self, + const char *ifname, + NMDeviceType device_type); +gboolean nm_manager_remove_device (NMManager *self, + const char *ifname, + NMDeviceType device_type); #endif /* __NETWORKMANAGER_MANAGER_H__ */ From c843fe478337a857b44647ba63df2518cfab109d Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Thu, 24 Aug 2017 09:09:18 +0200 Subject: [PATCH 09/36] device: ignore enslavement to ovs-master That one is special. All interfaces that are attached to OpenVSwitch ports appear as slaves to that one even for our purposes we like to pretend they're slaves to the actual OpenVSwitch bridges. --- src/devices/nm-device.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 0aac304cdd..bac1577654 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -2538,12 +2538,27 @@ static void device_recheck_slave_status (NMDevice *self, const NMPlatformLink *plink) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevice *master; + nm_auto_nmpobj const NMPObject *plink_master_keep_alive = NULL; + const NMPlatformLink *plink_master; g_return_if_fail (plink); if (plink->master <= 0) return; + master = nm_manager_get_device_by_ifindex (nm_manager_get (), plink->master); + plink_master = nm_platform_link_get (nm_device_get_platform (self), plink->master); + plink_master_keep_alive = nmp_object_ref (NMP_OBJECT_UP_CAST (plink_master)); + + if ( master == NULL + && plink_master + && g_strcmp0 (plink_master->name, "ovs-system") == 0 + && plink_master->type == NM_LINK_TYPE_OPENVSWITCH) { + _LOGD (LOGD_DEVICE, "the device claimed by openvswitch"); + return; + } + if (priv->master) { if ( plink->master > 0 && plink->master == nm_device_get_ifindex (priv->master)) { @@ -2555,20 +2570,16 @@ device_recheck_slave_status (NMDevice *self, const NMPlatformLink *plink) nm_device_master_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); } - if (plink->master > 0) { - NMDevice *master; - master = nm_manager_get_device_by_ifindex (nm_manager_get (), plink->master); - if (master && NM_DEVICE_GET_CLASS (master)->enslave_slave) - nm_device_master_add_slave (master, self, FALSE); - else if (master) { - _LOGI (LOGD_DEVICE, "enslaved to non-master-type device %s; ignoring", - nm_device_get_iface (master)); - } else { - _LOGW (LOGD_DEVICE, "enslaved to unknown device %d %s", - plink->master, - nm_platform_link_get_name (nm_device_get_platform (self), plink->master)); - } + if (master && NM_DEVICE_GET_CLASS (master)->enslave_slave) + nm_device_master_add_slave (master, self, FALSE); + else if (master) { + _LOGI (LOGD_DEVICE, "enslaved to non-master-type device %s; ignoring", + nm_device_get_iface (master)); + } else { + _LOGW (LOGD_DEVICE, "enslaved to unknown device %d (%s%s%s)", + plink->master, + NM_PRINT_FMT_QUOTED (plink_master, "\"", plink_master->name, "\"", "??")); } } From 6ac826350cfd95e3307ac2e4666b618d7331e8ba Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 11 Oct 2017 20:14:51 +0200 Subject: [PATCH 10/36] device: do not limit unrealizement to devices with platform links --- src/devices/nm-device.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index bac1577654..8e50eaaed8 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -8907,7 +8907,7 @@ delete_on_deactivate_link_delete (gpointer user_data) if (!nm_device_unrealize (data->device, TRUE, &error)) _LOGD (LOGD_DEVICE, "delete_on_deactivate: unrealizing %d failed (%s)", data->ifindex, error->message); - } else + } else if (data->ifindex > 0) nm_platform_link_delete (nm_device_get_platform (self), data->ifindex); g_free (data); @@ -8938,8 +8938,6 @@ delete_on_deactivate_check_and_schedule (NMDevice *self, int ifindex) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); DeleteOnDeactivateData *data; - if (ifindex <= 0) - return; if (!priv->nm_owned) return; if (priv->queued_act_request) From 340e35c09d8950e6c8151a7934d05d90b37418ea Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Thu, 12 Oct 2017 13:50:40 +0200 Subject: [PATCH 11/36] device: log device type too --- src/devices/nm-device-logging.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/devices/nm-device-logging.h b/src/devices/nm-device-logging.h index f0c7e59134..5f2e7d0da6 100644 --- a/src/devices/nm-device-logging.h +++ b/src/devices/nm-device-logging.h @@ -40,13 +40,16 @@ _nm_device_log_self_to_device (t *self) \ \ if (nm_logging_enabled (_level, _domain)) { \ typeof (*self) *const _self = (self); \ - const char *const _ifname = _nm_device_get_iface (_nm_device_log_self_to_device (_self)); \ + NMDevice *_device = _nm_device_log_self_to_device (_self); \ + const char *const _ifname = _nm_device_get_iface (_device); \ + const char *const _type_description = _ifname ? nm_device_get_type_description (_device) : NULL; \ \ nm_log_obj (_level, _domain, \ _ifname, NULL, \ _self, "device", \ - "%s%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - NM_PRINT_FMT_QUOTED (_ifname, "(", _ifname, ")", "[null]") \ + "%s%s%s%s%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + NM_PRINT_FMT_QUOTED (_ifname, "(", _ifname, "", "[null]"), \ + NM_PRINT_FMT_QUOTED (_ifname, ",", _type_description, ")", "") \ _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ } \ } G_STMT_END From dcfe276a829a5b965458aa73169cbc39ebc674c4 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Thu, 26 Oct 2017 19:56:52 +0200 Subject: [PATCH 12/36] device: don't wait for a carrier before enslaving devices The OpenVSwitch interfaces come into existence by their enslavement to a port. They can also bear an IP4 or IP6 configuration -- waiting on a carrier would deadlock the acitvation. --- src/devices/nm-device.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 8e50eaaed8..5e8053b882 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -6255,9 +6255,16 @@ static gboolean connection_requires_carrier (NMConnection *connection) { NMSettingIPConfig *s_ip4, *s_ip6; + NMSettingConnection *s_con; gboolean ip4_carrier_wanted, ip6_carrier_wanted; gboolean ip4_used = FALSE, ip6_used = FALSE; + /* We can progress to IP_CONFIG now, so that we're enslaved. + * That may actually cause carrier to go up and thus continue acivation. */ + s_con = nm_connection_get_setting_connection (connection); + if (nm_setting_connection_get_master (s_con)) + return FALSE; + ip4_carrier_wanted = connection_ip4_method_requires_carrier (connection, &ip4_used); if (ip4_carrier_wanted) { /* If IPv4 wants a carrier and cannot fail, the whole connection From 44eef0cfff12001afafd6117373135108925e045 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 23 Oct 2017 10:26:27 +0200 Subject: [PATCH 13/36] device/trivial: move check_ip_state() upwards --- src/devices/nm-device.c | 202 ++++++++++++++++++++-------------------- 1 file changed, 101 insertions(+), 101 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 5e8053b882..6fdcc2f032 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -3889,6 +3889,107 @@ nm_device_get_master (NMDevice *self) return NULL; } +static gboolean +get_ip_config_may_fail (NMDevice *self, int addr_family) +{ + NMConnection *connection; + NMSettingIPConfig *s_ip = NULL; + + connection = nm_device_get_applied_connection (self); + + /* Fail the connection if the failed IP method is required to complete */ + switch (addr_family) { + case AF_INET: + s_ip = nm_connection_get_setting_ip4_config (connection); + break; + case AF_INET6: + s_ip = nm_connection_get_setting_ip6_config (connection); + break; + default: + nm_assert_not_reached (); + } + + return !s_ip || nm_setting_ip_config_get_may_fail (s_ip); +} + +/* + * check_ip_state + * + * Transition the device from IP_CONFIG to the next state according to the + * outcome of IPv4 and IPv6 configuration. @may_fail indicates that we are + * called just after the initial configuration and thus IPv4/IPv6 are allowed to + * fail if the ipvx.may-fail properties say so, because the IP methods couldn't + * even be started. + */ +static void +check_ip_state (NMDevice *self, gboolean may_fail) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gboolean ip4_disabled = FALSE, ip6_ignore = FALSE; + NMSettingIPConfig *s_ip4, *s_ip6; + NMDeviceState state; + + if (nm_device_get_state (self) != NM_DEVICE_STATE_IP_CONFIG) + return; + + s_ip4 = (NMSettingIPConfig *) nm_device_get_applied_setting (self, NM_TYPE_SETTING_IP4_CONFIG); + if (s_ip4 && nm_streq0 (nm_setting_ip_config_get_method (s_ip4), + NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) + ip4_disabled = TRUE; + + s_ip6 = (NMSettingIPConfig *) nm_device_get_applied_setting (self, NM_TYPE_SETTING_IP6_CONFIG); + if (s_ip6 && nm_streq0 (nm_setting_ip_config_get_method (s_ip6), + NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) + ip6_ignore = TRUE; + + if ( priv->ip4_state == IP_DONE + && priv->ip6_state == IP_DONE) { + /* Both method completed (or disabled), proceed with activation */ + nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE); + return; + } + + if ( (priv->ip4_state == IP_FAIL || (ip4_disabled && priv->ip4_state == IP_DONE)) + && (priv->ip6_state == IP_FAIL || (ip6_ignore && priv->ip6_state == IP_DONE))) { + /* Either both methods failed, or only one failed and the other is + * disabled */ + if (nm_device_sys_iface_state_is_external_or_assume (self)) { + /* We have assumed configuration, but couldn't redo it. No problem, + * move to check state. */ + _set_ip_state (self, AF_INET, IP_DONE); + _set_ip_state (self, AF_INET6, IP_DONE); + state = NM_DEVICE_STATE_IP_CHECK; + } else if ( may_fail + && get_ip_config_may_fail (self, AF_INET) + && get_ip_config_may_fail (self, AF_INET6)) { + /* Couldn't start either IPv6 and IPv4 autoconfiguration, + * but both are allowed to fail. */ + state = NM_DEVICE_STATE_SECONDARIES; + } else { + /* Autoconfiguration attempted without success. */ + state = NM_DEVICE_STATE_FAILED; + } + + nm_device_state_changed (self, + state, + NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + return; + } + + /* If a method is still pending but required, wait */ + if (priv->ip4_state != IP_DONE && !get_ip_config_may_fail (self, AF_INET)) + return; + if (priv->ip6_state != IP_DONE && !get_ip_config_may_fail (self, AF_INET6)) + return; + + /* If at least a method has completed, proceed with activation */ + if ( (priv->ip4_state == IP_DONE && !ip4_disabled) + || (priv->ip6_state == IP_DONE && !ip6_ignore)) { + nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE); + return; + } +} + /** * nm_device_slave_notify_enslave: * @self: the slave device @@ -4899,29 +5000,6 @@ activation_source_is_scheduled (NMDevice *self, /*****************************************************************************/ -static gboolean -get_ip_config_may_fail (NMDevice *self, int addr_family) -{ - NMConnection *connection; - NMSettingIPConfig *s_ip = NULL; - - connection = nm_device_get_applied_connection (self); - - /* Fail the connection if the failed IP method is required to complete */ - switch (addr_family) { - case AF_INET: - s_ip = nm_connection_get_setting_ip4_config (connection); - break; - case AF_INET6: - s_ip = nm_connection_get_setting_ip6_config (connection); - break; - default: - nm_assert_not_reached (); - } - - return !s_ip || nm_setting_ip_config_get_may_fail (s_ip); -} - static void master_ready (NMDevice *self, NMActiveConnection *active) @@ -5216,84 +5294,6 @@ nm_device_activate_schedule_stage2_device_config (NMDevice *self) activation_source_schedule (self, activate_stage2_device_config, AF_INET); } -/* - * check_ip_state - * - * Transition the device from IP_CONFIG to the next state according to the - * outcome of IPv4 and IPv6 configuration. @may_fail indicates that we are - * called just after the initial configuration and thus IPv4/IPv6 are allowed to - * fail if the ipvx.may-fail properties say so, because the IP methods couldn't - * even be started. - */ -static void -check_ip_state (NMDevice *self, gboolean may_fail) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean ip4_disabled = FALSE, ip6_ignore = FALSE; - NMSettingIPConfig *s_ip4, *s_ip6; - NMDeviceState state; - - if (nm_device_get_state (self) != NM_DEVICE_STATE_IP_CONFIG) - return; - - s_ip4 = (NMSettingIPConfig *) nm_device_get_applied_setting (self, NM_TYPE_SETTING_IP4_CONFIG); - if (s_ip4 && nm_streq0 (nm_setting_ip_config_get_method (s_ip4), - NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) - ip4_disabled = TRUE; - - s_ip6 = (NMSettingIPConfig *) nm_device_get_applied_setting (self, NM_TYPE_SETTING_IP6_CONFIG); - if (s_ip6 && nm_streq0 (nm_setting_ip_config_get_method (s_ip6), - NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) - ip6_ignore = TRUE; - - if ( priv->ip4_state == IP_DONE - && priv->ip6_state == IP_DONE) { - /* Both method completed (or disabled), proceed with activation */ - nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE); - return; - } - - if ( (priv->ip4_state == IP_FAIL || (ip4_disabled && priv->ip4_state == IP_DONE)) - && (priv->ip6_state == IP_FAIL || (ip6_ignore && priv->ip6_state == IP_DONE))) { - /* Either both methods failed, or only one failed and the other is - * disabled */ - if (nm_device_sys_iface_state_is_external_or_assume (self)) { - /* We have assumed configuration, but couldn't redo it. No problem, - * move to check state. */ - _set_ip_state (self, AF_INET, IP_DONE); - _set_ip_state (self, AF_INET6, IP_DONE); - state = NM_DEVICE_STATE_IP_CHECK; - } else if ( may_fail - && get_ip_config_may_fail (self, AF_INET) - && get_ip_config_may_fail (self, AF_INET6)) { - /* Couldn't start either IPv6 and IPv4 autoconfiguration, - * but both are allowed to fail. */ - state = NM_DEVICE_STATE_SECONDARIES; - } else { - /* Autoconfiguration attempted without success. */ - state = NM_DEVICE_STATE_FAILED; - } - - nm_device_state_changed (self, - state, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - return; - } - - /* If a method is still pending but required, wait */ - if (priv->ip4_state != IP_DONE && !get_ip_config_may_fail (self, AF_INET)) - return; - if (priv->ip6_state != IP_DONE && !get_ip_config_may_fail (self, AF_INET6)) - return; - - /* If at least a method has completed, proceed with activation */ - if ( (priv->ip4_state == IP_DONE && !ip4_disabled) - || (priv->ip6_state == IP_DONE && !ip6_ignore)) { - nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE); - return; - } -} - void nm_device_ip_method_failed (NMDevice *self, int addr_family, From 89c4732142fd30d10d8db7e49a1111ee458b602d Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 23 Oct 2017 11:59:23 +0200 Subject: [PATCH 14/36] device: don't progress from ip-config state when we're enslaved We now can be enslaved and have L3 configuration at the same time. This also reduces some unnecessary complexity, because the decision to progress to IP_CHECK or SECONDARIES now happens in a single place, in the check_ip_state() routine. --- src/devices/nm-device.c | 46 +++++++---------------------------------- 1 file changed, 7 insertions(+), 39 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 6fdcc2f032..91e7881e5a 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -3932,6 +3932,12 @@ check_ip_state (NMDevice *self, gboolean may_fail) if (nm_device_get_state (self) != NM_DEVICE_STATE_IP_CONFIG) return; + /* Don't progress into IP_CHECK or SECONDARIES if we're waiting for the + * master to enslave us. */ + if ( nm_active_connection_get_master (NM_ACTIVE_CONNECTION (priv->act_request)) + && !priv->is_enslaved) + return; + s_ip4 = (NMSettingIPConfig *) nm_device_get_applied_setting (self, NM_TYPE_SETTING_IP4_CONFIG); if (s_ip4 && nm_streq0 (nm_setting_ip_config_get_method (s_ip4), NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) @@ -4026,10 +4032,8 @@ nm_device_slave_notify_enslave (NMDevice *self, gboolean success) } if (activating) { - _set_ip_state (self, AF_INET, IP_DONE); - _set_ip_state (self, AF_INET6, IP_DONE); if (success) - nm_device_queue_state (self, NM_DEVICE_STATE_SECONDARIES, NM_DEVICE_STATE_REASON_NONE); + check_ip_state (self, FALSE); else nm_device_queue_state (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_UNKNOWN); } else @@ -8022,12 +8026,6 @@ nm_device_activate_stage3_ip4_start (NMDevice *self) g_assert (priv->ip4_state == IP_WAIT); - /* Slaves stay in IP_CONFIG state until master is ready, and then - * they go directly to SECONDARIES without configuring IPv4. - */ - if (nm_active_connection_get_master (NM_ACTIVE_CONNECTION (priv->act_request))) - return TRUE; - _set_ip_state (self, AF_INET, IP_CONF); ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip4_config_start (self, &ip4_config, &failure_reason); if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { @@ -8069,12 +8067,6 @@ nm_device_activate_stage3_ip6_start (NMDevice *self) g_assert (priv->ip6_state == IP_WAIT); - /* Slaves stay in IP_CONFIG state until master is ready, and then - * they go directly to SECONDARIES without configuring IPv6. - */ - if (nm_active_connection_get_master (NM_ACTIVE_CONNECTION (priv->act_request))) - return TRUE; - _set_ip_state (self, AF_INET6, IP_CONF); ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip6_config_start (self, &ip6_config, &failure_reason); if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { @@ -8113,10 +8105,6 @@ nm_device_activate_stage3_ip6_start (NMDevice *self) static void activate_stage3_ip_config_start (NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMActiveConnection *master; - NMDevice *master_device; - _set_ip_state (self, AF_INET, IP_WAIT); _set_ip_state (self, AF_INET6, IP_WAIT); @@ -8129,26 +8117,6 @@ activate_stage3_ip_config_start (NMDevice *self) if (!nm_platform_link_is_up (nm_device_get_platform (self), nm_device_get_ip_ifindex (self))) _LOGW (LOGD_DEVICE, "interface %s not up for IP configuration", nm_device_get_ip_iface (self)); - /* If the device is a slave, then we don't do any IP configuration but we - * use the IP config stage to indicate to the master we're ready for - * enslavement. If the master is already activating, it will have tried to - * enslave us when we changed state to IP_CONFIG, causing us to queue a - * transition to SECONDARIES (or FAILED if the enslavement failed), with - * our IP states set to IP_DONE either way. If the master isn't yet - * activating, then they'll still be in IP_WAIT. Either way, we bail out - * of IP config here. - */ - master = nm_active_connection_get_master (NM_ACTIVE_CONNECTION (priv->act_request)); - if (master) { - master_device = nm_active_connection_get_device (master); - if (priv->ip4_state == IP_WAIT && priv->ip6_state == IP_WAIT) { - _LOGI (LOGD_DEVICE, "Activation: connection '%s' waiting on master '%s'", - nm_connection_get_id (nm_device_get_applied_connection (self)), - master_device ? nm_device_get_iface (master_device) : "(unknown)"); - } - return; - } - /* IPv4 */ if ( nm_device_activate_ip4_state_in_wait (self) && !nm_device_activate_stage3_ip4_start (self)) From d4a7fe46797b081ec3be64be201642ee74d63da3 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 1 Aug 2017 18:36:34 +0200 Subject: [PATCH 15/36] libnm-core: add ovs-patch setting --- Makefile.am | 2 + clients/common/settings-docs.c.in | 2 + libnm-core/nm-connection.c | 16 +++ libnm-core/nm-connection.h | 2 + libnm-core/nm-core-internal.h | 1 + libnm-core/nm-core-types.h | 1 + libnm-core/nm-setting-ovs-patch.c | 215 ++++++++++++++++++++++++++++++ libnm-core/nm-setting-ovs-patch.h | 54 ++++++++ libnm/libnm.ver | 3 + po/POTFILES.in | 1 + 10 files changed, 297 insertions(+) create mode 100644 libnm-core/nm-setting-ovs-patch.c create mode 100644 libnm-core/nm-setting-ovs-patch.h diff --git a/Makefile.am b/Makefile.am index 83fe9de83d..9c18709083 100644 --- a/Makefile.am +++ b/Makefile.am @@ -393,6 +393,7 @@ libnm_core_lib_h_pub_real = \ libnm-core/nm-setting-macsec.h \ libnm-core/nm-setting-macvlan.h \ libnm-core/nm-setting-olpc-mesh.h \ + libnm-core/nm-setting-ovs-patch.h \ libnm-core/nm-setting-ppp.h \ libnm-core/nm-setting-pppoe.h \ libnm-core/nm-setting-proxy.h \ @@ -474,6 +475,7 @@ libnm_core_lib_c_real = \ libnm-core/nm-setting-macsec.c \ libnm-core/nm-setting-macvlan.c \ libnm-core/nm-setting-olpc-mesh.c \ + libnm-core/nm-setting-ovs-patch.c \ libnm-core/nm-setting-ppp.c \ libnm-core/nm-setting-pppoe.c \ libnm-core/nm-setting-proxy.c \ diff --git a/clients/common/settings-docs.c.in b/clients/common/settings-docs.c.in index 8812255a48..7228c7fb83 100644 --- a/clients/common/settings-docs.c.in +++ b/clients/common/settings-docs.c.in @@ -262,6 +262,8 @@ #define DESCRIBE_DOC_NM_SETTING_MACVLAN_PARENT N_("If given, specifies the parent interface name or parent connection UUID from which this MAC-VLAN interface should be created. If this property is not specified, the connection must contain an \"802-3-ethernet\" setting with a \"mac-address\" property.") #define DESCRIBE_DOC_NM_SETTING_MACVLAN_PROMISCUOUS N_("Whether the interface should be put in promiscuous mode.") #define DESCRIBE_DOC_NM_SETTING_MACVLAN_TAP N_("Whether the interface should be a MACVTAP.") +#define DESCRIBE_DOC_NM_SETTING_OVS_PATCH_NAME N_("The setting's name, which uniquely identifies the setting within the connection. Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".") +#define DESCRIBE_DOC_NM_SETTING_OVS_PATCH_PEER N_("Specifies the unicast destination IP address of a remote OpenVSwitch bridge port to connect to.") #define DESCRIBE_DOC_NM_SETTING_PPP_BAUD N_("If non-zero, instruct pppd to set the serial port to the specified baudrate. This value should normally be left as 0 to automatically choose the speed.") #define DESCRIBE_DOC_NM_SETTING_PPP_CRTSCTS N_("If TRUE, specify that pppd should set the serial port to use hardware flow control with RTS and CTS signals. This value should normally be set to FALSE.") #define DESCRIBE_DOC_NM_SETTING_PPP_LCP_ECHO_FAILURE N_("If non-zero, instruct pppd to presume the connection to the peer has failed if the specified number of LCP echo-requests go unanswered by the peer. The \"lcp-echo-interval\" property must also be set to a non-zero value if this property is used.") diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index 0296c6f9b2..607852e26a 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -2335,6 +2335,22 @@ nm_connection_get_setting_olpc_mesh (NMConnection *connection) return _connection_get_setting_check (connection, NM_TYPE_SETTING_OLPC_MESH); } +/** + * nm_connection_get_setting_ovs_patch: + * @connection: the #NMConnection + * + * A shortcut to return any #NMSettingOvsPatch the connection might contain. + * + * Returns: (transfer none): an #NMSettingOvsPatch if the connection contains one, otherwise %NULL + * + * Since: 1.10 + **/ +NMSettingOvsPatch * +nm_connection_get_setting_ovs_patch (NMConnection *connection) +{ + return _connection_get_setting_check (connection, NM_TYPE_SETTING_OVS_PATCH); +} + /** * nm_connection_get_setting_ppp: * @connection: the #NMConnection diff --git a/libnm-core/nm-connection.h b/libnm-core/nm-connection.h index fae9862a40..dc664c6939 100644 --- a/libnm-core/nm-connection.h +++ b/libnm-core/nm-connection.h @@ -213,6 +213,8 @@ NMSettingMacsec * nm_connection_get_setting_macsec (NMConnec NM_AVAILABLE_IN_1_2 NMSettingMacvlan * nm_connection_get_setting_macvlan (NMConnection *connection); NMSettingOlpcMesh * nm_connection_get_setting_olpc_mesh (NMConnection *connection); +NM_AVAILABLE_IN_1_10 +NMSettingOvsPatch * nm_connection_get_setting_ovs_patch (NMConnection *connection); NMSettingPpp * nm_connection_get_setting_ppp (NMConnection *connection); NMSettingPppoe * nm_connection_get_setting_pppoe (NMConnection *connection); NM_AVAILABLE_IN_1_6 diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index adba8ed116..a379d8e781 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -56,6 +56,7 @@ #include "nm-setting-macsec.h" #include "nm-setting-macvlan.h" #include "nm-setting-olpc-mesh.h" +#include "nm-setting-ovs-patch.h" #include "nm-setting-ppp.h" #include "nm-setting-pppoe.h" #include "nm-setting-serial.h" diff --git a/libnm-core/nm-core-types.h b/libnm-core/nm-core-types.h index 3b9ec37b8e..2599717b50 100644 --- a/libnm-core/nm-core-types.h +++ b/libnm-core/nm-core-types.h @@ -50,6 +50,7 @@ typedef struct _NMSettingIP6Config NMSettingIP6Config; typedef struct _NMSettingMacsec NMSettingMacsec; typedef struct _NMSettingMacvlan NMSettingMacvlan; typedef struct _NMSettingOlpcMesh NMSettingOlpcMesh; +typedef struct _NMSettingOvsPatch NMSettingOvsPatch; typedef struct _NMSettingPpp NMSettingPpp; typedef struct _NMSettingPppoe NMSettingPppoe; typedef struct _NMSettingSerial NMSettingSerial; diff --git a/libnm-core/nm-setting-ovs-patch.c b/libnm-core/nm-setting-ovs-patch.c new file mode 100644 index 0000000000..9e38091474 --- /dev/null +++ b/libnm-core/nm-setting-ovs-patch.c @@ -0,0 +1,215 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-setting-ovs-patch.h" + +#include "nm-connection-private.h" +#include "nm-setting-connection.h" +#include "nm-setting-private.h" + +/** + * SECTION:nm-setting-ovs-patch + * @short_description: Describes connection properties for OpenVSwitch patch interfaces. + * + * The #NMSettingOvsPatch object is a #NMSetting subclass that describes properties + * necessary for OpenVSwitch interfaces of type "patch". + **/ + +enum { + PROP_0, + PROP_PEER, + LAST_PROP +}; + +/** + * NMSettingOvsPatch: + * + * OvsPatch Link Settings + */ +struct _NMSettingOvsPatch { + NMSetting parent; + + char *peer; +}; + +struct _NMSettingOvsPatchClass { + NMSettingClass parent; +}; + +G_DEFINE_TYPE_WITH_CODE (NMSettingOvsPatch, nm_setting_ovs_patch, NM_TYPE_SETTING, + _nm_register_setting (OVS_PATCH, NM_SETTING_PRIORITY_HW_BASE)) +NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_OVS_PATCH) + +/*****************************************************************************/ + +/** + * nm_setting_ovs_patch_get_peer: + * @self: the #NMSettingOvsPatch + * + * Returns: the #NMSettingOvsPatch:peer property of the setting + * + * Since: 1.10 + **/ +const char * +nm_setting_ovs_patch_get_peer (NMSettingOvsPatch *self) +{ + g_return_val_if_fail (NM_IS_SETTING_OVS_PATCH (self), NULL); + + return self->peer; +} + +/*****************************************************************************/ + +static int +verify (NMSetting *setting, NMConnection *connection, GError **error) +{ + NMSettingOvsPatch *self = NM_SETTING_OVS_PATCH (setting); + int family = AF_UNSPEC; + + if (!_nm_connection_verify_required_interface_name (connection, error)) + return FALSE; + + if (!self->peer) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("property is missing")); + g_prefix_error (error, "%s.%s: ", + NM_SETTING_OVS_PATCH_SETTING_NAME, + NM_SETTING_OVS_PATCH_PEER); + return FALSE; + } + + if (nm_utils_ipaddr_valid (AF_INET, self->peer)) + family = AF_INET; + else if (nm_utils_ipaddr_valid (AF_INET6, self->peer)) + family = AF_INET6; + else { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid IP address"), + self->peer); + g_prefix_error (error, "%s.%s: ", + NM_SETTING_OVS_PATCH_SETTING_NAME, + NM_SETTING_OVS_PATCH_PEER); + return FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMSettingOvsPatch *self = NM_SETTING_OVS_PATCH (object); + + switch (prop_id) { + case PROP_PEER: + g_value_set_string (value, self->peer); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMSettingOvsPatch *self = NM_SETTING_OVS_PATCH (object); + + switch (prop_id) { + case PROP_PEER: + g_free (self->peer); + self->peer = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_setting_ovs_patch_init (NMSettingOvsPatch *self) +{ +} + +/** + * nm_setting_ovs_patch_new: + * + * Creates a new #NMSettingOvsPatch object with default values. + * + * Returns: (transfer full): the new empty #NMSettingOvsPatch object + * + * Since: 1.10 + **/ +NMSetting * +nm_setting_ovs_patch_new (void) +{ + return (NMSetting *) g_object_new (NM_TYPE_SETTING_OVS_PATCH, NULL); +} + +static void +finalize (GObject *object) +{ + NMSettingOvsPatch *self = NM_SETTING_OVS_PATCH (object); + + g_free (self->peer); + + G_OBJECT_CLASS (nm_setting_ovs_patch_parent_class)->finalize (object); +} + +static void +nm_setting_ovs_patch_class_init (NMSettingOvsPatchClass *setting_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (setting_class); + NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class); + + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->finalize = finalize; + parent_class->verify = verify; + + /** + * NMSettingOvsPatch:peer: + * + * Specifies the unicast destination IP address of a remote OpenVSwitch + * bridge port to connect to. + * + * Since: 1.10 + **/ + g_object_class_install_property + (object_class, PROP_PEER, + g_param_spec_string (NM_SETTING_OVS_PATCH_PEER, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/libnm-core/nm-setting-ovs-patch.h b/libnm-core/nm-setting-ovs-patch.h new file mode 100644 index 0000000000..091f0d43d5 --- /dev/null +++ b/libnm-core/nm-setting-ovs-patch.h @@ -0,0 +1,54 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#ifndef __NM_SETTING_OVS_PATCH_H__ +#define __NM_SETTING_OVS_PATCH_H__ + +#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION) +#error "Only can be included directly." +#endif + +#include "nm-setting.h" + +G_BEGIN_DECLS + +#define NM_TYPE_SETTING_OVS_PATCH (nm_setting_ovs_patch_get_type ()) +#define NM_SETTING_OVS_PATCH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_OVS_PATCH, NMSettingOvsPatch)) +#define NM_SETTING_OVS_PATCH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_OVS_PATCHCONFIG, NMSettingOvsPatchClass)) +#define NM_IS_SETTING_OVS_PATCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_OVS_PATCH)) +#define NM_IS_SETTING_OVS_PATCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTING_OVS_PATCH)) +#define NM_SETTING_OVS_PATCH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_OVS_PATCH, NMSettingOvsPatchClass)) + +#define NM_SETTING_OVS_PATCH_SETTING_NAME "ovs-patch" + +#define NM_SETTING_OVS_PATCH_PEER "peer" + +typedef struct _NMSettingOvsPatchClass NMSettingOvsPatchClass; + +NM_AVAILABLE_IN_1_10 +GType nm_setting_ovs_patch_get_type (void); +NM_AVAILABLE_IN_1_10 +NMSetting *nm_setting_ovs_patch_new (void); + +NM_AVAILABLE_IN_1_10 +const char *nm_setting_ovs_patch_get_peer (NMSettingOvsPatch *self); + +G_END_DECLS + +#endif /* __NM_SETTING_OVS_PATCH_H__ */ diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 0fd28beecd..18b318c716 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1190,6 +1190,9 @@ global: nm_ip_route_equal_full; nm_setting_bridge_get_group_forward_mask; nm_setting_ip_config_get_route_table; + nm_setting_ovs_patch_get_peer; + nm_setting_ovs_patch_get_type; + nm_setting_ovs_patch_new; nm_setting_pppoe_get_parent; nm_setting_wireless_security_get_pmf; nm_setting_wireless_security_get_wps_method; diff --git a/po/POTFILES.in b/po/POTFILES.in index d4dfc496bb..21da33f0aa 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -75,6 +75,7 @@ libnm-core/nm-setting-ip-tunnel.c libnm-core/nm-setting-macsec.c libnm-core/nm-setting-macvlan.c libnm-core/nm-setting-olpc-mesh.c +libnm-core/nm-setting-ovs-patch.c libnm-core/nm-setting-ppp.c libnm-core/nm-setting-pppoe.c libnm-core/nm-setting-proxy.c From 27790fa976c66d99dd3d2d38ead97e823910bdbb Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 1 Aug 2017 18:36:34 +0200 Subject: [PATCH 16/36] libnm-core: add ovs-interface setting --- Makefile.am | 2 + clients/common/settings-docs.c.in | 2 + libnm-core/nm-connection.c | 47 ++++++ libnm-core/nm-connection.h | 1 + libnm-core/nm-core-internal.h | 1 + libnm-core/nm-core-types.h | 1 + libnm-core/nm-setting-ovs-interface.c | 229 ++++++++++++++++++++++++++ libnm-core/nm-setting-ovs-interface.h | 54 ++++++ libnm-core/nm-setting-ovs-patch.c | 31 ++++ libnm-core/nm-setting.c | 2 + libnm/libnm.ver | 3 + po/POTFILES.in | 1 + 12 files changed, 374 insertions(+) create mode 100644 libnm-core/nm-setting-ovs-interface.c create mode 100644 libnm-core/nm-setting-ovs-interface.h diff --git a/Makefile.am b/Makefile.am index 9c18709083..2b8e423995 100644 --- a/Makefile.am +++ b/Makefile.am @@ -393,6 +393,7 @@ libnm_core_lib_h_pub_real = \ libnm-core/nm-setting-macsec.h \ libnm-core/nm-setting-macvlan.h \ libnm-core/nm-setting-olpc-mesh.h \ + libnm-core/nm-setting-ovs-interface.h \ libnm-core/nm-setting-ovs-patch.h \ libnm-core/nm-setting-ppp.h \ libnm-core/nm-setting-pppoe.h \ @@ -475,6 +476,7 @@ libnm_core_lib_c_real = \ libnm-core/nm-setting-macsec.c \ libnm-core/nm-setting-macvlan.c \ libnm-core/nm-setting-olpc-mesh.c \ + libnm-core/nm-setting-ovs-interface.c \ libnm-core/nm-setting-ovs-patch.c \ libnm-core/nm-setting-ppp.c \ libnm-core/nm-setting-pppoe.c \ diff --git a/clients/common/settings-docs.c.in b/clients/common/settings-docs.c.in index 7228c7fb83..34e1683659 100644 --- a/clients/common/settings-docs.c.in +++ b/clients/common/settings-docs.c.in @@ -262,6 +262,8 @@ #define DESCRIBE_DOC_NM_SETTING_MACVLAN_PARENT N_("If given, specifies the parent interface name or parent connection UUID from which this MAC-VLAN interface should be created. If this property is not specified, the connection must contain an \"802-3-ethernet\" setting with a \"mac-address\" property.") #define DESCRIBE_DOC_NM_SETTING_MACVLAN_PROMISCUOUS N_("Whether the interface should be put in promiscuous mode.") #define DESCRIBE_DOC_NM_SETTING_MACVLAN_TAP N_("Whether the interface should be a MACVTAP.") +#define DESCRIBE_DOC_NM_SETTING_OVS_INTERFACE_NAME N_("The setting's name, which uniquely identifies the setting within the connection. Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".") +#define DESCRIBE_DOC_NM_SETTING_OVS_INTERFACE_TYPE N_("The interface type. Either \"internal\", or empty.") #define DESCRIBE_DOC_NM_SETTING_OVS_PATCH_NAME N_("The setting's name, which uniquely identifies the setting within the connection. Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".") #define DESCRIBE_DOC_NM_SETTING_OVS_PATCH_PEER N_("Specifies the unicast destination IP address of a remote OpenVSwitch bridge port to connect to.") #define DESCRIBE_DOC_NM_SETTING_PPP_BAUD N_("If non-zero, instruct pppd to set the serial port to the specified baudrate. This value should normally be left as 0 to automatically choose the speed.") diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index 607852e26a..43a5356133 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -1095,6 +1095,35 @@ _normalize_bluetooth_type (NMConnection *self, GHashTable *parameters) return FALSE; } +static gboolean +_normalize_ovs_interface_type (NMConnection *self, GHashTable *parameters) +{ + NMSettingOvsInterface *s_ovs_interface = nm_connection_get_setting_ovs_interface (self); + const char *interface_type; + + if (strcmp (nm_connection_get_connection_type (self), NM_SETTING_OVS_INTERFACE_SETTING_NAME) == 0) { + /* OpenVSwitch managed interface. */ + if (nm_connection_get_setting_ovs_patch (self)) + interface_type = "patch"; + else + interface_type = "internal"; + } else { + /* Something else. */ + return FALSE; + } + + if (!s_ovs_interface) { + s_ovs_interface = NM_SETTING_OVS_INTERFACE (nm_setting_ovs_interface_new ()); + nm_connection_add_setting (self, NM_SETTING (s_ovs_interface)); + } + + g_object_set (s_ovs_interface, + NM_SETTING_OVS_INTERFACE_TYPE, interface_type, + NULL); + + return TRUE; +} + static gboolean _normalize_required_settings (NMConnection *self, GHashTable *parameters) { @@ -1397,6 +1426,7 @@ nm_connection_normalize (NMConnection *connection, was_modified |= _normalize_team_config (connection, parameters); was_modified |= _normalize_team_port_config (connection, parameters); was_modified |= _normalize_bluetooth_type (connection, parameters); + was_modified |= _normalize_ovs_interface_type (connection, parameters); /* Verify anew. */ success = _nm_connection_verify (connection, error); @@ -1983,6 +2013,7 @@ nm_connection_is_virtual (NMConnection *connection) || !strcmp (type, NM_SETTING_IP_TUNNEL_SETTING_NAME) || !strcmp (type, NM_SETTING_MACSEC_SETTING_NAME) || !strcmp (type, NM_SETTING_MACVLAN_SETTING_NAME) + || !strcmp (type, NM_SETTING_OVS_INTERFACE_SETTING_NAME) || !strcmp (type, NM_SETTING_VXLAN_SETTING_NAME)) return TRUE; @@ -2335,6 +2366,22 @@ nm_connection_get_setting_olpc_mesh (NMConnection *connection) return _connection_get_setting_check (connection, NM_TYPE_SETTING_OLPC_MESH); } +/** + * nm_connection_get_setting_ovs_interface: + * @connection: the #NMConnection + * + * A shortcut to return any #NMSettingOvsInterface the connection might contain. + * + * Returns: (transfer none): an #NMSettingOvsInterface if the connection contains one, otherwise %NULL + * + * Since: 1.10 + **/ +NMSettingOvsInterface * +nm_connection_get_setting_ovs_interface (NMConnection *connection) +{ + return _connection_get_setting_check (connection, NM_TYPE_SETTING_OVS_INTERFACE); +} + /** * nm_connection_get_setting_ovs_patch: * @connection: the #NMConnection diff --git a/libnm-core/nm-connection.h b/libnm-core/nm-connection.h index dc664c6939..6d49c3a3d9 100644 --- a/libnm-core/nm-connection.h +++ b/libnm-core/nm-connection.h @@ -214,6 +214,7 @@ NM_AVAILABLE_IN_1_2 NMSettingMacvlan * nm_connection_get_setting_macvlan (NMConnection *connection); NMSettingOlpcMesh * nm_connection_get_setting_olpc_mesh (NMConnection *connection); NM_AVAILABLE_IN_1_10 +NMSettingOvsInterface * nm_connection_get_setting_ovs_interface (NMConnection *connection); NMSettingOvsPatch * nm_connection_get_setting_ovs_patch (NMConnection *connection); NMSettingPpp * nm_connection_get_setting_ppp (NMConnection *connection); NMSettingPppoe * nm_connection_get_setting_pppoe (NMConnection *connection); diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index a379d8e781..550a08d1a5 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -56,6 +56,7 @@ #include "nm-setting-macsec.h" #include "nm-setting-macvlan.h" #include "nm-setting-olpc-mesh.h" +#include "nm-setting-ovs-interface.h" #include "nm-setting-ovs-patch.h" #include "nm-setting-ppp.h" #include "nm-setting-pppoe.h" diff --git a/libnm-core/nm-core-types.h b/libnm-core/nm-core-types.h index 2599717b50..4026f9e3f9 100644 --- a/libnm-core/nm-core-types.h +++ b/libnm-core/nm-core-types.h @@ -50,6 +50,7 @@ typedef struct _NMSettingIP6Config NMSettingIP6Config; typedef struct _NMSettingMacsec NMSettingMacsec; typedef struct _NMSettingMacvlan NMSettingMacvlan; typedef struct _NMSettingOlpcMesh NMSettingOlpcMesh; +typedef struct _NMSettingOvsInterface NMSettingOvsInterface; typedef struct _NMSettingOvsPatch NMSettingOvsPatch; typedef struct _NMSettingPpp NMSettingPpp; typedef struct _NMSettingPppoe NMSettingPppoe; diff --git a/libnm-core/nm-setting-ovs-interface.c b/libnm-core/nm-setting-ovs-interface.c new file mode 100644 index 0000000000..b9e749ba96 --- /dev/null +++ b/libnm-core/nm-setting-ovs-interface.c @@ -0,0 +1,229 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-setting-ovs-interface.h" + +#include "nm-connection-private.h" +#include "nm-setting-connection.h" +#include "nm-setting-private.h" + +/** + * SECTION:nm-setting-ovs-interface + * @short_description: Describes connection properties for OpenVSwitch interfaces. + * + * The #NMSettingOvsInterface object is a #NMSetting subclass that describes properties + * necessary for OpenVSwitch interfaces. + **/ + +enum { + PROP_0, + PROP_TYPE, + LAST_PROP +}; + +/** + * NMSettingOvsInterface: + * + * OpenVSwitch Interface Settings + */ +struct _NMSettingOvsInterface { + NMSetting parent; + + char *type; +}; + +struct _NMSettingOvsInterfaceClass { + NMSettingClass parent; +}; + +G_DEFINE_TYPE_WITH_CODE (NMSettingOvsInterface, nm_setting_ovs_interface, NM_TYPE_SETTING, + _nm_register_setting (OVS_INTERFACE, NM_SETTING_PRIORITY_HW_BASE)) +NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_OVS_INTERFACE) + +/*****************************************************************************/ + +/** + * nm_setting_ovs_interface_get_interface_type: + * @self: the #NMSettingOvsInterface + * + * Returns: the #NMSettingOvsInterface:type property of the setting + * + * Since: 1.10 + **/ +const char * +nm_setting_ovs_interface_get_interface_type (NMSettingOvsInterface *self) +{ + g_return_val_if_fail (NM_IS_SETTING_OVS_INTERFACE (self), NULL); + + return self->type; +} + +/*****************************************************************************/ + +static int +verify (NMSetting *setting, NMConnection *connection, GError **error) +{ + NMSettingOvsInterface *self = NM_SETTING_OVS_INTERFACE (setting); + + if (connection) { + NMSettingConnection *s_con; + + s_con = nm_connection_get_setting_connection (connection); + if (!s_con) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_SETTING, + _("missing setting")); + g_prefix_error (error, "%s: ", NM_SETTING_CONNECTION_SETTING_NAME); + return FALSE; + } + + if (!nm_setting_connection_get_master (s_con)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("A connection with a '%s' setting must have a master."), + NM_SETTING_OVS_INTERFACE_SETTING_NAME); + g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_MASTER); + return FALSE; + } + } + + if (!NM_IN_STRSET (self->type, "internal", "system", "patch", "", NULL)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid interface type"), + self->type); + g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_INTERFACE_SETTING_NAME, NM_SETTING_OVS_INTERFACE_TYPE); + return FALSE; + } + + if (connection) { + if ( g_strcmp0 (self->type, "patch") == 0 + && !nm_connection_get_setting_ovs_patch (connection)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("A connection of 'patch' interface type needs a '%s' setting."), + NM_SETTING_OVS_PATCH_SETTING_NAME); + g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_INTERFACE_SETTING_NAME, NM_SETTING_OVS_INTERFACE_TYPE); + return FALSE; + } + } + + return TRUE; +} + +/*****************************************************************************/ + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMSettingOvsInterface *self = NM_SETTING_OVS_INTERFACE (object); + + switch (prop_id) { + case PROP_TYPE: + g_value_set_string (value, self->type); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMSettingOvsInterface *self = NM_SETTING_OVS_INTERFACE (object); + + switch (prop_id) { + case PROP_TYPE: + g_free (self->type); + self->type = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_setting_ovs_interface_init (NMSettingOvsInterface *self) +{ +} + +/** + * nm_setting_ovs_interface_new: + * + * Creates a new #NMSettingOvsInterface object with default values. + * + * Returns: (transfer full): the new empty #NMSettingOvsInterface object + * + * Since: 1.10 + **/ +NMSetting * +nm_setting_ovs_interface_new (void) +{ + return (NMSetting *) g_object_new (NM_TYPE_SETTING_OVS_INTERFACE, NULL); +} + +static void +finalize (GObject *object) +{ + NMSettingOvsInterface *self = NM_SETTING_OVS_INTERFACE (object); + + g_free (self->type); + + G_OBJECT_CLASS (nm_setting_ovs_interface_parent_class)->finalize (object); +} + +static void +nm_setting_ovs_interface_class_init (NMSettingOvsInterfaceClass *setting_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (setting_class); + NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class); + + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->finalize = finalize; + parent_class->verify = verify; + + /** + * NMSettingOvsInterface:type: + * + * The interface type. Either "internal", or empty. + * + * Since: 1.10 + **/ + g_object_class_install_property + (object_class, PROP_TYPE, + g_param_spec_string (NM_SETTING_OVS_INTERFACE_TYPE, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/libnm-core/nm-setting-ovs-interface.h b/libnm-core/nm-setting-ovs-interface.h new file mode 100644 index 0000000000..7261cfd8c9 --- /dev/null +++ b/libnm-core/nm-setting-ovs-interface.h @@ -0,0 +1,54 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#ifndef __NM_SETTING_OVS_INTERFACE_H__ +#define __NM_SETTING_OVS_INTERFACE_H__ + +#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION) +#error "Only can be included directly." +#endif + +#include "nm-setting.h" + +G_BEGIN_DECLS + +#define NM_TYPE_SETTING_OVS_INTERFACE (nm_setting_ovs_interface_get_type ()) +#define NM_SETTING_OVS_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_OVS_INTERFACE, NMSettingOvsInterface)) +#define NM_SETTING_OVS_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_OVS_INTERFACECONFIG, NMSettingOvsInterfaceClass)) +#define NM_IS_SETTING_OVS_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_OVS_INTERFACE)) +#define NM_IS_SETTING_OVS_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTING_OVS_INTERFACE)) +#define NM_SETTING_OVS_INTERFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_OVS_INTERFACE, NMSettingOvsInterfaceClass)) + +#define NM_SETTING_OVS_INTERFACE_SETTING_NAME "ovs-interface" + +#define NM_SETTING_OVS_INTERFACE_TYPE "type" + +typedef struct _NMSettingOvsInterfaceClass NMSettingOvsInterfaceClass; + +NM_AVAILABLE_IN_1_10 +GType nm_setting_ovs_interface_get_type (void); +NM_AVAILABLE_IN_1_10 +NMSetting *nm_setting_ovs_interface_new (void); + +NM_AVAILABLE_IN_1_10 +const char *nm_setting_ovs_interface_get_interface_type (NMSettingOvsInterface *self); + +G_END_DECLS + +#endif /* __NM_SETTING_OVS_INTERFACE_H__ */ diff --git a/libnm-core/nm-setting-ovs-patch.c b/libnm-core/nm-setting-ovs-patch.c index 9e38091474..fb1412bf4a 100644 --- a/libnm-core/nm-setting-ovs-patch.c +++ b/libnm-core/nm-setting-ovs-patch.c @@ -115,6 +115,37 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } + + if (connection) { + NMSettingOvsInterface *s_ovs_interface; + const char *interface_type = NULL; + + s_ovs_interface = nm_connection_get_setting_ovs_interface (connection); + if (s_ovs_interface) + interface_type = nm_setting_ovs_interface_get_interface_type (s_ovs_interface); + + if (interface_type && strcmp (interface_type, "patch") != 0) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("A connection with '%s' setting needs to be of 'patch' interface type, not '%s'"), + NM_SETTING_OVS_PATCH_SETTING_NAME, + interface_type); + g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_INTERFACE_SETTING_NAME, NM_SETTING_OVS_INTERFACE_TYPE); + return FALSE; + } + + if (!interface_type) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("A connection with '%s' setting needs to be of 'patch' interface type"), + NM_SETTING_OVS_PATCH_SETTING_NAME); + g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_INTERFACE_SETTING_NAME, NM_SETTING_OVS_INTERFACE_TYPE); + return NM_SETTING_VERIFY_NORMALIZABLE_ERROR; + } + } + return TRUE; } diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c index 2f282db6aa..f103727ce9 100644 --- a/libnm-core/nm-setting.c +++ b/libnm-core/nm-setting.c @@ -258,6 +258,8 @@ _nm_setting_slave_type_is_valid (const char *slave_type, const char **out_port_t ; else if (!strcmp (slave_type, NM_SETTING_BRIDGE_SETTING_NAME)) port_type = NM_SETTING_BRIDGE_PORT_SETTING_NAME; + else if (!strcmp (slave_type, NM_SETTING_OVS_INTERFACE_SETTING_NAME)) + ; else if (!strcmp (slave_type, NM_SETTING_TEAM_SETTING_NAME)) port_type = NM_SETTING_TEAM_PORT_SETTING_NAME; else diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 18b318c716..5045a2a9e6 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1190,6 +1190,9 @@ global: nm_ip_route_equal_full; nm_setting_bridge_get_group_forward_mask; nm_setting_ip_config_get_route_table; + nm_setting_ovs_interface_get_interface_type; + nm_setting_ovs_interface_get_type; + nm_setting_ovs_interface_new; nm_setting_ovs_patch_get_peer; nm_setting_ovs_patch_get_type; nm_setting_ovs_patch_new; diff --git a/po/POTFILES.in b/po/POTFILES.in index 21da33f0aa..e5b50a780e 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -75,6 +75,7 @@ libnm-core/nm-setting-ip-tunnel.c libnm-core/nm-setting-macsec.c libnm-core/nm-setting-macvlan.c libnm-core/nm-setting-olpc-mesh.c +libnm-core/nm-setting-ovs-interface.c libnm-core/nm-setting-ovs-patch.c libnm-core/nm-setting-ppp.c libnm-core/nm-setting-pppoe.c From 8a1ae40a80efcd6632ea7ba4845b85aec5afe19b Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 2 Oct 2017 09:03:19 +0200 Subject: [PATCH 17/36] libnm-core: add ovs-port setting --- Makefile.am | 2 + clients/common/settings-docs.c.in | 7 + libnm-core/nm-connection.c | 21 ++ libnm-core/nm-connection.h | 2 + libnm-core/nm-core-internal.h | 1 + libnm-core/nm-core-types.h | 1 + libnm-core/nm-setting-ovs-interface.c | 15 + libnm-core/nm-setting-ovs-port.c | 456 ++++++++++++++++++++++++++ libnm-core/nm-setting-ovs-port.h | 69 ++++ libnm-core/nm-setting.c | 4 +- libnm/libnm.ver | 8 + po/POTFILES.in | 1 + 12 files changed, 585 insertions(+), 2 deletions(-) create mode 100644 libnm-core/nm-setting-ovs-port.c create mode 100644 libnm-core/nm-setting-ovs-port.h diff --git a/Makefile.am b/Makefile.am index 2b8e423995..31a4f03f5d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -395,6 +395,7 @@ libnm_core_lib_h_pub_real = \ libnm-core/nm-setting-olpc-mesh.h \ libnm-core/nm-setting-ovs-interface.h \ libnm-core/nm-setting-ovs-patch.h \ + libnm-core/nm-setting-ovs-port.h \ libnm-core/nm-setting-ppp.h \ libnm-core/nm-setting-pppoe.h \ libnm-core/nm-setting-proxy.h \ @@ -478,6 +479,7 @@ libnm_core_lib_c_real = \ libnm-core/nm-setting-olpc-mesh.c \ libnm-core/nm-setting-ovs-interface.c \ libnm-core/nm-setting-ovs-patch.c \ + libnm-core/nm-setting-ovs-port.c \ libnm-core/nm-setting-ppp.c \ libnm-core/nm-setting-pppoe.c \ libnm-core/nm-setting-proxy.c \ diff --git a/clients/common/settings-docs.c.in b/clients/common/settings-docs.c.in index 34e1683659..0eea53c4e6 100644 --- a/clients/common/settings-docs.c.in +++ b/clients/common/settings-docs.c.in @@ -266,6 +266,13 @@ #define DESCRIBE_DOC_NM_SETTING_OVS_INTERFACE_TYPE N_("The interface type. Either \"internal\", or empty.") #define DESCRIBE_DOC_NM_SETTING_OVS_PATCH_NAME N_("The setting's name, which uniquely identifies the setting within the connection. Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".") #define DESCRIBE_DOC_NM_SETTING_OVS_PATCH_PEER N_("Specifies the unicast destination IP address of a remote OpenVSwitch bridge port to connect to.") +#define DESCRIBE_DOC_NM_SETTING_OVS_PORT_BOND_DOWNDELAY N_("The time port must be inactive in order to be considered down.") +#define DESCRIBE_DOC_NM_SETTING_OVS_PORT_BOND_MODE N_("Bonding mode. One of \"active-backup\", \"balance-slb\", or \"balance-tcp\".") +#define DESCRIBE_DOC_NM_SETTING_OVS_PORT_BOND_UPDELAY N_("The time port must be active befor it starts forwarding traffic.") +#define DESCRIBE_DOC_NM_SETTING_OVS_PORT_LACP N_("LACP mode. One of \"active\", \"off\", or \"passive\".") +#define DESCRIBE_DOC_NM_SETTING_OVS_PORT_NAME N_("The setting's name, which uniquely identifies the setting within the connection. Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".") +#define DESCRIBE_DOC_NM_SETTING_OVS_PORT_TAG N_("The VLAN tag in the range 0-4095.") +#define DESCRIBE_DOC_NM_SETTING_OVS_PORT_VLAN_MODE N_("The VLAN mode. One of \"access\", \"native-tagged\", \"native-untagged\", \"trunk\" or unset.") #define DESCRIBE_DOC_NM_SETTING_PPP_BAUD N_("If non-zero, instruct pppd to set the serial port to the specified baudrate. This value should normally be left as 0 to automatically choose the speed.") #define DESCRIBE_DOC_NM_SETTING_PPP_CRTSCTS N_("If TRUE, specify that pppd should set the serial port to use hardware flow control with RTS and CTS signals. This value should normally be set to FALSE.") #define DESCRIBE_DOC_NM_SETTING_PPP_LCP_ECHO_FAILURE N_("If non-zero, instruct pppd to presume the connection to the peer has failed if the specified number of LCP echo-requests go unanswered by the peer. The \"lcp-echo-interval\" property must also be set to a non-zero value if this property is used.") diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index 43a5356133..b1640a45a4 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -1099,6 +1099,7 @@ static gboolean _normalize_ovs_interface_type (NMConnection *self, GHashTable *parameters) { NMSettingOvsInterface *s_ovs_interface = nm_connection_get_setting_ovs_interface (self); + NMSettingConnection *s_con = nm_connection_get_setting_connection (self); const char *interface_type; if (strcmp (nm_connection_get_connection_type (self), NM_SETTING_OVS_INTERFACE_SETTING_NAME) == 0) { @@ -1107,6 +1108,9 @@ _normalize_ovs_interface_type (NMConnection *self, GHashTable *parameters) interface_type = "patch"; else interface_type = "internal"; + } else if (g_strcmp0 (nm_setting_connection_get_slave_type (s_con), NM_SETTING_OVS_PORT_SETTING_NAME) == 0) { + /* A regular device enslaved to a port. */ + interface_type = ""; } else { /* Something else. */ return FALSE; @@ -2014,6 +2018,7 @@ nm_connection_is_virtual (NMConnection *connection) || !strcmp (type, NM_SETTING_MACSEC_SETTING_NAME) || !strcmp (type, NM_SETTING_MACVLAN_SETTING_NAME) || !strcmp (type, NM_SETTING_OVS_INTERFACE_SETTING_NAME) + || !strcmp (type, NM_SETTING_OVS_PORT_SETTING_NAME) || !strcmp (type, NM_SETTING_VXLAN_SETTING_NAME)) return TRUE; @@ -2397,6 +2402,22 @@ nm_connection_get_setting_ovs_patch (NMConnection *connection) { return _connection_get_setting_check (connection, NM_TYPE_SETTING_OVS_PATCH); } + +/** + * nm_connection_get_setting_ovs_port: + * @connection: the #NMConnection + * + * A shortcut to return any #NMSettingOvsPort the connection might contain. + * + * Returns: (transfer none): an #NMSettingOvsPort if the connection contains one, otherwise %NULL + * + * Since: 1.10 + **/ +NMSettingOvsPort * +nm_connection_get_setting_ovs_port (NMConnection *connection) +{ + return _connection_get_setting_check (connection, NM_TYPE_SETTING_OVS_PORT); +} /** * nm_connection_get_setting_ppp: diff --git a/libnm-core/nm-connection.h b/libnm-core/nm-connection.h index 6d49c3a3d9..cac421bd20 100644 --- a/libnm-core/nm-connection.h +++ b/libnm-core/nm-connection.h @@ -216,6 +216,8 @@ NMSettingOlpcMesh * nm_connection_get_setting_olpc_mesh (NMConnec NM_AVAILABLE_IN_1_10 NMSettingOvsInterface * nm_connection_get_setting_ovs_interface (NMConnection *connection); NMSettingOvsPatch * nm_connection_get_setting_ovs_patch (NMConnection *connection); +NM_AVAILABLE_IN_1_10 +NMSettingOvsPort * nm_connection_get_setting_ovs_port (NMConnection *connection); NMSettingPpp * nm_connection_get_setting_ppp (NMConnection *connection); NMSettingPppoe * nm_connection_get_setting_pppoe (NMConnection *connection); NM_AVAILABLE_IN_1_6 diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 550a08d1a5..408a849064 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -58,6 +58,7 @@ #include "nm-setting-olpc-mesh.h" #include "nm-setting-ovs-interface.h" #include "nm-setting-ovs-patch.h" +#include "nm-setting-ovs-port.h" #include "nm-setting-ppp.h" #include "nm-setting-pppoe.h" #include "nm-setting-serial.h" diff --git a/libnm-core/nm-core-types.h b/libnm-core/nm-core-types.h index 4026f9e3f9..a66a94ef56 100644 --- a/libnm-core/nm-core-types.h +++ b/libnm-core/nm-core-types.h @@ -52,6 +52,7 @@ typedef struct _NMSettingMacvlan NMSettingMacvlan; typedef struct _NMSettingOlpcMesh NMSettingOlpcMesh; typedef struct _NMSettingOvsInterface NMSettingOvsInterface; typedef struct _NMSettingOvsPatch NMSettingOvsPatch; +typedef struct _NMSettingOvsPort NMSettingOvsPort; typedef struct _NMSettingPpp NMSettingPpp; typedef struct _NMSettingPppoe NMSettingPppoe; typedef struct _NMSettingSerial NMSettingSerial; diff --git a/libnm-core/nm-setting-ovs-interface.c b/libnm-core/nm-setting-ovs-interface.c index b9e749ba96..3b214af892 100644 --- a/libnm-core/nm-setting-ovs-interface.c +++ b/libnm-core/nm-setting-ovs-interface.c @@ -85,6 +85,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) if (connection) { NMSettingConnection *s_con; + const char *slave_type; s_con = nm_connection_get_setting_connection (connection); if (!s_con) { @@ -105,6 +106,20 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_MASTER); return FALSE; } + + slave_type = nm_setting_connection_get_slave_type (s_con); + if ( slave_type + && strcmp (slave_type, NM_SETTING_OVS_PORT_SETTING_NAME)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("A connection with a '%s' setting must have the slave-type set to '%s'. Instead it is '%s'"), + NM_SETTING_OVS_INTERFACE_SETTING_NAME, + NM_SETTING_OVS_PORT_SETTING_NAME, + slave_type); + g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_SLAVE_TYPE); + return FALSE; + } } if (!NM_IN_STRSET (self->type, "internal", "system", "patch", "", NULL)) { diff --git a/libnm-core/nm-setting-ovs-port.c b/libnm-core/nm-setting-ovs-port.c new file mode 100644 index 0000000000..43b7621bf8 --- /dev/null +++ b/libnm-core/nm-setting-ovs-port.c @@ -0,0 +1,456 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-setting-ovs-port.h" + +#include "nm-connection-private.h" +#include "nm-setting-connection.h" +#include "nm-setting-private.h" + +/** + * SECTION:nm-setting-ovs-port + * @short_description: Describes connection properties for OpenVSwitch ports. + * + * The #NMSettingOvsPort object is a #NMSetting subclass that describes properties + * necessary for OpenVSwitch ports. + **/ + +enum { + PROP_0, + PROP_VLAN_MODE, + PROP_TAG, + PROP_LACP, + PROP_BOND_MODE, + PROP_BOND_UPDELAY, + PROP_BOND_DOWNDELAY, + LAST_PROP +}; + +/** + * NMSettingOvsPort: + * + * OvsPort Link Settings + */ +struct _NMSettingOvsPort { + NMSetting parent; + + char *vlan_mode; + guint tag; + char *lacp; + char *bond_mode; + guint bond_updelay; + guint bond_downdelay; +}; + +struct _NMSettingOvsPortClass { + NMSettingClass parent; +}; + +G_DEFINE_TYPE_WITH_CODE (NMSettingOvsPort, nm_setting_ovs_port, NM_TYPE_SETTING, + _nm_register_setting (OVS_PORT, NM_SETTING_PRIORITY_HW_BASE)) +NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_OVS_PORT) + +/*****************************************************************************/ + +/** + * nm_setting_ovs_port_get_vlan_mode: + * @self: the #NMSettingOvsPort + * + * Returns: the #NMSettingOvsPort:vlan-mode property of the setting + * + * Since: 1.10 + **/ +const char * +nm_setting_ovs_port_get_vlan_mode (NMSettingOvsPort *self) +{ + g_return_val_if_fail (NM_IS_SETTING_OVS_PORT (self), NULL); + + return self->vlan_mode; +} + +/** + * nm_setting_ovs_port_get_tag: + * @self: the #NMSettingOvsPort + * + * Returns: the #NMSettingOvsPort:tag property of the setting + * + * Since: 1.10 + **/ +guint +nm_setting_ovs_port_get_tag (NMSettingOvsPort *self) +{ + g_return_val_if_fail (NM_IS_SETTING_OVS_PORT (self), 0); + + return self->tag; +} + +/** + * nm_setting_ovs_port_get_lacp: + * @self: the #NMSettingOvsPort + * + * Returns: the #NMSettingOvsPort:lacp property of the setting + * + * Since: 1.10 + **/ +const char * +nm_setting_ovs_port_get_lacp (NMSettingOvsPort *self) +{ + g_return_val_if_fail (NM_IS_SETTING_OVS_PORT (self), NULL); + + return self->lacp; +} + +/** + * nm_setting_ovs_port_get_bond_mode: + * @self: the #NMSettingOvsPort + * + * Returns: the #NMSettingOvsPort:bond-mode property of the setting + * + * Since: 1.10 + **/ +const char * +nm_setting_ovs_port_get_bond_mode (NMSettingOvsPort *self) +{ + g_return_val_if_fail (NM_IS_SETTING_OVS_PORT (self), NULL); + + return self->bond_mode; +} + +/** + * nm_setting_ovs_port_get_bond_updelay: + * @self: the #NMSettingOvsPort + * + * Returns: the #NMSettingOvsPort:bond-updelay property of the setting + * + * Since: 1.10 + **/ +guint +nm_setting_ovs_port_get_bond_updelay (NMSettingOvsPort *self) +{ + g_return_val_if_fail (NM_IS_SETTING_OVS_PORT (self), 0); + + return self->bond_updelay; +} + +/** + * nm_setting_ovs_port_get_bond_downdelay: + * @self: the #NMSettingOvsPort + * + * Returns: the #NMSettingOvsPort:bond-downdelay property of the setting + * + * Since: 1.10 + **/ +guint +nm_setting_ovs_port_get_bond_downdelay (NMSettingOvsPort *self) +{ + g_return_val_if_fail (NM_IS_SETTING_OVS_PORT (self), 0); + + return self->bond_downdelay; +} + +/*****************************************************************************/ + +static int +verify (NMSetting *setting, NMConnection *connection, GError **error) +{ + NMSettingOvsPort *self = NM_SETTING_OVS_PORT (setting); + + if (!_nm_connection_verify_required_interface_name (connection, error)) + return FALSE; + + if (connection) { + NMSettingConnection *s_con; + + s_con = nm_connection_get_setting_connection (connection); + if (!s_con) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_SETTING, + _("missing setting")); + g_prefix_error (error, "%s: ", NM_SETTING_CONNECTION_SETTING_NAME); + return FALSE; + } + + if (!nm_setting_connection_get_master (s_con)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("A connection with a '%s' setting must have a master."), + NM_SETTING_OVS_PORT_SETTING_NAME); + g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_MASTER); + return FALSE; + } + } + + if (!NM_IN_STRSET (self->vlan_mode, "access", "native-tagged", "native-untagged", "trunk", NULL)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not allowed in vlan_mode"), + self->vlan_mode); + g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_PORT_SETTING_NAME, NM_SETTING_OVS_PORT_VLAN_MODE); + return FALSE; + } + + if (self->tag >= 4095) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("the tag id must be in range 0-4094 but is %u"), + self->tag); + g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_PORT_SETTING_NAME, NM_SETTING_OVS_PORT_TAG); + return FALSE; + } + + if (!NM_IN_STRSET (self->lacp, "active", "off", "passive", NULL)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not allowed in lacp"), + self->lacp); + g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_PORT_SETTING_NAME, NM_SETTING_OVS_PORT_LACP); + return FALSE; + } + + if (!NM_IN_STRSET (self->bond_mode, "active-backup", "balance-slb", "balance-tcp", NULL)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not allowed in bond_mode"), + self->bond_mode); + g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_PORT_SETTING_NAME, NM_SETTING_OVS_PORT_BOND_MODE); + return FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMSettingOvsPort *self = NM_SETTING_OVS_PORT (object); + + switch (prop_id) { + case PROP_VLAN_MODE: + g_value_set_string (value, self->vlan_mode); + break; + case PROP_TAG: + g_value_set_uint (value, self->tag); + break; + case PROP_LACP: + g_value_set_string (value, self->lacp); + break; + case PROP_BOND_MODE: + g_value_set_string (value, self->bond_mode); + break; + case PROP_BOND_UPDELAY: + g_value_set_uint (value, self->bond_updelay); + break; + case PROP_BOND_DOWNDELAY: + g_value_set_uint (value, self->bond_downdelay); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMSettingOvsPort *self = NM_SETTING_OVS_PORT (object); + + switch (prop_id) { + case PROP_VLAN_MODE: + g_free (self->vlan_mode); + self->vlan_mode = g_value_dup_string (value); + break; + case PROP_TAG: + self->tag = g_value_get_uint (value); + break; + case PROP_LACP: + g_free (self->lacp); + self->lacp = g_value_dup_string (value); + break; + case PROP_BOND_MODE: + g_free (self->bond_mode); + self->bond_mode = g_value_dup_string (value); + break; + case PROP_BOND_UPDELAY: + self->bond_updelay = g_value_get_uint (value); + break; + case PROP_BOND_DOWNDELAY: + self->bond_downdelay = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_setting_ovs_port_init (NMSettingOvsPort *self) +{ +} + +/** + * nm_setting_ovs_port_new: + * + * Creates a new #NMSettingOvsPort object with default values. + * + * Returns: (transfer full): the new empty #NMSettingOvsPort object + * + * Since: 1.10 + **/ +NMSetting * +nm_setting_ovs_port_new (void) +{ + return (NMSetting *) g_object_new (NM_TYPE_SETTING_OVS_PORT, NULL); +} + +static void +finalize (GObject *object) +{ + NMSettingOvsPort *self = NM_SETTING_OVS_PORT (object); + + g_free (self->vlan_mode); + g_free (self->lacp); + g_free (self->bond_mode); + + G_OBJECT_CLASS (nm_setting_ovs_port_parent_class)->finalize (object); +} + +static void +nm_setting_ovs_port_class_init (NMSettingOvsPortClass *setting_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (setting_class); + NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class); + + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->finalize = finalize; + parent_class->verify = verify; + + /** + * NMSettingOvsPort:vlan-mode: + * + * The VLAN mode. One of "access", "native-tagged", "native-untagged", + * "trunk" or unset. + * + * Since: 1.10 + **/ + g_object_class_install_property + (object_class, PROP_VLAN_MODE, + g_param_spec_string (NM_SETTING_OVS_PORT_VLAN_MODE, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingOvsPort:tag: + * + * The VLAN tag in the range 0-4095. + * + * Since: 1.10 + **/ + g_object_class_install_property + (object_class, PROP_TAG, + g_param_spec_uint (NM_SETTING_OVS_PORT_TAG, "", "", + 0, 4095, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingOvsPort:lacp: + * + * LACP mode. One of "active", "off", or "passive". + * + * Since: 1.10 + **/ + g_object_class_install_property + (object_class, PROP_LACP, + g_param_spec_string (NM_SETTING_OVS_PORT_LACP, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingOvsPort:bond-mode: + * + * Bonding mode. One of "active-backup", "balance-slb", or "balance-tcp". + * + * Since: 1.10 + **/ + g_object_class_install_property + (object_class, PROP_BOND_MODE, + g_param_spec_string (NM_SETTING_OVS_PORT_BOND_MODE, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + + /** + * NMSettingOvsPort:bond-updelay: + * + * The time port must be active befor it starts forwarding traffic. + * + * Since: 1.10 + **/ + g_object_class_install_property + (object_class, PROP_BOND_UPDELAY, + g_param_spec_uint (NM_SETTING_OVS_PORT_BOND_UPDELAY, "", "", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingOvsPort:bond-downdelay: + * + * The time port must be inactive in order to be considered down. + * + * Since: 1.10 + **/ + g_object_class_install_property + (object_class, PROP_BOND_DOWNDELAY, + g_param_spec_uint (NM_SETTING_OVS_PORT_BOND_DOWNDELAY, "", "", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); +} diff --git a/libnm-core/nm-setting-ovs-port.h b/libnm-core/nm-setting-ovs-port.h new file mode 100644 index 0000000000..4c14f123df --- /dev/null +++ b/libnm-core/nm-setting-ovs-port.h @@ -0,0 +1,69 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#ifndef __NM_SETTING_OVS_PORT_H__ +#define __NM_SETTING_OVS_PORT_H__ + +#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION) +#error "Only can be included directly." +#endif + +#include "nm-setting.h" + +G_BEGIN_DECLS + +#define NM_TYPE_SETTING_OVS_PORT (nm_setting_ovs_port_get_type ()) +#define NM_SETTING_OVS_PORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_OVS_PORT, NMSettingOvsPort)) +#define NM_SETTING_OVS_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_OVS_PORTCONFIG, NMSettingOvsPortClass)) +#define NM_IS_SETTING_OVS_PORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_OVS_PORT)) +#define NM_IS_SETTING_OVS_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTING_OVS_PORT)) +#define NM_SETTING_OVS_PORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_OVS_PORT, NMSettingOvsPortClass)) + +#define NM_SETTING_OVS_PORT_SETTING_NAME "ovs-port" + +#define NM_SETTING_OVS_PORT_VLAN_MODE "vlan-mode" +#define NM_SETTING_OVS_PORT_TAG "tag" +#define NM_SETTING_OVS_PORT_LACP "lacp" +#define NM_SETTING_OVS_PORT_BOND_MODE "bond-mode" +#define NM_SETTING_OVS_PORT_BOND_UPDELAY "bond-updelay" +#define NM_SETTING_OVS_PORT_BOND_DOWNDELAY "bond-downdelay" + +typedef struct _NMSettingOvsPortClass NMSettingOvsPortClass; + +NM_AVAILABLE_IN_1_10 +GType nm_setting_ovs_port_get_type (void); +NM_AVAILABLE_IN_1_10 +NMSetting *nm_setting_ovs_port_new (void); + +NM_AVAILABLE_IN_1_10 +const char *nm_setting_ovs_port_get_vlan_mode (NMSettingOvsPort *self); +NM_AVAILABLE_IN_1_10 +guint nm_setting_ovs_port_get_tag (NMSettingOvsPort *self); +NM_AVAILABLE_IN_1_10 +const char *nm_setting_ovs_port_get_lacp (NMSettingOvsPort *self); +NM_AVAILABLE_IN_1_10 +const char *nm_setting_ovs_port_get_bond_mode (NMSettingOvsPort *self); +NM_AVAILABLE_IN_1_10 +guint nm_setting_ovs_port_get_bond_updelay (NMSettingOvsPort *self); +NM_AVAILABLE_IN_1_10 +guint nm_setting_ovs_port_get_bond_downdelay (NMSettingOvsPort *self); + +G_END_DECLS + +#endif /* __NM_SETTING_OVS_PORT_H__ */ diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c index f103727ce9..6515f27cf5 100644 --- a/libnm-core/nm-setting.c +++ b/libnm-core/nm-setting.c @@ -258,8 +258,8 @@ _nm_setting_slave_type_is_valid (const char *slave_type, const char **out_port_t ; else if (!strcmp (slave_type, NM_SETTING_BRIDGE_SETTING_NAME)) port_type = NM_SETTING_BRIDGE_PORT_SETTING_NAME; - else if (!strcmp (slave_type, NM_SETTING_OVS_INTERFACE_SETTING_NAME)) - ; + else if (!strcmp (slave_type, NM_SETTING_OVS_PORT_SETTING_NAME)) + port_type = NM_SETTING_OVS_INTERFACE_SETTING_NAME; else if (!strcmp (slave_type, NM_SETTING_TEAM_SETTING_NAME)) port_type = NM_SETTING_TEAM_PORT_SETTING_NAME; else diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 5045a2a9e6..c1e1817bb0 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1196,6 +1196,14 @@ global: nm_setting_ovs_patch_get_peer; nm_setting_ovs_patch_get_type; nm_setting_ovs_patch_new; + nm_setting_ovs_port_get_bond_downdelay; + nm_setting_ovs_port_get_bond_mode; + nm_setting_ovs_port_get_bond_updelay; + nm_setting_ovs_port_get_lacp; + nm_setting_ovs_port_get_tag; + nm_setting_ovs_port_get_type; + nm_setting_ovs_port_get_vlan_mode; + nm_setting_ovs_port_new; nm_setting_pppoe_get_parent; nm_setting_wireless_security_get_pmf; nm_setting_wireless_security_get_wps_method; diff --git a/po/POTFILES.in b/po/POTFILES.in index e5b50a780e..b0e4525535 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -77,6 +77,7 @@ libnm-core/nm-setting-macvlan.c libnm-core/nm-setting-olpc-mesh.c libnm-core/nm-setting-ovs-interface.c libnm-core/nm-setting-ovs-patch.c +libnm-core/nm-setting-ovs-port.c libnm-core/nm-setting-ppp.c libnm-core/nm-setting-pppoe.c libnm-core/nm-setting-proxy.c From cb9b024ddb81144985095e14449d0c8ddf43519b Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 1 Aug 2017 18:36:34 +0200 Subject: [PATCH 18/36] libnm-core: add ovs-bridge setting --- Makefile.am | 2 + clients/common/settings-docs.c.in | 5 + libnm-core/nm-connection.c | 21 ++ libnm-core/nm-connection.h | 2 + libnm-core/nm-core-internal.h | 1 + libnm-core/nm-core-types.h | 1 + libnm-core/nm-setting-connection.c | 12 + libnm-core/nm-setting-ovs-bridge.c | 337 +++++++++++++++++++++++++++++ libnm-core/nm-setting-ovs-bridge.h | 63 ++++++ libnm-core/nm-setting-ovs-port.c | 15 ++ libnm-core/nm-setting.c | 2 + libnm/libnm.ver | 6 + po/POTFILES.in | 1 + 13 files changed, 468 insertions(+) create mode 100644 libnm-core/nm-setting-ovs-bridge.c create mode 100644 libnm-core/nm-setting-ovs-bridge.h diff --git a/Makefile.am b/Makefile.am index 31a4f03f5d..660dc3c64a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -393,6 +393,7 @@ libnm_core_lib_h_pub_real = \ libnm-core/nm-setting-macsec.h \ libnm-core/nm-setting-macvlan.h \ libnm-core/nm-setting-olpc-mesh.h \ + libnm-core/nm-setting-ovs-bridge.h \ libnm-core/nm-setting-ovs-interface.h \ libnm-core/nm-setting-ovs-patch.h \ libnm-core/nm-setting-ovs-port.h \ @@ -477,6 +478,7 @@ libnm_core_lib_c_real = \ libnm-core/nm-setting-macsec.c \ libnm-core/nm-setting-macvlan.c \ libnm-core/nm-setting-olpc-mesh.c \ + libnm-core/nm-setting-ovs-bridge.c \ libnm-core/nm-setting-ovs-interface.c \ libnm-core/nm-setting-ovs-patch.c \ libnm-core/nm-setting-ovs-port.c \ diff --git a/clients/common/settings-docs.c.in b/clients/common/settings-docs.c.in index 0eea53c4e6..1378f2dced 100644 --- a/clients/common/settings-docs.c.in +++ b/clients/common/settings-docs.c.in @@ -262,6 +262,11 @@ #define DESCRIBE_DOC_NM_SETTING_MACVLAN_PARENT N_("If given, specifies the parent interface name or parent connection UUID from which this MAC-VLAN interface should be created. If this property is not specified, the connection must contain an \"802-3-ethernet\" setting with a \"mac-address\" property.") #define DESCRIBE_DOC_NM_SETTING_MACVLAN_PROMISCUOUS N_("Whether the interface should be put in promiscuous mode.") #define DESCRIBE_DOC_NM_SETTING_MACVLAN_TAP N_("Whether the interface should be a MACVTAP.") +#define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_FAIL_MODE N_("The bridge failure mode. One of \"secure\", \"standalone\" or empty.") +#define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_MCAST_SNOOPING_ENABLE N_("Enable or disable multicast snooping.") +#define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_NAME N_("The setting's name, which uniquely identifies the setting within the connection. Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".") +#define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_RSTP_ENABLE N_("Enable or disable RSTP.") +#define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_STP_ENABLE N_("Enable or disable STP.") #define DESCRIBE_DOC_NM_SETTING_OVS_INTERFACE_NAME N_("The setting's name, which uniquely identifies the setting within the connection. Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".") #define DESCRIBE_DOC_NM_SETTING_OVS_INTERFACE_TYPE N_("The interface type. Either \"internal\", or empty.") #define DESCRIBE_DOC_NM_SETTING_OVS_PATCH_NAME N_("The setting's name, which uniquely identifies the setting within the connection. Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".") diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index b1640a45a4..d76009cd37 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -729,6 +729,10 @@ _nm_connection_detect_slave_type (NMConnection *connection, NMSetting **out_s_po i_slave_type = NM_SETTING_BRIDGE_SETTING_NAME; else if (!strcmp (name, NM_SETTING_TEAM_PORT_SETTING_NAME)) i_slave_type = NM_SETTING_TEAM_SETTING_NAME; + else if (!strcmp (name, NM_SETTING_OVS_PORT_SETTING_NAME)) + i_slave_type = NM_SETTING_OVS_BRIDGE_SETTING_NAME; + else if (!strcmp (name, NM_SETTING_OVS_INTERFACE_SETTING_NAME)) + i_slave_type = NM_SETTING_OVS_PORT_SETTING_NAME; else continue; @@ -2017,6 +2021,7 @@ nm_connection_is_virtual (NMConnection *connection) || !strcmp (type, NM_SETTING_IP_TUNNEL_SETTING_NAME) || !strcmp (type, NM_SETTING_MACSEC_SETTING_NAME) || !strcmp (type, NM_SETTING_MACVLAN_SETTING_NAME) + || !strcmp (type, NM_SETTING_OVS_BRIDGE_SETTING_NAME) || !strcmp (type, NM_SETTING_OVS_INTERFACE_SETTING_NAME) || !strcmp (type, NM_SETTING_OVS_PORT_SETTING_NAME) || !strcmp (type, NM_SETTING_VXLAN_SETTING_NAME)) @@ -2371,6 +2376,22 @@ nm_connection_get_setting_olpc_mesh (NMConnection *connection) return _connection_get_setting_check (connection, NM_TYPE_SETTING_OLPC_MESH); } +/** + * nm_connection_get_setting_ovs_bridge: + * @connection: the #NMConnection + * + * A shortcut to return any #NMSettingOvsBridge the connection might contain. + * + * Returns: (transfer none): an #NMSettingOvsBridge if the connection contains one, otherwise %NULL + * + * Since: 1.10 + **/ +NMSettingOvsBridge * +nm_connection_get_setting_ovs_bridge (NMConnection *connection) +{ + return _connection_get_setting_check (connection, NM_TYPE_SETTING_OVS_BRIDGE); +} + /** * nm_connection_get_setting_ovs_interface: * @connection: the #NMConnection diff --git a/libnm-core/nm-connection.h b/libnm-core/nm-connection.h index cac421bd20..9419c6254e 100644 --- a/libnm-core/nm-connection.h +++ b/libnm-core/nm-connection.h @@ -214,6 +214,8 @@ NM_AVAILABLE_IN_1_2 NMSettingMacvlan * nm_connection_get_setting_macvlan (NMConnection *connection); NMSettingOlpcMesh * nm_connection_get_setting_olpc_mesh (NMConnection *connection); NM_AVAILABLE_IN_1_10 +NMSettingOvsBridge * nm_connection_get_setting_ovs_bridge (NMConnection *connection); +NM_AVAILABLE_IN_1_10 NMSettingOvsInterface * nm_connection_get_setting_ovs_interface (NMConnection *connection); NMSettingOvsPatch * nm_connection_get_setting_ovs_patch (NMConnection *connection); NM_AVAILABLE_IN_1_10 diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 408a849064..59ebfcb132 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -56,6 +56,7 @@ #include "nm-setting-macsec.h" #include "nm-setting-macvlan.h" #include "nm-setting-olpc-mesh.h" +#include "nm-setting-ovs-bridge.h" #include "nm-setting-ovs-interface.h" #include "nm-setting-ovs-patch.h" #include "nm-setting-ovs-port.h" diff --git a/libnm-core/nm-core-types.h b/libnm-core/nm-core-types.h index a66a94ef56..ae680b7a5a 100644 --- a/libnm-core/nm-core-types.h +++ b/libnm-core/nm-core-types.h @@ -50,6 +50,7 @@ typedef struct _NMSettingIP6Config NMSettingIP6Config; typedef struct _NMSettingMacsec NMSettingMacsec; typedef struct _NMSettingMacvlan NMSettingMacvlan; typedef struct _NMSettingOlpcMesh NMSettingOlpcMesh; +typedef struct _NMSettingOvsBridge NMSettingOvsBridge; typedef struct _NMSettingOvsInterface NMSettingOvsInterface; typedef struct _NMSettingOvsPatch NMSettingOvsPatch; typedef struct _NMSettingOvsPort NMSettingOvsPort; diff --git a/libnm-core/nm-setting-connection.c b/libnm-core/nm-setting-connection.c index 728367c9b2..4b2c5d501b 100644 --- a/libnm-core/nm-setting-connection.c +++ b/libnm-core/nm-setting-connection.c @@ -1006,6 +1006,18 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) } } + if ( g_strcmp0 (priv->type, NM_SETTING_OVS_PORT_SETTING_NAME) != 0 + && g_strcmp0 (priv->slave_type, NM_SETTING_OVS_BRIDGE_SETTING_NAME) == 0) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("Only '%s' connections can be enslaved to '%s'"), + NM_SETTING_OVS_PORT_SETTING_NAME, + NM_SETTING_OVS_BRIDGE_SETTING_NAME); + g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_TYPE); + return FALSE; + } + if (priv->metered != NM_METERED_UNKNOWN && priv->metered != NM_METERED_YES && priv->metered != NM_METERED_NO) { diff --git a/libnm-core/nm-setting-ovs-bridge.c b/libnm-core/nm-setting-ovs-bridge.c new file mode 100644 index 0000000000..fbae95d0c9 --- /dev/null +++ b/libnm-core/nm-setting-ovs-bridge.c @@ -0,0 +1,337 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-setting-ovs-bridge.h" + +#include "nm-connection-private.h" +#include "nm-setting-connection.h" +#include "nm-setting-private.h" + +/** + * SECTION:nm-setting-ovs-bridge + * @short_description: Describes connection properties for OpenVSwitch bridges. + * + * The #NMSettingOvsBridge object is a #NMSetting subclass that describes properties + * necessary for OpenVSwitch bridges. + **/ + +enum { + PROP_0, + PROP_FAIL_MODE, + PROP_MCAST_SNOOPING_ENABLE, + PROP_RSTP_ENABLE, + PROP_STP_ENABLE, + LAST_PROP +}; + +/** + * NMSettingOvsBridge: + * + * OvsBridge Link Settings + */ +struct _NMSettingOvsBridge { + NMSetting parent; + + char *fail_mode; + gboolean mcast_snooping_enable; + gboolean rstp_enable; + gboolean stp_enable; +}; + +struct _NMSettingOvsBridgeClass { + NMSettingClass parent; +}; + +G_DEFINE_TYPE_WITH_CODE (NMSettingOvsBridge, nm_setting_ovs_bridge, NM_TYPE_SETTING, + _nm_register_setting (OVS_BRIDGE, NM_SETTING_PRIORITY_HW_BASE)) +NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_OVS_BRIDGE) + +/*****************************************************************************/ + +/** + * nm_setting_ovs_bridge_get_fail_mode: + * @self: the #NMSettingOvsBridge + * + * Returns: the #NMSettingOvsBridge:fail_mode property of the setting + * + * Since: 1.10 + **/ +const char * +nm_setting_ovs_bridge_get_fail_mode (NMSettingOvsBridge *self) +{ + g_return_val_if_fail (NM_IS_SETTING_OVS_BRIDGE (self), NULL); + + return self->fail_mode; +} + +/** + * nm_setting_ovs_bridge_get_mcast_snooping_enable: + * @self: the #NMSettingOvsBridge + * + * Returns: the #NMSettingOvsBridge:mcast_snooping_enable property of the setting + * + * Since: 1.10 + **/ +gboolean +nm_setting_ovs_bridge_get_mcast_snooping_enable (NMSettingOvsBridge *self) +{ + g_return_val_if_fail (NM_IS_SETTING_OVS_BRIDGE (self), FALSE); + + return self->mcast_snooping_enable; +} + +/** + * nm_setting_ovs_bridge_get_rstp_enable: + * @self: the #NMSettingOvsBridge + * + * Returns: the #NMSettingOvsBridge:rstp_enable property of the setting + * + * Since: 1.10 + **/ +gboolean +nm_setting_ovs_bridge_get_rstp_enable (NMSettingOvsBridge *self) +{ + g_return_val_if_fail (NM_IS_SETTING_OVS_BRIDGE (self), FALSE); + + return self->rstp_enable; +} + +/** + * nm_setting_ovs_bridge_get_stp_enable: + * @self: the #NMSettingOvsBridge + * + * Returns: the #NMSettingOvsBridge:stp_enable property of the setting + * + * Since: 1.10 + **/ +gboolean +nm_setting_ovs_bridge_get_stp_enable (NMSettingOvsBridge *self) +{ + g_return_val_if_fail (NM_IS_SETTING_OVS_BRIDGE (self), FALSE); + + return self->stp_enable; +} + +/*****************************************************************************/ + +static int +verify (NMSetting *setting, NMConnection *connection, GError **error) +{ + NMSettingOvsBridge *self = NM_SETTING_OVS_BRIDGE (setting); + + if (!_nm_connection_verify_required_interface_name (connection, error)) + return FALSE; + + if (connection) { + NMSettingConnection *s_con; + + s_con = nm_connection_get_setting_connection (connection); + if (!s_con) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_SETTING, + _("missing setting")); + g_prefix_error (error, "%s: ", NM_SETTING_CONNECTION_SETTING_NAME); + return FALSE; + } + + if (nm_setting_connection_get_master (s_con)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("A connection with a '%s' setting must not have a master."), + NM_SETTING_OVS_BRIDGE_SETTING_NAME); + g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_MASTER); + return FALSE; + } + } + + if (!NM_IN_STRSET (self->fail_mode, "secure", "standalone", NULL)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not allowed in fail_mode"), + self->fail_mode); + g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_BRIDGE_SETTING_NAME, NM_SETTING_OVS_BRIDGE_FAIL_MODE); + return FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMSettingOvsBridge *self = NM_SETTING_OVS_BRIDGE (object); + + switch (prop_id) { + case PROP_FAIL_MODE: + g_value_set_string (value, self->fail_mode); + break; + case PROP_MCAST_SNOOPING_ENABLE: + g_value_set_boolean (value, self->mcast_snooping_enable); + break; + case PROP_RSTP_ENABLE: + g_value_set_boolean (value, self->rstp_enable); + break; + case PROP_STP_ENABLE: + g_value_set_boolean (value, self->stp_enable); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMSettingOvsBridge *self = NM_SETTING_OVS_BRIDGE (object); + + switch (prop_id) { + case PROP_FAIL_MODE: + g_free (self->fail_mode); + self->fail_mode = g_value_dup_string (value); + break; + case PROP_MCAST_SNOOPING_ENABLE: + self->mcast_snooping_enable = g_value_get_boolean (value); + break; + case PROP_RSTP_ENABLE: + self->rstp_enable = g_value_get_boolean (value); + break; + case PROP_STP_ENABLE: + self->stp_enable = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_setting_ovs_bridge_init (NMSettingOvsBridge *self) +{ +} + +/** + * nm_setting_ovs_bridge_new: + * + * Creates a new #NMSettingOvsBridge object with default values. + * + * Returns: (transfer full): the new empty #NMSettingOvsBridge object + * + * Since: 1.10 + **/ +NMSetting * +nm_setting_ovs_bridge_new (void) +{ + return (NMSetting *) g_object_new (NM_TYPE_SETTING_OVS_BRIDGE, NULL); +} + +static void +finalize (GObject *object) +{ + NMSettingOvsBridge *self = NM_SETTING_OVS_BRIDGE (object); + + g_free (self->fail_mode); + + G_OBJECT_CLASS (nm_setting_ovs_bridge_parent_class)->finalize (object); +} + +static void +nm_setting_ovs_bridge_class_init (NMSettingOvsBridgeClass *setting_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (setting_class); + NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class); + + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->finalize = finalize; + parent_class->verify = verify; + + /** + * NMSettingOvsBridge:fail-mode: + * + * The bridge failure mode. One of "secure", "standalone" or empty. + * + * Since: 1.10 + **/ + g_object_class_install_property + (object_class, PROP_FAIL_MODE, + g_param_spec_string (NM_SETTING_OVS_BRIDGE_FAIL_MODE, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingOvsBridge:mcast-snooping-enable: + * + * Enable or disable multicast snooping. + * + * Since: 1.10 + **/ + g_object_class_install_property + (object_class, PROP_MCAST_SNOOPING_ENABLE, + g_param_spec_boolean (NM_SETTING_OVS_BRIDGE_MCAST_SNOOPING_ENABLE, "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingOvsBridge:rstp-enable: + * + * Enable or disable RSTP. + * + * Since: 1.10 + **/ + g_object_class_install_property + (object_class, PROP_RSTP_ENABLE, + g_param_spec_boolean (NM_SETTING_OVS_BRIDGE_RSTP_ENABLE, "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingOvsBridge:stp-enable: + * + * Enable or disable STP. + * + * Since: 1.10 + **/ + g_object_class_install_property + (object_class, PROP_STP_ENABLE, + g_param_spec_boolean (NM_SETTING_OVS_BRIDGE_STP_ENABLE, "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); +} diff --git a/libnm-core/nm-setting-ovs-bridge.h b/libnm-core/nm-setting-ovs-bridge.h new file mode 100644 index 0000000000..d4837e58a2 --- /dev/null +++ b/libnm-core/nm-setting-ovs-bridge.h @@ -0,0 +1,63 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#ifndef __NM_SETTING_OVS_BRIDGE_H__ +#define __NM_SETTING_OVS_BRIDGE_H__ + +#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION) +#error "Only can be included directly." +#endif + +#include "nm-setting.h" + +G_BEGIN_DECLS + +#define NM_TYPE_SETTING_OVS_BRIDGE (nm_setting_ovs_bridge_get_type ()) +#define NM_SETTING_OVS_BRIDGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_OVS_BRIDGE, NMSettingOvsBridge)) +#define NM_SETTING_OVS_BRIDGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_OVS_BRIDGECONFIG, NMSettingOvsBridgeClass)) +#define NM_IS_SETTING_OVS_BRIDGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_OVS_BRIDGE)) +#define NM_IS_SETTING_OVS_BRIDGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTING_OVS_BRIDGE)) +#define NM_SETTING_OVS_BRIDGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_OVS_BRIDGE, NMSettingOvsBridgeClass)) + +#define NM_SETTING_OVS_BRIDGE_SETTING_NAME "ovs-bridge" + +#define NM_SETTING_OVS_BRIDGE_FAIL_MODE "fail-mode" +#define NM_SETTING_OVS_BRIDGE_MCAST_SNOOPING_ENABLE "mcast-snooping-enable" +#define NM_SETTING_OVS_BRIDGE_RSTP_ENABLE "rstp-enable" +#define NM_SETTING_OVS_BRIDGE_STP_ENABLE "stp-enable" + +typedef struct _NMSettingOvsBridgeClass NMSettingOvsBridgeClass; + +NM_AVAILABLE_IN_1_10 +GType nm_setting_ovs_bridge_get_type (void); +NM_AVAILABLE_IN_1_10 +NMSetting *nm_setting_ovs_bridge_new (void); + +NM_AVAILABLE_IN_1_10 +const char *nm_setting_ovs_bridge_get_fail_mode (NMSettingOvsBridge *self); +NM_AVAILABLE_IN_1_10 +gboolean nm_setting_ovs_bridge_get_mcast_snooping_enable (NMSettingOvsBridge *self); +NM_AVAILABLE_IN_1_10 +gboolean nm_setting_ovs_bridge_get_rstp_enable (NMSettingOvsBridge *self); +NM_AVAILABLE_IN_1_10 +gboolean nm_setting_ovs_bridge_get_stp_enable (NMSettingOvsBridge *self); + +G_END_DECLS + +#endif /* __NM_SETTING_OVS_BRIDGE_H__ */ diff --git a/libnm-core/nm-setting-ovs-port.c b/libnm-core/nm-setting-ovs-port.c index 43b7621bf8..bd05f2e7b2 100644 --- a/libnm-core/nm-setting-ovs-port.c +++ b/libnm-core/nm-setting-ovs-port.c @@ -179,6 +179,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) if (connection) { NMSettingConnection *s_con; + const char *slave_type; s_con = nm_connection_get_setting_connection (connection); if (!s_con) { @@ -199,6 +200,20 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_MASTER); return FALSE; } + + slave_type = nm_setting_connection_get_slave_type (s_con); + if ( slave_type + && strcmp (slave_type, NM_SETTING_OVS_BRIDGE_SETTING_NAME)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("A connection with a '%s' setting must have the slave-type set to '%s'. Instead it is '%s'"), + NM_SETTING_OVS_PORT_SETTING_NAME, + NM_SETTING_OVS_BRIDGE_SETTING_NAME, + slave_type); + g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_SLAVE_TYPE); + return FALSE; + } } if (!NM_IN_STRSET (self->vlan_mode, "access", "native-tagged", "native-untagged", "trunk", NULL)) { diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c index 6515f27cf5..590beea5d1 100644 --- a/libnm-core/nm-setting.c +++ b/libnm-core/nm-setting.c @@ -258,6 +258,8 @@ _nm_setting_slave_type_is_valid (const char *slave_type, const char **out_port_t ; else if (!strcmp (slave_type, NM_SETTING_BRIDGE_SETTING_NAME)) port_type = NM_SETTING_BRIDGE_PORT_SETTING_NAME; + else if (!strcmp (slave_type, NM_SETTING_OVS_BRIDGE_SETTING_NAME)) + port_type = NM_SETTING_OVS_PORT_SETTING_NAME; else if (!strcmp (slave_type, NM_SETTING_OVS_PORT_SETTING_NAME)) port_type = NM_SETTING_OVS_INTERFACE_SETTING_NAME; else if (!strcmp (slave_type, NM_SETTING_TEAM_SETTING_NAME)) diff --git a/libnm/libnm.ver b/libnm/libnm.ver index c1e1817bb0..d1d0bd442b 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1190,6 +1190,12 @@ global: nm_ip_route_equal_full; nm_setting_bridge_get_group_forward_mask; nm_setting_ip_config_get_route_table; + nm_setting_ovs_bridge_get_fail_mode; + nm_setting_ovs_bridge_get_mcast_snooping_enable; + nm_setting_ovs_bridge_get_rstp_enable; + nm_setting_ovs_bridge_get_stp_enable; + nm_setting_ovs_bridge_get_type; + nm_setting_ovs_bridge_new; nm_setting_ovs_interface_get_interface_type; nm_setting_ovs_interface_get_type; nm_setting_ovs_interface_new; diff --git a/po/POTFILES.in b/po/POTFILES.in index b0e4525535..403165fbcc 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -78,6 +78,7 @@ libnm-core/nm-setting-olpc-mesh.c libnm-core/nm-setting-ovs-interface.c libnm-core/nm-setting-ovs-patch.c libnm-core/nm-setting-ovs-port.c +libnm-core/nm-setting-ovs-bridge.c libnm-core/nm-setting-ppp.c libnm-core/nm-setting-pppoe.c libnm-core/nm-setting-proxy.c From b0f3dc0add9dc74ef1192f2996b420b159add9af Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 2 Oct 2017 08:39:09 +0200 Subject: [PATCH 19/36] introspection: add o.fd.NM.Device.OvsInterface interface --- Makefile.am | 4 + ...top.NetworkManager.Device.OvsInterface.xml | 20 +++ libnm-core/nm-dbus-interface.h | 123 +++++++++--------- libnm/nm-device.c | 3 + src/devices/nm-device.c | 2 + 5 files changed, 92 insertions(+), 60 deletions(-) create mode 100644 introspection/org.freedesktop.NetworkManager.Device.OvsInterface.xml diff --git a/Makefile.am b/Makefile.am index 660dc3c64a..4ed5a4f990 100644 --- a/Makefile.am +++ b/Makefile.am @@ -206,6 +206,8 @@ introspection_sources = \ introspection/org.freedesktop.NetworkManager.Device.Modem.h \ introspection/org.freedesktop.NetworkManager.Device.OlpcMesh.c \ introspection/org.freedesktop.NetworkManager.Device.OlpcMesh.h \ + introspection/org.freedesktop.NetworkManager.Device.OvsInterface.c \ + introspection/org.freedesktop.NetworkManager.Device.OvsInterface.h \ introspection/org.freedesktop.NetworkManager.Device.Ppp.c \ introspection/org.freedesktop.NetworkManager.Device.Ppp.h \ introspection/org.freedesktop.NetworkManager.Device.Statistics.c \ @@ -281,6 +283,7 @@ DBUS_INTERFACE_DOCS = \ docs/api/dbus-org.freedesktop.NetworkManager.Device.Tun.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.Bridge.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.OlpcMesh.xml \ + docs/api/dbus-org.freedesktop.NetworkManager.Device.OvsInterface.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.Ppp.xml \ docs/api/dbus-org.freedesktop.NetworkManager.DHCP4Config.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.Generic.xml \ @@ -329,6 +332,7 @@ dbusinterfaces_DATA = \ introspection/org.freedesktop.NetworkManager.Device.Macvlan.xml \ introspection/org.freedesktop.NetworkManager.Device.Modem.xml \ introspection/org.freedesktop.NetworkManager.Device.OlpcMesh.xml \ + introspection/org.freedesktop.NetworkManager.Device.OvsInterface.xml \ introspection/org.freedesktop.NetworkManager.Device.Ppp.xml \ introspection/org.freedesktop.NetworkManager.Device.Statistics.xml \ introspection/org.freedesktop.NetworkManager.Device.Team.xml \ diff --git a/introspection/org.freedesktop.NetworkManager.Device.OvsInterface.xml b/introspection/org.freedesktop.NetworkManager.Device.OvsInterface.xml new file mode 100644 index 0000000000..9605a958b4 --- /dev/null +++ b/introspection/org.freedesktop.NetworkManager.Device.OvsInterface.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h index 8b92dbe7e6..7fb75d4f79 100644 --- a/libnm-core/nm-dbus-interface.h +++ b/libnm-core/nm-dbus-interface.h @@ -36,43 +36,44 @@ /* * dbus services details */ -#define NM_DBUS_SERVICE "org.freedesktop.NetworkManager" +#define NM_DBUS_SERVICE "org.freedesktop.NetworkManager" -#define NM_DBUS_PATH "/org/freedesktop/NetworkManager" -#define NM_DBUS_INTERFACE "org.freedesktop.NetworkManager" -#define NM_DBUS_INTERFACE_DEVICE NM_DBUS_INTERFACE ".Device" -#define NM_DBUS_INTERFACE_DEVICE_WIRED NM_DBUS_INTERFACE_DEVICE ".Wired" -#define NM_DBUS_INTERFACE_DEVICE_ADSL NM_DBUS_INTERFACE_DEVICE ".Adsl" -#define NM_DBUS_INTERFACE_DEVICE_WIRELESS NM_DBUS_INTERFACE_DEVICE ".Wireless" -#define NM_DBUS_INTERFACE_DEVICE_BLUETOOTH NM_DBUS_INTERFACE_DEVICE ".Bluetooth" -#define NM_DBUS_INTERFACE_DEVICE_OLPC_MESH NM_DBUS_INTERFACE_DEVICE ".OlpcMesh" -#define NM_DBUS_PATH_ACCESS_POINT NM_DBUS_PATH "/AccessPoint" -#define NM_DBUS_INTERFACE_ACCESS_POINT NM_DBUS_INTERFACE ".AccessPoint" -#define NM_DBUS_INTERFACE_DEVICE_MODEM NM_DBUS_INTERFACE_DEVICE ".Modem" -#define NM_DBUS_INTERFACE_DEVICE_WIMAX NM_DBUS_INTERFACE_DEVICE ".WiMax" -#define NM_DBUS_INTERFACE_WIMAX_NSP NM_DBUS_INTERFACE ".WiMax.Nsp" -#define NM_DBUS_PATH_WIMAX_NSP NM_DBUS_PATH "/Nsp" -#define NM_DBUS_INTERFACE_ACTIVE_CONNECTION NM_DBUS_INTERFACE ".Connection.Active" -#define NM_DBUS_INTERFACE_IP4_CONFIG NM_DBUS_INTERFACE ".IP4Config" -#define NM_DBUS_INTERFACE_DHCP4_CONFIG NM_DBUS_INTERFACE ".DHCP4Config" -#define NM_DBUS_INTERFACE_IP6_CONFIG NM_DBUS_INTERFACE ".IP6Config" -#define NM_DBUS_INTERFACE_DHCP6_CONFIG NM_DBUS_INTERFACE ".DHCP6Config" -#define NM_DBUS_INTERFACE_DEVICE_INFINIBAND NM_DBUS_INTERFACE_DEVICE ".Infiniband" -#define NM_DBUS_INTERFACE_DEVICE_BOND NM_DBUS_INTERFACE_DEVICE ".Bond" -#define NM_DBUS_INTERFACE_DEVICE_DUMMY NM_DBUS_INTERFACE_DEVICE ".Dummy" -#define NM_DBUS_INTERFACE_DEVICE_TEAM NM_DBUS_INTERFACE_DEVICE ".Team" -#define NM_DBUS_INTERFACE_DEVICE_VLAN NM_DBUS_INTERFACE_DEVICE ".Vlan" -#define NM_DBUS_INTERFACE_DEVICE_BRIDGE NM_DBUS_INTERFACE_DEVICE ".Bridge" -#define NM_DBUS_INTERFACE_DEVICE_GENERIC NM_DBUS_INTERFACE_DEVICE ".Generic" -#define NM_DBUS_INTERFACE_DEVICE_VETH NM_DBUS_INTERFACE_DEVICE ".Veth" -#define NM_DBUS_INTERFACE_DEVICE_TUN NM_DBUS_INTERFACE_DEVICE ".Tun" -#define NM_DBUS_INTERFACE_DEVICE_MACSEC NM_DBUS_INTERFACE_DEVICE ".Macsec" -#define NM_DBUS_INTERFACE_DEVICE_MACVLAN NM_DBUS_INTERFACE_DEVICE ".Macvlan" -#define NM_DBUS_INTERFACE_DEVICE_PPP NM_DBUS_INTERFACE_DEVICE ".Ppp" -#define NM_DBUS_INTERFACE_DEVICE_VXLAN NM_DBUS_INTERFACE_DEVICE ".Vxlan" -#define NM_DBUS_INTERFACE_DEVICE_GRE NM_DBUS_INTERFACE_DEVICE ".Gre" -#define NM_DBUS_INTERFACE_DEVICE_IP_TUNNEL NM_DBUS_INTERFACE_DEVICE ".IPTunnel" -#define NM_DBUS_INTERFACE_DEVICE_STATISTICS NM_DBUS_INTERFACE_DEVICE ".Statistics" +#define NM_DBUS_PATH "/org/freedesktop/NetworkManager" +#define NM_DBUS_INTERFACE "org.freedesktop.NetworkManager" +#define NM_DBUS_INTERFACE_DEVICE NM_DBUS_INTERFACE ".Device" +#define NM_DBUS_INTERFACE_DEVICE_WIRED NM_DBUS_INTERFACE_DEVICE ".Wired" +#define NM_DBUS_INTERFACE_DEVICE_ADSL NM_DBUS_INTERFACE_DEVICE ".Adsl" +#define NM_DBUS_INTERFACE_DEVICE_WIRELESS NM_DBUS_INTERFACE_DEVICE ".Wireless" +#define NM_DBUS_INTERFACE_DEVICE_BLUETOOTH NM_DBUS_INTERFACE_DEVICE ".Bluetooth" +#define NM_DBUS_INTERFACE_DEVICE_OLPC_MESH NM_DBUS_INTERFACE_DEVICE ".OlpcMesh" +#define NM_DBUS_INTERFACE_DEVICE_OVS_INTERFACE NM_DBUS_INTERFACE_DEVICE ".OvsInterface" +#define NM_DBUS_PATH_ACCESS_POINT NM_DBUS_PATH "/AccessPoint" +#define NM_DBUS_INTERFACE_ACCESS_POINT NM_DBUS_INTERFACE ".AccessPoint" +#define NM_DBUS_INTERFACE_DEVICE_MODEM NM_DBUS_INTERFACE_DEVICE ".Modem" +#define NM_DBUS_INTERFACE_DEVICE_WIMAX NM_DBUS_INTERFACE_DEVICE ".WiMax" +#define NM_DBUS_INTERFACE_WIMAX_NSP NM_DBUS_INTERFACE ".WiMax.Nsp" +#define NM_DBUS_PATH_WIMAX_NSP NM_DBUS_PATH "/Nsp" +#define NM_DBUS_INTERFACE_ACTIVE_CONNECTION NM_DBUS_INTERFACE ".Connection.Active" +#define NM_DBUS_INTERFACE_IP4_CONFIG NM_DBUS_INTERFACE ".IP4Config" +#define NM_DBUS_INTERFACE_DHCP4_CONFIG NM_DBUS_INTERFACE ".DHCP4Config" +#define NM_DBUS_INTERFACE_IP6_CONFIG NM_DBUS_INTERFACE ".IP6Config" +#define NM_DBUS_INTERFACE_DHCP6_CONFIG NM_DBUS_INTERFACE ".DHCP6Config" +#define NM_DBUS_INTERFACE_DEVICE_INFINIBAND NM_DBUS_INTERFACE_DEVICE ".Infiniband" +#define NM_DBUS_INTERFACE_DEVICE_BOND NM_DBUS_INTERFACE_DEVICE ".Bond" +#define NM_DBUS_INTERFACE_DEVICE_DUMMY NM_DBUS_INTERFACE_DEVICE ".Dummy" +#define NM_DBUS_INTERFACE_DEVICE_TEAM NM_DBUS_INTERFACE_DEVICE ".Team" +#define NM_DBUS_INTERFACE_DEVICE_VLAN NM_DBUS_INTERFACE_DEVICE ".Vlan" +#define NM_DBUS_INTERFACE_DEVICE_BRIDGE NM_DBUS_INTERFACE_DEVICE ".Bridge" +#define NM_DBUS_INTERFACE_DEVICE_GENERIC NM_DBUS_INTERFACE_DEVICE ".Generic" +#define NM_DBUS_INTERFACE_DEVICE_VETH NM_DBUS_INTERFACE_DEVICE ".Veth" +#define NM_DBUS_INTERFACE_DEVICE_TUN NM_DBUS_INTERFACE_DEVICE ".Tun" +#define NM_DBUS_INTERFACE_DEVICE_MACSEC NM_DBUS_INTERFACE_DEVICE ".Macsec" +#define NM_DBUS_INTERFACE_DEVICE_MACVLAN NM_DBUS_INTERFACE_DEVICE ".Macvlan" +#define NM_DBUS_INTERFACE_DEVICE_PPP NM_DBUS_INTERFACE_DEVICE ".Ppp" +#define NM_DBUS_INTERFACE_DEVICE_VXLAN NM_DBUS_INTERFACE_DEVICE ".Vxlan" +#define NM_DBUS_INTERFACE_DEVICE_GRE NM_DBUS_INTERFACE_DEVICE ".Gre" +#define NM_DBUS_INTERFACE_DEVICE_IP_TUNNEL NM_DBUS_INTERFACE_DEVICE ".IPTunnel" +#define NM_DBUS_INTERFACE_DEVICE_STATISTICS NM_DBUS_INTERFACE_DEVICE ".Statistics" #define NM_DBUS_INTERFACE_SETTINGS "org.freedesktop.NetworkManager.Settings" #define NM_DBUS_PATH_SETTINGS "/org/freedesktop/NetworkManager/Settings" @@ -205,35 +206,37 @@ typedef enum { * @NM_DEVICE_TYPE_MACSEC: a MACsec interface * @NM_DEVICE_TYPE_DUMMY: a dummy interface * @NM_DEVICE_TYPE_PPP: a PPP interface + * @NM_DEVICE_TYPE_OVS_INTERFACE: a OpenVSwitch interface * * #NMDeviceType values indicate the type of hardware represented by a * device object. **/ typedef enum { - NM_DEVICE_TYPE_UNKNOWN = 0, - NM_DEVICE_TYPE_ETHERNET = 1, - NM_DEVICE_TYPE_WIFI = 2, - NM_DEVICE_TYPE_UNUSED1 = 3, - NM_DEVICE_TYPE_UNUSED2 = 4, - NM_DEVICE_TYPE_BT = 5, /* Bluetooth */ - NM_DEVICE_TYPE_OLPC_MESH = 6, - NM_DEVICE_TYPE_WIMAX = 7, - NM_DEVICE_TYPE_MODEM = 8, - NM_DEVICE_TYPE_INFINIBAND = 9, - NM_DEVICE_TYPE_BOND = 10, - NM_DEVICE_TYPE_VLAN = 11, - NM_DEVICE_TYPE_ADSL = 12, - NM_DEVICE_TYPE_BRIDGE = 13, - NM_DEVICE_TYPE_GENERIC = 14, - NM_DEVICE_TYPE_TEAM = 15, - NM_DEVICE_TYPE_TUN = 16, - NM_DEVICE_TYPE_IP_TUNNEL = 17, - NM_DEVICE_TYPE_MACVLAN = 18, - NM_DEVICE_TYPE_VXLAN = 19, - NM_DEVICE_TYPE_VETH = 20, - NM_DEVICE_TYPE_MACSEC = 21, - NM_DEVICE_TYPE_DUMMY = 22, - NM_DEVICE_TYPE_PPP = 23, + NM_DEVICE_TYPE_UNKNOWN = 0, + NM_DEVICE_TYPE_ETHERNET = 1, + NM_DEVICE_TYPE_WIFI = 2, + NM_DEVICE_TYPE_UNUSED1 = 3, + NM_DEVICE_TYPE_UNUSED2 = 4, + NM_DEVICE_TYPE_BT = 5, /* Bluetooth */ + NM_DEVICE_TYPE_OLPC_MESH = 6, + NM_DEVICE_TYPE_WIMAX = 7, + NM_DEVICE_TYPE_MODEM = 8, + NM_DEVICE_TYPE_INFINIBAND = 9, + NM_DEVICE_TYPE_BOND = 10, + NM_DEVICE_TYPE_VLAN = 11, + NM_DEVICE_TYPE_ADSL = 12, + NM_DEVICE_TYPE_BRIDGE = 13, + NM_DEVICE_TYPE_GENERIC = 14, + NM_DEVICE_TYPE_TEAM = 15, + NM_DEVICE_TYPE_TUN = 16, + NM_DEVICE_TYPE_IP_TUNNEL = 17, + NM_DEVICE_TYPE_MACVLAN = 18, + NM_DEVICE_TYPE_VXLAN = 19, + NM_DEVICE_TYPE_VETH = 20, + NM_DEVICE_TYPE_MACSEC = 21, + NM_DEVICE_TYPE_DUMMY = 22, + NM_DEVICE_TYPE_PPP = 23, + NM_DEVICE_TYPE_OVS_INTERFACE = 24, } NMDeviceType; /** diff --git a/libnm/nm-device.c b/libnm/nm-device.c index 7f15436638..96efbc348e 100644 --- a/libnm/nm-device.c +++ b/libnm/nm-device.c @@ -261,6 +261,7 @@ coerce_type (NMDeviceType type) case NM_DEVICE_TYPE_WIFI: case NM_DEVICE_TYPE_BT: case NM_DEVICE_TYPE_OLPC_MESH: + case NM_DEVICE_TYPE_OVS_INTERFACE: case NM_DEVICE_TYPE_WIMAX: case NM_DEVICE_TYPE_MODEM: case NM_DEVICE_TYPE_INFINIBAND: @@ -1522,6 +1523,8 @@ get_type_name (NMDevice *device) return _("Bluetooth"); case NM_DEVICE_TYPE_OLPC_MESH: return _("OLPC Mesh"); + case NM_DEVICE_TYPE_OVS_INTERFACE: + return _("OpenVSwitch Interface"); case NM_DEVICE_TYPE_WIMAX: return _("WiMAX"); case NM_DEVICE_TYPE_MODEM: diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 91e7881e5a..8106b4e95c 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1661,6 +1661,8 @@ _get_route_metric_default (NMDevice *self) return 700; case NM_DEVICE_TYPE_BT: return 750; + case NM_DEVICE_TYPE_OVS_INTERFACE: + return 800; case NM_DEVICE_TYPE_GENERIC: return 950; case NM_DEVICE_TYPE_UNKNOWN: From 6748c44cb66d6d9e631a91c9c86958acfcd6806f Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 2 Oct 2017 08:39:09 +0200 Subject: [PATCH 20/36] introspection: add o.fd.NM.Device.OvsPort interface --- Makefile.am | 4 ++++ ...edesktop.NetworkManager.Device.OvsPort.xml | 20 +++++++++++++++++++ libnm-core/nm-dbus-interface.h | 3 +++ libnm/nm-device.c | 3 +++ src/devices/nm-device.c | 1 + 5 files changed, 31 insertions(+) create mode 100644 introspection/org.freedesktop.NetworkManager.Device.OvsPort.xml diff --git a/Makefile.am b/Makefile.am index 4ed5a4f990..351862565a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -208,6 +208,8 @@ introspection_sources = \ introspection/org.freedesktop.NetworkManager.Device.OlpcMesh.h \ introspection/org.freedesktop.NetworkManager.Device.OvsInterface.c \ introspection/org.freedesktop.NetworkManager.Device.OvsInterface.h \ + introspection/org.freedesktop.NetworkManager.Device.OvsPort.c \ + introspection/org.freedesktop.NetworkManager.Device.OvsPort.h \ introspection/org.freedesktop.NetworkManager.Device.Ppp.c \ introspection/org.freedesktop.NetworkManager.Device.Ppp.h \ introspection/org.freedesktop.NetworkManager.Device.Statistics.c \ @@ -284,6 +286,7 @@ DBUS_INTERFACE_DOCS = \ docs/api/dbus-org.freedesktop.NetworkManager.Device.Bridge.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.OlpcMesh.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.OvsInterface.xml \ + docs/api/dbus-org.freedesktop.NetworkManager.Device.OvsPort.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.Ppp.xml \ docs/api/dbus-org.freedesktop.NetworkManager.DHCP4Config.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.Generic.xml \ @@ -333,6 +336,7 @@ dbusinterfaces_DATA = \ introspection/org.freedesktop.NetworkManager.Device.Modem.xml \ introspection/org.freedesktop.NetworkManager.Device.OlpcMesh.xml \ introspection/org.freedesktop.NetworkManager.Device.OvsInterface.xml \ + introspection/org.freedesktop.NetworkManager.Device.OvsPort.xml \ introspection/org.freedesktop.NetworkManager.Device.Ppp.xml \ introspection/org.freedesktop.NetworkManager.Device.Statistics.xml \ introspection/org.freedesktop.NetworkManager.Device.Team.xml \ diff --git a/introspection/org.freedesktop.NetworkManager.Device.OvsPort.xml b/introspection/org.freedesktop.NetworkManager.Device.OvsPort.xml new file mode 100644 index 0000000000..d4900f510c --- /dev/null +++ b/introspection/org.freedesktop.NetworkManager.Device.OvsPort.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h index 7fb75d4f79..1a5daf9797 100644 --- a/libnm-core/nm-dbus-interface.h +++ b/libnm-core/nm-dbus-interface.h @@ -47,6 +47,7 @@ #define NM_DBUS_INTERFACE_DEVICE_BLUETOOTH NM_DBUS_INTERFACE_DEVICE ".Bluetooth" #define NM_DBUS_INTERFACE_DEVICE_OLPC_MESH NM_DBUS_INTERFACE_DEVICE ".OlpcMesh" #define NM_DBUS_INTERFACE_DEVICE_OVS_INTERFACE NM_DBUS_INTERFACE_DEVICE ".OvsInterface" +#define NM_DBUS_INTERFACE_DEVICE_OVS_PORT NM_DBUS_INTERFACE_DEVICE ".OvsPort" #define NM_DBUS_PATH_ACCESS_POINT NM_DBUS_PATH "/AccessPoint" #define NM_DBUS_INTERFACE_ACCESS_POINT NM_DBUS_INTERFACE ".AccessPoint" #define NM_DBUS_INTERFACE_DEVICE_MODEM NM_DBUS_INTERFACE_DEVICE ".Modem" @@ -207,6 +208,7 @@ typedef enum { * @NM_DEVICE_TYPE_DUMMY: a dummy interface * @NM_DEVICE_TYPE_PPP: a PPP interface * @NM_DEVICE_TYPE_OVS_INTERFACE: a OpenVSwitch interface + * @NM_DEVICE_TYPE_OVS_PORT: a OpenVSwitch port * * #NMDeviceType values indicate the type of hardware represented by a * device object. @@ -237,6 +239,7 @@ typedef enum { NM_DEVICE_TYPE_DUMMY = 22, NM_DEVICE_TYPE_PPP = 23, NM_DEVICE_TYPE_OVS_INTERFACE = 24, + NM_DEVICE_TYPE_OVS_PORT = 25, } NMDeviceType; /** diff --git a/libnm/nm-device.c b/libnm/nm-device.c index 96efbc348e..6f972c6fac 100644 --- a/libnm/nm-device.c +++ b/libnm/nm-device.c @@ -262,6 +262,7 @@ coerce_type (NMDeviceType type) case NM_DEVICE_TYPE_BT: case NM_DEVICE_TYPE_OLPC_MESH: case NM_DEVICE_TYPE_OVS_INTERFACE: + case NM_DEVICE_TYPE_OVS_PORT: case NM_DEVICE_TYPE_WIMAX: case NM_DEVICE_TYPE_MODEM: case NM_DEVICE_TYPE_INFINIBAND: @@ -1525,6 +1526,8 @@ get_type_name (NMDevice *device) return _("OLPC Mesh"); case NM_DEVICE_TYPE_OVS_INTERFACE: return _("OpenVSwitch Interface"); + case NM_DEVICE_TYPE_OVS_PORT: + return _("OpenVSwitch Port"); case NM_DEVICE_TYPE_WIMAX: return _("WiMAX"); case NM_DEVICE_TYPE_MODEM: diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 8106b4e95c..4f7e46d347 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1662,6 +1662,7 @@ _get_route_metric_default (NMDevice *self) case NM_DEVICE_TYPE_BT: return 750; case NM_DEVICE_TYPE_OVS_INTERFACE: + case NM_DEVICE_TYPE_OVS_PORT: return 800; case NM_DEVICE_TYPE_GENERIC: return 950; From b5925d693cc716c973d751dc5675a9d7b775436e Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 2 Oct 2017 08:39:09 +0200 Subject: [PATCH 21/36] introspection: add o.fd.NM.Device.OvsBridge interface --- Makefile.am | 4 ++++ ...esktop.NetworkManager.Device.OvsBridge.xml | 20 +++++++++++++++++++ libnm-core/nm-dbus-interface.h | 3 +++ libnm/nm-device.c | 3 +++ src/devices/nm-device.c | 1 + 5 files changed, 31 insertions(+) create mode 100644 introspection/org.freedesktop.NetworkManager.Device.OvsBridge.xml diff --git a/Makefile.am b/Makefile.am index 351862565a..06630af78e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -210,6 +210,8 @@ introspection_sources = \ introspection/org.freedesktop.NetworkManager.Device.OvsInterface.h \ introspection/org.freedesktop.NetworkManager.Device.OvsPort.c \ introspection/org.freedesktop.NetworkManager.Device.OvsPort.h \ + introspection/org.freedesktop.NetworkManager.Device.OvsBridge.c \ + introspection/org.freedesktop.NetworkManager.Device.OvsBridge.h \ introspection/org.freedesktop.NetworkManager.Device.Ppp.c \ introspection/org.freedesktop.NetworkManager.Device.Ppp.h \ introspection/org.freedesktop.NetworkManager.Device.Statistics.c \ @@ -287,6 +289,7 @@ DBUS_INTERFACE_DOCS = \ docs/api/dbus-org.freedesktop.NetworkManager.Device.OlpcMesh.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.OvsInterface.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.OvsPort.xml \ + docs/api/dbus-org.freedesktop.NetworkManager.Device.OvsBridge.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.Ppp.xml \ docs/api/dbus-org.freedesktop.NetworkManager.DHCP4Config.xml \ docs/api/dbus-org.freedesktop.NetworkManager.Device.Generic.xml \ @@ -337,6 +340,7 @@ dbusinterfaces_DATA = \ introspection/org.freedesktop.NetworkManager.Device.OlpcMesh.xml \ introspection/org.freedesktop.NetworkManager.Device.OvsInterface.xml \ introspection/org.freedesktop.NetworkManager.Device.OvsPort.xml \ + introspection/org.freedesktop.NetworkManager.Device.OvsBridge.xml \ introspection/org.freedesktop.NetworkManager.Device.Ppp.xml \ introspection/org.freedesktop.NetworkManager.Device.Statistics.xml \ introspection/org.freedesktop.NetworkManager.Device.Team.xml \ diff --git a/introspection/org.freedesktop.NetworkManager.Device.OvsBridge.xml b/introspection/org.freedesktop.NetworkManager.Device.OvsBridge.xml new file mode 100644 index 0000000000..08ed5dc01b --- /dev/null +++ b/introspection/org.freedesktop.NetworkManager.Device.OvsBridge.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h index 1a5daf9797..7618542697 100644 --- a/libnm-core/nm-dbus-interface.h +++ b/libnm-core/nm-dbus-interface.h @@ -48,6 +48,7 @@ #define NM_DBUS_INTERFACE_DEVICE_OLPC_MESH NM_DBUS_INTERFACE_DEVICE ".OlpcMesh" #define NM_DBUS_INTERFACE_DEVICE_OVS_INTERFACE NM_DBUS_INTERFACE_DEVICE ".OvsInterface" #define NM_DBUS_INTERFACE_DEVICE_OVS_PORT NM_DBUS_INTERFACE_DEVICE ".OvsPort" +#define NM_DBUS_INTERFACE_DEVICE_OVS_BRIDGE NM_DBUS_INTERFACE_DEVICE ".OvsBridge" #define NM_DBUS_PATH_ACCESS_POINT NM_DBUS_PATH "/AccessPoint" #define NM_DBUS_INTERFACE_ACCESS_POINT NM_DBUS_INTERFACE ".AccessPoint" #define NM_DBUS_INTERFACE_DEVICE_MODEM NM_DBUS_INTERFACE_DEVICE ".Modem" @@ -209,6 +210,7 @@ typedef enum { * @NM_DEVICE_TYPE_PPP: a PPP interface * @NM_DEVICE_TYPE_OVS_INTERFACE: a OpenVSwitch interface * @NM_DEVICE_TYPE_OVS_PORT: a OpenVSwitch port + * @NM_DEVICE_TYPE_OVS_BRIDGE: a OpenVSwitch bridge * * #NMDeviceType values indicate the type of hardware represented by a * device object. @@ -240,6 +242,7 @@ typedef enum { NM_DEVICE_TYPE_PPP = 23, NM_DEVICE_TYPE_OVS_INTERFACE = 24, NM_DEVICE_TYPE_OVS_PORT = 25, + NM_DEVICE_TYPE_OVS_BRIDGE = 26, } NMDeviceType; /** diff --git a/libnm/nm-device.c b/libnm/nm-device.c index 6f972c6fac..65afd078dc 100644 --- a/libnm/nm-device.c +++ b/libnm/nm-device.c @@ -263,6 +263,7 @@ coerce_type (NMDeviceType type) case NM_DEVICE_TYPE_OLPC_MESH: case NM_DEVICE_TYPE_OVS_INTERFACE: case NM_DEVICE_TYPE_OVS_PORT: + case NM_DEVICE_TYPE_OVS_BRIDGE: case NM_DEVICE_TYPE_WIMAX: case NM_DEVICE_TYPE_MODEM: case NM_DEVICE_TYPE_INFINIBAND: @@ -1528,6 +1529,8 @@ get_type_name (NMDevice *device) return _("OpenVSwitch Interface"); case NM_DEVICE_TYPE_OVS_PORT: return _("OpenVSwitch Port"); + case NM_DEVICE_TYPE_OVS_BRIDGE: + return _("OpenVSwitch Bridge"); case NM_DEVICE_TYPE_WIMAX: return _("WiMAX"); case NM_DEVICE_TYPE_MODEM: diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 4f7e46d347..4453acae23 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1661,6 +1661,7 @@ _get_route_metric_default (NMDevice *self) return 700; case NM_DEVICE_TYPE_BT: return 750; + case NM_DEVICE_TYPE_OVS_BRIDGE: case NM_DEVICE_TYPE_OVS_INTERFACE: case NM_DEVICE_TYPE_OVS_PORT: return 800; From e5c19377ec9255372a5bd4a74a4fcf0cc03695c6 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 10 Oct 2017 11:04:32 +0200 Subject: [PATCH 22/36] libnm: add support for ovs-interface devices --- Makefile.am | 2 + libnm/NetworkManager.h | 1 + libnm/libnm.ver | 1 + libnm/nm-client.c | 3 ++ libnm/nm-device-ovs-interface.c | 96 +++++++++++++++++++++++++++++++++ libnm/nm-device-ovs-interface.h | 45 ++++++++++++++++ libnm/nm-types.h | 61 ++++++++++----------- po/POTFILES.in | 1 + 8 files changed, 180 insertions(+), 30 deletions(-) create mode 100644 libnm/nm-device-ovs-interface.c create mode 100644 libnm/nm-device-ovs-interface.h diff --git a/Makefile.am b/Makefile.am index 06630af78e..772731b74d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -751,6 +751,7 @@ libnm_lib_h_pub_real = \ libnm/nm-device-macvlan.h \ libnm/nm-device-modem.h \ libnm/nm-device-olpc-mesh.h \ + libnm/nm-device-ovs-interface.h \ libnm/nm-device-ppp.h \ libnm/nm-device-team.h \ libnm/nm-device-tun.h \ @@ -804,6 +805,7 @@ libnm_lib_c_real = \ libnm/nm-device-macvlan.c \ libnm/nm-device-modem.c \ libnm/nm-device-olpc-mesh.c \ + libnm/nm-device-ovs-interface.c \ libnm/nm-device-ppp.c \ libnm/nm-device-team.c \ libnm/nm-device-tun.c \ diff --git a/libnm/NetworkManager.h b/libnm/NetworkManager.h index 97327f92d6..407fd62c60 100644 --- a/libnm/NetworkManager.h +++ b/libnm/NetworkManager.h @@ -41,6 +41,7 @@ #include "nm-device-macvlan.h" #include "nm-device-modem.h" #include "nm-device-olpc-mesh.h" +#include "nm-device-ovs-interface.h" #include "nm-device-team.h" #include "nm-device-tun.h" #include "nm-device-vlan.h" diff --git a/libnm/libnm.ver b/libnm/libnm.ver index d1d0bd442b..0b3378cfbd 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1186,6 +1186,7 @@ global: nm_client_connectivity_check_get_enabled; nm_client_connectivity_check_set_enabled; nm_device_dummy_get_hw_address; + nm_device_ovs_interface_get_type; nm_device_ppp_get_type; nm_ip_route_equal_full; nm_setting_bridge_get_group_forward_mask; diff --git a/libnm/nm-client.c b/libnm/nm-client.c index 8912a5f419..e608499040 100644 --- a/libnm/nm-client.c +++ b/libnm/nm-client.c @@ -63,6 +63,7 @@ #include "nm-device-macvlan.h" #include "nm-device-modem.h" #include "nm-device-olpc-mesh.h" +#include "nm-device-ovs-interface.h" #include "nm-device-ppp.h" #include "nm-device-team.h" #include "nm-device-tun.h" @@ -2147,6 +2148,8 @@ obj_nm_for_gdbus_object (NMClient *self, GDBusObject *object, GDBusObjectManager type = NM_TYPE_DEVICE_MODEM; else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_OLPC_MESH) == 0) type = NM_TYPE_DEVICE_OLPC_MESH; + else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_OVS_INTERFACE) == 0) + type = NM_TYPE_DEVICE_OVS_INTERFACE; else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_PPP) == 0) type = NM_TYPE_DEVICE_PPP; else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_TEAM) == 0) diff --git a/libnm/nm-device-ovs-interface.c b/libnm/nm-device-ovs-interface.c new file mode 100644 index 0000000000..ed3dbd4ca4 --- /dev/null +++ b/libnm/nm-device-ovs-interface.c @@ -0,0 +1,96 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include + +#include "nm-device-ovs-interface.h" +#include "nm-object-private.h" +#include "nm-setting-ovs-interface.h" +#include "nm-setting-ovs-port.h" +#include "nm-setting-connection.h" + +/** + * NMDeviceOvsInterface: + */ +struct _NMDeviceOvsInterface { + NMDevice parent; +}; + +struct _NMDeviceOvsInterfaceClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE (NMDeviceOvsInterface, nm_device_ovs_interface, NM_TYPE_DEVICE) + +/*****************************************************************************/ + +static const char * +get_type_description (NMDevice *device) +{ + return "ovs-interface"; +} + +static gboolean +connection_compatible (NMDevice *device, NMConnection *connection, GError **error) +{ + const char *iface_name; + + if (!NM_DEVICE_CLASS (nm_device_ovs_interface_parent_class)->connection_compatible (device, connection, error)) + return FALSE; + + if (!nm_connection_is_type (connection, NM_SETTING_OVS_INTERFACE_SETTING_NAME)) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, + _("The connection was not a ovs_interface connection.")); + return FALSE; + } + + iface_name = nm_connection_get_interface_name (connection); + if (!iface_name) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, + _("The connection did not specify an interface name.")); + return FALSE; + } + + return TRUE; +} + +static GType +get_setting_type (NMDevice *device) +{ + return NM_TYPE_SETTING_OVS_INTERFACE; +} + +/*****************************************************************************/ + +static void +nm_device_ovs_interface_init (NMDeviceOvsInterface *device) +{ +} + +static void +nm_device_ovs_interface_class_init (NMDeviceOvsInterfaceClass *ovs_interface_class) +{ + NMDeviceClass *device_class = NM_DEVICE_CLASS (ovs_interface_class); + + device_class->get_type_description = get_type_description; + device_class->connection_compatible = connection_compatible; + device_class->get_setting_type = get_setting_type; +} diff --git a/libnm/nm-device-ovs-interface.h b/libnm/nm-device-ovs-interface.h new file mode 100644 index 0000000000..a49db559ae --- /dev/null +++ b/libnm/nm-device-ovs-interface.h @@ -0,0 +1,45 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#ifndef __NM_DEVICE_OVS_INTERFACE_H__ +#define __NM_DEVICE_OVS_INTERFACE_H__ + +#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION) +#error "Only can be included directly." +#endif + +#include "nm-device.h" + +G_BEGIN_DECLS + +#define NM_TYPE_DEVICE_OVS_INTERFACE (nm_device_ovs_interface_get_type ()) +#define NM_DEVICE_OVS_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_OVS_INTERFACE, NMDeviceOvsInterface)) +#define NM_DEVICE_OVS_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_OVS_INTERFACE, NMDeviceOvsInterfaceClass)) +#define NM_IS_DEVICE_OVS_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_OVS_INTERFACE)) +#define NM_IS_DEVICE_OVS_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_OVS_INTERFACE)) +#define NM_DEVICE_OVS_INTERFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_OVS_INTERFACE, NMDeviceOvsInterfaceClass)) + +typedef struct _NMDeviceOvsInterfaceClass NMDeviceOvsInterfaceClass; + +NM_AVAILABLE_IN_1_10 +GType nm_device_ovs_interface_get_type (void); + +G_END_DECLS + +#endif /* __NM_DEVICE_OVS_INTERFACE_H__ */ diff --git a/libnm/nm-types.h b/libnm/nm-types.h index 1e06d15feb..bc861f194b 100644 --- a/libnm/nm-types.h +++ b/libnm/nm-types.h @@ -26,35 +26,36 @@ #include "nm-dbus-interface.h" #include "nm-connection.h" -typedef struct _NMAccessPoint NMAccessPoint; -typedef struct _NMActiveConnection NMActiveConnection; -typedef struct _NMClient NMClient; -typedef struct _NMDevice NMDevice; -typedef struct _NMDeviceAdsl NMDeviceAdsl; -typedef struct _NMDeviceBond NMDeviceBond; -typedef struct _NMDeviceBridge NMDeviceBridge; -typedef struct _NMDeviceBt NMDeviceBt; -typedef struct _NMDeviceDummy NMDeviceDummy; -typedef struct _NMDeviceEthernet NMDeviceEthernet; -typedef struct _NMDeviceGeneric NMDeviceGeneric; -typedef struct _NMDeviceInfiniband NMDeviceInfiniband; -typedef struct _NMDeviceIPTunnel NMDeviceIPTunnel; -typedef struct _NMDeviceMacsec NMDeviceMacsec; -typedef struct _NMDeviceMacvlan NMDeviceMacvlan; -typedef struct _NMDeviceModem NMDeviceModem; -typedef struct _NMDeviceOlpcMesh NMDeviceOlpcMesh; -typedef struct _NMDevicePpp NMDevicePpp; -typedef struct _NMDeviceTeam NMDeviceTeam; -typedef struct _NMDeviceTun NMDeviceTun; -typedef struct _NMDeviceVlan NMDeviceVlan; -typedef struct _NMDeviceVxlan NMDeviceVxlan; -typedef struct _NMDeviceWifi NMDeviceWifi; -typedef struct _NMDeviceWimax NMDeviceWimax; -typedef struct _NMDhcpConfig NMDhcpConfig; -typedef struct _NMIPConfig NMIPConfig; -typedef struct _NMObject NMObject; -typedef struct _NMRemoteConnection NMRemoteConnection; -typedef struct _NMVpnConnection NMVpnConnection; -typedef struct _NMWimaxNsp NMWimaxNsp; +typedef struct _NMAccessPoint NMAccessPoint; +typedef struct _NMActiveConnection NMActiveConnection; +typedef struct _NMClient NMClient; +typedef struct _NMDevice NMDevice; +typedef struct _NMDeviceAdsl NMDeviceAdsl; +typedef struct _NMDeviceBond NMDeviceBond; +typedef struct _NMDeviceBridge NMDeviceBridge; +typedef struct _NMDeviceBt NMDeviceBt; +typedef struct _NMDeviceDummy NMDeviceDummy; +typedef struct _NMDeviceEthernet NMDeviceEthernet; +typedef struct _NMDeviceGeneric NMDeviceGeneric; +typedef struct _NMDeviceInfiniband NMDeviceInfiniband; +typedef struct _NMDeviceIPTunnel NMDeviceIPTunnel; +typedef struct _NMDeviceMacsec NMDeviceMacsec; +typedef struct _NMDeviceMacvlan NMDeviceMacvlan; +typedef struct _NMDeviceModem NMDeviceModem; +typedef struct _NMDeviceOlpcMesh NMDeviceOlpcMesh; +typedef struct _NMDeviceOvsInterface NMDeviceOvsInterface; +typedef struct _NMDevicePpp NMDevicePpp; +typedef struct _NMDeviceTeam NMDeviceTeam; +typedef struct _NMDeviceTun NMDeviceTun; +typedef struct _NMDeviceVlan NMDeviceVlan; +typedef struct _NMDeviceVxlan NMDeviceVxlan; +typedef struct _NMDeviceWifi NMDeviceWifi; +typedef struct _NMDeviceWimax NMDeviceWimax; +typedef struct _NMDhcpConfig NMDhcpConfig; +typedef struct _NMIPConfig NMIPConfig; +typedef struct _NMObject NMObject; +typedef struct _NMRemoteConnection NMRemoteConnection; +typedef struct _NMVpnConnection NMVpnConnection; +typedef struct _NMWimaxNsp NMWimaxNsp; #endif /* NM_TYPES_H */ diff --git a/po/POTFILES.in b/po/POTFILES.in index 403165fbcc..cf9920a2b3 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -141,6 +141,7 @@ libnm/nm-device-ip-tunnel.c libnm/nm-device-macvlan.c libnm/nm-device-modem.c libnm/nm-device-olpc-mesh.c +libnm/nm-device-ovs-interface.c libnm/nm-device-team.c libnm/nm-device-vlan.c libnm/nm-device-vxlan.c From c536d7e6664c25e477af1537bf780d238db8e01d Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 10 Oct 2017 11:04:32 +0200 Subject: [PATCH 23/36] libnm: add support for ovs-port devices --- Makefile.am | 2 + libnm/NetworkManager.h | 1 + libnm/libnm.ver | 1 + libnm/nm-client.c | 3 ++ libnm/nm-device-ovs-port.c | 95 ++++++++++++++++++++++++++++++++++++++ libnm/nm-device-ovs-port.h | 45 ++++++++++++++++++ libnm/nm-types.h | 1 + po/POTFILES.in | 1 + 8 files changed, 149 insertions(+) create mode 100644 libnm/nm-device-ovs-port.c create mode 100644 libnm/nm-device-ovs-port.h diff --git a/Makefile.am b/Makefile.am index 772731b74d..672e18810c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -752,6 +752,7 @@ libnm_lib_h_pub_real = \ libnm/nm-device-modem.h \ libnm/nm-device-olpc-mesh.h \ libnm/nm-device-ovs-interface.h \ + libnm/nm-device-ovs-port.h \ libnm/nm-device-ppp.h \ libnm/nm-device-team.h \ libnm/nm-device-tun.h \ @@ -806,6 +807,7 @@ libnm_lib_c_real = \ libnm/nm-device-modem.c \ libnm/nm-device-olpc-mesh.c \ libnm/nm-device-ovs-interface.c \ + libnm/nm-device-ovs-port.c \ libnm/nm-device-ppp.c \ libnm/nm-device-team.c \ libnm/nm-device-tun.c \ diff --git a/libnm/NetworkManager.h b/libnm/NetworkManager.h index 407fd62c60..9b2d0ea940 100644 --- a/libnm/NetworkManager.h +++ b/libnm/NetworkManager.h @@ -42,6 +42,7 @@ #include "nm-device-modem.h" #include "nm-device-olpc-mesh.h" #include "nm-device-ovs-interface.h" +#include "nm-device-ovs-port.h" #include "nm-device-team.h" #include "nm-device-tun.h" #include "nm-device-vlan.h" diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 0b3378cfbd..a157724970 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1187,6 +1187,7 @@ global: nm_client_connectivity_check_set_enabled; nm_device_dummy_get_hw_address; nm_device_ovs_interface_get_type; + nm_device_ovs_port_get_type; nm_device_ppp_get_type; nm_ip_route_equal_full; nm_setting_bridge_get_group_forward_mask; diff --git a/libnm/nm-client.c b/libnm/nm-client.c index e608499040..730e2af762 100644 --- a/libnm/nm-client.c +++ b/libnm/nm-client.c @@ -64,6 +64,7 @@ #include "nm-device-modem.h" #include "nm-device-olpc-mesh.h" #include "nm-device-ovs-interface.h" +#include "nm-device-ovs-port.h" #include "nm-device-ppp.h" #include "nm-device-team.h" #include "nm-device-tun.h" @@ -2150,6 +2151,8 @@ obj_nm_for_gdbus_object (NMClient *self, GDBusObject *object, GDBusObjectManager type = NM_TYPE_DEVICE_OLPC_MESH; else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_OVS_INTERFACE) == 0) type = NM_TYPE_DEVICE_OVS_INTERFACE; + else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_OVS_PORT) == 0) + type = NM_TYPE_DEVICE_OVS_PORT; else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_PPP) == 0) type = NM_TYPE_DEVICE_PPP; else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_TEAM) == 0) diff --git a/libnm/nm-device-ovs-port.c b/libnm/nm-device-ovs-port.c new file mode 100644 index 0000000000..17176dba3c --- /dev/null +++ b/libnm/nm-device-ovs-port.c @@ -0,0 +1,95 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include + +#include "nm-device-ovs-port.h" +#include "nm-object-private.h" +#include "nm-setting-ovs-port.h" +#include "nm-setting-ovs-port.h" +#include "nm-setting-connection.h" + +/** + * NMDeviceOvsPort: + */ +struct _NMDeviceOvsPort { + NMDevice parent; +}; + +struct _NMDeviceOvsPortClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE (NMDeviceOvsPort, nm_device_ovs_port, NM_TYPE_DEVICE) + +/*****************************************************************************/ + +static const char * +get_type_description (NMDevice *device) +{ + return "ovs-port"; +} +static gboolean +connection_compatible (NMDevice *device, NMConnection *connection, GError **error) +{ + const char *iface_name; + + if (!NM_DEVICE_CLASS (nm_device_ovs_port_parent_class)->connection_compatible (device, connection, error)) + return FALSE; + + if (!nm_connection_is_type (connection, NM_SETTING_OVS_PORT_SETTING_NAME)) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, + _("The connection was not a ovs_port connection.")); + return FALSE; + } + + iface_name = nm_connection_get_interface_name (connection); + if (!iface_name) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, + _("The connection did not specify an interface name.")); + return FALSE; + } + + return TRUE; +} + +static GType +get_setting_type (NMDevice *device) +{ + return NM_TYPE_SETTING_OVS_PORT; +} + +/*****************************************************************************/ + +static void +nm_device_ovs_port_init (NMDeviceOvsPort *device) +{ +} + +static void +nm_device_ovs_port_class_init (NMDeviceOvsPortClass *ovs_port_class) +{ + NMDeviceClass *device_class = NM_DEVICE_CLASS (ovs_port_class); + + device_class->get_type_description = get_type_description; + device_class->connection_compatible = connection_compatible; + device_class->get_setting_type = get_setting_type; +} diff --git a/libnm/nm-device-ovs-port.h b/libnm/nm-device-ovs-port.h new file mode 100644 index 0000000000..af661e7b82 --- /dev/null +++ b/libnm/nm-device-ovs-port.h @@ -0,0 +1,45 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#ifndef __NM_DEVICE_OVS_PORT_H__ +#define __NM_DEVICE_OVS_PORT_H__ + +#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION) +#error "Only can be included directly." +#endif + +#include "nm-device.h" + +G_BEGIN_DECLS + +#define NM_TYPE_DEVICE_OVS_PORT (nm_device_ovs_port_get_type ()) +#define NM_DEVICE_OVS_PORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_OVS_PORT, NMDeviceOvsPort)) +#define NM_DEVICE_OVS_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_OVS_PORT, NMDeviceOvsPortClass)) +#define NM_IS_DEVICE_OVS_PORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_OVS_PORT)) +#define NM_IS_DEVICE_OVS_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_OVS_PORT)) +#define NM_DEVICE_OVS_PORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_OVS_PORT, NMDeviceOvsPortClass)) + +typedef struct _NMDeviceOvsPortClass NMDeviceOvsPortClass; + +NM_AVAILABLE_IN_1_10 +GType nm_device_ovs_port_get_type (void); + +G_END_DECLS + +#endif /* __NM_DEVICE_OVS_PORT_H__ */ diff --git a/libnm/nm-types.h b/libnm/nm-types.h index bc861f194b..631388d9c1 100644 --- a/libnm/nm-types.h +++ b/libnm/nm-types.h @@ -44,6 +44,7 @@ typedef struct _NMDeviceMacvlan NMDeviceMacvlan; typedef struct _NMDeviceModem NMDeviceModem; typedef struct _NMDeviceOlpcMesh NMDeviceOlpcMesh; typedef struct _NMDeviceOvsInterface NMDeviceOvsInterface; +typedef struct _NMDeviceOvsPort NMDeviceOvsPort; typedef struct _NMDevicePpp NMDevicePpp; typedef struct _NMDeviceTeam NMDeviceTeam; typedef struct _NMDeviceTun NMDeviceTun; diff --git a/po/POTFILES.in b/po/POTFILES.in index cf9920a2b3..205d1409b3 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -142,6 +142,7 @@ libnm/nm-device-macvlan.c libnm/nm-device-modem.c libnm/nm-device-olpc-mesh.c libnm/nm-device-ovs-interface.c +libnm/nm-device-ovs-port.c libnm/nm-device-team.c libnm/nm-device-vlan.c libnm/nm-device-vxlan.c From 3f74528a0b82a06e7be2734808ebfbde2b2588d4 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 10 Oct 2017 11:04:32 +0200 Subject: [PATCH 24/36] libnm: add support for ovs-bridge devices --- Makefile.am | 2 + libnm/NetworkManager.h | 1 + libnm/libnm.ver | 1 + libnm/nm-client.c | 3 ++ libnm/nm-device-ovs-bridge.c | 96 ++++++++++++++++++++++++++++++++++++ libnm/nm-device-ovs-bridge.h | 45 +++++++++++++++++ libnm/nm-types.h | 1 + po/POTFILES.in | 1 + 8 files changed, 150 insertions(+) create mode 100644 libnm/nm-device-ovs-bridge.c create mode 100644 libnm/nm-device-ovs-bridge.h diff --git a/Makefile.am b/Makefile.am index 672e18810c..bdb47f8629 100644 --- a/Makefile.am +++ b/Makefile.am @@ -753,6 +753,7 @@ libnm_lib_h_pub_real = \ libnm/nm-device-olpc-mesh.h \ libnm/nm-device-ovs-interface.h \ libnm/nm-device-ovs-port.h \ + libnm/nm-device-ovs-bridge.h \ libnm/nm-device-ppp.h \ libnm/nm-device-team.h \ libnm/nm-device-tun.h \ @@ -808,6 +809,7 @@ libnm_lib_c_real = \ libnm/nm-device-olpc-mesh.c \ libnm/nm-device-ovs-interface.c \ libnm/nm-device-ovs-port.c \ + libnm/nm-device-ovs-bridge.c \ libnm/nm-device-ppp.c \ libnm/nm-device-team.c \ libnm/nm-device-tun.c \ diff --git a/libnm/NetworkManager.h b/libnm/NetworkManager.h index 9b2d0ea940..7e4e8e08a4 100644 --- a/libnm/NetworkManager.h +++ b/libnm/NetworkManager.h @@ -43,6 +43,7 @@ #include "nm-device-olpc-mesh.h" #include "nm-device-ovs-interface.h" #include "nm-device-ovs-port.h" +#include "nm-device-ovs-bridge.h" #include "nm-device-team.h" #include "nm-device-tun.h" #include "nm-device-vlan.h" diff --git a/libnm/libnm.ver b/libnm/libnm.ver index a157724970..72690ff4f2 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1186,6 +1186,7 @@ global: nm_client_connectivity_check_get_enabled; nm_client_connectivity_check_set_enabled; nm_device_dummy_get_hw_address; + nm_device_ovs_bridge_get_type; nm_device_ovs_interface_get_type; nm_device_ovs_port_get_type; nm_device_ppp_get_type; diff --git a/libnm/nm-client.c b/libnm/nm-client.c index 730e2af762..8c7e293147 100644 --- a/libnm/nm-client.c +++ b/libnm/nm-client.c @@ -65,6 +65,7 @@ #include "nm-device-olpc-mesh.h" #include "nm-device-ovs-interface.h" #include "nm-device-ovs-port.h" +#include "nm-device-ovs-bridge.h" #include "nm-device-ppp.h" #include "nm-device-team.h" #include "nm-device-tun.h" @@ -2153,6 +2154,8 @@ obj_nm_for_gdbus_object (NMClient *self, GDBusObject *object, GDBusObjectManager type = NM_TYPE_DEVICE_OVS_INTERFACE; else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_OVS_PORT) == 0) type = NM_TYPE_DEVICE_OVS_PORT; + else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_OVS_BRIDGE) == 0) + type = NM_TYPE_DEVICE_OVS_BRIDGE; else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_PPP) == 0) type = NM_TYPE_DEVICE_PPP; else if (strcmp (ifname, NM_DBUS_INTERFACE_DEVICE_TEAM) == 0) diff --git a/libnm/nm-device-ovs-bridge.c b/libnm/nm-device-ovs-bridge.c new file mode 100644 index 0000000000..798f6d20de --- /dev/null +++ b/libnm/nm-device-ovs-bridge.c @@ -0,0 +1,96 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include + +#include "nm-device-ovs-bridge.h" +#include "nm-object-private.h" +#include "nm-setting-ovs-bridge.h" +#include "nm-setting-ovs-port.h" +#include "nm-setting-connection.h" + +/** + * NMDeviceOvsBridge: + */ +struct _NMDeviceOvsBridge { + NMDevice parent; +}; + +struct _NMDeviceOvsBridgeClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE (NMDeviceOvsBridge, nm_device_ovs_bridge, NM_TYPE_DEVICE) + +/*****************************************************************************/ + +static const char * +get_type_description (NMDevice *device) +{ + return "ovs-bridge"; +} + +static gboolean +connection_compatible (NMDevice *device, NMConnection *connection, GError **error) +{ + const char *iface_name; + + if (!NM_DEVICE_CLASS (nm_device_ovs_bridge_parent_class)->connection_compatible (device, connection, error)) + return FALSE; + + if (!nm_connection_is_type (connection, NM_SETTING_OVS_BRIDGE_SETTING_NAME)) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, + _("The connection was not a ovs_bridge connection.")); + return FALSE; + } + + iface_name = nm_connection_get_interface_name (connection); + if (!iface_name) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, + _("The connection did not specify an interface name.")); + return FALSE; + } + + return TRUE; +} + +static GType +get_setting_type (NMDevice *device) +{ + return NM_TYPE_SETTING_OVS_BRIDGE; +} + +/*****************************************************************************/ + +static void +nm_device_ovs_bridge_init (NMDeviceOvsBridge *device) +{ +} + +static void +nm_device_ovs_bridge_class_init (NMDeviceOvsBridgeClass *ovs_bridge_class) +{ + NMDeviceClass *device_class = NM_DEVICE_CLASS (ovs_bridge_class); + + device_class->get_type_description = get_type_description; + device_class->connection_compatible = connection_compatible; + device_class->get_setting_type = get_setting_type; +} diff --git a/libnm/nm-device-ovs-bridge.h b/libnm/nm-device-ovs-bridge.h new file mode 100644 index 0000000000..b4b0b98b00 --- /dev/null +++ b/libnm/nm-device-ovs-bridge.h @@ -0,0 +1,45 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#ifndef __NM_DEVICE_OVS_BRIDGE_H__ +#define __NM_DEVICE_OVS_BRIDGE_H__ + +#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION) +#error "Only can be included directly." +#endif + +#include "nm-device.h" + +G_BEGIN_DECLS + +#define NM_TYPE_DEVICE_OVS_BRIDGE (nm_device_ovs_bridge_get_type ()) +#define NM_DEVICE_OVS_BRIDGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_OVS_BRIDGE, NMDeviceOvsBridge)) +#define NM_DEVICE_OVS_BRIDGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_OVS_BRIDGE, NMDeviceOvsBridgeClass)) +#define NM_IS_DEVICE_OVS_BRIDGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_OVS_BRIDGE)) +#define NM_IS_DEVICE_OVS_BRIDGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_OVS_BRIDGE)) +#define NM_DEVICE_OVS_BRIDGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_OVS_BRIDGE, NMDeviceOvsBridgeClass)) + +typedef struct _NMDeviceOvsBridgeClass NMDeviceOvsBridgeClass; + +NM_AVAILABLE_IN_1_10 +GType nm_device_ovs_bridge_get_type (void); + +G_END_DECLS + +#endif /* __NM_DEVICE_OVS_BRIDGE_H__ */ diff --git a/libnm/nm-types.h b/libnm/nm-types.h index 631388d9c1..4310120fec 100644 --- a/libnm/nm-types.h +++ b/libnm/nm-types.h @@ -43,6 +43,7 @@ typedef struct _NMDeviceMacsec NMDeviceMacsec; typedef struct _NMDeviceMacvlan NMDeviceMacvlan; typedef struct _NMDeviceModem NMDeviceModem; typedef struct _NMDeviceOlpcMesh NMDeviceOlpcMesh; +typedef struct _NMDeviceOvsBridge NMDeviceOvsBridge; typedef struct _NMDeviceOvsInterface NMDeviceOvsInterface; typedef struct _NMDeviceOvsPort NMDeviceOvsPort; typedef struct _NMDevicePpp NMDevicePpp; diff --git a/po/POTFILES.in b/po/POTFILES.in index 205d1409b3..c86a0dbdab 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -141,6 +141,7 @@ libnm/nm-device-ip-tunnel.c libnm/nm-device-macvlan.c libnm/nm-device-modem.c libnm/nm-device-olpc-mesh.c +libnm/nm-device-ovs-bridge.c libnm/nm-device-ovs-interface.c libnm/nm-device-ovs-port.c libnm/nm-device-team.c From e7ab81098a18e5d5e550c1273c4047112799322e Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 1 Aug 2017 20:28:05 +0200 Subject: [PATCH 25/36] clients: add support for ovs-patch setting --- clients/cli/connections.c | 1 + clients/common/nm-meta-setting-desc.c | 11 +++++++++++ libnm/NetworkManager.h | 1 + shared/nm-meta-setting.c | 6 ++++++ shared/nm-meta-setting.h | 1 + 5 files changed, 20 insertions(+) diff --git a/clients/cli/connections.c b/clients/cli/connections.c index a13af882e2..0e618b72e6 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -136,6 +136,7 @@ const NmcMetaGenericInfo *const nmc_fields_con_active_details_general[] = { NM_SETTING_BRIDGE_PORT_SETTING_NAME","\ NM_SETTING_TEAM_SETTING_NAME","\ NM_SETTING_TEAM_PORT_SETTING_NAME"," \ + NM_SETTING_OVS_PATCH_SETTING_NAME","\ NM_SETTING_DCB_SETTING_NAME"," \ NM_SETTING_TUN_SETTING_NAME"," \ NM_SETTING_IP_TUNNEL_SETTING_NAME"," \ diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 4e90c42643..cf1d82a1f1 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -5803,6 +5803,15 @@ static const NMMetaPropertyInfo *const property_infos_PPPOE[] = { NULL }; +#undef _CURRENT_NM_META_SETTING_TYPE +#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_OVS_PATCH +static const NMMetaPropertyInfo *const property_infos_OVS_PATCH[] = { + PROPERTY_INFO_WITH_DESC (NM_SETTING_OVS_PATCH_PEER, + .property_type = &_pt_gobject_string, + ), + NULL +}; + #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_PPP static const NMMetaPropertyInfo *const property_infos_PPP[] = { @@ -6722,6 +6731,7 @@ _setting_init_fcn_wireless (ARGS_SETTING_INIT_FCN) #define SETTING_PRETTY_NAME_MACSEC N_("MACsec connection") #define SETTING_PRETTY_NAME_MACVLAN N_("macvlan connection") #define SETTING_PRETTY_NAME_OLPC_MESH N_("OLPC Mesh connection") +#define SETTING_PRETTY_NAME_OVS_PATCH N_("OpenVSwitch patch interface settings") #define SETTING_PRETTY_NAME_PPP N_("PPP settings") #define SETTING_PRETTY_NAME_PPPOE N_("PPPoE") #define SETTING_PRETTY_NAME_PROXY N_("Proxy") @@ -6871,6 +6881,7 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = { ), .setting_init_fcn = _setting_init_fcn_olpc_mesh, ), + SETTING_INFO (OVS_PATCH), SETTING_INFO (PPPOE, /* PPPoE is a base connection type from historical reasons. * See libnm-core/nm-setting.c:_nm_setting_is_base_type() diff --git a/libnm/NetworkManager.h b/libnm/NetworkManager.h index 7e4e8e08a4..6aa40b6f7d 100644 --- a/libnm/NetworkManager.h +++ b/libnm/NetworkManager.h @@ -76,6 +76,7 @@ #include "nm-setting-macsec.h" #include "nm-setting-macvlan.h" #include "nm-setting-olpc-mesh.h" +#include "nm-setting-ovs-patch.h" #include "nm-setting-ppp.h" #include "nm-setting-pppoe.h" #include "nm-setting-proxy.h" diff --git a/shared/nm-meta-setting.c b/shared/nm-meta-setting.c index 3730bb8925..b44becd2d0 100644 --- a/shared/nm-meta-setting.c +++ b/shared/nm-meta-setting.c @@ -43,6 +43,7 @@ #include "nm-setting-macsec.h" #include "nm-setting-macvlan.h" #include "nm-setting-olpc-mesh.h" +#include "nm-setting-ovs-patch.h" #include "nm-setting-ppp.h" #include "nm-setting-pppoe.h" #include "nm-setting-proxy.h" @@ -235,6 +236,11 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = { .setting_name = NM_SETTING_OLPC_MESH_SETTING_NAME, .get_setting_gtype = nm_setting_olpc_mesh_get_type, }, + [NM_META_SETTING_TYPE_OVS_PATCH] = { + .meta_type = NM_META_SETTING_TYPE_OVS_PATCH, + .setting_name = NM_SETTING_OVS_PATCH_SETTING_NAME, + .get_setting_gtype = nm_setting_ovs_patch_get_type, + }, [NM_META_SETTING_TYPE_PPPOE] = { .meta_type = NM_META_SETTING_TYPE_PPPOE, .setting_name = NM_SETTING_PPPOE_SETTING_NAME, diff --git a/shared/nm-meta-setting.h b/shared/nm-meta-setting.h index 949a6920c6..6c2ba2f7a6 100644 --- a/shared/nm-meta-setting.h +++ b/shared/nm-meta-setting.h @@ -75,6 +75,7 @@ typedef enum { NM_META_SETTING_TYPE_MACSEC, NM_META_SETTING_TYPE_MACVLAN, NM_META_SETTING_TYPE_OLPC_MESH, + NM_META_SETTING_TYPE_OVS_PATCH, NM_META_SETTING_TYPE_PPP, NM_META_SETTING_TYPE_PPPOE, NM_META_SETTING_TYPE_PROXY, From 6dcd54b0de026b997a0260eac4661ef84e3e82c6 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 1 Aug 2017 20:28:05 +0200 Subject: [PATCH 26/36] clients: add support for ovs-interface setting --- clients/cli/connections.c | 1 + clients/common/nm-meta-setting-desc.c | 23 +++++++++++++++++++++++ libnm/NetworkManager.h | 1 + shared/nm-meta-setting.c | 6 ++++++ shared/nm-meta-setting.h | 1 + 5 files changed, 32 insertions(+) diff --git a/clients/cli/connections.c b/clients/cli/connections.c index 0e618b72e6..0ece209479 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -136,6 +136,7 @@ const NmcMetaGenericInfo *const nmc_fields_con_active_details_general[] = { NM_SETTING_BRIDGE_PORT_SETTING_NAME","\ NM_SETTING_TEAM_SETTING_NAME","\ NM_SETTING_TEAM_PORT_SETTING_NAME"," \ + NM_SETTING_OVS_INTERFACE_SETTING_NAME","\ NM_SETTING_OVS_PATCH_SETTING_NAME","\ NM_SETTING_DCB_SETTING_NAME"," \ NM_SETTING_TUN_SETTING_NAME"," \ diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index cf1d82a1f1..41ee370e42 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -5803,6 +5803,18 @@ static const NMMetaPropertyInfo *const property_infos_PPPOE[] = { NULL }; +#undef _CURRENT_NM_META_SETTING_TYPE +#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_OVS_INTERFACE +static const NMMetaPropertyInfo *const property_infos_OVS_INTERFACE[] = { + PROPERTY_INFO_WITH_DESC (NM_SETTING_OVS_INTERFACE_TYPE, + .property_type = &_pt_gobject_string, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + .values_static = VALUES_STATIC ("internal", "patch"), + ), + ), + NULL +}; + #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_OVS_PATCH static const NMMetaPropertyInfo *const property_infos_OVS_PATCH[] = { @@ -6731,6 +6743,7 @@ _setting_init_fcn_wireless (ARGS_SETTING_INIT_FCN) #define SETTING_PRETTY_NAME_MACSEC N_("MACsec connection") #define SETTING_PRETTY_NAME_MACVLAN N_("macvlan connection") #define SETTING_PRETTY_NAME_OLPC_MESH N_("OLPC Mesh connection") +#define SETTING_PRETTY_NAME_OVS_INTERFACE N_("OpenVSwitch interface settings") #define SETTING_PRETTY_NAME_OVS_PATCH N_("OpenVSwitch patch interface settings") #define SETTING_PRETTY_NAME_PPP N_("PPP settings") #define SETTING_PRETTY_NAME_PPPOE N_("PPPoE") @@ -6881,6 +6894,16 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = { ), .setting_init_fcn = _setting_init_fcn_olpc_mesh, ), + SETTING_INFO (OVS_INTERFACE, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (OVS_INTERFACE, TRUE), + NM_META_SETTING_VALID_PART_ITEM (OVS_PATCH, FALSE), + NM_META_SETTING_VALID_PART_ITEM (IP4_CONFIG, FALSE), + NM_META_SETTING_VALID_PART_ITEM (IP6_CONFIG, FALSE), + NM_META_SETTING_VALID_PART_ITEM (WIRED, FALSE), + ), + ), SETTING_INFO (OVS_PATCH), SETTING_INFO (PPPOE, /* PPPoE is a base connection type from historical reasons. diff --git a/libnm/NetworkManager.h b/libnm/NetworkManager.h index 6aa40b6f7d..a83c3a7245 100644 --- a/libnm/NetworkManager.h +++ b/libnm/NetworkManager.h @@ -76,6 +76,7 @@ #include "nm-setting-macsec.h" #include "nm-setting-macvlan.h" #include "nm-setting-olpc-mesh.h" +#include "nm-setting-ovs-interface.h" #include "nm-setting-ovs-patch.h" #include "nm-setting-ppp.h" #include "nm-setting-pppoe.h" diff --git a/shared/nm-meta-setting.c b/shared/nm-meta-setting.c index b44becd2d0..313d469542 100644 --- a/shared/nm-meta-setting.c +++ b/shared/nm-meta-setting.c @@ -43,6 +43,7 @@ #include "nm-setting-macsec.h" #include "nm-setting-macvlan.h" #include "nm-setting-olpc-mesh.h" +#include "nm-setting-ovs-interface.h" #include "nm-setting-ovs-patch.h" #include "nm-setting-ppp.h" #include "nm-setting-pppoe.h" @@ -236,6 +237,11 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = { .setting_name = NM_SETTING_OLPC_MESH_SETTING_NAME, .get_setting_gtype = nm_setting_olpc_mesh_get_type, }, + [NM_META_SETTING_TYPE_OVS_INTERFACE] = { + .meta_type = NM_META_SETTING_TYPE_OVS_INTERFACE, + .setting_name = NM_SETTING_OVS_INTERFACE_SETTING_NAME, + .get_setting_gtype = nm_setting_ovs_interface_get_type, + }, [NM_META_SETTING_TYPE_OVS_PATCH] = { .meta_type = NM_META_SETTING_TYPE_OVS_PATCH, .setting_name = NM_SETTING_OVS_PATCH_SETTING_NAME, diff --git a/shared/nm-meta-setting.h b/shared/nm-meta-setting.h index 6c2ba2f7a6..6b35c4acfd 100644 --- a/shared/nm-meta-setting.h +++ b/shared/nm-meta-setting.h @@ -75,6 +75,7 @@ typedef enum { NM_META_SETTING_TYPE_MACSEC, NM_META_SETTING_TYPE_MACVLAN, NM_META_SETTING_TYPE_OLPC_MESH, + NM_META_SETTING_TYPE_OVS_INTERFACE, NM_META_SETTING_TYPE_OVS_PATCH, NM_META_SETTING_TYPE_PPP, NM_META_SETTING_TYPE_PPPOE, From 6f73b4608af089cde3b7e5f51b018713f3e48421 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 1 Aug 2017 20:28:05 +0200 Subject: [PATCH 27/36] clients: add support for ovs-port setting --- clients/cli/connections.c | 1 + clients/common/nm-meta-setting-desc.c | 50 +++++++++++++++++++++++++++ libnm/NetworkManager.h | 1 + shared/nm-meta-setting.c | 6 ++++ shared/nm-meta-setting.h | 1 + 5 files changed, 59 insertions(+) diff --git a/clients/cli/connections.c b/clients/cli/connections.c index 0ece209479..8e00433ed7 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -138,6 +138,7 @@ const NmcMetaGenericInfo *const nmc_fields_con_active_details_general[] = { NM_SETTING_TEAM_PORT_SETTING_NAME"," \ NM_SETTING_OVS_INTERFACE_SETTING_NAME","\ NM_SETTING_OVS_PATCH_SETTING_NAME","\ + NM_SETTING_OVS_PORT_SETTING_NAME","\ NM_SETTING_DCB_SETTING_NAME"," \ NM_SETTING_TUN_SETTING_NAME"," \ NM_SETTING_IP_TUNNEL_SETTING_NAME"," \ diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 41ee370e42..d6b939af44 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -5009,6 +5009,7 @@ static const NMMetaPropertyInfo *const property_infos_CONNECTION[] = { .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( .values_static = VALUES_STATIC (NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BRIDGE_SETTING_NAME, + NM_SETTING_OVS_PORT_SETTING_NAME, NM_SETTING_TEAM_SETTING_NAME), ), ), @@ -5824,6 +5825,39 @@ static const NMMetaPropertyInfo *const property_infos_OVS_PATCH[] = { NULL }; +#undef _CURRENT_NM_META_SETTING_TYPE +#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_OVS_PORT +static const NMMetaPropertyInfo *const property_infos_OVS_PORT[] = { + PROPERTY_INFO_WITH_DESC (NM_SETTING_OVS_PORT_VLAN_MODE, + .property_type = &_pt_gobject_string, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + .values_static = VALUES_STATIC ("access", "native-tagged", "native-untagged", "trunk"), + ), + ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_OVS_PORT_TAG, + .property_type = &_pt_gobject_int, + ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_OVS_PORT_LACP, + .property_type = &_pt_gobject_string, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + .values_static = VALUES_STATIC ("active", "off", "passive"), + ), + ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_OVS_PORT_BOND_MODE, + .property_type = &_pt_gobject_string, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + .values_static = VALUES_STATIC ("active-backup", "balance-slb", "balance-tcp"), + ), + ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_OVS_PORT_BOND_UPDELAY, + .property_type = &_pt_gobject_int, + ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_OVS_PORT_BOND_DOWNDELAY, + .property_type = &_pt_gobject_int, + ), + NULL +}; + #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_PPP static const NMMetaPropertyInfo *const property_infos_PPP[] = { @@ -6745,6 +6779,7 @@ _setting_init_fcn_wireless (ARGS_SETTING_INIT_FCN) #define SETTING_PRETTY_NAME_OLPC_MESH N_("OLPC Mesh connection") #define SETTING_PRETTY_NAME_OVS_INTERFACE N_("OpenVSwitch interface settings") #define SETTING_PRETTY_NAME_OVS_PATCH N_("OpenVSwitch patch interface settings") +#define SETTING_PRETTY_NAME_OVS_PORT N_("OpenVSwitch port settings") #define SETTING_PRETTY_NAME_PPP N_("PPP settings") #define SETTING_PRETTY_NAME_PPPOE N_("PPPoE") #define SETTING_PRETTY_NAME_PROXY N_("Proxy") @@ -6905,6 +6940,12 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = { ), ), SETTING_INFO (OVS_PATCH), + SETTING_INFO (OVS_PORT, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (OVS_PORT, TRUE), + ), + ), SETTING_INFO (PPPOE, /* PPPoE is a base connection type from historical reasons. * See libnm-core/nm-setting.c:_nm_setting_is_base_type() @@ -7011,6 +7052,11 @@ static const NMMetaSettingValidPartItem *const valid_settings_slave_bridge[] = { NULL, }; +static const NMMetaSettingValidPartItem *const valid_settings_slave_ovs_port[] = { + NM_META_SETTING_VALID_PART_ITEM (OVS_INTERFACE, FALSE), + NULL, +}; + static const NMMetaSettingValidPartItem *const valid_settings_slave_team[] = { NM_META_SETTING_VALID_PART_ITEM (TEAM_PORT, TRUE), NULL, @@ -7031,6 +7077,10 @@ nm_meta_setting_info_valid_parts_for_slave_type (const char *slave_type, const c NM_SET_OUT (out_slave_name, "bridge-slave"); return valid_settings_slave_bridge; } + if (nm_streq (slave_type, NM_SETTING_OVS_PORT_SETTING_NAME)) { + NM_SET_OUT (out_slave_name, "ovs-slave"); + return valid_settings_slave_ovs_port; + } if (nm_streq (slave_type, NM_SETTING_TEAM_SETTING_NAME)) { NM_SET_OUT (out_slave_name, "team-slave"); return valid_settings_slave_team; diff --git a/libnm/NetworkManager.h b/libnm/NetworkManager.h index a83c3a7245..eba8770feb 100644 --- a/libnm/NetworkManager.h +++ b/libnm/NetworkManager.h @@ -78,6 +78,7 @@ #include "nm-setting-olpc-mesh.h" #include "nm-setting-ovs-interface.h" #include "nm-setting-ovs-patch.h" +#include "nm-setting-ovs-port.h" #include "nm-setting-ppp.h" #include "nm-setting-pppoe.h" #include "nm-setting-proxy.h" diff --git a/shared/nm-meta-setting.c b/shared/nm-meta-setting.c index 313d469542..d7aba8f646 100644 --- a/shared/nm-meta-setting.c +++ b/shared/nm-meta-setting.c @@ -45,6 +45,7 @@ #include "nm-setting-olpc-mesh.h" #include "nm-setting-ovs-interface.h" #include "nm-setting-ovs-patch.h" +#include "nm-setting-ovs-port.h" #include "nm-setting-ppp.h" #include "nm-setting-pppoe.h" #include "nm-setting-proxy.h" @@ -247,6 +248,11 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = { .setting_name = NM_SETTING_OVS_PATCH_SETTING_NAME, .get_setting_gtype = nm_setting_ovs_patch_get_type, }, + [NM_META_SETTING_TYPE_OVS_PORT] = { + .meta_type = NM_META_SETTING_TYPE_OVS_PORT, + .setting_name = NM_SETTING_OVS_PORT_SETTING_NAME, + .get_setting_gtype = nm_setting_ovs_port_get_type, + }, [NM_META_SETTING_TYPE_PPPOE] = { .meta_type = NM_META_SETTING_TYPE_PPPOE, .setting_name = NM_SETTING_PPPOE_SETTING_NAME, diff --git a/shared/nm-meta-setting.h b/shared/nm-meta-setting.h index 6b35c4acfd..7f8c514acc 100644 --- a/shared/nm-meta-setting.h +++ b/shared/nm-meta-setting.h @@ -77,6 +77,7 @@ typedef enum { NM_META_SETTING_TYPE_OLPC_MESH, NM_META_SETTING_TYPE_OVS_INTERFACE, NM_META_SETTING_TYPE_OVS_PATCH, + NM_META_SETTING_TYPE_OVS_PORT, NM_META_SETTING_TYPE_PPP, NM_META_SETTING_TYPE_PPPOE, NM_META_SETTING_TYPE_PROXY, From aec8d36b3e02adcb4cd8740e8e779b21846dd395 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 1 Aug 2017 20:28:05 +0200 Subject: [PATCH 28/36] clients: add support for ovs-bridge setting --- clients/cli/connections.c | 1 + clients/common/nm-meta-setting-desc.c | 38 +++++++++++++++++++++++++++ libnm/NetworkManager.h | 1 + shared/nm-meta-setting.c | 6 +++++ shared/nm-meta-setting.h | 1 + 5 files changed, 47 insertions(+) diff --git a/clients/cli/connections.c b/clients/cli/connections.c index 8e00433ed7..73c1de2644 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -136,6 +136,7 @@ const NmcMetaGenericInfo *const nmc_fields_con_active_details_general[] = { NM_SETTING_BRIDGE_PORT_SETTING_NAME","\ NM_SETTING_TEAM_SETTING_NAME","\ NM_SETTING_TEAM_PORT_SETTING_NAME"," \ + NM_SETTING_OVS_BRIDGE_SETTING_NAME","\ NM_SETTING_OVS_INTERFACE_SETTING_NAME","\ NM_SETTING_OVS_PATCH_SETTING_NAME","\ NM_SETTING_OVS_PORT_SETTING_NAME","\ diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index d6b939af44..0231fe06ce 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -5009,6 +5009,7 @@ static const NMMetaPropertyInfo *const property_infos_CONNECTION[] = { .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( .values_static = VALUES_STATIC (NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BRIDGE_SETTING_NAME, + NM_SETTING_OVS_BRIDGE_SETTING_NAME, NM_SETTING_OVS_PORT_SETTING_NAME, NM_SETTING_TEAM_SETTING_NAME), ), @@ -5804,6 +5805,27 @@ static const NMMetaPropertyInfo *const property_infos_PPPOE[] = { NULL }; +#undef _CURRENT_NM_META_SETTING_TYPE +#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_OVS_BRIDGE +static const NMMetaPropertyInfo *const property_infos_OVS_BRIDGE[] = { + PROPERTY_INFO_WITH_DESC (NM_SETTING_OVS_BRIDGE_FAIL_MODE, + .property_type = &_pt_gobject_string, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + .values_static = VALUES_STATIC ("secure", "standalone"), + ), + ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_OVS_BRIDGE_MCAST_SNOOPING_ENABLE, + .property_type = &_pt_gobject_bool, + ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_OVS_BRIDGE_RSTP_ENABLE, + .property_type = &_pt_gobject_bool, + ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_OVS_BRIDGE_STP_ENABLE, + .property_type = &_pt_gobject_bool, + ), + NULL +}; + #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_OVS_INTERFACE static const NMMetaPropertyInfo *const property_infos_OVS_INTERFACE[] = { @@ -6777,6 +6799,7 @@ _setting_init_fcn_wireless (ARGS_SETTING_INIT_FCN) #define SETTING_PRETTY_NAME_MACSEC N_("MACsec connection") #define SETTING_PRETTY_NAME_MACVLAN N_("macvlan connection") #define SETTING_PRETTY_NAME_OLPC_MESH N_("OLPC Mesh connection") +#define SETTING_PRETTY_NAME_OVS_BRIDGE N_("OpenVSwitch bridge settings") #define SETTING_PRETTY_NAME_OVS_INTERFACE N_("OpenVSwitch interface settings") #define SETTING_PRETTY_NAME_OVS_PATCH N_("OpenVSwitch patch interface settings") #define SETTING_PRETTY_NAME_OVS_PORT N_("OpenVSwitch port settings") @@ -6929,6 +6952,12 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = { ), .setting_init_fcn = _setting_init_fcn_olpc_mesh, ), + SETTING_INFO (OVS_BRIDGE, + .valid_parts = NM_META_SETTING_VALID_PARTS ( + NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), + NM_META_SETTING_VALID_PART_ITEM (OVS_BRIDGE, TRUE), + ), + ), SETTING_INFO (OVS_INTERFACE, .valid_parts = NM_META_SETTING_VALID_PARTS ( NM_META_SETTING_VALID_PART_ITEM (CONNECTION, TRUE), @@ -7052,6 +7081,11 @@ static const NMMetaSettingValidPartItem *const valid_settings_slave_bridge[] = { NULL, }; +static const NMMetaSettingValidPartItem *const valid_settings_slave_ovs_bridge[] = { + NM_META_SETTING_VALID_PART_ITEM (OVS_PORT, FALSE), + NULL, +}; + static const NMMetaSettingValidPartItem *const valid_settings_slave_ovs_port[] = { NM_META_SETTING_VALID_PART_ITEM (OVS_INTERFACE, FALSE), NULL, @@ -7077,6 +7111,10 @@ nm_meta_setting_info_valid_parts_for_slave_type (const char *slave_type, const c NM_SET_OUT (out_slave_name, "bridge-slave"); return valid_settings_slave_bridge; } + if (nm_streq (slave_type, NM_SETTING_OVS_BRIDGE_SETTING_NAME)) { + NM_SET_OUT (out_slave_name, "ovs-slave"); + return valid_settings_slave_ovs_bridge; + } if (nm_streq (slave_type, NM_SETTING_OVS_PORT_SETTING_NAME)) { NM_SET_OUT (out_slave_name, "ovs-slave"); return valid_settings_slave_ovs_port; diff --git a/libnm/NetworkManager.h b/libnm/NetworkManager.h index eba8770feb..27737e0e1b 100644 --- a/libnm/NetworkManager.h +++ b/libnm/NetworkManager.h @@ -76,6 +76,7 @@ #include "nm-setting-macsec.h" #include "nm-setting-macvlan.h" #include "nm-setting-olpc-mesh.h" +#include "nm-setting-ovs-bridge.h" #include "nm-setting-ovs-interface.h" #include "nm-setting-ovs-patch.h" #include "nm-setting-ovs-port.h" diff --git a/shared/nm-meta-setting.c b/shared/nm-meta-setting.c index d7aba8f646..734b824246 100644 --- a/shared/nm-meta-setting.c +++ b/shared/nm-meta-setting.c @@ -43,6 +43,7 @@ #include "nm-setting-macsec.h" #include "nm-setting-macvlan.h" #include "nm-setting-olpc-mesh.h" +#include "nm-setting-ovs-bridge.h" #include "nm-setting-ovs-interface.h" #include "nm-setting-ovs-patch.h" #include "nm-setting-ovs-port.h" @@ -238,6 +239,11 @@ const NMMetaSettingInfo nm_meta_setting_infos[] = { .setting_name = NM_SETTING_OLPC_MESH_SETTING_NAME, .get_setting_gtype = nm_setting_olpc_mesh_get_type, }, + [NM_META_SETTING_TYPE_OVS_BRIDGE] = { + .meta_type = NM_META_SETTING_TYPE_OVS_BRIDGE, + .setting_name = NM_SETTING_OVS_BRIDGE_SETTING_NAME, + .get_setting_gtype = nm_setting_ovs_bridge_get_type, + }, [NM_META_SETTING_TYPE_OVS_INTERFACE] = { .meta_type = NM_META_SETTING_TYPE_OVS_INTERFACE, .setting_name = NM_SETTING_OVS_INTERFACE_SETTING_NAME, diff --git a/shared/nm-meta-setting.h b/shared/nm-meta-setting.h index 7f8c514acc..f36e322e89 100644 --- a/shared/nm-meta-setting.h +++ b/shared/nm-meta-setting.h @@ -75,6 +75,7 @@ typedef enum { NM_META_SETTING_TYPE_MACSEC, NM_META_SETTING_TYPE_MACVLAN, NM_META_SETTING_TYPE_OLPC_MESH, + NM_META_SETTING_TYPE_OVS_BRIDGE, NM_META_SETTING_TYPE_OVS_INTERFACE, NM_META_SETTING_TYPE_OVS_PATCH, NM_META_SETTING_TYPE_OVS_PORT, From d0cb2050f371824f3f660e52e2655334559671bd Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 16 Oct 2017 21:32:12 +0200 Subject: [PATCH 29/36] all: add OVSDB connection failure device state reason --- clients/common/nm-client-utils.c | 3 +++ libnm-core/nm-dbus-interface.h | 2 ++ src/devices/nm-device.c | 1 + 3 files changed, 6 insertions(+) diff --git a/clients/common/nm-client-utils.c b/clients/common/nm-client-utils.c index fa7b720f46..bf4dcc77f3 100644 --- a/clients/common/nm-client-utils.c +++ b/clients/common/nm-client-utils.c @@ -399,6 +399,9 @@ nmc_device_reason_to_string (NMDeviceStateReason reason) return _("The device's parent changed"); case NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED: return _("The device parent's management changed"); + + case NM_DEVICE_STATE_REASON_OVSDB_FAILED: + return _("OpenVSwitch database connection failed"); } /* TRANSLATORS: Unknown reason for a device state change (NMDeviceStateReason) */ diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h index 7618542697..7f75c84955 100644 --- a/libnm-core/nm-dbus-interface.h +++ b/libnm-core/nm-dbus-interface.h @@ -550,6 +550,7 @@ typedef enum { * @NM_DEVICE_STATE_REASON_NEW_ACTIVATION: New connection activation was enqueued * @NM_DEVICE_STATE_REASON_PARENT_CHANGED: the device's parent changed * @NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED: the device parent's management changed + * @NM_DEVICE_STATE_REASON_OVSDB_FAILED: problem communicating with OpenVSwitch database * * Device state change reason codes */ @@ -617,6 +618,7 @@ typedef enum { NM_DEVICE_STATE_REASON_NEW_ACTIVATION = 60, NM_DEVICE_STATE_REASON_PARENT_CHANGED = 61, NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED = 62, + NM_DEVICE_STATE_REASON_OVSDB_FAILED = 63, } NMDeviceStateReason; /** diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 4453acae23..04b522f8a9 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -646,6 +646,7 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_reason_to_string, NMDeviceStateReason, NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_NEW_ACTIVATION, "new-activation"), NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_PARENT_CHANGED, "parent-changed"), NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED, "parent-managed-changed"), + NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_OVSDB_FAILED, "ovsdb-failed"), ); #define reason_to_string(reason) \ From 830a5a14cb29ca00b73a9623c1ea7c5cd92f4d00 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 1 Aug 2017 18:27:22 +0200 Subject: [PATCH 30/36] device: add support for OpenVSwitch devices --- Makefile.am | 57 + configure.ac | 15 + contrib/fedora/rpm/NetworkManager.spec | 20 + data/NetworkManager-ovs.conf | 2 + src/devices/ovs/nm-device-ovs-bridge.c | 156 ++ src/devices/ovs/nm-device-ovs-bridge.h | 35 + src/devices/ovs/nm-device-ovs-interface.c | 191 +++ src/devices/ovs/nm-device-ovs-interface.h | 35 + src/devices/ovs/nm-device-ovs-port.c | 201 +++ src/devices/ovs/nm-device-ovs-port.h | 35 + src/devices/ovs/nm-ovs-factory.c | 195 +++ src/devices/ovs/nm-ovsdb.c | 1591 +++++++++++++++++++++ src/devices/ovs/nm-ovsdb.h | 50 + 13 files changed, 2583 insertions(+) create mode 100644 data/NetworkManager-ovs.conf create mode 100644 src/devices/ovs/nm-device-ovs-bridge.c create mode 100644 src/devices/ovs/nm-device-ovs-bridge.h create mode 100644 src/devices/ovs/nm-device-ovs-interface.c create mode 100644 src/devices/ovs/nm-device-ovs-interface.h create mode 100644 src/devices/ovs/nm-device-ovs-port.c create mode 100644 src/devices/ovs/nm-device-ovs-port.h create mode 100644 src/devices/ovs/nm-ovs-factory.c create mode 100644 src/devices/ovs/nm-ovsdb.c create mode 100644 src/devices/ovs/nm-ovsdb.h diff --git a/Makefile.am b/Makefile.am index bdb47f8629..1c7456d6f4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2768,6 +2768,63 @@ check_local += check-local-devices-team endif +############################################################################### +# src/devices/ovs +############################################################################### + +if WITH_OPENVSWITCH + +if HAVE_SYSTEMD + +systemdnmunitdir = $(systemdsystemunitdir)/NetworkManager.service.d +systemdnmunit_DATA = \ + data/NetworkManager-ovs.conf + +endif + +core_plugins += src/devices/ovs/libnm-device-plugin-ovs.la + +src_devices_ovs_libnm_device_plugin_ovs_la_SOURCES = \ + src/devices/ovs/nm-ovsdb.c \ + src/devices/ovs/nm-ovsdb.h \ + src/devices/ovs/nm-ovs-factory.c \ + src/devices/ovs/nm-device-ovs-interface.c \ + src/devices/ovs/nm-device-ovs-interface.h \ + src/devices/ovs/nm-device-ovs-port.c \ + src/devices/ovs/nm-device-ovs-port.h \ + src/devices/ovs/nm-device-ovs-bridge.c \ + src/devices/ovs/nm-device-ovs-bridge.h + +src_devices_ovs_libnm_device_plugin_ovs_la_CPPFLAGS = \ + -I$(srcdir)/src \ + -I$(builddir)/src \ + -I$(srcdir)/shared \ + -I$(builddir)/shared \ + -I$(builddir)/libnm-core \ + -I$(srcdir)/libnm-core \ + \ + -DG_LOG_DOMAIN=\""NetworkManager"\" \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ + -DRUNSTATEDIR=\"$(runstatedir)\" \ + \ + $(JANSSON_CFLAGS) \ + $(GLIB_CFLAGS) + +src_devices_ovs_libnm_device_plugin_ovs_la_LDFLAGS = \ + -module -avoid-version \ + -Wl,--version-script="$(srcdir)/linker-script-devices.ver" + +src_devices_ovs_libnm_device_plugin_ovs_la_LIBADD = \ + introspection/libnmdbus.la \ + $(JANSSON_LIBS) \ + $(GLIB_LIBS) + +check-local-devices-ovs: src/devices/ovs/libnm-device-plugin-ovs.la + $(srcdir)/tools/check-exports.sh $(builddir)/src/devices/ovs/.libs/libnm-device-plugin-ovs.so "$(srcdir)/linker-script-devices.ver" + $(call check_so_symbols,$(builddir)/src/devices/ovs/.libs/libnm-device-plugin-ovs.so) + +endif + ############################################################################### # src/dnsmasq/tests ############################################################################### diff --git a/configure.ac b/configure.ac index a4353760a4..8ff914d0e8 100644 --- a/configure.ac +++ b/configure.ac @@ -871,6 +871,20 @@ if test "$with_dhcpcanon" != "no"; then else AC_DEFINE(WITH_DHCPCANON, 0, [Define if you have dhcpcanon]) fi + +# OpenVSwitch integration +AC_ARG_ENABLE(ovs, AS_HELP_STRING([--enable-ovs], [enable OpenVSwitch support])) +if test "${enable_ovs}" != "no"; then + enable_ovs='yes' + if test "$have_jansson" = "no"; then + AC_MSG_ERROR(Jansson is required for ovs support) + fi + AC_DEFINE(WITH_OPENVSWITCH, 1, [Define if you have OpenVSwitch support]) +else + AC_DEFINE(WITH_OPENVSWITCH, 0, [Define if you have OpenVSwitch support]) +fi +AM_CONDITIONAL(WITH_OPENVSWITCH, test "${enable_ovs}" = "yes") + # DHCP client support AC_ARG_WITH([dhclient], AS_HELP_STRING([--with-dhclient=yes|no|path], [Enable dhclient 4.x support])) @@ -1359,6 +1373,7 @@ echo " modemmanager-1: $with_modem_manager_1" echo " ofono: $with_ofono" echo " concheck: $enable_concheck" echo " libteamdctl: $enable_teamdctl" +echo " ovs: $enable_ovs" echo " libnm-glib: $with_libnm_glib" echo " nmcli: $build_nmcli" echo " nmtui: $build_nmtui" diff --git a/contrib/fedora/rpm/NetworkManager.spec b/contrib/fedora/rpm/NetworkManager.spec index 64393526c4..6dcadf81f3 100644 --- a/contrib/fedora/rpm/NetworkManager.spec +++ b/contrib/fedora/rpm/NetworkManager.spec @@ -50,6 +50,7 @@ %bcond_without wwan %bcond_without team %bcond_without wifi +%bcond_without ovs %bcond_without ppp %bcond_without nmtui %bcond_without regen_docs @@ -240,6 +241,19 @@ This package contains NetworkManager support for mobile broadband (WWAN) devices. %endif + +%if %{with ovs} +%package ovs +Summary: OpenVSwitch device plugin for NetworkManager +Group: System Environment/Base +Requires: %{name}%{?_isa} = %{epoch}:%{version}-%{release} +Requires: openvswitch + +%description ovs +This package contains NetworkManager support for OpenVSwitch bridges. +%endif + + %if %{with ppp} %package ppp Summary: PPP plugin for NetworkManager @@ -608,6 +622,12 @@ fi %{_libdir}/%{name}/libnm-wwan.so %endif +%if %{with ovs} +%files ovs +%{_libdir}/%{name}/libnm-device-plugin-ovs.so +%{systemd_dir}/NetworkManager.service.d/NetworkManager-ovs.conf +%endif + %if %{with ppp} %files ppp %{_libdir}/pppd/%{ppp_version}/nm-pppd-plugin.so diff --git a/data/NetworkManager-ovs.conf b/data/NetworkManager-ovs.conf new file mode 100644 index 0000000000..dde5ba5897 --- /dev/null +++ b/data/NetworkManager-ovs.conf @@ -0,0 +1,2 @@ +[Unit] +After=openvswitch.service diff --git a/src/devices/ovs/nm-device-ovs-bridge.c b/src/devices/ovs/nm-device-ovs-bridge.c new file mode 100644 index 0000000000..53ea2b8287 --- /dev/null +++ b/src/devices/ovs/nm-device-ovs-bridge.c @@ -0,0 +1,156 @@ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-device-ovs-bridge.h" +#include "nm-device-ovs-port.h" +#include "nm-ovsdb.h" + +#include "devices/nm-device-private.h" +#include "nm-active-connection.h" +#include "nm-setting-connection.h" +#include "nm-setting-ovs-bridge.h" + +#include "introspection/org.freedesktop.NetworkManager.Device.OvsBridge.h" + +#include "devices/nm-device-logging.h" +_LOG_DECLARE_SELF(NMDeviceOvsBridge); + +/*****************************************************************************/ + +struct _NMDeviceOvsBridge { + NMDevice parent; +}; + +struct _NMDeviceOvsBridgeClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE (NMDeviceOvsBridge, nm_device_ovs_bridge, NM_TYPE_DEVICE) + +/*****************************************************************************/ + +static const char * +get_type_description (NMDevice *device) +{ + return "ovs-bridge"; +} + +static gboolean +create_and_realize (NMDevice *device, + NMConnection *connection, + NMDevice *parent, + const NMPlatformLink **out_plink, + GError **error) +{ + /* The actual backing resources will be created on enslavement by the port + * when it can identify the port and the bridge. */ + + return TRUE; +} + +static gboolean +unrealize (NMDevice *device, GError **error) +{ + return TRUE; +} + +static NMDeviceCapabilities +get_generic_capabilities (NMDevice *device) +{ + return NM_DEVICE_CAP_IS_SOFTWARE; +} + +static gboolean +check_connection_compatible (NMDevice *device, NMConnection *connection) +{ + const char *connection_type; + + if (!NM_DEVICE_CLASS (nm_device_ovs_bridge_parent_class)->check_connection_compatible (device, connection)) + return FALSE; + + connection_type = nm_connection_get_connection_type (connection); + if (!nm_streq0 (connection_type, NM_SETTING_OVS_BRIDGE_SETTING_NAME)) + return FALSE; + + return TRUE; +} + +static NMActStageReturn +act_stage3_ip4_config_start (NMDevice *device, + NMIP4Config **out_config, + NMDeviceStateReason *out_failure_reason) +{ + return NM_ACT_STAGE_RETURN_IP_FAIL; +} + +static NMActStageReturn +act_stage3_ip6_config_start (NMDevice *device, + NMIP6Config **out_config, + NMDeviceStateReason *out_failure_reason) +{ + return NM_ACT_STAGE_RETURN_IP_FAIL; +} + +static gboolean +enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure) +{ + if (!configure) + return TRUE; + + if (!NM_IS_DEVICE_OVS_PORT (slave)) + return FALSE; + + return TRUE; +} + +static void +release_slave (NMDevice *device, NMDevice *slave, gboolean configure) +{ +} + +/*****************************************************************************/ + +static void +nm_device_ovs_bridge_init (NMDeviceOvsBridge *self) +{ +} + +static void +nm_device_ovs_bridge_class_init (NMDeviceOvsBridgeClass *klass) +{ + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); + + device_class->connection_type = NM_SETTING_OVS_BRIDGE_SETTING_NAME; + device_class->is_master = TRUE; + device_class->get_type_description = get_type_description; + device_class->create_and_realize = create_and_realize; + device_class->unrealize = unrealize; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->check_connection_compatible = check_connection_compatible; + device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; + device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; + device_class->enslave_slave = enslave_slave; + device_class->release_slave = release_slave; + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_OVS_BRIDGE_SKELETON, + NULL); +} diff --git a/src/devices/ovs/nm-device-ovs-bridge.h b/src/devices/ovs/nm-device-ovs-bridge.h new file mode 100644 index 0000000000..631b4754ca --- /dev/null +++ b/src/devices/ovs/nm-device-ovs-bridge.h @@ -0,0 +1,35 @@ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#ifndef __NETWORKMANAGER_DEVICE_OVS_BRIDGE_H__ +#define __NETWORKMANAGER_DEVICE_OVS_BRIDGE_H__ + +#define NM_TYPE_DEVICE_OVS_BRIDGE (nm_device_ovs_bridge_get_type ()) +#define NM_DEVICE_OVS_BRIDGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_OVS_BRIDGE, NMDeviceOvsBridge)) +#define NM_DEVICE_OVS_BRIDGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_OVS_BRIDGE, NMDeviceOvsBridgeClass)) +#define NM_IS_DEVICE_OVS_BRIDGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_OVS_BRIDGE)) +#define NM_IS_DEVICE_OVS_BRIDGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_OVS_BRIDGE)) +#define NM_DEVICE_OVS_BRIDGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_OVS_BRIDGE, NMDeviceOvsBridgeClass)) + +typedef struct _NMDeviceOvsBridge NMDeviceOvsBridge; +typedef struct _NMDeviceOvsBridgeClass NMDeviceOvsBridgeClass; + +GType nm_device_ovs_bridge_get_type (void); + +#endif /* __NETWORKMANAGER_DEVICE_OVS_BRIDGE_H__ */ diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c new file mode 100644 index 0000000000..426521c52c --- /dev/null +++ b/src/devices/ovs/nm-device-ovs-interface.c @@ -0,0 +1,191 @@ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-device-ovs-interface.h" +#include "nm-ovsdb.h" + +#include "devices/nm-device-private.h" +#include "nm-active-connection.h" +#include "nm-setting-connection.h" +#include "nm-setting-ovs-interface.h" +#include "nm-setting-ovs-port.h" + +#include "introspection/org.freedesktop.NetworkManager.Device.OvsInterface.h" + +#include "devices/nm-device-logging.h" +_LOG_DECLARE_SELF(NMDeviceOvsInterface); + +/*****************************************************************************/ + +struct _NMDeviceOvsInterface { + NMDevice parent; +}; + +struct _NMDeviceOvsInterfaceClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE (NMDeviceOvsInterface, nm_device_ovs_interface, NM_TYPE_DEVICE) + +/*****************************************************************************/ + +static const char * +get_type_description (NMDevice *device) +{ + return "ovs-interface"; +} + +static gboolean +create_and_realize (NMDevice *device, + NMConnection *connection, + NMDevice *parent, + const NMPlatformLink **out_plink, + GError **error) +{ + /* The actual backing resources will be created once an interface is + * added to a port of ours, since there can be neither an empty port nor + * an empty bridge. */ + + return TRUE; +} + +static NMDeviceCapabilities +get_generic_capabilities (NMDevice *device) +{ + return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; +} + +static gboolean +is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) +{ + return TRUE; +} + +static gboolean +check_connection_compatible (NMDevice *device, NMConnection *connection) +{ + NMSettingConnection *s_con; + NMSettingOvsInterface *s_ovs_iface; + + if (!NM_DEVICE_CLASS (nm_device_ovs_interface_parent_class)->check_connection_compatible (device, connection)) + return FALSE; + + s_ovs_iface = nm_connection_get_setting_ovs_interface (connection); + if (!s_ovs_iface) + return FALSE; + if (!NM_IN_STRSET (nm_setting_ovs_interface_get_interface_type (s_ovs_iface), + "internal", "patch")) { + return FALSE; + } + + s_con = nm_connection_get_setting_connection (connection); + if (g_strcmp0 (nm_setting_connection_get_connection_type (s_con), + NM_SETTING_OVS_INTERFACE_SETTING_NAME) != 0) { + return FALSE; + } + + return TRUE; +} + +static void +link_changed (NMDevice *device, + const NMPlatformLink *pllink) +{ + if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) { + nm_device_bring_up (device, TRUE, NULL); + nm_device_activate_schedule_stage3_ip_config_start (device); + } +} + +static gboolean +_is_internal_interface (NMDevice *device) +{ + NMConnection *connection = nm_device_get_applied_connection (device); + NMSettingOvsInterface *s_ovs_iface = nm_connection_get_setting_ovs_interface (connection); + + g_return_val_if_fail (s_ovs_iface, FALSE); + + return strcmp (nm_setting_ovs_interface_get_interface_type (s_ovs_iface), "internal") == 0; +} + +static NMActStageReturn +act_stage3_ip4_config_start (NMDevice *device, + NMIP4Config **out_config, + NMDeviceStateReason *out_failure_reason) +{ + if (!_is_internal_interface (device)) + return NM_ACT_STAGE_RETURN_IP_FAIL; + + if (!nm_device_get_ip_ifindex (device)) + return NM_ACT_STAGE_RETURN_POSTPONE; + + return NM_DEVICE_CLASS (nm_device_ovs_interface_parent_class)->act_stage3_ip4_config_start (device, out_config, out_failure_reason); +} + +static NMActStageReturn +act_stage3_ip6_config_start (NMDevice *device, + NMIP6Config **out_config, + NMDeviceStateReason *out_failure_reason) +{ + if (!_is_internal_interface (device)) + return NM_ACT_STAGE_RETURN_IP_FAIL; + + if (!nm_device_get_ip_ifindex (device)) + return NM_ACT_STAGE_RETURN_POSTPONE; + + return NM_DEVICE_CLASS (nm_device_ovs_interface_parent_class)->act_stage3_ip6_config_start (device, out_config, out_failure_reason); +} + +static gboolean +can_unmanaged_external_down (NMDevice *self) +{ + return FALSE; +} + +/*****************************************************************************/ + +static void +nm_device_ovs_interface_init (NMDeviceOvsInterface *self) +{ +} + +static void +nm_device_ovs_interface_class_init (NMDeviceOvsInterfaceClass *klass) +{ + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); + + NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_OPENVSWITCH); + + device_class->connection_type = NM_SETTING_OVS_INTERFACE_SETTING_NAME; + device_class->get_type_description = get_type_description; + device_class->create_and_realize = create_and_realize; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->is_available = is_available; + device_class->check_connection_compatible = check_connection_compatible; + device_class->link_changed = link_changed; + device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; + device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; + device_class->can_unmanaged_external_down = can_unmanaged_external_down; + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_OVS_INTERFACE_SKELETON, + NULL); +} diff --git a/src/devices/ovs/nm-device-ovs-interface.h b/src/devices/ovs/nm-device-ovs-interface.h new file mode 100644 index 0000000000..a748e206e3 --- /dev/null +++ b/src/devices/ovs/nm-device-ovs-interface.h @@ -0,0 +1,35 @@ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#ifndef __NETWORKMANAGER_DEVICE_OVS_INTERFACE_H__ +#define __NETWORKMANAGER_DEVICE_OVS_INTERFACE_H__ + +#define NM_TYPE_DEVICE_OVS_INTERFACE (nm_device_ovs_interface_get_type ()) +#define NM_DEVICE_OVS_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_OVS_INTERFACE, NMDeviceOvsInterface)) +#define NM_DEVICE_OVS_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_OVS_INTERFACE, NMDeviceOvsInterfaceClass)) +#define NM_IS_DEVICE_OVS_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_OVS_INTERFACE)) +#define NM_IS_DEVICE_OVS_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_OVS_INTERFACE)) +#define NM_DEVICE_OVS_INTERFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_OVS_INTERFACE, NMDeviceOvsInterfaceClass)) + +typedef struct _NMDeviceOvsInterface NMDeviceOvsInterface; +typedef struct _NMDeviceOvsInterfaceClass NMDeviceOvsInterfaceClass; + +GType nm_device_ovs_interface_get_type (void); + +#endif /* __NETWORKMANAGER_DEVICE_OVS_INTERFACE_H__ */ diff --git a/src/devices/ovs/nm-device-ovs-port.c b/src/devices/ovs/nm-device-ovs-port.c new file mode 100644 index 0000000000..83199f2d4c --- /dev/null +++ b/src/devices/ovs/nm-device-ovs-port.c @@ -0,0 +1,201 @@ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-device-ovs-port.h" +#include "nm-ovsdb.h" + +#include "devices/nm-device-private.h" +#include "nm-active-connection.h" +#include "nm-setting-connection.h" +#include "nm-setting-ovs-port.h" +#include "nm-setting-ovs-port.h" + +#include "introspection/org.freedesktop.NetworkManager.Device.OvsPort.h" + +#include "devices/nm-device-logging.h" +_LOG_DECLARE_SELF(NMDeviceOvsPort); + +/*****************************************************************************/ + +struct _NMDeviceOvsPort { + NMDevice parent; +}; + +struct _NMDeviceOvsPortClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE (NMDeviceOvsPort, nm_device_ovs_port, NM_TYPE_DEVICE) + +/*****************************************************************************/ + +static const char * +get_type_description (NMDevice *device) +{ + return "ovs-port"; +} + +static gboolean +create_and_realize (NMDevice *device, + NMConnection *connection, + NMDevice *parent, + const NMPlatformLink **out_plink, + GError **error) +{ + /* The port will be added to ovsdb when an interface is enslaved, + * because there's no such thing like an empty port. */ + + return TRUE; +} + +static NMDeviceCapabilities +get_generic_capabilities (NMDevice *device) +{ + return NM_DEVICE_CAP_IS_SOFTWARE; +} + + +static gboolean +check_connection_compatible (NMDevice *device, NMConnection *connection) +{ + NMSettingConnection *s_con; + const char *connection_type; + + if (!NM_DEVICE_CLASS (nm_device_ovs_port_parent_class)->check_connection_compatible (device, connection)) + return FALSE; + + s_con = nm_connection_get_setting_connection (connection); + connection_type = nm_setting_connection_get_connection_type (s_con); + if (!connection_type) + return FALSE; + + if (strcmp (connection_type, NM_SETTING_OVS_PORT_SETTING_NAME) == 0) + return TRUE; + + return FALSE; +} + +static NMActStageReturn +act_stage3_ip4_config_start (NMDevice *device, + NMIP4Config **out_config, + NMDeviceStateReason *out_failure_reason) +{ + return NM_ACT_STAGE_RETURN_IP_FAIL; +} + +static NMActStageReturn +act_stage3_ip6_config_start (NMDevice *device, + NMIP6Config **out_config, + NMDeviceStateReason *out_failure_reason) +{ + return NM_ACT_STAGE_RETURN_IP_FAIL; +} + +static void +add_iface_cb (GError *error, gpointer user_data) +{ + NMDevice *slave = user_data; + + if (error) { + nm_log_warn (LOGD_DEVICE, "device %s could not be added to a ovs port: %s", + nm_device_get_iface (slave), error->message); + nm_device_state_changed (slave, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_OVSDB_FAILED); + } + + g_object_unref (slave); +} + +static gboolean +enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure) +{ + NMActiveConnection *ac_port = NULL; + NMActiveConnection *ac_bridge = NULL; + + if (!configure) + return TRUE; + + + ac_port = NM_ACTIVE_CONNECTION (nm_device_get_act_request (device)); + ac_bridge = nm_active_connection_get_master (ac_port); + if (!ac_bridge) + ac_bridge = ac_port; + + nm_ovsdb_add_interface (nm_ovsdb_get (), + nm_active_connection_get_applied_connection (ac_bridge), + nm_device_get_applied_connection (device), + nm_device_get_applied_connection (slave), + add_iface_cb, g_object_ref (slave)); + + return TRUE; +} + +static void +del_iface_cb (GError *error, gpointer user_data) +{ + NMDevice *slave = user_data; + + if (error) { + nm_log_warn (LOGD_DEVICE, "device %s could not be removed from a ovs port: %s", + nm_device_get_iface (slave), error->message); + nm_device_state_changed (slave, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_OVSDB_FAILED); + } + + g_object_unref (slave); +} + +static void +release_slave (NMDevice *device, NMDevice *slave, gboolean configure) +{ + nm_ovsdb_del_interface (nm_ovsdb_get (), nm_device_get_iface (slave), + del_iface_cb, g_object_ref (slave)); +} + +/*****************************************************************************/ + +static void +nm_device_ovs_port_init (NMDeviceOvsPort *self) +{ +} + +static void +nm_device_ovs_port_class_init (NMDeviceOvsPortClass *klass) +{ + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); + + device_class->connection_type = NM_SETTING_OVS_PORT_SETTING_NAME; + device_class->is_master = TRUE; + device_class->get_type_description = get_type_description; + device_class->create_and_realize = create_and_realize; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->check_connection_compatible = check_connection_compatible; + device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; + device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; + device_class->enslave_slave = enslave_slave; + device_class->release_slave = release_slave; + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_OVS_PORT_SKELETON, + NULL); +} diff --git a/src/devices/ovs/nm-device-ovs-port.h b/src/devices/ovs/nm-device-ovs-port.h new file mode 100644 index 0000000000..5ccf1ec195 --- /dev/null +++ b/src/devices/ovs/nm-device-ovs-port.h @@ -0,0 +1,35 @@ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#ifndef __NETWORKMANAGER_DEVICE_OVS_PORT_H__ +#define __NETWORKMANAGER_DEVICE_OVS_PORT_H__ + +#define NM_TYPE_DEVICE_OVS_PORT (nm_device_ovs_port_get_type ()) +#define NM_DEVICE_OVS_PORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_OVS_PORT, NMDeviceOvsPort)) +#define NM_DEVICE_OVS_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_OVS_PORT, NMDeviceOvsPortClass)) +#define NM_IS_DEVICE_OVS_PORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_OVS_PORT)) +#define NM_IS_DEVICE_OVS_PORT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_OVS_PORT)) +#define NM_DEVICE_OVS_PORT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_OVS_PORT, NMDeviceOvsPortClass)) + +typedef struct _NMDeviceOvsPort NMDeviceOvsPort; +typedef struct _NMDeviceOvsPortClass NMDeviceOvsPortClass; + +GType nm_device_ovs_port_get_type (void); + +#endif /* __NETWORKMANAGER_DEVICE_OVS_PORT_H__ */ diff --git a/src/devices/ovs/nm-ovs-factory.c b/src/devices/ovs/nm-ovs-factory.c new file mode 100644 index 0000000000..830f94fc0c --- /dev/null +++ b/src/devices/ovs/nm-ovs-factory.c @@ -0,0 +1,195 @@ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-manager.h" +#include "nm-ovsdb.h" +#include "nm-device-ovs-interface.h" +#include "nm-device-ovs-port.h" +#include "nm-device-ovs-bridge.h" +#include "platform/nm-platform.h" +#include "nm-core-internal.h" +#include "devices/nm-device-factory.h" + +/*****************************************************************************/ + +typedef struct { + NMDeviceFactory parent; +} NMOvsFactory; + +typedef struct { + NMDeviceFactoryClass parent; +} NMOvsFactoryClass; + +#define NM_TYPE_OVS_FACTORY (nm_ovs_factory_get_type ()) +#define NM_OVS_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_OVS_FACTORY, NMOvsFactory)) +#define NM_OVS_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_OVS_FACTORY, NMOvsFactoryClass)) +#define NM_IS_OVS_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_OVS_FACTORY)) +#define NM_IS_OVS_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_OVS_FACTORY)) +#define NM_OVS_FACTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_OVS_FACTORY, NMOvsFactoryClass)) + +static GType nm_ovs_factory_get_type (void); +G_DEFINE_TYPE (NMOvsFactory, nm_ovs_factory, NM_TYPE_DEVICE_FACTORY) + +/*****************************************************************************/ + +#define _NMLOG_DOMAIN LOGD_DEVICE +#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "ovs", __VA_ARGS__) + +/*****************************************************************************/ + +NM_DEVICE_FACTORY_DECLARE_TYPES ( + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_OPENVSWITCH) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_OVS_BRIDGE_SETTING_NAME, + NM_SETTING_OVS_INTERFACE_SETTING_NAME, + NM_SETTING_OVS_PORT_SETTING_NAME) +) + +G_MODULE_EXPORT NMDeviceFactory * +nm_device_factory_create (GError **error) +{ + return (NMDeviceFactory *) g_object_new (NM_TYPE_OVS_FACTORY, NULL); +} + +static NMDevice * +new_device_from_type (const char *name, NMDeviceType device_type) +{ + GType type; + const char *type_desc; + NMLinkType link_type = NM_LINK_TYPE_NONE; + + if (nm_manager_get_device (nm_manager_get (), name, device_type)) + return NULL; + + if (device_type == NM_DEVICE_TYPE_OVS_INTERFACE) { + type = NM_TYPE_DEVICE_OVS_INTERFACE; + type_desc = "OpenVSwitch Interface"; + link_type = NM_LINK_TYPE_OPENVSWITCH; + } else if (device_type == NM_DEVICE_TYPE_OVS_PORT) { + type = NM_TYPE_DEVICE_OVS_PORT; + type_desc = "OpenVSwitch Port"; + } else if (device_type == NM_DEVICE_TYPE_OVS_BRIDGE) { + type = NM_TYPE_DEVICE_OVS_BRIDGE; + type_desc = "OpenVSwitch Bridge"; + } else { + return NULL; + } + + return g_object_new (type, + NM_DEVICE_IFACE, name, + NM_DEVICE_DRIVER, "openvswitch", + NM_DEVICE_DEVICE_TYPE, device_type, + NM_DEVICE_TYPE_DESC, type_desc, + NM_DEVICE_LINK_TYPE, link_type, + NULL); +} + +static void +ovsdb_device_added (NMOvsdb *ovsdb, const char *name, NMDeviceType device_type, + NMDeviceFactory *self) +{ + NMDevice *device = NULL; + + device = new_device_from_type (name, device_type); + if (!device) + return; + + g_signal_emit_by_name (self, NM_DEVICE_FACTORY_DEVICE_ADDED, device); + g_object_unref (device); +} + +static void +ovsdb_device_removed (NMOvsdb *ovsdb, const char *name, NMDeviceType device_type, + NMDeviceFactory *self) +{ + NMDevice *device; + NMDeviceState device_state; + + device = nm_manager_get_device (nm_manager_get (), name, device_type); + if (!device) + return; + + device_state = nm_device_get_state (device); + if ( device_type == NM_DEVICE_TYPE_OVS_INTERFACE + && device_state > NM_DEVICE_STATE_DISCONNECTED + && device_state < NM_DEVICE_STATE_DEACTIVATING) { + nm_device_state_changed (device, + NM_DEVICE_STATE_DEACTIVATING, + NM_DEVICE_STATE_REASON_REMOVED); + } else if (device_state == NM_DEVICE_STATE_UNMANAGED) { + nm_device_unrealize (device, TRUE, NULL); + } +} + +static void +start (NMDeviceFactory *self) +{ + NMOvsdb *ovsdb; + + ovsdb = nm_ovsdb_get (); + + g_signal_connect_object (ovsdb, NM_OVSDB_DEVICE_ADDED, G_CALLBACK (ovsdb_device_added), self, (GConnectFlags) 0); + g_signal_connect_object (ovsdb, NM_OVSDB_DEVICE_REMOVED, G_CALLBACK (ovsdb_device_removed), self, (GConnectFlags) 0); +} + +static NMDevice * +create_device (NMDeviceFactory *self, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) +{ + NMDeviceType device_type = NM_DEVICE_TYPE_UNKNOWN; + const char *connection_type = NULL; + + if (g_strcmp0 (iface, "ovs-system") == 0) { + *out_ignore = TRUE; + return NULL; + } + + if (connection) + connection_type = nm_connection_get_connection_type (connection); + + if (plink) + device_type = NM_DEVICE_TYPE_OVS_INTERFACE; + else if (g_strcmp0 (connection_type, NM_SETTING_OVS_INTERFACE_SETTING_NAME) == 0) + device_type = NM_DEVICE_TYPE_OVS_INTERFACE; + else if (g_strcmp0 (connection_type, NM_SETTING_OVS_PORT_SETTING_NAME) == 0) + device_type = NM_DEVICE_TYPE_OVS_PORT; + else if (g_strcmp0 (connection_type, NM_SETTING_OVS_BRIDGE_SETTING_NAME) == 0) + device_type = NM_DEVICE_TYPE_OVS_BRIDGE; + + return new_device_from_type (iface, device_type); +} + +static void +nm_ovs_factory_init (NMOvsFactory *self) +{ +} + +static void +nm_ovs_factory_class_init (NMOvsFactoryClass *klass) +{ + NMDeviceFactoryClass *factory_class = NM_DEVICE_FACTORY_CLASS (klass); + + factory_class->get_supported_types = get_supported_types; + factory_class->start = start; + factory_class->create_device = create_device; +} diff --git a/src/devices/ovs/nm-ovsdb.c b/src/devices/ovs/nm-ovsdb.c new file mode 100644 index 0000000000..28f44f287b --- /dev/null +++ b/src/devices/ovs/nm-ovsdb.c @@ -0,0 +1,1591 @@ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-ovsdb.h" + +#include +#include +#include +#include + +#include "devices/nm-device.h" +#include "platform/nm-platform.h" +#include "nm-core-internal.h" + +/* Added in Jansson v2.4 (released Sep 23 2012), but travis.ci has v2.2. */ +#ifndef json_boolean +#define json_boolean(val) ((val) ? json_true() : json_false()) +#endif + +/*****************************************************************************/ + +typedef struct { + char *name; + char *connection_uuid; + GPtrArray *interfaces; /* interface uuids */ +} OpenvswitchPort; + +typedef struct { + char *name; + char *connection_uuid; + GPtrArray *ports; /* port uuids */ +} OpenvswitchBridge; + +typedef struct { + char *name; + char *type; + char *connection_uuid; +} OpenvswitchInterface; + +/*****************************************************************************/ + +enum { + DEVICE_ADDED, + DEVICE_REMOVED, + DEVICE_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +typedef struct { + GSocketClient *client; + GSocketConnection *conn; + GCancellable *cancellable; + char buf[4096]; /* Input buffer */ + size_t bufp; /* Last decoded byte in the input buffer. */ + GString *input; /* JSON stream waiting for decoding. */ + GString *output; /* JSON stream to be sent. */ + gint64 seq; + GArray *calls; /* Method calls waiting for a response. */ + GHashTable *interfaces; /* interface uuid => OpenvswitchInterface */ + GHashTable *ports; /* port uuid => OpenvswitchPort */ + GHashTable *bridges; /* bridge uuid => OpenvswitchBridge */ + const char *db_uuid; +} NMOvsdbPrivate; + +struct _NMOvsdb { + GObject parent; + NMOvsdbPrivate _priv; +}; + +struct _NMOvsdbClass { + GObjectClass parent; +}; + +G_DEFINE_TYPE (NMOvsdb, nm_ovsdb, G_TYPE_OBJECT) + +#define NM_OVSDB_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMOvsdb, NM_IS_OVSDB) + +#define _NMLOG_DOMAIN LOGD_DEVICE +#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "ovsdb", __VA_ARGS__) + +NM_DEFINE_SINGLETON_GETTER (NMOvsdb, nm_ovsdb_get, NM_TYPE_OVSDB); + +/*****************************************************************************/ + +static void ovsdb_try_connect (NMOvsdb *self); +static void ovsdb_disconnect (NMOvsdb *self); +static void ovsdb_read (NMOvsdb *self); +static void ovsdb_write (NMOvsdb *self); +static void ovsdb_next_command (NMOvsdb *self); + +/*****************************************************************************/ + +/* ovsdb command abstraction. */ + +typedef void (*OvsdbMethodCallback) (NMOvsdb *self, json_t *response, + GError *error, gpointer user_data); + +typedef enum { + OVSDB_MONITOR, + OVSDB_ADD_INTERFACE, + OVSDB_DEL_INTERFACE, +} OvsdbCommand; + +typedef struct { + gint64 id; +#define COMMAND_PENDING -1 /* id not yet assigned */ + OvsdbCommand command; + OvsdbMethodCallback callback; + gpointer user_data; + union { + const char *ifname; + struct { + NMConnection *bridge; + NMConnection *port; + NMConnection *interface; + }; + }; +} OvsdbMethodCall; + +static void +_call_trace (const char *comment, OvsdbMethodCall *call, json_t *msg) +{ +#ifdef NM_MORE_LOGGING + char *str = NULL; + + if (msg) + str = json_dumps (msg, 0); + + switch (call->command) { + case OVSDB_MONITOR: + _LOGT ("%s: monitor%s%s", + comment, + msg ? ": " : "", + msg ? str : ""); + break; + case OVSDB_ADD_INTERFACE: + _LOGT ("%s: add-iface bridge=%s port=%s interface=%s%s%s", + comment, + nm_connection_get_interface_name (call->bridge), + nm_connection_get_interface_name (call->port), + nm_connection_get_interface_name (call->interface), + msg ? ": " : "", + msg ? str : ""); + break; + case OVSDB_DEL_INTERFACE: + _LOGT ("%s: del-iface interface=%s%s%s", + comment, call->ifname, + msg ? ": " : "", + msg ? str : ""); + break; + } + + if (msg) + g_free (str); +#endif +} + +/** + * ovsdb_call_method: + * + * Queues the ovsdb command. Eventually fires the command right away if + * there's no command pending completion. + */ +static void +ovsdb_call_method (NMOvsdb *self, OvsdbCommand command, + const char *ifname, + NMConnection *bridge, NMConnection *port, NMConnection *interface, + OvsdbMethodCallback callback, gpointer user_data) +{ + NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); + OvsdbMethodCall *call; + + /* Ensure we're not unsynchronized before we queue the method call. */ + ovsdb_try_connect (self); + + g_array_set_size (priv->calls, priv->calls->len + 1); + call = &g_array_index (priv->calls, OvsdbMethodCall, priv->calls->len - 1); + call->id = COMMAND_PENDING; + call->command = command; + call->callback = callback; + call->user_data = user_data; + + switch (call->command) { + case OVSDB_MONITOR: + break; + case OVSDB_ADD_INTERFACE: + call->bridge = nm_simple_connection_new_clone (bridge); + call->port = nm_simple_connection_new_clone (port); + call->interface = nm_simple_connection_new_clone (interface); + break; + case OVSDB_DEL_INTERFACE: + call->ifname = g_strdup (ifname); + break; + } + + _call_trace ("enqueue", call, NULL); + + ovsdb_next_command (self); +} + +/*****************************************************************************/ + +/* Create and process the JSON-RPC messages from ovsdb. */ + +/** + * _expect_ovs_bridges: + * + * Return a command that will fail the transaction if the actual set of + * bridges doesn't match @bridges. This is a way of detecting race conditions + * with other ovsdb clients that might be adding or removing bridges + * at the same time. + */ +static void +_expect_ovs_bridges (json_t *params, const char *db_uuid, json_t *bridges) +{ + json_array_append_new (params, + json_pack ("{s:s, s:s, s:i, s:[s], s:s, s:[{s:[s, O]}], s:[[s, s, [s, s]]]}", + "op", "wait", "table", "Open_vSwitch", + "timeout", 0, "columns", "bridges", + "until", "==", "rows", "bridges", "set", bridges, + "where", "_uuid", "==", "uuid", db_uuid) + ); +} + +/** + * _set_ovs_bridges: + * + * Return a command that will update the list of bridges in @db_uuid + * database to @new_bridges. + */ +static void +_set_ovs_bridges (json_t *params, const char *db_uuid, json_t *new_bridges) +{ + json_array_append_new (params, + json_pack ("{s:s, s:s, s:{s:[s, O]}, s:[[s, s, [s, s]]]}", + "op", "update", "table", "Open_vSwitch", + "row", "bridges", "set", new_bridges, + "where", "_uuid", "==", "uuid", db_uuid) + ); +} + +/** + * _expect_bridge_ports: + * + * Return a command that will fail the transaction if the actual set of + * ports in bridge @ifname doesn't match @ports. This is a way of detecting + * race conditions with other ovsdb clients that might be adding or removing + * bridge ports at the same time. + */ +static void +_expect_bridge_ports (json_t *params, const char *ifname, json_t *ports) +{ + json_array_append_new (params, + json_pack ("{s:s, s:s, s:i, s:[s], s:s, s:[{s:[s, O]}], s:[[s, s, s]]}", + "op", "wait", "table", "Bridge", + "timeout", 0, "columns", "ports", + "until", "==", "rows", "ports", "set", ports, + "where", "name", "==", ifname) + ); +} + +/** + * _set_bridge_ports: + * + * Return a command that will update the list of ports of bridge + * @ifname to @new_ports. + */ +static void +_set_bridge_ports (json_t *params, const char *ifname, json_t *new_ports) +{ + json_array_append_new (params, + json_pack ("{s:s, s:s, s:{s:[s, O]}, s:[[s, s, s]]}", + "op", "update", "table", "Bridge", + "row", "ports", "set", new_ports, + "where", "name", "==", ifname) + ); +} + +/** + * _expect_port_interfaces: + * + * Return a command that will fail the transaction if the actual set of + * interfaces in port @ifname doesn't match @interfaces. This is a way of + * detecting race conditions with other ovsdb clients that might be adding + * or removing port interfaces at the same time. + */ +static void +_expect_port_interfaces (json_t *params, const char *ifname, json_t *interfaces) +{ + json_array_append_new (params, + json_pack ("{s:s, s:s, s:i, s:[s], s:s, s:[{s:[s, O]}], s:[[s, s, s]]}", + "op", "wait", "table", "Port", + "timeout", 0, "columns", "interfaces", + "until", "==", "rows", "interfaces", "set", interfaces, + "where", "name", "==", ifname) + ); +} + +/** + * _set_port_interfaces: + * + * Return a command that will update the list of interfaces of port @ifname + * to @new_interfaces. + */ +static void +_set_port_interfaces (json_t *params, const char *ifname, json_t *new_interfaces) +{ + json_array_append_new (params, + json_pack ("{s:s, s:s, s:{s:[s, O]}, s:[[s, s, s]]}", + "op", "update", "table", "Port", + "row", "interfaces", "set", new_interfaces, + "where", "name", "==", ifname) + ); +} + +/** + * _insert_interface: + * + * Returns an commands that adds new interface from a given connection. + */ +static void +_insert_interface (json_t *params, NMConnection *interface) +{ + const char *type = NULL; + NMSettingOvsInterface *s_ovs_iface; + NMSettingOvsPatch *s_ovs_patch; + json_t *options = json_array (); + + s_ovs_iface = nm_connection_get_setting_ovs_interface (interface); + if (s_ovs_iface) + type = nm_setting_ovs_interface_get_interface_type (s_ovs_iface); + + json_array_append (options, json_string ("map")); + s_ovs_patch = nm_connection_get_setting_ovs_patch (interface); + if (s_ovs_patch) { + json_array_append (options, json_pack ("[[s, s]]", + "peer", + nm_setting_ovs_patch_get_peer (s_ovs_patch))); + } else { + json_array_append (options, json_array ()); + } + + json_array_append_new (params, + json_pack ("{s:s, s:s, s:{s:s, s:s, s:o, s:[s, [[s, s]]]}, s:s}", + "op", "insert", "table", "Interface", "row", + "name", nm_connection_get_interface_name (interface), + "type", type ? type : "", + "options", options, + "external_ids", "map", "NM.connection.uuid", nm_connection_get_uuid (interface), + "uuid-name", "rowInterface")); +} + +/** + * _insert_port: + * + * Returns an commands that adds new port from a given connection. + */ +static void +_insert_port (json_t *params, NMConnection *port, json_t *new_interfaces) +{ + NMSettingOvsPort *s_ovs_port; + const char *vlan_mode = NULL; + guint tag = 0; + const char *lacp = NULL; + const char *bond_mode = NULL; + guint bond_updelay = 0; + guint bond_downdelay = 0; + json_t *row; + + s_ovs_port = nm_connection_get_setting_ovs_port (port); + + row = json_object (); + + if (s_ovs_port) { + vlan_mode = nm_setting_ovs_port_get_vlan_mode (s_ovs_port); + tag = nm_setting_ovs_port_get_tag (s_ovs_port); + lacp = nm_setting_ovs_port_get_lacp (s_ovs_port); + bond_mode = nm_setting_ovs_port_get_bond_mode (s_ovs_port); + bond_updelay = nm_setting_ovs_port_get_bond_updelay (s_ovs_port); + bond_downdelay = nm_setting_ovs_port_get_bond_downdelay (s_ovs_port); + } + + if (vlan_mode) + json_object_set_new (row, "vlan_mode", json_string (vlan_mode)); + if (tag) + json_object_set_new (row, "tag", json_integer (tag)); + if (lacp) + json_object_set_new (row, "lacp", json_string (lacp)); + if (bond_mode) + json_object_set_new (row, "bond_mode", json_string (bond_mode)); + if (bond_updelay) + json_object_set_new (row, "bond_updelay", json_integer (bond_updelay)); + if (bond_downdelay) + json_object_set_new (row, "bond_downdelay", json_integer (bond_downdelay)); + + json_object_set_new (row, "name", json_string (nm_connection_get_interface_name (port))); + json_object_set_new (row, "interfaces", json_pack ("[s, O]", "set", new_interfaces)); + json_object_set_new (row, "external_ids", + json_pack ("[s, [[s, s]]]", "map", + "NM.connection.uuid", nm_connection_get_uuid (port))); + + /* Create a new one. */ + json_array_append_new (params, + json_pack ("{s:s, s:s, s:o, s:s}", "op", "insert", "table", "Port", + "row", row, "uuid-name", "rowPort")); +} + +/** + * _insert_bridge: + * + * Returns an commands that adds new bridge from a given connection. + */ +static void +_insert_bridge (json_t *params, NMConnection *bridge, json_t *new_ports) +{ + NMSettingOvsBridge *s_ovs_bridge; + const char *fail_mode = NULL; + gboolean mcast_snooping_enable = FALSE; + gboolean rstp_enable = FALSE; + gboolean stp_enable = FALSE; + json_t *row; + + s_ovs_bridge = nm_connection_get_setting_ovs_bridge (bridge); + + row = json_object (); + + if (s_ovs_bridge) { + fail_mode = nm_setting_ovs_bridge_get_fail_mode (s_ovs_bridge); + mcast_snooping_enable = nm_setting_ovs_bridge_get_mcast_snooping_enable (s_ovs_bridge); + rstp_enable = nm_setting_ovs_bridge_get_rstp_enable (s_ovs_bridge); + stp_enable = nm_setting_ovs_bridge_get_stp_enable (s_ovs_bridge); + } + + if (fail_mode) + json_object_set_new (row, "fail_mode", json_string (fail_mode)); + if (mcast_snooping_enable) + json_object_set_new (row, "mcast_snooping_enable", json_boolean (mcast_snooping_enable)); + if (rstp_enable) + json_object_set_new (row, "rstp_enable", json_boolean (rstp_enable)); + if (stp_enable) + json_object_set_new (row, "stp_enable", json_boolean (stp_enable)); + + json_object_set_new (row, "name", json_string (nm_connection_get_interface_name (bridge))); + json_object_set_new (row, "ports", json_pack ("[s, O]", "set", new_ports)); + json_object_set_new (row, "external_ids", + json_pack ("[s, [[s, s]]]", "map", + "NM.connection.uuid", nm_connection_get_uuid (bridge))); + + /* Create a new one. */ + json_array_append_new (params, + json_pack ("{s:s, s:s, s:o, s:s}", "op", "insert", "table", "Bridge", + "row", row, "uuid-name", "rowBridge")); +} + +/** + * _inc_next_cfg: + * + * Returns an mutate command that bumps next_cfg upon successful completion + * of the transaction it is in. + */ +static json_t * +_inc_next_cfg (const char *db_uuid) +{ + return json_pack ("{s:s, s:s, s:[[s, s, i]], s:[[s, s, [s, s]]]}", + "op", "mutate", "table", "Open_vSwitch", + "mutations", "next_cfg", "+=", 1, + "where", "_uuid", "==", "uuid", db_uuid); +} + +/** + * _add_interface: + * + * Adds an interface as specified by @interface connection, optionally creating + * a parent @port and @bridge if needed. + */ +static void +_add_interface (NMOvsdb *self, json_t *params, + NMConnection *bridge, NMConnection *port, NMConnection *interface) +{ + NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); + GHashTableIter iter; + const char *bridge_uuid; + const char *port_uuid; + const char *interface_uuid; + OpenvswitchBridge *ovs_bridge = NULL; + OpenvswitchPort *ovs_port = NULL; + OpenvswitchInterface *ovs_interface = NULL; + int pi; + int ii; + json_t *bridges, *new_bridges; + json_t *ports, *new_ports; + json_t *interfaces, *new_interfaces; + gboolean has_interface = FALSE; + + bridges = json_array (); + ports = json_array (); + interfaces = json_array (); + new_bridges = json_array (); + new_ports = json_array (); + new_interfaces = json_array (); + + g_hash_table_iter_init (&iter, priv->bridges); + while (g_hash_table_iter_next (&iter, (gpointer) &bridge_uuid, (gpointer) &ovs_bridge)) { + json_array_append_new (bridges, json_pack ("[s, s]", "uuid", bridge_uuid)); + + if ( g_strcmp0 (ovs_bridge->name, nm_connection_get_interface_name (bridge)) != 0 + || g_strcmp0 (ovs_bridge->connection_uuid, nm_connection_get_uuid (bridge)) != 0) + continue; + + for (pi = 0; pi < ovs_bridge->ports->len; pi++) { + port_uuid = g_ptr_array_index (ovs_bridge->ports, pi); + ovs_port = g_hash_table_lookup (priv->ports, port_uuid); + + json_array_append_new (ports, json_pack ("[s, s]", "uuid", port_uuid)); + + if ( g_strcmp0 (ovs_port->name, nm_connection_get_interface_name (port)) != 0 + || g_strcmp0 (ovs_port->connection_uuid, nm_connection_get_uuid (port)) != 0) + continue; + + for (ii = 0; ii < ovs_port->interfaces->len; ii++) { + interface_uuid = g_ptr_array_index (ovs_port->interfaces, ii); + ovs_interface = g_hash_table_lookup (priv->interfaces, interface_uuid); + + json_array_append_new (interfaces, json_pack ("[s, s]", "uuid", interface_uuid)); + + if ( g_strcmp0 (ovs_interface->name, nm_connection_get_interface_name (interface)) == 0 + && g_strcmp0 (ovs_interface->connection_uuid, nm_connection_get_uuid (interface)) == 0) + has_interface = TRUE; + } + + break; + } + + break; + } + + json_array_extend (new_bridges, bridges); + json_array_extend (new_ports, ports); + json_array_extend (new_interfaces, interfaces); + + if (json_array_size (interfaces) == 0) { + /* Need to create a port. */ + if (json_array_size (ports) == 0) { + /* Need to create a bridge. */ + _expect_ovs_bridges (params, priv->db_uuid, bridges); + json_array_append_new (new_bridges, json_pack ("[s, s]", "named-uuid", "rowBridge")); + _set_ovs_bridges (params, priv->db_uuid, new_bridges); + _insert_bridge (params, bridge, new_ports); + } else { + /* Bridge already exists. */ + g_return_if_fail (ovs_bridge); + _expect_bridge_ports (params, ovs_bridge->name, ports); + _set_bridge_ports (params, nm_connection_get_interface_name (bridge), new_ports); + } + + json_array_append_new (new_ports, json_pack ("[s, s]", "named-uuid", "rowPort")); + _insert_port (params, port, new_interfaces); + } else { + /* Port already exists */ + g_return_if_fail (ovs_port); + _expect_port_interfaces (params, ovs_port->name, interfaces); + _set_port_interfaces (params, nm_connection_get_interface_name (port), new_interfaces); + } + + if (!has_interface) { + _insert_interface (params, interface); + json_array_append_new (new_interfaces, json_pack ("[s, s]", "named-uuid", "rowInterface")); + } + + json_decref (interfaces); + json_decref (ports); + json_decref (bridges); + + json_decref (new_interfaces); + json_decref (new_ports); + json_decref (new_bridges); +} + +/** + * _delete_interface: + * + * Removes an interface of @ifname name, collecting empty ports and bridge + * if last item is removed from them. + */ +static void +_delete_interface (NMOvsdb *self, json_t *params, const char *ifname) +{ + NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); + GHashTableIter iter; + char *bridge_uuid; + char *port_uuid; + char *interface_uuid; + OpenvswitchBridge *ovs_bridge; + OpenvswitchPort *ovs_port; + OpenvswitchInterface *ovs_interface; + int pi; + int ii; + json_t *bridges, *new_bridges; + json_t *ports, *new_ports; + json_t *interfaces, *new_interfaces; + gboolean bridges_changed; + gboolean ports_changed; + gboolean interfaces_changed; + + bridges = json_array (); + new_bridges = json_array (); + bridges_changed = FALSE; + + g_hash_table_iter_init (&iter, priv->bridges); + while (g_hash_table_iter_next (&iter, (gpointer) &bridge_uuid, (gpointer) &ovs_bridge)) { + json_array_append_new (bridges, json_pack ("[s,s]", "uuid", bridge_uuid)); + + ports = json_array (); + new_ports = json_array (); + ports_changed = FALSE; + + for (pi = 0; pi < ovs_bridge->ports->len; pi++) { + port_uuid = g_ptr_array_index (ovs_bridge->ports, pi); + ovs_port = g_hash_table_lookup (priv->ports, port_uuid); + + json_array_append_new (ports, json_pack ("[s,s]", "uuid", port_uuid)); + + interfaces = json_array (); + new_interfaces = json_array (); + interfaces_changed = FALSE; + + for (ii = 0; ii < ovs_port->interfaces->len; ii++) { + interface_uuid = g_ptr_array_index (ovs_port->interfaces, ii); + ovs_interface = g_hash_table_lookup (priv->interfaces, interface_uuid); + + json_array_append_new (interfaces, json_pack ("[s,s]", "uuid", interface_uuid)); + + if (strcmp (ovs_interface->name, ifname) == 0) { + /* skip the interface */ + interfaces_changed = TRUE; + continue; + } + + json_array_append_new (new_interfaces, json_pack ("[s,s]", "uuid", interface_uuid)); + } + + if (json_array_size (new_interfaces) == 0) { + ports_changed = TRUE; + } else { + if (interfaces_changed) { + _expect_port_interfaces (params, ovs_port->name, interfaces); + _set_port_interfaces (params, ovs_port->name, new_interfaces); + } + json_array_append_new (new_ports, json_pack ("[s,s]", "uuid", port_uuid)); + } + + json_decref (interfaces); + json_decref (new_interfaces); + } + + if (json_array_size (new_ports) == 0) { + bridges_changed = TRUE; + } else { + if (ports_changed) { + _expect_bridge_ports (params, ovs_bridge->name, ports); + _set_bridge_ports (params, ovs_bridge->name, new_ports); + } + json_array_append_new (new_bridges, json_pack ("[s,s]", "uuid", bridge_uuid)); + } + + json_decref (ports); + json_decref (new_ports); + } + + if (bridges_changed) { + _expect_ovs_bridges (params, priv->db_uuid, bridges); + _set_ovs_bridges (params, priv->db_uuid, new_bridges); + } +} + +/** + * ovsdb_next_command: + * + * Translates a higher level operation (add/remove bridge/port) to a RFC 7047 + * command serialized into JSON ands sends it over to the database. + + * Only called when no command is waiting for a response, since the serialized + * command might depend on result of a previous one (add and remove need to + * include an up to date bridge list in their transactions to rule out races). + */ +static void +ovsdb_next_command (NMOvsdb *self) +{ + NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); + OvsdbMethodCall *call = NULL; + char *cmd; + json_t *msg = NULL; + json_t *params; + + if (!priv->conn) + return; + if (!priv->calls->len) + return; + call = &g_array_index (priv->calls, OvsdbMethodCall, 0); + if (call->id != COMMAND_PENDING) + return; + call->id = priv->seq++; + + switch (call->command) { + case OVSDB_MONITOR: + msg = json_pack ("{s:i, s:s, s:[s, n, {" + " s:[{s:[s, s, s]}]," + " s:[{s:[s, s, s]}]," + " s:[{s:[s, s, s]}]," + " s:[{s:[]}]" + "}]}", + "id", call->id, + "method", "monitor", "params", "Open_vSwitch", + "Bridge", "columns", "name", "ports", "external_ids", + "Port", "columns", "name", "interfaces", "external_ids", + "Interface", "columns", "name", "type", "external_ids", + "Open_vSwitch", "columns"); + break; + case OVSDB_ADD_INTERFACE: + params = json_array (); + json_array_append_new (params, json_string ("Open_vSwitch")); + json_array_append_new (params, _inc_next_cfg (priv->db_uuid)); + + _add_interface (self, params, call->bridge, call->port, call->interface); + + msg = json_pack ("{s:i, s:s, s:o}", + "id", call->id, + "method", "transact", "params", params); + break; + case OVSDB_DEL_INTERFACE: + params = json_array (); + json_array_append_new (params, json_string ("Open_vSwitch")); + json_array_append_new (params, _inc_next_cfg (priv->db_uuid)); + + _delete_interface (self, params, call->ifname); + + msg = json_pack ("{s:i, s:s, s:o}", + "id", call->id, + "method", "transact", "params", params); + break; + } + + g_return_if_fail (msg); + _call_trace ("send", call, msg); + cmd = json_dumps (msg, 0); + + g_string_append (priv->output, cmd); + json_decref (msg); + free (cmd); + + ovsdb_write (self); +} + +/** + * _uuids_to_array: + * + * This tidies up the somewhat non-straightforward way ovsdb represents an array + * of UUID elements. The single element is a tuple (called in RFC7047), + * + * [ "uuid", "aa095ffb-e1f1-0fc4-8038-82c1ea7e4797" ] + * + * while the list of multiple UUIDs are turned into a set of such tuples ("atoms"): + * + * [ "set", [ [ "uuid", "aa095ffb-e1f1-0fc4-8038-82c1ea7e4797" ], + * [ "uuid", "185c93f6-0b39-424e-8587-77d074aa7ce0" ], ... ] ] + */ +static void +_uuids_to_array (GPtrArray *array, const json_t *items) +{ + const char *key; + json_t *value; + size_t index = 0; + json_t *set_value; + size_t set_index; + + while (index < json_array_size (items)) { + key = json_string_value (json_array_get (items, index)); + index++; + value = json_array_get (items, index); + index++; + + if (!value) + return; + + if (g_strcmp0 (key, "uuid") == 0 && json_is_string (value)) { + g_ptr_array_add (array, g_strdup (json_string_value (value))); + } else if (g_strcmp0 (key, "set") == 0 && json_is_array (value)) { + json_array_foreach (value, set_index, set_value) { + _uuids_to_array (array, set_value); + } + } + } +} + +static char * +_connection_uuid_from_external_ids (json_t *external_ids) +{ + json_t *value; + size_t index; + + if (g_strcmp0 ("map", json_string_value (json_array_get (external_ids, 0))) != 0) + return NULL; + + json_array_foreach (json_array_get (external_ids, 1), index, value) { + if (g_strcmp0 ("NM.connection.uuid", json_string_value (json_array_get (value, 0))) == 0) + return g_strdup (json_string_value (json_array_get (value, 1))); + } + + return NULL; +} + +/** + * ovsdb_got_update: + * + * Called when we've got an "update" method call (we asked for it with the monitor + * command). We use it to maintain a consistent view of bridge list regardless of + * whether the changes are done by us or externally. + */ +static void +ovsdb_got_update (NMOvsdb *self, json_t *msg) +{ + NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); + json_t *ovs = NULL; + json_t *bridge = NULL; + json_t *port = NULL; + json_t *interface = NULL; + json_t *items; + json_t *external_ids; + json_error_t json_error = { 0, }; + void *iter; + const char *name; + const char *key; + const char *type; + json_t *value; + OpenvswitchBridge *ovs_bridge; + OpenvswitchPort *ovs_port; + OpenvswitchInterface *ovs_interface; + + if (json_unpack_ex (msg, &json_error, 0, "{s?:o, s?:o, s?:o, s?:o}", + "Open_vSwitch", &ovs, + "Bridge", &bridge, + "Port", &port, + "Interface", &interface) == -1) { + /* This doesn't really have to be an error; the key might + * be missing if there really are no bridges present. */ + _LOGD ("Bad update: %s", json_error.text); + } + + if (ovs) { + iter = json_object_iter (ovs); + priv->db_uuid = g_strdup (iter ? json_object_iter_key (iter) : NULL); + } + + /* Interfaces */ + json_object_foreach (interface, key, value) { + gboolean old = FALSE; + gboolean new = FALSE; + + if (json_unpack (value, "{s:{}}", "old") == 0) + old = TRUE; + + if (json_unpack (value, "{s:{s:s, s:s, s:o}}", "new", + "name", &name, + "type", &type, + "external_ids", &external_ids) == 0) + new = TRUE; + + if (old) { + ovs_interface = g_hash_table_lookup (priv->interfaces, key); + if (!new || g_strcmp0 (ovs_interface->name, name) != 0) { + old = FALSE; + _LOGT ("removed an '%s' interface: %s%s%s", + ovs_interface->type, ovs_interface->name, + ovs_interface->connection_uuid ? ", " : "", + ovs_interface->connection_uuid ? ovs_interface->connection_uuid : ""); + if (g_strcmp0 (ovs_interface->type, "internal") == 0) { + /* Currently the factory only creates NMDevices for + * internal interfaces. Ignore the rest. */ + g_signal_emit (self, signals[DEVICE_REMOVED], 0, + ovs_interface->name, NM_DEVICE_TYPE_OVS_INTERFACE); + } + } + g_hash_table_remove (priv->interfaces, key); + } + + if (new) { + ovs_interface = g_slice_new (OpenvswitchInterface); + ovs_interface->name = g_strdup (name); + ovs_interface->type = g_strdup (type); + ovs_interface->connection_uuid = _connection_uuid_from_external_ids (external_ids); + if (old) { + _LOGT ("changed an '%s' interface: %s%s%s", type, ovs_interface->name, + ovs_interface->connection_uuid ? ", " : "", + ovs_interface->connection_uuid ? ovs_interface->connection_uuid : ""); + g_signal_emit (self, signals[DEVICE_CHANGED], 0, + "ovs-interface", ovs_interface->name); + } else { + _LOGT ("added an '%s' interface: %s%s%s", + ovs_interface->type, ovs_interface->name, + ovs_interface->connection_uuid ? ", " : "", + ovs_interface->connection_uuid ? ovs_interface->connection_uuid : ""); + if (g_strcmp0 (ovs_interface->type, "internal") == 0) { + /* Currently the factory only creates NMDevices for + * internal interfaces. Ignore the rest. */ + g_signal_emit (self, signals[DEVICE_ADDED], 0, + ovs_interface->name, NM_DEVICE_TYPE_OVS_INTERFACE); + } + } + g_hash_table_insert (priv->interfaces, g_strdup (key), ovs_interface); + } + } + + /* Ports */ + json_object_foreach (port, key, value) { + gboolean old = FALSE; + gboolean new = FALSE; + + if (json_unpack (value, "{s:{}}", "old") == 0) + old = TRUE; + + if (json_unpack (value, "{s:{s:s, s:o, s:o}}", "new", + "name", &name, + "external_ids", &external_ids, + "interfaces", &items) == 0) + new = TRUE; + + if (old) { + ovs_port = g_hash_table_lookup (priv->ports, key); + if (!new || g_strcmp0 (ovs_port->name, name) != 0) { + old = FALSE; + _LOGT ("removed a port: %s%s%s", ovs_port->name, + ovs_port->connection_uuid ? ", " : "", + ovs_port->connection_uuid ? ovs_port->connection_uuid : ""); + g_signal_emit (self, signals[DEVICE_REMOVED], 0, + ovs_port->name, NM_DEVICE_TYPE_OVS_PORT); + } + g_hash_table_remove (priv->ports, key); + } + + if (new) { + ovs_port = g_slice_new (OpenvswitchPort); + ovs_port->name = g_strdup (name); + ovs_port->connection_uuid = _connection_uuid_from_external_ids (external_ids); + ovs_port->interfaces = g_ptr_array_new_with_free_func (g_free); + _uuids_to_array (ovs_port->interfaces, items); + if (old) { + _LOGT ("changed a port: %s%s%s", ovs_port->name, + ovs_port->connection_uuid ? ", " : "", + ovs_port->connection_uuid ? ovs_port->connection_uuid : ""); + g_signal_emit (self, signals[DEVICE_CHANGED], 0, + NM_SETTING_OVS_PORT_SETTING_NAME, ovs_port->name); + } else { + _LOGT ("added a port: %s%s%s", ovs_port->name, + ovs_port->connection_uuid ? ", " : "", + ovs_port->connection_uuid ? ovs_port->connection_uuid : ""); + g_signal_emit (self, signals[DEVICE_ADDED], 0, + ovs_port->name, NM_DEVICE_TYPE_OVS_PORT); + } + g_hash_table_insert (priv->ports, g_strdup (key), ovs_port); + } + } + + /* Bridges */ + json_object_foreach (bridge, key, value) { + gboolean old = FALSE; + gboolean new = FALSE; + + if (json_unpack (value, "{s:{}}", "old") == 0) + old = TRUE; + + if (json_unpack (value, "{s:{s:s, s:o, s:o}}", "new", + "name", &name, + "external_ids", &external_ids, + "ports", &items) == 0) + new = TRUE; + + if (old) { + ovs_bridge = g_hash_table_lookup (priv->bridges, key); + if (!new || g_strcmp0 (ovs_bridge->name, name) != 0) { + old = FALSE; + _LOGT ("removed a bridge: %s%s%s", ovs_bridge->name, + ovs_bridge->connection_uuid ? ", " : "", + ovs_bridge->connection_uuid ? ovs_bridge->connection_uuid : ""); + g_signal_emit (self, signals[DEVICE_REMOVED], 0, + ovs_bridge->name, NM_DEVICE_TYPE_OVS_BRIDGE); + } + g_hash_table_remove (priv->bridges, key); + } + + if (new) { + ovs_bridge = g_slice_new (OpenvswitchBridge); + ovs_bridge->name = g_strdup (name); + ovs_bridge->connection_uuid = _connection_uuid_from_external_ids (external_ids); + ovs_bridge->ports = g_ptr_array_new_with_free_func (g_free); + _uuids_to_array (ovs_bridge->ports, items); + if (old) { + _LOGT ("changed a bridge: %s%s%s", ovs_bridge->name, + ovs_bridge->connection_uuid ? ", " : "", + ovs_bridge->connection_uuid ? ovs_bridge->connection_uuid : ""); + g_signal_emit (self, signals[DEVICE_CHANGED], 0, + NM_SETTING_OVS_BRIDGE_SETTING_NAME, ovs_bridge->name); + } else { + _LOGT ("added a bridge: %s%s%s", ovs_bridge->name, + ovs_bridge->connection_uuid ? ", " : "", + ovs_bridge->connection_uuid ? ovs_bridge->connection_uuid : ""); + g_signal_emit (self, signals[DEVICE_ADDED], 0, + ovs_bridge->name, NM_DEVICE_TYPE_OVS_BRIDGE); + } + g_hash_table_insert (priv->bridges, g_strdup (key), ovs_bridge); + } + } + +} + +/** + * ovsdb_got_echo: + * + * Only implemented because the specification mandates it. Actual ovsdb hasn't been + * seen doing this. + */ +static void +ovsdb_got_echo (NMOvsdb *self, json_int_t id, json_t *data) +{ + NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); + json_t *msg; + char *reply; + gboolean output_was_empty; + + output_was_empty = priv->output->len == 0; + + msg = json_pack ("{s:I, s:O}", "id", id, "result", data); + reply = json_dumps (msg, 0); + g_string_append (priv->output, reply); + json_decref (msg); + free (reply); + + if (output_was_empty) + ovsdb_write (self); +} + +/** + * ovsdb_got_msg:: + * + * Called when when a complete JSON object was seen and unmarshalled. + * Either finishes a method call or processes a method call. + */ +static void +ovsdb_got_msg (NMOvsdb *self, json_t *msg) +{ + NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); + json_error_t json_error = { 0, }; + json_t *json_id = NULL; + gint64 id = -1; + const char *method = NULL; + json_t *params = NULL; + json_t *result = NULL; + json_t *error = NULL; + OvsdbMethodCall *call = NULL; + OvsdbMethodCallback callback; + gpointer user_data; + GError *local = NULL; + + if (json_unpack_ex (msg, &json_error, 0, "{s?:o, s?:s, s?:o, s?:o, s?:o}", + "id", &json_id, + "method", &method, + "params", ¶ms, + "result", &result, + "error", &error) == -1) { + _LOGW ("couldn't grok the message: %s", json_error.text); + ovsdb_disconnect (self); + return; + } + + if (json_is_number (json_id)) + id = json_integer_value (json_id); + + if (method) { + /* It's a method call! */ + if (!params) { + _LOGW ("a method call with no params: '%s'", method); + ovsdb_disconnect (self); + return; + } + + if (g_strcmp0 (method, "update") == 0) { + /* This is a update method call. */ + ovsdb_got_update (self, json_array_get (params, 1)); + } else if (g_strcmp0 (method, "echo") == 0) { + /* This is an echo request. */ + ovsdb_got_echo (self, id, params); + } else { + _LOGW ("got an unknown method call: '%s'", method); + } + return; + } + + if (id > -1) { + /* This is a response to a method call. */ + if (!priv->calls->len) { + _LOGE ("there are no queued calls expecting response %ld", id); + ovsdb_disconnect (self); + return; + } + call = &g_array_index (priv->calls, OvsdbMethodCall, 0); + if (call->id != id) { + _LOGE ("expected a response to call %ld, not %ld", call->id, id); + ovsdb_disconnect (self); + return; + } + /* Cool, we found a corresponsing call. Finish it. */ + + _call_trace ("response", call, msg); + + if (!json_is_null (error)) { + /* The response contains an error. */ + g_set_error (&local, G_IO_ERROR, G_IO_ERROR_FAILED, + "Error call to OVSDB returned an error: %s", + json_string_value (error)); + } + + callback = call->callback; + user_data = call->user_data; + g_array_remove_index (priv->calls, 0); + callback (self, result, local, user_data); + + /* Don't progress further commands in case the callback hit an error + * and disconnected us. */ + if (!priv->conn) + return; + + /* Now we're free to serialize and send the next command, if any. */ + ovsdb_next_command (self); + + return; + } + + + /* This is a message we are not interested in. */ + _LOGW ("got an unknown message, ignoring"); +} + +/*****************************************************************************/ + +/* Lower level marshalling and demarshalling of the JSON-RPC traffic on the + * ovsdb socket. */ + +static size_t +_json_callback (void *buffer, size_t buflen, void *user_data) +{ + NMOvsdb *self = NM_OVSDB (user_data); + NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); + + if (priv->bufp == priv->input->len) { + /* No more bytes buffered for decoding. */ + return 0; + } + + /* Pass one more byte to the JSON decoder. */ + *(char *)buffer = priv->input->str[priv->bufp]; + priv->bufp++; + + return (size_t)1; +} + +/** + * ovsdb_read_cb: + * + * Read out the data available from the ovsdb socket and try to deserialize + * the JSON. If we see a complete object, pass it upwards to ovsdb_got_msg(). + */ +static void +ovsdb_read_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + NMOvsdb *self = NM_OVSDB (user_data); + NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); + GInputStream *stream = G_INPUT_STREAM (source_object); + GError *error = NULL; + gssize size; + json_t *msg; + json_error_t json_error = { 0, }; + + size = g_input_stream_read_finish (stream, res, &error); + if (size == -1) { + _LOGW ("short read from ovsdb: %s", error->message); + g_clear_error (&error); + ovsdb_disconnect (self); + return; + } + + g_string_append_len (priv->input, priv->buf, size); + do { + priv->bufp = 0; + /* The callback always eats up only up to a single byte. This makes + * it possible for us to identify complete JSON objects in spite of + * us not knowing the length in advance. */ + msg = json_load_callback (_json_callback, self, JSON_DISABLE_EOF_CHECK, &json_error); + if (msg) { + ovsdb_got_msg (self, msg); + g_string_erase (priv->input, 0, priv->bufp); + } + json_decref (msg); + } while (msg); + + if (!priv->conn) + return; + + if (size) + ovsdb_read (self); +} + +static void +ovsdb_read (NMOvsdb *self) +{ + NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); + + g_input_stream_read_async (g_io_stream_get_input_stream (G_IO_STREAM (priv->conn)), + priv->buf, sizeof(priv->buf), + G_PRIORITY_DEFAULT, NULL, ovsdb_read_cb, self); +} + +static void +ovsdb_write_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GOutputStream *stream = G_OUTPUT_STREAM (source_object); + NMOvsdb *self = NM_OVSDB (user_data); + NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); + GError *error = NULL; + gssize size; + + size = g_output_stream_write_finish (stream, res, &error); + if (size == -1) { + _LOGW ("short write to ovsdb: %s", error->message); + g_clear_error (&error); + ovsdb_disconnect (self); + return; + } + + if (!priv->conn) + return; + + g_string_erase (priv->output, 0, size); + + ovsdb_write (self); +} + +static void +ovsdb_write (NMOvsdb *self) +{ + NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); + GOutputStream *stream; + + if (!priv->output->len) + return; + + stream = g_io_stream_get_output_stream (G_IO_STREAM (priv->conn)); + if (g_output_stream_has_pending (stream)) + return; + + g_output_stream_write_async (stream, + priv->output->str, priv->output->len, + G_PRIORITY_DEFAULT, NULL, ovsdb_write_cb, self); +} + +/*****************************************************************************/ + +/* Routines to maintain the ovsdb connection. */ + +/** + * ovsdb_disconnect: + * + * Clean up the internal state to the point equivalent to before connecting. + * Apart from clean shutdown this is a good response to unexpected trouble, + * since the next method call attempt a will trigger reconnect which hopefully + * puts us back in sync. + */ +static void +ovsdb_disconnect (NMOvsdb *self) +{ + NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); + OvsdbMethodCall *call; + OvsdbMethodCallback callback; + gpointer user_data; + GError *error; + + _LOGD ("disconnecting from ovsdb"); + + while (priv->calls->len) { + error = NULL; + call = &g_array_index (priv->calls, OvsdbMethodCall, priv->calls->len - 1); + g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled"); + + callback = call->callback; + user_data = call->user_data; + g_array_remove_index (priv->calls, priv->calls->len - 1); + callback (self, NULL, error, user_data); + } + + priv->bufp = 0; + g_string_truncate (priv->input, 0); + g_string_truncate (priv->output, 0); + g_clear_object (&priv->client); + g_clear_object (&priv->conn); + g_clear_pointer (&priv->db_uuid, g_free); +} + +static void +_monitor_bridges_cb (NMOvsdb *self, json_t *result, GError *error, gpointer user_data) +{ + if (error) { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + _LOGI ("%s", error->message); + ovsdb_disconnect (self); + } + + g_clear_error (&error); + return; + } + + /* Treat the first response the same as the subsequent "update" + * messages we eventually get. */ + ovsdb_got_update (self, result); +} + +static void +_client_connect_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GSocketClient *client = G_SOCKET_CLIENT (source_object); + NMOvsdb *self = NM_OVSDB (user_data); + NMOvsdbPrivate *priv; + GError *error = NULL; + GSocketConnection *conn; + + conn = g_socket_client_connect_finish (client, res, &error); + if (conn == NULL) { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + _LOGI ("%s", error->message); + + ovsdb_disconnect (self); + g_clear_error (&error); + return; + } + + priv = NM_OVSDB_GET_PRIVATE (self); + priv->conn = conn; + g_clear_object (&priv->cancellable); + + ovsdb_read (self); + ovsdb_next_command (self); +} + +/** + * ovsdb_try_connect: + * + * Establish a connection to ovsdb unless it's already established or being + * established. Queues a monitor command as a very first one so that we're in + * sync when other commands are issued. + */ +static void +ovsdb_try_connect (NMOvsdb *self) +{ + NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); + GSocketAddress *addr; + + if (priv->client) + return; + + /* XXX: This should probably be made configurable via NetworkManager.conf */ + addr = g_unix_socket_address_new (RUNSTATEDIR "/openvswitch/db.sock"); + + priv->client = g_socket_client_new (); + priv->cancellable = g_cancellable_new (); + g_socket_client_connect_async (priv->client, G_SOCKET_CONNECTABLE (addr), + priv->cancellable, _client_connect_cb, self); + g_object_unref (addr); + + /* Queue a monitor call before any other command, ensuring that we have an up + * to date view of existing bridged that we need for add and remove ops. */ + ovsdb_call_method (self, OVSDB_MONITOR, NULL, + NULL, NULL, NULL, _monitor_bridges_cb, NULL); +} + +/*****************************************************************************/ + +/* Public functions useful for NMDeviceOpenvswitch to maintain the life cycle of + * their ovsdb entries without having to deal with ovsdb complexities themselves. */ + +typedef struct { + NMOvsdbCallback callback; + gpointer user_data; +} OvsdbCall; + +static void +_transact_cb (NMOvsdb *self, json_t *result, GError *error, gpointer user_data) +{ + OvsdbCall *call = user_data; + const char *err; + const char *err_details; + size_t index; + json_t *value; + + if (error) + goto out; + + json_array_foreach (result, index, value) { + if (json_unpack (value, "{s:s, s:s}", "error", &err, "details", &err_details) == 0) { + g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Error running the transaction: %s: %s", err, err_details); + goto out; + } + } + +out: + call->callback (error, call->user_data); + g_slice_free (OvsdbCall, call); +} + +void +nm_ovsdb_add_interface (NMOvsdb *self, + NMConnection *bridge, NMConnection *port, NMConnection *interface, + NMOvsdbCallback callback, gpointer user_data) +{ + OvsdbCall *call; + + call = g_slice_new (OvsdbCall); + call->callback = callback; + call->user_data = user_data; + + ovsdb_call_method (self, OVSDB_ADD_INTERFACE, NULL, + bridge, port, interface, _transact_cb, call); +} + +void +nm_ovsdb_del_interface (NMOvsdb *self, const char *ifname, + NMOvsdbCallback callback, gpointer user_data) +{ + OvsdbCall *call; + + call = g_slice_new (OvsdbCall); + call->callback = callback; + call->user_data = user_data; + + ovsdb_call_method (self, OVSDB_DEL_INTERFACE, ifname, + NULL, NULL, NULL, _transact_cb, call); +} + +/*****************************************************************************/ + +static void +_clear_call (gpointer data) +{ + OvsdbMethodCall *call = data; + + switch (call->command) { + case OVSDB_MONITOR: + break; + case OVSDB_ADD_INTERFACE: + g_clear_object (&call->bridge); + g_clear_object (&call->port); + g_clear_object (&call->interface); + break; + case OVSDB_DEL_INTERFACE: + g_clear_pointer (&call->ifname, g_free); + break; + } +} + +static void +_free_bridge (gpointer data) +{ + OpenvswitchBridge *ovs_bridge = data; + + g_free (ovs_bridge->name); + g_free (ovs_bridge->connection_uuid); + g_ptr_array_free (ovs_bridge->ports, TRUE); + g_slice_free (OpenvswitchBridge, ovs_bridge); +} + +static void +_free_port (gpointer data) +{ + OpenvswitchPort *ovs_port = data; + + g_free (ovs_port->name); + g_free (ovs_port->connection_uuid); + g_ptr_array_free (ovs_port->interfaces, TRUE); + g_slice_free (OpenvswitchPort, ovs_port); +} + +static void +_free_interface (gpointer data) +{ + OpenvswitchInterface *ovs_interface = data; + + g_free (ovs_interface->name); + g_free (ovs_interface->connection_uuid); + g_free (ovs_interface->type); + g_slice_free (OpenvswitchInterface, ovs_interface); +} + +static void +nm_ovsdb_init (NMOvsdb *self) +{ + NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); + + priv->calls = g_array_new (FALSE, TRUE, sizeof (OvsdbMethodCall)); + g_array_set_clear_func (priv->calls, _clear_call); + priv->input = g_string_new (NULL); + priv->output = g_string_new (NULL); + priv->bridges = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, _free_bridge); + priv->ports = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, _free_port); + priv->interfaces = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, _free_interface); + + ovsdb_try_connect (self); +} + +static void +dispose (GObject *object) +{ + NMOvsdb *self = NM_OVSDB (object); + NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); + + ovsdb_disconnect (self); + + g_string_free (priv->input, TRUE); + priv->input = NULL; + g_string_free (priv->output, TRUE); + priv->output = NULL; + + if (priv->calls) { + g_array_free (priv->calls, TRUE); + priv->calls = NULL; + } + + g_clear_pointer (&priv->bridges, g_hash_table_destroy); + g_clear_pointer (&priv->ports, g_hash_table_destroy); + g_clear_pointer (&priv->interfaces, g_hash_table_destroy); + + g_cancellable_cancel (priv->cancellable); + g_clear_object (&priv->cancellable); + + G_OBJECT_CLASS (nm_ovsdb_parent_class)->dispose (object); +} + +static void +nm_ovsdb_class_init (NMOvsdbClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = dispose; + + signals[DEVICE_ADDED] = + g_signal_new (NM_OVSDB_DEVICE_ADDED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT); + + signals[DEVICE_REMOVED] = + g_signal_new (NM_OVSDB_DEVICE_REMOVED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT); + + signals[DEVICE_CHANGED] = + g_signal_new (NM_OVSDB_DEVICE_CHANGED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT); +} diff --git a/src/devices/ovs/nm-ovsdb.h b/src/devices/ovs/nm-ovsdb.h new file mode 100644 index 0000000000..cf9fe2a21b --- /dev/null +++ b/src/devices/ovs/nm-ovsdb.h @@ -0,0 +1,50 @@ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2017 Red Hat, Inc. + */ + +#ifndef __NETWORKMANAGER_OVSDB_H__ +#define __NETWORKMANAGER_OVSDB_H__ + +#define NM_TYPE_OVSDB (nm_ovsdb_get_type ()) +#define NM_OVSDB(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_OVSDB, NMOvsdb)) +#define NM_OVSDB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_OVSDB, NMOvsdbClass)) +#define NM_IS_OVSDB(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_OVSDB)) +#define NM_IS_OVSDB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_OVSDB)) +#define NM_OVSDB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_OVSDB, NMOvsdbClass)) + +#define NM_OVSDB_DEVICE_ADDED "device-added" +#define NM_OVSDB_DEVICE_REMOVED "device-removed" +#define NM_OVSDB_DEVICE_CHANGED "device-changed" + +typedef struct _NMOvsdb NMOvsdb; +typedef struct _NMOvsdbClass NMOvsdbClass; + +typedef void (*NMOvsdbCallback) (GError *error, gpointer user_data); + +NMOvsdb *nm_ovsdb_get (void); + +GType nm_ovsdb_get_type (void); + +void nm_ovsdb_add_interface (NMOvsdb *self, + NMConnection *bridge, NMConnection *port, NMConnection *interface, + NMOvsdbCallback callback, gpointer user_data); + +void nm_ovsdb_del_interface (NMOvsdb *self, const char *ifname, + NMOvsdbCallback callback, gpointer user_data); + +#endif /* __NETWORKMANAGER_OVSDB_H__ */ From 1f25ae08fbe43abff69328bd790c02f9916474ea Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 16 Oct 2017 22:53:54 +0200 Subject: [PATCH 31/36] core/connection: allow address for ovs interfaces --- libnm-core/nm-connection.c | 85 ++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index d76009cd37..32fa9fd78a 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -812,10 +812,21 @@ _normalize_ethernet_link_neg (NMConnection *self) return FALSE; } +static gboolean +_without_ip_config (NMConnection *self) +{ + const char *connection_type = nm_connection_get_connection_type (self); + + g_return_val_if_fail (connection_type, FALSE); + if (strcmp (connection_type, NM_SETTING_OVS_INTERFACE_SETTING_NAME) == 0) + return FALSE; + + return !!nm_setting_connection_get_master (nm_connection_get_setting_connection (self)); +} + static gboolean _normalize_ip_config (NMConnection *self, GHashTable *parameters) { - NMSettingConnection *s_con = nm_connection_get_setting_connection (self); const char *default_ip4_method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; const char *default_ip6_method = NULL; NMSettingIPConfig *s_ip4, *s_ip6; @@ -833,7 +844,7 @@ _normalize_ip_config (NMConnection *self, GHashTable *parameters) s_ip6 = nm_connection_get_setting_ip6_config (self); s_proxy = nm_connection_get_setting_proxy (self); - if (nm_setting_connection_get_master (s_con)) { + if (_without_ip_config (self)) { /* Slave connections don't have IP configuration. */ if (s_ip4) @@ -1289,40 +1300,42 @@ _nm_connection_verify (NMConnection *connection, GError **error) s_ip6 = nm_connection_get_setting_ip6_config (connection); s_proxy = nm_connection_get_setting_proxy (connection); - if (nm_setting_connection_get_master (s_con)) { - if ( NM_IN_SET (normalizable_error_type, NM_SETTING_VERIFY_SUCCESS, - NM_SETTING_VERIFY_NORMALIZABLE) - && (s_ip4 || s_ip6 || s_proxy)) { - g_clear_error (&normalizable_error); - g_set_error_literal (&normalizable_error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_SETTING, - _("setting not allowed in slave connection")); - g_prefix_error (&normalizable_error, "%s: ", - s_ip4 - ? NM_SETTING_IP4_CONFIG_SETTING_NAME - : (s_ip6 - ? NM_SETTING_IP6_CONFIG_SETTING_NAME - : NM_SETTING_PROXY_SETTING_NAME)); - /* having a slave with IP config *was* and is a verify() error. */ - normalizable_error_type = NM_SETTING_VERIFY_NORMALIZABLE_ERROR; - } - } else { - if ( NM_IN_SET (normalizable_error_type, NM_SETTING_VERIFY_SUCCESS) - && (!s_ip4 || !s_ip6 || !s_proxy)) { - g_set_error_literal (&normalizable_error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_MISSING_SETTING, - _("setting is required for non-slave connections")); - g_prefix_error (&normalizable_error, "%s: ", - !s_ip4 - ? NM_SETTING_IP4_CONFIG_SETTING_NAME - : (!s_ip6 - ? NM_SETTING_IP6_CONFIG_SETTING_NAME - : NM_SETTING_PROXY_SETTING_NAME)); - /* having a master without IP config was not a verify() error, accept - * it for backward compatibility. */ - normalizable_error_type = NM_SETTING_VERIFY_NORMALIZABLE; + nm_assert (normalizable_error_type != NM_SETTING_VERIFY_ERROR); + if (NM_IN_SET (normalizable_error_type, NM_SETTING_VERIFY_SUCCESS, + NM_SETTING_VERIFY_NORMALIZABLE)) { + if (_without_ip_config (connection)) { + if (s_ip4 || s_ip6 || s_proxy) { + g_clear_error (&normalizable_error); + g_set_error_literal (&normalizable_error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_SETTING, + _("setting not allowed in slave connection")); + g_prefix_error (&normalizable_error, "%s: ", + s_ip4 + ? NM_SETTING_IP4_CONFIG_SETTING_NAME + : (s_ip6 + ? NM_SETTING_IP6_CONFIG_SETTING_NAME + : NM_SETTING_PROXY_SETTING_NAME)); + /* having a slave with IP config *was* and is a verify() error. */ + normalizable_error_type = NM_SETTING_VERIFY_NORMALIZABLE_ERROR; + } + } else { + if ( normalizable_error_type == NM_SETTING_VERIFY_SUCCESS + && (!s_ip4 || !s_ip6 || !s_proxy)) { + g_set_error_literal (&normalizable_error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_SETTING, + _("setting is required for non-slave connections")); + g_prefix_error (&normalizable_error, "%s: ", + !s_ip4 + ? NM_SETTING_IP4_CONFIG_SETTING_NAME + : (!s_ip6 + ? NM_SETTING_IP6_CONFIG_SETTING_NAME + : NM_SETTING_PROXY_SETTING_NAME)); + /* having a master without IP config was not a verify() error, accept + * it for backward compatibility. */ + normalizable_error_type = NM_SETTING_VERIFY_NORMALIZABLE; + } } } From f2858220e3aa0182f73edee7dfebc4dc495f5920 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 27 Oct 2017 11:56:20 +0200 Subject: [PATCH 32/36] device: keep platform link alive in device_link_changed() For a while now, all NMPObject instances are not modified after being cached. They are immutable, and can be passed around by keeping a reference to them. No longer copy the NMPlatformLink data to a @info variable. Instead, take a reference (which ensures that the instance stays alive). It won't change, as it's immutable. The advantage is, that whenever you see a NMPlatformLink pointer, for exmple in device_recheck_slave_status(), you can be sure that it's actually a NMPObect, and NMP_OBJECT_UP_CAST() will work. --- src/devices/nm-device.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 04b522f8a9..c286d4668a 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -2666,7 +2666,7 @@ device_link_changed (NMDevice *self) NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); gboolean ip_ifname_changed = FALSE; - NMPlatformLink info; + nm_auto_nmpobj const NMPObject *pllink_keep_alive = NULL; const NMPlatformLink *pllink; int ifindex; gboolean was_up; @@ -2680,20 +2680,20 @@ device_link_changed (NMDevice *self) if (!pllink) return G_SOURCE_REMOVE; - nm_device_update_from_platform_link (self, pllink); + pllink_keep_alive = nmp_object_ref (NMP_OBJECT_UP_CAST (pllink)); - info = *pllink; + nm_device_update_from_platform_link (self, pllink); had_hw_addr = (priv->hw_addr != NULL); nm_device_update_hw_address (self); got_hw_addr = (!had_hw_addr && priv->hw_addr); nm_device_update_permanent_hw_address (self, FALSE); - if (info.name[0] && strcmp (priv->iface, info.name) != 0) { + if (pllink->name[0] && strcmp (priv->iface, pllink->name) != 0) { _LOGI (LOGD_DEVICE, "interface index %d renamed iface from '%s' to '%s'", - priv->ifindex, priv->iface, info.name); + priv->ifindex, priv->iface, pllink->name); g_free (priv->iface); - priv->iface = g_strdup (info.name); + priv->iface = g_strdup (pllink->name); /* If the device has no explicit ip_iface, then changing iface changes ip_iface too. */ ip_ifname_changed = !priv->ip_iface; @@ -2716,8 +2716,8 @@ device_link_changed (NMDevice *self) nm_device_emit_recheck_auto_activate (self); } - if (priv->ndisc && info.inet6_token.id) { - if (nm_ndisc_set_iid (priv->ndisc, info.inet6_token)) + if (priv->ndisc && pllink->inet6_token.id) { + if (nm_ndisc_set_iid (priv->ndisc, pllink->inet6_token)) _LOGD (LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface); } @@ -2726,16 +2726,16 @@ device_link_changed (NMDevice *self) && !nm_device_has_capability (self, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) nm_device_set_carrier (self, pllink->connected); - klass->link_changed (self, &info); + klass->link_changed (self, pllink); /* Update DHCP, etc, if needed */ if (ip_ifname_changed) nm_device_update_dynamic_ip_setup (self); was_up = priv->up; - priv->up = NM_FLAGS_HAS (info.n_ifi_flags, IFF_UP); + priv->up = NM_FLAGS_HAS (pllink->n_ifi_flags, IFF_UP); - if ( info.initialized + if ( pllink->initialized && nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)) { NMDeviceStateReason reason; @@ -2765,7 +2765,7 @@ device_link_changed (NMDevice *self) set_unmanaged_external_down (self, FALSE); - device_recheck_slave_status (self, &info); + device_recheck_slave_status (self, pllink); if (priv->up && !was_up) { /* the link was down and just came up. That happens for example, while changing MTU. From 7b36a6a890a83ddf585644ffada28f37b00e5c82 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 28 Oct 2017 17:46:26 +0200 Subject: [PATCH 33/36] libnm: add nm_connection_get_settings() There is no API to get all settings. You can only ask for settings explicitly, but that requires you to probe for them and know which ones may exist. The alternative API might be nm_connection_for_each_setting_value(), but that only iterates over settings' properties. If a setting has no properties, it is ignored. --- libnm-core/nm-connection.c | 88 +++++++++++++++++++++++++------------- libnm-core/nm-connection.h | 4 ++ libnm/libnm.ver | 1 + 3 files changed, 64 insertions(+), 29 deletions(-) diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index 32fa9fd78a..720ba8468d 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -1797,6 +1797,60 @@ _for_each_sort (NMSetting **p_a, NMSetting **p_b, void *unused) return strcmp (nm_setting_get_name (a), nm_setting_get_name (b)); } +/** + * nm_connection_get_settings: + * @connection: the #NMConnection instance + * @out_length: (allow-none): (out): the length of the returned array + * + * Retrieves the settings in @connection. + * + * The returned array is %NULL-terminated. + * + * Returns: (array length=out_length) (transfer container): a + * %NULL-terminated array containing every setting of + * @connection. + * If the connection has no settings, %NULL is returned. + * + * Since: 1.10 + */ +NMSetting ** +nm_connection_get_settings (NMConnection *connection, + guint *out_length) +{ + NMConnectionPrivate *priv; + NMSetting **arr; + GHashTableIter iter; + NMSetting *setting; + guint i, size; + + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + + priv = NM_CONNECTION_GET_PRIVATE (connection); + + size = g_hash_table_size (priv->settings); + + if (!size) { + NM_SET_OUT (out_length, 0); + return NULL; + } + + arr = g_new (NMSetting *, size + 1); + + g_hash_table_iter_init (&iter, priv->settings); + for (i = 0; g_hash_table_iter_next (&iter, NULL, (gpointer *) &setting); i++) + arr[i] = setting; + nm_assert (i == size); + arr[size] = NULL; + + /* sort the settings. This has an effect on the order in which keyfile + * prints them. */ + if (size > 1) + g_qsort_with_data (arr, size, sizeof (NMSetting *), (GCompareDataFunc) _for_each_sort, NULL); + + NM_SET_OUT (out_length, size); + return arr; +} + /** * nm_connection_for_each_setting_value: * @connection: the #NMConnection @@ -1811,39 +1865,15 @@ nm_connection_for_each_setting_value (NMConnection *connection, NMSettingValueIterFn func, gpointer user_data) { - NMConnectionPrivate *priv; - gs_free NMSetting **arr_free = NULL; - NMSetting *arr_temp[20], **arr; - GHashTableIter iter; - gpointer value; - guint i, size; + gs_free NMSetting **settings = NULL; + guint i, length = 0; g_return_if_fail (NM_IS_CONNECTION (connection)); g_return_if_fail (func); - priv = NM_CONNECTION_GET_PRIVATE (connection); - - size = g_hash_table_size (priv->settings); - if (!size) - return; - - if (size > G_N_ELEMENTS (arr_temp)) - arr = arr_free = g_new (NMSetting *, size); - else - arr = arr_temp; - - g_hash_table_iter_init (&iter, priv->settings); - for (i = 0; g_hash_table_iter_next (&iter, NULL, &value); i++) - arr[i] = NM_SETTING (value); - g_assert (i == size); - - /* sort the settings. This has an effect on the order in which keyfile - * prints them. */ - if (size > 1) - g_qsort_with_data (arr, size, sizeof (NMSetting *), (GCompareDataFunc) _for_each_sort, NULL); - - for (i = 0; i < size; i++) - nm_setting_enumerate_values (arr[i], func, user_data); + settings = nm_connection_get_settings (connection, &length); + for (i = 0; i < length; i++) + nm_setting_enumerate_values (settings[i], func, user_data); } /** diff --git a/libnm-core/nm-connection.h b/libnm-core/nm-connection.h index 9419c6254e..c6b23a00bc 100644 --- a/libnm-core/nm-connection.h +++ b/libnm-core/nm-connection.h @@ -179,6 +179,10 @@ void nm_connection_for_each_setting_value (NMConnection *connection, NMSettingValueIterFn func, gpointer user_data); +NM_AVAILABLE_IN_1_10 +NMSetting ** nm_connection_get_settings (NMConnection *connection, + guint *out_length); + void nm_connection_dump (NMConnection *connection); /* Helpers */ diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 72690ff4f2..1b245b277b 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1185,6 +1185,7 @@ global: nm_client_connectivity_check_get_available; nm_client_connectivity_check_get_enabled; nm_client_connectivity_check_set_enabled; + nm_connection_get_settings; nm_device_dummy_get_hw_address; nm_device_ovs_bridge_get_type; nm_device_ovs_interface_get_type; From 93315d01da72c833338e9591d810b44c42da51ef Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 29 Oct 2017 16:03:53 +0100 Subject: [PATCH 34/36] tests: add nmtst_assert_connection_has_settings() helper --- shared/nm-utils/nm-test-utils.h | 57 +++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/shared/nm-utils/nm-test-utils.h b/shared/nm-utils/nm-test-utils.h index f7a87aae82..126546ec93 100644 --- a/shared/nm-utils/nm-test-utils.h +++ b/shared/nm-utils/nm-test-utils.h @@ -1697,6 +1697,63 @@ nmtst_assert_setting_verifies (NMSetting *setting) g_assert (success); } +#if defined(__NM_SIMPLE_CONNECTION_H__) +static inline void +_nmtst_assert_connection_has_settings (NMConnection *connection, gboolean has_at_least, gboolean has_at_most, ...) +{ + gs_unref_hashtable GHashTable *names = NULL; + gs_free NMSetting **settings = NULL; + va_list ap; + const char *name; + guint i, len; + gs_unref_ptrarray GPtrArray *names_arr = NULL; + + g_assert (NM_IS_CONNECTION (connection)); + + names = g_hash_table_new (g_str_hash, g_str_equal); + names_arr = g_ptr_array_new (); + + va_start (ap, has_at_most); + while ((name = va_arg (ap, const char *))) { + if (!nm_g_hash_table_add (names, (gpointer) name)) + g_assert_not_reached (); + g_ptr_array_add (names_arr, (gpointer) name); + } + va_end (ap); + + g_ptr_array_add (names_arr, NULL); + + settings = nm_connection_get_settings (connection, &len); + for (i = 0; i < len; i++) { + if ( !g_hash_table_remove (names, nm_setting_get_name (settings[i])) + && has_at_most) { + g_error ("nmtst_assert_connection_has_settings(): has setting \"%s\" which is not expected", + nm_setting_get_name (settings[i])); + } + } + if ( g_hash_table_size (names) > 0 + && has_at_least) { + gs_free char *expected_str = g_strjoinv (" ", (char **) names_arr->pdata); + gs_free const char **settings_names = NULL; + gs_free char *has_str = NULL; + + settings_names = g_new0 (const char *, len + 1); + for (i = 0; i < len; i++) + settings_names[i] = nm_setting_get_name (settings[i]); + has_str = g_strjoinv (" ", (char **) settings_names); + + g_error ("nmtst_assert_connection_has_settings(): the setting lacks %u expected settings (expected: [%s] vs. has: [%s])", + g_hash_table_size (names), + expected_str, + has_str); + } +} +#define nmtst_assert_connection_has_settings(connection, ...) _nmtst_assert_connection_has_settings ((connection), TRUE, TRUE, __VA_ARGS__, NULL) +#define nmtst_assert_connection_has_settings_at_least(connection, ...) _nmtst_assert_connection_has_settings ((connection), TRUE, FALSE, __VA_ARGS__, NULL) +#define nmtst_assert_connection_has_settings_at_most(connection, ...) _nmtst_assert_connection_has_settings ((connection), FALSE, TRUE, __VA_ARGS__, NULL) + +#endif /* __NM_SIMPLE_CONNECTION_H__ */ + static inline void nmtst_assert_setting_verify_fails (NMSetting *setting, GQuark expect_error_domain, From 4199c976dac21c22773e0c133c42c3b738ca76d2 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 27 Oct 2017 14:30:18 +0200 Subject: [PATCH 35/36] libnm: fix normalizing and verifying OVS connections Normalizing can be complicated, as settings depend on each other and possibly conflict. That is, because verify() must exactly anticipate whether normalization will succeed and how the result will look like. That is because we only want to modify the connection, if we are sure that the result will verify. Hence, verify() and normalize() are strongly related. The implementation should not be spread out between NMSettingOvsInterface:verify(), NMSettingOvsPatch:verify() and _normalize_ovs_interface_type(). Also, add some unit-tests. --- libnm-core/nm-connection-private.h | 6 + libnm-core/nm-connection.c | 35 +-- libnm-core/nm-setting-connection.c | 32 ++- libnm-core/nm-setting-ovs-interface.c | 198 ++++++++++++-- libnm-core/nm-setting-ovs-patch.c | 31 --- libnm-core/nm-setting.c | 2 +- libnm-core/tests/test-general.c | 357 ++++++++++++++++++++++++++ 7 files changed, 568 insertions(+), 93 deletions(-) diff --git a/libnm-core/nm-connection-private.h b/libnm-core/nm-connection-private.h index 7dd088ace0..ee2d7264b9 100644 --- a/libnm-core/nm-connection-private.h +++ b/libnm-core/nm-connection-private.h @@ -34,4 +34,10 @@ const char *_nm_connection_detect_bluetooth_type (NMConnection *self); gboolean _nm_connection_verify_required_interface_name (NMConnection *connection, GError **error); +int _nm_setting_ovs_interface_verify_interface_type (NMSettingOvsInterface *self, + NMConnection *connection, + gboolean normalize, + gboolean *out_modified, + GError **error); + #endif /* __NM_CONNECTION_PRIVATE_H__ */ diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index 720ba8468d..d5e28f7b3e 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -1114,33 +1114,21 @@ static gboolean _normalize_ovs_interface_type (NMConnection *self, GHashTable *parameters) { NMSettingOvsInterface *s_ovs_interface = nm_connection_get_setting_ovs_interface (self); - NMSettingConnection *s_con = nm_connection_get_setting_connection (self); - const char *interface_type; + gboolean modified; + int v; - if (strcmp (nm_connection_get_connection_type (self), NM_SETTING_OVS_INTERFACE_SETTING_NAME) == 0) { - /* OpenVSwitch managed interface. */ - if (nm_connection_get_setting_ovs_patch (self)) - interface_type = "patch"; - else - interface_type = "internal"; - } else if (g_strcmp0 (nm_setting_connection_get_slave_type (s_con), NM_SETTING_OVS_PORT_SETTING_NAME) == 0) { - /* A regular device enslaved to a port. */ - interface_type = ""; - } else { - /* Something else. */ + if (!s_ovs_interface) return FALSE; - } - if (!s_ovs_interface) { - s_ovs_interface = NM_SETTING_OVS_INTERFACE (nm_setting_ovs_interface_new ()); - nm_connection_add_setting (self, NM_SETTING (s_ovs_interface)); - } + v = _nm_setting_ovs_interface_verify_interface_type (s_ovs_interface, + self, + TRUE, + &modified, + NULL); + if (v != TRUE) + g_return_val_if_reached (modified); - g_object_set (s_ovs_interface, - NM_SETTING_OVS_INTERFACE_TYPE, interface_type, - NULL); - - return TRUE; + return modified; } static gboolean @@ -1465,6 +1453,7 @@ nm_connection_normalize (NMConnection *connection, NM_CONNECTION_ERROR_FAILED, _("Unexpected failure to normalize the connection")); } + g_warning ("connection did not verify after normalization: %s", error ? (*error)->message : "??"); g_return_val_if_reached (FALSE); } diff --git a/libnm-core/nm-setting-connection.c b/libnm-core/nm-setting-connection.c index 4b2c5d501b..28d7a8f6b7 100644 --- a/libnm-core/nm-setting-connection.c +++ b/libnm-core/nm-setting-connection.c @@ -859,6 +859,8 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) gboolean is_slave; const char *slave_setting_type; NMSetting *normerr_base_type = NULL; + const char *type; + const char *slave_type; const char *normerr_slave_setting_type = NULL; const char *normerr_missing_slave_type = NULL; const char *normerr_missing_slave_type_port = NULL; @@ -904,8 +906,10 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) } } - if (!priv->type) { - if (!connection || !(normerr_base_type = _nm_connection_find_base_type_setting (connection))) { + type = priv->type; + if (!type) { + if ( !connection + || !(normerr_base_type = _nm_connection_find_base_type_setting (connection))) { g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_PROPERTY, @@ -913,10 +917,11 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_TYPE); return FALSE; } + type = nm_setting_get_name (normerr_base_type); } else { GType base_type; - if (!priv->type[0]) { + if (!type[0]) { g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, @@ -925,21 +930,21 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } - base_type = nm_setting_lookup_type (priv->type); + base_type = nm_setting_lookup_type (type); if ( base_type == G_TYPE_INVALID || _nm_setting_type_get_base_type_priority (base_type) == NM_SETTING_PRIORITY_INVALID) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("connection type '%s' is not valid"), - priv->type); + type); g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_TYPE); return FALSE; } /* Make sure the corresponding 'type' item is present */ if ( connection - && !nm_connection_get_setting_by_name (connection, priv->type)) { + && !nm_connection_get_setting_by_name (connection, type)) { NMSetting *s_base; NMConnection *connection2; @@ -952,7 +957,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) g_object_unref (connection2); if (!normerr_base_setting) { - _set_error_missing_base_setting (error, priv->type); + _set_error_missing_base_setting (error, type); return FALSE; } } @@ -960,13 +965,14 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) is_slave = FALSE; slave_setting_type = NULL; - if (priv->slave_type) { - is_slave = _nm_setting_slave_type_is_valid (priv->slave_type, &slave_setting_type); + slave_type = priv->slave_type; + if (slave_type) { + is_slave = _nm_setting_slave_type_is_valid (slave_type, &slave_setting_type); if (!is_slave) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("Unknown slave type '%s'"), priv->slave_type); + _("Unknown slave type '%s'"), slave_type); g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_SLAVE_TYPE); return FALSE; } @@ -986,8 +992,8 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) && !nm_connection_get_setting_by_name (connection, slave_setting_type)) normerr_slave_setting_type = slave_setting_type; } else { + nm_assert (!slave_type); if (priv->master) { - const char *slave_type; NMSetting *s_port; if ( connection @@ -1006,8 +1012,8 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) } } - if ( g_strcmp0 (priv->type, NM_SETTING_OVS_PORT_SETTING_NAME) != 0 - && g_strcmp0 (priv->slave_type, NM_SETTING_OVS_BRIDGE_SETTING_NAME) == 0) { + if ( nm_streq0 (type, NM_SETTING_OVS_PORT_SETTING_NAME) + && !nm_streq0 (slave_type, NM_SETTING_OVS_BRIDGE_SETTING_NAME)) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_PROPERTY, diff --git a/libnm-core/nm-setting-ovs-interface.c b/libnm-core/nm-setting-ovs-interface.c index 3b214af892..f06db32abb 100644 --- a/libnm-core/nm-setting-ovs-interface.c +++ b/libnm-core/nm-setting-ovs-interface.c @@ -78,6 +78,173 @@ nm_setting_ovs_interface_get_interface_type (NMSettingOvsInterface *self) /*****************************************************************************/ +int +_nm_setting_ovs_interface_verify_interface_type (NMSettingOvsInterface *self, + NMConnection *connection, + gboolean normalize, + gboolean *out_modified, + GError **error) +{ + gboolean has_patch; + const char *type; + const char *connection_type; + gboolean is_ovs_connection_type; + gboolean missing_patch_setting = FALSE; + + g_return_val_if_fail (NM_IS_SETTING_OVS_INTERFACE (self), FALSE); + if (normalize) { + g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); + nm_assert (self == nm_connection_get_setting_ovs_interface (connection)); + } else + g_return_val_if_fail (!connection || NM_IS_CONNECTION (connection), FALSE); + + NM_SET_OUT (out_modified, FALSE); + + type = self ? self->type : NULL; + + if ( type + && !NM_IN_STRSET (type, + "internal", + "system", + "patch")) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid interface type"), + type); + g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_INTERFACE_SETTING_NAME, NM_SETTING_OVS_INTERFACE_TYPE); + return FALSE; + } + + if (!connection) + return TRUE; + + connection_type = nm_connection_get_connection_type (connection); + if (!connection_type) { + /* if we have an ovs-interface, then the connection type must be either + * "ovs-interface" (for non "system" type) or anything else (for "system" type). + * + * The connection type usually can be normalized based on the presence of a + * base setting. However, in this case, if the connection type is missing, + * that is too complicate to guess what the user wanted. + * + * Require the use to be explicit and fail. */ + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("A connection with a '%s' setting needs connection.type explicitly set"), + NM_SETTING_OVS_INTERFACE_SETTING_NAME); + g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_TYPE); + return FALSE; + } + + if (nm_streq (connection_type, NM_SETTING_OVS_INTERFACE_SETTING_NAME)) { + if ( type + && nm_streq (type, "system")) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("A connection of type '%s' cannot have ovs-interface.type \"system\""), + NM_SETTING_OVS_INTERFACE_SETTING_NAME); + g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_INTERFACE_SETTING_NAME, NM_SETTING_OVS_INTERFACE_TYPE); + return FALSE; + } + is_ovs_connection_type = TRUE; + } else { + if ( type + && !nm_streq (type, "system")) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("A connection of type '%s' cannot have an ovs-interface.type \"%s\""), + connection_type, + type); + g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_INTERFACE_SETTING_NAME, NM_SETTING_OVS_INTERFACE_TYPE); + return FALSE; + } + is_ovs_connection_type = FALSE; + } + + has_patch = !!nm_connection_get_setting_by_name (connection, NM_SETTING_OVS_PATCH_SETTING_NAME); + + if (has_patch) { + if (!is_ovs_connection_type) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("A connection with '%s' setting must be of connection.type \"ovs-interface\" but is \"%s\""), + NM_SETTING_OVS_PATCH_SETTING_NAME, + connection_type); + g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_INTERFACE_SETTING_NAME, NM_SETTING_OVS_INTERFACE_TYPE); + return FALSE; + } + if (type) { + if (!nm_streq (type, "patch")) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("A connection with '%s' setting needs to be of 'patch' interface type, not '%s'"), + NM_SETTING_OVS_PATCH_SETTING_NAME, + type); + g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_INTERFACE_SETTING_NAME, NM_SETTING_OVS_INTERFACE_TYPE); + return FALSE; + } + return TRUE; + } + type = "patch"; + goto normalize; + } else { + if (nm_streq0 (type, "patch")) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_SETTING, + _("A connection with ovs-interface.type '%s' setting a 'ovs-patch' setting"), + type); + g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_INTERFACE_SETTING_NAME, NM_SETTING_OVS_INTERFACE_TYPE); + return FALSE; + } + } + + if (type) + return TRUE; + + if (is_ovs_connection_type) + type = "internal"; + else + type = "system"; +normalize: + if (!normalize) { + if (!self) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_SETTING, + _("Missing ovs interface setting")); + g_prefix_error (error, "%s: ", NM_SETTING_OVS_INTERFACE_SETTING_NAME); + } else { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("Missing ovs interface type")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_INTERFACE_SETTING_NAME, NM_SETTING_OVS_INTERFACE_TYPE); + } + if (missing_patch_setting) { + } + return NM_SETTING_VERIFY_NORMALIZABLE_ERROR; + } + + if (!self) { + self = NM_SETTING_OVS_INTERFACE (nm_setting_ovs_interface_new ()); + nm_connection_add_setting (connection, NM_SETTING (self)); + } + g_object_set (self, + NM_SETTING_OVS_INTERFACE_TYPE, type, + NULL); + NM_SET_OUT (out_modified, TRUE); + + return TRUE; +} + + static int verify (NMSetting *setting, NMConnection *connection, GError **error) { @@ -109,7 +276,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) slave_type = nm_setting_connection_get_slave_type (s_con); if ( slave_type - && strcmp (slave_type, NM_SETTING_OVS_PORT_SETTING_NAME)) { + && !nm_streq (slave_type, NM_SETTING_OVS_PORT_SETTING_NAME)) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, @@ -122,30 +289,11 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) } } - if (!NM_IN_STRSET (self->type, "internal", "system", "patch", "", NULL)) { - g_set_error (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("'%s' is not a valid interface type"), - self->type); - g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_INTERFACE_SETTING_NAME, NM_SETTING_OVS_INTERFACE_TYPE); - return FALSE; - } - - if (connection) { - if ( g_strcmp0 (self->type, "patch") == 0 - && !nm_connection_get_setting_ovs_patch (connection)) { - g_set_error (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("A connection of 'patch' interface type needs a '%s' setting."), - NM_SETTING_OVS_PATCH_SETTING_NAME); - g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_INTERFACE_SETTING_NAME, NM_SETTING_OVS_INTERFACE_TYPE); - return FALSE; - } - } - - return TRUE; + return _nm_setting_ovs_interface_verify_interface_type (self, + connection, + FALSE, + NULL, + error); } /*****************************************************************************/ diff --git a/libnm-core/nm-setting-ovs-patch.c b/libnm-core/nm-setting-ovs-patch.c index fb1412bf4a..9e38091474 100644 --- a/libnm-core/nm-setting-ovs-patch.c +++ b/libnm-core/nm-setting-ovs-patch.c @@ -115,37 +115,6 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } - - if (connection) { - NMSettingOvsInterface *s_ovs_interface; - const char *interface_type = NULL; - - s_ovs_interface = nm_connection_get_setting_ovs_interface (connection); - if (s_ovs_interface) - interface_type = nm_setting_ovs_interface_get_interface_type (s_ovs_interface); - - if (interface_type && strcmp (interface_type, "patch") != 0) { - g_set_error (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("A connection with '%s' setting needs to be of 'patch' interface type, not '%s'"), - NM_SETTING_OVS_PATCH_SETTING_NAME, - interface_type); - g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_INTERFACE_SETTING_NAME, NM_SETTING_OVS_INTERFACE_TYPE); - return FALSE; - } - - if (!interface_type) { - g_set_error (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("A connection with '%s' setting needs to be of 'patch' interface type"), - NM_SETTING_OVS_PATCH_SETTING_NAME); - g_prefix_error (error, "%s.%s: ", NM_SETTING_OVS_INTERFACE_SETTING_NAME, NM_SETTING_OVS_INTERFACE_TYPE); - return NM_SETTING_VERIFY_NORMALIZABLE_ERROR; - } - } - return TRUE; } diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c index 590beea5d1..9c8e53aeac 100644 --- a/libnm-core/nm-setting.c +++ b/libnm-core/nm-setting.c @@ -219,7 +219,7 @@ _nm_setting_get_base_type_priority (NMSetting *setting) GType nm_setting_lookup_type (const char *name) { - SettingInfo *info; + const SettingInfo *info; g_return_val_if_fail (name, G_TYPE_INVALID); diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index 5f4540c57a..0dc7616d6c 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -4654,6 +4654,344 @@ test_connection_normalize_shared_addresses (void) g_assert_cmpstr (nm_ip_address_get_address (addr), ==, "1.1.1.1"); } +static void +test_connection_normalize_ovs_interface_type_system (gconstpointer test_data) +{ + const guint TEST_CASE = GPOINTER_TO_UINT (test_data); + gs_unref_object NMConnection *con = NULL; + NMSettingConnection *s_con; + NMSettingOvsInterface *s_ovs_if; + + con = nmtst_create_minimal_connection ("test_connection_normalize_ovs_interface_type_system", + NULL, + NM_SETTING_WIRED_SETTING_NAME, &s_con); + + switch (TEST_CASE) { + case 1: + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, "master0", + NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_OVS_PORT_SETTING_NAME, + NULL); + + nmtst_assert_connection_verifies_after_normalization (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_SETTING); + + nmtst_connection_normalize (con); + nmtst_assert_connection_has_settings (con, NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_OVS_INTERFACE_SETTING_NAME); + s_ovs_if = nm_connection_get_setting_ovs_interface (con); + g_assert (s_ovs_if); + g_assert_cmpstr (nm_setting_ovs_interface_get_interface_type (s_ovs_if), ==, "system"); + break; + case 2: + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, "master0", + NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_OVS_PORT_SETTING_NAME, + NULL); + + s_ovs_if = NM_SETTING_OVS_INTERFACE (nm_setting_ovs_interface_new ()); + nm_connection_add_setting (con, NM_SETTING (s_ovs_if)); + + nmtst_assert_connection_verifies_after_normalization (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_PROPERTY); + + nmtst_connection_normalize (con); + nmtst_assert_connection_has_settings (con, NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_OVS_INTERFACE_SETTING_NAME); + g_assert (s_ovs_if == nm_connection_get_setting_ovs_interface (con)); + g_assert_cmpstr (nm_setting_ovs_interface_get_interface_type (s_ovs_if), ==, "system"); + break; + case 3: + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, "master0", + NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_OVS_PORT_SETTING_NAME, + NULL); + + s_ovs_if = NM_SETTING_OVS_INTERFACE (nm_setting_ovs_interface_new ()); + nm_connection_add_setting (con, NM_SETTING (s_ovs_if)); + + g_object_set (s_ovs_if, + NM_SETTING_OVS_INTERFACE_TYPE, "system", + NULL); + nmtst_assert_connection_verifies_without_normalization (con); + nmtst_assert_connection_has_settings (con, NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_OVS_INTERFACE_SETTING_NAME); + break; + case 4: + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, "master0", + NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_OVS_PORT_SETTING_NAME, + NULL); + + s_ovs_if = NM_SETTING_OVS_INTERFACE (nm_setting_ovs_interface_new ()); + nm_connection_add_setting (con, NM_SETTING (s_ovs_if)); + + g_object_set (s_ovs_if, + NM_SETTING_OVS_INTERFACE_TYPE, "internal", + NULL); + /* the setting doesn't verify, because the interface-type must be "system". */ + nmtst_assert_connection_unnormalizable (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); + break; + case 5: + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, "master0", + NULL); + + s_ovs_if = NM_SETTING_OVS_INTERFACE (nm_setting_ovs_interface_new ()); + nm_connection_add_setting (con, NM_SETTING (s_ovs_if)); + + g_object_set (s_ovs_if, + NM_SETTING_OVS_INTERFACE_TYPE, "system", + NULL); + nmtst_assert_connection_verifies_after_normalization (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_PROPERTY); + nmtst_connection_normalize (con); + nmtst_assert_connection_has_settings (con, NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_OVS_INTERFACE_SETTING_NAME); + g_assert (s_con == nm_connection_get_setting_connection (con)); + g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NM_SETTING_OVS_PORT_SETTING_NAME); + break; + case 6: + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, "master0", + NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BRIDGE_SETTING_NAME, + NULL); + + s_ovs_if = NM_SETTING_OVS_INTERFACE (nm_setting_ovs_interface_new ()); + nm_connection_add_setting (con, NM_SETTING (s_ovs_if)); + + g_object_set (s_ovs_if, + NM_SETTING_OVS_INTERFACE_TYPE, "system", + NULL); + nmtst_assert_connection_unnormalizable (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); + break; + case 7: + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, "master0", + NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BRIDGE_SETTING_NAME, + NULL); + + nm_connection_add_setting (con, nm_setting_bridge_port_new ()); + + s_ovs_if = NM_SETTING_OVS_INTERFACE (nm_setting_ovs_interface_new ()); + nm_connection_add_setting (con, NM_SETTING (s_ovs_if)); + + g_object_set (s_ovs_if, + NM_SETTING_OVS_INTERFACE_TYPE, "system", + NULL); + nmtst_assert_connection_unnormalizable (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); + break; + default: + g_assert_not_reached (); + break; + } +} + +static void +test_connection_normalize_ovs_interface_type_ovs_interface (gconstpointer test_data) +{ + const guint TEST_CASE = GPOINTER_TO_UINT (test_data); + gs_unref_object NMConnection *con = NULL; + NMSettingConnection *s_con; + NMSettingOvsInterface *s_ovs_if; + NMSettingOvsPatch *s_ovs_patch; + NMSettingIP4Config *s_ip4; + NMSettingIP6Config *s_ip6; + + con = nmtst_create_minimal_connection ("test_connection_normalize_ovs_interface_type_ovs_interface", + NULL, + NM_SETTING_OVS_INTERFACE_SETTING_NAME, &s_con); + s_ovs_if = nm_connection_get_setting_ovs_interface (con); + g_assert (s_ovs_if); + + switch (TEST_CASE) { + case 1: + nmtst_assert_connection_unnormalizable (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); + break; + case 2: + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, "master0", + NULL); + nmtst_assert_connection_verifies_after_normalization (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_PROPERTY); + nmtst_connection_normalize (con); + nmtst_assert_connection_has_settings (con, NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_PROXY_SETTING_NAME, + NM_SETTING_OVS_INTERFACE_SETTING_NAME); + g_assert (s_con == nm_connection_get_setting_connection (con)); + g_assert (s_ovs_if == nm_connection_get_setting_ovs_interface (con)); + g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NM_SETTING_OVS_PORT_SETTING_NAME); + g_assert_cmpstr (nm_setting_ovs_interface_get_interface_type (s_ovs_if), ==, "internal"); + break; + case 3: + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, "master0", + NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_OVS_PORT_SETTING_NAME, + NULL); + nmtst_assert_connection_verifies_after_normalization (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_PROPERTY); + nmtst_connection_normalize (con); + nmtst_assert_connection_has_settings (con, NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_PROXY_SETTING_NAME, + NM_SETTING_OVS_INTERFACE_SETTING_NAME); + g_assert (s_con == nm_connection_get_setting_connection (con)); + g_assert (s_ovs_if == nm_connection_get_setting_ovs_interface (con)); + g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NM_SETTING_OVS_PORT_SETTING_NAME); + g_assert_cmpstr (nm_setting_ovs_interface_get_interface_type (s_ovs_if), ==, "internal"); + break; + case 4: + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, "master0", + NULL); + g_object_set (s_ovs_if, + NM_SETTING_OVS_INTERFACE_TYPE, "internal", + NULL); + nmtst_assert_connection_verifies_after_normalization (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_PROPERTY); + nmtst_connection_normalize (con); + nmtst_assert_connection_has_settings (con, NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_PROXY_SETTING_NAME, + NM_SETTING_OVS_INTERFACE_SETTING_NAME); + g_assert (s_con == nm_connection_get_setting_connection (con)); + g_assert (s_ovs_if == nm_connection_get_setting_ovs_interface (con)); + g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NM_SETTING_OVS_PORT_SETTING_NAME); + g_assert_cmpstr (nm_setting_ovs_interface_get_interface_type (s_ovs_if), ==, "internal"); + break; + case 5: + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, "master0", + NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_OVS_PORT_SETTING_NAME, + NULL); + g_object_set (s_ovs_if, + NM_SETTING_OVS_INTERFACE_TYPE, "internal", + NULL); + nm_connection_add_setting (con, nm_setting_ip4_config_new ()); + nm_connection_add_setting (con, nm_setting_ip6_config_new ()); + nm_connection_add_setting (con, nm_setting_proxy_new ()); + s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting_ip4_config (con)); + s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (con)); + g_object_set (s_ip4, + NM_SETTING_IP_CONFIG_METHOD, "auto", + NULL); + g_object_set (s_ip6, + NM_SETTING_IP_CONFIG_METHOD, "auto", + NULL); + nmtst_assert_connection_verifies_without_normalization (con); + nmtst_assert_connection_has_settings (con, NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_PROXY_SETTING_NAME, + NM_SETTING_OVS_INTERFACE_SETTING_NAME); + break; + case 6: + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, "master0", + NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_OVS_PORT_SETTING_NAME, + NULL); + g_object_set (s_ovs_if, + NM_SETTING_OVS_INTERFACE_TYPE, "internal", + NULL); + nmtst_assert_connection_verifies_and_normalizable (con); + nmtst_connection_normalize (con); + nmtst_assert_connection_has_settings (con, NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_PROXY_SETTING_NAME, + NM_SETTING_OVS_INTERFACE_SETTING_NAME); + g_assert (s_con == nm_connection_get_setting_connection (con)); + g_assert (s_ovs_if == nm_connection_get_setting_ovs_interface (con)); + g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NM_SETTING_OVS_PORT_SETTING_NAME); + g_assert_cmpstr (nm_setting_ovs_interface_get_interface_type (s_ovs_if), ==, "internal"); + break; + case 7: + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, "master0", + NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_OVS_PORT_SETTING_NAME, + NULL); + g_object_set (s_ovs_if, + NM_SETTING_OVS_INTERFACE_TYPE, "system", + NULL); + nmtst_assert_connection_unnormalizable (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); + break; + case 8: + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, "master0", + NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_OVS_PORT_SETTING_NAME, + NULL); + g_object_set (s_ovs_if, + NM_SETTING_OVS_INTERFACE_TYPE, "bogus", + NULL); + nmtst_assert_connection_unnormalizable (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); + break; + case 9: + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, "master0", + NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_OVS_PORT_SETTING_NAME, + NULL); + g_object_set (s_ovs_if, + NM_SETTING_OVS_INTERFACE_TYPE, "patch", + NULL); + nmtst_assert_connection_unnormalizable (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_SETTING); + break; + case 10: + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, "master0", + NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_OVS_PORT_SETTING_NAME, + NULL); + g_object_set (s_ovs_if, + NM_SETTING_OVS_INTERFACE_TYPE, "patch", + NULL); + nm_connection_add_setting (con, nm_setting_ovs_patch_new ()); + nmtst_assert_connection_unnormalizable (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_PROPERTY); + break; + case 11: + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, "master0", + NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_OVS_PORT_SETTING_NAME, + NM_SETTING_CONNECTION_INTERFACE_NAME, "adsf", + NULL); + g_object_set (s_ovs_if, + NM_SETTING_OVS_INTERFACE_TYPE, "patch", + NULL); + nm_connection_add_setting (con, nm_setting_ovs_patch_new ()); + nmtst_assert_connection_unnormalizable (con, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_PROPERTY); + break; + case 12: + g_object_set (s_con, + NM_SETTING_CONNECTION_MASTER, "master0", + NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_OVS_PORT_SETTING_NAME, + NM_SETTING_CONNECTION_INTERFACE_NAME, "adsf", + NULL); + g_object_set (s_ovs_if, + NM_SETTING_OVS_INTERFACE_TYPE, "patch", + NULL); + s_ovs_patch = NM_SETTING_OVS_PATCH (nm_setting_ovs_patch_new ()); + nm_connection_add_setting (con, NM_SETTING (s_ovs_patch)); + g_object_set (s_ovs_patch, + NM_SETTING_OVS_PATCH_PEER, "1.2.3.4", + NULL); + nmtst_assert_connection_verifies_and_normalizable (con); + nmtst_connection_normalize (con); + nmtst_assert_connection_has_settings (con, NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_PROXY_SETTING_NAME, + NM_SETTING_OVS_INTERFACE_SETTING_NAME, + NM_SETTING_OVS_PATCH_SETTING_NAME); + g_assert (s_con == nm_connection_get_setting_connection (con)); + g_assert (s_ovs_if == nm_connection_get_setting_ovs_interface (con)); + g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NM_SETTING_OVS_PORT_SETTING_NAME); + g_assert_cmpstr (nm_setting_ovs_interface_get_interface_type (s_ovs_if), ==, "patch"); + break; + default: + g_assert_not_reached (); + } +} + static void test_setting_ip4_gateway (void) { @@ -6540,6 +6878,25 @@ int main (int argc, char **argv) g_test_add_func ("/core/general/test_connection_normalize_gateway_never_default", test_connection_normalize_gateway_never_default); g_test_add_func ("/core/general/test_connection_normalize_may_fail", test_connection_normalize_may_fail); g_test_add_func ("/core/general/test_connection_normalize_shared_addresses", test_connection_normalize_shared_addresses); + g_test_add_data_func ("/core/general/test_connection_normalize_ovs_interface_type_system/1", GUINT_TO_POINTER (1), test_connection_normalize_ovs_interface_type_system); + g_test_add_data_func ("/core/general/test_connection_normalize_ovs_interface_type_system/2", GUINT_TO_POINTER (2), test_connection_normalize_ovs_interface_type_system); + g_test_add_data_func ("/core/general/test_connection_normalize_ovs_interface_type_system/3", GUINT_TO_POINTER (3), test_connection_normalize_ovs_interface_type_system); + g_test_add_data_func ("/core/general/test_connection_normalize_ovs_interface_type_system/4", GUINT_TO_POINTER (4), test_connection_normalize_ovs_interface_type_system); + g_test_add_data_func ("/core/general/test_connection_normalize_ovs_interface_type_system/5", GUINT_TO_POINTER (5), test_connection_normalize_ovs_interface_type_system); + g_test_add_data_func ("/core/general/test_connection_normalize_ovs_interface_type_system/6", GUINT_TO_POINTER (6), test_connection_normalize_ovs_interface_type_system); + g_test_add_data_func ("/core/general/test_connection_normalize_ovs_interface_type_system/7", GUINT_TO_POINTER (7), test_connection_normalize_ovs_interface_type_system); + g_test_add_data_func ("/core/general/test_connection_normalize_ovs_interface_type_ovs_interface/1", GUINT_TO_POINTER (1), test_connection_normalize_ovs_interface_type_ovs_interface); + g_test_add_data_func ("/core/general/test_connection_normalize_ovs_interface_type_ovs_interface/2", GUINT_TO_POINTER (2), test_connection_normalize_ovs_interface_type_ovs_interface); + g_test_add_data_func ("/core/general/test_connection_normalize_ovs_interface_type_ovs_interface/3", GUINT_TO_POINTER (3), test_connection_normalize_ovs_interface_type_ovs_interface); + g_test_add_data_func ("/core/general/test_connection_normalize_ovs_interface_type_ovs_interface/4", GUINT_TO_POINTER (4), test_connection_normalize_ovs_interface_type_ovs_interface); + g_test_add_data_func ("/core/general/test_connection_normalize_ovs_interface_type_ovs_interface/5", GUINT_TO_POINTER (5), test_connection_normalize_ovs_interface_type_ovs_interface); + g_test_add_data_func ("/core/general/test_connection_normalize_ovs_interface_type_ovs_interface/6", GUINT_TO_POINTER (6), test_connection_normalize_ovs_interface_type_ovs_interface); + g_test_add_data_func ("/core/general/test_connection_normalize_ovs_interface_type_ovs_interface/7", GUINT_TO_POINTER (7), test_connection_normalize_ovs_interface_type_ovs_interface); + g_test_add_data_func ("/core/general/test_connection_normalize_ovs_interface_type_ovs_interface/8", GUINT_TO_POINTER (8), test_connection_normalize_ovs_interface_type_ovs_interface); + g_test_add_data_func ("/core/general/test_connection_normalize_ovs_interface_type_ovs_interface/9", GUINT_TO_POINTER (9), test_connection_normalize_ovs_interface_type_ovs_interface); + g_test_add_data_func ("/core/general/test_connection_normalize_ovs_interface_type_ovs_interface/10", GUINT_TO_POINTER (10), test_connection_normalize_ovs_interface_type_ovs_interface); + g_test_add_data_func ("/core/general/test_connection_normalize_ovs_interface_type_ovs_interface/11", GUINT_TO_POINTER (11), test_connection_normalize_ovs_interface_type_ovs_interface); + g_test_add_data_func ("/core/general/test_connection_normalize_ovs_interface_type_ovs_interface/12", GUINT_TO_POINTER (12), test_connection_normalize_ovs_interface_type_ovs_interface); g_test_add_func ("/core/general/test_setting_connection_permissions_helpers", test_setting_connection_permissions_helpers); g_test_add_func ("/core/general/test_setting_connection_permissions_property", test_setting_connection_permissions_property); From 6b532fed5046d0d658164e5ab9813ce8871cfbeb Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 30 Oct 2017 17:32:30 +0100 Subject: [PATCH 36/36] man: add OpenVSwitch overview --- Makefile.am | 7 + configure.ac | 2 + contrib/fedora/rpm/NetworkManager.spec | 3 +- docs/api/Makefile.am | 1 + docs/api/network-manager-docs.xml | 1 + man/nm-openvswitch.xml | 204 +++++++++++++++++++++++++ 6 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 man/nm-openvswitch.xml diff --git a/Makefile.am b/Makefile.am index 1c7456d6f4..46799cb1f1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4375,6 +4375,13 @@ man_pages_autogen += \ man/nm-settings-keyfile.5 \ man/nm-settings.5 +if WITH_OPENVSWITCH +man_pages += man/nm-openvswitch.7 +else +EXTRA_DIST += man/nm-openvswitch.7 +dist_dependencies += man/nm-openvswitch.7 +endif + if CONFIG_PLUGIN_IFCFG_RH man_pages_autogen += man/nm-settings-ifcfg-rh.5 else diff --git a/configure.ac b/configure.ac index 8ff914d0e8..146f7ccd15 100644 --- a/configure.ac +++ b/configure.ac @@ -1296,6 +1296,8 @@ if test "$build_docs" != "yes" -a \ -f "$srcdir"/man/nmcli.1 -a \ -f "$srcdir"/man/nmtui.1 -a \ \ + -f "$srcdir"/man/nm-openvswitch.7 -a \ + \ -f "$srcdir"/man/nm-settings-ifcfg-rh.5 -a \ -f "$srcdir"/man/nm-settings-keyfile.5 -a \ -f "$srcdir"/man/nm-settings.5 -a \ diff --git a/contrib/fedora/rpm/NetworkManager.spec b/contrib/fedora/rpm/NetworkManager.spec index 6dcadf81f3..4778f15042 100644 --- a/contrib/fedora/rpm/NetworkManager.spec +++ b/contrib/fedora/rpm/NetworkManager.spec @@ -577,7 +577,7 @@ fi %dir %{nmlibdir}/VPN %{_mandir}/man1/* %{_mandir}/man5/* -%{_mandir}/man7/* +%{_mandir}/man7/nmcli-examples.7* %{_mandir}/man8/* %dir %{_localstatedir}/lib/NetworkManager %dir %{_sysconfdir}/NetworkManager/system-connections @@ -626,6 +626,7 @@ fi %files ovs %{_libdir}/%{name}/libnm-device-plugin-ovs.so %{systemd_dir}/NetworkManager.service.d/NetworkManager-ovs.conf +%{_mandir}/man7/nm-openvswitch.7* %endif %if %{with ppp} diff --git a/docs/api/Makefile.am b/docs/api/Makefile.am index f5def7b8b8..67f0a22691 100644 --- a/docs/api/Makefile.am +++ b/docs/api/Makefile.am @@ -88,6 +88,7 @@ content_files = \ $(top_builddir)/man/nmcli-examples.xml \ $(top_builddir)/man/nm-settings.xml \ $(top_builddir)/man/nm-settings-keyfile.xml \ + $(top_builddir)/man/nm-openvswitch.xml \ version.xml \ ../../COPYING \ $(NULL) diff --git a/docs/api/network-manager-docs.xml b/docs/api/network-manager-docs.xml index dd5f0e47f5..0002f8ee11 100644 --- a/docs/api/network-manager-docs.xml +++ b/docs/api/network-manager-docs.xml @@ -76,6 +76,7 @@ + diff --git a/man/nm-openvswitch.xml b/man/nm-openvswitch.xml new file mode 100644 index 0000000000..5573046c38 --- /dev/null +++ b/man/nm-openvswitch.xml @@ -0,0 +1,204 @@ + + + +%entities; +]> + + + + + + nm-openvswitch + NetworkManager OpenVSwitch support + + + + nm-openvswitch + 7 + NetworkManager + OpenVSwitch support overview + &NM_VERSION; + + + + nm-openvswitch + overview of NetworkManager OpenVSwitch support + + + + Overview + + NetworkManager includes basic OpenVSwitch support, good enough + to be capable of setting up simple OpenVSwitch configurations. It is not + extensive and does not expose all functionality of OpenVSwitch provides. + For large or complicated deployments users are advised to use native tools + shipped with OpenVSwitch. This document seeks to provide overview of + functionality currently provided by NetworkManager, its capabilities and + limitations. + + First and foremost: NetworkManager applies the configuration by + modifying the OVSDB directly. Its configuration model follows the OVSDB + database model closely and it does not provide the level of abstraction + ovs-vsctl provides. + + In practical terms it means the following: + + + NetworkManager only ever talks to a single OVSDB instance via an + UNIX domain socket. + + + The configuration is made up of Bridges, Ports and + Interfaces. Interfaces are always enslaved to Ports, and Ports are always + enslaved to Bridges. + + + NetworkManager only creates Bridges, Ports and Interfaces + you ask it to. Unlike ovs-vsctl, it doesn't create the + local interface nor its port automatically. + + + You can't enslave Interface directly to a Bridge. You + always need a Port, even if it has just one interface. + + + There are no VLANs. The VLAN tagging is enabled by setting a + ovs-port.tag + property on a Port. + + + There are no bonds either. The bonding is enabled by + enslaving multiple Interfaces to a Port and configured by setting + properties on a port. + + + + + + Bridges + + Bridges are represented by connections of ovs-bridge + type. + Due to the limitations of OVSDB, "empty" Bridges (with no Ports) can't exist. + NetworkManager inserts the records for Bridges into OVSDB when a Port is + enslaved. + + + + + Ports + + Ports are represented by connections of ovs-port + type. + Due to the limitations of OVSDB, "empty" Ports (with no Interfaces) can't + exist. Ports can also be configured to do VLAN tagging or Bonding. + NetworkManager inserts the records for Ports into OVSDB when an Interface is + enslaved. Ports must be enslaved to a Bridge. + + + + Interfaces + + Interfaces are represented by a connections enslaved to a Port. The + system interfaces (that have a corresponding Linux link) have a respective + connection.type + of the link (e.g. "wired", "bond", "dummy", etc.). Other interfaces ("internal" + or "patch" interfaces) are of ovs-interface type. The OVSDB entries are + inserted upon enslavement to a Port. + + + + + + Examples + + Creating a Bridge with a single internal Interface +$ nmcli conn add conn.type ovs-bridge conn.interface bridge0 +Connection 'ovs-bridge-bridge0' (d10fc64d-1d48-4394-a1b8-e1aea72f27d5) successfully added. +$ nmcli conn add conn.type ovs-port conn.interface port0 conn.master bridge0 +Connection 'ovs-port-port0' (5ae22bae-bba4-4815-9ade-7e635633e1f0) successfully added. +$ nmcli conn add conn.type ovs-interface conn.interface iface0 conn.master port0 \ + ipv4.method manual ipv4.address 192.0.2.1/24 +Connection 'ovs-interface-iface0' (3640d2a1-a2fd-4718-92f1-cffadb5b6cdc) successfully added. + + As said above, you need to create a Port even for a single interface. + Also, before you add the Interface, the Bridge and Port devices appear active, + but are not configured in OVSDB yet. You can inspect the results with + ovs-vsctl show. + + + Adding a Linux interface to a Bridge +$ nmcli conn add conn.type ovs-port conn.interface port1 conn.master bridge0 +Connection 'ovs-port-port1' (67d041eb-8e7b-4458-afee-a1d07c9c4552) successfully added. +$ nmcli conn add conn.type ethernet conn.interface eth0 conn.master port1 +Connection 'ovs-slave-eth0' (d459c45c-cf78-4c1c-b4b7-505e71379624) successfully added. + +Again, you need a port. + + + Creating a VLAN +$ nmcli conn add conn.type ovs-port conn.interface port2 conn.master bridge0 ovs-port.tag 120 +Connection 'ovs-port-port2' (3994c093-4ef7-4549-a4fd-627b831c3cb8) successfully added. +$ nmcli conn add conn.type ethernet conn.interface eth1 conn.master port2 +Connection 'ovs-slave-eth1' (099be06e-71ad-484d-8d5a-fcadc5f207f5) successfully added. + + It's just a port with a tag. + + + Creating a Bond +$ nmcli conn add conn.type ovs-port conn.interface bond0 conn.master bridge0 +Connection 'ovs-port-bond0' (d154ebf9-e999-4e1b-a084-a3de53d25d8a) successfully added. +$ nmcli conn add conn.type ethernet conn.interface eth2 conn.master bond0 +Connection 'ovs-slave-eth2' (475ac1bf-30b2-4534-a877-27f33f58b082) successfully added. +$ nmcli conn add conn.type ethernet conn.interface eth3 conn.master bond0 +Connection 'ovs-slave-eth3' (8dedeecb-ed12-482b-b77a-24a4fb835136) successfully added. + + It's just a Port with multiple interfaces. See nm-settings manual for + Bonding options you can use with "nmcli c add" or "nmcli c modify". You could + even set a VLAN tag on the same Port to do VLAN tagging and bonding at the same + time. + + + + + Bugs + + + + Not all OpenVSwitch capabilities are supported. + + + OpenVSwitch devices don't expose many useful properties on D-Bus. + + + Probably many more. + + + + See Also + + RFC 7047: The Open vSwitch Database Management Protocol, + ovs-vsctl8, + ovs-vswitchd.conf.db5, + nm-settings5, + nmcli1 + + +